計算機科学のブログ

楕円曲線暗号 署名検証のGoによる実装

プログラミング・ビットコイン ―ゼロからビットコインをプログラムする方法 (Jimmy Song(著)、中川 卓俊(監修)、住田 和則(監修)、中村 昭雄(監修)、星野 靖子(翻訳)、オライリー・ジャパン)の3章(楕円曲線暗号)、3.11(署名と検証)、3.11.4(署名の検証のプログラミング)をPytrhonではなくGoでコードを書いて実装してみる。

コード

ecc.go

// Package ecc (Elliptic Curve Cryptography, 楕円曲線暗号)
package ecc

import (
	"errors"
	"fmt"
	"math/big"
)

// FieldElement 有限体の要素
type FieldElement struct {
	Num, Prime *big.Int
}

func (x FieldElement) String() string {
	return fmt.Sprintf("FieldElement_%v(%v)", x.Prime, x.Num)
}

// NewFieldElement ...
func NewFieldElement(n, p *big.Int) (FieldElement, error) {
	np := n.Cmp(p)
	nz := n.Cmp(big.NewInt(0))
	if !(np == -1 && nz != -1) {
		pSub1 := new(big.Int)
		pSub1.Sub(p, big.NewInt(1))
		return FieldElement{},
			fmt.Errorf("%v not in field range 0 to %v", n, pSub1)
	}
	return FieldElement{n, p}, nil
}

// NewFieldElementInt ...
func NewFieldElementInt(ni, pi int64) (FieldElement, error) {
	n := big.NewInt(ni)
	p := big.NewInt(pi)
	return NewFieldElement(n, p)
}

// NewFieldElementString ...
func NewFieldElementString(ns, ps string, base int) (FieldElement, error) {
	n := new(big.Int)
	n.SetString(ns, base)
	p := new(big.Int)
	p.SetString(ps, base)
	return NewFieldElement(n, p)
}

// Eq ...
func (x FieldElement) Eq(y FieldElement) bool {
	if y.Num == nil {
		return false
	}
	return x.Num.Cmp(y.Num) == 0 && x.Prime.Cmp(y.Prime) == 0
}

// Ne ...
func (x FieldElement) Ne(y FieldElement) bool {
	return !x.Eq(y)
}

// Add ...
func (x FieldElement) Add(y FieldElement) (FieldElement, error) {
	if x.Prime.Cmp(y.Prime) != 0 {
		return FieldElement{}, errors.New("Cannot add two numbers in different Fields")
	}
	n := new(big.Int)
	n.Set(x.Num)
	n.Add(n, y.Num)
	n.Mod(n, x.Prime)
	p := new(big.Int)
	p.Set(x.Prime)
	return NewFieldElement(n, p)
}

// Sub ...
func (x FieldElement) Sub(y FieldElement) (FieldElement, error) {
	if x.Prime.Cmp(y.Prime) != 0 {
		return FieldElement{}, errors.New("Cannot sub two niumbers in different Fields")
	}
	n := new(big.Int)
	n.Set(x.Num)
	n.Sub(n, y.Num)
	n.Mod(n, x.Prime)
	p := new(big.Int)
	p.Set(x.Prime)
	return NewFieldElement(n, p)
}

// Mul ...
func (x FieldElement) Mul(y FieldElement) (FieldElement, error) {
	if x.Prime.Cmp(y.Prime) != 0 {
		return FieldElement{}, errors.New("Cannot mul two niumbers in different Fields")
	}
	n := new(big.Int)
	n.Set(x.Num)
	n.Mul(n, y.Num)
	n.Mod(n, x.Prime)
	p := new(big.Int)
	p.Set(x.Prime)
	return NewFieldElement(n, p)
}

// Pow ...
func (x FieldElement) Pow(y *big.Int) FieldElement {
	prime := new(big.Int)
	prime.Set(x.Prime)
	exp := new(big.Int)
	exp.Set(y)
	p := new(big.Int)
	p.Set(prime)
	one := big.NewInt(1)
	p.Sub(p, one)
	exp.Mod(exp, p)
	base := new(big.Int)
	base.Set(x.Num)
	n := big.NewInt(1)
	two := big.NewInt(2)
	m := new(big.Int)
	for exp.Cmp(one) != 0 {
		exp.DivMod(exp, two, m)
		if m.Cmp(one) == 0 {
			n.Mul(n, base)
		}
		base.Mul(base, base)
		base.Mod(base, prime)
		// r := new(big.Int)
		// r.Set(exp)
		// r.Mod(exp, two)
		// if r.Cmp(one) == 0 {
		// 	n.Mul(n, base)
		// 	exp.Sub(exp, one)
		// }
		// base.Mul(base, base)
		// base.Mod(base, prime)
		// exp.Div(exp, two)
	}
	n.Mul(n, base)
	n.Mod(n, prime)
	f, _ := NewFieldElement(n, prime)
	return f
}

