Skip to content

Commit 2e0f7d1

Browse files
committed
simd-0284: alt_bn128 little endian compatibility
1 parent 35857a1 commit 2e0f7d1

File tree

12 files changed

+311
-127
lines changed

12 files changed

+311
-127
lines changed

src/ballet/bn254/fd_bn254.c

Lines changed: 49 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@
1010

1111
uchar *
1212
fd_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

4243
uchar *
4344
fd_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

8789
uchar *
8890
fd_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

116119
uchar *
117120
fd_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],
162166
int
163167
fd_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

188196
int
189197
fd_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

222233
int
223234
fd_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
}

src/ballet/bn254/fd_bn254.h

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,27 @@
88
#include "./fd_bn254_scalar.h"
99

1010
#define FD_BN254_PAIRING_BATCH_MAX 16UL
11+
#define FD_BIG_ENDIAN_LIKELY FD_LIKELY
1112

1213
FD_PROTOTYPES_BEGIN
1314

1415
int
1516
fd_bn254_g1_add_syscall( uchar out[64],
1617
uchar const in[],
17-
ulong in_sz );
18+
ulong in_sz,
19+
int big_endian );
1820

1921
int
2022
fd_bn254_g1_scalar_mul_syscall( uchar out[64],
2123
uchar const in[],
2224
ulong in_sz,
23-
int check_correct_sz );
25+
int big_endian );
2426

2527
int
2628
fd_bn254_pairing_is_one_syscall( uchar out[32],
2729
uchar const in[],
2830
ulong in_sz,
31+
int big_endian,
2932
int check_len );
3033

3134
/* fd_bn254_g1_compress compresses a point in G1.
@@ -37,7 +40,8 @@ fd_bn254_pairing_is_one_syscall( uchar out[32],
3740
Note: this function does NOT check that (x, y) is in G1. */
3841
uchar *
3942
fd_bn254_g1_compress( uchar out[32],
40-
uchar const in [64] );
43+
uchar const in [64],
44+
int big_endian );
4145

4246
/* fd_bn254_g1_decompress decompresses a point in G1.
4347
Input in is a 32-byte big endian buffer representing the x coord of a point,
@@ -48,7 +52,8 @@ fd_bn254_g1_compress( uchar out[32],
4852
(Success implies that (x, y) is in G1.) */
4953
uchar *
5054
fd_bn254_g1_decompress( uchar out[64],
51-
uchar const in [32] );
55+
uchar const in [32],
56+
int big_endian );
5257

5358
/* fd_bn254_g2_compress compresses a point in G2.
5459
Same as fd_bn254_g1_compress, but x, y are in Fp2, so twice as long.
@@ -60,7 +65,8 @@ fd_bn254_g1_decompress( uchar out[64],
6065
Note: this function does NOT check that (x, y) is in G2. */
6166
uchar *
6267
fd_bn254_g2_compress( uchar out[64],
63-
uchar const in[128] );
68+
uchar const in[128],
69+
int big_endian );
6470

6571
/* fd_bn254_g2_decompress decompresses a point in G2.
6672
Same as fd_bn254_g1_decompress, but x, y are in Fp2, so twice as long.
@@ -73,7 +79,8 @@ fd_bn254_g2_compress( uchar out[64],
7379
imply that). */
7480
uchar *
7581
fd_bn254_g2_decompress( uchar out[128],
76-
uchar const in [64] );
82+
uchar const in [64],
83+
int big_endian );
7784

7885
FD_PROTOTYPES_END
7986

src/ballet/bn254/fd_bn254_field.c

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,15 @@ fd_bn254_fp_is_neg_nm( fd_bn254_fp_t * x ) {
6565
}
6666

6767
static inline fd_bn254_fp_t *
68-
fd_bn254_fp_frombytes_be_nm( fd_bn254_fp_t * r,
69-
uchar const buf[32],
70-
int * is_inf,
71-
int * is_neg ) {
68+
fd_bn254_fp_frombytes_nm( fd_bn254_fp_t * r,
69+
uchar const buf[32],
70+
int big_endian,
71+
int * is_inf,
72+
int * is_neg ) {
7273
/* Flags (optional) */
7374
if( is_inf != NULL /* && is_neg != NULL */ ) {
74-
*is_inf = !!(buf[0] & FLAG_INF);
75-
*is_neg = !!(buf[0] & FLAG_NEG);
75+
*is_inf = !!(buf[ big_endian ? 0 : 31 ] & FLAG_INF);
76+
*is_neg = !!(buf[ big_endian ? 0 : 31 ] & FLAG_NEG);
7677
/* If both flags are set (bit 6, 7), return error.
7778
https://github.com/arkworks-rs/algebra/blob/v0.4.2/ec/src/models/short_weierstrass/serialization_flags.rs#L75 */
7879
if( FD_UNLIKELY( *is_inf && *is_neg ) ) {
@@ -81,9 +82,11 @@ fd_bn254_fp_frombytes_be_nm( fd_bn254_fp_t * r,
8182
}
8283

8384
fd_memcpy( r, buf, 32 );
84-
fd_uint256_bswap( r, r );
85+
if( FD_BIG_ENDIAN_LIKELY( big_endian ) ) {
86+
fd_uint256_bswap( r, r );
87+
}
8588
if( is_inf != NULL ) {
86-
r->buf[31] &= FLAG_MASK;
89+
r->buf[ 31 ] &= FLAG_MASK;
8790
}
8891

8992
/* Field element */
@@ -94,9 +97,12 @@ fd_bn254_fp_frombytes_be_nm( fd_bn254_fp_t * r,
9497
}
9598

9699
static inline uchar *
97-
fd_bn254_fp_tobytes_be_nm( uchar buf[32],
98-
fd_bn254_fp_t * a ) {
99-
fd_uint256_bswap( a, a );
100+
fd_bn254_fp_tobytes_nm( uchar buf[32],
101+
fd_bn254_fp_t * a,
102+
int big_endian ) {
103+
if( FD_BIG_ENDIAN_LIKELY( big_endian ) ) {
104+
fd_uint256_bswap( a, a );
105+
}
100106
fd_memcpy( buf, a, 32 );
101107
return buf;
102108
}

0 commit comments

Comments
 (0)