Skip to content

Commit a4c6d9c

Browse files
committed
Add bn254
1 parent 30c3ebc commit a4c6d9c

32 files changed

+4153
-5
lines changed

crypto/bn254.go

+344
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,344 @@
1+
package crypto
2+
3+
import "C"
4+
import (
5+
"crypto/rand"
6+
"fmt"
7+
"github.com/onflow/flow-go/crypto/bn254"
8+
bn256cf "github.com/onflow/flow-go/crypto/bn254/cloudflare"
9+
"github.com/onflow/flow-go/crypto/hash"
10+
"golang.org/x/crypto/sha3"
11+
"math/big"
12+
)
13+
14+
var (
15+
Big0 = big.NewInt(0)
16+
Big1 = big.NewInt(1)
17+
Big2 = big.NewInt(2)
18+
Big3 = big.NewInt(3)
19+
Big4 = big.NewInt(4)
20+
)
21+
22+
const (
23+
PubKeyLenBLSBN256 = 128
24+
25+
SignatureLengthBLSBN256 = 64
26+
27+
KeyGenSeedMaxLenBLSBN256 = 2048 // large enough constant accepted by the implementation
28+
29+
)
30+
31+
var G2, _ = BuildG2(
32+
BigFromBase10("11559732032986387107991004021392285783925812861821192530917403151452391805634"),
33+
BigFromBase10("10857046999023057135944570762232829481370756359578518086990519993285655852781"),
34+
BigFromBase10("4082367875863433681332203403145435568316851327593401208105741076214120093531"),
35+
BigFromBase10("8495653923123431417604973247489272438418190587263600148770280649306958101930"))
36+
37+
// P is a prime over which we form a basic field: 36u⁴+36u³+24u²+6u+1.
38+
var P = BigFromBase10("21888242871839275222246405745257275088696311157297823662689037894645226208583")
39+
40+
func BigFromBase10(s string) *big.Int {
41+
n, _ := new(big.Int).SetString(s, 10)
42+
return n
43+
}
44+
45+
// BuildG1 create G1 point from big.Int(s)
46+
func BuildG1(x, y *big.Int) (*bn254.G1, error) {
47+
// Each value is a 256-bit number.
48+
const numBytes = 256 / 8
49+
xBytes := new(big.Int).Mod(x, P).Bytes()
50+
yBytes := new(big.Int).Mod(y, P).Bytes()
51+
m := make([]byte, numBytes*2)
52+
copy(m[1*numBytes-len(xBytes):], xBytes)
53+
copy(m[2*numBytes-len(yBytes):], yBytes)
54+
point := new(bn254.G1)
55+
if _, err := point.Unmarshal(m); err != nil {
56+
return nil, err
57+
}
58+
return point, nil
59+
}
60+
61+
// BuildG2 create G2 point from big.Int(s)
62+
func BuildG2(xx, xy, yx, yy *big.Int) (*bn254.G2, error) {
63+
// Each value is a 256-bit number.
64+
const numBytes = 256 / 8
65+
xxBytes := new(big.Int).Mod(xx, P).Bytes()
66+
xyBytes := new(big.Int).Mod(xy, P).Bytes()
67+
yxBytes := new(big.Int).Mod(yx, P).Bytes()
68+
yyBytes := new(big.Int).Mod(yy, P).Bytes()
69+
70+
m := make([]byte, numBytes*4)
71+
copy(m[1*numBytes-len(xxBytes):], xxBytes)
72+
copy(m[2*numBytes-len(xyBytes):], xyBytes)
73+
copy(m[3*numBytes-len(yxBytes):], yxBytes)
74+
copy(m[4*numBytes-len(yyBytes):], yyBytes)
75+
point := new(bn254.G2)
76+
if _, err := point.Unmarshal(m); err != nil {
77+
return nil, err
78+
}
79+
return point, nil
80+
}
81+
82+
// blsBLS12381Algo, embeds SignAlgo
83+
type blsBN256Algo struct {
84+
// the signing algo and parameters
85+
algo SigningAlgorithm
86+
}
87+
88+
// BLS context on the BLS 12-381 curve
89+
var blsBN256Instance *blsBN256Algo
90+
91+
// prKeyBLSBLS12381 is the private key of BLS using BLS12_381, it implements PrivateKey
92+
type prKeyBLSBN256 struct {
93+
pk *pubKeyBLSBN256
94+
s *big.Int
95+
point *bn254.G1
96+
}
97+
98+
// newPrKeyBLSBLS12381 creates a new BLS private key with the given scalar.
99+
// If no scalar is provided, the function allocates an
100+
// empty scalar.
101+
func newPrKeyBLSBN256(s *big.Int) *prKeyBLSBN256 {
102+
if s == nil {
103+
k, p, _ := bn256cf.RandomG1(rand.Reader)
104+
return &prKeyBLSBN256{s: k, point: p}
105+
}
106+
107+
return &prKeyBLSBN256{s: s, point: new(bn254.G1).ScalarBaseMult(s)}
108+
}
109+
110+
// Algorithm returns the Signing Algorithm
111+
func (sk *prKeyBLSBN256) Algorithm() SigningAlgorithm {
112+
return BLSBN256
113+
}
114+
115+
// Size returns the private key length in bytes
116+
func (sk *prKeyBLSBN256) Size() int {
117+
return PubKeyLenBLSBN256
118+
}
119+
120+
// computePublicKey generates the public key corresponding to
121+
// the input private key. The function makes sure the public key
122+
// is valid in G2.
123+
func (sk *prKeyBLSBN256) computePublicKey() {
124+
pk := new(bn254.G2).ScalarBaseMult(sk.s)
125+
126+
sk.pk = &pubKeyBLSBN256{point: pk}
127+
}
128+
129+
// PublicKey returns the public key corresponding to the private key
130+
func (sk *prKeyBLSBN256) PublicKey() PublicKey {
131+
if sk.pk != nil {
132+
return sk.pk
133+
}
134+
135+
sk.computePublicKey()
136+
return sk.pk
137+
}
138+
139+
// BigToBytes convert big int to byte array
140+
// `minLen` is the minimum length of the array
141+
func BigToBytes(bi *big.Int, minLen int) []byte {
142+
b := bi.Bytes()
143+
if minLen <= len(b) {
144+
return b
145+
}
146+
m := make([]byte, minLen)
147+
copy(m[minLen-len(b):], b)
148+
return m
149+
}
150+
151+
// Encode returns a byte encoding of the private key.
152+
// The encoding is a raw encoding in big endian padded to the group order
153+
func (sk *prKeyBLSBN256) Encode() []byte {
154+
return BigToBytes(sk.s, 32)
155+
}
156+
157+
// Equals checks is two public keys are equal.
158+
func (sk *prKeyBLSBN256) Equals(other PrivateKey) bool {
159+
otherBLS, ok := other.(*prKeyBLSBN256)
160+
if !ok {
161+
return false
162+
}
163+
164+
return otherBLS.String() == sk.String()
165+
}
166+
167+
func (sk *prKeyBLSBN256) Sign(data []byte, hasher hash.Hasher) (Signature, error) {
168+
m := hasher.ComputeHash(data)
169+
hm := HashToG1(m)
170+
g1 := new(bn254.G1)
171+
g1.ScalarMult(hm, sk.s)
172+
return g1.Marshal(), nil
173+
}
174+
175+
// String returns the hex string representation of the key.
176+
func (sk *prKeyBLSBN256) String() string {
177+
return fmt.Sprintf("%#x", sk.Encode())
178+
}
179+
180+
// pubKeyBLSBN256 is the public key of BLS using BN256,
181+
// it implements PublicKey.
182+
type pubKeyBLSBN256 struct {
183+
// public key G2 point
184+
point *bn254.G2
185+
}
186+
187+
// Algorithm returns the Signing Algorithm
188+
func (pk *pubKeyBLSBN256) Algorithm() SigningAlgorithm {
189+
return BLSBN256
190+
}
191+
192+
// Size returns the public key lengh in bytes
193+
func (pk *pubKeyBLSBN256) Size() int {
194+
return PubKeyLenBLSBN256
195+
}
196+
197+
// Encode returns a byte encoding of the public key.
198+
// Since we use a compressed encoding by default, this delegates to EncodeCompressed
199+
func (pk *pubKeyBLSBN256) Encode() []byte {
200+
dest := make([]byte, PubKeyLenBLSBN256)
201+
_, _ = pk.point.Unmarshal(dest)
202+
return dest
203+
}
204+
205+
// Equals checks is two public keys are equal
206+
func (pk *pubKeyBLSBN256) Equals(other PublicKey) bool {
207+
otherBLS, ok := other.(*pubKeyBLSBN256)
208+
if !ok {
209+
return false
210+
}
211+
return pk.point.String() == otherBLS.point.String()
212+
}
213+
214+
// String returns the hex string representation of the key.
215+
func (pk *pubKeyBLSBN256) String() string {
216+
return fmt.Sprintf("%#x", pk.Encode())
217+
}
218+
219+
func (pk *pubKeyBLSBN256) EncodeCompressed() []byte {
220+
return pk.Encode()
221+
}
222+
223+
func (pk *pubKeyBLSBN256) Verify(s Signature, data []byte, hasher hash.Hasher) (bool, error) {
224+
// hash the input to 128 bytes
225+
h := hasher.ComputeHash(data)
226+
227+
hm := new(bn254.G1).Neg(HashToG1(h))
228+
a := make([]*bn254.G1, 2)
229+
b := make([]*bn254.G2, 2)
230+
231+
sig := new(bn254.G1)
232+
if _, err := sig.Unmarshal(s); err != nil {
233+
return false, err
234+
}
235+
236+
a[0], b[0] = hm, pk.point
237+
a[1], b[1] = sig, G2
238+
return bn254.PairingCheck(a, b), nil
239+
}
240+
241+
func Keccak256(m []byte) []byte {
242+
sha := sha3.NewLegacyKeccak256()
243+
sha.Write(m)
244+
return sha.Sum(nil)
245+
}
246+
247+
func g1XToYSquared(x *big.Int) *big.Int {
248+
result := new(big.Int)
249+
result.Exp(x, Big3, P)
250+
result.Add(result, Big3)
251+
return result
252+
}
253+
254+
// Currently implementing first method from
255+
// http://mathworld.wolfram.com/QuadraticResidue.html
256+
// Experimentally, this seems to always return the canonical square root,
257+
// however I haven't seen a proof of this.
258+
func calcQuadRes(ySqr *big.Int, q *big.Int) *big.Int {
259+
resMod4 := new(big.Int).Mod(q, Big4)
260+
if resMod4.Cmp(Big3) == 0 {
261+
k := new(big.Int).Sub(q, Big3)
262+
k.Div(k, Big4)
263+
exp := new(big.Int).Add(k, Big1)
264+
result := new(big.Int)
265+
result.Exp(ySqr, exp, q)
266+
return result
267+
}
268+
// TODO: ADD CODE TO CALC QUADRATIC RESIDUE IN OTHER CASES
269+
return Big0
270+
}
271+
272+
// HashToG1 try and increment hashing data to a G1 point
273+
func HashToG1(m []byte) *bn254.G1 {
274+
px := new(big.Int)
275+
py := new(big.Int)
276+
277+
h := m
278+
//h := Keccak256(m)
279+
bf := append([]byte{0}, h...)
280+
for {
281+
h = Keccak256(bf)
282+
px.SetBytes(h[:32])
283+
px.Mod(px, P)
284+
ySqr := g1XToYSquared(px)
285+
root := calcQuadRes(ySqr, P)
286+
rootSqr := new(big.Int).Exp(root, Big2, P)
287+
if rootSqr.Cmp(ySqr) == 0 {
288+
py = root
289+
bf[0] = byte(255)
290+
signY := Keccak256(bf)[31] % 2
291+
if signY == 1 {
292+
py.Sub(P, py)
293+
}
294+
break
295+
}
296+
bf[0]++
297+
}
298+
p, err := BuildG1(px, py)
299+
if err != nil {
300+
panic(err)
301+
}
302+
return p
303+
}
304+
305+
func (a *blsBN256Algo) decodePublicKey(publicKeyBytes []byte) (PublicKey, error) {
306+
p := new(bn254.G2)
307+
if _, err := p.Unmarshal(publicKeyBytes); err != nil {
308+
return nil, err
309+
}
310+
return &pubKeyBLSBN256{point: p}, nil
311+
}
312+
313+
// generatePrivateKey generates a private key for BLS on BLS12-381 curve.
314+
// The minimum size of the input seed is 48 bytes.
315+
//
316+
// It is recommended to use a secure crypto RNG to generate the seed.
317+
// The seed must have enough entropy and should be sampled uniformly at random.
318+
//
319+
// The generated private key (resp. its corresponding public key) are guaranteed
320+
// not to be equal to the identity element of Z_r (resp. G2).
321+
func (a *blsBN256Algo) generatePrivateKey(seed []byte) (PrivateKey, error) {
322+
if len(seed) == 0 {
323+
return newPrKeyBLSBN256(nil), nil
324+
}
325+
326+
if len(seed) > KeyGenSeedMaxLenBLSBN256 {
327+
return nil, invalidInputsErrorf("seed byte length should be between %d and %d",
328+
0, KeyGenSeedMaxLenECDSA)
329+
}
330+
331+
k := new(big.Int).SetBytes(seed)
332+
333+
sk := newPrKeyBLSBN256(k)
334+
335+
return sk, nil
336+
}
337+
338+
func (a *blsBN256Algo) decodePrivateKey(privateKeyBytes []byte) (PrivateKey, error) {
339+
return a.generatePrivateKey(privateKeyBytes)
340+
}
341+
342+
func (a *blsBN256Algo) decodePublicKeyCompressed(publicKeyBytes []byte) (PublicKey, error) {
343+
return a.decodePublicKey(publicKeyBytes)
344+
}