// Div ...
func (x FieldElement) Div(y FieldElement) (FieldElement, error) {
	if x.Prime.Cmp(y.Prime) != 0 {
		return FieldElement{}, errors.New("Cannot div two niumbers in different Fields")
	}
	two := big.NewInt(2)
	p := new(big.Int)
	p.Set(x.Prime)
	exp := new(big.Int)
	exp.Set(x.Prime)
	exp.Sub(exp, two)
	base := new(big.Int)
	base.Set(y.Num)
	m := big.NewInt(1)
	one := big.NewInt(1)
	for exp.Cmp(one) != 0 {
		r := new(big.Int)
		r.Set(exp)
		r.Mod(exp, two)
		if r.Cmp(one) == 0 {
			m.Mul(m, base)
			exp.Sub(exp, one)
		}
		base.Mul(base, base)
		base.Mod(base, p)
		exp.Div(exp, two)
	}
	m.Mul(m, base)
	n := new(big.Int)
	n.Set(x.Num)
	n.Mul(n, m)
	n.Mod(n, p)
	return NewFieldElement(n, p)
}

// Point 有限体上の楕円曲線 y^2 = x^3 + Ax + B の点
type Point struct {
	A, B     FieldElement
	Infinity bool
	X, Y     FieldElement
}

// NewPoint ...
func NewPoint(inf bool, x, y, a, b FieldElement) (Point, error) {
	xPrime := x.Prime
	for _, f := range []FieldElement{y, a, b} {
		if xPrime.Cmp(f.Prime) != 0 {
			return Point{}, fmt.Errorf("(%v, %v) in different Fields", x, f)
		}
	}
	if inf {
		zero, _ := NewFieldElement(big.NewInt(0), x.Prime)
		return Point{Infinity: inf, X: zero, Y: zero, A: a, B: b}, nil
	}
	l := y.Pow(big.NewInt(2))
	r := x.Pow(big.NewInt(3))
	t, _ := a.Mul(x)
	r, _ = r.Add(t)
	r, _ = r.Add(b)
	if l.Ne(r) {
		return Point{}, fmt.Errorf("(%v, %v) is not on the curve", x, y)
	}
	return Point{A: a, B: b, X: x, Y: y}, nil
}

func (px Point) String() string {
	if px.Infinity {
		return "Point(Infinity)"
	}
	return fmt.Sprintf("Point(%v,%v)_%v_%v FieldElement(%v)",
		px.X.Num, px.Y.Num, px.A.Num, px.B.Num, px.X.Prime)
}

// Eq ...
func (px Point) Eq(py Point) bool {
	return px.X.Eq(py.X) && px.Y.Eq(py.Y) && px.A.Eq(py.A) && px.B.Eq(py.B)
}

// Ne ...
func (px Point) Ne(py Point) bool {
	return !px.Eq(py)
}

