楕円曲線暗号 署名検証の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
%