crypto/bn254/bn254.go

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2018 Péter Szilágyi. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be found
3+
// in the LICENSE file.
4+
5+
//go:build amd64 || arm64
6+
// +build amd64 arm64
7+
8+
// Package bn254 implements the Optimal Ate pairing over a 256-bit Barreto-Naehrig curve.
9+
package bn254
10+
11+
import (
12+
bn256cf "github.com/onflow/flow-go/crypto/bn254/cloudflare"
13+
)
14+
15+
// G1 is an abstract cyclic group. The zero value is suitable for use as the
16+
// output of an operation, but cannot be used as an input.
17+
type G1 = bn256cf.G1
18+
19+
// G2 is an abstract cyclic group. The zero value is suitable for use as the
20+
// output of an operation, but cannot be used as an input.
21+
type G2 = bn256cf.G2
22+
23+
// PairingCheck calculates the Optimal Ate pairing for a set of points.
24+
func PairingCheck(a []*G1, b []*G2) bool {
25+
return bn256cf.PairingCheck(a, b)
26+
}

crypto/bn254/cloudflare/LICENSE

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
Copyright (c) 2009 The Go Authors. All rights reserved.
2+
3+
Redistribution and use in source and binary forms, with or without
4+
modification, are permitted provided that the following conditions are
5+
met:
6+
7+
* Redistributions of source code must retain the above copyright
8+
notice, this list of conditions and the following disclaimer.
9+
* Redistributions in binary form must reproduce the above
10+
copyright notice, this list of conditions and the following disclaimer
11+
in the documentation and/or other materials provided with the
12+
distribution.
13+
* Neither the name of Google Inc. nor the names of its
14+
contributors may be used to endorse or promote products derived from
15+
this software without specific prior written permission.
16+
17+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

0 commit comments

Comments
 (0)