// Add ...
func (px Point) Add(py Point) (Point, error) {
	if px.A.Ne(py.A) || px.B.Ne(py.B) {
		return Point{},
			fmt.Errorf("Points %v, %v are not on the same curve", px, py)
	}
	if px.X.Prime.Cmp(py.X.Prime) != 0 {
		return Point{},
			fmt.Errorf("Points %v, %v are not on the same Field", px, py)
	}
	if px.Infinity {
		return py, nil
	}
	if py.Infinity {
		return px, nil
	}
	if px.X.Ne(py.X) {
		s, _ := py.Y.Sub(px.Y)
		t, _ := py.X.Sub(px.X)
		s, _ = s.Div(t)
		x := s.Pow(big.NewInt(2))
		x, _ = x.Sub(px.X)
		x, _ = x.Sub(py.X)
		y, _ := px.X.Sub(x)
		y, _ = s.Mul(y)
		y, _ = y.Sub(px.Y)
		return NewPoint(false, x, y, px.A, px.B)
	}
	zero, _ := NewFieldElement(big.NewInt(0), px.X.Prime)
	if px.Y.Ne(py.Y) {
		return NewPoint(true, zero, zero, px.A, px.B)
	}
	if px.Eq(py) && px.Y.Eq(zero) {
		return Point{Infinity: true, A: px.A, B: px.B}, nil
	}
	if px.Eq(py) {
		three, _ := NewFieldElement(big.NewInt(3), px.X.Prime)
		s := px.X.Pow(big.NewInt(2))
		s, _ = three.Mul(s)
		s, _ = s.Add(px.A)
		two, _ := NewFieldElement(big.NewInt(2), px.X.Prime)
		s, _ = s.Div(two)
		s, _ = s.Div(px.Y)
		x := s.Pow(big.NewInt(2))
		t, _ := two.Mul(px.X)
		x, _ = x.Sub(t)
		y, _ := px.X.Sub(x)
		y, _ = s.Mul(y)
		y, _ = y.Sub(px.Y)
		return NewPoint(false, x, y, px.A, px.B)
	}
	return Point{}, nil
}

// ScalarMul ...
func (px Point) ScalarMul(coef *big.Int) Point {
	z, _ := NewFieldElement(big.NewInt(0), px.A.Prime)
	p, _ := NewPoint(true, z, z, px.A, px.B)
	c := new(big.Int)
	c.Set(coef)
	cur := px
	m := new(big.Int)
	zero := big.NewInt(0)
	one := big.NewInt(1)
	two := big.NewInt(2)
	for c.Cmp(zero) != 0 {
		c.DivMod(c, two, m)
		if m.Cmp(one) == 0 {
			p, _ = p.Add(cur)
		}
		cur, _ = cur.Add(cur)
	}
	// for _, word := range c.Bits() {
	// 	for word != 0 {
	// 		if word&1 != 0 {
	// 			p, _ = p.Add(cur)
	// 		}
	// 		cur, _ = cur.Add(cur)
	// 		word >>= 1
	// 	}
	// }
	return p
}

// S256Field secp256k1曲線専用のFieldElement型
type S256Field struct {
	FieldElement
}

// P secp256k1曲線専用の有限体の素数
// A, B secp256k1k曲線(有限体上の楕円曲線) y^2 = x^3 + Ax + B
// N 群の位数
var (
	P *big.Int
	A *big.Int
	B *big.Int
	// N *big.Int
)

// PS secp256k1曲線専用の有限体の素数の文字列による表現(16進数)
var PS string = "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"

// N 群の位数
func N() *big.Int {
	n := new(big.Int)
	n.SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16)
	return n
}

func init() {
	P = new(big.Int)
	P.SetString(PS, 16)
	A = big.NewInt(0)
	B = big.NewInt(7)
}

// NewS256Field ...
func NewS256Field(n *big.Int) (S256Field, error) {
	fe, err := NewFieldElement(n, P)
	if err != nil {
		return S256Field{}, err
	}
	return S256Field{fe}, err
}

// NewS256FieldInt ...
func NewS256FieldInt(n int64) (S256Field, error) {
	num := big.NewInt(n)
	fe, err := NewFieldElement(num, P)
	if err != nil {
		return S256Field{}, err
	}
	return S256Field{fe}, nil
}

// NewS256FieldString ...
func NewS256FieldString(s string, base int) (S256Field, error) {
	fe, err := NewFieldElementString(s, PS, base)
	if err != nil {
		return S256Field{}, err
	}
	return S256Field{fe}, nil
}

func (x S256Field) String() string {
	return fmt.Sprintf("%064x", x.Num)
}

// S256Point secp256k1曲線上の点
type S256Point struct {
	Point
}

// NewS256Point ...
func NewS256Point(inf bool, x, y S256Field) (S256Point, error) {
	a, _ := NewS256Field(A)
	b, _ := NewS256Field(B)
	p, err := NewPoint(inf, x.FieldElement, y.FieldElement, a.FieldElement, b.FieldElement)
	if err != nil {
		return S256Point{}, err
	}
	return S256Point{p}, nil
}

// NewS256PointString ...
func NewS256PointString(inf bool, xs, ys string, base int) (S256Point, error) {
	x, err := NewS256FieldString(xs, base)
	if err != nil {
		return S256Point{}, err
	}
	y, err := NewS256FieldString(ys, base)
	if err != nil {
		return S256Point{}, err
	}
	return NewS256Point(inf, x, y)
}

