precompute part 2

This commit is contained in:
Sun Yimin 2022-06-13 16:29:58 +08:00 committed by GitHub
parent 2b0119dda7
commit d6a464f470
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 190 additions and 7 deletions

View File

@ -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.

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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 := &GT{}
base.Set(pub.Pair())
for i := 0; i < 32*2; i++ {
pub.table[i][0] = &GT{}
pub.table[i][0].Set(base)
for j := 1; j < 15; j += 2 {
pub.table[i][j] = &GT{}
pub.table[i][j].p = &gfP12{}
pub.table[i][j].p.Square(pub.table[i][j/2].p)
pub.table[i][j+1] = &GT{}
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 := &GT{}, &GT{}
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 := &GT{}
base.Set(pub.Pair())
for i := 0; i < 32*2; i++ {
pub.table[i][0] = &GT{}
pub.table[i][0].Set(base)
for j := 1; j < 15; j += 2 {
pub.table[i][j] = &GT{}
pub.table[i][j].p = &gfP12{}
pub.table[i][j].p.Square(pub.table[i][j/2].p)
pub.table[i][j+1] = &GT{}
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 := &GT{}, &GT{}
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()...)

View File

@ -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 {