-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2190 from CortexFoundation/dev
add gnark bn254 precompile methods
- Loading branch information
Showing
52 changed files
with
18,507 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package bn256 | ||
|
||
import ( | ||
"math/big" | ||
|
||
"github.com/consensys/gnark-crypto/ecc/bn254" | ||
) | ||
|
||
// G1 is the affine representation of a G1 group element. | ||
// | ||
// Since this code is used for precompiles, using Jacobian | ||
// points are not beneficial because there are no intermediate | ||
// points to allow us to save on inversions. | ||
// | ||
// Note: We also use this struct so that we can conform to the existing API | ||
// that the precompiles want. | ||
type G1 struct { | ||
inner bn254.G1Affine | ||
} | ||
|
||
// Add adds `a` and `b` together, storing the result in `g` | ||
func (g *G1) Add(a, b *G1) { | ||
g.inner.Add(&a.inner, &b.inner) | ||
} | ||
|
||
// ScalarMult computes the scalar multiplication between `a` and | ||
// `scalar`, storing the result in `g` | ||
func (g *G1) ScalarMult(a *G1, scalar *big.Int) { | ||
g.inner.ScalarMultiplication(&a.inner, scalar) | ||
} | ||
|
||
// Unmarshal deserializes `buf` into `g` | ||
// | ||
// Note: whether the deserialization is of a compressed | ||
// or an uncompressed point, is encoded in the bytes. | ||
// | ||
// For our purpose, the point will always be serialized | ||
// as uncompressed, ie 64 bytes. | ||
// | ||
// This method also checks whether the point is on the | ||
// curve and in the prime order subgroup. | ||
func (g *G1) Unmarshal(buf []byte) (int, error) { | ||
return g.inner.SetBytes(buf) | ||
} | ||
|
||
// Marshal serializes the point into a byte slice. | ||
// | ||
// Note: The point is serialized as uncompressed. | ||
func (p *G1) Marshal() []byte { | ||
return p.inner.Marshal() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package bn256 | ||
|
||
import ( | ||
"github.com/consensys/gnark-crypto/ecc/bn254" | ||
) | ||
|
||
// G2 is the affine representation of a G2 group element. | ||
// | ||
// Since this code is used for precompiles, using Jacobian | ||
// points are not beneficial because there are no intermediate | ||
// points and G2 in particular is only used for the pairing input. | ||
// | ||
// Note: We also use this struct so that we can conform to the existing API | ||
// that the precompiles want. | ||
type G2 struct { | ||
inner bn254.G2Affine | ||
} | ||
|
||
// Unmarshal deserializes `buf` into `g` | ||
// | ||
// Note: whether the deserialization is of a compressed | ||
// or an uncompressed point, is encoded in the bytes. | ||
// | ||
// For our purpose, the point will always be serialized | ||
// as uncompressed, ie 128 bytes. | ||
// | ||
// This method also checks whether the point is on the | ||
// curve and in the prime order subgroup. | ||
func (g *G2) Unmarshal(buf []byte) (int, error) { | ||
return g.inner.SetBytes(buf) | ||
} | ||
|
||
// Marshal serializes the point into a byte slice. | ||
// | ||
// Note: The point is serialized as uncompressed. | ||
func (g *G2) Marshal() []byte { | ||
return g.inner.Marshal() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package bn256 | ||
|
||
import ( | ||
"fmt" | ||
"math/big" | ||
|
||
"github.com/consensys/gnark-crypto/ecc/bn254" | ||
) | ||
|
||
// GT is the affine representation of a GT field element. | ||
// | ||
// Note: GT is not explicitly used in mainline code. | ||
// It is needed for fuzzing. | ||
type GT struct { | ||
inner bn254.GT | ||
} | ||
|
||
// Pair compute the optimal Ate pairing between a G1 and | ||
// G2 element. | ||
// | ||
// Note: This method is not explicitly used in mainline code. | ||
// It is needed for fuzzing. It should also be noted, | ||
// that the output of this function may not match other | ||
func Pair(a_ *G1, b_ *G2) *GT { | ||
a := a_.inner | ||
b := b_.inner | ||
|
||
pairingOutput, err := bn254.Pair([]bn254.G1Affine{a}, []bn254.G2Affine{b}) | ||
|
||
if err != nil { | ||
// Since this method is only called during fuzzing, it is okay to panic here. | ||
// We do not return an error to match the interface of the other bn256 libraries. | ||
panic(fmt.Sprintf("gnark/bn254 encountered error: %v", err)) | ||
} | ||
|
||
return >{ | ||
inner: pairingOutput, | ||
} | ||
} | ||
|
||
// Unmarshal deserializes `buf` into `g` | ||
// | ||
// Note: This method is not explicitly used in mainline code. | ||
// It is needed for fuzzing. | ||
func (g *GT) Unmarshal(buf []byte) error { | ||
return g.inner.SetBytes(buf) | ||
} | ||
|
||
// Marshal serializes the point into a byte slice. | ||
// | ||
// Note: This method is not explicitly used in mainline code. | ||
// It is needed for fuzzing. | ||
func (g *GT) Marshal() []byte { | ||
bytes := g.inner.Bytes() | ||
return bytes[:] | ||
} | ||
|
||
// Exp raises `base` to the power of `exponent` | ||
// | ||
// Note: This method is not explicitly used in mainline code. | ||
// It is needed for fuzzing. | ||
func (g *GT) Exp(base GT, exponent *big.Int) *GT { | ||
g.inner.Exp(base.inner, exponent) | ||
return g | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package bn256 | ||
|
||
import ( | ||
"github.com/consensys/gnark-crypto/ecc/bn254" | ||
) | ||
|
||
// Computes the following relation: ∏ᵢ e(Pᵢ, Qᵢ) =? 1 | ||
// | ||
// To explain why gnark returns a (bool, error): | ||
// | ||
// - If the function `e` does not return a result then internally | ||
// an error is returned. | ||
// - If `e` returns a result, then error will be nil, | ||
// but if this value is not `1` then the boolean value will be false | ||
// | ||
// We therefore check for an error, and return false if its non-nil and | ||
// then return the value of the boolean if not. | ||
func PairingCheck(a_ []*G1, b_ []*G2) bool { | ||
a := getInnerG1s(a_) | ||
b := getInnerG2s(b_) | ||
|
||
// Assume that len(a) == len(b) | ||
// | ||
// The pairing function will return | ||
// false, if this is not the case. | ||
size := len(a) | ||
|
||
// Check if input is empty -- gnark will | ||
// return false on an empty input, however | ||
// the ossified behavior is to return true | ||
// on an empty input, so we add this if statement. | ||
if size == 0 { | ||
return true | ||
} | ||
|
||
ok, err := bn254.PairingCheck(a, b) | ||
if err != nil { | ||
return false | ||
} | ||
return ok | ||
} | ||
|
||
// getInnerG1s gets the inner gnark G1 elements. | ||
// | ||
// These methods are used for two reasons: | ||
// | ||
// - We use a new type `G1`, so we need to convert from | ||
// []*G1 to []*bn254.G1Affine | ||
// - The gnark API accepts slices of values and not slices of | ||
// pointers to values, so we need to return []bn254.G1Affine | ||
// instead of []*bn254.G1Affine. | ||
func getInnerG1s(pointerSlice []*G1) []bn254.G1Affine { | ||
gnarkValues := make([]bn254.G1Affine, 0, len(pointerSlice)) | ||
for _, ptr := range pointerSlice { | ||
if ptr != nil { | ||
gnarkValues = append(gnarkValues, ptr.inner) | ||
} | ||
} | ||
return gnarkValues | ||
} | ||
|
||
// getInnerG2s gets the inner gnark G2 elements. | ||
// | ||
// The rationale for this method is the same as `getInnerG1s`. | ||
func getInnerG2s(pointerSlice []*G2) []bn254.G2Affine { | ||
gnarkValues := make([]bn254.G2Affine, 0, len(pointerSlice)) | ||
for _, ptr := range pointerSlice { | ||
if ptr != nil { | ||
gnarkValues = append(gnarkValues, ptr.inner) | ||
} | ||
} | ||
return gnarkValues | ||
} |
Oops, something went wrong.