// G 生成点
var G S256Point

func init() {
	x, _ := NewS256FieldString("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", 16)
	y, _ := NewS256FieldString("483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", 16)
	G, _ = NewS256Point(false, x, y)
}

func (px S256Point) String() string {
	if px.Infinity {
		return "S256Point(infinity)"
	}
	return fmt.Sprintf("S256Point(%v, %v)", px.X, px.Y)
}

// Add ...
func (px S256Point) Add(py S256Point) S256Point {
	p, _ := px.Point.Add(py.Point)
	return S256Point{p}
}

// ScalarMul ...
func (px S256Point) ScalarMul(coef *big.Int) S256Point {
	n := N()
	coef.Mod(coef, n)
	return S256Point{px.Point.ScalarMul(coef)}
}

// ScalarMulInt ...
func (px S256Point) ScalarMulInt(coef int64) S256Point {
	c := big.NewInt(coef)
	return px.ScalarMul(c)
}

// ScalarMulString ...
func (px S256Point) ScalarMulString(s string, base int) S256Point {
	c := new(big.Int)
	c.SetString(s, base)
	return px.ScalarMul(c)
}

func pow(x *big.Int) *big.Int {
	i := big.NewInt(1)
	exp := new(big.Int)
	exp.Set(N())
	exp.Sub(exp, big.NewInt(2))
	if exp.Cmp(big.NewInt(0)) == -1 {
		exp.Add(exp, P)
	}
	base := new(big.Int)
	base.Set(x)
	one := big.NewInt(1)
	two := big.NewInt(2)
	n := new(big.Int)
	n.SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16)
	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, n)
		exp.Div(exp, two)
	}
	i.Mul(i, base)
	i.Mod(i, n)
	return i
}

// Verify 署名検証
func (px S256Point) Verify(z *big.Int, sig Signature) bool {
	sInv := pow(sig.S)
	u := new(big.Int)
	u.Set(z)
	u.Mul(u, sInv)
	u.Mod(u, N())
	v := new(big.Int)
	v.Set(sig.R)
	v.Mul(v, sInv)
	v.Mod(v, N())
	total := G.ScalarMul(u).Add(px.ScalarMul(v))
	return total.X.Num.Cmp(sig.R) == 0
}

// Signature rとsを格納する署名
type Signature struct {
	R, S *big.Int
}

// NewSignature ...
func NewSignature(r, s *big.Int) Signature {
	return Signature{R: r, S: s}
}

// NewSignatureString ...
func NewSignatureString(rs, ss string, base int) Signature {
	r := new(big.Int)
	r.SetString(rs, base)
	s := new(big.Int)
	s.SetString(ss, base)
	return NewSignature(r, s)
}

func (sig Signature) String() string {
	return fmt.Sprintf("Signature(%x,%x)", sig.R, sig.S)
}

ecc_test.go

package ecc

import (
	"fmt"
	"math/big"
	"testing"
)

func TestFieldElementEq(t *testing.T) {
	a, _ := NewFieldElementInt(2, 31)
	b, _ := NewFieldElementInt(2, 31)
	got := a.Eq(b)
	want := true
	if !got {
		t.Errorf("%v.Eq(%v) got %v, want %v", a, b, got, want)
	}
}

func TestFieldElementNe(t *testing.T) {
	a, _ := NewFieldElementInt(2, 31)
	b, _ := NewFieldElementInt(2, 31)
	c, _ := NewFieldElementInt(15, 31)
	tests := []struct {
		x, y FieldElement
		bln  bool
	}{
		{a, c, true},
		{a, b, false},
	}
	for _, test := range tests {
		x, y := test.x, test.y
		got := x.Ne(y)
		want := test.bln
		if got != want {
			t.Errorf("%v.Ne(%gv) got %v, want %v", x, y, got, want)
		}
	}
}

