//go:build (!amd64 && !arm64) || generic32 || generic64 // +build !amd64,!arm64 generic32 generic64 // build when !amd64 AND !arm64 OR generic32 OR generic64 package ec256 import ( crand "crypto/rand" "fmt" "math/big" "math/rand" "testing" "time" ) func BenchmarkScalarMultc256(b *testing.B) { b.ResetTimer() // _, x, y, _ := elliptic.GenerateKey(c256, rand.Reader) // priv, _, _, _ := elliptic.GenerateKey(c256, rand.Reader) priv, _ := new(big.Int).SetString("115792089210356248762697446949407573529996955224135760342422259061068512044369", 10) bb := priv.Bytes() b.ReportAllocs() b.StartTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { // c256.ScalarMult(c256.Gx, c256.Gy, bb) c256.ScalarBaseMult(bb) } }) } func TestPointMul(t *testing.T) { priv, _ := new(big.Int).SetString("115792089210356248762697446949407573529996955224135760342422259061068512044369", 10) bb := priv.Bytes() cnt := 5000 start := time.Now() for i := 0; i < cnt; i++ { // c256.ScalarMult(c256.Gx, c256.Gy, bb) c256.ScalarBaseMult(bb) } end := time.Now() elapsed := end.Sub(start) fmt.Printf("SM2 Scalar Mul Point: %d PerSec\n", int(float64(cnt)/elapsed.Seconds())) } func TestReduceCarry(t *testing.T) { // fmt.Printf("%08x\n", 1<<29-1-2<<21) var inout [c256Limbs]uint32 var temp [c256Limbs]uint32 rnd := rand.New(rand.NewSource(time.Now().UnixNano())) for i := 0; i < c256Limbs; i++ { temp[i] = uint32(rnd.Int31()) & 0xFFFFFFF inout[i] = temp[i] } var carry uint32 = 5 c256ReduceCarry(&inout, carry) // for _, n := range inout { // fmt.Printf("0x%08x, ", n) // } ret := c256ToBig(&inout) fmt.Println(ret.Text(16)) s := c256ToBig(&temp) r := big.NewInt(int64(carry)) r.Lsh(r, 257) s.Add(s, r) s.Mod(s, c256.P) // c256FromBig(&inout, s) fmt.Println(s.Text(16)) // c256FromBig(&inout, s) // for _, n := range inout { // fmt.Printf("0x%08x, ", n) // } ret.Sub(ret, s) fmt.Println(ret) } func TestReduceDegree(t *testing.T) { for j := uint64(0); j < 100000000; j++ { if j%1000000 == 0 { fmt.Println(j/10000, "万次pass") } var in [c256Limbs]uint32 //= [c256Limbs]uint32{0x1604a25, 0x6d1db34, 0x140458b9, 0xd3371b7, 0x79446ec, 0xd2bca28, 0xb98f19b, 0xc227f7c, 0xcaed5c} var out [c256Limbs]uint32 var temp [c256Limbs]uint32 //= [c256Limbs]uint32{0xdb99003, 0x964a8c3, 0x1f7dc5a9, 0xc9db569, 0x1893e838, 0xeecb116, 0xca9ff4f, 0x68bd063, 0x11e538bf} rnd := rand.New(rand.NewSource(time.Now().UnixNano())) for i := 0; i < c256Limbs; i++ { if i%2 == 0 { temp[i] = uint32(rnd.Int()) & 0x1FFFFFFF } else { temp[i] = uint32(rnd.Int()) & 0xFFFFFFF } // fmt.Printf("0x%x,", temp[i]) } for i := 0; i < c256Limbs; i++ { if i%2 == 0 { in[i] = uint32(rnd.Int31()) & 0x1FFFFFFF } else { in[i] = uint32(rnd.Int31()) & 0xFFFFFFF } // fmt.Printf("0x%x,", in[i]) } ret := c256ToBig(&temp) // fmt.Println("a:= ", ret.Text(16)) // ret = c256ToBig(&in) // fmt.Println("b:= ", ret.Text(16)) c256Mul(&out, &in, &temp) ret = c256ToBig(&out) ret.Mod(ret, c256.P) // fmt.Println("a*b=", ret.Text(16)) s := c256ToBig(&temp) s.Mul(s, c256ToBig(&in)) s.Mul(s, c256RInverse) s.Mod(s, c256.P) // ret.Mod(ret, c256.P) if ret.Cmp(s) != 0 { fmt.Println("failed") fmt.Println(ret.Text(16)) fmt.Println(s.Text(16)) fmt.Println("in:", in) fmt.Println("temp:", temp) fmt.Println("diff:", ret.Sub(ret, s).Text(16)) return } // ret.Sub(ret, s) // fmt.Println("?0=", ret.Text(16)) } fmt.Println("test over") } func TestInverse(t *testing.T) { for i := 0; i < 100000; i++ { if i%10000 == 0 { fmt.Println(i, "pass") } var in [c256Limbs]uint32 //= [c256Limbs]uint32{0x1604a25, 0x6d1db34, 0x140458b9, 0xd3371b7, 0x79446ec, 0xd2bca28, 0xb98f19b, 0xc227f7c, 0xcaed5c} var out [c256Limbs]uint32 rnd := rand.New(rand.NewSource(time.Now().UnixNano())) for i := 0; i < c256Limbs; i++ { if i%2 == 0 { in[i] = uint32(rnd.Int()) & 0x1FFFFFFF } else { in[i] = uint32(rnd.Int()) & 0xFFFFFFF } // fmt.Printf("0x%x,", temp[i]) } c256Invert(&out, &in) // in^(-1)*R outInt := c256ToBig(&out) outInt.Mod(outInt, c256.P) // fmt.Println(outInt.Text(16)) inInt := c256ToBig(&in) // in * R inInt.ModInverse(inInt, c256.P) // (in*R)^-1 inInt.Lsh(inInt, 257+257) // in^-1 * R inInt.Mod(inInt, c256.P) // fmt.Println(inInt.Text(16)) if inInt.Cmp(outInt) != 0 { fmt.Println("Failed") fmt.Println(in) fmt.Println(new(big.Int).Sub(inInt, outInt).Text(16)) return } } } func TestGenTable32(t *testing.T) { // Index | Index (binary) | Value // 0 | 0000 | 0G (all zeros, omitted) // 1 | 0001 | G // 2 | 0010 | 2**64G // 3 | 0011 | 2**64G + G // 4 | 0100 | 2**128G // 5 | 0101 | 2**128G + G // 6 | 0110 | 2**128G + 2**64G // 7 | 0111 | 2**128G + 2**64G + G // 8 | 1000 | 2**192G // 9 | 1001 | 2**192G + G // 10 | 1010 | 2**192G + 2**64G // 11 | 1011 | 2**192G + 2**64G + G // 12 | 1100 | 2**192G + 2**128G // 13 | 1101 | 2**192G + 2**128G + G // 14 | 1110 | 2**192G + 2**128G + 2**64G // 15 | 1111 | 2**192G + 2**128G + 2**64G + G // // The second table follows the same style, but the terms are 2**32G, // 2**96G, 2**160G, 2**224G. for i := 1; i < 16; i++ { n := new(big.Int) one := new(big.Int).SetInt64(1) if i&0x08 > 0 { n.Add(new(big.Int).SetInt64(1).Lsh(one, 192), n) } if i&0x04 > 0 { n.Add(new(big.Int).SetInt64(1).Lsh(one, 128), n) } if i&0x02 > 0 { n.Add(new(big.Int).SetInt64(1).Lsh(one, 64), n) } if i&0x01 > 0 { n.Add(one, n) } // fmt.Println(n.Text(16)) x, y := c256.ScalarMult(c256.Gx, c256.Gy, n.Bytes()) var xOut, yOut [c256Limbs]uint32 c256FromBig(&xOut, x) c256FromBig(&yOut, y) for _, i := range xOut { fmt.Printf("0x%x, ", i) } fmt.Println() for _, i := range yOut { fmt.Printf("0x%x, ", i) } fmt.Println() } for i := 1; i < 16; i++ { n := new(big.Int) one := new(big.Int).SetInt64(1) if i&0x08 > 0 { n.Add(new(big.Int).SetInt64(1).Lsh(one, 224), n) } if i&0x04 > 0 { n.Add(new(big.Int).SetInt64(1).Lsh(one, 160), n) } if i&0x02 > 0 { n.Add(new(big.Int).SetInt64(1).Lsh(one, 96), n) } if i&0x01 > 0 { n.Add(new(big.Int).SetInt64(1).Lsh(one, 32), n) } // fmt.Println(n.Text(16)) x, y := c256.ScalarMult(c256.Gx, c256.Gy, n.Bytes()) var xOut, yOut [c256Limbs]uint32 c256FromBig(&xOut, x) c256FromBig(&yOut, y) for _, i := range xOut { fmt.Printf("0x%x, ", i) } fmt.Println() for _, i := range yOut { fmt.Printf("0x%x, ", i) } fmt.Println() } } // c256FromBig sets out = R*in. func c256FromBig64(out *[5]uint64, in *big.Int) { var bottom51Bits uint64 = 1<<51 - 1 var bottom52Bits uint64 = 1<<52 - 1 tmp := new(big.Int).Lsh(in, 257) tmp.Mod(tmp, c256.P) for i := 0; i < 5; i++ { if bits := tmp.Bits(); len(bits) > 0 { out[i] = uint64(bits[0]) & bottom51Bits } else { out[i] = 0 } tmp.Rsh(tmp, 51) i++ if i == 5 { break } if bits := tmp.Bits(); len(bits) > 0 { out[i] = uint64(bits[0]) & bottom52Bits } else { out[i] = 0 } tmp.Rsh(tmp, 52) } } func TestGenTable64(t *testing.T) { // Index | Index (binary) | Value // 0 | 0000 | 0G (all zeros, omitted) // 1 | 0001 | G // 2 | 0010 | 2**64G // 3 | 0011 | 2**64G + G // 4 | 0100 | 2**128G // 5 | 0101 | 2**128G + G // 6 | 0110 | 2**128G + 2**64G // 7 | 0111 | 2**128G + 2**64G + G // 8 | 1000 | 2**192G // 9 | 1001 | 2**192G + G // 10 | 1010 | 2**192G + 2**64G // 11 | 1011 | 2**192G + 2**64G + G // 12 | 1100 | 2**192G + 2**128G // 13 | 1101 | 2**192G + 2**128G + G // 14 | 1110 | 2**192G + 2**128G + 2**64G // 15 | 1111 | 2**192G + 2**128G + 2**64G + G // // The second table follows the same style, but the terms are 2**32G, // 2**96G, 2**160G, 2**224G. for i := 1; i < 16; i++ { n := new(big.Int) one := new(big.Int).SetInt64(1) if i&0x08 > 0 { n.Add(new(big.Int).SetInt64(1).Lsh(one, 192), n) } if i&0x04 > 0 { n.Add(new(big.Int).SetInt64(1).Lsh(one, 128), n) } if i&0x02 > 0 { n.Add(new(big.Int).SetInt64(1).Lsh(one, 64), n) } if i&0x01 > 0 { n.Add(one, n) } // fmt.Println(n.Text(16)) x, y := c256.ScalarMult(c256.Gx, c256.Gy, n.Bytes()) var xOut, yOut [5]uint64 c256FromBig64(&xOut, x) c256FromBig64(&yOut, y) for _, i := range xOut { fmt.Printf("0x%xLLU, ", i) } fmt.Println() for _, i := range yOut { fmt.Printf("0x%xLLU, ", i) } fmt.Println() } for i := 1; i < 16; i++ { n := new(big.Int) one := new(big.Int).SetInt64(1) if i&0x08 > 0 { n.Add(new(big.Int).SetInt64(1).Lsh(one, 224), n) } if i&0x04 > 0 { n.Add(new(big.Int).SetInt64(1).Lsh(one, 160), n) } if i&0x02 > 0 { n.Add(new(big.Int).SetInt64(1).Lsh(one, 96), n) } if i&0x01 > 0 { n.Add(new(big.Int).SetInt64(1).Lsh(one, 32), n) } // fmt.Println(n.Text(16)) x, y := c256.ScalarMult(c256.Gx, c256.Gy, n.Bytes()) var xOut, yOut [5]uint64 c256FromBig64(&xOut, x) c256FromBig64(&yOut, y) for _, i := range xOut { fmt.Printf("0x%xLLU, ", i) } fmt.Println() for _, i := range yOut { fmt.Printf("0x%xLLU, ", i) } fmt.Println() } } func TestPointMul2(t *testing.T) { n, _ := crand.Int(crand.Reader, c256.N) n.SetInt64(4) //n.Set(c256.N) //n.Sub(n, gmath.BigInt1) //x, y := c256.ScalarBaseMult(n.Bytes()) //fmt.Println(x.Text(16), y.Text(16)) // n.Set(c256.N) //xx, yy := c256.ScalarMult(c256.Gx, c256.Gy, n.Bytes()) xx, yy := c256.ScalarBaseMult(n.Bytes()) fmt.Println(xx.Text(16), yy.Text(16)) //fmt.Println(xx.Text(16), yy.Text(16)) // p := c256ToBig(&c256Zero31) // fmt.Println(p.Text(16)) } // FIXME c256ScalarBaseMult error when scalar = 0 func TestZeroScaleBaseMult(t *testing.T) { n := new(big.Int) var scalarReversed [32]byte for i := 0; i < 32; i++ { scalarReversed[i] = 0xcc } c256GetScalar(&scalarReversed, n.Bytes()) var x1, y1, z1 [c256Limbs]uint32 var tmp [17]uint64 c256PointDouble(&x1, &y1, &z1, &x1, &y1, &z1) c256ReduceDegree(&z1, tmp) c256ScalarBaseMult(&x1, &y1, &z1, &scalarReversed) for _, z := range z1 { if z != 0 { t.Fail() } } } func TestReduce(t *testing.T) { var tmp = [17]uint64{1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1} var out [9]uint32 c256ReduceDegree(&out, tmp) for i := 0; i < 9; i++ { fmt.Println(out[i]) } } func TestIssue52075(t *testing.T) { Gx, Gy := c256.Params().Gx, c256.Params().Gy scalar := make([]byte, 33) scalar[32] = 1 x, y := c256.ScalarBaseMult(scalar) if x.Cmp(Gx) != 0 || y.Cmp(Gy) != 0 { t.Errorf("unexpected output (%v,%v)", x, y) } x, y = c256.ScalarMult(Gx, Gy, scalar) if x.Cmp(Gx) != 0 || y.Cmp(Gy) != 0 { t.Errorf("unexpected output (%v,%v)", x, y) } }