Skip to content

Commit

Permalink
add test cases for point not on curve, use IntByReference to indicate…
Browse files Browse the repository at this point in the history
… error and output length rather than static vals

Signed-off-by: garyschulte <[email protected]>
  • Loading branch information
garyschulte committed Jul 10, 2024
1 parent c7e706e commit ef5e5e3
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ input,result,gas,notes
1ca0717a8dfb9c3940a731d7c52f1699f64fe05e76189a91dc622e8fafd99de62313a1df5b32b17c21e53e2d0a1ff3eeac6ab4359a9f86e51b1c236f414d87ea00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,1ca0717a8dfb9c3940a731d7c52f1699f64fe05e76189a91dc622e8fafd99de62313a1df5b32b17c21e53e2d0a1ff3eeac6ab4359a9f86e51b1c236f414d87ea,150,
1234,,150,invalid input parameters, Point 0 is not on curve
0174fc233104c2ad4f56a8396b8c1b7d9c6ad10bffc70761c5e8f5280862f137029733a9f20a4cdbb7ae9c5dd1adf6ccc7fe3439d7dc71093af0656ae0ca0f290964773f12e2292f332306374f957d10,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,150,invalid input parameters, Point 1 is not on curve
0174fc233104c2ad4f56a8396b8c1b7d9c6ad10bffc70761c5e8f5280862f137029733a9f20a4cdbb7ae9c5dd1adf6ccc7fe3439d7dc71093af0656ae0ca0f290964773f12e2292f332306374f957d10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,150,invalid input parameters, Point 1 is not on curve
67376aad340c93eb0fc9bc8e040dc691bd00e426c6456b4d13079e7f1dbb3da847eb0fc271cd23da50c6ebc261928abb1af9bfcea998791e18af1817b06221e1fe708d2f4224275523fcd37460a310ce4b56f1694dfe36280410f0fb6efc5f47b85662e5b08d881242a72acbc2c8e2fa71ac593be977ad3e090c8158aace0247,,150,invalid input parameters, Failed to parse Fp element
,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,150,
ff000000000000000000000000000000000000000000000000000000000000ff,,150,invalid input parameters, Failed to parse Fp element
1470b80a6d5de1470aeadfa0b2eb913d9286bd966aa8a99b09879f3b10c985d02432b8ccd7083d421127dac6ad90bd569e763810e32d37114a786c7645864647,1470b80a6d5de1470aeadfa0b2eb913d9286bd966aa8a99b09879f3b10c985d02432b8ccd7083d421127dac6ad90bd569e763810e32d37114a786c7645864647,150,
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ input,result,gas,notes
1c2cb2b4504b19c7e073679432e625f2706b7c4728cd9bd3ce36579f4de2f3902c8605f723ac2f73baa15eac674f62ab06c79809aa4a4be3391c4d41d5a6e62ca0a73a5b559cd0384ca11d444e34f40e04f2080483db9e54ae09e44ec19c26a1,1147da8fc5774b5ef94fda682437b04f9b6aea72987d1269496769baf7e67dc729fe144eab44c6da4c851123165cd6506ce3e10b7691b8bf11b757e2ae058fcb,6000,
0d6ad8e12b4f61e3e2a2252ce11428941f2a84b7f0a821cb8cc7699303bd4fec2247870562618fd8d6169072d9b33614d2acf800b3ba0ff68ef8d5fd4d6c250d3e70b3bed17894f958579644c83fa9d485121d580e2b061c697e68f950297768,0be6d75e2fe2887835d396dae11321ca7c53083abd6a0b270ee1c087593517aa2ffd1bad577de7cf2b19b82bfff0c66e2afbfb79a72cbe834290437f3caf2f21,6000,
d2acf800b3ba0ff68ef8d5fd4d6c250d3e70b3bed17894f958579644c83fa9d485121d580e2b061c697e68f9502977680d6ad8e12b4f61e3e2a2252ce11428941f2a84b7f0a821cb8cc7699303bd4fec2247870562618fd8d6169072d9b33614,,6000,invalid input parameters, Failed to parse Fp element
02acf800b3ba0ff68ef8d5fd4d6c250d3e70b3bed17894f958579644c83fa9d405121d580e2b061c697e68f9502977680d6ad8e12b4f61e3e2a2252ce11428941f2a84b7f0a821cb8cc7699303bd4fec2247870562618fd8d6169072d9b33614,,6000,invalid input parameters, Point is not on curve
,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,6000,
1A87B0584CE92F4593D161480614F2989035225609F08058CCFA3D0F940FEBE31A2F3C951F6DADCC7EE9007DFF81504B0FCD6D7CF59996EFDC33D92BF7F9F8F60100000000000000000000000000000000,0x220cb1540fa85ba04d863dca86de9359a43ac9fc084aebb9f2a936d989abbb602ccdc6c020dd2cf78332132b3f1d1122391b515035623cd6f53d4aea24ea2466,6000,
1A87B0584CE92F4593D161480614F2989035225609F08058CCFA3D0F940FEBE31A2F3C951F6DADCC7EE9007DFF81504B0FCD6D7CF59996EFDC33D92BF7F9F8F60000000000000000000000000000000100000000000000000000000000000000,1051acb0700ec6d42a88215852d582efbaef31529b6fcbc3277b5c1b300f5cf0135b2394bb45ab04b8bd7611bd2dfe1de6a4e6e2ccea1ea1955f577cd66af85b,6000,
132 changes: 74 additions & 58 deletions gnark/gnark-jni/gnark-eip-196.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,10 @@ import (
"github.com/consensys/gnark-crypto/ecc/bn254/fp"
)

