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 3033 : int big_endian ) {
99 : /* blst expects input in big endian. if little endian, bswap. */
100 3033 : ulong be[ 48/sizeof(ulong) ];
101 3033 : uchar const * in = _a;
102 3033 : 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 3033 : fd_bls12_381_g1aff_t r[1];
110 3033 : if( FD_UNLIKELY( blst_p1_uncompress( r, in )!=BLST_SUCCESS ) ) {
111 6 : return -1;
112 6 : }
113 3027 : if( FD_UNLIKELY( !blst_p1_affine_in_g1( r ) ) ) {
114 6 : return -1;
115 6 : }
116 3021 : blst_p1_affine_serialize( _r, r );
117 :
118 : /* blst output is big endian. if we want little endian, bswap. */
119 3021 : if( !big_endian ) {
120 3012 : fd_bls12_381_g1_bswap( _r, _r );
121 3012 : }
122 3021 : return 0;
123 3027 : }
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 187371 : uchar const in [ 96*2 ] ) {
209 : /* copy into aligned memory */
210 187371 : ulong e[ 96*2/sizeof(ulong) ];
211 187371 : memcpy( e, in, 96*2 );
212 :
213 : /* bswap X, Y independently (96 bytes each) */
214 187371 : fd_ulong_n_bswap( e+00, 12 );
215 187371 : fd_ulong_n_bswap( e+12, 12 );
216 :
217 : /* copy to out */
218 187371 : memcpy( out, e, 96*2 );
219 187371 : }
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 124158 : int big_endian ) {
236 124158 : ulong be[ 96*2/sizeof(ulong) ];
237 124158 : uchar const * in = _in;
238 124158 : if( !big_endian ) {
239 124014 : fd_bls12_381_g2_bswap( (uchar *)be, _in );
240 124014 : in = (uchar *)be;
241 124014 : }
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 124158 : if( FD_UNLIKELY( in[ 0 ] & 0xA0 ) ) {
246 3 : return NULL;
247 3 : }
248 :
249 124155 : if( FD_UNLIKELY( blst_p2_deserialize( r, in )!=BLST_SUCCESS ) ) {
250 12 : return NULL;
251 12 : }
252 124143 : return r;
253 124155 : }
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 4038 : int big_endian ) {
259 4038 : if( FD_UNLIKELY( !fd_bls12_381_g2_frombytes_unchecked( r, in, big_endian ) ) ) {
260 15 : return NULL;
261 15 : }
262 4023 : if( FD_UNLIKELY( !blst_p2_affine_in_g2( r ) ) ) {
263 0 : return NULL;
264 0 : }
265 4023 : return r;
266 4023 : }
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 3033 : int big_endian ) {
274 : /* blst expects input in big endian. if little endian, bswap. */
275 3033 : ulong be[ 48*2/sizeof(ulong) ];
276 3033 : uchar const * in = _a;
277 3033 : 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 3033 : fd_bls12_381_g2aff_t r[1];
285 3033 : if( FD_UNLIKELY( blst_p2_uncompress( r, in )!=BLST_SUCCESS ) ) {
286 6 : return -1;
287 6 : }
288 3027 : if( FD_UNLIKELY( !blst_p2_affine_in_g2( r ) ) ) {
289 6 : return -1;
290 6 : }
291 3021 : blst_p2_affine_serialize( _r, r );
292 :
293 : /* blst output is big endian. if we want little endian, bswap. */
294 3021 : if( !big_endian ) {
295 3012 : fd_bls12_381_g2_bswap( _r, _r );
296 3012 : }
297 3021 : return 0;
298 3027 : }
299 :
300 : int
301 : fd_bls12_381_g2_validate_syscall( uchar const _a[ 96*2 ],
302 3027 : int big_endian ) {
303 3027 : fd_bls12_381_g2aff_t a[1];
304 3027 : return !!fd_bls12_381_g2_frombytes( a, _a, big_endian );
305 3027 : }
306 :
307 : int
308 : fd_bls12_381_g2_add_syscall( uchar _r[ 96*2 ],
309 : uchar const _a[ 96*2 ],
310 : uchar const _b[ 96*2 ],
311 30030 : int big_endian ) {
312 : /* points a, b are unchecked per SIMD-0388 */
313 30030 : fd_bls12_381_g2aff_t a[1], b[1];
314 30030 : if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( a, _a, big_endian )==NULL ) ) {
315 0 : return -1;
316 0 : }
317 30030 : if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( b, _b, big_endian )==NULL ) ) {
318 0 : return -1;
319 0 : }
320 :
321 30030 : fd_bls12_381_g2_t r[1], p[1];
322 30030 : blst_p2_from_affine( p, a );
323 30030 : blst_p2_add_or_double_affine( r, p, b );
324 :
325 30030 : fd_bls12_381_g2_tobytes( _r, r, big_endian );
326 30030 : return 0;
327 30030 : }
328 :
329 : int
330 : fd_bls12_381_g2_sub_syscall( uchar _r[ 96*2 ],
331 : uchar const _a[ 96*2 ],
332 : uchar const _b[ 96*2 ],
333 30030 : int big_endian ) {
334 : /* points a, b are unchecked per SIMD-0388 */
335 30030 : fd_bls12_381_g2aff_t a[1], b[1];
336 30030 : if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( a, _a, big_endian )==NULL ) ) {
337 0 : return -1;
338 0 : }
339 30030 : if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( b, _b, big_endian )==NULL ) ) {
340 0 : return -1;
341 0 : }
342 :
343 30030 : fd_bls12_381_g2_t r[1], p[1];
344 30030 : blst_p2_from_affine( p, a );
345 30030 : blst_fp2_cneg( &b->y, &b->y, 1 ); /* -b, it works also with b=0 */
346 30030 : blst_p2_add_or_double_affine( r, p, b );
347 :
348 30030 : fd_bls12_381_g2_tobytes( _r, r, big_endian );
349 30030 : return 0;
350 30030 : }
351 :
352 : int
353 : fd_bls12_381_g2_mul_syscall( uchar _r[ 96*2 ],
354 : uchar const _n[ 32 ],
355 : uchar const _a[ 96*2 ],
356 330 : int big_endian ) {
357 : /* point a, scalar n are validated per SIMD-0388 */
358 330 : fd_bls12_381_g2aff_t a[1];
359 330 : fd_bls12_381_scalar_t n[1];
360 330 : if( FD_UNLIKELY( fd_bls12_381_g2_frombytes( a, _a, big_endian )==NULL ) ) {
361 0 : return -1;
362 0 : }
363 330 : if( FD_UNLIKELY( fd_bls12_381_scalar_frombytes( n, _n, big_endian )==NULL ) ) {
364 0 : return -1;
365 0 : }
366 :
367 330 : fd_bls12_381_g2_t r[1], p[1];
368 330 : blst_p2_from_affine( p, a );
369 : /* https://github.com/filecoin-project/blstrs/blob/v0.7.1/src/g2.rs#L545-L547 */
370 330 : blst_p2_mult( r, p, n->b, 255 );
371 :
372 330 : fd_bls12_381_g2_tobytes( _r, r, big_endian );
373 330 : return 0;
374 330 : }
375 :
376 : int
377 : fd_bls12_381_pairing_syscall( uchar _r[ 48*12 ],
378 : uchar const _a[], /* 96*n */
379 : uchar const _b[], /* 96*2*n */
380 : ulong const _n,
381 360 : int big_endian ) {
382 :
383 360 : if( FD_UNLIKELY( _n>FD_BLS12_381_PAIRING_BATCH_SZ ) ) {
384 0 : return -1;
385 0 : }
386 :
387 360 : fd_bls12_381_g1aff_t a[ FD_BLS12_381_PAIRING_BATCH_SZ ];
388 360 : fd_bls12_381_g2aff_t b[ FD_BLS12_381_PAIRING_BATCH_SZ ];
389 360 : fd_bls12_381_g1aff_t const * aptr[ FD_BLS12_381_PAIRING_BATCH_SZ ];
390 360 : fd_bls12_381_g2aff_t const * bptr[ FD_BLS12_381_PAIRING_BATCH_SZ ];
391 : /* skip pairs where either side is the point at infinity.
392 : this is important because blst otherwise produces an invalid result. */
393 360 : ulong m = 0UL;
394 1041 : for( ulong j=0; j<_n; j++ ) {
395 681 : fd_bls12_381_g1aff_t * aj = &a[ m ];
396 681 : fd_bls12_381_g2aff_t * bj = &b[ m ];
397 681 : if( FD_UNLIKELY( fd_bls12_381_g1_frombytes( aj, _a+96*j, big_endian )==NULL ) ) {
398 0 : return -1;
399 0 : }
400 681 : if( FD_UNLIKELY( fd_bls12_381_g2_frombytes( bj, _b+96*2*j, big_endian )==NULL ) ) {
401 0 : return -1;
402 0 : }
403 681 : if( FD_UNLIKELY( blst_p1_affine_is_inf( aj ) || blst_p2_affine_is_inf( bj ) ) ) {
404 24 : continue;
405 24 : }
406 : /* blst wants an array of pointers (not necessarily a compact array) */
407 657 : aptr[ m ] = aj;
408 657 : bptr[ m ] = bj;
409 657 : m++;
410 657 : }
411 :
412 360 : blst_fp12 r[1];
413 360 : memcpy( r, blst_fp12_one(), sizeof(blst_fp12) );
414 :
415 360 : if( FD_LIKELY ( m>0 ) ) {
416 333 : blst_miller_loop_n( r, bptr, aptr, m );
417 333 : blst_final_exp( r, r );
418 333 : }
419 :
420 360 : if( big_endian ) {
421 507 : for( ulong j=0; j<12; j++ ) {
422 468 : blst_bendian_from_fp( _r+48*(12-1-j), &r[ 0 ].fp6[ j/6 ].fp2[ (j/2)%3 ].fp[ j%2 ] );
423 468 : }
424 321 : } else {
425 4173 : for( ulong j=0; j<12; j++ ) {
426 3852 : blst_lendian_from_fp( _r+48*j, &r[ 0 ].fp6[ j/6 ].fp2[ (j/2)%3 ].fp[ j%2 ] );
427 3852 : }
428 321 : }
429 :
430 360 : return 0;
431 360 : }
432 :
433 : /* Proof of possession */
434 :
435 315 : #define FD_BLS_LITERAL(STR) ("" STR), (sizeof(STR)-1)
436 : #define FD_BLS_SIG_DOMAIN_H2P "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_POP_"
437 : #define FD_BLS_SIG_DOMAIN_POP "BLS_POP_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"
438 :
439 : /* fd_bls12_381_core_verify verifies a BLS signature in the mathematical
440 : sense, i.e. computes a pairing to check that the signature is correct.
441 : This is the core computation both for "real world" signatures and proofs
442 : of possession. In both cases, the difference between the math paper and
443 : the RFC implementation is an additional domain separator that's used
444 : in computing the hash to G2.
445 :
446 : See also:
447 : https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-06#name-coreverify
448 :
449 : We use a1, a2 for points in G1, b1, b2 for points in G2.
450 : We have to check that e( pk, H(msg) ) == e( g1, sig ), or equivalently
451 : e( pk, H(msg) ) * e( -g1, sig ) == 1.
452 :
453 : Replacing the variables we get:
454 : - a1 <- public_key, input needs to be decompressed in G1
455 : - b1 <- msg, input needs to be hashed to G2
456 : - a2 <- -g1, the const generator of G1, negated
457 : - b2 <- signature, input needs to be decompressed in G2
458 : */
459 : static inline int
460 : fd_bls12_381_core_verify( uchar const msg[], /* msg_sz */
461 : ulong msg_sz,
462 : uchar const signature[ 96 ],
463 : uchar const public_key[ 48 ],
464 : char const * domain,
465 315 : ulong domain_len ) {
466 315 : fd_bls12_381_g1aff_t a1[1]; /* a2 is const, we don't need a var */
467 315 : fd_bls12_381_g2aff_t b1[1], b2[1];
468 :
469 : /* decompress public_key into a1 and check that it's a valid point in G1 */
470 315 : if( FD_UNLIKELY( blst_p1_uncompress( a1, public_key )!=BLST_SUCCESS ) ) {
471 3 : return -1;
472 3 : }
473 312 : if( FD_UNLIKELY( !blst_p1_affine_in_g1( a1 ) ) ) {
474 0 : return -1;
475 0 : }
476 : /* https://github.com/anza-xyz/solana-sdk/blob/b66abfddd564aef5b4b82cf4e76381e96f2459f0/bls-signatures/src/pubkey/verify.rs#L120 */
477 312 : if( FD_UNLIKELY( blst_p1_affine_is_inf( a1 ) ) ) {
478 0 : return -1;
479 0 : }
480 :
481 : /* hash msg into b1. the check that it's a valid point in G2 is implicit/guaranteed */
482 312 : fd_bls12_381_g2_t _b1[1];
483 312 : blst_hash_to_g2( _b1, msg, msg_sz, (uchar const *)domain, domain_len, NULL, 0UL );
484 312 : blst_p2_to_affine( b1, _b1 );
485 :
486 : /* decompress signature into b2 and check that it's a valid point in G2 */
487 312 : if( FD_UNLIKELY( blst_p2_uncompress( b2, signature )!=BLST_SUCCESS ) ) {
488 3 : return -1;
489 3 : }
490 309 : if( FD_UNLIKELY( !blst_p2_affine_in_g2( b2 ) ) ) {
491 0 : return -1;
492 0 : }
493 :
494 : /* prepare pairing input: blst needs 2 arrays of pointers, and the result
495 : needs to be initialized to 1. */
496 309 : fd_bls12_381_g1aff_t const * aptr[ 2 ] = { a1, &BLS12_381_NEG_G1 };
497 309 : fd_bls12_381_g2aff_t const * bptr[ 2 ] = { b1, b2 };
498 309 : blst_fp12 r[1];
499 309 : memcpy( r, blst_fp12_one(), sizeof(blst_fp12) );
500 :
501 : /* compute the actual pairing and check that it's 1 */
502 309 : blst_miller_loop_n( r, bptr, aptr, 2 );
503 309 : if( FD_LIKELY( blst_fp12_finalverify( r, blst_fp12_one() ) ) ) {
504 306 : return 0; /* success */
505 306 : }
506 3 : return -1;
507 309 : }
508 :
509 : int
510 : fd_bls12_381_proof_of_possession_verify( uchar const msg[], /* msg_sz */
511 : ulong msg_sz,
512 : uchar const proof[ static 96 ],
513 321 : uchar const public_key[ static 48 ] ) {
514 : /* Agave supports the case of empty msg, where the public key is used
515 : instead (i.e. the plain RFC proof of possession). But that's not really
516 : used anywhere, and probably shouldn't be used for security reasons.
517 : In order to avoid accidental future changes, we prefer to not implement
518 : the case msg_sz==0 and instead explicitly throw an error.
519 : Since the public key must be part of the message, we check that
520 : msg_sz >= public key size, again to avoid accidental mistakes. */
521 321 : if( FD_UNLIKELY( msg_sz<48 ) ) {
522 6 : return -1;
523 6 : }
524 :
525 315 : return fd_bls12_381_core_verify( msg, msg_sz, proof, public_key, FD_BLS_LITERAL( FD_BLS_SIG_DOMAIN_POP ) );
526 321 : }
|