From 618dae47a5837dbf19e2ddca047496bd475f7989 Mon Sep 17 00:00:00 2001 From: Alex Vlasov Date: Fri, 4 Sep 2020 02:13:53 +0300 Subject: [PATCH 1/7] implement binary EEA inversion --- crypto/bn256/cloudflare/bn256_test.go | 58 ++++++++++++ crypto/bn256/cloudflare/curve.go | 3 +- crypto/bn256/cloudflare/gfp.go | 128 ++++++++++++++++++++++++++ 3 files changed, 188 insertions(+), 1 deletion(-) diff --git a/crypto/bn256/cloudflare/bn256_test.go b/crypto/bn256/cloudflare/bn256_test.go index 0c8016d86ccc..73843e5cd064 100644 --- a/crypto/bn256/cloudflare/bn256_test.go +++ b/crypto/bn256/cloudflare/bn256_test.go @@ -92,6 +92,64 @@ func TestTripartiteDiffieHellman(t *testing.T) { } } +func TestBinaryEAA(t *testing.T) { + for i := 0; i < 10000; i++ { + _, Ga, err := RandomG1(rand.Reader) + if err != nil { + t.Fatal(err) + } + tmpLittleFermat := &gfP{} + tmpLittleFermat.Invert(&Ga.p.x) + + tmpBinaryEAA := &gfP{} + tmpBinaryEAA.EaaInvert(&Ga.p.x) + + eq := equals(tmpLittleFermat, tmpBinaryEAA) + if eq == false { + t.Fatalf("results of different inversion do not agree") + } + } +} + +func BenchmarkLittleFermatInversion(b *testing.B) { + el := gfP{0x0, 0x97816a916871ca8d, 0xb85045b68181585d, 0x30644e72e131a029} + + b.ResetTimer() + + tmp := &gfP{} + for i := 0; i < b.N; i++ { + tmp.Invert(&el) + } +} + +func BenchmarkBinaryEEAInversion(b *testing.B) { + el := gfP{0x0, 0x97816a916871ca8d, 0xb85045b68181585d, 0x30644e72e131a029} + + b.ResetTimer() + + tmp := &gfP{} + for i := 0; i < b.N; i++ { + tmp.EaaInvert(&el) + } +} + +func BenchmarkG1AddAndMakeAffine(b *testing.B) { + _, Ga, err := RandomG1(rand.Reader) + if err != nil { + b.Fatal(err) + } + _, Gb, err := RandomG1(rand.Reader) + if err != nil { + b.Fatal(err) + } + b.ResetTimer() + + for i := 0; i < b.N; i++ { + e := new(G1).Add(Ga, Gb) + e.p.MakeAffine() + } +} + func BenchmarkG1(b *testing.B) { x, _ := rand.Int(rand.Reader, Order) b.ResetTimer() diff --git a/crypto/bn256/cloudflare/curve.go b/crypto/bn256/cloudflare/curve.go index 18e9b38f3f5f..35e2d88e7934 100644 --- a/crypto/bn256/cloudflare/curve.go +++ b/crypto/bn256/cloudflare/curve.go @@ -217,7 +217,8 @@ func (c *curvePoint) MakeAffine() { } zInv := &gfP{} - zInv.Invert(&c.z) + zInv.EaaInvert(&c.z) + // zInv.Invert(&c.z) t, zInv2 := &gfP{}, &gfP{} gfpMul(t, &c.y, zInv) diff --git a/crypto/bn256/cloudflare/gfp.go b/crypto/bn256/cloudflare/gfp.go index e8e84e7b3b58..41b4f7f82164 100644 --- a/crypto/bn256/cloudflare/gfp.go +++ b/crypto/bn256/cloudflare/gfp.go @@ -3,6 +3,7 @@ package bn256 import ( "errors" "fmt" + "math/bits" ) type gfP [4]uint64 @@ -79,3 +80,130 @@ func (e *gfP) Unmarshal(in []byte) error { func montEncode(c, a *gfP) { gfpMul(c, a, r2) } func montDecode(c, a *gfP) { gfpMul(c, a, &gfP{1}) } + +func isZero(a *gfP) bool { + return a[0] == 0 && a[1] == 0 && a[2] == 0 && a[3] == 0 +} + +func isEven(a *gfP) bool { + return bits.TrailingZeros64((a[0])) > 0 +} + +func div2(a *gfP) { + a[0] = a[0]>>1 | a[1]<<63 + a[1] = a[1]>>1 | a[2]<<63 + a[2] = a[2]>>1 | a[3]<<63 + a[3] = a[3] >> 1 +} + +func (e *gfP) addNocarry(f *gfP) { + carry := uint64(0) + e[0], carry = bits.Add64(e[0], f[0], carry) + e[1], carry = bits.Add64(e[1], f[1], carry) + e[2], carry = bits.Add64(e[2], f[2], carry) + e[3], _ = bits.Add64(e[3], f[3], carry) +} + +func (e *gfP) subNoborrow(f *gfP) { + borrow := uint64(0) + e[0], borrow = bits.Sub64(e[0], f[0], borrow) + e[1], borrow = bits.Sub64(e[1], f[1], borrow) + e[2], borrow = bits.Sub64(e[2], f[2], borrow) + e[3], _ = bits.Sub64(e[3], f[3], borrow) +} + +func gte(a, b *gfP) bool { + // subtract b from a. If no borrow occures then a >= b + borrow := uint64(0) + _, borrow = bits.Sub64(a[0], b[0], borrow) + _, borrow = bits.Sub64(a[1], b[1], borrow) + _, borrow = bits.Sub64(a[2], b[2], borrow) + _, borrow = bits.Sub64(a[3], b[3], borrow) + + return borrow == 0 +} + +func equals(a, b *gfP) bool { + return a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3] +} + +// Performs inversion of the field element using binary EEA. +// If element is zero (no inverse exists) then set `e` to zero +func (e *gfP) EaaInvert(f *gfP) { + if isZero(f) { + e.Set(&gfP{0, 0, 0, 0}) + return + } + + // Guajardo Kumar Paar Pelzl + // Efficient Software-Implementation of Finite Fields with Applications to Cryptography + // Algorithm 16 (BEA for Inversion in Fp) + + one := gfP{1, 0, 0, 0} + + u, b := gfP{}, gfP{} + u.Set(f) + b.Set(r2) + + v := gfP{p2[0], p2[1], p2[2], p2[3]} + c := gfP{0, 0, 0, 0} + modulus := gfP{p2[0], p2[1], p2[2], p2[3]} + + for { + if equals(&u, &one) || equals(&v, &one) { + break + } + + // while u is even + for { + if !isEven(&u) { + break + } + + div2(&u) + if isEven(&b) { + div2(&b) + } else { + // we will not overflow a modulus here, + // so we can use specialized function + // do perform addition without reduction + b.addNocarry(&modulus) + div2(&b) + } + } + + // while v is even + for { + if !isEven(&v) { + break + } + + div2(&v) + if isEven(&c) { + div2(&c) + } else { + // we will not overflow a modulus here, + // so we can use specialized function + // do perform addition without reduction + c.addNocarry(&modulus) + div2(&c) + } + } + + if gte(&v, &u) { + // v >= u + v.subNoborrow(&u) + gfpSub(&c, &c, &b) + } else { + // if v < u + u.subNoborrow(&v) + gfpSub(&b, &b, &c) + } + } + + if equals(&u, &one) { + e.Set(&b) + } else { + e.Set(&c) + } +} From e8126660569b8ad02976f1b0c47b6ab6accd2b0a Mon Sep 17 00:00:00 2001 From: Alex Vlasov Date: Fri, 4 Sep 2020 16:55:30 +0300 Subject: [PATCH 2/7] also test self-assignment --- crypto/bn256/cloudflare/bn256_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/crypto/bn256/cloudflare/bn256_test.go b/crypto/bn256/cloudflare/bn256_test.go index 73843e5cd064..488a06e529bc 100644 --- a/crypto/bn256/cloudflare/bn256_test.go +++ b/crypto/bn256/cloudflare/bn256_test.go @@ -104,10 +104,19 @@ func TestBinaryEAA(t *testing.T) { tmpBinaryEAA := &gfP{} tmpBinaryEAA.EaaInvert(&Ga.p.x) + tmpBinaryEAASelfSet := &gfP{} + tmpBinaryEAASelfSet.Set(&Ga.p.x) + tmpBinaryEAASelfSet.EaaInvert(tmpBinaryEAASelfSet) + eq := equals(tmpLittleFermat, tmpBinaryEAA) if eq == false { t.Fatalf("results of different inversion do not agree") } + + eq = equals(tmpLittleFermat, tmpBinaryEAASelfSet) + if eq == false { + t.Fatalf("self-assigned inversion is invalid") + } } } From 92e7fe311bcf8b5764df61dd35618e996e46d514 Mon Sep 17 00:00:00 2001 From: Alex Vlasov Date: Tue, 8 Sep 2020 00:23:58 +0300 Subject: [PATCH 3/7] make explicit variable and constant time inversions and proj -> affine --- crypto/bn256/cloudflare/bn256.go | 2 +- crypto/bn256/cloudflare/bn256_test.go | 10 +++--- crypto/bn256/cloudflare/curve.go | 27 +++++++++++++-- crypto/bn256/cloudflare/gfp.go | 4 +-- crypto/bn256/cloudflare/gfp12.go | 20 +++++++++-- crypto/bn256/cloudflare/gfp2.go | 22 ++++++++++-- crypto/bn256/cloudflare/gfp6.go | 48 +++++++++++++++++++++++++-- crypto/bn256/cloudflare/optate.go | 4 +-- crypto/bn256/cloudflare/twist.go | 28 +++++++++++++--- 9 files changed, 143 insertions(+), 22 deletions(-) diff --git a/crypto/bn256/cloudflare/bn256.go b/crypto/bn256/cloudflare/bn256.go index 38822a76bfec..0bc9204d223e 100644 --- a/crypto/bn256/cloudflare/bn256.go +++ b/crypto/bn256/cloudflare/bn256.go @@ -236,7 +236,7 @@ func (e *G2) Marshal() []byte { e.p = &twistPoint{} } - e.p.MakeAffine() + e.p.MakeAffineConstantTime() ret := make([]byte, numBytes*4) if e.p.IsInfinity() { return ret diff --git a/crypto/bn256/cloudflare/bn256_test.go b/crypto/bn256/cloudflare/bn256_test.go index 488a06e529bc..5d5b7eb8a9c9 100644 --- a/crypto/bn256/cloudflare/bn256_test.go +++ b/crypto/bn256/cloudflare/bn256_test.go @@ -99,14 +99,14 @@ func TestBinaryEAA(t *testing.T) { t.Fatal(err) } tmpLittleFermat := &gfP{} - tmpLittleFermat.Invert(&Ga.p.x) + tmpLittleFermat.InvertConstantTime(&Ga.p.x) tmpBinaryEAA := &gfP{} - tmpBinaryEAA.EaaInvert(&Ga.p.x) + tmpBinaryEAA.InvertVariableTime(&Ga.p.x) tmpBinaryEAASelfSet := &gfP{} tmpBinaryEAASelfSet.Set(&Ga.p.x) - tmpBinaryEAASelfSet.EaaInvert(tmpBinaryEAASelfSet) + tmpBinaryEAASelfSet.InvertVariableTime(tmpBinaryEAASelfSet) eq := equals(tmpLittleFermat, tmpBinaryEAA) if eq == false { @@ -127,7 +127,7 @@ func BenchmarkLittleFermatInversion(b *testing.B) { tmp := &gfP{} for i := 0; i < b.N; i++ { - tmp.Invert(&el) + tmp.InvertConstantTime(&el) } } @@ -138,7 +138,7 @@ func BenchmarkBinaryEEAInversion(b *testing.B) { tmp := &gfP{} for i := 0; i < b.N; i++ { - tmp.EaaInvert(&el) + tmp.InvertVariableTime(&el) } } diff --git a/crypto/bn256/cloudflare/curve.go b/crypto/bn256/cloudflare/curve.go index 35e2d88e7934..23c8064dace9 100644 --- a/crypto/bn256/cloudflare/curve.go +++ b/crypto/bn256/cloudflare/curve.go @@ -217,8 +217,31 @@ func (c *curvePoint) MakeAffine() { } zInv := &gfP{} - zInv.EaaInvert(&c.z) - // zInv.Invert(&c.z) + zInv.InvertVariableTime(&c.z) + + t, zInv2 := &gfP{}, &gfP{} + gfpMul(t, &c.y, zInv) + gfpMul(zInv2, zInv, zInv) + + gfpMul(&c.x, &c.x, zInv2) + gfpMul(&c.y, t, zInv2) + + c.z = *newGFp(1) + c.t = *newGFp(1) +} + +func (c *curvePoint) MakeAffineConstantTime() { + if c.z == *newGFp(1) { + return + } else if c.z == *newGFp(0) { + c.x = gfP{0} + c.y = *newGFp(1) + c.t = gfP{0} + return + } + + zInv := &gfP{} + zInv.InvertConstantTime(&c.z) t, zInv2 := &gfP{}, &gfP{} gfpMul(t, &c.y, zInv) diff --git a/crypto/bn256/cloudflare/gfp.go b/crypto/bn256/cloudflare/gfp.go index 41b4f7f82164..f3aff93077c6 100644 --- a/crypto/bn256/cloudflare/gfp.go +++ b/crypto/bn256/cloudflare/gfp.go @@ -31,7 +31,7 @@ func (e *gfP) Set(f *gfP) { e[3] = f[3] } -func (e *gfP) Invert(f *gfP) { +func (e *gfP) InvertConstantTime(f *gfP) { bits := [4]uint64{0x3c208c16d87cfd45, 0x97816a916871ca8d, 0xb85045b68181585d, 0x30644e72e131a029} sum, power := &gfP{}, &gfP{} @@ -129,7 +129,7 @@ func equals(a, b *gfP) bool { // Performs inversion of the field element using binary EEA. // If element is zero (no inverse exists) then set `e` to zero -func (e *gfP) EaaInvert(f *gfP) { +func (e *gfP) InvertVariableTime(f *gfP) { if isZero(f) { e.Set(&gfP{0, 0, 0, 0}) return diff --git a/crypto/bn256/cloudflare/gfp12.go b/crypto/bn256/cloudflare/gfp12.go index 93fb368a7bf0..e8da86952779 100644 --- a/crypto/bn256/cloudflare/gfp12.go +++ b/crypto/bn256/cloudflare/gfp12.go @@ -143,7 +143,7 @@ func (e *gfP12) Square(a *gfP12) *gfP12 { return e } -func (e *gfP12) Invert(a *gfP12) *gfP12 { +func (e *gfP12) InvertVariableTime(a *gfP12) *gfP12 { // See "Implementing cryptographic pairings", M. Scott, section 3.2. // ftp://136.206.11.249/pub/crypto/pairings.pdf t1, t2 := &gfP6{}, &gfP6{} @@ -151,7 +151,23 @@ func (e *gfP12) Invert(a *gfP12) *gfP12 { t1.Square(&a.x) t2.Square(&a.y) t1.MulTau(t1).Sub(t2, t1) - t2.Invert(t1) + t2.InvertVariableTime(t1) + + e.x.Neg(&a.x) + e.y.Set(&a.y) + e.MulScalar(e, t2) + return e +} + +func (e *gfP12) InvertConstantTime(a *gfP12) *gfP12 { + // See "Implementing cryptographic pairings", M. Scott, section 3.2. + // ftp://136.206.11.249/pub/crypto/pairings.pdf + t1, t2 := &gfP6{}, &gfP6{} + + t1.Square(&a.x) + t2.Square(&a.y) + t1.MulTau(t1).Sub(t2, t1) + t2.InvertConstantTime(t1) e.x.Neg(&a.x) e.y.Set(&a.y) diff --git a/crypto/bn256/cloudflare/gfp2.go b/crypto/bn256/cloudflare/gfp2.go index 90a89e8b47c6..794c6531c3ed 100644 --- a/crypto/bn256/cloudflare/gfp2.go +++ b/crypto/bn256/cloudflare/gfp2.go @@ -137,7 +137,7 @@ func (e *gfP2) Square(a *gfP2) *gfP2 { return e } -func (e *gfP2) Invert(a *gfP2) *gfP2 { +func (e *gfP2) InvertVariableTime(a *gfP2) *gfP2 { // See "Implementing cryptographic pairings", M. Scott, section 3.2. // ftp://136.206.11.249/pub/crypto/pairings.pdf t1, t2 := &gfP{}, &gfP{} @@ -146,7 +146,25 @@ func (e *gfP2) Invert(a *gfP2) *gfP2 { gfpAdd(t1, t1, t2) inv := &gfP{} - inv.Invert(t1) + inv.InvertVariableTime(t1) + + gfpNeg(t1, &a.x) + + gfpMul(&e.x, t1, inv) + gfpMul(&e.y, &a.y, inv) + return e +} + +func (e *gfP2) InvertConstantTime(a *gfP2) *gfP2 { + // See "Implementing cryptographic pairings", M. Scott, section 3.2. + // ftp://136.206.11.249/pub/crypto/pairings.pdf + t1, t2 := &gfP{}, &gfP{} + gfpMul(t1, &a.x, &a.x) + gfpMul(t2, &a.y, &a.y) + gfpAdd(t1, t1, t2) + + inv := &gfP{} + inv.InvertConstantTime(t1) gfpNeg(t1, &a.x) diff --git a/crypto/bn256/cloudflare/gfp6.go b/crypto/bn256/cloudflare/gfp6.go index a42734911c64..2d0306f94093 100644 --- a/crypto/bn256/cloudflare/gfp6.go +++ b/crypto/bn256/cloudflare/gfp6.go @@ -168,7 +168,7 @@ func (e *gfP6) Square(a *gfP6) *gfP6 { return e } -func (e *gfP6) Invert(a *gfP6) *gfP6 { +func (e *gfP6) InvertConstantTime(a *gfP6) *gfP6 { // See "Implementing cryptographic pairings", M. Scott, section 3.2. // ftp://136.206.11.249/pub/crypto/pairings.pdf @@ -204,7 +204,51 @@ func (e *gfP6) Invert(a *gfP6) *gfP6 { t1.Mul(B, &a.x).MulXi(t1) F.Add(F, t1) - F.Invert(F) + F.InvertVariableTime(F) + + e.x.Mul(C, F) + e.y.Mul(B, F) + e.z.Mul(A, F) + return e +} + +func (e *gfP6) InvertVariableTime(a *gfP6) *gfP6 { + // See "Implementing cryptographic pairings", M. Scott, section 3.2. + // ftp://136.206.11.249/pub/crypto/pairings.pdf + + // Here we can give a short explanation of how it works: let j be a cubic root of + // unity in GF(p²) so that 1+j+j²=0. + // Then (xτ² + yτ + z)(xj²τ² + yjτ + z)(xjτ² + yj²τ + z) + // = (xτ² + yτ + z)(Cτ²+Bτ+A) + // = (x³ξ²+y³ξ+z³-3ξxyz) = F is an element of the base field (the norm). + // + // On the other hand (xj²τ² + yjτ + z)(xjτ² + yj²τ + z) + // = τ²(y²-ξxz) + τ(ξx²-yz) + (z²-ξxy) + // + // So that's why A = (z²-ξxy), B = (ξx²-yz), C = (y²-ξxz) + t1 := (&gfP2{}).Mul(&a.x, &a.y) + t1.MulXi(t1) + + A := (&gfP2{}).Square(&a.z) + A.Sub(A, t1) + + B := (&gfP2{}).Square(&a.x) + B.MulXi(B) + t1.Mul(&a.y, &a.z) + B.Sub(B, t1) + + C := (&gfP2{}).Square(&a.y) + t1.Mul(&a.x, &a.z) + C.Sub(C, t1) + + F := (&gfP2{}).Mul(C, &a.y) + F.MulXi(F) + t1.Mul(A, &a.z) + F.Add(F, t1) + t1.Mul(B, &a.x).MulXi(t1) + F.Add(F, t1) + + F.InvertConstantTime(F) e.x.Mul(C, F) e.y.Mul(B, F) diff --git a/crypto/bn256/cloudflare/optate.go b/crypto/bn256/cloudflare/optate.go index b71e50e3a21c..a28ba607b6dd 100644 --- a/crypto/bn256/cloudflare/optate.go +++ b/crypto/bn256/cloudflare/optate.go @@ -124,7 +124,7 @@ func miller(q *twistPoint, p *curvePoint) *gfP12 { aAffine := &twistPoint{} aAffine.Set(q) - aAffine.MakeAffine() + aAffine.MakeAffineConstantTime() bAffine := &curvePoint{} bAffine.Set(p) @@ -217,7 +217,7 @@ func finalExponentiation(in *gfP12) *gfP12 { t1.y.Set(&in.y) inv := &gfP12{} - inv.Invert(in) + inv.InvertConstantTime(in) t1.Mul(t1, inv) t2 := (&gfP12{}).FrobeniusP2(t1) diff --git a/crypto/bn256/cloudflare/twist.go b/crypto/bn256/cloudflare/twist.go index 0c2f80d4eda7..8e10983b316e 100644 --- a/crypto/bn256/cloudflare/twist.go +++ b/crypto/bn256/cloudflare/twist.go @@ -31,7 +31,7 @@ var twistGen = &twistPoint{ } func (c *twistPoint) String() string { - c.MakeAffine() + c.MakeAffineConstantTime() x, y := gfP2Decode(&c.x), gfP2Decode(&c.y) return "(" + x.String() + ", " + y.String() + ")" } @@ -45,7 +45,7 @@ func (c *twistPoint) Set(a *twistPoint) { // IsOnCurve returns true iff c is on the curve. func (c *twistPoint) IsOnCurve() bool { - c.MakeAffine() + c.MakeAffineConstantTime() if c.IsInfinity() { return true } @@ -176,7 +176,7 @@ func (c *twistPoint) Mul(a *twistPoint, scalar *big.Int) { c.Set(sum) } -func (c *twistPoint) MakeAffine() { +func (c *twistPoint) MakeAffineVariableTime() { if c.z.IsOne() { return } else if c.z.IsZero() { @@ -186,7 +186,27 @@ func (c *twistPoint) MakeAffine() { return } - zInv := (&gfP2{}).Invert(&c.z) + zInv := (&gfP2{}).InvertVariableTime(&c.z) + t := (&gfP2{}).Mul(&c.y, zInv) + zInv2 := (&gfP2{}).Square(zInv) + c.y.Mul(t, zInv2) + t.Mul(&c.x, zInv2) + c.x.Set(t) + c.z.SetOne() + c.t.SetOne() +} + +func (c *twistPoint) MakeAffineConstantTime() { + if c.z.IsOne() { + return + } else if c.z.IsZero() { + c.x.SetZero() + c.y.SetOne() + c.t.SetZero() + return + } + + zInv := (&gfP2{}).InvertConstantTime(&c.z) t := (&gfP2{}).Mul(&c.y, zInv) zInv2 := (&gfP2{}).Square(zInv) c.y.Mul(t, zInv2) From 8d5020a5e5a08139aa97252f212227db546815a2 Mon Sep 17 00:00:00 2001 From: Alex Vlasov Date: Thu, 10 Sep 2020 21:01:05 +0300 Subject: [PATCH 4/7] Default to constant time. Make Marshal() vartime instead --- core/vm/contracts.go | 4 ++-- crypto/bn256/cloudflare/bn256.go | 28 ++++++++++++++++++++++++++- crypto/bn256/cloudflare/bn256_test.go | 4 ++-- crypto/bn256/cloudflare/curve.go | 6 +++--- crypto/bn256/cloudflare/gfp.go | 4 ++-- crypto/bn256/cloudflare/gfp12.go | 4 ++-- crypto/bn256/cloudflare/gfp2.go | 4 ++-- crypto/bn256/cloudflare/gfp6.go | 6 +++--- crypto/bn256/cloudflare/optate.go | 4 ++-- crypto/bn256/cloudflare/twist.go | 8 ++++---- 10 files changed, 49 insertions(+), 23 deletions(-) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 8930a06266b8..87a8f1c2dd75 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -338,7 +338,7 @@ func runBn256Add(input []byte) ([]byte, error) { } res := new(bn256.G1) res.Add(x, y) - return res.Marshal(), nil + return res.MarshalVariableTime(), nil } // bn256Add implements a native elliptic curve point addition conforming to @@ -376,7 +376,7 @@ func runBn256ScalarMul(input []byte) ([]byte, error) { } res := new(bn256.G1) res.ScalarMult(p, new(big.Int).SetBytes(getData(input, 64, 32))) - return res.Marshal(), nil + return res.MarshalVariableTime(), nil } // bn256ScalarMulIstanbul implements a native elliptic curve scalar diff --git a/crypto/bn256/cloudflare/bn256.go b/crypto/bn256/cloudflare/bn256.go index 0bc9204d223e..a21bfd9dd669 100644 --- a/crypto/bn256/cloudflare/bn256.go +++ b/crypto/bn256/cloudflare/bn256.go @@ -119,6 +119,32 @@ func (e *G1) Marshal() []byte { return ret } +// Marshal converts e to a byte slice. +// Uses variable time algorithms for inversion +// for transformation to affine coordinates +func (e *G1) MarshalVariableTime() []byte { + // Each value is a 256-bit number. + const numBytes = 256 / 8 + + if e.p == nil { + e.p = &curvePoint{} + } + + e.p.MakeAffineVariableTime() + ret := make([]byte, numBytes*2) + if e.p.IsInfinity() { + return ret + } + temp := &gfP{} + + montDecode(temp, &e.p.x) + temp.Marshal(ret) + montDecode(temp, &e.p.y) + temp.Marshal(ret[numBytes:]) + + return ret +} + // Unmarshal sets e to the result of converting the output of Marshal back into // a group element and then returns e. func (e *G1) Unmarshal(m []byte) ([]byte, error) { @@ -236,7 +262,7 @@ func (e *G2) Marshal() []byte { e.p = &twistPoint{} } - e.p.MakeAffineConstantTime() + e.p.MakeAffine() ret := make([]byte, numBytes*4) if e.p.IsInfinity() { return ret diff --git a/crypto/bn256/cloudflare/bn256_test.go b/crypto/bn256/cloudflare/bn256_test.go index 5d5b7eb8a9c9..f21e2c1f56c7 100644 --- a/crypto/bn256/cloudflare/bn256_test.go +++ b/crypto/bn256/cloudflare/bn256_test.go @@ -99,7 +99,7 @@ func TestBinaryEAA(t *testing.T) { t.Fatal(err) } tmpLittleFermat := &gfP{} - tmpLittleFermat.InvertConstantTime(&Ga.p.x) + tmpLittleFermat.Invert(&Ga.p.x) tmpBinaryEAA := &gfP{} tmpBinaryEAA.InvertVariableTime(&Ga.p.x) @@ -127,7 +127,7 @@ func BenchmarkLittleFermatInversion(b *testing.B) { tmp := &gfP{} for i := 0; i < b.N; i++ { - tmp.InvertConstantTime(&el) + tmp.Invert(&el) } } diff --git a/crypto/bn256/cloudflare/curve.go b/crypto/bn256/cloudflare/curve.go index 23c8064dace9..9a0487086d48 100644 --- a/crypto/bn256/cloudflare/curve.go +++ b/crypto/bn256/cloudflare/curve.go @@ -206,7 +206,7 @@ func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int) { c.Set(sum) } -func (c *curvePoint) MakeAffine() { +func (c *curvePoint) MakeAffineVariableTime() { if c.z == *newGFp(1) { return } else if c.z == *newGFp(0) { @@ -230,7 +230,7 @@ func (c *curvePoint) MakeAffine() { c.t = *newGFp(1) } -func (c *curvePoint) MakeAffineConstantTime() { +func (c *curvePoint) MakeAffine() { if c.z == *newGFp(1) { return } else if c.z == *newGFp(0) { @@ -241,7 +241,7 @@ func (c *curvePoint) MakeAffineConstantTime() { } zInv := &gfP{} - zInv.InvertConstantTime(&c.z) + zInv.Invert(&c.z) t, zInv2 := &gfP{}, &gfP{} gfpMul(t, &c.y, zInv) diff --git a/crypto/bn256/cloudflare/gfp.go b/crypto/bn256/cloudflare/gfp.go index f3aff93077c6..ed7c2f096422 100644 --- a/crypto/bn256/cloudflare/gfp.go +++ b/crypto/bn256/cloudflare/gfp.go @@ -31,7 +31,7 @@ func (e *gfP) Set(f *gfP) { e[3] = f[3] } -func (e *gfP) InvertConstantTime(f *gfP) { +func (e *gfP) Invert(f *gfP) { bits := [4]uint64{0x3c208c16d87cfd45, 0x97816a916871ca8d, 0xb85045b68181585d, 0x30644e72e131a029} sum, power := &gfP{}, &gfP{} @@ -82,7 +82,7 @@ func montEncode(c, a *gfP) { gfpMul(c, a, r2) } func montDecode(c, a *gfP) { gfpMul(c, a, &gfP{1}) } func isZero(a *gfP) bool { - return a[0] == 0 && a[1] == 0 && a[2] == 0 && a[3] == 0 + return (a[0] | a[1] | a[2] | a[3]) == 0 } func isEven(a *gfP) bool { diff --git a/crypto/bn256/cloudflare/gfp12.go b/crypto/bn256/cloudflare/gfp12.go index e8da86952779..db38c810b04f 100644 --- a/crypto/bn256/cloudflare/gfp12.go +++ b/crypto/bn256/cloudflare/gfp12.go @@ -159,7 +159,7 @@ func (e *gfP12) InvertVariableTime(a *gfP12) *gfP12 { return e } -func (e *gfP12) InvertConstantTime(a *gfP12) *gfP12 { +func (e *gfP12) Invert(a *gfP12) *gfP12 { // See "Implementing cryptographic pairings", M. Scott, section 3.2. // ftp://136.206.11.249/pub/crypto/pairings.pdf t1, t2 := &gfP6{}, &gfP6{} @@ -167,7 +167,7 @@ func (e *gfP12) InvertConstantTime(a *gfP12) *gfP12 { t1.Square(&a.x) t2.Square(&a.y) t1.MulTau(t1).Sub(t2, t1) - t2.InvertConstantTime(t1) + t2.Invert(t1) e.x.Neg(&a.x) e.y.Set(&a.y) diff --git a/crypto/bn256/cloudflare/gfp2.go b/crypto/bn256/cloudflare/gfp2.go index 794c6531c3ed..533358510eb4 100644 --- a/crypto/bn256/cloudflare/gfp2.go +++ b/crypto/bn256/cloudflare/gfp2.go @@ -155,7 +155,7 @@ func (e *gfP2) InvertVariableTime(a *gfP2) *gfP2 { return e } -func (e *gfP2) InvertConstantTime(a *gfP2) *gfP2 { +func (e *gfP2) Invert(a *gfP2) *gfP2 { // See "Implementing cryptographic pairings", M. Scott, section 3.2. // ftp://136.206.11.249/pub/crypto/pairings.pdf t1, t2 := &gfP{}, &gfP{} @@ -164,7 +164,7 @@ func (e *gfP2) InvertConstantTime(a *gfP2) *gfP2 { gfpAdd(t1, t1, t2) inv := &gfP{} - inv.InvertConstantTime(t1) + inv.Invert(t1) gfpNeg(t1, &a.x) diff --git a/crypto/bn256/cloudflare/gfp6.go b/crypto/bn256/cloudflare/gfp6.go index 2d0306f94093..87a72fd6e27c 100644 --- a/crypto/bn256/cloudflare/gfp6.go +++ b/crypto/bn256/cloudflare/gfp6.go @@ -168,7 +168,7 @@ func (e *gfP6) Square(a *gfP6) *gfP6 { return e } -func (e *gfP6) InvertConstantTime(a *gfP6) *gfP6 { +func (e *gfP6) Invert(a *gfP6) *gfP6 { // See "Implementing cryptographic pairings", M. Scott, section 3.2. // ftp://136.206.11.249/pub/crypto/pairings.pdf @@ -204,7 +204,7 @@ func (e *gfP6) InvertConstantTime(a *gfP6) *gfP6 { t1.Mul(B, &a.x).MulXi(t1) F.Add(F, t1) - F.InvertVariableTime(F) + F.Invert(F) e.x.Mul(C, F) e.y.Mul(B, F) @@ -248,7 +248,7 @@ func (e *gfP6) InvertVariableTime(a *gfP6) *gfP6 { t1.Mul(B, &a.x).MulXi(t1) F.Add(F, t1) - F.InvertConstantTime(F) + F.InvertVariableTime(F) e.x.Mul(C, F) e.y.Mul(B, F) diff --git a/crypto/bn256/cloudflare/optate.go b/crypto/bn256/cloudflare/optate.go index a28ba607b6dd..b71e50e3a21c 100644 --- a/crypto/bn256/cloudflare/optate.go +++ b/crypto/bn256/cloudflare/optate.go @@ -124,7 +124,7 @@ func miller(q *twistPoint, p *curvePoint) *gfP12 { aAffine := &twistPoint{} aAffine.Set(q) - aAffine.MakeAffineConstantTime() + aAffine.MakeAffine() bAffine := &curvePoint{} bAffine.Set(p) @@ -217,7 +217,7 @@ func finalExponentiation(in *gfP12) *gfP12 { t1.y.Set(&in.y) inv := &gfP12{} - inv.InvertConstantTime(in) + inv.Invert(in) t1.Mul(t1, inv) t2 := (&gfP12{}).FrobeniusP2(t1) diff --git a/crypto/bn256/cloudflare/twist.go b/crypto/bn256/cloudflare/twist.go index 8e10983b316e..4f5f5080f16d 100644 --- a/crypto/bn256/cloudflare/twist.go +++ b/crypto/bn256/cloudflare/twist.go @@ -31,7 +31,7 @@ var twistGen = &twistPoint{ } func (c *twistPoint) String() string { - c.MakeAffineConstantTime() + c.MakeAffine() x, y := gfP2Decode(&c.x), gfP2Decode(&c.y) return "(" + x.String() + ", " + y.String() + ")" } @@ -45,7 +45,7 @@ func (c *twistPoint) Set(a *twistPoint) { // IsOnCurve returns true iff c is on the curve. func (c *twistPoint) IsOnCurve() bool { - c.MakeAffineConstantTime() + c.MakeAffine() if c.IsInfinity() { return true } @@ -196,7 +196,7 @@ func (c *twistPoint) MakeAffineVariableTime() { c.t.SetOne() } -func (c *twistPoint) MakeAffineConstantTime() { +func (c *twistPoint) MakeAffine() { if c.z.IsOne() { return } else if c.z.IsZero() { @@ -206,7 +206,7 @@ func (c *twistPoint) MakeAffineConstantTime() { return } - zInv := (&gfP2{}).InvertConstantTime(&c.z) + zInv := (&gfP2{}).Invert(&c.z) t := (&gfP2{}).Mul(&c.y, zInv) zInv2 := (&gfP2{}).Square(zInv) c.y.Mul(t, zInv2) From 40f5708f3aa8e62e25f416953cbfd439c4f01dce Mon Sep 17 00:00:00 2001 From: Alex Vlasov Date: Fri, 11 Sep 2020 12:50:53 +0300 Subject: [PATCH 5/7] cleanup --- crypto/bn256/cloudflare/bn256_test.go | 6 +-- crypto/bn256/cloudflare/gfp.go | 54 +++++++++------------------ 2 files changed, 19 insertions(+), 41 deletions(-) diff --git a/crypto/bn256/cloudflare/bn256_test.go b/crypto/bn256/cloudflare/bn256_test.go index f21e2c1f56c7..e1d7fd5f1e14 100644 --- a/crypto/bn256/cloudflare/bn256_test.go +++ b/crypto/bn256/cloudflare/bn256_test.go @@ -108,13 +108,11 @@ func TestBinaryEAA(t *testing.T) { tmpBinaryEAASelfSet.Set(&Ga.p.x) tmpBinaryEAASelfSet.InvertVariableTime(tmpBinaryEAASelfSet) - eq := equals(tmpLittleFermat, tmpBinaryEAA) - if eq == false { + if *tmpLittleFermat != *tmpBinaryEAA { t.Fatalf("results of different inversion do not agree") } - eq = equals(tmpLittleFermat, tmpBinaryEAASelfSet) - if eq == false { + if *tmpLittleFermat != *tmpBinaryEAASelfSet { t.Fatalf("self-assigned inversion is invalid") } } diff --git a/crypto/bn256/cloudflare/gfp.go b/crypto/bn256/cloudflare/gfp.go index ed7c2f096422..1ae6cf9a3b05 100644 --- a/crypto/bn256/cloudflare/gfp.go +++ b/crypto/bn256/cloudflare/gfp.go @@ -86,7 +86,7 @@ func isZero(a *gfP) bool { } func isEven(a *gfP) bool { - return bits.TrailingZeros64((a[0])) > 0 + return a[0]&1 == 0 } func div2(a *gfP) { @@ -123,10 +123,6 @@ func gte(a, b *gfP) bool { return borrow == 0 } -func equals(a, b *gfP) bool { - return a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3] -} - // Performs inversion of the field element using binary EEA. // If element is zero (no inverse exists) then set `e` to zero func (e *gfP) InvertVariableTime(f *gfP) { @@ -145,63 +141,47 @@ func (e *gfP) InvertVariableTime(f *gfP) { u.Set(f) b.Set(r2) - v := gfP{p2[0], p2[1], p2[2], p2[3]} + v := gfP(p2) c := gfP{0, 0, 0, 0} - modulus := gfP{p2[0], p2[1], p2[2], p2[3]} - - for { - if equals(&u, &one) || equals(&v, &one) { - break - } + modulus := gfP(p2) + for u != one && v != one { // while u is even - for { - if !isEven(&u) { - break - } - + for isEven(&u) { div2(&u) - if isEven(&b) { - div2(&b) - } else { + if !isEven(&b) { // we will not overflow a modulus here, // so we can use specialized function // do perform addition without reduction b.addNocarry(&modulus) - div2(&b) } + div2(&b) } // while v is even - for { - if !isEven(&v) { - break - } - + for isEven(&v) { div2(&v) - if isEven(&c) { - div2(&c) - } else { + if !isEven(&c) { // we will not overflow a modulus here, // so we can use specialized function // do perform addition without reduction c.addNocarry(&modulus) - div2(&c) + } else { + } + div2(&c) } - if gte(&v, &u) { - // v >= u - v.subNoborrow(&u) - gfpSub(&c, &c, &b) - } else { - // if v < u + if gte(&u, &v) { u.subNoborrow(&v) gfpSub(&b, &b, &c) + } else { + v.subNoborrow(&u) + gfpSub(&c, &c, &b) } } - if equals(&u, &one) { + if u == one { e.Set(&b) } else { e.Set(&c) From 77c8f3c468d9bfac9219a8a4234691d970d05f8e Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 15 Sep 2020 13:14:42 +0200 Subject: [PATCH 6/7] added fuzzer --- crypto/bn256/cloudflare/bn256.go | 17 +++++++++++++++++ .../07c9199009bd79044f4041b084ef158a7ac2f66d-1 | 1 + .../0f57d28c4168244c6f90aa3d9a99d64d33698243-4 | 1 + .../0feed69da5a6bda0ae2c7f5d0274401f03caa1f0-5 | Bin 0 -> 25 bytes .../10652cc66509610582932608143f65cfda032d06-1 | 1 + .../1ad4c39ef8f74cb004bb3210c593a5af3fe300c2-2 | 1 + .../2c6692a15a45db3d5594f264c042996af11b0563-2 | 1 + ...375558a8683127df952cea26d54e2117afe0a4f4-15 | 1 + ...3a10b9848e0c7fbfbaaa68221cdd5409a55037a2-10 | 1 + .../42515ce5642ad58b4bd4571f03583561f81562ed-2 | Bin 0 -> 51 bytes .../42b0c72ed5839a82c1713588945627b0b957520a-4 | 1 + .../537a65c5bb620e17869c5d29816641eb1e0b4d77-4 | 1 + .../542ec7a8f8915b53f1fa86e89ab8c205f4406a89-5 | 1 + .../5b2f702be9d68b4fa3343dc502b82aca66ac79ac-1 | Bin 0 -> 56 bytes .../5ba93c9db0cff93f52b521d7420e43f6eda2784f-1 | Bin 0 -> 1 bytes ...5d6b1f52eb5963e058631e208ed7e42fe737c17b-11 | 1 + .../63c5b8ef764aec4065823c8384fa449a13dda127-5 | 1 + .../7177d67ab7a66c2d734d661f17254c6059227d46-5 | 1 + .../71d4fb7cadd2a3a626c8e6f8c8ff2ac58d5c3d11-1 | 1 + ...731cf6eb251a941dc4f725fb475b48e4a6bf4ac2-13 | 1 + .../75d5bde9b08f68446f39675d33f06373cc3cc657-4 | 1 + .../784fe4d548210a81635fb4be628208fd40c4f1e6-3 | 1 + .../7b908eb39e1448ac1660770e77a4fe04ebbec50b-6 | 1 + ...83de6dd4bce8e2e0a64aab81374af2257a0de4e0-10 | 1 + ...8abe94f6ec077cd9bb07bbe014f5acf384b008cc-14 | 1 + .../8da2c38f239f130f71660ef73a307b2ab9e9abf7-2 | 1 + .../8e0c3ca5c43ef63b61ee6c4a00142eabc8d6f87f-4 | 1 + .../92fff21d155559f03a8d89d4470af33edc1a7729-2 | 1 + ...a78616eec08ece4c3f640f3757b99f4b8a2da1ea-12 | 1 + .../a9ba900c94971240ed0e40dc06a0a66951f9a1c4-2 | 1 + crypto/bn256/cloudflare/corpus/adsf | 1 + crypto/bn256/cloudflare/corpus/asdaf | 1 + .../b27e2a272f699ef6f191a9bd8ac8850cd31f328b-9 | 1 + .../b2a373e746e2547e90de614917dfe79dae877741-7 | 1 + ...b2e7f9aefb81dfa43956eb35b6cc161ac34e6a83-16 | 1 + .../b323c0ccd309ce19e3789ad08129407337db48c2-2 | Bin 0 -> 137 bytes .../b6aa00dbfb54b3611122b8de5f2d689221051c16-5 | 1 + .../bd780cc351a62d344f6300d7c76f937c190123e6-1 | 1 + .../bdfa978fc503ffed27aeed20e9766f353c5f2a38-2 | 1 + .../bf8b4530d8d246dd74ac53a13471bba17941dff7-1 | 1 + .../c1076a8aa61b7bfcc30736a4e8c50d70e3ebeb65-2 | 1 + .../c4214de44c0a7b5b3a2b42af25c4cc173a1a3f06-3 | 1 + .../c57e070aaac9567405ea3e895d61829bfafb453b-3 | Bin 0 -> 7 bytes .../da39a3ee5e6b4b0d3255bfef95601890afd80709 | 0 .../e64dd62bd352b0387e9ce6890dc93ba3d61578b5-1 | 1 + .../ed1ffddcfca965bd4f8e49a6a8bc680081c25035-6 | 1 + .../f031927af198b3e4aefd7244113e4a004f9368f3-3 | Bin 0 -> 110 bytes .../f04b0f8a2ef23dc4ba2694706e789bc525a69d02-8 | 1 + .../fcefd5c9efad891253cdb8671d07be76165b3aad-5 | 1 + crypto/bn256/cloudflare/corpus/zero | 1 + crypto/bn256/cloudflare/corpus/zeroz | 1 + crypto/bn256/cloudflare/corpus/zerozero | 0 52 files changed, 59 insertions(+) create mode 100644 crypto/bn256/cloudflare/corpus/07c9199009bd79044f4041b084ef158a7ac2f66d-1 create mode 100644 crypto/bn256/cloudflare/corpus/0f57d28c4168244c6f90aa3d9a99d64d33698243-4 create mode 100644 crypto/bn256/cloudflare/corpus/0feed69da5a6bda0ae2c7f5d0274401f03caa1f0-5 create mode 100644 crypto/bn256/cloudflare/corpus/10652cc66509610582932608143f65cfda032d06-1 create mode 100644 crypto/bn256/cloudflare/corpus/1ad4c39ef8f74cb004bb3210c593a5af3fe300c2-2 create mode 100644 crypto/bn256/cloudflare/corpus/2c6692a15a45db3d5594f264c042996af11b0563-2 create mode 100644 crypto/bn256/cloudflare/corpus/375558a8683127df952cea26d54e2117afe0a4f4-15 create mode 100644 crypto/bn256/cloudflare/corpus/3a10b9848e0c7fbfbaaa68221cdd5409a55037a2-10 create mode 100644 crypto/bn256/cloudflare/corpus/42515ce5642ad58b4bd4571f03583561f81562ed-2 create mode 100644 crypto/bn256/cloudflare/corpus/42b0c72ed5839a82c1713588945627b0b957520a-4 create mode 100644 crypto/bn256/cloudflare/corpus/537a65c5bb620e17869c5d29816641eb1e0b4d77-4 create mode 100644 crypto/bn256/cloudflare/corpus/542ec7a8f8915b53f1fa86e89ab8c205f4406a89-5 create mode 100644 crypto/bn256/cloudflare/corpus/5b2f702be9d68b4fa3343dc502b82aca66ac79ac-1 create mode 100644 crypto/bn256/cloudflare/corpus/5ba93c9db0cff93f52b521d7420e43f6eda2784f-1 create mode 100644 crypto/bn256/cloudflare/corpus/5d6b1f52eb5963e058631e208ed7e42fe737c17b-11 create mode 100644 crypto/bn256/cloudflare/corpus/63c5b8ef764aec4065823c8384fa449a13dda127-5 create mode 100644 crypto/bn256/cloudflare/corpus/7177d67ab7a66c2d734d661f17254c6059227d46-5 create mode 100644 crypto/bn256/cloudflare/corpus/71d4fb7cadd2a3a626c8e6f8c8ff2ac58d5c3d11-1 create mode 100644 crypto/bn256/cloudflare/corpus/731cf6eb251a941dc4f725fb475b48e4a6bf4ac2-13 create mode 100644 crypto/bn256/cloudflare/corpus/75d5bde9b08f68446f39675d33f06373cc3cc657-4 create mode 100644 crypto/bn256/cloudflare/corpus/784fe4d548210a81635fb4be628208fd40c4f1e6-3 create mode 100644 crypto/bn256/cloudflare/corpus/7b908eb39e1448ac1660770e77a4fe04ebbec50b-6 create mode 100644 crypto/bn256/cloudflare/corpus/83de6dd4bce8e2e0a64aab81374af2257a0de4e0-10 create mode 100644 crypto/bn256/cloudflare/corpus/8abe94f6ec077cd9bb07bbe014f5acf384b008cc-14 create mode 100644 crypto/bn256/cloudflare/corpus/8da2c38f239f130f71660ef73a307b2ab9e9abf7-2 create mode 100644 crypto/bn256/cloudflare/corpus/8e0c3ca5c43ef63b61ee6c4a00142eabc8d6f87f-4 create mode 100644 crypto/bn256/cloudflare/corpus/92fff21d155559f03a8d89d4470af33edc1a7729-2 create mode 100644 crypto/bn256/cloudflare/corpus/a78616eec08ece4c3f640f3757b99f4b8a2da1ea-12 create mode 100644 crypto/bn256/cloudflare/corpus/a9ba900c94971240ed0e40dc06a0a66951f9a1c4-2 create mode 100644 crypto/bn256/cloudflare/corpus/adsf create mode 100644 crypto/bn256/cloudflare/corpus/asdaf create mode 100644 crypto/bn256/cloudflare/corpus/b27e2a272f699ef6f191a9bd8ac8850cd31f328b-9 create mode 100644 crypto/bn256/cloudflare/corpus/b2a373e746e2547e90de614917dfe79dae877741-7 create mode 100644 crypto/bn256/cloudflare/corpus/b2e7f9aefb81dfa43956eb35b6cc161ac34e6a83-16 create mode 100644 crypto/bn256/cloudflare/corpus/b323c0ccd309ce19e3789ad08129407337db48c2-2 create mode 100644 crypto/bn256/cloudflare/corpus/b6aa00dbfb54b3611122b8de5f2d689221051c16-5 create mode 100644 crypto/bn256/cloudflare/corpus/bd780cc351a62d344f6300d7c76f937c190123e6-1 create mode 100644 crypto/bn256/cloudflare/corpus/bdfa978fc503ffed27aeed20e9766f353c5f2a38-2 create mode 100644 crypto/bn256/cloudflare/corpus/bf8b4530d8d246dd74ac53a13471bba17941dff7-1 create mode 100644 crypto/bn256/cloudflare/corpus/c1076a8aa61b7bfcc30736a4e8c50d70e3ebeb65-2 create mode 100644 crypto/bn256/cloudflare/corpus/c4214de44c0a7b5b3a2b42af25c4cc173a1a3f06-3 create mode 100644 crypto/bn256/cloudflare/corpus/c57e070aaac9567405ea3e895d61829bfafb453b-3 create mode 100644 crypto/bn256/cloudflare/corpus/da39a3ee5e6b4b0d3255bfef95601890afd80709 create mode 100644 crypto/bn256/cloudflare/corpus/e64dd62bd352b0387e9ce6890dc93ba3d61578b5-1 create mode 100644 crypto/bn256/cloudflare/corpus/ed1ffddcfca965bd4f8e49a6a8bc680081c25035-6 create mode 100644 crypto/bn256/cloudflare/corpus/f031927af198b3e4aefd7244113e4a004f9368f3-3 create mode 100644 crypto/bn256/cloudflare/corpus/f04b0f8a2ef23dc4ba2694706e789bc525a69d02-8 create mode 100644 crypto/bn256/cloudflare/corpus/fcefd5c9efad891253cdb8671d07be76165b3aad-5 create mode 100644 crypto/bn256/cloudflare/corpus/zero create mode 100644 crypto/bn256/cloudflare/corpus/zeroz create mode 100644 crypto/bn256/cloudflare/corpus/zerozero diff --git a/crypto/bn256/cloudflare/bn256.go b/crypto/bn256/cloudflare/bn256.go index a21bfd9dd669..beb6d96f6368 100644 --- a/crypto/bn256/cloudflare/bn256.go +++ b/crypto/bn256/cloudflare/bn256.go @@ -16,8 +16,11 @@ package bn256 import ( "crypto/rand" "errors" + "fmt" "io" "math/big" + + fuzz "github.com/google/gofuzz" ) func randomK(r io.Reader) (k *big.Int, err error) { @@ -49,6 +52,20 @@ func (g *G1) String() string { return "bn256.G1" + g.p.String() } +func Fuzz(data []byte) int { + var gfpTest gfP + f := fuzz.NewFromGoFuzz(data) + f.Fuzz(&gfpTest) + zInvVar := &gfP{} + zInvVar.InvertVariableTime(&gfpTest) + zInv := &gfP{} + zInv.Invert(&gfpTest) + if zInv[0] != zInvVar[0] || zInv[1] != zInvVar[1] || zInv[2] != zInvVar[2] || zInv[3] != zInvVar[3] { + panic(fmt.Sprintf("invalid invert: %v %v", zInv, zInvVar)) + } + return 0 +} + // ScalarBaseMult sets e to g*k where g is the generator of the group and then // returns e. func (e *G1) ScalarBaseMult(k *big.Int) *G1 { diff --git a/crypto/bn256/cloudflare/corpus/07c9199009bd79044f4041b084ef158a7ac2f66d-1 b/crypto/bn256/cloudflare/corpus/07c9199009bd79044f4041b084ef158a7ac2f66d-1 new file mode 100644 index 000000000000..28d9e76cac78 --- /dev/null +++ b/crypto/bn256/cloudflare/corpus/07c9199009bd79044f4041b084ef158a7ac2f66d-1 @@ -0,0 +1 @@ +;8w \ No newline at end of file diff --git a/crypto/bn256/cloudflare/corpus/0f57d28c4168244c6f90aa3d9a99d64d33698243-4 b/crypto/bn256/cloudflare/corpus/0f57d28c4168244c6f90aa3d9a99d64d33698243-4 new file mode 100644 index 000000000000..974ea1dc2bae --- /dev/null +++ b/crypto/bn256/cloudflare/corpus/0f57d28c4168244c6f90aa3d9a99d64d33698243-4 @@ -0,0 +1 @@ +ty710542pe 437764856785504449281190514550177096728800832068CallSlice-466353402crypto/ra blobocked for 70 ecordrandnds waiting to read er for 60 econds waiting to read random data from the kernelnot a pointerrandom data fromthe kerWelnota pointed: \ No newline at end of file diff --git a/crypto/bn256/cloudflare/corpus/0feed69da5a6bda0ae2c7f5d0274401f03caa1f0-5 b/crypto/bn256/cloudflare/corpus/0feed69da5a6bda0ae2c7f5d0274401f03caa1f0-5 new file mode 100644 index 0000000000000000000000000000000000000000..b8bf202a0c2a3112f635c142f9bc9e6ce58fb1e7 GIT binary patch literal 25 ZcmZQ%fCGj17MAP \ No newline at end of file diff --git a/crypto/bn256/cloudflare/corpus/375558a8683127df952cea26d54e2117afe0a4f4-15 b/crypto/bn256/cloudflare/corpus/375558a8683127df952cea26d54e2117afe0a4f4-15 new file mode 100644 index 000000000000..3f0bf99f03dd --- /dev/null +++ b/crypto/bn256/cloudflare/corpus/375558a8683127df952cea26d54e2117afe0a4f4-15 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/crypto/bn256/cloudflare/corpus/3a10b9848e0c7fbfbaaa68221cdd5409a55037a2-10 b/crypto/bn256/cloudflare/corpus/3a10b9848e0c7fbfbaaa68221cdd5409a55037a2-10 new file mode 100644 index 000000000000..df9af24a5cbc --- /dev/null +++ b/crypto/bn256/cloudflare/corpus/3a10b9848e0c7fbfbaaa68221cdd5409a55037a2-10 @@ -0,0 +1 @@ + 2155010672361yt/rrrn aig3319bood t763726738rbc@udittm778375564928114"051455017709672880083202068677396868739640837315@616991234crypto/ra blobockrandom d0 ecordrandnds waiting to read random dataBfroo readdrandom data from the kernelno \ No newline at end of file diff --git a/crypto/bn256/cloudflare/corpus/42515ce5642ad58b4bd4571f03583561f81562ed-2 b/crypto/bn256/cloudflare/corpus/42515ce5642ad58b4bd4571f03583561f81562ed-2 new file mode 100644 index 0000000000000000000000000000000000000000..8893a02800a8c9e877d5bf7ce6feb1db3625f66f GIT binary patch literal 51 zcmXrFG%+(bHM6iVG`FziifTN_$gUTx-DYfPU~Xn=AY)(wl{PT8FfcYTWMnY1001lh B3fcew literal 0 HcmV?d00001 diff --git a/crypto/bn256/cloudflare/corpus/42b0c72ed5839a82c1713588945627b0b957520a-4 b/crypto/bn256/cloudflare/corpus/42b0c72ed5839a82c1713588945627b0b957520a-4 new file mode 100644 index 000000000000..05c326312246 --- /dev/null +++ b/crypto/bn256/cloudflare/corpus/42b0c72ed5839a82c1713588945627b0b957520a-4 @@ -0,0 +1 @@ +89wQʭ \ No newline at end of file diff --git a/crypto/bn256/cloudflare/corpus/537a65c5bb620e17869c5d29816641eb1e0b4d77-4 b/crypto/bn256/cloudflare/corpus/537a65c5bb620e17869c5d29816641eb1e0b4d77-4 new file mode 100644 index 000000000000..3c1e64ea849f --- /dev/null +++ b/crypto/bn256/cloudflare/corpus/537a65c5bb620e17869c5d29816641eb1e0b4d77-4 @@ -0,0 +1 @@ +ty710542pe 43776485743678550444492811490514550177096728800832068687396408373151616991234crypto/ra blobocryp/otrand: blocked for 60 seconds waiting to read random data from the kernelcked for 70 ecordrandnds waiting to read random data from the kernelnota pointer: \ No newline at end of file diff --git a/crypto/bn256/cloudflare/corpus/542ec7a8f8915b53f1fa86e89ab8c205f4406a89-5 b/crypto/bn256/cloudflare/corpus/542ec7a8f8915b53f1fa86e89ab8c205f4406a89-5 new file mode 100644 index 000000000000..1fcb914274fd --- /dev/null +++ b/crypto/bn256/cloudflare/corpus/542ec7a8f8915b53f1fa86e89ab8c205f4406a89-5 @@ -0,0 +1 @@ +ty1051149051455017709672880832068687396408373151616991234crypto/ra blobocked for 70 ecordrandnds waiting to read random42pe 43776485743678550444492811490514550177096728800832068687396408373151616991234crypto/ra blobocked for 70 ecordrandnds waiting to read random data from the kernelnota point \ No newline at end of file diff --git a/crypto/bn256/cloudflare/corpus/5b2f702be9d68b4fa3343dc502b82aca66ac79ac-1 b/crypto/bn256/cloudflare/corpus/5b2f702be9d68b4fa3343dc502b82aca66ac79ac-1 new file mode 100644 index 0000000000000000000000000000000000000000..7deb5a9d4fbafe5ee1a14812d277c058305e97d3 GIT binary patch literal 56 zcmXpsF}E}^GdDG}urM^Yu;hwrJjlqd7p&c8Y-njjOV7y6%FfBn%P%M_Dppl4Ei13Aa&&fab#wRdVrcO7^A9M= z&sWGz%&SyL&d*COEhCDe7R>;p&NK`1!%uCNnRY=PO68S|6#retE lsU->;xrr4Dh6W}Ursk%afkD9yp<&?>kx}pW?**cpvjNXbGK2sC literal 0 HcmV?d00001 diff --git a/crypto/bn256/cloudflare/corpus/b6aa00dbfb54b3611122b8de5f2d689221051c16-5 b/crypto/bn256/cloudflare/corpus/b6aa00dbfb54b3611122b8de5f2d689221051c16-5 new file mode 100644 index 000000000000..8d06eb296f3a --- /dev/null +++ b/crypto/bn256/cloudflare/corpus/b6aa00dbfb54b3611122b8de5f2d689221051c16-5 @@ -0,0 +1 @@ +ty710542pe 3776485743678550444492811490514550177096728800832068687396408373151616991234crypto/ra blobocryp/otrand: b read random d the kerfor 70 ecordrandnds waiting to read random data from the kernelnota pointer: \ No newline at end of file diff --git a/crypto/bn256/cloudflare/corpus/bd780cc351a62d344f6300d7c76f937c190123e6-1 b/crypto/bn256/cloudflare/corpus/bd780cc351a62d344f6300d7c76f937c190123e6-1 new file mode 100644 index 000000000000..cd84aefe6a5e --- /dev/null +++ b/crypto/bn256/cloudflare/corpus/bd780cc351a62d344f6300d7c76f937c190123e6-1 @@ -0,0 +1 @@ +0123456789abcdefghijklmnopqrst%#uvwxyzA Date: Mon, 21 Sep 2020 16:30:48 +0200 Subject: [PATCH 7/7] bn256: better fuzzer for inversion --- crypto/bn256/cloudflare/bn256.go | 17 ------ crypto/bn256/cloudflare/fuzz.go | 98 ++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 17 deletions(-) create mode 100644 crypto/bn256/cloudflare/fuzz.go diff --git a/crypto/bn256/cloudflare/bn256.go b/crypto/bn256/cloudflare/bn256.go index beb6d96f6368..a21bfd9dd669 100644 --- a/crypto/bn256/cloudflare/bn256.go +++ b/crypto/bn256/cloudflare/bn256.go @@ -16,11 +16,8 @@ package bn256 import ( "crypto/rand" "errors" - "fmt" "io" "math/big" - - fuzz "github.com/google/gofuzz" ) func randomK(r io.Reader) (k *big.Int, err error) { @@ -52,20 +49,6 @@ func (g *G1) String() string { return "bn256.G1" + g.p.String() } -func Fuzz(data []byte) int { - var gfpTest gfP - f := fuzz.NewFromGoFuzz(data) - f.Fuzz(&gfpTest) - zInvVar := &gfP{} - zInvVar.InvertVariableTime(&gfpTest) - zInv := &gfP{} - zInv.Invert(&gfpTest) - if zInv[0] != zInvVar[0] || zInv[1] != zInvVar[1] || zInv[2] != zInvVar[2] || zInv[3] != zInvVar[3] { - panic(fmt.Sprintf("invalid invert: %v %v", zInv, zInvVar)) - } - return 0 -} - // ScalarBaseMult sets e to g*k where g is the generator of the group and then // returns e. func (e *G1) ScalarBaseMult(k *big.Int) *G1 { diff --git a/crypto/bn256/cloudflare/fuzz.go b/crypto/bn256/cloudflare/fuzz.go new file mode 100644 index 000000000000..14a939b722fa --- /dev/null +++ b/crypto/bn256/cloudflare/fuzz.go @@ -0,0 +1,98 @@ +package bn256 + +import ( + "fmt" + + fuzz "github.com/google/gofuzz" +) + +func Fuzz(data []byte) int { + var gfpTest gfP + f := fuzz.NewFromGoFuzz(data) + f.Fuzz(&gfpTest) + zInvVar := &gfP{} + zInvVar.InvertVariableTime(&gfpTest) + zInv := &gfP{} + zInv.Invert(&gfpTest) + if !gfpEq(zInv, zInvVar) { + panic(fmt.Sprintf("invalid invert: %v %v", zInv, zInvVar)) + } + return 0 +} + +func Fuzz2(data []byte) int { + var gfpTest gfP2 + f := fuzz.NewFromGoFuzz(data) + f.Fuzz(&gfpTest) + zInvVar := &gfP2{} + zInvVar.InvertVariableTime(&gfpTest) + zInv := &gfP2{} + zInv.Invert(&gfpTest) + if !gfp2Eq(zInv, zInvVar) { + panic(fmt.Sprintf("invalid invert: %v %v", zInv, zInvVar)) + } + return 0 +} + +func Fuzz3(data []byte) int { + var gfpTest gfP6 + f := fuzz.NewFromGoFuzz(data) + f.Fuzz(&gfpTest) + zInvVar := &gfP6{} + zInvVar.InvertVariableTime(&gfpTest) + zInv := &gfP6{} + zInv.Invert(&gfpTest) + if !gfp6Eq(zInv, zInvVar) { + panic(fmt.Sprintf("invalid invert: %v %v", zInv, zInvVar)) + } + return 0 +} + +func Fuzz4(data []byte) int { + var gfpTest gfP12 + f := fuzz.NewFromGoFuzz(data) + f.Fuzz(&gfpTest) + zInvVar := &gfP12{} + zInvVar.InvertVariableTime(&gfpTest) + zInv := &gfP12{} + zInv.Invert(&gfpTest) + if !gfp12Eq(zInv, zInvVar) { + panic(fmt.Sprintf("invalid invert: %v %v", zInv, zInvVar)) + } + return 0 +} + +func gfp12Eq(a, b *gfP12) bool { + if gfp6Eq(&a.x, &b.x) && + gfp6Eq(&a.y, &b.y) { + return true + } + return false +} + +func gfp6Eq(a, b *gfP6) bool { + if gfp2Eq(&a.x, &b.x) && + gfp2Eq(&a.y, &b.y) && + gfp2Eq(&a.z, &b.z) { + return true + } + return false +} + +func gfp2Eq(a, b *gfP2) bool { + if gfpEq(&a.x, &b.x) && + gfpEq(&a.y, &b.y) { + return true + } + return false +} + +func gfpEq(a, b *gfP) bool { + if a[0] == b[0] && + a[1] == b[1] && + a[2] == b[2] && + a[3] == b[3] { + return true + } + return false +}