-
Notifications
You must be signed in to change notification settings - Fork 20.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
crypto, tests/fuzzers: add gnark bn254 precompile methods for fuzzing #30585
Merged
+261
−30
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
db226c0
initial commit
kevaundray a65fe31
add note on zero check
kevaundray 8eecf9f
use gnark API for Add
kevaundray 6d04721
add wrapper for GT
kevaundray dce736e
modify fuzzing
kevaundray 3c03b0c
remove `Double`
kevaundray 177c7a1
[multi]
kevaundray dbf7703
formatting
kevaundray 9eb68f2
formatting
kevaundray File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 | ||
jwasinger marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
// 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 | ||
} |
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
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Me not being a cryptographer, bear with me... This is package
bn256
, but it operates onbn254
operands? Why the discrepancy?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was mainly poor historical naming: bn128/bn256/bn254 all refer to the same thing -- the discrepancy in numbers refer to different properties of the curve.
The 128 referred to the level of security, however it was found out that it did not have this level of security and then it was changed to bn256 or bn254 depending on who you ask
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
both the scalar and base fields are 254 bits