Skip to content

Commit

Permalink
Add BN254 (#55)
Browse files Browse the repository at this point in the history
* implement ethereum bn254
* pull in missing changes from geth
* make G2 points affine in ValidatePairing
* move bn254 to own dir
* fix bn254 GT Base and Null
* test G1 suite against gnark-crypto
* adapt G2 test to gnark-crypto, fix bn254 marshal ids
* fix G1 hashToPoint reference tests
* fix pairing/bn254/gfp_amd64.s
* use keccak256 instead of sha256 in bn254
* implement TestGT for bn254
* implement hashToField, expandMsgXmd
* implement mapToPoint
* implement hashToPoint
* rename toPointG1 -> fromBigInt
* add comments on mapToPoint, cleanup
* fix TestPointG1_HashToPoint with new keccak256 impl
* use ref implementation of expand_message_xmd
* panic if DST length > 255
* remove unnecessary iteration in expandMsgXmd
* update tests to use full length DSTs
* set DST in group instead of suite
* fix: actually write bytes in zeroPadBytes
* fix: leftpad intermediate prb in expandMsgXmd
* fix: leftpad intermediate xored hashes in expandMsgXmd
* add instructions to create hash-to-point reference values, remove old TODO
* remove irrelevant issue400 test for bn254
* use CX instead of R15 in amd64

replaying fix from geth, see: ethereum/go-ethereum@ec64358

When using -buildmode=shared, R15 is clobbered by a global variable
access; use a different register instead.

* remove gfp.h in bn254
* use geth's Unmarshal func: error out on invalid coordinates
* make constants z0 and z1 private
* check that random points are different in TestG1Ops
* implement Stringer interface for bn254 groups
* remove irrelevant benchmarks
* implement SVDW from RFC9380 for bn254 G1 map-to-point
* encode the right variable in hashToField
* borrow expand_message_xmd implementation from kilic-bls12381
* update test vectors in TestPointG1_HashToPoint, TestHashToField
* test expandMsgXmd against a copy of gnark's
* fix default DST for hash-to-curve
* remove unused fromBigInt func
* add sources for gfp exp/sqrt functions
* use curveB constant in g(x)
* create new DST buffers instead of passing refs
  • Loading branch information
kevincharm committed Mar 18, 2024
1 parent 266eb7b commit 6fadd9d
Show file tree
Hide file tree
Showing 30 changed files with 9,814 additions and 1 deletion.
7 changes: 7 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.18

require (
github.com/cloudflare/circl v1.3.7
github.com/consensys/gnark-crypto v0.12.1
github.com/drand/kyber-bls12381 v0.3.1
github.com/jonboulle/clockwork v0.4.0
github.com/stretchr/testify v1.9.0
Expand All @@ -14,8 +15,14 @@ require (
)

require (
github.com/bits-and-blooms/bitset v1.7.0 // indirect
github.com/consensys/bavard v0.1.13 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/kilic/bls12-381 v0.1.0 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/mmcloughlin/addchain v0.4.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
rsc.io/tmplfunc v0.0.3 // indirect
)
21 changes: 20 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
@@ -1,16 +1,33 @@
github.com/bits-and-blooms/bitset v1.7.0 h1:YjAGVd3XmtK9ktAbX8Zg2g2PwLIMjGREZJHlV4j7NEo=
github.com/bits-and-blooms/bitset v1.7.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ=
github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI=
github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M=
github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/drand/kyber-bls12381 v0.3.1 h1:KWb8l/zYTP5yrvKTgvhOrk2eNPscbMiUOIeWBnmUxGo=
github.com/drand/kyber-bls12381 v0.3.1/go.mod h1:H4y9bLPu7KZA/1efDg+jtJ7emKx+ro3PU7/jWUVt140=
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4=
github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c=
github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY=
github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU=
github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
Expand All @@ -31,7 +48,9 @@ golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU=
rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA=
27 changes: 27 additions & 0 deletions pairing/bn254/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
Copyright (c) 2009 The Go Authors. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 changes: 27 additions & 0 deletions pairing/bn254/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
## bn254

Package bn254 implements a particular bilinear group.

Note: this _is_ the curve implemented in Ethereum.

Bilinear groups are the basis of many of the new cryptographic protocols that
have been proposed over the past decade. They consist of a triplet of groups
(G₁, G₂ and GT) such that there exists a function e(g₁ˣ,g₂ʸ)=gTˣʸ (where gₓ is a
generator of the respective group). That function is called a pairing function.

This package specifically implements the Optimal Ate pairing over a 256-bit
Barreto-Naehrig curve as described in
http://cryptojedi.org/papers/dclxvi-20100714.pdf. Its output is compatible with
the implementation described in that paper.

This package previously claimed to operate at a 128-bit security level. However,
recent improvements in attacks mean that is no longer true. See
https://moderncrypto.org/mail-archive/curves/2016/000740.html.

## Kyber additions

The basis for this package is [Cloudflare's bn256 implementation](https://github.com/cloudflare/bn256)
which itself is an improved version of the [official bn256 package](https://golang.org/x/crypto/bn256).
The package at hand maintains compatibility to Cloudflare's library. The biggest difference is the replacement of their
[public API](https://github.com/cloudflare/bn256/blob/master/bn256.go) by a new
one that is compatible to Kyber's scalar, point, group, and suite interfaces.
50 changes: 50 additions & 0 deletions pairing/bn254/adapter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package bn254

import (
"github.com/drand/kyber"
)

// SuiteBn254 is an adapter that implements the suites.Suite interface so that
// bn254 can be used as a common suite to generate key pairs for instance but
// still preserves the properties of the pairing (e.g. the Pair function).
//
// It's important to note that the Point function will generate a point
// compatible with public keys only (group G2) where the signature must be
// used as a point from the group G1.
type SuiteBn254 struct {
*Suite
kyber.Group
}

// NewSuiteBn254 makes a new BN254 suite
func NewSuiteBn254() *SuiteBn254 {
return &SuiteBn254{
Suite: NewSuite(),
}
}

// Point generates a point from the G2 group that can only be used
// for public keys
func (s *SuiteBn254) Point() kyber.Point {
return s.G2().Point()
}

// PointLen returns the length of a G2 point
func (s *SuiteBn254) PointLen() int {
return s.G2().PointLen()
}

// Scalar generates a scalar
func (s *SuiteBn254) Scalar() kyber.Scalar {
return s.G1().Scalar()
}

// ScalarLen returns the lenght of a scalar
func (s *SuiteBn254) ScalarLen() int {
return s.G1().ScalarLen()
}

// String returns the name of the suite
func (s *SuiteBn254) String() string {
return "bn254.adapter"
}
28 changes: 28 additions & 0 deletions pairing/bn254/adapter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package bn254

import (
"testing"

"github.com/drand/kyber/util/key"
"github.com/stretchr/testify/require"
)

func TestAdapter_SuiteBn254(t *testing.T) {
suite := NewSuiteBn254()

pair := key.NewKeyPair(suite)
pubkey, err := pair.Public.MarshalBinary()
require.Nil(t, err)
privkey, err := pair.Private.MarshalBinary()
require.Nil(t, err)

pubhex := suite.Point()
err = pubhex.UnmarshalBinary(pubkey)
require.Nil(t, err)

privhex := suite.Scalar()
err = privhex.UnmarshalBinary(privkey)
require.Nil(t, err)

require.Equal(t, "bn254.adapter", suite.String())
}
14 changes: 14 additions & 0 deletions pairing/bn254/bls_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package bn254

import (
"testing"

"github.com/drand/kyber/sign/bls"
"github.com/drand/kyber/sign/test"
)

func TestBLSSchemeBN254G1(t *testing.T) {
suite := NewSuite()
s := bls.NewSchemeOnG1(suite)
test.SchemeTesting(t, s)
}
76 changes: 76 additions & 0 deletions pairing/bn254/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package bn254

import (
"math/big"
)

func bigFromBase10(s string) *big.Int {
n, _ := new(big.Int).SetString(s, 10)
return n
}

// u is the BN parameter.
var u = bigFromBase10("4965661367192848881")

// Order is the number of elements in both G₁ and G₂: 36u⁴+36u³+18u²+6u+1.
// Needs to be highly 2-adic for efficient SNARK key and proof generation.
// Order - 1 = 2^28 * 3^2 * 13 * 29 * 983 * 11003 * 237073 * 405928799 * 1670836401704629 * 13818364434197438864469338081.
// Refer to https://eprint.iacr.org/2013/879.pdf and https://eprint.iacr.org/2013/507.pdf for more information on these parameters.
var Order = bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495617")

// p is a prime over which we form a basic field: 36u⁴+36u³+24u²+6u+1.
var p = bigFromBase10("21888242871839275222246405745257275088696311157297823662689037894645226208583")

// p2 is p, represented as little-endian 64-bit words.
var p2 = [4]uint64{0x3c208c16d87cfd47, 0x97816a916871ca8d, 0xb85045b68181585d, 0x30644e72e131a029}

var curveB = newGFp(3)

// np is the negative inverse of p, mod 2^256.
var np = [4]uint64{0x87d20782e4866389, 0x9ede7d651eca6ac9, 0xd8afcbd01833da80, 0xf57a22b791888c6b}

// rN1 is R^-1 where R = 2^256 mod p.
var rN1 = &gfP{0xed84884a014afa37, 0xeb2022850278edf8, 0xcf63e9cfb74492d9, 0x2e67157159e5c639}

// r2 is R^2 where R = 2^256 mod p.
var r2 = &gfP{0xf32cfc5b538afa89, 0xb5e71911d44501fb, 0x47ab1eff0a417ff6, 0x06d89f71cab8351f}

// r3 is R^3 where R = 2^256 mod p.
var r3 = &gfP{0xb1cd6dafda1530df, 0x62f210e6a7283db6, 0xef7f0b0c0ada0afb, 0x20fd6e902d592544}

// xiToPMinus1Over6 is ξ^((p-1)/6) where ξ = i+9.
var xiToPMinus1Over6 = &gfP2{gfP{0xa222ae234c492d72, 0xd00f02a4565de15b, 0xdc2ff3a253dfc926, 0x10a75716b3899551}, gfP{0xaf9ba69633144907, 0xca6b1d7387afb78a, 0x11bded5ef08a2087, 0x02f34d751a1f3a7c}}

// xiToPMinus1Over3 is ξ^((p-1)/3) where ξ = i+9.
var xiToPMinus1Over3 = &gfP2{gfP{0x6e849f1ea0aa4757, 0xaa1c7b6d89f89141, 0xb6e713cdfae0ca3a, 0x26694fbb4e82ebc3}, gfP{0xb5773b104563ab30, 0x347f91c8a9aa6454, 0x7a007127242e0991, 0x1956bcd8118214ec}}

// xiToPMinus1Over2 is ξ^((p-1)/2) where ξ = i+9.
var xiToPMinus1Over2 = &gfP2{gfP{0xa1d77ce45ffe77c7, 0x07affd117826d1db, 0x6d16bd27bb7edc6b, 0x2c87200285defecc}, gfP{0xe4bbdd0c2936b629, 0xbb30f162e133bacb, 0x31a9d1b6f9645366, 0x253570bea500f8dd}}

// xiToPSquaredMinus1Over3 is ξ^((p²-1)/3) where ξ = i+9.
var xiToPSquaredMinus1Over3 = &gfP{0x3350c88e13e80b9c, 0x7dce557cdb5e56b9, 0x6001b4b8b615564a, 0x2682e617020217e0}

// xiTo2PSquaredMinus2Over3 is ξ^((2p²-2)/3) where ξ = i+9 (a cubic root of unity, mod p).
var xiTo2PSquaredMinus2Over3 = &gfP{0x71930c11d782e155, 0xa6bb947cffbe3323, 0xaa303344d4741444, 0x2c3b3f0d26594943}

// xiToPSquaredMinus1Over6 is ξ^((1p²-1)/6) where ξ = i+9 (a cubic root of -1, mod p).
var xiToPSquaredMinus1Over6 = &gfP{0xca8d800500fa1bf2, 0xf0c5d61468b39769, 0x0e201271ad0d4418, 0x04290f65bad856e6}

// xiTo2PMinus2Over3 is ξ^((2p-2)/3) where ξ = i+9.
var xiTo2PMinus2Over3 = &gfP2{gfP{0x5dddfd154bd8c949, 0x62cb29a5a4445b60, 0x37bc870a0c7dd2b9, 0x24830a9d3171f0fd}, gfP{0x7361d77f843abe92, 0xa5bb2bd3273411fb, 0x9c941f314b3e2399, 0x15df9cddbb9fd3ec}}

// g(Z)
var c1 = &gfP{0x115482203dbf392d, 0x926242126eaa626a, 0xe16a48076063c052, 0x07c5909386eddc93}

// -Z / 2
var c2 = &gfP{0xb461a4448976f7d5, 0xc6843fb439555fa7, 0x28f0d12384840918, 0x112ceb58a394e07d}

// sqrt(-g(Z) * (3 * Z^2 + 4 * A))
var c3 = &gfP{0x7c8487078735ab72, 0x51da7e0048bfb8d4, 0x945cfd183cbd7bf4, 0x0b70b1ec48ae62c6}

// 4 * -g(Z) / (3 * Z^2 + 4 * A)
var c4 = &gfP{0xa79a2bdca0800831, 0x19fd7617e49815a1, 0xbb8d0c885550c7b1, 0x05c4aeb6ec7e0f48}

var pMinus1Over2 = [4]uint64{0x9e10460b6c3e7ea3, 0xcbc0b548b438e546, 0xdc2822db40c0ac2e, 0x183227397098d014}

var pPlus1Over4 = [4]uint64{0x4f082305b61f3f52, 0x65e05aa45a1c72a3, 0x6e14116da0605617, 0xc19139cb84c680a}
Loading

0 comments on commit 6fadd9d

Please sign in to comment.