Line data Source code
1 : #include "fd_bls12_381.h"
2 : #include "../bigint/fd_uint256.h"
3 :
4 : #include <blst.h>
5 :
6 : /* Scalar */
7 :
8 : typedef blst_scalar fd_bls12_381_scalar_t;
9 :
10 : static inline fd_bls12_381_scalar_t *
11 : fd_bls12_381_scalar_frombytes( fd_bls12_381_scalar_t * n,
12 : uchar const in[ 32 ],
13 660 : int big_endian ) {
14 : /* https://github.com/filecoin-project/blstrs/blob/v0.7.1/src/scalar.rs#L551-L569 */
15 660 : if( big_endian ) {
16 30 : blst_scalar_from_bendian( n, in );
17 630 : } else {
18 630 : blst_scalar_from_lendian( n, in );
19 630 : }
20 660 : if( FD_UNLIKELY( !blst_scalar_fr_check( n ) ) ) {
21 0 : return NULL;
22 0 : }
23 660 : return n;
24 660 : }
25 :
26 : /* G1 serde */
27 :
28 : typedef blst_p1_affine fd_bls12_381_g1aff_t;
29 : typedef blst_p1 fd_bls12_381_g1_t;
30 :
31 : static inline void
32 : fd_bls12_381_g1_bswap( uchar out[ 96 ], /* out can be in */
33 187377 : uchar const in [ 96 ] ) {
34 : /* copy into aligned memory */
35 187377 : ulong e[ 96/sizeof(ulong) ];
36 187377 : memcpy( e, in, 96 );
37 :
38 : /* bswap X, Y independently (48 bytes each) */
39 187377 : fd_ulong_n_bswap( e+0, 6 );
40 187377 : fd_ulong_n_bswap( e+6, 6 );
41 :
42 : /* copy to out */
43 187377 : memcpy( out, e, 96 );
44 187377 : }
45 :
46 : static inline uchar *
47 : fd_bls12_381_g1_tobytes( uchar out[ 96 ],
48 : fd_bls12_381_g1_t const * a,
49 60393 : int big_endian ) {
50 60393 : blst_p1_serialize( out, a );
51 60393 : if( !big_endian ) {
52 60348 : fd_bls12_381_g1_bswap( out, out );
53 60348 : }
54 60393 : return out;
55 60393 : }
56 :
57 : static inline fd_bls12_381_g1aff_t *
58 : fd_bls12_381_g1_frombytes_unchecked( fd_bls12_381_g1aff_t * r,
59 : uchar const _in[ 96 ],
60 124134 : int big_endian ) {
61 124134 : ulong be[ 96/sizeof(ulong) ];
62 124134 : uchar const * in = _in;
63 124134 : if( !big_endian ) {
64 124020 : fd_bls12_381_g1_bswap( (uchar *)be, _in );
65 124020 : in = (uchar *)be;
66 124020 : }
67 124134 : if( FD_UNLIKELY( blst_p1_deserialize( r, in )!=BLST_SUCCESS ) ) {
68 12 : return NULL;
69 12 : }
70 124122 : return r;
71 124134 : }
72 :
73 : static inline fd_bls12_381_g1aff_t *
74 : fd_bls12_381_g1_frombytes( fd_bls12_381_g1aff_t * r,
75 : uchar const in[ 96 ],
76 4008 : int big_endian ) {
77 4008 : if( FD_UNLIKELY( !fd_bls12_381_g1_frombytes_unchecked( r, in, big_endian ) ) ) {
78 12 : return NULL;
79 12 : }
80 3996 : if( FD_UNLIKELY( !blst_p1_affine_in_g1( r ) ) ) {
81 0 : return NULL;
82 0 : }
83 3996 : return r;
84 3996 : }
85 :
86 : /* G1 syscalls */
87 :
88 : int
89 : fd_bls12_381_g1_decompress_syscall( uchar _r[ 96 ],
90 : uchar const _a[ 48 ],
91 3030 : int big_endian ) {
92 : /* blst expects input in big endian. if little endian, bswap. */
93 3030 : ulong be[ 48/sizeof(ulong) ];
94 3030 : uchar const * in = _a;
95 3030 : if( !big_endian ) {
96 3015 : in = (uchar *)be;
97 3015 : memcpy( be, _a, 48 );
98 3015 : fd_ulong_n_bswap( be, 6 );
99 3015 : }
100 :
101 : /* decompress and serialize */
102 3030 : fd_bls12_381_g1aff_t r[1];
103 3030 : if( FD_UNLIKELY( blst_p1_uncompress( r, in )!=BLST_SUCCESS ) ) {
104 6 : return -1;
105 6 : }
106 3024 : if( FD_UNLIKELY( !blst_p1_affine_in_g1( r ) ) ) {
107 6 : return -1;
108 6 : }
109 3018 : blst_p1_affine_serialize( _r, r );
110 :
111 : /* blst output is big endian. if we want little endian, bswap. */
112 3018 : if( !big_endian ) {
113 3009 : fd_bls12_381_g1_bswap( _r, _r );
114 3009 : }
115 3018 : return 0;
116 3024 : }
117 :
118 : int
119 : fd_bls12_381_g1_validate_syscall( uchar const _a[ 96 ],
120 3030 : int big_endian ) {
121 3030 : fd_bls12_381_g1aff_t a[1];
122 3030 : return fd_bls12_381_g1_frombytes( a, _a, big_endian )!=NULL ? 0 : -1;
123 3030 : }
124 :
125 : int
126 : fd_bls12_381_g1_add_syscall( uchar _r[ 96 ],
127 : uchar const _a[ 96 ],
128 : uchar const _b[ 96 ],
129 30033 : int big_endian ) {
130 : /* points a, b are unchecked per SIMD-0388 */
131 30033 : fd_bls12_381_g1aff_t a[1], b[1];
132 30033 : if( FD_UNLIKELY( fd_bls12_381_g1_frombytes_unchecked( a, _a, big_endian )==NULL ) ) {
133 0 : return -1;
134 0 : }
135 30033 : if( FD_UNLIKELY( fd_bls12_381_g1_frombytes_unchecked( b, _b, big_endian )==NULL ) ) {
136 0 : return -1;
137 0 : }
138 :
139 30033 : fd_bls12_381_g1_t r[1], p[1];
140 30033 : blst_p1_from_affine( p, a );
141 30033 : blst_p1_add_or_double_affine( r, p, b );
142 :
143 30033 : fd_bls12_381_g1_tobytes( _r, r, big_endian );
144 30033 : return 0;
145 30033 : }
146 :
147 : int
148 : fd_bls12_381_g1_sub_syscall( uchar _r[ 96 ],
149 : uchar const _a[ 96 ],
150 : uchar const _b[ 96 ],
151 30030 : int big_endian ) {
152 : /* points a, b are unchecked per SIMD-0388 */
153 30030 : fd_bls12_381_g1aff_t a[1], b[1];
154 30030 : if( FD_UNLIKELY( fd_bls12_381_g1_frombytes_unchecked( a, _a, big_endian )==NULL ) ) {
155 0 : return -1;
156 0 : }
157 30030 : if( FD_UNLIKELY( fd_bls12_381_g1_frombytes_unchecked( b, _b, big_endian )==NULL ) ) {
158 0 : return -1;
159 0 : }
160 :
161 30030 : fd_bls12_381_g1_t r[1], p[1];
162 30030 : blst_p1_from_affine( p, a );
163 30030 : blst_fp_cneg( &b->y, &b->y, 1 ); /* -b, it works also with b=0 */
164 30030 : blst_p1_add_or_double_affine( r, p, b );
165 :
166 30030 : fd_bls12_381_g1_tobytes( _r, r, big_endian );
167 30030 : return 0;
168 30030 : }
169 :
170 : int
171 : fd_bls12_381_g1_mul_syscall( uchar _r[ 96 ],
172 : uchar const _a[ 96 ],
173 : uchar const _n[ 32 ],
174 330 : int big_endian ) {
175 : /* point a, scalar n are validated per SIMD-0388 */
176 330 : fd_bls12_381_g1aff_t a[1];
177 330 : fd_bls12_381_scalar_t n[1];
178 330 : if( FD_UNLIKELY( fd_bls12_381_g1_frombytes( a, _a, big_endian )==NULL ) ) {
179 0 : return -1;
180 0 : }
181 330 : if( FD_UNLIKELY( fd_bls12_381_scalar_frombytes( n, _n, big_endian )==NULL ) ) {
182 0 : return -1;
183 0 : }
184 :
185 330 : fd_bls12_381_g1_t r[1], p[1];
186 330 : blst_p1_from_affine( p, a );
187 : /* https://github.com/filecoin-project/blstrs/blob/v0.7.1/src/g1.rs#L578-L580 */
188 330 : blst_p1_mult( r, p, n->b, 255 );
189 :
190 330 : fd_bls12_381_g1_tobytes( _r, r, big_endian );
191 330 : return 0;
192 330 : }
193 :
194 : /* G2 serde */
195 :
196 : typedef blst_p2_affine fd_bls12_381_g2aff_t;
197 : typedef blst_p2 fd_bls12_381_g2_t;
198 :
199 : static inline void
200 : fd_bls12_381_g2_bswap( uchar out[ 96*2 ], /* out can be in */
201 187365 : uchar const in [ 96*2 ] ) {
202 : /* copy into aligned memory */
203 187365 : ulong e[ 96*2/sizeof(ulong) ];
204 187365 : memcpy( e, in, 96*2 );
205 :
206 : /* bswap X, Y independently (96 bytes each) */
207 187365 : fd_ulong_n_bswap( e+00, 12 );
208 187365 : fd_ulong_n_bswap( e+12, 12 );
209 :
210 : /* copy to out */
211 187365 : memcpy( out, e, 96*2 );
212 187365 : }
213 :
214 : static inline uchar *
215 : fd_bls12_381_g2_tobytes( uchar out[ 96*2 ],
216 : fd_bls12_381_g2_t const * a,
217 60390 : int big_endian ) {
218 60390 : blst_p2_serialize( out, a );
219 60390 : if( !big_endian ) {
220 60345 : fd_bls12_381_g2_bswap( out, out );
221 60345 : }
222 60390 : return out;
223 60390 : }
224 :
225 : static inline fd_bls12_381_g2aff_t *
226 : fd_bls12_381_g2_frombytes_unchecked( fd_bls12_381_g2aff_t * r,
227 : uchar const _in[ 96*2 ],
228 124122 : int big_endian ) {
229 124122 : ulong be[ 96*2/sizeof(ulong) ];
230 124122 : uchar const * in = _in;
231 124122 : if( !big_endian ) {
232 124011 : fd_bls12_381_g2_bswap( (uchar *)be, _in );
233 124011 : in = (uchar *)be;
234 124011 : }
235 124122 : if( FD_UNLIKELY( blst_p2_deserialize( r, in )!=BLST_SUCCESS ) ) {
236 12 : return NULL;
237 12 : }
238 124110 : return r;
239 124122 : }
240 :
241 : static inline fd_bls12_381_g2aff_t *
242 : fd_bls12_381_g2_frombytes( fd_bls12_381_g2aff_t * r,
243 : uchar const in[ 96*2 ],
244 4002 : int big_endian ) {
245 4002 : if( FD_UNLIKELY( !fd_bls12_381_g2_frombytes_unchecked( r, in, big_endian ) ) ) {
246 12 : return NULL;
247 12 : }
248 3990 : if( FD_UNLIKELY( !blst_p2_affine_in_g2( r ) ) ) {
249 0 : return NULL;
250 0 : }
251 3990 : return r;
252 3990 : }
253 :
254 : /* G2 syscalls */
255 :
256 : int
257 : fd_bls12_381_g2_decompress_syscall( uchar _r[ 96*2 ],
258 : uchar const _a[ 48*2 ],
259 3030 : int big_endian ) {
260 : /* blst expects input in big endian. if little endian, bswap. */
261 3030 : ulong be[ 48*2/sizeof(ulong) ];
262 3030 : uchar const * in = _a;
263 3030 : if( !big_endian ) {
264 3015 : in = (uchar *)be;
265 3015 : memcpy( be, _a, 48*2 );
266 3015 : fd_ulong_n_bswap( be, 6*2 );
267 3015 : }
268 :
269 : /* decompress and serialize */
270 3030 : fd_bls12_381_g2aff_t r[1];
271 3030 : if( FD_UNLIKELY( blst_p2_uncompress( r, in )!=BLST_SUCCESS ) ) {
272 6 : return -1;
273 6 : }
274 3024 : if( FD_UNLIKELY( !blst_p2_affine_in_g2( r ) ) ) {
275 6 : return -1;
276 6 : }
277 3018 : blst_p2_affine_serialize( _r, r );
278 :
279 : /* blst output is big endian. if we want little endian, bswap. */
280 3018 : if( !big_endian ) {
281 3009 : fd_bls12_381_g2_bswap( _r, _r );
282 3009 : }
283 3018 : return 0;
284 3024 : }
285 :
286 : int
287 : fd_bls12_381_g2_validate_syscall( uchar const _a[ 96*2 ],
288 3024 : int big_endian ) {
289 3024 : fd_bls12_381_g2aff_t a[1];
290 3024 : return fd_bls12_381_g2_frombytes( a, _a, big_endian )!=NULL ? 0 : -1;
291 3024 : }
292 :
293 : int
294 : fd_bls12_381_g2_add_syscall( uchar _r[ 96*2 ],
295 : uchar const _a[ 96*2 ],
296 : uchar const _b[ 96*2 ],
297 30030 : int big_endian ) {
298 : /* points a, b are unchecked per SIMD-0388 */
299 30030 : fd_bls12_381_g2aff_t a[1], b[1];
300 30030 : if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( a, _a, big_endian )==NULL ) ) {
301 0 : return -1;
302 0 : }
303 30030 : if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( b, _b, big_endian )==NULL ) ) {
304 0 : return -1;
305 0 : }
306 :
307 30030 : fd_bls12_381_g2_t r[1], p[1];
308 30030 : blst_p2_from_affine( p, a );
309 30030 : blst_p2_add_or_double_affine( r, p, b );
310 :
311 30030 : fd_bls12_381_g2_tobytes( _r, r, big_endian );
312 30030 : return 0;
313 30030 : }
314 :
315 : int
316 : fd_bls12_381_g2_sub_syscall( uchar _r[ 96*2 ],
317 : uchar const _a[ 96*2 ],
318 : uchar const _b[ 96*2 ],
319 30030 : int big_endian ) {
320 : /* points a, b are unchecked per SIMD-0388 */
321 30030 : fd_bls12_381_g2aff_t a[1], b[1];
322 30030 : if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( a, _a, big_endian )==NULL ) ) {
323 0 : return -1;
324 0 : }
325 30030 : if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( b, _b, big_endian )==NULL ) ) {
326 0 : return -1;
327 0 : }
328 :
329 30030 : fd_bls12_381_g2_t r[1], p[1];
330 30030 : blst_p2_from_affine( p, a );
331 30030 : blst_fp2_cneg( &b->y, &b->y, 1 ); /* -b, it works also with b=0 */
332 30030 : blst_p2_add_or_double_affine( r, p, b );
333 :
334 30030 : fd_bls12_381_g2_tobytes( _r, r, big_endian );
335 30030 : return 0;
336 30030 : }
337 :
338 : int
339 : fd_bls12_381_g2_mul_syscall( uchar _r[ 96*2 ],
340 : uchar const _a[ 96*2 ],
341 : uchar const _n[ 32 ],
342 330 : int big_endian ) {
343 : /* point a, scalar n are validated per SIMD-0388 */
344 330 : fd_bls12_381_g2aff_t a[1];
345 330 : fd_bls12_381_scalar_t n[1];
346 330 : if( FD_UNLIKELY( fd_bls12_381_g2_frombytes( a, _a, big_endian )==NULL ) ) {
347 0 : return -1;
348 0 : }
349 330 : if( FD_UNLIKELY( fd_bls12_381_scalar_frombytes( n, _n, big_endian )==NULL ) ) {
350 0 : return -1;
351 0 : }
352 :
353 330 : fd_bls12_381_g2_t r[1], p[1];
354 330 : blst_p2_from_affine( p, a );
355 : /* https://github.com/filecoin-project/blstrs/blob/v0.7.1/src/g2.rs#L545-L547 */
356 330 : blst_p2_mult( r, p, n->b, 255 );
357 :
358 330 : fd_bls12_381_g2_tobytes( _r, r, big_endian );
359 330 : return 0;
360 330 : }
361 :
362 : int
363 : fd_bls12_381_pairing_syscall( uchar _r[ 48*12 ],
364 : uchar const _a[], /* 96*n */
365 : uchar const _b[], /* 96*2*n */
366 : ulong const _n,
367 330 : int big_endian ) {
368 :
369 330 : if( FD_UNLIKELY( _n>FD_BLS12_381_PAIRING_BATCH_SZ ) ) {
370 0 : return -1;
371 0 : }
372 :
373 330 : fd_bls12_381_g1aff_t a[ FD_BLS12_381_PAIRING_BATCH_SZ ];
374 330 : fd_bls12_381_g2aff_t b[ FD_BLS12_381_PAIRING_BATCH_SZ ];
375 330 : fd_bls12_381_g1aff_t const * aptr[ FD_BLS12_381_PAIRING_BATCH_SZ ];
376 330 : fd_bls12_381_g2aff_t const * bptr[ FD_BLS12_381_PAIRING_BATCH_SZ ];
377 330 : ulong n = 0;
378 978 : for( ulong j=0; j<_n; j++ ) {
379 648 : if( FD_UNLIKELY( fd_bls12_381_g1_frombytes( &a[ n ], _a+96*j, big_endian )==NULL ) ) {
380 0 : return -1;
381 0 : }
382 648 : if( FD_UNLIKELY( fd_bls12_381_g2_frombytes( &b[ n ], _b+96*2*j, big_endian )==NULL ) ) {
383 0 : return -1;
384 0 : }
385 : /* blst wants an array of pointers (not necessarily a compact array) */
386 648 : aptr[ n ] = &a[ n ];
387 648 : bptr[ n ] = &b[ n ];
388 648 : ++n;
389 648 : }
390 :
391 330 : blst_fp12 r[1];
392 330 : memcpy( r, blst_fp12_one(), sizeof(blst_fp12) );
393 :
394 330 : if( FD_LIKELY ( n>0 ) ) {
395 324 : blst_miller_loop_n( r, bptr, aptr, n );
396 324 : blst_final_exp( r, r );
397 324 : }
398 :
399 330 : if( big_endian ) {
400 195 : for( ulong j=0; j<12; j++ ) {
401 180 : blst_bendian_from_fp( _r+48*(12-1-j), &r[ 0 ].fp6[ j/6 ].fp2[ (j/2)%3 ].fp[ j%2 ] );
402 180 : }
403 315 : } else {
404 4095 : for( ulong j=0; j<12; j++ ) {
405 3780 : blst_lendian_from_fp( _r+48*j, &r[ 0 ].fp6[ j/6 ].fp2[ (j/2)%3 ].fp[ j%2 ] );
406 3780 : }
407 315 : }
408 :
409 330 : return 0;
410 330 : }
|