From f07acaee9083e5254272851619ed1974dd850914 Mon Sep 17 00:00:00 2001 From: Emanuele Cesena Date: Tue, 30 Dec 2025 17:54:28 +0000 Subject: [PATCH] simd-0284: alt_bn128 little endian compatibility --- src/ballet/bn254/fd_bn254.c | 90 +++--- src/ballet/bn254/fd_bn254.h | 19 +- src/ballet/bn254/fd_bn254_field.c | 28 +- src/ballet/bn254/fd_bn254_field_ext.c | 22 +- src/ballet/bn254/fd_bn254_g1.c | 19 +- src/ballet/bn254/fd_bn254_g2.c | 12 +- src/ballet/bn254/test_bn254.c | 302 ++++++++++++++++-- src/flamenco/features/fd_features_generated.c | 8 + src/flamenco/features/fd_features_generated.h | 5 +- src/flamenco/features/feature_map.json | 3 +- src/flamenco/vm/syscall/fd_vm_syscall.h | 25 +- .../vm/syscall/fd_vm_syscall_crypto.c | 77 +++-- 12 files changed, 477 insertions(+), 133 deletions(-) diff --git a/src/ballet/bn254/fd_bn254.c b/src/ballet/bn254/fd_bn254.c index c7832e48fa8..4cfb46ffbe0 100644 --- a/src/ballet/bn254/fd_bn254.c +++ b/src/ballet/bn254/fd_bn254.c @@ -10,13 +10,14 @@ uchar * fd_bn254_g1_compress( uchar out[32], - uchar const in [64] ) { + uchar const in [64], + int big_endian ) { fd_bn254_g1_t p[1] = { 0 }; - if( FD_UNLIKELY( !fd_bn254_g1_frombytes_internal( p, in ) ) ) { + if( FD_UNLIKELY( !fd_bn254_g1_frombytes_internal( p, in, big_endian ) ) ) { return NULL; } int is_inf = fd_bn254_g1_is_zero( p ); - int flag_inf = in[32] & FLAG_INF; + int flag_inf = in[ big_endian ? 32 : 63 ] & FLAG_INF; /* Serialize compressed point: https://github.com/arkworks-rs/algebra/blob/v0.4.2/ec/src/models/short_weierstrass/mod.rs#L122 @@ -32,25 +33,26 @@ fd_bn254_g1_compress( uchar out[32], } int is_neg = fd_bn254_fp_is_neg_nm( &p->Y ); - memmove( out, in, 32 ); + fd_bn254_fp_tobytes_nm( out, &p->X, big_endian ); if( is_neg ) { - out[0] = (uchar)( out[0] | FLAG_NEG ); + out[ big_endian ? 0 : 31 ] = (uchar)( out[ big_endian ? 0 : 31 ] | FLAG_NEG ); } return out; } uchar * fd_bn254_g1_decompress( uchar out[64], - uchar const in [32] ) { + uchar const in [32], + int big_endian ) { /* Special case: all zeros in => all zeros out, no flags */ const uchar zero[32] = { 0 }; if( fd_memeq( in, zero, 32 ) ) { return fd_memset( out, 0, 64UL ); } - fd_bn254_fp_t x[1], x2[1], x3_plus_b[1], y[1]; + fd_bn254_fp_t x_nm[1], x[1], x2[1], x3_plus_b[1], y[1]; int is_inf, is_neg; - if( FD_UNLIKELY( !fd_bn254_fp_frombytes_be_nm( x, in, &is_inf, &is_neg ) ) ) { + if( FD_UNLIKELY( !fd_bn254_fp_frombytes_nm( x_nm, in, big_endian, &is_inf, &is_neg ) ) ) { return NULL; } @@ -65,7 +67,7 @@ fd_bn254_g1_decompress( uchar out[64], return out; } - fd_bn254_fp_to_mont( x, x ); + fd_bn254_fp_to_mont( x, x_nm ); fd_bn254_fp_sqr( x2, x ); fd_bn254_fp_mul( x3_plus_b, x2, x ); fd_bn254_fp_add( x3_plus_b, x3_plus_b, fd_bn254_const_b_mont ); @@ -78,17 +80,18 @@ fd_bn254_g1_decompress( uchar out[64], fd_bn254_fp_neg_nm( y, y ); } - memmove( out, in, 32 ); out[0] &= FLAG_MASK; - fd_bn254_fp_tobytes_be_nm( &out[32], y ); + fd_bn254_fp_tobytes_nm( out, x_nm, big_endian ); + fd_bn254_fp_tobytes_nm( &out[32], y, big_endian ); /* no flags */ return out; } uchar * fd_bn254_g2_compress( uchar out[64], - uchar const in[128] ) { + uchar const in[128], + int big_endian ) { fd_bn254_g2_t p[1] = { 0 }; - if( FD_UNLIKELY( !fd_bn254_g2_frombytes_internal( p, in ) ) ) { + if( FD_UNLIKELY( !fd_bn254_g2_frombytes_internal( p, in, big_endian ) ) ) { return NULL; } int is_inf = fd_bn254_g2_is_zero( p ); @@ -106,25 +109,26 @@ fd_bn254_g2_compress( uchar out[64], /* Serialize x coordinate. The flags are on the 2nd element. https://github.com/arkworks-rs/algebra/blob/v0.4.2/ff/src/fields/models/quadratic_extension.rs#L700-L702 */ int is_neg = fd_bn254_fp2_is_neg_nm( &p->Y ); - memmove( out, in, 64 ); + fd_bn254_fp2_tobytes_nm( out, &p->X, big_endian ); if( is_neg ) { - out[0] = (uchar)( out[0] | FLAG_NEG ); + out[ big_endian ? 0 : 63 ] = (uchar)( out[ big_endian ? 0 : 63 ] | FLAG_NEG ); } return out; } uchar * fd_bn254_g2_decompress( uchar out[128], - uchar const in [64] ) { + uchar const in [64], + int big_endian ) { /* Special case: all zeros in => all zeros out, no flags */ const uchar zero[64] = { 0 }; if( fd_memeq( in, zero, 64 ) ) { return fd_memset( out, 0, 128UL ); } - fd_bn254_fp2_t x[1], x2[1], x3_plus_b[1], y[1]; + fd_bn254_fp2_t x_nm[1], x[1], x2[1], x3_plus_b[1], y[1]; int is_inf, is_neg; - if( FD_UNLIKELY( !fd_bn254_fp2_frombytes_be_nm( x, in, &is_inf, &is_neg ) ) ) { + if( FD_UNLIKELY( !fd_bn254_fp2_frombytes_nm( x_nm, in, big_endian, &is_inf, &is_neg ) ) ) { return NULL; } @@ -138,7 +142,7 @@ fd_bn254_g2_decompress( uchar out[128], return out; } - fd_bn254_fp2_to_mont( x, x ); + fd_bn254_fp2_to_mont( x, x_nm ); fd_bn254_fp2_sqr( x2, x ); fd_bn254_fp2_mul( x3_plus_b, x2, x ); fd_bn254_fp2_add( x3_plus_b, x3_plus_b, fd_bn254_const_twist_b_mont ); @@ -151,8 +155,8 @@ fd_bn254_g2_decompress( uchar out[128], fd_bn254_fp2_neg_nm( y, y ); } - memmove( out, in, 64 ); out[0] &= FLAG_MASK; - fd_bn254_fp2_tobytes_be_nm( &out[64], y ); + fd_bn254_fp2_tobytes_nm( out, x_nm, big_endian ); + fd_bn254_fp2_tobytes_nm( &out[64], y, big_endian ); /* no flags */ return out; } @@ -162,26 +166,30 @@ fd_bn254_g2_decompress( uchar out[128], int fd_bn254_g1_add_syscall( uchar out[64], uchar const in[], - ulong in_sz ) { - /* Expected 128-byte input (2 points). Pad input with 0s. */ + ulong in_sz, + int big_endian ) { + /* Expected 128-byte input (2 points). Pad input with 0s (only big endian). */ if( FD_UNLIKELY( in_sz > 128UL ) ) { return -1; } + if( FD_UNLIKELY( !big_endian && in_sz != 128UL ) ) { + return -1; + } uchar FD_ALIGNED buf[128] = { 0 }; fd_memcpy( buf, in, in_sz ); /* Validate inputs */ fd_bn254_g1_t r[1], a[1], b[1]; - if( FD_UNLIKELY( !fd_bn254_g1_frombytes_check_subgroup( a, &buf[ 0] ) ) ) { + if( FD_UNLIKELY( !fd_bn254_g1_frombytes_check_subgroup( a, &buf[ 0], big_endian ) ) ) { return -1; } - if( FD_UNLIKELY( !fd_bn254_g1_frombytes_check_subgroup( b, &buf[64] ) ) ) { + if( FD_UNLIKELY( !fd_bn254_g1_frombytes_check_subgroup( b, &buf[64], big_endian ) ) ) { return -1; } /* Compute point add and serialize result */ fd_bn254_g1_affine_add( r, a, b ); - fd_bn254_g1_tobytes( out, r ); + fd_bn254_g1_tobytes( out, r, big_endian ); return 0; } @@ -189,13 +197,12 @@ int fd_bn254_g1_scalar_mul_syscall( uchar out[64], uchar const in[], ulong in_sz, - int check_correct_sz ) { - /* Expected 96-byte input (1 point + 1 scalar). Pad input with 0s. - Note: Agave checks for 128 bytes instead of 96. We have to do the same check. - https://github.com/anza-xyz/agave/blob/v1.18.6/sdk/program/src/alt_bn128/mod.rs#L17 - Update: https://github.com/anza-xyz/agave/blob/d2df66d3/programs/bpf_loader/src/syscalls/mod.rs#L1654-L1658 */ - ulong check_sz = check_correct_sz ? 96UL : 128UL; - if( FD_UNLIKELY( in_sz > check_sz ) ) { + int big_endian ) { + /* Expected 96-byte input (1 point + 1 scalar). Pad input with 0s (only big endian). */ + if( FD_UNLIKELY( in_sz > 96UL ) ) { + return -1; + } + if( FD_UNLIKELY( !big_endian && in_sz != 96UL ) ) { return -1; } uchar FD_ALIGNED buf[96] = { 0 }; @@ -204,18 +211,22 @@ fd_bn254_g1_scalar_mul_syscall( uchar out[64], /* Validate inputs */ fd_bn254_g1_t r[1], a[1]; fd_bn254_scalar_t s[1]; - if( FD_UNLIKELY( !fd_bn254_g1_frombytes_check_subgroup( a, &buf[ 0] ) ) ) { + if( FD_UNLIKELY( !fd_bn254_g1_frombytes_check_subgroup( a, &buf[ 0], big_endian ) ) ) { return -1; } /* Scalar is big endian and NOT validated https://github.com/anza-xyz/agave/blob/v1.18.6/sdk/program/src/alt_bn128/mod.rs#L211-L214 */ - fd_uint256_bswap( s, fd_type_pun_const( &buf[64] ) ); /* &buf[64] is always FD_ALIGNED */ + if( FD_BIG_ENDIAN_LIKELY( big_endian ) ) { + fd_uint256_bswap( s, fd_type_pun_const( &buf[64] ) ); /* &buf[64] is always FD_ALIGNED */ + } else { + memcpy( s, &buf[64], 32 ); + } // no: if( FD_UNLIKELY( !fd_bn254_scalar_validate( s ) ) ) return -1; /* Compute scalar mul and serialize result */ fd_bn254_g1_scalar_mul( r, a, s ); - fd_bn254_g1_tobytes( out, r ); + fd_bn254_g1_tobytes( out, r, big_endian ); return 0; } @@ -223,6 +234,7 @@ int fd_bn254_pairing_is_one_syscall( uchar out[32], uchar const in[], ulong in_sz, + int big_endian, int check_len ) { /* https://github.com/anza-xyz/agave/blob/v1.18.6/sdk/program/src/alt_bn128/mod.rs#L244 Note: Solana had a bug where it checked if input.len().checked_rem(192).is_none(), @@ -245,11 +257,11 @@ fd_bn254_pairing_is_one_syscall( uchar out[32], ulong sz=0; for( ulong i=0; ibuf[31] &= FLAG_MASK; + r->buf[ 31 ] &= FLAG_MASK; } /* Field element */ @@ -94,9 +97,12 @@ fd_bn254_fp_frombytes_be_nm( fd_bn254_fp_t * r, } static inline uchar * -fd_bn254_fp_tobytes_be_nm( uchar buf[32], - fd_bn254_fp_t * a ) { - fd_uint256_bswap( a, a ); +fd_bn254_fp_tobytes_nm( uchar buf[32], + fd_bn254_fp_t * a, + int big_endian ) { + if( FD_BIG_ENDIAN_LIKELY( big_endian ) ) { + fd_uint256_bswap( a, a ); + } fd_memcpy( buf, a, 32 ); return buf; } diff --git a/src/ballet/bn254/fd_bn254_field_ext.c b/src/ballet/bn254/fd_bn254_field_ext.c index b730acdef1c..b4d40b9b7cf 100644 --- a/src/ballet/bn254/fd_bn254_field_ext.c +++ b/src/ballet/bn254/fd_bn254_field_ext.c @@ -69,26 +69,28 @@ const fd_bn254_fp_t fd_bn254_const_frob_gamma2_mont[5] = { /* Fp2 */ static inline fd_bn254_fp2_t * -fd_bn254_fp2_frombytes_be_nm( fd_bn254_fp2_t * r, - uchar const buf[64], - int * is_inf, - int * is_neg ) { +fd_bn254_fp2_frombytes_nm( fd_bn254_fp2_t * r, + uchar const buf[64], + int big_endian, + int * is_inf, + int * is_neg ) { /* validate fp2.el[0] without flags */ - if( FD_UNLIKELY( !fd_bn254_fp_frombytes_be_nm( &r->el[0], &buf[32], NULL, NULL ) ) ) { + if( FD_UNLIKELY( !fd_bn254_fp_frombytes_nm( &r->el[0], &buf[ big_endian ? 32 : 0 ], big_endian, NULL, NULL ) ) ) { return NULL; } /* validate fp2.el[1] with flags */ - if( FD_UNLIKELY( !fd_bn254_fp_frombytes_be_nm( &r->el[1], &buf[0], is_inf, is_neg ) ) ) { + if( FD_UNLIKELY( !fd_bn254_fp_frombytes_nm( &r->el[1], &buf[ big_endian ? 0 : 32 ], big_endian, is_inf, is_neg ) ) ) { return NULL; } return r; } static inline uchar * -fd_bn254_fp2_tobytes_be_nm( uchar buf[64], - fd_bn254_fp2_t * const a ) { - fd_bn254_fp_tobytes_be_nm( &buf[ 0], &a->el[1] ); - fd_bn254_fp_tobytes_be_nm( &buf[32], &a->el[0] ); +fd_bn254_fp2_tobytes_nm( uchar buf[64], + fd_bn254_fp2_t * const a, + int big_endian ) { + fd_bn254_fp_tobytes_nm( &buf[ 0], &a->el[ big_endian ? 1 : 0 ], big_endian ); + fd_bn254_fp_tobytes_nm( &buf[32], &a->el[ big_endian ? 0 : 1 ], big_endian ); return buf; } diff --git a/src/ballet/bn254/fd_bn254_g1.c b/src/ballet/bn254/fd_bn254_g1.c index 2e0cb9b035a..1a5f6bf47f1 100644 --- a/src/ballet/bn254/fd_bn254_g1.c +++ b/src/ballet/bn254/fd_bn254_g1.c @@ -45,7 +45,8 @@ fd_bn254_g1_to_affine( fd_bn254_g1_t * r, uchar * fd_bn254_g1_tobytes( uchar out[64], - fd_bn254_g1_t const * p ) { + fd_bn254_g1_t const * p, + int big_endian ) { if( FD_UNLIKELY( fd_bn254_g1_is_zero( p ) ) ) { fd_memset( out, 0, 64UL ); /* no flags */ @@ -58,8 +59,8 @@ fd_bn254_g1_tobytes( uchar out[64], fd_bn254_fp_from_mont( &r->X, &r->X ); fd_bn254_fp_from_mont( &r->Y, &r->Y ); - fd_bn254_fp_tobytes_be_nm( &out[ 0], &r->X ); - fd_bn254_fp_tobytes_be_nm( &out[32], &r->Y ); + fd_bn254_fp_tobytes_nm( &out[ 0], &r->X, big_endian ); + fd_bn254_fp_tobytes_nm( &out[32], &r->Y, big_endian ); /* no flags */ return out; } @@ -264,7 +265,8 @@ fd_bn254_g1_scalar_mul( fd_bn254_g1_t * r, https://github.com/arkworks-rs/algebra/blob/v0.4.2/ec/src/models/short_weierstrass/mod.rs#L173-L178 */ static inline fd_bn254_g1_t * fd_bn254_g1_frombytes_internal( fd_bn254_g1_t * p, - uchar const in[64] ) { + uchar const in[64], + int big_endian ) { /* Special case: all zeros => point at infinity */ const uchar zero[64] = { 0 }; if( FD_UNLIKELY( fd_memeq( in, zero, 64 ) ) ) { @@ -272,13 +274,13 @@ fd_bn254_g1_frombytes_internal( fd_bn254_g1_t * p, } /* Check x < p */ - if( FD_UNLIKELY( !fd_bn254_fp_frombytes_be_nm( &p->X, &in[0], NULL, NULL ) ) ) { + if( FD_UNLIKELY( !fd_bn254_fp_frombytes_nm( &p->X, &in[0], big_endian, NULL, NULL ) ) ) { return NULL; } /* Check flags and y < p */ int is_inf, is_neg; - if( FD_UNLIKELY( !fd_bn254_fp_frombytes_be_nm( &p->Y, &in[32], &is_inf, &is_neg ) ) ) { + if( FD_UNLIKELY( !fd_bn254_fp_frombytes_nm( &p->Y, &in[32], big_endian, &is_inf, &is_neg ) ) ) { return NULL; } @@ -293,8 +295,9 @@ fd_bn254_g1_frombytes_internal( fd_bn254_g1_t * p, /* fd_bn254_g1_frombytes_check_subgroup performs frombytes AND checks subgroup membership. */ static inline fd_bn254_g1_t * fd_bn254_g1_frombytes_check_subgroup( fd_bn254_g1_t * p, - uchar const in[64] ) { - if( FD_UNLIKELY( !fd_bn254_g1_frombytes_internal( p, in ) ) ) { + uchar const in[64], + int big_endian ) { + if( FD_UNLIKELY( !fd_bn254_g1_frombytes_internal( p, in, big_endian ) ) ) { return NULL; } if( FD_UNLIKELY( fd_bn254_g1_is_zero( p ) ) ) { diff --git a/src/ballet/bn254/fd_bn254_g2.c b/src/ballet/bn254/fd_bn254_g2.c index ad77421b0a3..765da7e049f 100644 --- a/src/ballet/bn254/fd_bn254_g2.c +++ b/src/ballet/bn254/fd_bn254_g2.c @@ -304,7 +304,8 @@ fd_bn254_g2_scalar_mul( fd_bn254_g2_t * r, This is used by fd_bn254_g2_compress() and fd_bn254_g2_frombytes_check_subgroup(). */ static inline fd_bn254_g2_t * fd_bn254_g2_frombytes_internal( fd_bn254_g2_t * p, - uchar const in[128] ) { + uchar const in[128], + int big_endian ) { /* Special case: all zeros => point at infinity */ const uchar zero[128] = { 0 }; if( FD_UNLIKELY( fd_memeq( in, zero, 128 ) ) ) { @@ -312,13 +313,13 @@ fd_bn254_g2_frombytes_internal( fd_bn254_g2_t * p, } /* Check x < p */ - if( FD_UNLIKELY( !fd_bn254_fp2_frombytes_be_nm( &p->X, &in[0], NULL, NULL ) ) ) { + if( FD_UNLIKELY( !fd_bn254_fp2_frombytes_nm( &p->X, &in[0], big_endian, NULL, NULL ) ) ) { return NULL; } /* Check flags and y < p */ int is_inf, is_neg; - if( FD_UNLIKELY( !fd_bn254_fp2_frombytes_be_nm( &p->Y, &in[64], &is_inf, &is_neg ) ) ) { + if( FD_UNLIKELY( !fd_bn254_fp2_frombytes_nm( &p->Y, &in[64], big_endian, &is_inf, &is_neg ) ) ) { return NULL; } @@ -333,8 +334,9 @@ fd_bn254_g2_frombytes_internal( fd_bn254_g2_t * p, /* fd_bn254_g2_frombytes_check_subgroup performs frombytes AND checks subgroup membership. */ static inline fd_bn254_g2_t * fd_bn254_g2_frombytes_check_subgroup( fd_bn254_g2_t * p, - uchar const in[128] ) { - if( FD_UNLIKELY( !fd_bn254_g2_frombytes_internal( p, in ) ) ) { + uchar const in[128], + int big_endian ) { + if( FD_UNLIKELY( !fd_bn254_g2_frombytes_internal( p, in, big_endian ) ) ) { return NULL; } if( FD_UNLIKELY( fd_bn254_g2_is_zero( p ) ) ) { diff --git a/src/ballet/bn254/test_bn254.c b/src/ballet/bn254/test_bn254.c index 120edccf387..ff770c973d1 100644 --- a/src/ballet/bn254/test_bn254.c +++ b/src/ballet/bn254/test_bn254.c @@ -55,15 +55,15 @@ int main( int argc, }; uchar FD_ALIGNED res[64]; - uchar in[128]; - uchar exp[64]; + uchar FD_ALIGNED in[128]; + uchar FD_ALIGNED exp[64]; for( ulong i=0; i decompress */ - FD_TEST( fd_bn254_g1_compress( g1c, &in[0] ) ); - FD_TEST( fd_bn254_g1_decompress( g1d, g1c ) ); + FD_TEST( fd_bn254_g1_compress( g1c, &in[0], 1 /*BE*/ ) ); + FD_TEST( fd_bn254_g1_decompress( g1d, g1c, 1 /*BE*/ ) ); + if( !fd_memeq( &in[0], g1d, 64 ) ) { + FD_LOG_HEXDUMP_WARNING(( "res", g1d, 64 )); + FD_LOG_HEXDUMP_WARNING(( "exp", &in[0], 64 )); + FD_LOG_ERR(( "FAIL: test g1 %lu, %s", i, "res != exp" )); + } + + /* test G2 compress > decompress */ + FD_TEST( fd_bn254_g2_compress( g2c, &in[64], 1 /*BE*/ ) ); + FD_TEST( fd_bn254_g2_decompress( g2d, g2c, 1 /*BE*/ ) ); + if( !fd_memeq( &in[64], g2d, 64 ) ) { + FD_LOG_HEXDUMP_WARNING(( "res", g2d, 128 )); + FD_LOG_HEXDUMP_WARNING(( "exp", &in[64], 128 )); + FD_LOG_ERR(( "FAIL: test g2 %lu, %s", i, "res != exp" )); + } + FD_TEST( fd_bn254_pairing_is_one_syscall( res, in, in_sz, 1 /*BE*/, 0 /* no length check */ )==0 ); + + fd_hex_decode( exp, tests[2*i+1], 32 ); + if( !fd_memeq( res, exp, 32 ) ) { + FD_LOG_HEXDUMP_WARNING(( "res", res, 32 )); + FD_LOG_HEXDUMP_WARNING(( "exp", exp, 32 )); + FD_LOG_ERR(( "FAIL: test %lu, %s", i, "res != exp" )); + } + } + + /* little endian */ + for( ulong i=0; i decompress */ + FD_TEST( fd_bn254_g1_compress( g1c, &in[0], 0 /*LE*/ ) ); + FD_TEST( fd_bn254_g1_decompress( g1d, g1c, 0 /*LE*/ ) ); if( !fd_memeq( &in[0], g1d, 64 ) ) { FD_LOG_HEXDUMP_WARNING(( "res", g1d, 64 )); FD_LOG_HEXDUMP_WARNING(( "exp", &in[0], 64 )); @@ -332,16 +477,55 @@ int main( int argc, } /* test G2 compress > decompress */ - FD_TEST( fd_bn254_g2_compress( g2c, &in[64] ) ); - FD_TEST( fd_bn254_g2_decompress( g2d, g2c ) ); + FD_TEST( fd_bn254_g2_compress( g2c, &in[64], 0 /*LE*/ ) ); + FD_TEST( fd_bn254_g2_decompress( g2d, g2c, 0 /*LE*/ ) ); if( !fd_memeq( &in[64], g2d, 64 ) ) { FD_LOG_HEXDUMP_WARNING(( "res", g2d, 128 )); FD_LOG_HEXDUMP_WARNING(( "exp", &in[64], 128 )); FD_LOG_ERR(( "FAIL: test g2 %lu, %s", i, "res != exp" )); } - FD_TEST( fd_bn254_pairing_is_one_syscall( res, in, in_sz, 0 /* no length check */ )==0 ); + FD_TEST( fd_bn254_pairing_is_one_syscall( res, in, in_sz, 0 /*LE*/, 1 /* length check */ )==0 ); fd_hex_decode( exp, tests[2*i+1], 32 ); + fd_uint256_bswap( fd_type_pun( exp+00 ), fd_type_pun_const( exp+00 ) ); + if( !fd_memeq( res, exp, 32 ) ) { + FD_LOG_HEXDUMP_WARNING(( "res", res, 32 )); + FD_LOG_HEXDUMP_WARNING(( "exp", exp, 32 )); + FD_LOG_ERR(( "FAIL: test %lu, %s", i, "res != exp" )); + } + } + + /* https://github.com/anza-xyz/agave/pull/8771/files */ + const char * tests_le[] = { + // test 0 + "593fc42460c131dd64a6ad76aaa7ff813319a1bb7ed54145b94bef4d6f47761c41ef6aa7039b5ce494d2e9d3559b81fc4587671c81e2fe04e273f62029dd34307816a415634baf4940c08a4c11605990288d846135b4348bfa3b4801ca11bf04f75ba30320454a6b391435c6369632a799cf931ae588d84b6cd4f5bf5ed19d20507587dee4e55f1648b09b0c1fe6cca27ee039fec6205f84f91b0cf34c2a0a124d34be512a3c93bfad1fc47acd1aa7a20cfd5c441aada23735c9cff64a32b82b7cdfb6d149de22c3eacbf16f3c02a25bfacd0fc74a1cd4107709f11c9f121e1111f46b6acefa5338a77038b9853588a2fc42f22b46e96d28173c0e831ac63220edf692d95cbdde46ddda5ef7d422436779445c5e66006a42761e1f12efde0018c212f3aeb785e49712e7a9353349aaf1255dfb31b7bf60723a480d9293938e19aa7dfa6601cce64c7bd3430c69e7d1e38f40cb8d8071ab4aeb6d8cdba55ec8125b9722d1dcdaac55f38eb37033314bbc95330c69ad999eec75f05f58d0890609", + "0100000000000000000000000000000000000000000000000000000000000000", + }; + + for( ulong i=0; i decompress */ + FD_TEST( fd_bn254_g1_compress( g1c, &in[0], 0 /*LE*/ ) ); + FD_TEST( fd_bn254_g1_decompress( g1d, g1c, 0 /*LE*/ ) ); + if( !fd_memeq( &in[0], g1d, 64 ) ) { + FD_LOG_HEXDUMP_WARNING(( "res", g1d, 64 )); + FD_LOG_HEXDUMP_WARNING(( "exp", &in[0], 64 )); + FD_LOG_ERR(( "FAIL: test g1 %lu, %s", i, "res != exp" )); + } + + /* test G2 compress > decompress */ + FD_TEST( fd_bn254_g2_compress( g2c, &in[64], 0 /*LE*/ ) ); + FD_TEST( fd_bn254_g2_decompress( g2d, g2c, 0 /*LE*/ ) ); + if( !fd_memeq( &in[64], g2d, 64 ) ) { + FD_LOG_HEXDUMP_WARNING(( "res", g2d, 128 )); + FD_LOG_HEXDUMP_WARNING(( "exp", &in[64], 128 )); + FD_LOG_ERR(( "FAIL: test g2 %lu, %s", i, "res != exp" )); + } + FD_TEST( fd_bn254_pairing_is_one_syscall( res, in, in_sz, 0 /*LE*/, 1 /* length check */ )==0 ); + + fd_hex_decode( exp, tests_le[2*i+1], 32 ); if( !fd_memeq( res, exp, 32 ) ) { FD_LOG_HEXDUMP_WARNING(( "res", res, 32 )); FD_LOG_HEXDUMP_WARNING(( "exp", exp, 32 )); @@ -353,7 +537,7 @@ int main( int argc, ulong iter = 10000UL; long dt = fd_log_wallclock(); for( ulong rem=iter; rem; rem-- ) { - fd_bn254_g1_compress( g1c, &in[0] ); + fd_bn254_g1_compress( g1c, &in[0], 0 /*LE*/ ); } dt = fd_log_wallclock() - dt; log_bench( "fd_bn254_g1_compress", iter, dt ); @@ -362,7 +546,7 @@ int main( int argc, ulong iter = 10000UL; long dt = fd_log_wallclock(); for( ulong rem=iter; rem; rem-- ) { - fd_bn254_g1_decompress( g1d, g1c ); + fd_bn254_g1_decompress( g1d, g1c, 0 /*LE*/ ); } dt = fd_log_wallclock() - dt; log_bench( "fd_bn254_g1_decompress", iter, dt ); @@ -371,7 +555,7 @@ int main( int argc, ulong iter = 10000UL; long dt = fd_log_wallclock(); for( ulong rem=iter; rem; rem-- ) { - fd_bn254_g2_compress( g2c, &in[64] ); + fd_bn254_g2_compress( g2c, &in[64], 0 /*LE*/ ); } dt = fd_log_wallclock() - dt; log_bench( "fd_bn254_g2_compress", iter, dt ); @@ -380,7 +564,7 @@ int main( int argc, ulong iter = 1000UL; long dt = fd_log_wallclock(); for( ulong rem=iter; rem; rem-- ) { - fd_bn254_g2_decompress( g2d, g2c ); + fd_bn254_g2_decompress( g2d, g2c, 0 /*LE*/ ); } dt = fd_log_wallclock() - dt; log_bench( "fd_bn254_g2_decompress", iter, dt ); @@ -389,13 +573,91 @@ int main( int argc, ulong iter = 100UL; long dt = fd_log_wallclock(); for( ulong rem=iter; rem; rem-- ) { - fd_bn254_pairing_is_one_syscall( res, in, in_sz, 0 /* no length check */ ); + fd_bn254_pairing_is_one_syscall( res, in, in_sz, 0 /*LE*/, 1 /* length check */ ); } dt = fd_log_wallclock() - dt; log_bench( "fd_bn254_pairing_is_one_syscall", iter, dt ); } } + { + /* https://github.com/anza-xyz/agave/pull/8771/files */ + const char * tests_le[] = { + // test 0 + "aca862af2c0ccdb878852ca29544d9eaea784a19a491d94f8a803798a6ffce2d54c1512a7adabff3fe20089468dacad197f5db7b655aec934b6aafd10fd81814", + "aca862af2c0ccdb878852ca29544d9eaea784a19a491d94f8a803798a6ffce2d", + // test 1 + "aca862af2c0ccdb878852ca29544d9eaea784a19a491d94f8a803798a6ffce2df33b2bae9cb160488ea969d42890b6c5c562a50551eb6324de35820f63764b1c", + "aca862af2c0ccdb878852ca29544d9eaea784a19a491d94f8a803798a6ffcead", + // test 2 + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000", + }; + + uchar FD_ALIGNED in[64]; + uchar FD_ALIGNED g1c[32]; + uchar FD_ALIGNED g1d[64]; + uchar FD_ALIGNED exp[32]; + + for( ulong i=0; i decompress */ + FD_TEST( fd_bn254_g1_compress( g1c, &in[0], 0 /*LE*/ ) ); + FD_TEST( fd_bn254_g1_decompress( g1d, g1c, 0 /*LE*/ ) ); + if( !fd_memeq( &in[0], g1d, 64 ) ) { + FD_LOG_HEXDUMP_WARNING(( "res", g1d, 64 )); + FD_LOG_HEXDUMP_WARNING(( "exp", &in[0], 64 )); + FD_LOG_ERR(( "FAIL: test g1 %lu, %s", i, "res != exp" )); + } + if( !fd_memeq( exp, g1c, 32 ) ) { + FD_LOG_HEXDUMP_WARNING(( "res", g1c, 32 )); + FD_LOG_HEXDUMP_WARNING(( "exp", exp, 32 )); + FD_LOG_ERR(( "FAIL: test g1 %lu, %s", i, "res != exp" )); + } + } + } + + { + /* https://github.com/anza-xyz/agave/pull/8771/files */ + const char * tests_le[] = { + // test 0 + "38b05612a851ae4b9f5cc4a8b7cd8911d185bdec97eeb442d497226eb07ccb0019f2348d679250b8bd6a822f93f72e07e176470c5d1705d76f232eb4cde939281298933ebd13115aae93903c5bb1c816f503d3f7315e83da64fef65006a8810e16046cae9358b74f1fe46d210fb68232fd158d62a9fb3e688e7a511214d21a10", + "38b05612a851ae4b9f5cc4a8b7cd8911d185bdec97eeb442d497226eb07ccb0019f2348d679250b8bd6a822f93f72e07e176470c5d1705d76f232eb4cde93928", + // test 1 + "38b05612a851ae4b9f5cc4a8b7cd8911d185bdec97eeb442d497226eb07ccb0019f2348d679250b8bd6a822f93f72e07e176470c5d1705d76f232eb4cde939283565e99959780fe2de36e12b36b9b8806854ae8984e7ccddc4a13a906ca6e22131f9102a833369ec6de6034782b4fe646042f41e0d4a11509b25e0ce5e7c4920", + "38b05612a851ae4b9f5cc4a8b7cd8911d185bdec97eeb442d497226eb07ccb0019f2348d679250b8bd6a822f93f72e07e176470c5d1705d76f232eb4cde939a8", + // test 2 + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }; + + uchar FD_ALIGNED in[128]; + uchar FD_ALIGNED g2c[64]; + uchar FD_ALIGNED g2d[128]; + uchar FD_ALIGNED exp[64]; + + for( ulong i=0; i decompress */ + FD_TEST( fd_bn254_g2_compress( g2c, &in[0], 0 /*LE*/ ) ); + FD_TEST( fd_bn254_g2_decompress( g2d, g2c, 0 /*LE*/ ) ); + if( !fd_memeq( &in[0], g2d, 128 ) ) { + FD_LOG_HEXDUMP_WARNING(( "res", g2d, 128 )); + FD_LOG_HEXDUMP_WARNING(( "exp", &in[0], 128 )); + FD_LOG_ERR(( "FAIL: test g1 %lu, %s", i, "res != exp" )); + } + if( !fd_memeq( exp, g2c, 64 ) ) { + FD_LOG_HEXDUMP_WARNING(( "res", g2c, 64 )); + FD_LOG_HEXDUMP_WARNING(( "exp", exp, 64 )); + FD_LOG_ERR(( "FAIL: test g1 %lu, %s", i, "res != exp" )); + } + } + } + FD_LOG_NOTICE(( "pass" )); fd_halt(); return 0; diff --git a/src/flamenco/features/fd_features_generated.c b/src/flamenco/features/fd_features_generated.c index f5d6ce9160b..50a124375e1 100644 --- a/src/flamenco/features/fd_features_generated.c +++ b/src/flamenco/features/fd_features_generated.c @@ -1733,6 +1733,12 @@ fd_feature_id_t const ids[] = { .name = "vote_state_v4", .cleaned_up = {UINT_MAX, UINT_MAX, UINT_MAX} }, + { .index = offsetof(fd_features_t, alt_bn128_little_endian)>>3, + .id = {"\x08\xe9\x1e\x13\xdc\xdd\x4a\x1b\x2e\x74\x17\x90\x41\x13\xdf\xa7\xe6\x56\x26\xa8\x1f\x90\x65\x52\x79\xaf\x2c\x85\xb0\x8b\xf5\x4e"}, + /* bnS3pWfLrxHRJvMyLm6EaYQkP7A2Fe9DxoKv4aGA8YM */ + .name = "alt_bn128_little_endian", + .cleaned_up = {UINT_MAX, UINT_MAX, UINT_MAX} }, + { .index = ULONG_MAX } }; /* TODO replace this with fd_map_perfect */ @@ -1993,6 +1999,7 @@ fd_feature_id_query( ulong prefix ) { case 0xf4792febab30b80c: return &ids[ 251 ]; case 0xdab5b6a991a03e4b: return &ids[ 252 ]; case 0x8921a3abf23afaec: return &ids[ 253 ]; + case 0x1b4adddc131ee908: return &ids[ 254 ]; default: break; } return NULL; @@ -2252,4 +2259,5 @@ FD_STATIC_ASSERT( offsetof( fd_features_t, increase_cpi_account_info_limit FD_STATIC_ASSERT( offsetof( fd_features_t, deprecate_rent_exemption_threshold )>>3==251UL, layout ); FD_STATIC_ASSERT( offsetof( fd_features_t, static_instruction_limit )>>3==252UL, layout ); FD_STATIC_ASSERT( offsetof( fd_features_t, vote_state_v4 )>>3==253UL, layout ); +FD_STATIC_ASSERT( offsetof( fd_features_t, alt_bn128_little_endian )>>3==254UL, layout ); FD_STATIC_ASSERT( sizeof( fd_features_t )>>3==FD_FEATURE_ID_CNT, layout ); diff --git a/src/flamenco/features/fd_features_generated.h b/src/flamenco/features/fd_features_generated.h index 31ca8a19a60..787dc136a64 100644 --- a/src/flamenco/features/fd_features_generated.h +++ b/src/flamenco/features/fd_features_generated.h @@ -8,10 +8,10 @@ #endif /* FEATURE_ID_CNT is the number of features in ids */ -#define FD_FEATURE_ID_CNT (254UL) +#define FD_FEATURE_ID_CNT (255UL) /* Feature set ID calculated from all feature names */ -#define FD_FEATURE_SET_ID (2034823332U) +#define FD_FEATURE_SET_ID (1433567363U) union fd_features { ulong f[ FD_FEATURE_ID_CNT ]; @@ -270,5 +270,6 @@ union fd_features { /* 0xf4792febab30b80c */ ulong deprecate_rent_exemption_threshold; /* 0xdab5b6a991a03e4b */ ulong static_instruction_limit; /* 0x8921a3abf23afaec */ ulong vote_state_v4; + /* 0x1b4adddc131ee908 */ ulong alt_bn128_little_endian; }; }; diff --git a/src/flamenco/features/feature_map.json b/src/flamenco/features/feature_map.json index 621e0241d88..5792aabb3ee 100644 --- a/src/flamenco/features/feature_map.json +++ b/src/flamenco/features/feature_map.json @@ -252,5 +252,6 @@ {"name":"increase_cpi_account_info_limit","pubkey":"H6iVbVaDZgDphcPbcZwc5LoznMPWQfnJ1AM7L1xzqvt5"}, {"name":"deprecate_rent_exemption_threshold","pubkey":"rent6iVy6PDoViPBeJ6k5EJQrkj62h7DPyLbWGHwjrC"}, {"name":"static_instruction_limit","pubkey":"64ixypL1HPu8WtJhNSMb9mSgfFaJvsANuRkTbHyuLfnx"}, - {"name":"vote_state_v4","pubkey":"Gx4XFcrVMt4HUvPzTpTSVkdDVgcDSjKhDN1RqRS6KDuZ"} + {"name":"vote_state_v4","pubkey":"Gx4XFcrVMt4HUvPzTpTSVkdDVgcDSjKhDN1RqRS6KDuZ"}, + {"name":"alt_bn128_little_endian","pubkey":"bnS3pWfLrxHRJvMyLm6EaYQkP7A2Fe9DxoKv4aGA8YM"} ] diff --git a/src/flamenco/vm/syscall/fd_vm_syscall.h b/src/flamenco/vm/syscall/fd_vm_syscall.h index ea3db2480f3..83a5d3d7866 100644 --- a/src/flamenco/vm/syscall/fd_vm_syscall.h +++ b/src/flamenco/vm/syscall/fd_vm_syscall.h @@ -799,17 +799,26 @@ FD_VM_SYSCALL_DECL( cpi_rust ); /* FD_VM_SYSCALL_SOL_ALT_BN128_{ADD,SUB,MUL,PAIRING} specifies the curve operation. */ -#define FD_VM_SYSCALL_SOL_ALT_BN128_ADD ( 0UL) /* add */ -#define FD_VM_SYSCALL_SOL_ALT_BN128_SUB ( 1UL) /* add inverse */ -#define FD_VM_SYSCALL_SOL_ALT_BN128_MUL ( 2UL) /* scalar mult */ -#define FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING ( 3UL) /* pairing */ +#define FD_VM_SYSCALL_SOL_ALT_BN128_ADD_BE ( 0UL) /* add */ +#define FD_VM_SYSCALL_SOL_ALT_BN128_SUB_BE ( 1UL) /* add inverse */ +#define FD_VM_SYSCALL_SOL_ALT_BN128_MUL_BE ( 2UL) /* scalar mult */ +#define FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_BE ( 3UL) /* pairing */ +#define FD_VM_SYSCALL_SOL_ALT_BN128_LITTLE_ENDIAN_FLAG ( 0x80) /* little endian (SIMD-0284) */ +#define FD_VM_SYSCALL_SOL_ALT_BN128_ADD_LE ( FD_VM_SYSCALL_SOL_ALT_BN128_ADD_BE | FD_VM_SYSCALL_SOL_ALT_BN128_LITTLE_ENDIAN_FLAG ) +#define FD_VM_SYSCALL_SOL_ALT_BN128_SUB_LE ( FD_VM_SYSCALL_SOL_ALT_BN128_SUB_BE | FD_VM_SYSCALL_SOL_ALT_BN128_LITTLE_ENDIAN_FLAG ) +#define FD_VM_SYSCALL_SOL_ALT_BN128_MUL_LE ( FD_VM_SYSCALL_SOL_ALT_BN128_MUL_BE | FD_VM_SYSCALL_SOL_ALT_BN128_LITTLE_ENDIAN_FLAG ) +#define FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_LE ( FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_BE | FD_VM_SYSCALL_SOL_ALT_BN128_LITTLE_ENDIAN_FLAG ) /* FD_VM_SYSCALL_SOL_ALT_BN128_{...}COMPRESS specifies the (de)compress operation. */ -#define FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESS ( 0UL) /* compress point in G1 */ -#define FD_VM_SYSCALL_SOL_ALT_BN128_G1_DECOMPRESS ( 1UL) /* decompress point in G1 */ -#define FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESS ( 2UL) /* compress point in G2 */ -#define FD_VM_SYSCALL_SOL_ALT_BN128_G2_DECOMPRESS ( 3UL) /* decompress point in G2 */ +#define FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESS_BE ( 0UL) /* compress point in G1 */ +#define FD_VM_SYSCALL_SOL_ALT_BN128_G1_DECOMPRESS_BE ( 1UL) /* decompress point in G1 */ +#define FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESS_BE ( 2UL) /* compress point in G2 */ +#define FD_VM_SYSCALL_SOL_ALT_BN128_G2_DECOMPRESS_BE ( 3UL) /* decompress point in G2 */ +#define FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESS_LE ( FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESS_BE | FD_VM_SYSCALL_SOL_ALT_BN128_LITTLE_ENDIAN_FLAG ) +#define FD_VM_SYSCALL_SOL_ALT_BN128_G1_DECOMPRESS_LE ( FD_VM_SYSCALL_SOL_ALT_BN128_G1_DECOMPRESS_BE | FD_VM_SYSCALL_SOL_ALT_BN128_LITTLE_ENDIAN_FLAG ) +#define FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESS_LE ( FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESS_BE | FD_VM_SYSCALL_SOL_ALT_BN128_LITTLE_ENDIAN_FLAG ) +#define FD_VM_SYSCALL_SOL_ALT_BN128_G2_DECOMPRESS_LE ( FD_VM_SYSCALL_SOL_ALT_BN128_G2_DECOMPRESS_BE | FD_VM_SYSCALL_SOL_ALT_BN128_LITTLE_ENDIAN_FLAG ) /* FD_VM_SYSCALL_SOL_ALT_BN128_{...}_SZ specifies the size of inputs/outputs for the Alt_BN128 curve. */ diff --git a/src/flamenco/vm/syscall/fd_vm_syscall_crypto.c b/src/flamenco/vm/syscall/fd_vm_syscall_crypto.c index 461d67ae9c2..c9adec4643d 100644 --- a/src/flamenco/vm/syscall/fd_vm_syscall_crypto.c +++ b/src/flamenco/vm/syscall/fd_vm_syscall_crypto.c @@ -22,17 +22,20 @@ fd_vm_syscall_sol_alt_bn128_group_op( void * _vm, ulong output_sz = 0UL; switch( group_op ) { - case FD_VM_SYSCALL_SOL_ALT_BN128_ADD: + case FD_VM_SYSCALL_SOL_ALT_BN128_ADD_BE: + case FD_VM_SYSCALL_SOL_ALT_BN128_ADD_LE: output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G1_SZ; cost = FD_VM_ALT_BN128_ADDITION_COST; break; - case FD_VM_SYSCALL_SOL_ALT_BN128_MUL: + case FD_VM_SYSCALL_SOL_ALT_BN128_MUL_BE: + case FD_VM_SYSCALL_SOL_ALT_BN128_MUL_LE: output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G1_SZ; cost = FD_VM_ALT_BN128_MULTIPLICATION_COST; break; - case FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING: + case FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_BE: + case FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_LE: output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_OUTPUT_SZ; ulong elements_len = input_sz / FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_INPUT_EL_SZ; cost = FD_VM_ALT_BN128_PAIRING_ONE_PAIR_COST_FIRST @@ -68,29 +71,40 @@ fd_vm_syscall_sol_alt_bn128_group_op( void * _vm, uchar * call_result = call_result_query.haddr; uchar const * input = FD_VM_MEM_SLICE_HADDR_LD( vm, input_addr, FD_VM_ALIGN_RUST_U8, input_sz ); + int big_endian = ( group_op & FD_VM_SYSCALL_SOL_ALT_BN128_LITTLE_ENDIAN_FLAG ) ? 0 : 1; + + /* little endian is under feature gate (big endian is not) */ + int is_active_alt_bn128_little_endian = FD_FEATURE_ACTIVE_BANK( vm->instr_ctx->bank, alt_bn128_little_endian ); + if( FD_LIKELY( !is_active_alt_bn128_little_endian && !big_endian ) ) { + FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE ); + return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */ + } + /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1567-L1598 Note: this implementation is post SIMD-0129, we only support the simplified error codes. */ switch( group_op ) { - case FD_VM_SYSCALL_SOL_ALT_BN128_ADD: + case FD_VM_SYSCALL_SOL_ALT_BN128_ADD_BE: + case FD_VM_SYSCALL_SOL_ALT_BN128_ADD_LE: /* Compute add */ - if( FD_LIKELY( fd_bn254_g1_add_syscall( call_result, input, input_sz )==0 ) ) { + if( FD_LIKELY( fd_bn254_g1_add_syscall( call_result, input, input_sz, big_endian )==0 ) ) { ret = 0UL; /* success */ } break; - case FD_VM_SYSCALL_SOL_ALT_BN128_MUL: + case FD_VM_SYSCALL_SOL_ALT_BN128_MUL_BE: + case FD_VM_SYSCALL_SOL_ALT_BN128_MUL_LE: /* Compute scalar mul */ - if( FD_LIKELY( fd_bn254_g1_scalar_mul_syscall( call_result, input, input_sz, - FD_FEATURE_ACTIVE_BANK( vm->instr_ctx->bank, fix_alt_bn128_multiplication_input_length ) )==0 ) ) { + if( FD_LIKELY( fd_bn254_g1_scalar_mul_syscall( call_result, input, input_sz, big_endian )==0 ) ) { ret = 0UL; /* success */ } break; - case FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING: + case FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_BE: + case FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_LE: /* Compute pairing with length check based on feature gate. https://github.com/anza-xyz/solana-sdk/blob/bn254%40v3.1.2/bn254/src/pairing.rs#L76-L82 */ - if( FD_LIKELY( fd_bn254_pairing_is_one_syscall( call_result, input, input_sz, + if( FD_LIKELY( fd_bn254_pairing_is_one_syscall( call_result, input, input_sz, big_endian, FD_FEATURE_ACTIVE_BANK( vm->instr_ctx->bank, fix_alt_bn128_pairing_length_check ) )==0 ) ) { ret = 0UL; /* success */ } @@ -118,22 +132,26 @@ fd_vm_syscall_sol_alt_bn128_compression( void * _vm, ulong output_sz = 0UL; switch( op ) { - case FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESS: + case FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESS_BE: + case FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESS_LE: output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESSED_SZ; cost = FD_VM_ALT_BN128_G1_COMPRESS; break; - case FD_VM_SYSCALL_SOL_ALT_BN128_G1_DECOMPRESS: + case FD_VM_SYSCALL_SOL_ALT_BN128_G1_DECOMPRESS_BE: + case FD_VM_SYSCALL_SOL_ALT_BN128_G1_DECOMPRESS_LE: output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G1_SZ; cost = FD_VM_ALT_BN128_G1_DECOMPRESS; break; - case FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESS: + case FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESS_BE: + case FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESS_LE: output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESSED_SZ; cost = FD_VM_ALT_BN128_G2_COMPRESS; break; - case FD_VM_SYSCALL_SOL_ALT_BN128_G2_DECOMPRESS: + case FD_VM_SYSCALL_SOL_ALT_BN128_G2_DECOMPRESS_BE: + case FD_VM_SYSCALL_SOL_ALT_BN128_G2_DECOMPRESS_LE: output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G2_SZ; cost = FD_VM_ALT_BN128_G2_DECOMPRESS; break; @@ -164,47 +182,60 @@ fd_vm_syscall_sol_alt_bn128_compression( void * _vm, void const * input = FD_VM_MEM_SLICE_HADDR_LD( vm, input_addr, FD_VM_ALIGN_RUST_U8, input_sz ); /* input and call_result may alias. Therefore, buffer via out_buf */ - uchar out_buf[128]; + uchar FD_ALIGNED out_buf[128]; + + int big_endian = ( op & FD_VM_SYSCALL_SOL_ALT_BN128_LITTLE_ENDIAN_FLAG ) ? 0 : 1; + + /* little endian is under feature gate (big endian is not) */ + int is_active_alt_bn128_little_endian = FD_FEATURE_ACTIVE_BANK( vm->instr_ctx->bank, alt_bn128_little_endian ); + if( FD_LIKELY( !is_active_alt_bn128_little_endian && !big_endian ) ) { + FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE ); + return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */ + } /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1829-L1891 Note: this implementation is post SIMD-0129, we only support the simplified error codes. */ switch( op ) { - case FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESS: + case FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESS_BE: + case FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESS_LE: if( FD_UNLIKELY( input_sz!=FD_VM_SYSCALL_SOL_ALT_BN128_G1_SZ ) ) { goto soft_error; } - if( FD_LIKELY( fd_bn254_g1_compress( out_buf, fd_type_pun_const(input) ) ) ) { + if( FD_LIKELY( fd_bn254_g1_compress( out_buf, fd_type_pun_const(input), big_endian ) ) ) { fd_memcpy( call_result, out_buf, FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESSED_SZ ); ret = 0UL; /* success */ } break; - case FD_VM_SYSCALL_SOL_ALT_BN128_G1_DECOMPRESS: + case FD_VM_SYSCALL_SOL_ALT_BN128_G1_DECOMPRESS_BE: + case FD_VM_SYSCALL_SOL_ALT_BN128_G1_DECOMPRESS_LE: if( FD_UNLIKELY( input_sz!=FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESSED_SZ ) ) { goto soft_error; } - if( FD_LIKELY( fd_bn254_g1_decompress( out_buf, fd_type_pun_const(input) ) ) ) { + if( FD_LIKELY( fd_bn254_g1_decompress( out_buf, fd_type_pun_const(input), big_endian ) ) ) { fd_memcpy( call_result, out_buf, FD_VM_SYSCALL_SOL_ALT_BN128_G1_SZ ); ret = 0UL; /* success */ } break; - case FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESS: + case FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESS_BE: + case FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESS_LE: if( FD_UNLIKELY( input_sz!=FD_VM_SYSCALL_SOL_ALT_BN128_G2_SZ ) ) { goto soft_error; } - if( FD_LIKELY( fd_bn254_g2_compress( out_buf, fd_type_pun_const(input) ) ) ) { + if( FD_LIKELY( fd_bn254_g2_compress( out_buf, fd_type_pun_const(input), big_endian ) ) ) { fd_memcpy( call_result, out_buf, FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESSED_SZ ); ret = 0UL; /* success */ } break; - case FD_VM_SYSCALL_SOL_ALT_BN128_G2_DECOMPRESS: + case FD_VM_SYSCALL_SOL_ALT_BN128_G2_DECOMPRESS_BE: + case FD_VM_SYSCALL_SOL_ALT_BN128_G2_DECOMPRESS_LE: if( FD_UNLIKELY( input_sz!=FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESSED_SZ ) ) { goto soft_error; } - if( FD_LIKELY( fd_bn254_g2_decompress( out_buf, fd_type_pun_const(input) ) ) ) { + if( FD_LIKELY( fd_bn254_g2_decompress( out_buf, fd_type_pun_const(input), big_endian ) ) ) { fd_memcpy( call_result, out_buf, FD_VM_SYSCALL_SOL_ALT_BN128_G2_SZ ); ret = 0UL; /* success */ }