Line data Source code
1 : #include "./fd_bn254.h"
2 :
3 : /* G2 */
4 :
5 : /* COV: unlike g1, g2 operations are not exposed to users.
6 : So many edge cases and checks for zero are never triggered, e.g. by syscall tests. */
7 :
8 : static inline int
9 101337 : fd_bn254_g2_is_zero( fd_bn254_g2_t const * p ) {
10 101337 : return fd_bn254_fp2_is_zero( &p->Z );
11 101337 : }
12 :
13 : static inline int
14 : fd_bn254_g2_eq( fd_bn254_g2_t const * p,
15 735 : fd_bn254_g2_t const * q ) {
16 735 : if( fd_bn254_g2_is_zero( p ) ) {
17 0 : return fd_bn254_g2_is_zero( q );
18 0 : }
19 735 : if( fd_bn254_g2_is_zero( q ) ) {
20 0 : return 0;
21 0 : }
22 :
23 735 : fd_bn254_fp2_t pz2[1], qz2[1];
24 735 : fd_bn254_fp2_t l[1], r[1];
25 :
26 735 : fd_bn254_fp2_sqr( pz2, &p->Z );
27 735 : fd_bn254_fp2_sqr( qz2, &q->Z );
28 :
29 735 : fd_bn254_fp2_mul( l, &p->X, qz2 );
30 735 : fd_bn254_fp2_mul( r, &q->X, pz2 );
31 735 : if( !fd_bn254_fp2_eq( l, r ) ) {
32 0 : return 0;
33 0 : }
34 :
35 735 : fd_bn254_fp2_mul( l, &p->Y, qz2 );
36 735 : fd_bn254_fp2_mul( l, l, &q->Z );
37 735 : fd_bn254_fp2_mul( r, &q->Y, pz2 );
38 735 : fd_bn254_fp2_mul( r, r, &p->Z );
39 735 : return fd_bn254_fp2_eq( l, r );
40 735 : }
41 :
42 : static inline fd_bn254_g2_t *
43 : fd_bn254_g2_set( fd_bn254_g2_t * r,
44 1470 : fd_bn254_g2_t const * p ) {
45 1470 : fd_bn254_fp2_set( &r->X, &p->X );
46 1470 : fd_bn254_fp2_set( &r->Y, &p->Y );
47 1470 : fd_bn254_fp2_set( &r->Z, &p->Z );
48 1470 : return r;
49 1470 : }
50 :
51 : static inline fd_bn254_g2_t *
52 : fd_bn254_g2_neg( fd_bn254_g2_t * r,
53 735 : fd_bn254_g2_t const * p ) {
54 735 : fd_bn254_fp2_set( &r->X, &p->X );
55 735 : fd_bn254_fp2_neg( &r->Y, &p->Y );
56 735 : fd_bn254_fp2_set( &r->Z, &p->Z );
57 735 : return r;
58 735 : }
59 :
60 : static inline fd_bn254_g2_t *
61 0 : fd_bn254_g2_set_zero( fd_bn254_g2_t * r ) {
62 : // fd_bn254_fp2_set_zero( &r->X );
63 : // fd_bn254_fp2_set_zero( &r->Y );
64 0 : fd_bn254_fp2_set_zero( &r->Z );
65 0 : return r;
66 0 : }
67 :
68 : static inline fd_bn254_g2_t *
69 : fd_bn254_g2_frob( fd_bn254_g2_t * r,
70 2205 : fd_bn254_g2_t const * p ) {
71 2205 : fd_bn254_fp2_conj( &r->X, &p->X );
72 2205 : fd_bn254_fp2_mul ( &r->X, &r->X, &fd_bn254_const_frob_gamma1_mont[1] );
73 2205 : fd_bn254_fp2_conj( &r->Y, &p->Y );
74 2205 : fd_bn254_fp2_mul ( &r->Y, &r->Y, &fd_bn254_const_frob_gamma1_mont[2] );
75 2205 : fd_bn254_fp2_conj( &r->Z, &p->Z );
76 2205 : return r;
77 2205 : }
78 :
79 : static inline fd_bn254_g2_t *
80 : fd_bn254_g2_frob2( fd_bn254_g2_t * r,
81 1470 : fd_bn254_g2_t const * p ) {
82 : /* X */
83 1470 : fd_bn254_fp_mul( &r->X.el[0], &p->X.el[0], &fd_bn254_const_frob_gamma2_mont[1] );
84 1470 : fd_bn254_fp_mul( &r->X.el[1], &p->X.el[1], &fd_bn254_const_frob_gamma2_mont[1] );
85 : /* Y */
86 1470 : fd_bn254_fp_mul( &r->Y.el[0], &p->Y.el[0], &fd_bn254_const_frob_gamma2_mont[2] );
87 1470 : fd_bn254_fp_mul( &r->Y.el[1], &p->Y.el[1], &fd_bn254_const_frob_gamma2_mont[2] );
88 : /* Z=1 */
89 1470 : fd_bn254_fp2_set( &r->Z, &p->Z );
90 1470 : return r;
91 1470 : }
92 :
93 : /* fd_bn254_g2_dbl computes r = 2p.
94 : https://hyperelliptic.org/efd/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l */
95 : fd_bn254_g2_t *
96 : fd_bn254_g2_dbl( fd_bn254_g2_t * r,
97 46305 : fd_bn254_g2_t const * p ) {
98 : /* p==0, return 0 */
99 46305 : if( FD_UNLIKELY( fd_bn254_g2_is_zero( p ) ) ) {
100 0 : return fd_bn254_g2_set_zero( r );
101 0 : }
102 :
103 46305 : fd_bn254_fp2_t a[1], b[1], c[1];
104 46305 : fd_bn254_fp2_t d[1], e[1], f[1];
105 :
106 : /* A = X1^2 */
107 46305 : fd_bn254_fp2_sqr( a, &p->X );
108 : /* B = Y1^2 */
109 46305 : fd_bn254_fp2_sqr( b, &p->Y );
110 : /* C = B^2 */
111 46305 : fd_bn254_fp2_sqr( c, b );
112 : /* D = 2*((X1+B)^2-A-C)
113 : (X1+B)^2 = X1^2 + 2*X1*B + B^2
114 : D = 2*(X1^2 + 2*X1*B + B^2 - A - C)
115 : D = 2*(X1^2 + 2*X1*B + B^2 - X1^2 - B^2)
116 : ^ ^ ^ ^
117 : |---------------|-----| |
118 : |------------|
119 : These terms cancel each other out, and we're left with:
120 : D = 2*(2*X1*B) */
121 46305 : fd_bn254_fp2_mul( d, &p->X, b );
122 46305 : fd_bn254_fp2_add( d, d, d );
123 46305 : fd_bn254_fp2_add( d, d, d );
124 : /* E = 3*A */
125 46305 : fd_bn254_fp2_add( e, a, a );
126 46305 : fd_bn254_fp2_add( e, a, e );
127 : /* F = E^2 */
128 46305 : fd_bn254_fp2_sqr( f, e );
129 : /* X3 = F-2*D */
130 46305 : fd_bn254_fp2_add( &r->X, d, d );
131 46305 : fd_bn254_fp2_sub( &r->X, f, &r->X );
132 : /* Z3 = (Y1+Z1)^2-YY-ZZ
133 : note: compute Z3 before Y3 because it depends on p->Y,
134 : that might be overwritten if r==p. */
135 : /* Z3 = 2*Y1*Z1 */
136 46305 : fd_bn254_fp2_mul( &r->Z, &p->Y, &p->Z );
137 46305 : fd_bn254_fp2_add( &r->Z, &r->Z, &r->Z );
138 : /* Y3 = E*(D-X3)-8*C */
139 46305 : fd_bn254_fp2_sub( &r->Y, d, &r->X );
140 46305 : fd_bn254_fp2_mul( &r->Y, e, &r->Y );
141 46305 : fd_bn254_fp2_add( c, c, c ); /* 2*c */
142 46305 : fd_bn254_fp2_add( c, c, c ); /* 4*y */
143 46305 : fd_bn254_fp2_add( c, c, c ); /* 8*y */
144 46305 : fd_bn254_fp2_sub( &r->Y, &r->Y, c );
145 46305 : return r;
146 46305 : }
147 :
148 : /* fd_bn254_g2_add_mixed computes r = p + q, when q->Z==1.
149 : http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl */
150 : fd_bn254_g2_t *
151 : fd_bn254_g2_add_mixed( fd_bn254_g2_t * r,
152 : fd_bn254_g2_t const * p,
153 20580 : fd_bn254_g2_t const * q ) {
154 : /* p==0, return q */
155 20580 : if( FD_UNLIKELY( fd_bn254_g2_is_zero( p ) ) ) {
156 0 : return fd_bn254_g2_set( r, q );
157 0 : }
158 20580 : fd_bn254_fp2_t zz[1], u2[1], s2[1];
159 20580 : fd_bn254_fp2_t h[1], hh[1];
160 20580 : fd_bn254_fp2_t i[1], j[1];
161 20580 : fd_bn254_fp2_t rr[1], v[1];
162 : /* Z1Z1 = Z1^2 */
163 20580 : fd_bn254_fp2_sqr( zz, &p->Z );
164 : /* U2 = X2*Z1Z1 */
165 20580 : fd_bn254_fp2_mul( u2, &q->X, zz );
166 : /* S2 = Y2*Z1*Z1Z1 */
167 20580 : fd_bn254_fp2_mul( s2, &q->Y, &p->Z );
168 20580 : fd_bn254_fp2_mul( s2, s2, zz );
169 :
170 : /* if p==q, call fd_bn254_g2_dbl */
171 20580 : if( FD_UNLIKELY( fd_bn254_fp2_eq( u2, &p->X ) && fd_bn254_fp2_eq( s2, &p->Y ) ) ) {
172 0 : return fd_bn254_g2_dbl( r, p );
173 0 : }
174 :
175 : /* H = U2-X1 */
176 20580 : fd_bn254_fp2_sub( h, u2, &p->X );
177 : /* HH = H^2 */
178 20580 : fd_bn254_fp2_sqr( hh, h );
179 : /* I = 4*HH */
180 20580 : fd_bn254_fp2_add( i, hh, hh );
181 20580 : fd_bn254_fp2_add( i, i, i );
182 : /* J = H*I */
183 20580 : fd_bn254_fp2_mul( j, h, i );
184 : /* r = 2*(S2-Y1) */
185 20580 : fd_bn254_fp2_sub( rr, s2, &p->Y );
186 20580 : fd_bn254_fp2_add( rr, rr, rr );
187 : /* V = X1*I */
188 20580 : fd_bn254_fp2_mul( v, &p->X, i );
189 : /* X3 = r^2-J-2*V */
190 20580 : fd_bn254_fp2_sqr( &r->X, rr );
191 20580 : fd_bn254_fp2_sub( &r->X, &r->X, j );
192 20580 : fd_bn254_fp2_sub( &r->X, &r->X, v );
193 20580 : fd_bn254_fp2_sub( &r->X, &r->X, v );
194 : /* Y3 = r*(V-X3)-2*Y1*J
195 : note: i no longer used */
196 20580 : fd_bn254_fp2_mul( i, &p->Y, j ); /* i = Y1*J */
197 20580 : fd_bn254_fp2_add( i, i, i ); /* i = 2*Y1*J */
198 20580 : fd_bn254_fp2_sub( &r->Y, v, &r->X );
199 20580 : fd_bn254_fp2_mul( &r->Y, &r->Y, rr );
200 20580 : fd_bn254_fp2_sub( &r->Y, &r->Y, i );
201 : /* Z3 = (Z1+H)^2-Z1Z1-HH */
202 20580 : fd_bn254_fp2_add( &r->Z, &p->Z, h );
203 20580 : fd_bn254_fp2_sqr( &r->Z, &r->Z );
204 20580 : fd_bn254_fp2_sub( &r->Z, &r->Z, zz );
205 20580 : fd_bn254_fp2_sub( &r->Z, &r->Z, hh );
206 20580 : return r;
207 20580 : }
208 :
209 : /* fd_bn254_g2_add computes r = p + q.
210 : http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl */
211 : fd_bn254_g2_t *
212 : fd_bn254_g2_add( fd_bn254_g2_t * r,
213 : fd_bn254_g2_t const * p,
214 1470 : fd_bn254_g2_t const * q ) {
215 : /* p==0, return q */
216 1470 : if( FD_UNLIKELY( fd_bn254_g2_is_zero( p ) ) ) {
217 0 : return fd_bn254_g2_set( r, q );
218 0 : }
219 1470 : fd_bn254_fp2_t zz1[1], zz2[1];
220 1470 : fd_bn254_fp2_t u1[1], s1[1];
221 1470 : fd_bn254_fp2_t u2[1], s2[1];
222 1470 : fd_bn254_fp2_t h[1];
223 1470 : fd_bn254_fp2_t i[1], j[1];
224 1470 : fd_bn254_fp2_t rr[1], v[1];
225 : /* Z1Z1 = Z1^2 */
226 1470 : fd_bn254_fp2_sqr( zz1, &p->Z );
227 : /* Z2Z2 = Z2^2 */
228 1470 : fd_bn254_fp2_sqr( zz2, &q->Z );
229 : /* U1 = X1*Z2Z2 */
230 1470 : fd_bn254_fp2_mul( u1, &p->X, zz2 );
231 : /* U2 = X2*Z1Z1 */
232 1470 : fd_bn254_fp2_mul( u2, &q->X, zz1 );
233 : /* S1 = Y1*Z2*Z2Z2 */
234 1470 : fd_bn254_fp2_mul( s1, &p->Y, &q->Z );
235 1470 : fd_bn254_fp2_mul( s1, s1, zz2 );
236 : /* S2 = Y2*Z1*Z1Z1 */
237 1470 : fd_bn254_fp2_mul( s2, &q->Y, &p->Z );
238 1470 : fd_bn254_fp2_mul( s2, s2, zz1 );
239 :
240 : /* if p==q, call fd_bn254_g2_dbl */
241 : // if( FD_UNLIKELY( fd_bn254_fp2_eq( u2, &p->X ) && fd_bn254_fp2_eq( s2, &p->Y ) ) ) {
242 : // return fd_bn254_g2_dbl( r, p );
243 : // }
244 :
245 : /* H = U2-U1 */
246 1470 : fd_bn254_fp2_sub( h, u2, u1 );
247 : /* HH = (2*H)^2 */
248 1470 : fd_bn254_fp2_add( i, h, h );
249 1470 : fd_bn254_fp2_sqr( i, i );
250 : /* J = H*I */
251 1470 : fd_bn254_fp2_mul( j, h, i );
252 : /* r = 2*(S2-S1) */
253 1470 : fd_bn254_fp2_sub( rr, s2, s1 );
254 1470 : fd_bn254_fp2_add( rr, rr, rr );
255 : /* V = U1*I */
256 1470 : fd_bn254_fp2_mul( v, u1, i );
257 : /* X3 = r^2-J-2*V */
258 1470 : fd_bn254_fp2_sqr( &r->X, rr );
259 1470 : fd_bn254_fp2_sub( &r->X, &r->X, j );
260 1470 : fd_bn254_fp2_sub( &r->X, &r->X, v );
261 1470 : fd_bn254_fp2_sub( &r->X, &r->X, v );
262 : /* Y3 = r*(V-X3)-2*S1*J
263 : note: i no longer used */
264 1470 : fd_bn254_fp2_mul( i, s1, j ); /* i = S1*J */
265 1470 : fd_bn254_fp2_add( i, i, i ); /* i = 2*S1*J */
266 1470 : fd_bn254_fp2_sub( &r->Y, v, &r->X );
267 1470 : fd_bn254_fp2_mul( &r->Y, &r->Y, rr );
268 1470 : fd_bn254_fp2_sub( &r->Y, &r->Y, i );
269 : /* Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2)*H */
270 1470 : fd_bn254_fp2_add( &r->Z, &p->Z, &q->Z );
271 1470 : fd_bn254_fp2_sqr( &r->Z, &r->Z );
272 1470 : fd_bn254_fp2_sub( &r->Z, &r->Z, zz1 );
273 1470 : fd_bn254_fp2_sub( &r->Z, &r->Z, zz2 );
274 1470 : fd_bn254_fp2_mul( &r->Z, &r->Z, h );
275 1470 : return r;
276 1470 : }
277 :
278 : /* fd_bn254_g2_scalar_mul computes r = s * p.
279 : This assumes that p is affine, i.e. p->Z==1. */
280 : fd_bn254_g2_t *
281 : fd_bn254_g2_scalar_mul( fd_bn254_g2_t * r,
282 : fd_bn254_g2_t const * p,
283 735 : fd_bn254_scalar_t const * s ) {
284 : /* TODO: wNAF, GLV */
285 735 : int i = 255;
286 142590 : for( ; i>=0 && !fd_uint256_bit( s, i ); i-- ) ; /* do nothing, just i-- */
287 735 : if( FD_UNLIKELY( i<0 ) ) {
288 : /* COV: this only happens when the scalar is zero.
289 : Unlike g1, g2_scalar_mul is not exposed to users but only used internally,
290 : so scalar is never zero. */
291 0 : return fd_bn254_g2_set_zero( r );
292 0 : }
293 735 : fd_bn254_g2_set( r, p );
294 46305 : for( i--; i>=0; i-- ) {
295 45570 : fd_bn254_g2_dbl( r, r );
296 45570 : if( fd_uint256_bit( s, i ) ) {
297 19845 : fd_bn254_g2_add_mixed( r, r, p );
298 19845 : }
299 45570 : }
300 735 : return r;
301 735 : }
302 :
303 : /* fd_bn254_g2_frombytes_internal extracts (x, y) and performs basic checks.
304 : This is used by fd_bn254_g2_compress() and fd_bn254_g2_frombytes_check_subgroup(). */
305 : static inline fd_bn254_g2_t *
306 : fd_bn254_g2_frombytes_internal( fd_bn254_g2_t * p,
307 30777 : uchar const in[128] ) {
308 : /* Special case: all zeros => point at infinity */
309 30777 : const uchar zero[128] = { 0 };
310 30777 : if( FD_UNLIKELY( fd_memeq( in, zero, 128 ) ) ) {
311 0 : return fd_bn254_g2_set_zero( p );
312 0 : }
313 :
314 : /* Check x < p */
315 30777 : if( FD_UNLIKELY( !fd_bn254_fp2_frombytes_be_nm( &p->X, &in[0], NULL, NULL ) ) ) {
316 0 : return NULL;
317 0 : }
318 :
319 : /* Check flags and y < p */
320 30777 : int is_inf, is_neg;
321 30777 : if( FD_UNLIKELY( !fd_bn254_fp2_frombytes_be_nm( &p->Y, &in[64], &is_inf, &is_neg ) ) ) {
322 0 : return NULL;
323 0 : }
324 :
325 30777 : if( FD_UNLIKELY( is_inf ) ) {
326 0 : return fd_bn254_g2_set_zero( p );
327 0 : }
328 :
329 30777 : fd_bn254_fp2_set_one( &p->Z );
330 30777 : return p;
331 30777 : }
332 :
333 : /* fd_bn254_g2_frombytes_check_subgroup performs frombytes AND checks subgroup membership. */
334 : static inline fd_bn254_g2_t *
335 : fd_bn254_g2_frombytes_check_subgroup( fd_bn254_g2_t * p,
336 735 : uchar const in[128] ) {
337 735 : if( FD_UNLIKELY( !fd_bn254_g2_frombytes_internal( p, in ) ) ) {
338 0 : return NULL;
339 0 : }
340 735 : if( FD_UNLIKELY( fd_bn254_g2_is_zero( p ) ) ) {
341 0 : return p;
342 0 : }
343 :
344 735 : fd_bn254_fp2_to_mont( &p->X, &p->X );
345 735 : fd_bn254_fp2_to_mont( &p->Y, &p->Y );
346 735 : fd_bn254_fp2_set_one( &p->Z );
347 :
348 : /* Check that y^2 = x^3 + b */
349 735 : fd_bn254_fp2_t y2[1], x3b[1];
350 735 : fd_bn254_fp2_sqr( y2, &p->Y );
351 735 : fd_bn254_fp2_sqr( x3b, &p->X );
352 735 : fd_bn254_fp2_mul( x3b, x3b, &p->X );
353 735 : fd_bn254_fp2_add( x3b, x3b, fd_bn254_const_twist_b_mont );
354 735 : if( FD_UNLIKELY( !fd_bn254_fp2_eq( y2, x3b ) ) ) {
355 0 : return NULL;
356 0 : }
357 :
358 : /* G2 does NOT have prime order, so we have to check group membership. */
359 :
360 : /* We use the fast subgroup membership check, that requires a single 64-bit scalar mul.
361 : https://eprint.iacr.org/2022/348, Sec 3.1.
362 : [r]P == 0 <==> [x+1]P + ψ([x]P) + ψ²([x]P) = ψ³([2x]P)
363 : See also: https://github.com/Consensys/gnark-crypto/blob/v0.12.1/ecc/bn254/g2.go#L404
364 :
365 : For reference, the followings also work:
366 :
367 : 1) very slow: 256-bit scalar mul
368 :
369 : fd_bn254_g2_t r[1];
370 : fd_bn254_g2_scalar_mul( r, p, fd_bn254_const_r );
371 : if( !fd_bn254_g2_is_zero( r ) ) return NULL;
372 :
373 : 2) slow: 128-bit scalar mul
374 :
375 : fd_bn254_g2_t a[1], b[1];
376 : const fd_bn254_scalar_t six_x_sqr[1] = {{{ 0xf83e9682e87cfd46, 0x6f4d8248eeb859fb, 0x0, 0x0, }}};
377 : fd_bn254_g2_scalar_mul( a, p, six_x_sqr );
378 : fd_bn254_g2_frob( b, p );
379 : if( !fd_bn254_g2_eq( a, b ) ) return NULL; */
380 :
381 735 : fd_bn254_g2_t xp[1], l[1], psi[1], r[1];
382 735 : fd_bn254_g2_scalar_mul( xp, p, fd_bn254_const_x ); /* 64-bit */
383 735 : fd_bn254_g2_add_mixed( l, xp, p );
384 :
385 735 : fd_bn254_g2_frob( psi, xp );
386 735 : fd_bn254_g2_add( l, l, psi );
387 :
388 735 : fd_bn254_g2_frob2( psi, xp ); /* faster than frob( psi, psi ) */
389 735 : fd_bn254_g2_add( l, l, psi );
390 :
391 735 : fd_bn254_g2_frob( psi, psi );
392 735 : fd_bn254_g2_dbl( r, psi );
393 735 : if( FD_UNLIKELY( !fd_bn254_g2_eq( l, r ) ) ) {
394 0 : return NULL;
395 0 : }
396 :
397 735 : return p;
398 735 : }
|