From 81c0dbb0faf7dd21de9daca7cb2f0e0c64e7cfe8 Mon Sep 17 00:00:00 2001 From: Sun Yimin Date: Thu, 16 Jun 2022 10:14:45 +0800 Subject: [PATCH] SM9: refactoring, move separate SM9 & bn256 --- sm9/README.md | 5 +- sm9/bn256/README.md | 4 + sm9/{ => bn256}/bn_pair.go | 2 +- sm9/{ => bn256}/bn_pair_test.go | 2 +- sm9/{ => bn256}/constants.go | 2 +- sm9/{ => bn256}/curve.go | 2 +- sm9/{ => bn256}/elliptic.go | 2 +- sm9/{ => bn256}/g1.go | 16 +++- sm9/{ => bn256}/g1_test.go | 2 +- sm9/{ => bn256}/g2.go | 16 +++- sm9/{ => bn256}/g2_test.go | 2 +- sm9/{ => bn256}/gfp.go | 2 +- sm9/{ => bn256}/gfp12.go | 2 +- sm9/{ => bn256}/gfp12_test.go | 2 +- sm9/{ => bn256}/gfp2.go | 2 +- sm9/{ => bn256}/gfp2_test.go | 2 +- sm9/{ => bn256}/gfp4.go | 2 +- sm9/{ => bn256}/gfp4_test.go | 2 +- sm9/{ => bn256}/gfp_amd64.s | 0 sm9/{ => bn256}/gfp_arm64.s | 0 sm9/{ => bn256}/gfp_decl.go | 2 +- sm9/{ => bn256}/gfp_generic.go | 2 +- sm9/{ => bn256}/gfp_test.go | 2 +- sm9/{ => bn256}/gt.go | 61 ++++++++++++-- sm9/{ => bn256}/gt_test.go | 2 +- sm9/{ => bn256}/mul_amd64.h | 0 sm9/{ => bn256}/mul_arm64.h | 0 sm9/{ => bn256}/mul_bmi2_amd64.h | 0 sm9/{ => bn256}/params.go | 2 +- sm9/{ => bn256}/params_test.go | 2 +- sm9/{ => bn256}/twist.go | 2 +- sm9/{ => bn256}/twist_test.go | 2 +- sm9/sm9.go | 139 +++++++------------------------ sm9/sm9_key.go | 57 ++++++------- sm9/sm9_key_test.go | 14 +--- sm9/sm9_test.go | 31 ++++--- 36 files changed, 196 insertions(+), 191 deletions(-) create mode 100644 sm9/bn256/README.md rename sm9/{ => bn256}/bn_pair.go (95%) rename sm9/{ => bn256}/bn_pair_test.go (97%) rename sm9/{ => bn256}/constants.go (97%) rename sm9/{ => bn256}/curve.go (95%) rename sm9/{ => bn256}/elliptic.go (96%) rename sm9/{ => bn256}/g1.go (93%) rename sm9/{ => bn256}/g1_test.go (96%) rename sm9/{ => bn256}/g2.go (92%) rename sm9/{ => bn256}/g2_test.go (94%) rename sm9/{ => bn256}/gfp.go (99%) rename sm9/{ => bn256}/gfp12.go (95%) rename sm9/{ => bn256}/gfp12_test.go (96%) rename sm9/{ => bn256}/gfp2.go (94%) rename sm9/{ => bn256}/gfp2_test.go (95%) rename sm9/{ => bn256}/gfp4.go (94%) rename sm9/{ => bn256}/gfp4_test.go (96%) rename sm9/{ => bn256}/gfp_amd64.s (100%) rename sm9/{ => bn256}/gfp_arm64.s (100%) rename sm9/{ => bn256}/gfp_decl.go (97%) rename sm9/{ => bn256}/gfp_generic.go (99%) rename sm9/{ => bn256}/gfp_test.go (96%) rename sm9/{ => bn256}/gt.go (72%) rename sm9/{ => bn256}/gt_test.go (92%) rename sm9/{ => bn256}/mul_amd64.h (100%) rename sm9/{ => bn256}/mul_arm64.h (100%) rename sm9/{ => bn256}/mul_bmi2_amd64.h (100%) rename sm9/{ => bn256}/params.go (95%) rename sm9/{ => bn256}/params_test.go (97%) rename sm9/{ => bn256}/twist.go (95%) rename sm9/{ => bn256}/twist_test.go (95%) diff --git a/sm9/README.md b/sm9/README.md index 6143cfe..f19a4ed 100644 --- a/sm9/README.md +++ b/sm9/README.md @@ -1,7 +1,4 @@ -This part codes mainly refer two projects: - -1. [bn256](https://github.com/cloudflare/bn256), 主要是基域运算 -2. [gmssl sm9](https://github.com/guanzhi/GmSSL/blob/develop/src/sm9_alg.c),主要是2-4-12塔式扩域,以及r-ate等 +SM9 current performance: **SM9 Sign Benchmark** diff --git a/sm9/bn256/README.md b/sm9/bn256/README.md new file mode 100644 index 0000000..b7a27cf --- /dev/null +++ b/sm9/bn256/README.md @@ -0,0 +1,4 @@ +This part codes mainly refer two projects: + +1. [bn256](https://github.com/cloudflare/bn256), 主要是基域运算 +2. [gmssl sm9](https://github.com/guanzhi/GmSSL/blob/develop/src/sm9_alg.c),主要是2-4-12塔式扩域,以及r-ate等 diff --git a/sm9/bn_pair.go b/sm9/bn256/bn_pair.go similarity index 95% rename from sm9/bn_pair.go rename to sm9/bn256/bn_pair.go index 6a6737a..9c58699 100644 --- a/sm9/bn_pair.go +++ b/sm9/bn256/bn_pair.go @@ -1,4 +1,4 @@ -package sm9 +package bn256 import ( "math/big" diff --git a/sm9/bn_pair_test.go b/sm9/bn256/bn_pair_test.go similarity index 97% rename from sm9/bn_pair_test.go rename to sm9/bn256/bn_pair_test.go index c45b707..8a2e850 100644 --- a/sm9/bn_pair_test.go +++ b/sm9/bn256/bn_pair_test.go @@ -1,4 +1,4 @@ -package sm9 +package bn256 import ( "math/big" diff --git a/sm9/constants.go b/sm9/bn256/constants.go similarity index 97% rename from sm9/constants.go rename to sm9/bn256/constants.go index 0b59dce..7838d07 100644 --- a/sm9/constants.go +++ b/sm9/bn256/constants.go @@ -1,4 +1,4 @@ -package sm9 +package bn256 // u is the BN parameter that determines the prime: 600000000058f98a. var u = bigFromHex("600000000058f98a") diff --git a/sm9/curve.go b/sm9/bn256/curve.go similarity index 95% rename from sm9/curve.go rename to sm9/bn256/curve.go index 91f0e3e..ce0ca7b 100644 --- a/sm9/curve.go +++ b/sm9/bn256/curve.go @@ -1,4 +1,4 @@ -package sm9 +package bn256 import ( "crypto/subtle" diff --git a/sm9/elliptic.go b/sm9/bn256/elliptic.go similarity index 96% rename from sm9/elliptic.go rename to sm9/bn256/elliptic.go index 85faafd..e09c366 100644 --- a/sm9/elliptic.go +++ b/sm9/bn256/elliptic.go @@ -1,4 +1,4 @@ -package sm9 +package bn256 import ( "io" diff --git a/sm9/g1.go b/sm9/bn256/g1.go similarity index 93% rename from sm9/g1.go rename to sm9/bn256/g1.go index 76ae8db..c846dfd 100644 --- a/sm9/g1.go +++ b/sm9/bn256/g1.go @@ -1,4 +1,4 @@ -package sm9 +package bn256 import ( "crypto/rand" @@ -333,6 +333,20 @@ func (e *G1) Unmarshal(m []byte) ([]byte, error) { return m[2*numBytes:], nil } +func (e *G1) Equal(other *G1) bool { + if e.p == nil && other.p == nil { + return true + } + return e.p.x == other.p.x && + e.p.y == other.p.y && + e.p.z == other.p.z && + e.p.t == other.p.t +} + +func (e *G1) IsOnCurve() bool { + return e.p.IsOnCurve() +} + type G1Curve struct { params *CurveParams g G1 diff --git a/sm9/g1_test.go b/sm9/bn256/g1_test.go similarity index 96% rename from sm9/g1_test.go rename to sm9/bn256/g1_test.go index 42139f0..a27d625 100644 --- a/sm9/g1_test.go +++ b/sm9/bn256/g1_test.go @@ -1,4 +1,4 @@ -package sm9 +package bn256 import ( "crypto/rand" diff --git a/sm9/g2.go b/sm9/bn256/g2.go similarity index 92% rename from sm9/g2.go rename to sm9/bn256/g2.go index 4e96e15..2753624 100644 --- a/sm9/g2.go +++ b/sm9/bn256/g2.go @@ -1,4 +1,4 @@ -package sm9 +package bn256 import ( "errors" @@ -317,3 +317,17 @@ func (e *G2) Unmarshal(m []byte) ([]byte, error) { } return m[4*numBytes:], nil } + +func (e *G2) Equal(other *G2) bool { + if e.p == nil && other.p == nil { + return true + } + return e.p.x == other.p.x && + e.p.y == other.p.y && + e.p.z == other.p.z && + e.p.t == other.p.t +} + +func (e *G2) IsOnCurve() bool { + return e.p.IsOnCurve() +} diff --git a/sm9/g2_test.go b/sm9/bn256/g2_test.go similarity index 94% rename from sm9/g2_test.go rename to sm9/bn256/g2_test.go index 7a5b2aa..e80603f 100644 --- a/sm9/g2_test.go +++ b/sm9/bn256/g2_test.go @@ -1,4 +1,4 @@ -package sm9 +package bn256 import ( "bytes" diff --git a/sm9/gfp.go b/sm9/bn256/gfp.go similarity index 99% rename from sm9/gfp.go rename to sm9/bn256/gfp.go index a9370ca..83e2fd4 100644 --- a/sm9/gfp.go +++ b/sm9/bn256/gfp.go @@ -1,4 +1,4 @@ -package sm9 +package bn256 import ( "crypto/sha256" diff --git a/sm9/gfp12.go b/sm9/bn256/gfp12.go similarity index 95% rename from sm9/gfp12.go rename to sm9/bn256/gfp12.go index 0ef3b48..fe59547 100644 --- a/sm9/gfp12.go +++ b/sm9/bn256/gfp12.go @@ -1,4 +1,4 @@ -package sm9 +package bn256 import "math/big" diff --git a/sm9/gfp12_test.go b/sm9/bn256/gfp12_test.go similarity index 96% rename from sm9/gfp12_test.go rename to sm9/bn256/gfp12_test.go index 2d9b6ac..df653a1 100644 --- a/sm9/gfp12_test.go +++ b/sm9/bn256/gfp12_test.go @@ -1,4 +1,4 @@ -package sm9 +package bn256 import ( "math/big" diff --git a/sm9/gfp2.go b/sm9/bn256/gfp2.go similarity index 94% rename from sm9/gfp2.go rename to sm9/bn256/gfp2.go index 6c2c371..831c5f7 100644 --- a/sm9/gfp2.go +++ b/sm9/bn256/gfp2.go @@ -1,4 +1,4 @@ -package sm9 +package bn256 import ( "math/big" diff --git a/sm9/gfp2_test.go b/sm9/bn256/gfp2_test.go similarity index 95% rename from sm9/gfp2_test.go rename to sm9/bn256/gfp2_test.go index 20f4bf2..cbac3c0 100644 --- a/sm9/gfp2_test.go +++ b/sm9/bn256/gfp2_test.go @@ -1,4 +1,4 @@ -package sm9 +package bn256 import ( "math/big" diff --git a/sm9/gfp4.go b/sm9/bn256/gfp4.go similarity index 94% rename from sm9/gfp4.go rename to sm9/bn256/gfp4.go index 5f4a99e..f60ed7f 100644 --- a/sm9/gfp4.go +++ b/sm9/bn256/gfp4.go @@ -1,4 +1,4 @@ -package sm9 +package bn256 import "math/big" diff --git a/sm9/gfp4_test.go b/sm9/bn256/gfp4_test.go similarity index 96% rename from sm9/gfp4_test.go rename to sm9/bn256/gfp4_test.go index fd16eae..9232eac 100644 --- a/sm9/gfp4_test.go +++ b/sm9/bn256/gfp4_test.go @@ -1,4 +1,4 @@ -package sm9 +package bn256 import ( "math/big" diff --git a/sm9/gfp_amd64.s b/sm9/bn256/gfp_amd64.s similarity index 100% rename from sm9/gfp_amd64.s rename to sm9/bn256/gfp_amd64.s diff --git a/sm9/gfp_arm64.s b/sm9/bn256/gfp_arm64.s similarity index 100% rename from sm9/gfp_arm64.s rename to sm9/bn256/gfp_arm64.s diff --git a/sm9/gfp_decl.go b/sm9/bn256/gfp_decl.go similarity index 97% rename from sm9/gfp_decl.go rename to sm9/bn256/gfp_decl.go index 4a8621c..652089d 100644 --- a/sm9/gfp_decl.go +++ b/sm9/bn256/gfp_decl.go @@ -1,7 +1,7 @@ //go:build (amd64 && !generic) || (arm64 && !generic) // +build amd64,!generic arm64,!generic -package sm9 +package bn256 // This file contains forward declarations for the architecture-specific // assembly implementations of these functions, provided that they exist. diff --git a/sm9/gfp_generic.go b/sm9/bn256/gfp_generic.go similarity index 99% rename from sm9/gfp_generic.go rename to sm9/bn256/gfp_generic.go index 87b42c3..aa26de9 100644 --- a/sm9/gfp_generic.go +++ b/sm9/bn256/gfp_generic.go @@ -1,7 +1,7 @@ //go:build !amd64 && !arm64 || generic // +build !amd64,!arm64 generic -package sm9 +package bn256 func gfpCarry(a *gfP, head uint64) { b := &gfP{} diff --git a/sm9/gfp_test.go b/sm9/bn256/gfp_test.go similarity index 96% rename from sm9/gfp_test.go rename to sm9/bn256/gfp_test.go index a3b096f..a6583c1 100644 --- a/sm9/gfp_test.go +++ b/sm9/bn256/gfp_test.go @@ -1,4 +1,4 @@ -package sm9 +package bn256 import ( "encoding/hex" diff --git a/sm9/gt.go b/sm9/bn256/gt.go similarity index 72% rename from sm9/gt.go rename to sm9/bn256/gt.go index eac5b48..ae5e5c1 100644 --- a/sm9/gt.go +++ b/sm9/bn256/gt.go @@ -1,4 +1,4 @@ -package sm9 +package bn256 import ( "crypto/subtle" @@ -92,7 +92,7 @@ func (e *GT) SetOne() *GT { e.p = &gfP12{} } e.p.SetOne() - return e + return e } // Finalize is a linear function from F_p^12 to GT. @@ -208,16 +208,16 @@ func (e *GT) Unmarshal(m []byte) ([]byte, error) { return m[12*numBytes:], nil } -// A gtPointTable holds the first 15 Exp of a value at offset -1, so P +// A GTFieldTable holds the first 15 Exp of a value at offset -1, so P // is at table[0], P^15 is at table[14], and P^0 is implicitly the identity // point. -type gtTable [15]*GT +type GTFieldTable [15]*GT // Select selects the n-th multiple of the table base point into p. It works in // constant time by iterating over every entry of the table. n must be in [0, 15]. -func (table *gtTable) Select(p *GT, n uint8) { +func (table *GTFieldTable) Select(p *GT, n uint8) { if n >= 16 { - panic("sm9: internal error: gtTable called with out-of-bounds value") + panic("sm9: internal error: GTFieldTable called with out-of-bounds value") } p.p.SetOne() for i := uint8(1); i < 16; i++ { @@ -225,3 +225,52 @@ func (table *gtTable) Select(p *GT, n uint8) { p.p.Select(table[i-1].p, p.p, cond) } } + +func GenerateGTFieldTable(basePoint *GT) *[32 * 2]GTFieldTable { + table := new([32 * 2]GTFieldTable) + base := >{} + base.Set(basePoint) + for i := 0; i < 32*2; i++ { + table[i][0] = >{} + table[i][0].Set(base) + for j := 1; j < 15; j += 2 { + table[i][j] = >{} + table[i][j].p = &gfP12{} + table[i][j].p.Square(table[i][j/2].p) + table[i][j+1] = >{} + table[i][j+1].p = &gfP12{} + table[i][j+1].Add(table[i][j], base) + } + base.p.Square(base.p) + base.p.Square(base.p) + base.p.Square(base.p) + base.p.Square(base.p) + } + return table +} + +// ScalarBaseMultGT compute basepoint^r with precomputed table +func ScalarBaseMultGT(tables *[32 * 2]GTFieldTable, r *big.Int) *GT { + scalar := normalizeScalar(r.Bytes()) + // This is also a scalar multiplication with a four-bit window like in + // ScalarMult, but in this case the doublings are precomputed. The value + // [windowValue]G added at iteration k would normally get doubled + // (totIterations-k)×4 times, but with a larger precomputation we can + // instead add [2^((totIterations-k)×4)][windowValue]G and avoid the + // doublings between iterations. + e, t := >{}, >{} + tableIndex := len(tables) - 1 + e.SetOne() + t.SetOne() + for _, byte := range scalar { + windowValue := byte >> 4 + tables[tableIndex].Select(t, windowValue) + e.Add(e, t) + tableIndex-- + windowValue = byte & 0b1111 + tables[tableIndex].Select(t, windowValue) + e.Add(e, t) + tableIndex-- + } + return e +} diff --git a/sm9/gt_test.go b/sm9/bn256/gt_test.go similarity index 92% rename from sm9/gt_test.go rename to sm9/bn256/gt_test.go index bd44c80..eb2a057 100644 --- a/sm9/gt_test.go +++ b/sm9/bn256/gt_test.go @@ -1,4 +1,4 @@ -package sm9 +package bn256 import ( "bytes" diff --git a/sm9/mul_amd64.h b/sm9/bn256/mul_amd64.h similarity index 100% rename from sm9/mul_amd64.h rename to sm9/bn256/mul_amd64.h diff --git a/sm9/mul_arm64.h b/sm9/bn256/mul_arm64.h similarity index 100% rename from sm9/mul_arm64.h rename to sm9/bn256/mul_arm64.h diff --git a/sm9/mul_bmi2_amd64.h b/sm9/bn256/mul_bmi2_amd64.h similarity index 100% rename from sm9/mul_bmi2_amd64.h rename to sm9/bn256/mul_bmi2_amd64.h diff --git a/sm9/params.go b/sm9/bn256/params.go similarity index 95% rename from sm9/params.go rename to sm9/bn256/params.go index 91c2e4a..db9f9c1 100644 --- a/sm9/params.go +++ b/sm9/bn256/params.go @@ -1,4 +1,4 @@ -package sm9 +package bn256 import "math/big" diff --git a/sm9/params_test.go b/sm9/bn256/params_test.go similarity index 97% rename from sm9/params_test.go rename to sm9/bn256/params_test.go index fcab8f3..51722af 100644 --- a/sm9/params_test.go +++ b/sm9/bn256/params_test.go @@ -1,4 +1,4 @@ -package sm9 +package bn256 import ( "encoding/hex" diff --git a/sm9/twist.go b/sm9/bn256/twist.go similarity index 95% rename from sm9/twist.go rename to sm9/bn256/twist.go index 4a83923..01544fb 100644 --- a/sm9/twist.go +++ b/sm9/bn256/twist.go @@ -1,4 +1,4 @@ -package sm9 +package bn256 import ( "crypto/subtle" diff --git a/sm9/twist_test.go b/sm9/bn256/twist_test.go similarity index 95% rename from sm9/twist_test.go rename to sm9/bn256/twist_test.go index 3eb4fad..d438c78 100644 --- a/sm9/twist_test.go +++ b/sm9/bn256/twist_test.go @@ -1,4 +1,4 @@ -package sm9 +package bn256 import ( "testing" diff --git a/sm9/sm9.go b/sm9/sm9.go index 419750a..fe5e4a4 100644 --- a/sm9/sm9.go +++ b/sm9/sm9.go @@ -12,6 +12,7 @@ import ( "github.com/emmansun/gmsm/internal/xor" "github.com/emmansun/gmsm/sm3" + "github.com/emmansun/gmsm/sm9/bn256" "golang.org/x/crypto/cryptobyte" "golang.org/x/crypto/cryptobyte/asn1" ) @@ -56,7 +57,7 @@ func hash(z []byte, h hashMode) *big.Int { md.Reset() } k := new(big.Int).SetBytes(ha[:40]) - n := new(big.Int).Sub(Order, bigOne) + n := new(big.Int).Sub(bn256.Order, bigOne) k.Mod(k, n) k.Add(k, bigOne) return k @@ -80,75 +81,36 @@ func randFieldElement(rand io.Reader) (k *big.Int, err error) { } k = new(big.Int).SetBytes(b) - n := new(big.Int).Sub(Order, bigOne) + n := new(big.Int).Sub(bn256.Order, bigOne) k.Mod(k, n) k.Add(k, bigOne) return } // Pair generate the basepoint once -func (pub *SignMasterPublicKey) Pair() *GT { +func (pub *SignMasterPublicKey) Pair() *bn256.GT { pub.pairOnce.Do(func() { - pub.basePoint = Pair(Gen1, pub.MasterPublicKey) + pub.basePoint = bn256.Pair(bn256.Gen1, pub.MasterPublicKey) }) return pub.basePoint } -func (pub *SignMasterPublicKey) generatorTable() *[32 * 2]gtTable { +func (pub *SignMasterPublicKey) generatorTable() *[32 * 2]bn256.GTFieldTable { pub.tableGenOnce.Do(func() { - pub.table = new([32 * 2]gtTable) - base := >{} - base.Set(pub.Pair()) - for i := 0; i < 32*2; i++ { - pub.table[i][0] = >{} - pub.table[i][0].Set(base) - for j := 1; j < 15; j += 2 { - pub.table[i][j] = >{} - pub.table[i][j].p = &gfP12{} - pub.table[i][j].p.Square(pub.table[i][j/2].p) - pub.table[i][j+1] = >{} - pub.table[i][j+1].p = &gfP12{} - pub.table[i][j+1].Add(pub.table[i][j], base) - } - base.p.Square(base.p) - base.p.Square(base.p) - base.p.Square(base.p) - base.p.Square(base.p) - } + pub.table = bn256.GenerateGTFieldTable(pub.Pair()) }) return pub.table } // ScalarBaseMult compute basepoint^r with precomputed table -func (pub *SignMasterPublicKey) ScalarBaseMult(r *big.Int) *GT { - scalar := normalizeScalar(r.Bytes()) +func (pub *SignMasterPublicKey) ScalarBaseMult(r *big.Int) *bn256.GT { tables := pub.generatorTable() - // This is also a scalar multiplication with a four-bit window like in - // ScalarMult, but in this case the doublings are precomputed. The value - // [windowValue]G added at iteration k would normally get doubled - // (totIterations-k)×4 times, but with a larger precomputation we can - // instead add [2^((totIterations-k)×4)][windowValue]G and avoid the - // doublings between iterations. - e, t := >{}, >{} - tableIndex := len(tables) - 1 - e.SetOne() - t.SetOne() - for _, byte := range scalar { - windowValue := byte >> 4 - tables[tableIndex].Select(t, windowValue) - e.Add(e, t) - tableIndex-- - windowValue = byte & 0b1111 - tables[tableIndex].Select(t, windowValue) - e.Add(e, t) - tableIndex-- - } - return e + return bn256.ScalarBaseMultGT(tables, r) } // Sign signs a hash (which should be the result of hashing a larger message) // using the user dsa key. It returns the signature as a pair of h and s. -func Sign(rand io.Reader, priv *SignPrivateKey, hash []byte) (h *big.Int, s *G1, err error) { +func Sign(rand io.Reader, priv *SignPrivateKey, hash []byte) (h *big.Int, s *bn256.G1, err error) { var r *big.Int for { r, err = randFieldElement(rand) @@ -167,11 +129,11 @@ func Sign(rand io.Reader, priv *SignPrivateKey, hash []byte) (h *big.Int, s *G1, l := new(big.Int).Sub(r, h) if l.Sign() < 0 { - l.Add(l, Order) + l.Add(l, bn256.Order) } if l.Sign() != 0 { - s = new(G1).ScalarMult(priv.PrivateKey, l) + s = new(bn256.G1).ScalarMult(priv.PrivateKey, l) break } } @@ -206,11 +168,11 @@ func SignASN1(rand io.Reader, priv *SignPrivateKey, hash []byte) ([]byte, error) // Verify verifies the signature in h, s of hash using the master dsa public key and user id, uid and hid. // Its return value records whether the signature is valid. -func Verify(pub *SignMasterPublicKey, uid []byte, hid byte, hash []byte, h *big.Int, s *G1) bool { - if h.Sign() <= 0 || h.Cmp(Order) >= 0 { +func Verify(pub *SignMasterPublicKey, uid []byte, hid byte, hash []byte, h *big.Int, s *bn256.G1) bool { + if h.Sign() <= 0 || h.Cmp(bn256.Order) >= 0 { return false } - if !s.p.IsOnCurve() { + if !s.IsOnCurve() { return false } @@ -219,8 +181,8 @@ func Verify(pub *SignMasterPublicKey, uid []byte, hid byte, hash []byte, h *big. // user sign public key p generation p := pub.GenerateUserPublicKey(uid, hid) - u := Pair(s, p) - w := new(GT).Add(u, t) + u := bn256.Pair(s, p) + w := new(bn256.GT).Add(u, t) var buffer []byte buffer = append(buffer, hash...) @@ -250,7 +212,7 @@ func VerifyASN1(pub *SignMasterPublicKey, uid []byte, hid byte, hash, sig []byte if sBytes[0] != 4 { return false } - s := new(G1) + s := new(bn256.G1) _, err := s.Unmarshal(sBytes[1:]) if err != nil { return false @@ -266,67 +228,28 @@ func (pub *SignMasterPublicKey) Verify(uid []byte, hid byte, hash, sig []byte) b } // Pair generate the basepoint once -func (pub *EncryptMasterPublicKey) Pair() *GT { +func (pub *EncryptMasterPublicKey) Pair() *bn256.GT { pub.pairOnce.Do(func() { - pub.basePoint = Pair(pub.MasterPublicKey, Gen2) + pub.basePoint = bn256.Pair(pub.MasterPublicKey, bn256.Gen2) }) return pub.basePoint } -func (pub *EncryptMasterPublicKey) generatorTable() *[32 * 2]gtTable { +func (pub *EncryptMasterPublicKey) generatorTable() *[32 * 2]bn256.GTFieldTable { pub.tableGenOnce.Do(func() { - pub.table = new([32 * 2]gtTable) - base := >{} - base.Set(pub.Pair()) - for i := 0; i < 32*2; i++ { - pub.table[i][0] = >{} - pub.table[i][0].Set(base) - for j := 1; j < 15; j += 2 { - pub.table[i][j] = >{} - pub.table[i][j].p = &gfP12{} - pub.table[i][j].p.Square(pub.table[i][j/2].p) - pub.table[i][j+1] = >{} - pub.table[i][j+1].p = &gfP12{} - pub.table[i][j+1].Add(pub.table[i][j], base) - } - base.p.Square(base.p) - base.p.Square(base.p) - base.p.Square(base.p) - base.p.Square(base.p) - } + pub.table = bn256.GenerateGTFieldTable(pub.Pair()) }) return pub.table } // ScalarBaseMult compute basepoint^r with precomputed table -func (pub *EncryptMasterPublicKey) ScalarBaseMult(r *big.Int) *GT { - scalar := normalizeScalar(r.Bytes()) +func (pub *EncryptMasterPublicKey) ScalarBaseMult(r *big.Int) *bn256.GT { tables := pub.generatorTable() - // This is also a scalar multiplication with a four-bit window like in - // ScalarMult, but in this case the doublings are precomputed. The value - // [windowValue]G added at iteration k would normally get doubled - // (totIterations-k)×4 times, but with a larger precomputation we can - // instead add [2^((totIterations-k)×4)][windowValue]G and avoid the - // doublings between iterations. - e, t := >{}, >{} - tableIndex := len(tables) - 1 - e.SetOne() - t.SetOne() - for _, byte := range scalar { - windowValue := byte >> 4 - tables[tableIndex].Select(t, windowValue) - e.Add(e, t) - tableIndex-- - windowValue = byte & 0b1111 - tables[tableIndex].Select(t, windowValue) - e.Add(e, t) - tableIndex-- - } - return e + return bn256.ScalarBaseMultGT(tables, r) } // WrapKey generate and wrap key wtih reciever's uid and system hid -func WrapKey(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte, kLen int) (key []byte, cipher *G1, err error) { +func WrapKey(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte, kLen int) (key []byte, cipher *bn256.G1, err error) { q := pub.GenerateUserPublicKey(uid, hid) var r *big.Int var ok bool @@ -336,7 +259,7 @@ func WrapKey(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte, return } - cipher = new(G1).ScalarMult(q, r) + cipher = new(bn256.G1).ScalarMult(q, r) w := pub.ScalarBaseMult(r) @@ -382,7 +305,7 @@ func (pub *EncryptMasterPublicKey) WrapKeyASN1(rand io.Reader, uid []byte, hid b } // UnmarshalSM9KeyPackage is an utility to unmarshal SM9KeyPackage -func UnmarshalSM9KeyPackage(der []byte) ([]byte, *G1, error) { +func UnmarshalSM9KeyPackage(der []byte) ([]byte, *bn256.G1, error) { input := cryptobyte.String(der) var ( key []byte @@ -404,12 +327,12 @@ func UnmarshalSM9KeyPackage(der []byte) ([]byte, *G1, error) { } // UnwrapKey unwrap key from cipher, user id and aligned key length -func UnwrapKey(priv *EncryptPrivateKey, uid []byte, cipher *G1, kLen int) ([]byte, error) { - if !cipher.p.IsOnCurve() { +func UnwrapKey(priv *EncryptPrivateKey, uid []byte, cipher *bn256.G1, kLen int) ([]byte, error) { + if !cipher.IsOnCurve() { return nil, errors.New("sm9: invalid cipher, it's NOT on curve") } - w := Pair(cipher, priv.PrivateKey) + w := bn256.Pair(cipher, priv.PrivateKey) var buffer []byte buffer = append(buffer, cipher.Marshal()...) @@ -486,7 +409,7 @@ func (pub *EncryptMasterPublicKey) Encrypt(rand io.Reader, uid []byte, hid byte, // Decrypt decrypt chipher, ciphertext should be with format C1||C3||C2 func Decrypt(priv *EncryptPrivateKey, uid, ciphertext []byte) ([]byte, error) { - c := &G1{} + c := &bn256.G1{} c3, err := c.Unmarshal(ciphertext) if err != nil { return nil, err diff --git a/sm9/sm9_key.go b/sm9/sm9_key.go index e43e7fe..70f9a25 100644 --- a/sm9/sm9_key.go +++ b/sm9/sm9_key.go @@ -6,6 +6,7 @@ import ( "math/big" "sync" + "github.com/emmansun/gmsm/sm9/bn256" "golang.org/x/crypto/cryptobyte" ) @@ -17,17 +18,17 @@ type SignMasterPrivateKey struct { // SignMasterPublicKey master public key for sign, generated by KGC type SignMasterPublicKey struct { - MasterPublicKey *G2 // master public key + MasterPublicKey *bn256.G2 // master public key pairOnce sync.Once - basePoint *GT // the result of Pair(Gen1, pub.MasterPublicKey) + basePoint *bn256.GT // the result of Pair(Gen1, pub.MasterPublicKey) tableGenOnce sync.Once - table *[32 * 2]gtTable // precomputed basePoint^n + table *[32 * 2]bn256.GTFieldTable // precomputed basePoint^n } // SignPrivateKey user private key for sign, generated by KGC type SignPrivateKey struct { - PrivateKey *G1 // user private key - SignMasterPublicKey // master public key + PrivateKey *bn256.G1 // user private key + SignMasterPublicKey // master public key } // EncryptMasterPrivateKey master private key for encryption, generated by KGC @@ -38,17 +39,17 @@ type EncryptMasterPrivateKey struct { // EncryptMasterPublicKey master private key for encryption, generated by KGC type EncryptMasterPublicKey struct { - MasterPublicKey *G1 // public key + MasterPublicKey *bn256.G1 // public key pairOnce sync.Once - basePoint *GT // the result of Pair(pub.MasterPublicKey, Gen2) + basePoint *bn256.GT // the result of Pair(pub.MasterPublicKey, Gen2) tableGenOnce sync.Once - table *[32 * 2]gtTable // precomputed basePoint^n + table *[32 * 2]bn256.GTFieldTable // precomputed basePoint^n } // EncryptPrivateKey user private key for encryption, generated by KGC type EncryptPrivateKey struct { - PrivateKey *G2 // user private key - EncryptMasterPublicKey // master public key + PrivateKey *bn256.G2 // user private key + EncryptMasterPublicKey // master public key } // GenerateSignMasterKey generates a master public and private key pair for DSA usage. @@ -60,7 +61,7 @@ func GenerateSignMasterKey(rand io.Reader) (*SignMasterPrivateKey, error) { priv := new(SignMasterPrivateKey) priv.D = k - priv.MasterPublicKey = new(G2).ScalarBaseMult(k) + priv.MasterPublicKey = new(bn256.G2).ScalarBaseMult(k) return priv, nil } @@ -80,7 +81,7 @@ func (master *SignMasterPrivateKey) UnmarshalASN1(der []byte) error { return errors.New("sm9: invalid sign master key asn1 data") } master.D = d - master.MasterPublicKey = new(G2).ScalarBaseMult(d) + master.MasterPublicKey = new(bn256.G2).ScalarBaseMult(d) return nil } @@ -95,13 +96,13 @@ func (master *SignMasterPrivateKey) GenerateUserKey(uid []byte, hid byte) (*Sign if t1.Sign() == 0 { return nil, errors.New("sm9: need to re-generate sign master private key") } - t1 = fermatInverse(t1, Order) + t1 = fermatInverse(t1, bn256.Order) t2 := new(big.Int).Mul(t1, master.D) - t2.Mod(t2, Order) + t2.Mod(t2, bn256.Order) priv := new(SignPrivateKey) priv.SignMasterPublicKey = master.SignMasterPublicKey - priv.PrivateKey = new(G1).ScalarBaseMult(t2) + priv.PrivateKey = new(bn256.G1).ScalarBaseMult(t2) return priv, nil } @@ -112,12 +113,12 @@ func (master *SignMasterPrivateKey) Public() *SignMasterPublicKey { } // GenerateUserPublicKey generate user sign public key -func (pub *SignMasterPublicKey) GenerateUserPublicKey(uid []byte, hid byte) *G2 { +func (pub *SignMasterPublicKey) GenerateUserPublicKey(uid []byte, hid byte) *bn256.G2 { var buffer []byte buffer = append(buffer, uid...) buffer = append(buffer, hid) h1 := hashH1(buffer) - p := new(G2).ScalarBaseMult(h1) + p := new(bn256.G2).ScalarBaseMult(h1) p.Add(p, pub.MasterPublicKey) return p } @@ -130,8 +131,8 @@ func (pub *SignMasterPublicKey) MarshalASN1() ([]byte, error) { return b.Bytes() } -func unmarshalG2(bytes []byte) (*G2, error) { - g2 := new(G2) +func unmarshalG2(bytes []byte) (*bn256.G2, error) { + g2 := new(bn256.G2) switch bytes[0] { case 4: _, err := g2.Unmarshal(bytes[1:]) @@ -184,8 +185,8 @@ func (priv *SignPrivateKey) MarshalASN1() ([]byte, error) { return b.Bytes() } -func unmarshalG1(bytes []byte) (*G1, error) { - g := new(G1) +func unmarshalG1(bytes []byte) (*bn256.G1, error) { + g := new(bn256.G1) switch bytes[0] { case 4: _, err := g.Unmarshal(bytes[1:]) @@ -228,7 +229,7 @@ func GenerateEncryptMasterKey(rand io.Reader) (*EncryptMasterPrivateKey, error) priv := new(EncryptMasterPrivateKey) priv.D = k - priv.MasterPublicKey = new(G1).ScalarBaseMult(k) + priv.MasterPublicKey = new(bn256.G1).ScalarBaseMult(k) return priv, nil } @@ -243,13 +244,13 @@ func (master *EncryptMasterPrivateKey) GenerateUserKey(uid []byte, hid byte) (*E if t1.Sign() == 0 { return nil, errors.New("sm9: need to re-generate encrypt master private key") } - t1 = fermatInverse(t1, Order) + t1 = fermatInverse(t1, bn256.Order) t2 := new(big.Int).Mul(t1, master.D) - t2.Mod(t2, Order) + t2.Mod(t2, bn256.Order) priv := new(EncryptPrivateKey) priv.EncryptMasterPublicKey = master.EncryptMasterPublicKey - priv.PrivateKey = new(G2).ScalarBaseMult(t2) + priv.PrivateKey = new(bn256.G2).ScalarBaseMult(t2) return priv, nil } @@ -275,17 +276,17 @@ func (master *EncryptMasterPrivateKey) UnmarshalASN1(der []byte) error { return errors.New("sm9: invalid encrpt master key asn1 data") } master.D = d - master.MasterPublicKey = new(G1).ScalarBaseMult(d) + master.MasterPublicKey = new(bn256.G1).ScalarBaseMult(d) return nil } // GenerateUserPublicKey generate user encrypt public key -func (pub *EncryptMasterPublicKey) GenerateUserPublicKey(uid []byte, hid byte) *G1 { +func (pub *EncryptMasterPublicKey) GenerateUserPublicKey(uid []byte, hid byte) *bn256.G1 { var buffer []byte buffer = append(buffer, uid...) buffer = append(buffer, hid) h1 := hashH1(buffer) - p := new(G1).ScalarBaseMult(h1) + p := new(bn256.G1).ScalarBaseMult(h1) p.Add(p, pub.MasterPublicKey) return p } diff --git a/sm9/sm9_key_test.go b/sm9/sm9_key_test.go index cfd1c2e..a823be7 100644 --- a/sm9/sm9_key_test.go +++ b/sm9/sm9_key_test.go @@ -39,9 +39,7 @@ func TestSignMasterPublicKeyMarshalASN1(t *testing.T) { if err != nil { t.Fatal(err) } - if masterKey.MasterPublicKey.p.x != pub2.MasterPublicKey.p.x || - masterKey.MasterPublicKey.p.y != pub2.MasterPublicKey.p.y || - masterKey.MasterPublicKey.p.z != pub2.MasterPublicKey.p.z { + if !masterKey.MasterPublicKey.Equal(pub2.MasterPublicKey) { t.Errorf("not same") } } @@ -66,8 +64,7 @@ func TestSignUserPrivateKeyMarshalASN1(t *testing.T) { if err != nil { t.Fatal(err) } - if userKey.PrivateKey.p.x != userKey2.PrivateKey.p.x || - userKey.PrivateKey.p.y != userKey2.PrivateKey.p.y { + if !userKey.PrivateKey.Equal(userKey2.PrivateKey) { t.Errorf("not same") } } @@ -105,8 +102,7 @@ func TestEncryptMasterPublicKeyMarshalASN1(t *testing.T) { if err != nil { t.Fatal(err) } - if masterKey.MasterPublicKey.p.x != pub2.MasterPublicKey.p.x || - masterKey.MasterPublicKey.p.y != pub2.MasterPublicKey.p.y { + if !masterKey.MasterPublicKey.Equal(pub2.MasterPublicKey) { t.Errorf("not same") } } @@ -131,9 +127,7 @@ func TestEncryptUserPrivateKeyMarshalASN1(t *testing.T) { if err != nil { t.Fatal(err) } - if userKey.PrivateKey.p.x != userKey2.PrivateKey.p.x || - userKey.PrivateKey.p.y != userKey2.PrivateKey.p.y || - userKey.PrivateKey.p.z != userKey2.PrivateKey.p.z { + if !userKey.PrivateKey.Equal(userKey2.PrivateKey) { t.Errorf("not same") } } diff --git a/sm9/sm9_test.go b/sm9/sm9_test.go index 5c6bba4..753655f 100644 --- a/sm9/sm9_test.go +++ b/sm9/sm9_test.go @@ -9,8 +9,17 @@ import ( "github.com/emmansun/gmsm/internal/xor" "github.com/emmansun/gmsm/sm3" + "github.com/emmansun/gmsm/sm9/bn256" ) +func bigFromHex(s string) *big.Int { + b, ok := new(big.Int).SetString(s, 16) + if !ok { + panic("sm9/elliptic: internal error: invalid encoding") + } + return b +} + func TestHashH1(t *testing.T) { expected := "2acc468c3926b0bdb2767e99ff26e084de9ced8dbc7d5fbf418027b667862fab" h := hashH1([]byte{0x41, 0x6c, 0x69, 0x63, 0x65, 0x01}) @@ -88,7 +97,7 @@ func TestSignSM9Sample(t *testing.T) { r := bigFromHex("033c8616b06704813203dfd00965022ed15975c662337aed648835dc4b1cbe") masterKey := new(SignMasterPrivateKey) masterKey.D = bigFromHex("0130E78459D78545CB54C587E02CF480CE0B66340F319F348A1D5B1F2DC5F4") - masterKey.MasterPublicKey = new(G2).ScalarBaseMult(masterKey.D) + masterKey.MasterPublicKey = new(bn256.G2).ScalarBaseMult(masterKey.D) userKey, err := masterKey.GenerateUserKey(uid, hid) if err != nil { t.Fatal(err) @@ -107,10 +116,10 @@ func TestSignSM9Sample(t *testing.T) { l := new(big.Int).Sub(r, h) if l.Sign() < 0 { - l.Add(l, Order) + l.Add(l, bn256.Order) } - s := new(G1).ScalarMult(userKey.PrivateKey, l) + s := new(bn256.G1).ScalarMult(userKey.PrivateKey, l) if hex.EncodeToString(s.MarshalUncompressed()) != expectedS { t.Fatal("not same S") @@ -205,7 +214,7 @@ func TestWrapKeySM9Sample(t *testing.T) { expectedKey := "4ff5cf86d2ad40c8f4bac98d76abdbde0c0e2f0a829d3f911ef5b2bce0695480" masterKey := new(EncryptMasterPrivateKey) masterKey.D = bigFromHex("01EDEE3778F441F8DEA3D9FA0ACC4E07EE36C93F9A08618AF4AD85CEDE1C22") - masterKey.MasterPublicKey = new(G1).ScalarBaseMult(masterKey.D) + masterKey.MasterPublicKey = new(bn256.G1).ScalarBaseMult(masterKey.D) fmt.Printf("Pub-e=%v\n", hex.EncodeToString(masterKey.MasterPublicKey.Marshal())) uid := []byte("Bob") @@ -221,11 +230,11 @@ func TestWrapKeySM9Sample(t *testing.T) { fmt.Printf("Qb=%v\n", hex.EncodeToString(q.Marshal())) var r *big.Int = bigFromHex("74015F8489C01EF4270456F9E6475BFB602BDE7F33FD482AB4E3684A6722") - cipher := new(G1).ScalarMult(q, r) + cipher := new(bn256.G1).ScalarMult(q, r) fmt.Printf("C=%v\n", hex.EncodeToString(cipher.Marshal())) - g := Pair(masterKey.Public().MasterPublicKey, Gen2) - w := new(GT).ScalarMult(g, r) + g := bn256.Pair(masterKey.Public().MasterPublicKey, bn256.Gen2) + w := new(bn256.GT).ScalarMult(g, r) var buffer []byte buffer = append(buffer, cipher.Marshal()...) @@ -255,7 +264,7 @@ func TestEncryptSM9Sample(t *testing.T) { expectedCiphertext := "2445471164490618e1ee20528ff1d545b0f14c8bcaa44544f03dab5dac07d8ff42ffca97d57cddc05ea405f2e586feb3a6930715532b8000759f13059ed59ac0ba672387bcd6de5016a158a52bb2e7fc429197bcab70b25afee37a2b9db9f3671b5f5b0e951489682f3e64e1378cdd5da9513b1c" masterKey := new(EncryptMasterPrivateKey) masterKey.D = bigFromHex("01EDEE3778F441F8DEA3D9FA0ACC4E07EE36C93F9A08618AF4AD85CEDE1C22") - masterKey.MasterPublicKey = new(G1).ScalarBaseMult(masterKey.D) + masterKey.MasterPublicKey = new(bn256.G1).ScalarBaseMult(masterKey.D) fmt.Printf("Pub-e=%v\n", hex.EncodeToString(masterKey.MasterPublicKey.Marshal())) uid := []byte("Bob") @@ -271,11 +280,11 @@ func TestEncryptSM9Sample(t *testing.T) { fmt.Printf("Qb=%v\n", hex.EncodeToString(q.Marshal())) var r *big.Int = bigFromHex("AAC0541779C8FC45E3E2CB25C12B5D2576B2129AE8BB5EE2CBE5EC9E785C") - cipher := new(G1).ScalarMult(q, r) + cipher := new(bn256.G1).ScalarMult(q, r) fmt.Printf("C=%v\n", hex.EncodeToString(cipher.Marshal())) - g := Pair(masterKey.Public().MasterPublicKey, Gen2) - w := new(GT).ScalarMult(g, r) + g := bn256.Pair(masterKey.Public().MasterPublicKey, bn256.Gen2) + w := new(bn256.GT).ScalarMult(g, r) var buffer []byte buffer = append(buffer, cipher.Marshal()...)