func TestFieldElementAdd(t *testing.T) {
	x1, _ := NewFieldElementInt(2, 31)
	y1, _ := NewFieldElementInt(15, 31)
	z1, _ := NewFieldElementInt(17, 31)
	x2, _ := NewFieldElementInt(17, 31)
	y2, _ := NewFieldElementInt(21, 31)
	z2, _ := NewFieldElementInt(7, 31)
	tests := []struct {
		x, y, z FieldElement
	}{
		{x1, y1, z1},
		{x2, y2, z2},
	}
	for _, test := range tests {
		x := test.x
		y := test.y
		got, _ := x.Add(y)
		want := test.z
		if got.Ne(want) {
			t.Errorf("%v.Add(%v) got %v, want %v", x, y, got, want)
		}
	}
}

func TestFieldElementSub(t *testing.T) {
	p := int64(31)
	x1, _ := NewFieldElementInt(29, p)
	y1, _ := NewFieldElementInt(4, p)
	z1, _ := NewFieldElementInt(25, p)
	x2, _ := NewFieldElementInt(15, p)
	y2, _ := NewFieldElementInt(30, p)
	z2, _ := NewFieldElementInt(16, p)
	tests := []struct {
		x, y, z FieldElement
	}{
		{x1, y1, z1},
		{x2, y2, z2},
	}
	for _, test := range tests {
		x := test.x
		y := test.y
		got, _ := x.Sub(y)
		want := test.z
		if got.Ne(want) {
			t.Errorf("%v.Sub(%v) got %v, want %v", x, y, got, want)
		}
	}
}

func TestFieldElementMul(t *testing.T) {
	p := int64(31)
	x, _ := NewFieldElementInt(24, p)
	y, _ := NewFieldElementInt(19, 31)
	got, _ := x.Mul(y)
	want, _ := NewFieldElementInt(22, p)
	if got.Ne(want) {
		t.Errorf("%v.Mul(%v) got %v, want %v", x, y, got, want)
	}
}

func TestFieldElementPow(t *testing.T) {
	p := int64(31)
	x, _ := NewFieldElementInt(17, p)
	y := big.NewInt(3)
	got := x.Pow(y)
	want, _ := NewFieldElementInt(15, p)
	if got.Ne(want) {
		t.Errorf("%v.Pow(%v) got %v, want %v", x, y, got, want)
	}
	x, _ = NewFieldElementInt(5, p)
	y = big.NewInt(5)
	z, _ := NewFieldElementInt(18, p)
	got, _ = x.Pow(y).Mul(z)
	want, _ = NewFieldElementInt(16, p)
	if got.Ne(want) {
		t.Errorf("%v.Pow(%v.Mul(%v) got %v, want %v", x, y, z, got, want)
	}
}

func TestFieldElementDiv(t *testing.T) {
	p := int64(31)
	x, _ := NewFieldElementInt(3, p)
	y, _ := NewFieldElementInt(24, p)
	got, _ := x.Div(y)
	want, _ := NewFieldElementInt(4, p)
	if got.Ne(want) {
		t.Errorf("%v.Div(%v) got %v, want %v", x, y, got, want)
	}
	x, _ = NewFieldElementInt(17, p)
	exp := big.NewInt(-3)
	got = x.Pow(exp)
	want, _ = NewFieldElementInt(29, p)
	if got.Ne(want) {
		t.Errorf("%v.Pow(%v) got %v, want %v", x, exp, got, want)
	}
	x, _ = NewFieldElementInt(4, p)
	exp = big.NewInt(-4)
	y, _ = NewFieldElementInt(11, p)
	got, _ = x.Pow(exp).Mul(y)
	want, _ = NewFieldElementInt(13, p)
	if got.Ne(want) {
		t.Errorf("%v.Pow(%v).Mul(%v) got %v, want %v", x, exp, y, got, want)
	}
}

