計算機科学のブログ

楕円曲線暗号 秘密鍵、メッセージへの署名

プログラミング・ビットコイン ―ゼロからビットコインをプログラムする方法 (Jimmy Song(著)、中川 卓俊(監修)、住田 和則(監修)、中村 昭雄(監修)、星野 靖子(翻訳)、オライリー・ジャパン)の3章(楕円曲線暗号)、3.11(署名と検証)、3.11.6(署名の作成)、練習問題7の解答をPythonではなくGoで求めてみる。

コード

package main

import (
	"bitcoin/ecc"
	"crypto/sha256"
	"encoding/binary"
	"fmt"
	"math/big"
)

func pow(x *big.Int) *big.Int {
	i := big.NewInt(1)
	exp := new(big.Int)
	exp.Set(ecc.N())
	exp.Sub(exp, big.NewInt(2))
	base := new(big.Int)
	base.Set(x)
	one := big.NewInt(1)
	two := big.NewInt(2)
	for exp.Cmp(one) != 0 {
		m := new(big.Int)
		exp.DivMod(exp, two, m)
		if m.Cmp(one) == 0 {
			i.Mul(i, base)
		}
		base.Mul(base, base)
		base.Mod(base, ecc.N())
	}
	i.Mul(i, base)
	i.Mod(i, ecc.N())
	return i
}
func main() {
	e := big.NewInt(12345)
	b := sha256.Sum256([]byte("Programming Bitcoin"))
	z := big.NewInt(int64(binary.BigEndian.Uint32(b[:])))
	k := big.NewInt(1234567890)
	r := ecc.G.ScalarMul(k).X.Num
	kInv := pow(k)
	s := new(big.Int)
	s.Set(r)
	s.Mul(s, e)
	s.Add(s, z)
	s.Mul(s, kInv)
	s.Mod(s, ecc.N())
	fmt.Printf("署名: (0x%x,0x%x)\n", r, s)
}

入出力結果(Terminal, Zsh)

% go run main.go
署名: (0x2b698a0f0a4041b77e63488ad48c23e8e8838dd1fb7520408b121697b782ef22,0x9d3a74faaa95b4ef3578b00659cf4e7e922398202425e36eab21774d3639dbec)
%