mirror of
https://github.com/emmansun/gmsm.git
synced 2025-04-26 20:26:19 +08:00
precompute part 2
This commit is contained in:
parent
2b0119dda7
commit
d6a464f470
@ -2,3 +2,39 @@ 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 Sign Benchmark**
|
||||
|
||||
goos: windows
|
||||
goarch: amd64
|
||||
pkg: github.com/emmansun/gmsm/sm9
|
||||
cpu: Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
|
||||
BenchmarkSign-6 1344 871597 ns/op 35870 B/op 1013 allocs/op
|
||||
|
||||
|
||||
**SM9 Verify Benchmark**
|
||||
|
||||
goos: windows
|
||||
goarch: amd64
|
||||
pkg: github.com/emmansun/gmsm/sm9
|
||||
cpu: Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
|
||||
BenchmarkVerify-6 352 3331673 ns/op 237676 B/op 6283 allocs/op
|
||||
|
||||
**SM9 Encrypt(XOR) Benchmark**
|
||||
|
||||
goos: windows
|
||||
goarch: amd64
|
||||
pkg: github.com/emmansun/gmsm/sm9
|
||||
cpu: Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
|
||||
BenchmarkEncrypt-6 1120 971188 ns/op 38125 B/op 1036 allocs/op
|
||||
|
||||
**SM9 Decrypt(XOR) Benchmark**
|
||||
|
||||
goos: windows
|
||||
goarch: amd64
|
||||
pkg: github.com/emmansun/gmsm/sm9
|
||||
cpu: Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
|
||||
BenchmarkDecrypt-6 507 2345492 ns/op 202360 B/op 5228 allocs/op
|
||||
|
||||
To further improve `Verify()/Decrypt()` performance, need to improve `Pair()` method performance.
|
||||
|
@ -367,3 +367,11 @@ func (e *gfP12) Conjugate(a *gfP12) *gfP12 {
|
||||
e.x.Conjugate(&a.x)
|
||||
return e
|
||||
}
|
||||
|
||||
// Select sets q to p1 if cond == 1, and to p2 if cond == 0.
|
||||
func (q *gfP12) Select(p1, p2 *gfP12, cond int) *gfP12 {
|
||||
q.x.Select(&p1.x, &p2.x, cond)
|
||||
q.y.Select(&p1.y, &p2.y, cond)
|
||||
q.z.Select(&p1.z, &p2.z, cond)
|
||||
return q
|
||||
}
|
||||
|
@ -241,3 +241,10 @@ func (e *gfP4) FrobeniusP3(a *gfP4) *gfP4 {
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
// Select sets q to p1 if cond == 1, and to p2 if cond == 0.
|
||||
func (q *gfP4) Select(p1, p2 *gfP4, cond int) *gfP4 {
|
||||
q.x.Select(&p1.x, &p2.x, cond)
|
||||
q.y.Select(&p1.y, &p2.y, cond)
|
||||
return q
|
||||
}
|
||||
|
28
sm9/gt.go
28
sm9/gt.go
@ -1,6 +1,7 @@
|
||||
package sm9
|
||||
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"errors"
|
||||
"io"
|
||||
"math/big"
|
||||
@ -85,6 +86,15 @@ func (e *GT) Set(a *GT) *GT {
|
||||
return e
|
||||
}
|
||||
|
||||
// Set sets e to one and then returns e.
|
||||
func (e *GT) SetOne() *GT {
|
||||
if e.p == nil {
|
||||
e.p = &gfP12{}
|
||||
}
|
||||
e.p.SetOne()
|
||||
return e
|
||||
}
|
||||
|
||||
// Finalize is a linear function from F_p^12 to GT.
|
||||
func (e *GT) Finalize() *GT {
|
||||
ret := finalExponentiation(e.p)
|
||||
@ -197,3 +207,21 @@ 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
|
||||
// is at table[0], P^15 is at table[14], and P^0 is implicitly the identity
|
||||
// point.
|
||||
type gtTable [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) {
|
||||
if n >= 16 {
|
||||
panic("sm9: internal error: gtTable called with out-of-bounds value")
|
||||
}
|
||||
p.p.SetOne()
|
||||
for i := uint8(1); i < 16; i++ {
|
||||
cond := subtle.ConstantTimeByteEq(i, n)
|
||||
p.p.Select(table[i-1].p, p.p, cond)
|
||||
}
|
||||
}
|
||||
|
112
sm9/sm9.go
112
sm9/sm9.go
@ -91,17 +91,68 @@ func (pub *SignMasterPublicKey) Pair() *GT {
|
||||
return pub.basePoint
|
||||
}
|
||||
|
||||
func (pub *SignMasterPublicKey) generatorTable() *[32 * 2]gtTable {
|
||||
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)
|
||||
}
|
||||
})
|
||||
return pub.table
|
||||
}
|
||||
|
||||
func (pub *SignMasterPublicKey) ScalarBaseMult(r *big.Int) *GT {
|
||||
scalar := normalizeScalar(r.Bytes())
|
||||
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
|
||||
}
|
||||
|
||||
// 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) {
|
||||
g := priv.Pair()
|
||||
var r *big.Int
|
||||
for {
|
||||
r, err = randFieldElement(rand)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
w := new(GT).ScalarMult(g, r)
|
||||
|
||||
w := priv.SignMasterPublicKey.ScalarBaseMult(r)
|
||||
|
||||
var buffer []byte
|
||||
buffer = append(buffer, hash...)
|
||||
@ -157,9 +208,8 @@ func Verify(pub *SignMasterPublicKey, uid []byte, hid byte, hash []byte, h *big.
|
||||
if !s.p.IsOnCurve() {
|
||||
return false
|
||||
}
|
||||
g := pub.Pair()
|
||||
|
||||
t := new(GT).ScalarMult(g, h)
|
||||
t := pub.ScalarBaseMult(h)
|
||||
|
||||
// user sign public key p generation
|
||||
p := pub.GenerateUserPublicKey(uid, hid)
|
||||
@ -227,6 +277,57 @@ func (pub *EncryptMasterPublicKey) Pair() *GT {
|
||||
return pub.basePoint
|
||||
}
|
||||
|
||||
func (pub *EncryptMasterPublicKey) generatorTable() *[32 * 2]gtTable {
|
||||
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)
|
||||
}
|
||||
})
|
||||
return pub.table
|
||||
}
|
||||
|
||||
func (pub *EncryptMasterPublicKey) ScalarBaseMult(r *big.Int) *GT {
|
||||
scalar := normalizeScalar(r.Bytes())
|
||||
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
|
||||
}
|
||||
|
||||
// WrappKey generate and wrapp key wtih reciever's uid and system hid
|
||||
func WrappKey(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte, kLen int) (key []byte, cipher *G1, err error) {
|
||||
q := pub.GenerateUserPublicKey(uid, hid)
|
||||
@ -240,8 +341,7 @@ func WrappKey(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte,
|
||||
|
||||
cipher = new(G1).ScalarMult(q, r)
|
||||
|
||||
g := pub.Pair()
|
||||
w := new(GT).ScalarMult(g, r)
|
||||
w := pub.ScalarBaseMult(r)
|
||||
|
||||
var buffer []byte
|
||||
buffer = append(buffer, cipher.Marshal()...)
|
||||
|
@ -18,6 +18,8 @@ type SignMasterPublicKey struct {
|
||||
MasterPublicKey *G2
|
||||
pairOnce sync.Once
|
||||
basePoint *GT
|
||||
tableGenOnce sync.Once
|
||||
table *[32 * 2]gtTable
|
||||
}
|
||||
|
||||
type SignPrivateKey struct {
|
||||
@ -34,6 +36,8 @@ type EncryptMasterPublicKey struct {
|
||||
MasterPublicKey *G1
|
||||
pairOnce sync.Once
|
||||
basePoint *GT
|
||||
tableGenOnce sync.Once
|
||||
table *[32 * 2]gtTable
|
||||
}
|
||||
|
||||
type EncryptPrivateKey struct {
|
||||
|
Loading…
x
Reference in New Issue
Block a user