func TestPointString(t *testing.T) {
	p := int64(223)
	a, _ := NewFieldElementInt(0, p)
	b, _ := NewFieldElementInt(7, p)
	x, _ := NewFieldElementInt(192, p)
	y, _ := NewFieldElementInt(105, p)
	point, _ := NewPoint(false, x, y, a, b)
	got := point.String()
	want := "Point(192,105)_0_7 FieldElement(223)"
	if got != want {
		t.Errorf("%v.String() got %v, want %v", point, got, want)
	}
}
func TestPointOnCurve(t *testing.T) {
	p := int64(223)
	a, _ := NewFieldElementInt(0, p)
	b, _ := NewFieldElementInt(7, p)
	validPoints := []struct {
		x, y int64
	}{
		{192, 105},
		{17, 56},
		{1, 193},
	}
	for _, xy := range validPoints {
		x, _ := NewFieldElementInt(xy.x, p)
		y, _ := NewFieldElementInt(xy.y, p)
		point, err := NewPoint(false, x, y, a, b)
		if err != nil {
			t.Errorf("%v is not on curve", point)
		}
	}
	invalidPoints := []struct {
		x, y int64
	}{
		{200, 119},
		{42, 99},
	}
	for _, xy := range invalidPoints {
		x, _ := NewFieldElementInt(xy.x, p)
		y, _ := NewFieldElementInt(xy.y, p)
		point, err := NewPoint(false, x, y, a, b)
		if err == nil {
			t.Errorf("%v is on curve", point)
		}
	}
}
func TestPointEq(t *testing.T) {
	p := int64(79)
	x, _ := NewFieldElementInt(18, p)
	y, _ := NewFieldElementInt(77, p)
	a, _ := NewFieldElementInt(5, p)
	b, _ := NewFieldElementInt(7, p)
	point, _ := NewPoint(false, x, y, a, b)
	got := point.Eq(point)
	want := true
	if got != want {
		t.Errorf("%v.Eq(%v) got %v, want %v", x, y, got, want)
	}
}
func TestPointNe(t *testing.T) {
	p := int64(79)
	x, _ := NewFieldElementInt(18, p)
	y, _ := NewFieldElementInt(77, p)
	a, _ := NewFieldElementInt(5, p)
	b, _ := NewFieldElementInt(7, p)
	px, _ := NewPoint(false, x, y, a, b)
	x, _ = NewFieldElementInt(2, p)
	y, _ = NewFieldElementInt(3, p)
	a, _ = NewFieldElementInt(1, p)
	b, _ = NewFieldElementInt(1, p)
	py, _ := NewPoint(false, x, y, a, b)
	got := px.Ne(py)
	want := true
	if got != want {
		t.Errorf("%v.Ne(%v) got %v, want %v", px, py, got, want)
	}
}
func TestPointAdd(t *testing.T) {
	p := int64(223)
	a, _ := NewFieldElementInt(0, p)
	b, _ := NewFieldElementInt(7, p)
	tests := []struct {
		x1, y1, x2, y2, x3, y3 int64
	}{
		{192, 105, 17, 56, 170, 142},
		{170, 142, 60, 139, 220, 181},
		{47, 71, 17, 56, 215, 68},
		{143, 98, 76, 66, 47, 71},
	}
	for _, test := range tests {
		x1, _ := NewFieldElementInt(test.x1, p)
		y1, _ := NewFieldElementInt(test.y1, p)
		px, _ := NewPoint(false, x1, y1, a, b)
		x2, _ := NewFieldElementInt(test.x2, p)
		y2, _ := NewFieldElementInt(test.y2, p)
		py, _ := NewPoint(false, x2, y2, a, b)
		x3, _ := NewFieldElementInt(test.x3, p)
		y3, _ := NewFieldElementInt(test.y3, p)
		got, _ := px.Add(py)
		want, _ := NewPoint(false, x3, y3, a, b)
		if got.Ne(want) {
			t.Errorf("%v.Add(%v) got %v, want %v", px, py, got, want)
		}
	}
}

func TestPointScalarMul(t *testing.T) {
	p := int64(223)
	a, _ := NewFieldElementInt(0, p)
	b, _ := NewFieldElementInt(7, p)
	tests := []struct {
		c, x1, y1, x2, y2 int64
		inf               bool
	}{
		{2, 192, 105, 49, 71, false},
		{2, 143, 98, 64, 168, false},
		{2, 47, 71, 36, 111, false},
		{4, 47, 71, 194, 51, false},
		{8, 47, 71, 116, 55, false},
		{21, 47, 71, 0, 0, true},
	}
	for _, test := range tests {
		c := big.NewInt(test.c)
		x1, _ := NewFieldElementInt(test.x1, p)
		y1, _ := NewFieldElementInt(test.y1, p)
		point, _ := NewPoint(false, x1, y1, a, b)
		got := point.ScalarMul(c)
		x2, _ := NewFieldElementInt(test.x2, p)
		y2, _ := NewFieldElementInt(test.y2, p)
		want, _ := NewPoint(test.inf, x2, y2, a, b)
		if got.Ne(want) {
			t.Errorf("%v.ScalarMul(%v) got %v, want %v", point, c, got, want)
		}
	}
}

