1010
1111uchar *
1212fd_bn254_g1_compress ( uchar out [32 ],
13- uchar const in [64 ] ) {
13+ uchar const in [64 ],
14+ int big_endian ) {
1415 fd_bn254_g1_t p [1 ] = { 0 };
15- if ( FD_UNLIKELY ( !fd_bn254_g1_frombytes_internal ( p , in ) ) ) {
16+ if ( FD_UNLIKELY ( !fd_bn254_g1_frombytes_internal ( p , in , big_endian ) ) ) {
1617 return NULL ;
1718 }
1819 int is_inf = fd_bn254_g1_is_zero ( p );
19- int flag_inf = in [32 ] & FLAG_INF ;
20+ int flag_inf = in [ big_endian ? 32 : 63 ] & FLAG_INF ;
2021
2122 /* Serialize compressed point:
2223 https://github.com/arkworks-rs/algebra/blob/v0.4.2/ec/src/models/short_weierstrass/mod.rs#L122
@@ -32,7 +33,7 @@ fd_bn254_g1_compress( uchar out[32],
3233 }
3334
3435 int is_neg = fd_bn254_fp_is_neg_nm ( & p -> Y );
35- memmove ( out , in , 32 );
36+ fd_bn254_fp_tobytes_nm ( out , & p -> X , 1 /* compressed form is always big endian */ );
3637 if ( is_neg ) {
3738 out [0 ] = (uchar )( out [0 ] | FLAG_NEG );
3839 }
@@ -41,16 +42,17 @@ fd_bn254_g1_compress( uchar out[32],
4142
4243uchar *
4344fd_bn254_g1_decompress ( uchar out [64 ],
44- uchar const in [32 ] ) {
45+ uchar const in [32 ],
46+ int big_endian ) {
4547 /* Special case: all zeros in => all zeros out, no flags */
4648 const uchar zero [32 ] = { 0 };
4749 if ( fd_memeq ( in , zero , 32 ) ) {
4850 return fd_memset ( out , 0 , 64UL );
4951 }
5052
51- fd_bn254_fp_t x [1 ], x2 [1 ], x3_plus_b [1 ], y [1 ];
53+ fd_bn254_fp_t x_nm [ 1 ], x [1 ], x2 [1 ], x3_plus_b [1 ], y [1 ];
5254 int is_inf , is_neg ;
53- if ( FD_UNLIKELY ( !fd_bn254_fp_frombytes_be_nm ( x , in , & is_inf , & is_neg ) ) ) {
55+ if ( FD_UNLIKELY ( !fd_bn254_fp_frombytes_nm ( x_nm , in , 1 /* always BE */ , & is_inf , & is_neg ) ) ) {
5456 return NULL ;
5557 }
5658
@@ -65,7 +67,7 @@ fd_bn254_g1_decompress( uchar out[64],
6567 return out ;
6668 }
6769
68- fd_bn254_fp_to_mont ( x , x );
70+ fd_bn254_fp_to_mont ( x , x_nm );
6971 fd_bn254_fp_sqr ( x2 , x );
7072 fd_bn254_fp_mul ( x3_plus_b , x2 , x );
7173 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],
7880 fd_bn254_fp_neg_nm ( y , y );
7981 }
8082
81- memmove ( out , in , 32 ); out [ 0 ] &= FLAG_MASK ;
82- fd_bn254_fp_tobytes_be_nm ( & out [32 ], y );
83+ fd_bn254_fp_tobytes_nm ( out , x_nm , big_endian ) ;
84+ fd_bn254_fp_tobytes_nm ( & out [32 ], y , big_endian );
8385 /* no flags */
8486 return out ;
8587}
8688
8789uchar *
8890fd_bn254_g2_compress ( uchar out [64 ],
89- uchar const in [128 ] ) {
91+ uchar const in [128 ],
92+ int big_endian ) {
9093 fd_bn254_g2_t p [1 ] = { 0 };
91- if ( FD_UNLIKELY ( !fd_bn254_g2_frombytes_internal ( p , in ) ) ) {
94+ if ( FD_UNLIKELY ( !fd_bn254_g2_frombytes_internal ( p , in , big_endian ) ) ) {
9295 return NULL ;
9396 }
9497 int is_inf = fd_bn254_g2_is_zero ( p );
@@ -106,7 +109,7 @@ fd_bn254_g2_compress( uchar out[64],
106109 /* Serialize x coordinate. The flags are on the 2nd element.
107110 https://github.com/arkworks-rs/algebra/blob/v0.4.2/ff/src/fields/models/quadratic_extension.rs#L700-L702 */
108111 int is_neg = fd_bn254_fp2_is_neg_nm ( & p -> Y );
109- memmove ( out , in , 64 );
112+ fd_bn254_fp2_tobytes_nm ( out , & p -> X , 1 /* compressed form is always big endian */ );
110113 if ( is_neg ) {
111114 out [0 ] = (uchar )( out [0 ] | FLAG_NEG );
112115 }
@@ -115,16 +118,17 @@ fd_bn254_g2_compress( uchar out[64],
115118
116119uchar *
117120fd_bn254_g2_decompress ( uchar out [128 ],
118- uchar const in [64 ] ) {
121+ uchar const in [64 ],
122+ int big_endian ) {
119123 /* Special case: all zeros in => all zeros out, no flags */
120124 const uchar zero [64 ] = { 0 };
121125 if ( fd_memeq ( in , zero , 64 ) ) {
122126 return fd_memset ( out , 0 , 128UL );
123127 }
124128
125- fd_bn254_fp2_t x [1 ], x2 [1 ], x3_plus_b [1 ], y [1 ];
129+ fd_bn254_fp2_t x_nm [ 1 ], x [1 ], x2 [1 ], x3_plus_b [1 ], y [1 ];
126130 int is_inf , is_neg ;
127- if ( FD_UNLIKELY ( !fd_bn254_fp2_frombytes_be_nm ( x , in , & is_inf , & is_neg ) ) ) {
131+ if ( FD_UNLIKELY ( !fd_bn254_fp2_frombytes_nm ( x_nm , in , 1 , & is_inf , & is_neg ) ) ) {
128132 return NULL ;
129133 }
130134
@@ -138,7 +142,7 @@ fd_bn254_g2_decompress( uchar out[128],
138142 return out ;
139143 }
140144
141- fd_bn254_fp2_to_mont ( x , x );
145+ fd_bn254_fp2_to_mont ( x , x_nm );
142146 fd_bn254_fp2_sqr ( x2 , x );
143147 fd_bn254_fp2_mul ( x3_plus_b , x2 , x );
144148 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],
151155 fd_bn254_fp2_neg_nm ( y , y );
152156 }
153157
154- memmove ( out , in , 64 ); out [ 0 ] &= FLAG_MASK ;
155- fd_bn254_fp2_tobytes_be_nm ( & out [64 ], y );
158+ fd_bn254_fp2_tobytes_nm ( out , x_nm , big_endian ) ;
159+ fd_bn254_fp2_tobytes_nm ( & out [64 ], y , big_endian );
156160 /* no flags */
157161 return out ;
158162}
@@ -162,40 +166,43 @@ fd_bn254_g2_decompress( uchar out[128],
162166int
163167fd_bn254_g1_add_syscall ( uchar out [64 ],
164168 uchar const in [],
165- ulong in_sz ) {
166- /* Expected 128-byte input (2 points). Pad input with 0s. */
169+ ulong in_sz ,
170+ int big_endian ) {
171+ /* Expected 128-byte input (2 points). Pad input with 0s (only big endian). */
167172 if ( FD_UNLIKELY ( in_sz > 128UL ) ) {
168173 return -1 ;
169174 }
175+ if ( FD_UNLIKELY ( !big_endian && in_sz != 128UL ) ) {
176+ return -1 ;
177+ }
170178 uchar FD_ALIGNED buf [128 ] = { 0 };
171179 fd_memcpy ( buf , in , in_sz );
172180
173181 /* Validate inputs */
174182 fd_bn254_g1_t r [1 ], a [1 ], b [1 ];
175- if ( FD_UNLIKELY ( !fd_bn254_g1_frombytes_check_subgroup ( a , & buf [ 0 ] ) ) ) {
183+ if ( FD_UNLIKELY ( !fd_bn254_g1_frombytes_check_subgroup ( a , & buf [ 0 ], big_endian ) ) ) {
176184 return -1 ;
177185 }
178- if ( FD_UNLIKELY ( !fd_bn254_g1_frombytes_check_subgroup ( b , & buf [64 ] ) ) ) {
186+ if ( FD_UNLIKELY ( !fd_bn254_g1_frombytes_check_subgroup ( b , & buf [64 ], big_endian ) ) ) {
179187 return -1 ;
180188 }
181189
182190 /* Compute point add and serialize result */
183191 fd_bn254_g1_affine_add ( r , a , b );
184- fd_bn254_g1_tobytes ( out , r );
192+ fd_bn254_g1_tobytes ( out , r , big_endian );
185193 return 0 ;
186194}
187195
188196int
189197fd_bn254_g1_scalar_mul_syscall ( uchar out [64 ],
190198 uchar const in [],
191199 ulong in_sz ,
192- int check_correct_sz ) {
193- /* Expected 96-byte input (1 point + 1 scalar). Pad input with 0s.
194- Note: Agave checks for 128 bytes instead of 96. We have to do the same check.
195- https://github.com/anza-xyz/agave/blob/v1.18.6/sdk/program/src/alt_bn128/mod.rs#L17
196- Update: https://github.com/anza-xyz/agave/blob/d2df66d3/programs/bpf_loader/src/syscalls/mod.rs#L1654-L1658 */
197- ulong check_sz = check_correct_sz ? 96UL : 128UL ;
198- if ( FD_UNLIKELY ( in_sz > check_sz ) ) {
200+ int big_endian ) {
201+ /* Expected 96-byte input (1 point + 1 scalar). Pad input with 0s (only big endian). */
202+ if ( FD_UNLIKELY ( in_sz > 96UL ) ) {
203+ return -1 ;
204+ }
205+ if ( FD_UNLIKELY ( !big_endian && in_sz != 96UL ) ) {
199206 return -1 ;
200207 }
201208 uchar FD_ALIGNED buf [96 ] = { 0 };
@@ -204,25 +211,30 @@ fd_bn254_g1_scalar_mul_syscall( uchar out[64],
204211 /* Validate inputs */
205212 fd_bn254_g1_t r [1 ], a [1 ];
206213 fd_bn254_scalar_t s [1 ];
207- if ( FD_UNLIKELY ( !fd_bn254_g1_frombytes_check_subgroup ( a , & buf [ 0 ] ) ) ) {
214+ if ( FD_UNLIKELY ( !fd_bn254_g1_frombytes_check_subgroup ( a , & buf [ 0 ], big_endian ) ) ) {
208215 return -1 ;
209216 }
210217
211218 /* Scalar is big endian and NOT validated
212219 https://github.com/anza-xyz/agave/blob/v1.18.6/sdk/program/src/alt_bn128/mod.rs#L211-L214 */
213- fd_uint256_bswap ( s , fd_type_pun_const ( & buf [64 ] ) ); /* &buf[64] is always FD_ALIGNED */
220+ if ( FD_BIG_ENDIAN_LIKELY ( big_endian ) ) {
221+ fd_uint256_bswap ( s , fd_type_pun_const ( & buf [64 ] ) ); /* &buf[64] is always FD_ALIGNED */
222+ } else {
223+ memcpy ( s , & buf [64 ], 32 );
224+ }
214225 // no: if( FD_UNLIKELY( !fd_bn254_scalar_validate( s ) ) ) return -1;
215226
216227 /* Compute scalar mul and serialize result */
217228 fd_bn254_g1_scalar_mul ( r , a , s );
218- fd_bn254_g1_tobytes ( out , r );
229+ fd_bn254_g1_tobytes ( out , r , big_endian );
219230 return 0 ;
220231}
221232
222233int
223234fd_bn254_pairing_is_one_syscall ( uchar out [32 ],
224235 uchar const in [],
225236 ulong in_sz ,
237+ int big_endian ,
226238 int check_len ) {
227239 /* https://github.com/anza-xyz/agave/blob/v1.18.6/sdk/program/src/alt_bn128/mod.rs#L244
228240 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],
245257 ulong sz = 0 ;
246258 for ( ulong i = 0 ; i < elements_len ; i ++ ) {
247259 /* G1: deserialize and check subgroup membership */
248- if ( FD_UNLIKELY ( !fd_bn254_g1_frombytes_check_subgroup ( & p [sz ], & in [i * 192 ] ) ) ) {
260+ if ( FD_UNLIKELY ( !fd_bn254_g1_frombytes_check_subgroup ( & p [sz ], & in [i * 192 ], big_endian ) ) ) {
249261 return -1 ;
250262 }
251263 /* G2: deserialize and check subgroup membership */
252- if ( FD_UNLIKELY ( !fd_bn254_g2_frombytes_check_subgroup ( & q [sz ], & in [i * 192 + 64 ] ) ) ) {
264+ if ( FD_UNLIKELY ( !fd_bn254_g2_frombytes_check_subgroup ( & q [sz ], & in [i * 192 + 64 ], big_endian ) ) ) {
253265 return -1 ;
254266 }
255267 /* Skip any pair where either P or Q is the point at infinity */
@@ -278,7 +290,7 @@ fd_bn254_pairing_is_one_syscall( uchar out[32],
278290 /* Output is 0 or 1, serialized as big endian uint256. */
279291 fd_memset ( out , 0 , 32 );
280292 if ( FD_LIKELY ( fd_bn254_fp12_is_one ( r ) ) ) {
281- out [31 ] = 1 ;
293+ out [ big_endian ? 31 : 0 ] = 1 ;
282294 }
283295 return 0 ;
284296}
0 commit comments