var ErrMalformedPoint = errors.New("invalid input parameters, invalid point encoding")
var ErrInvalidInputLength = errors.New("invalid input parameters, invalid input length")
var ErrInvalidInputPairingLength = errors.New("invalid input parameters, invalid input length for pairing")
var ErrPointNotInField = errors.New("invalid input parameters, point not in field")
var ErrPointOnCurveCheckFailed = errors.New("invalid point: point is not on curve")
var ErrMalformedPointEIP196 = errors.New("invalid point encoding")
var ErrInvalidInputPairingLengthEIP196 = errors.New("invalid input parameters, invalid input length for pairing")
var ErrPointNotInFieldEIP196 = errors.New("point not in field")
var ErrPointOnCurveCheckFailedEIP196 = errors.New("point is not on curve")

const (
EIP196PreallocateForResult = 128
Expand All @@ -42,52 +41,52 @@ var bn254Modulus = new(big.Int).SetBytes([]byte{
})

// Predefine a zero slice of length 16
var zeroSlice = make([]byte, 16)
var zeroEIP196Slice = make([]byte, 16)

//export eip196altbn128G1Add
func eip196altbn128G1Add(javaInputBuf, javaOutputBuf, javaErrorBuf *C.char, cInputLen, cOutputLen, cErrorLen C.int) C.int {
func eip196altbn128G1Add(javaInputBuf, javaOutputBuf, javaErrorBuf *C.char, cInputLen C.int, cOutputLen, cErrorLen *C.int) C.int {
inputLen := int(cInputLen)
errorLen := int(cErrorLen)
errorLen := (*int)(unsafe.Pointer(cErrorLen))
outputLen := (*int)(unsafe.Pointer(cOutputLen))

// Convert error C pointers to Go slices
errorBuf := castErrorBuffer(javaErrorBuf, errorLen)
errorBuf := castErrorBufferEIP196(javaErrorBuf, *errorLen)

if (inputLen > 2*EIP196PreallocateForG1) {
copy(errorBuf, ErrInvalidInputLength.Error())
return 1
// trunc if input too long
inputLen = 2*EIP196PreallocateForG1
}

// Convert input C pointers to Go slices
input := (*[2*EIP196PreallocateForG1]byte)(unsafe.Pointer(javaInputBuf))[:inputLen:inputLen]

if (inputLen < EIP196PreallocateForG1) {
if (inputLen == 0) {
*outputLen = 0
return 0
}

// generate p0 g1 affine
p0, err := safeUnmarshal(input[:64])
p0, err := safeUnmarshalEIP196(input, 0)

if err != nil {
copy(errorBuf, "invalid input parameters, " + err.Error())
dryError(err, errorBuf, outputLen, errorLen)
return 1
}

if inputLen < 2*EIP196PreallocateForG1 {
// if incomplete input is all zero, return p0
if isAllZero(input[64:inputLen]) {
if isAllZeroEIP196(input, 64) {
ret := p0.Marshal()
g1AffineEncode(ret, javaOutputBuf)
*outputLen = EIP196PreallocateForG1
return 0;
}
copy(errorBuf, ErrInvalidInputLength.Error())
return 1
}

// generate p1 g1 affine
p1, err := safeUnmarshal(input[64:])
p1, err := safeUnmarshalEIP196(input, 64)

if err != nil {
copy(errorBuf, "invalid input parameters, " + err.Error())
dryError(err, errorBuf, outputLen, errorLen)
return 1
}

Expand All @@ -97,38 +96,39 @@ func eip196altbn128G1Add(javaInputBuf, javaOutputBuf, javaErrorBuf *C.char, cInp
// marshal the resulting point and encode directly to the output buffer
ret := result.Marshal()
g1AffineEncode(ret, javaOutputBuf)
*outputLen = EIP196PreallocateForG1
return 0

}

//export eip196altbn128G1Mul
func eip196altbn128G1Mul(javaInputBuf, javaOutputBuf, javaErrorBuf *C.char, cInputLen, cOutputLen, cErrorLen C.int) C.int {
func eip196altbn128G1Mul(javaInputBuf, javaOutputBuf, javaErrorBuf *C.char, cInputLen C.int, cOutputLen, cErrorLen *C.int) C.int {
inputLen := int(cInputLen)
errorLen := int(cErrorLen)
errorLen := (*int)(unsafe.Pointer(cErrorLen))
outputLen := (*int)(unsafe.Pointer(cOutputLen))

// Convert error C pointers to Go slices
errorBuf := castErrorBuffer(javaErrorBuf, errorLen)
errorBuf := castErrorBufferEIP196(javaErrorBuf, *errorLen)

if inputLen < EIP196PreallocateForG1 {
// if we do not have complete input, return 0
*outputLen = 0
return 0
}

if (inputLen > EIP196PreallocateForG1 + EIP196PreallocateForScalar) {
// trunc if input too long
copy(errorBuf, ErrInvalidInputLength.Error())
return 1
inputLen = EIP196PreallocateForG1 + EIP196PreallocateForScalar
}

// Convert input C pointers to Go slice
input := (*[EIP196PreallocateForG1 + EIP196PreallocateForScalar]byte)(unsafe.Pointer(javaInputBuf))[:inputLen:inputLen]

// generate p0 g1 affine
var p0 bn254.G1Affine
err := p0.Unmarshal(input[:64])
p0, err := safeUnmarshalEIP196(input, 0)

if err != nil {
copy(errorBuf, err.Error())
dryError(err, errorBuf, outputLen, errorLen)
return 1
}

Expand All @@ -144,38 +144,41 @@ func eip196altbn128G1Mul(javaInputBuf, javaOutputBuf, javaErrorBuf *C.char, cInp
scalar.SetBytes(scalarBytes[:])

// multiply g1 point by scalar
result := p0.ScalarMultiplication(&p0, scalar)
result := p0.ScalarMultiplication(p0, scalar)

// marshal the resulting point and encode directly to the output buffer
ret := result.Marshal()
g1AffineEncode(ret, javaOutputBuf)
*outputLen = EIP196PreallocateForG1
return 0
}

//export eip196altbn128Pairing
func eip196altbn128Pairing(javaInputBuf, javaOutputBuf, javaErrorBuf *C.char, cInputLen, cOutputLen, cErrorLen C.int) C.int {
func eip196altbn128Pairing(javaInputBuf, javaOutputBuf, javaErrorBuf *C.char, cInputLen C.int, cOutputLen, cErrorLen *C.int) C.int {
inputLen := int(cInputLen)
outputLen := int(cOutputLen)
errorLen := int(cErrorLen)
errorLen := (*int)(unsafe.Pointer(cErrorLen))
outputLen := (*int)(unsafe.Pointer(cOutputLen))

// Convert error C pointers to Go slices
output := castBuffer(javaOutputBuf, outputLen)
output := castBufferEIP196(javaOutputBuf, *outputLen)

// Convert error C pointers to Go slices
errorBuf := castErrorBuffer(javaErrorBuf, errorLen)
errorBuf := castErrorBufferEIP196(javaErrorBuf, *errorLen)

*outputLen = 32

if inputLen == 0 {
output[31]=0x01
return 0
}

if inputLen % (EIP196PreallocateForG2 + EIP196PreallocateForG1) != 0 {
copy(errorBuf, ErrInvalidInputPairingLength.Error())
dryError(ErrInvalidInputPairingLengthEIP196, errorBuf, outputLen, errorLen)
return 1
}

// Convert input C pointers to Go slice
input := castBufferToSlice(unsafe.Pointer(javaInputBuf), inputLen)
input := castBufferToSliceEIP196(unsafe.Pointer(javaInputBuf), inputLen)

var pairCount = inputLen / (EIP196PreallocateForG2 + EIP196PreallocateForG1)
g1Points := make([]bn254.G1Affine, pairCount)
Expand All @@ -189,7 +192,7 @@ func eip196altbn128Pairing(javaInputBuf, javaOutputBuf, javaErrorBuf *C.char, cI
err := g1.Unmarshal(input[i*192:i*192+64])

if err != nil {
copy(errorBuf, err.Error())
dryError(err, errorBuf, outputLen, errorLen)
return 1
}

Expand All @@ -198,7 +201,7 @@ func eip196altbn128Pairing(javaInputBuf, javaOutputBuf, javaErrorBuf *C.char, cI
err = g2.Unmarshal(input[i*192+64:(i+1)*192])

if err != nil {
copy(errorBuf, err.Error())
dryError(err, errorBuf, outputLen, errorLen)
return 1
}

Expand All @@ -209,15 +212,14 @@ func eip196altbn128Pairing(javaInputBuf, javaOutputBuf, javaErrorBuf *C.char, cI

isOne, err := bn254.PairingCheck(g1Points, g2Points)
if err != nil {
copy(errorBuf, err.Error())
dryError(err, errorBuf, outputLen, errorLen)
return -1
}

if (isOne) {
// respond with 1 if pairing check was true, leave 0's intact otherwise
output[31]=0x01
}

return 0

}
Expand All @@ -237,36 +239,40 @@ func g1AffineEncode(g1Point []byte, output *C.char) (error) {
return nil
}

func safeUnmarshal(input []byte) (*bn254.G1Affine, error) {
func safeUnmarshalEIP196(input []byte, offset int) (*bn254.G1Affine, error) {
var g1 bn254.G1Affine

if (len(input) < 64) {
return nil, ErrMalformedPoint
if (len(input) - offset < 64) {
return nil, ErrMalformedPointEIP196
}

if !checkInField(input[:32]) {
return nil, ErrPointOnCurveCheckFailed
if !checkInFieldEIP196(input[offset: offset + 32]) {
return nil, ErrPointNotInFieldEIP196
}

err := g1.X.SetBytesCanonical(input[:32])
err := g1.X.SetBytesCanonical(input[offset:offset + 32])

if (err == nil) {
err := g1.Y.SetBytesCanonical(input[32:64])

if !checkInFieldEIP196(input[offset + 32: offset + 64]) {
return nil, ErrPointNotInFieldEIP196
}
err := g1.Y.SetBytesCanonical(input[offset + 32:offset + 64])
if (err == nil) {
if (!g1.IsOnCurve()) {
return nil, ErrPointOnCurveCheckFailedEIP196
}
return &g1, nil
}
}

if (!g1.IsOnCurve()) {
return nil, ErrPointOnCurveCheckFailed
}

return nil, err
}

// checkInField checks that an element is in the field, not-in-field will normally
// be caught during unmarshal, but here in case of no-op calls of a single parameter
func checkInField(data []byte) bool {
func checkInFieldEIP196(data []byte) bool {

// Convert the byte slice to a big.Int
elem := new(big.Int).SetBytes(data)
Expand All @@ -276,16 +282,26 @@ func checkInField(data []byte) bool {
}

// isAllZero checks if all elements in the byte slice are zero
func isAllZero(data []byte) bool {
for _, b := range data {
if b != 0 {
return false
func isAllZeroEIP196(data []byte, offset int) bool {
if len(data) > 64 {
slice := data [offset:]
for _, b := range slice {
if b != 0 {
return false
}
}
}
return true
}

func castBufferToSlice(buf unsafe.Pointer, length int) []byte {
func dryError(err error, errorBuf []byte, outputLen, errorLen *int) {
errStr := "invalid input parameters, " + err.Error();
copy(errorBuf, errStr)
*outputLen = 0
*errorLen = len(errStr)
}

func castBufferToSliceEIP196(buf unsafe.Pointer, length int) []byte {
var slice []byte
// Obtain the slice header
header := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
Expand All @@ -296,15 +312,15 @@ func castBufferToSlice(buf unsafe.Pointer, length int) []byte {
return slice
}

func castBuffer(javaOutputBuf *C.char, length int) []byte {
func castBufferEIP196(javaOutputBuf *C.char, length int) []byte {
bufSize := length
if bufSize < EIP196PreallocateForResult {
bufSize = EIP196PreallocateForResult
}
return (*[EIP196PreallocateForResult]byte)(unsafe.Pointer(javaOutputBuf))[:bufSize:bufSize]
}

func castErrorBuffer(javaOutputBuf *C.char, length int) []byte {
func castErrorBufferEIP196(javaOutputBuf *C.char, length int) []byte {
bufSize := length
if bufSize < EIP196PreallocateForError {
bufSize = EIP196PreallocateForError
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,48 +41,36 @@ public static int eip196_perform_operation(
int ret = -1;
switch(op) {
case EIP196_ADD_OPERATION_RAW_VALUE:
ret = eip196altbn128G1Add(i, output, err, i_len,
EIP196_PREALLOCATE_FOR_RESULT_BYTES, EIP196_PREALLOCATE_FOR_ERROR_BYTES);
o_len.setValue(64);
ret = eip196altbn128G1Add(i, output, err, i_len, o_len, err_len);
break;
case EIP196_MUL_OPERATION_RAW_VALUE:
ret = eip196altbn128G1Mul(i, output, err, i_len,
EIP196_PREALLOCATE_FOR_RESULT_BYTES, EIP196_PREALLOCATE_FOR_ERROR_BYTES);
o_len.setValue(64);
ret = eip196altbn128G1Mul(i, output, err, i_len, o_len, err_len);
break;
case EIP196_PAIR_OPERATION_RAW_VALUE:
ret = eip196altbn128Pairing(i, output, err, i_len,
EIP196_PREALLOCATE_FOR_RESULT_BYTES, EIP196_PREALLOCATE_FOR_ERROR_BYTES);
o_len.setValue(32);
ret = eip196altbn128Pairing(i, output, err, i_len, o_len, err_len);
break;
default:
throw new RuntimeException("Not Implemented EIP-196 operation " + op);
}

if (ret != 0) {
err_len.setValue(LibGnarkUtils.findFirstTrailingZeroIndex(err));
o_len.setValue(0);
} else {
err_len.setValue(0);
}
return ret;
}

public static native int eip196altbn128G1Add(
byte[] input,
byte[] output,
byte[] error,
int inputSize, int outputSize, int err_len);
int inputSize, IntByReference outputSize, IntByReference err_len);

public static native int eip196altbn128G1Mul(
byte[] input,
byte[] output,
byte[] error,
int inputSize, int output_len, int err_len);
int inputSize, IntByReference output_len, IntByReference err_len);

public static native int eip196altbn128Pairing(
byte[] input,
byte[] output,
byte[] error,
int inputSize, int output_len, int err_len);
int inputSize, IntByReference output_len, IntByReference err_len);
}
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ public void compute_invalidPointsOutsideSubgroupG2() {
// assert there is an error
assertThat(errorLength.getValue()).isNotEqualTo(0);
String errorStr = new String(error, 0, errorLength.getValue());
assertThat(errorStr).isEqualTo("invalid point: subgroup check failed");
assertThat(errorStr).isEqualTo("invalid input parameters, invalid point: subgroup check failed");
// assert there is no output
assertThat(outputLength.getValue()).isEqualTo(0);
}
Expand Down
Loading

0 comments on commit ef5e5e3

Please sign in to comment.