func TestS256PointOnCurve(t *testing.T) {
	got := G.ScalarMul(N())
	if !got.Infinity {
		t.Errorf("%v.ScalarMul(%v) got %v, want Infinity", G, N(), got)
	}
}

func TestS256PointVerity(t *testing.T) {
	p, err := NewS256PointString(
		false,
		"887387e452b8eacc4acfde10d9aaf7f6d9a0f975aabb10d006e4da568744d06c",
		"61de6d95231cd89026e286df3b6ae4a894a3378e393e93a0f45b666329a0ae34",
		16,
	)
	if err != nil {
		t.Error(err)
	}
	signs := []struct {
		z, r, s string
	}{
		{
			"ec208baa0fc1c19f708a9ca96fdeff3ac3f230bb4a7ba4aede4942ad003c0f60",
			"ac8d1c87e51d0d441be8b3dd5b05c8795b48875dffe00b7ffcfac23010d3a395",
			"68342ceff8935ededd102dd876ffd6ba72d6a427a3edb13d26eb0781cb423c4",
		},
		{
			"7c076ff316692a3d7eb3c3bb0f8b1488cf72e1afcd929e29307032997a838a3d",
			"eff69ef2b1bd93a66ed5219add4fb51e11a840f404876325a1e8ffe0529a2c",
			"c7207fee197d27c618aea621406f6bf5ef6fca38681d82b2f06fddbdce6feab6",
		},
	}
	for _, sign := range signs {
		sig := NewSignatureString(sign.r, sign.s, 16)
		z := new(big.Int)
		z.SetString(sign.z, 16)
		got := p.Verify(z, sig)
		want := true
		if got != want {
			t.Errorf("%v.Verify(%v, %v) got %v, want %v", sig, z, sig, got, want)
		}
	}
}

func TestSignatureString(t *testing.T) {
	strs := []struct {
		r, s string
	}{
		{
			"ac8d1c87e51d0d441be8b3dd5b05c8795b48875dffe00b7ffcfac23010d3a395",
			"68342ceff8935ededd102dd876ffd6ba72d6a427a3edb13d26eb0781cb423c4",
		},
		{
			"eff69ef2b1bd93a66ed5219add4fb51e11a840f404876325a1e8ffe0529a2c",
			"c7207fee197d27c618aea621406f6bf5ef6fca38681d82b2f06fddbdce6feab6",
		},
	}
	for _, str := range strs {
		sig := NewSignatureString(str.r, str.s, 16)
		got := sig.String()
		want := fmt.Sprintf("Signature(%v,%v)", str.r, str.s)
		if got != want {
			t.Errorf("%v.String() got %v, want %v", sig, got, want)
		}
	}
}

入出力結果(Terminal, Zsh)

% go test
PASS
ok  	bitcoin/ecc	2.119s
% go test -v
=== RUN   TestFieldElementEq
--- PASS: TestFieldElementEq (0.00s)
=== RUN   TestFieldElementNe
--- PASS: TestFieldElementNe (0.00s)
=== RUN   TestFieldElementAdd
--- PASS: TestFieldElementAdd (0.00s)
=== RUN   TestFieldElementSub
--- PASS: TestFieldElementSub (0.00s)
=== RUN   TestFieldElementMul
--- PASS: TestFieldElementMul (0.00s)
=== RUN   TestFieldElementPow
--- PASS: TestFieldElementPow (0.00s)
=== RUN   TestFieldElementDiv
--- PASS: TestFieldElementDiv (0.00s)
=== RUN   TestPointString
--- PASS: TestPointString (0.00s)
=== RUN   TestPointOnCurve
--- PASS: TestPointOnCurve (0.00s)
=== RUN   TestPointEq
--- PASS: TestPointEq (0.00s)
=== RUN   TestPointNe
--- PASS: TestPointNe (0.00s)
=== RUN   TestPointAdd
--- PASS: TestPointAdd (0.00s)
=== RUN   TestPointScalarMul
--- PASS: TestPointScalarMul (0.00s)
=== RUN   TestS256PointOnCurve
--- PASS: TestS256PointOnCurve (0.00s)
=== RUN   TestS256PointVerity
--- PASS: TestS256PointVerity (2.06s)
=== RUN   TestSignatureString
--- PASS: TestSignatureString (0.00s)
PASS
ok  	bitcoin/ecc	2.130s
%