計算機科学のブログ

楕円曲線暗号 Goによる署名の作成

プログラミング・ビットコイン ―ゼロからビットコインをプログラムする方法 (Jimmy Song(著)、中川 卓俊(監修)、住田 和則(監修)、中村 昭雄(監修)、星野 靖子(翻訳)、オライリー・ジャパン)の3章(楕円曲線暗号)、3.11(署名と検証)、3.11.6(署名の作成)をPytrhonではなく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 {
		r := new(big.Int)
		r.Set(exp)
		r.Mod(exp, two)
		if r.Cmp(one) == 0 {
			i.Mul(i, base)
			exp.Sub(exp, one)
		}
		base.Mul(base, base)
		base.Mod(base, ecc.N())
		exp.Div(exp, two)
	}
	i.Mul(i, base)
	i.Mod(i, ecc.N())
	return i
}

func main() {
	eBytes := sha256.Sum256([]byte("my secret"))
	zBytes := sha256.Sum256([]byte("my message"))
	e := binary.BigEndian.Uint64(eBytes[:])
	eInt := big.NewInt(int64(e))
	z := binary.BigEndian.Uint64(zBytes[:])
	zInt := big.NewInt(int64(z))
	k := big.NewInt(1234567890)
	r := ecc.G.ScalarMul(k).X.Num
	kInv := new(big.Int)
	kInv.Set(pow(k))
	s := new(big.Int)
	s.Set(r)
	s.Mul(s, eInt)
	s.Add(zInt, s)
	s.Mul(s, kInv)
	s.Mod(s, ecc.N())
	point := ecc.G.ScalarMul(eInt)
	fmt.Println(point)
	fmt.Printf("z = 0x%x\nr = 0x%x\ns = 0x%x\n", z, r, s)
}

入出力結果(Terminal, Zsh)

% go run main.go
S256Point(10e83f4150adc34779367355a7b17cabdda5f46e23cb7dd032da94b27ad40fa6, e7fab2554ce9edee23901ccbba86b0303305a5343618135ece134a0041490ec8)
z = 0xea38e30f75767d7e
r = 0x2b698a0f0a4041b77e63488ad48c23e8e8838dd1fb7520408b121697b782ef22
s = 0xb4a951689f001626959b04d1bc0404c70b88281428e46e9ab918c850ad78d75e
%