Line data Source code
1 : #include "fd_bls12_381.h"
2 : #include "../bigint/fd_uint256.h"
3 :
4 : #include "../../third_party/blst/bindings/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 187383 : uchar const in [ 96 ] ) {
34 : /* copy into aligned memory */
35 187383 : ulong e[ 96/sizeof(ulong) ];
36 187383 : memcpy( e, in, 96 );
37 :
38 : /* bswap X, Y independently (48 bytes each) */
39 187383 : fd_ulong_n_bswap( e+0, 6 );
40 187383 : fd_ulong_n_bswap( e+6, 6 );
41 :
42 : /* copy to out */
43 187383 : memcpy( out, e, 96 );
44 187383 : }
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 124170 : int big_endian ) {
61 124170 : ulong be[ 96/sizeof(ulong) ];
62 124170 : uchar const * in = _in;
63 124170 : if( !big_endian ) {
64 124023 : fd_bls12_381_g1_bswap( (uchar *)be, _in );
65 124023 : in = (uchar *)be;
66 124023 : }
67 :
68 : /* Reject the point if the compressed or parity flag is set.
69 : https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/bls12-381/src/encoding.rs#L57-L60 */
70 124170 : if( FD_UNLIKELY( in[ 0 ] & 0xA0 ) ) {
71 3 : return NULL;
72 3 : }
73 :
74 124167 : if( FD_UNLIKELY( blst_p1_deserialize( r, in )!=BLST_SUCCESS ) ) {
75 12 : return NULL;
76 12 : }
77 124155 : return r;
78 124167 : }
79 :
80 : static inline fd_bls12_381_g1aff_t *
81 : fd_bls12_381_g1_frombytes( fd_bls12_381_g1aff_t * r,
82 : uchar const in[ 96 ],
83 4044 : int big_endian ) {
84 4044 : if( FD_UNLIKELY( !fd_bls12_381_g1_frombytes_unchecked( r, in, big_endian ) ) ) {
85 15 : return NULL;
86 15 : }
87 4029 : if( FD_UNLIKELY( !blst_p1_affine_in_g1( r ) ) ) {
88 0 : return NULL;
89 0 : }
90 4029 : return r;
91 4029 : }
92 :
93 : /* G1 syscalls */
94 :
95 : int
96 : fd_bls12_381_g1_decompress_syscall( uchar _r[ 96 ],
97 : uchar const _a[ 48 ],
98 3552 : int big_endian ) {
99 : /* blst expects input in big endian. if little endian, bswap. */
100 3552 : ulong be[ 48/sizeof(ulong) ];
101 3552 : uchar const * in = _a;
102 3552 : if( !big_endian ) {
103 3018 : in = (uchar *)be;
104 3018 : memcpy( be, _a, 48 );
105 3018 : fd_ulong_n_bswap( be, 6 );
106 3018 : }
107 :
108 : /* decompress and serialize */
109 3552 : fd_bls12_381_g1aff_t r[1];
110 3552 : if( FD_UNLIKELY( blst_p1_uncompress( r, in )!=BLST_SUCCESS ) ) {
111 465 : return -1;
112 465 : }
113 3087 : if( FD_UNLIKELY( !blst_p1_affine_in_g1( r ) ) ) {
114 6 : return -1;
115 6 : }
116 3081 : blst_p1_affine_serialize( _r, r );
117 :
118 : /* blst output is big endian. if we want little endian, bswap. */
119 3081 : if( !big_endian ) {
120 3012 : fd_bls12_381_g1_bswap( _r, _r );
121 3012 : }
122 3081 : return 0;
123 3087 : }
124 :
125 : int
126 : fd_bls12_381_g1_validate_syscall( uchar const _a[ 96 ],
127 3033 : int big_endian ) {
128 3033 : fd_bls12_381_g1aff_t a[1];
129 3033 : return !!fd_bls12_381_g1_frombytes( a, _a, big_endian );
130 3033 : }
131 :
132 : int
133 : fd_bls12_381_g1_add_syscall( uchar _r[ 96 ],
134 : uchar const _a[ 96 ],
135 : uchar const _b[ 96 ],
136 30033 : int big_endian ) {
137 : /* points a, b are unchecked per SIMD-0388 */
138 30033 : fd_bls12_381_g1aff_t a[1], b[1];
139 30033 : if( FD_UNLIKELY( fd_bls12_381_g1_frombytes_unchecked( a, _a, big_endian )==NULL ) ) {
140 0 : return -1;
141 0 : }
142 30033 : if( FD_UNLIKELY( fd_bls12_381_g1_frombytes_unchecked( b, _b, big_endian )==NULL ) ) {
143 0 : return -1;
144 0 : }
145 :
146 30033 : fd_bls12_381_g1_t r[1], p[1];
147 30033 : blst_p1_from_affine( p, a );
148 30033 : blst_p1_add_or_double_affine( r, p, b );
149 :
150 30033 : fd_bls12_381_g1_tobytes( _r, r, big_endian );
151 30033 : return 0;
152 30033 : }
153 :
154 : int
155 : fd_bls12_381_g1_sub_syscall( uchar _r[ 96 ],
156 : uchar const _a[ 96 ],
157 : uchar const _b[ 96 ],
158 30030 : int big_endian ) {
159 : /* points a, b are unchecked per SIMD-0388 */
160 30030 : fd_bls12_381_g1aff_t a[1], b[1];
161 30030 : if( FD_UNLIKELY( fd_bls12_381_g1_frombytes_unchecked( a, _a, big_endian )==NULL ) ) {
162 0 : return -1;
163 0 : }
164 30030 : if( FD_UNLIKELY( fd_bls12_381_g1_frombytes_unchecked( b, _b, big_endian )==NULL ) ) {
165 0 : return -1;
166 0 : }
167 :
168 30030 : fd_bls12_381_g1_t r[1], p[1];
169 30030 : blst_p1_from_affine( p, a );
170 30030 : blst_fp_cneg( &b->y, &b->y, 1 ); /* -b, it works also with b=0 */
171 30030 : blst_p1_add_or_double_affine( r, p, b );
172 :
173 30030 : fd_bls12_381_g1_tobytes( _r, r, big_endian );
174 30030 : return 0;
175 30030 : }
176 :
177 : int
178 : fd_bls12_381_g1_mul_syscall( uchar _r[ 96 ],
179 : uchar const _n[ 32 ],
180 : uchar const _a[ 96 ],
181 330 : int big_endian ) {
182 : /* point a, scalar n are validated per SIMD-0388 */
183 330 : fd_bls12_381_g1aff_t a[1];
184 330 : fd_bls12_381_scalar_t n[1];
185 330 : if( FD_UNLIKELY( fd_bls12_381_g1_frombytes( a, _a, big_endian )==NULL ) ) {
186 0 : return -1;
187 0 : }
188 330 : if( FD_UNLIKELY( fd_bls12_381_scalar_frombytes( n, _n, big_endian )==NULL ) ) {
189 0 : return -1;
190 0 : }
191 :
192 330 : fd_bls12_381_g1_t r[1], p[1];
193 330 : blst_p1_from_affine( p, a );
194 : /* https://github.com/filecoin-project/blstrs/blob/v0.7.1/src/g1.rs#L578-L580 */
195 330 : blst_p1_mult( r, p, n->b, 255 );
196 :
197 330 : fd_bls12_381_g1_tobytes( _r, r, big_endian );
198 330 : return 0;
199 330 : }
200 :
201 : /* G2 serde */
202 :
203 : typedef blst_p2_affine fd_bls12_381_g2aff_t;
204 : typedef blst_p2 fd_bls12_381_g2_t;
205 :
206 : static inline void
207 : fd_bls12_381_g2_bswap( uchar out[ 96*2 ], /* out can be in */
208 187383 : uchar const in [ 96*2 ] ) {
209 : /* copy into aligned memory */
210 187383 : ulong e[ 96*2/sizeof(ulong) ];
211 187383 : memcpy( e, in, 96*2 );
212 :
213 : /* bswap X, Y independently (96 bytes each) */
214 187383 : fd_ulong_n_bswap( e+00, 12 );
215 187383 : fd_ulong_n_bswap( e+12, 12 );
216 :
217 : /* copy to out */
218 187383 : memcpy( out, e, 96*2 );
219 187383 : }
220 :
221 : static inline uchar *
222 : fd_bls12_381_g2_tobytes( uchar out[ 96*2 ],
223 : fd_bls12_381_g2_t const * a,
224 60390 : int big_endian ) {
225 60390 : blst_p2_serialize( out, a );
226 60390 : if( !big_endian ) {
227 60345 : fd_bls12_381_g2_bswap( out, out );
228 60345 : }
229 60390 : return out;
230 60390 : }
231 :
232 : static inline fd_bls12_381_g2aff_t *
233 : fd_bls12_381_g2_frombytes_unchecked( fd_bls12_381_g2aff_t * r,
234 : uchar const _in[ 96*2 ],
235 124182 : int big_endian ) {
236 124182 : ulong be[ 96*2/sizeof(ulong) ];
237 124182 : uchar const * in = _in;
238 124182 : if( !big_endian ) {
239 124026 : fd_bls12_381_g2_bswap( (uchar *)be, _in );
240 124026 : in = (uchar *)be;
241 124026 : }
242 :
243 : /* Reject the point if the compressed or parity flag is set.
244 : https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/bls12-381/src/encoding.rs#L103-L106 */
245 124182 : if( FD_UNLIKELY( in[ 0 ] & 0xA0 ) ) {
246 3 : return NULL;
247 3 : }
248 :
249 124179 : if( FD_UNLIKELY( blst_p2_deserialize( r, in )!=BLST_SUCCESS ) ) {
250 18 : return NULL;
251 18 : }
252 124161 : return r;
253 124179 : }
254 :
255 : static inline fd_bls12_381_g2aff_t *
256 : fd_bls12_381_g2_frombytes( fd_bls12_381_g2aff_t * r,
257 : uchar const in[ 96*2 ],
258 4062 : int big_endian ) {
259 4062 : if( FD_UNLIKELY( !fd_bls12_381_g2_frombytes_unchecked( r, in, big_endian ) ) ) {
260 21 : return NULL;
261 21 : }
262 4041 : if( FD_UNLIKELY( !blst_p2_affine_in_g2( r ) ) ) {
263 6 : return NULL;
264 6 : }
265 4035 : return r;
266 4041 : }
267 :
268 : /* G2 syscalls */
269 :
270 : int
271 : fd_bls12_381_g2_decompress_syscall( uchar _r[ 96*2 ],
272 : uchar const _a[ 48*2 ],
273 3036 : int big_endian ) {
274 : /* blst expects input in big endian. if little endian, bswap. */
275 3036 : ulong be[ 48*2/sizeof(ulong) ];
276 3036 : uchar const * in = _a;
277 3036 : if( !big_endian ) {
278 3018 : in = (uchar *)be;
279 3018 : memcpy( be, _a, 48*2 );
280 3018 : fd_ulong_n_bswap( be, 6*2 );
281 3018 : }
282 :
283 : /* decompress and serialize */
284 3036 : fd_bls12_381_g2aff_t r[1];
285 3036 : if( FD_UNLIKELY( blst_p2_uncompress( r, in )!=BLST_SUCCESS ) ) {
286 6 : return -1;
287 6 : }
288 3030 : if( FD_UNLIKELY( !blst_p2_affine_in_g2( r ) ) ) {
289 6 : return -1;
290 6 : }
291 3024 : blst_p2_affine_serialize( _r, r );
292 :
293 : /* blst output is big endian. if we want little endian, bswap. */
294 3024 : if( !big_endian ) {
295 3012 : fd_bls12_381_g2_bswap( _r, _r );
296 3012 : }
297 3024 : return 0;
298 3030 : }
299 :
300 : int
301 : fd_bls12_381_g2_compress( uchar _r[ 48*2 ],
302 : uchar const _a[ 96*2 ],
303 24 : int big_endian ) {
304 24 : fd_bls12_381_g2aff_t a[1];
305 24 : if( FD_UNLIKELY( fd_bls12_381_g2_frombytes( a, _a, big_endian )==NULL ) ) {
306 12 : return -1;
307 12 : }
308 :
309 12 : blst_p2_affine_compress( _r, a );
310 :
311 : /* blst output is big endian. if we want little endian, bswap. */
312 12 : if( !big_endian ) {
313 6 : ulong le[ 48*2/sizeof(ulong) ];
314 6 : memcpy( le, _r, 48*2 );
315 6 : fd_ulong_n_bswap( le, 6*2 );
316 6 : memcpy( _r, le, 48*2 );
317 6 : }
318 12 : return 0;
319 24 : }
320 :
321 : int
322 : fd_bls12_381_g2_validate_syscall( uchar const _a[ 96*2 ],
323 3027 : int big_endian ) {
324 3027 : fd_bls12_381_g2aff_t a[1];
325 3027 : return !!fd_bls12_381_g2_frombytes( a, _a, big_endian );
326 3027 : }
327 :
328 : int
329 : fd_bls12_381_g2_add_syscall( uchar _r[ 96*2 ],
330 : uchar const _a[ 96*2 ],
331 : uchar const _b[ 96*2 ],
332 30030 : int big_endian ) {
333 : /* points a, b are unchecked per SIMD-0388 */
334 30030 : fd_bls12_381_g2aff_t a[1], b[1];
335 30030 : if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( a, _a, big_endian )==NULL ) ) {
336 0 : return -1;
337 0 : }
338 30030 : if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( b, _b, big_endian )==NULL ) ) {
339 0 : return -1;
340 0 : }
341 :
342 30030 : fd_bls12_381_g2_t r[1], p[1];
343 30030 : blst_p2_from_affine( p, a );
344 30030 : blst_p2_add_or_double_affine( r, p, b );
345 :
346 30030 : fd_bls12_381_g2_tobytes( _r, r, big_endian );
347 30030 : return 0;
348 30030 : }
349 :
350 : int
351 : fd_bls12_381_g2_sub_syscall( uchar _r[ 96*2 ],
352 : uchar const _a[ 96*2 ],
353 : uchar const _b[ 96*2 ],
354 30030 : int big_endian ) {
355 : /* points a, b are unchecked per SIMD-0388 */
356 30030 : fd_bls12_381_g2aff_t a[1], b[1];
357 30030 : if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( a, _a, big_endian )==NULL ) ) {
358 0 : return -1;
359 0 : }
360 30030 : if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( b, _b, big_endian )==NULL ) ) {
361 0 : return -1;
362 0 : }
363 :
364 30030 : fd_bls12_381_g2_t r[1], p[1];
365 30030 : blst_p2_from_affine( p, a );
366 30030 : blst_fp2_cneg( &b->y, &b->y, 1 ); /* -b, it works also with b=0 */
367 30030 : blst_p2_add_or_double_affine( r, p, b );
368 :
369 30030 : fd_bls12_381_g2_tobytes( _r, r, big_endian );
370 30030 : return 0;
371 30030 : }
372 :
373 : int
374 : fd_bls12_381_g2_mul_syscall( uchar _r[ 96*2 ],
375 : uchar const _n[ 32 ],
376 : uchar const _a[ 96*2 ],
377 330 : int big_endian ) {
378 : /* point a, scalar n are validated per SIMD-0388 */
379 330 : fd_bls12_381_g2aff_t a[1];
380 330 : fd_bls12_381_scalar_t n[1];
381 330 : if( FD_UNLIKELY( fd_bls12_381_g2_frombytes( a, _a, big_endian )==NULL ) ) {
382 0 : return -1;
383 0 : }
384 330 : if( FD_UNLIKELY( fd_bls12_381_scalar_frombytes( n, _n, big_endian )==NULL ) ) {
385 0 : return -1;
386 0 : }
387 :
388 330 : fd_bls12_381_g2_t r[1], p[1];
389 330 : blst_p2_from_affine( p, a );
390 : /* https://github.com/filecoin-project/blstrs/blob/v0.7.1/src/g2.rs#L545-L547 */
391 330 : blst_p2_mult( r, p, n->b, 255 );
392 :
393 330 : fd_bls12_381_g2_tobytes( _r, r, big_endian );
394 330 : return 0;
395 330 : }
396 :
397 : int
398 : fd_bls12_381_pairing_syscall( uchar _r[ 48*12 ],
399 : uchar const _a[], /* 96*n */
400 : uchar const _b[], /* 96*2*n */
401 : ulong const _n,
402 360 : int big_endian ) {
403 :
404 360 : if( FD_UNLIKELY( _n>FD_BLS12_381_PAIRING_BATCH_SZ ) ) {
405 0 : return -1;
406 0 : }
407 :
408 360 : fd_bls12_381_g1aff_t a[ FD_BLS12_381_PAIRING_BATCH_SZ ];
409 360 : fd_bls12_381_g2aff_t b[ FD_BLS12_381_PAIRING_BATCH_SZ ];
410 360 : fd_bls12_381_g1aff_t const * aptr[ FD_BLS12_381_PAIRING_BATCH_SZ ];
411 360 : fd_bls12_381_g2aff_t const * bptr[ FD_BLS12_381_PAIRING_BATCH_SZ ];
412 : /* skip pairs where either side is the point at infinity.
413 : this is important because blst otherwise produces an invalid result. */
414 360 : ulong m = 0UL;
415 1041 : for( ulong j=0; j<_n; j++ ) {
416 681 : fd_bls12_381_g1aff_t * aj = &a[ m ];
417 681 : fd_bls12_381_g2aff_t * bj = &b[ m ];
418 681 : if( FD_UNLIKELY( fd_bls12_381_g1_frombytes( aj, _a+96*j, big_endian )==NULL ) ) {
419 0 : return -1;
420 0 : }
421 681 : if( FD_UNLIKELY( fd_bls12_381_g2_frombytes( bj, _b+96*2*j, big_endian )==NULL ) ) {
422 0 : return -1;
423 0 : }
424 681 : if( FD_UNLIKELY( blst_p1_affine_is_inf( aj ) || blst_p2_affine_is_inf( bj ) ) ) {
425 24 : continue;
426 24 : }
427 : /* blst wants an array of pointers (not necessarily a compact array) */
428 657 : aptr[ m ] = aj;
429 657 : bptr[ m ] = bj;
430 657 : m++;
431 657 : }
432 :
433 360 : blst_fp12 r[1];
434 360 : memcpy( r, blst_fp12_one(), sizeof(blst_fp12) );
435 :
436 360 : if( FD_LIKELY ( m>0 ) ) {
437 333 : blst_miller_loop_n( r, bptr, aptr, m );
438 333 : blst_final_exp( r, r );
439 333 : }
440 :
441 360 : if( big_endian ) {
442 507 : for( ulong j=0; j<12; j++ ) {
443 468 : blst_bendian_from_fp( _r+48*(12-1-j), &r[ 0 ].fp6[ j/6 ].fp2[ (j/2)%3 ].fp[ j%2 ] );
444 468 : }
445 321 : } else {
446 4173 : for( ulong j=0; j<12; j++ ) {
447 3852 : blst_lendian_from_fp( _r+48*j, &r[ 0 ].fp6[ j/6 ].fp2[ (j/2)%3 ].fp[ j%2 ] );
448 3852 : }
449 321 : }
450 :
451 360 : return 0;
452 360 : }
453 :
454 : /* Proof of possession */
455 :
456 315 : #define FD_BLS_LITERAL(STR) ("" STR), (sizeof(STR)-1)
457 : #define FD_BLS_SIG_DOMAIN_H2P "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_POP_"
458 : #define FD_BLS_SIG_DOMAIN_POP "BLS_POP_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"
459 :
460 : /* fd_bls12_381_core_verify verifies a BLS signature in the mathematical
461 : sense, i.e. computes a pairing to check that the signature is correct.
462 : This is the core computation both for "real world" signatures and proofs
463 : of possession. In both cases, the difference between the math paper and
464 : the RFC implementation is an additional domain separator that's used
465 : in computing the hash to G2.
466 :
467 : See also:
468 : https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-06#name-coreverify
469 :
470 : We use a1, a2 for points in G1, b1, b2 for points in G2.
471 : We have to check that e( pk, H(msg) ) == e( g1, sig ), or equivalently
472 : e( pk, H(msg) ) * e( -g1, sig ) == 1.
473 :
474 : Replacing the variables we get:
475 : - a1 <- public_key, input needs to be decompressed in G1
476 : - b1 <- msg, input needs to be hashed to G2
477 : - a2 <- -g1, the const generator of G1, negated
478 : - b2 <- signature, input needs to be decompressed in G2
479 : */
480 : static inline int
481 : fd_bls12_381_core_verify( uchar const msg[], /* msg_sz */
482 : ulong msg_sz,
483 : uchar const signature[ 96 ],
484 : uchar const public_key[ 48 ],
485 : char const * domain,
486 315 : ulong domain_len ) {
487 315 : fd_bls12_381_g1aff_t a1[1]; /* a2 is const, we don't need a var */
488 315 : fd_bls12_381_g2aff_t b1[1], b2[1];
489 :
490 : /* decompress public_key into a1 and check that it's a valid point in G1 */
491 315 : if( FD_UNLIKELY( blst_p1_uncompress( a1, public_key )!=BLST_SUCCESS ) ) {
492 3 : return -1;
493 3 : }
494 312 : if( FD_UNLIKELY( !blst_p1_affine_in_g1( a1 ) ) ) {
495 0 : return -1;
496 0 : }
497 : /* https://github.com/anza-xyz/solana-sdk/blob/b66abfddd564aef5b4b82cf4e76381e96f2459f0/bls-signatures/src/pubkey/verify.rs#L120 */
498 312 : if( FD_UNLIKELY( blst_p1_affine_is_inf( a1 ) ) ) {
499 0 : return -1;
500 0 : }
501 :
502 : /* hash msg into b1. the check that it's a valid point in G2 is implicit/guaranteed */
503 312 : fd_bls12_381_g2_t _b1[1];
504 312 : blst_hash_to_g2( _b1, msg, msg_sz, (uchar const *)domain, domain_len, NULL, 0UL );
505 312 : blst_p2_to_affine( b1, _b1 );
506 :
507 : /* decompress signature into b2 and check that it's a valid point in G2 */
508 312 : if( FD_UNLIKELY( blst_p2_uncompress( b2, signature )!=BLST_SUCCESS ) ) {
509 3 : return -1;
510 3 : }
511 309 : if( FD_UNLIKELY( !blst_p2_affine_in_g2( b2 ) ) ) {
512 0 : return -1;
513 0 : }
514 :
515 : /* prepare pairing input: blst needs 2 arrays of pointers, and the result
516 : needs to be initialized to 1. */
517 309 : fd_bls12_381_g1aff_t const * aptr[ 2 ] = { a1, &BLS12_381_NEG_G1 };
518 309 : fd_bls12_381_g2aff_t const * bptr[ 2 ] = { b1, b2 };
519 309 : blst_fp12 r[1];
520 309 : memcpy( r, blst_fp12_one(), sizeof(blst_fp12) );
521 :
522 : /* compute the actual pairing and check that it's 1 */
523 309 : blst_miller_loop_n( r, bptr, aptr, 2 );
524 309 : if( FD_LIKELY( blst_fp12_finalverify( r, blst_fp12_one() ) ) ) {
525 306 : return 0; /* success */
526 306 : }
527 3 : return -1;
528 309 : }
529 :
530 : int
531 : fd_bls12_381_proof_of_possession_verify( uchar const msg[], /* msg_sz */
532 : ulong msg_sz,
533 : uchar const proof[ static 96 ],
534 321 : uchar const public_key[ static 48 ] ) {
535 : /* Agave supports the case of empty msg, where the public key is used
536 : instead (i.e. the plain RFC proof of possession). But that's not really
537 : used anywhere, and probably shouldn't be used for security reasons.
538 : In order to avoid accidental future changes, we prefer to not implement
539 : the case msg_sz==0 and instead explicitly throw an error.
540 : Since the public key must be part of the message, we check that
541 : msg_sz >= public key size, again to avoid accidental mistakes. */
542 321 : if( FD_UNLIKELY( msg_sz<48 ) ) {
543 6 : return -1;
544 6 : }
545 :
546 315 : return fd_bls12_381_core_verify( msg, msg_sz, proof, public_key, FD_BLS_LITERAL( FD_BLS_SIG_DOMAIN_POP ) );
547 321 : }
|