Line data Source code
1 : #ifndef HEADER_fd_src_ballet_bn254_fd_bn254_field_inl_h
2 : #define HEADER_fd_src_ballet_bn254_fd_bn254_field_inl_h
3 :
4 : /* Shared static-inline Fp/Fp2/Fp6/Fp12 ops for the bn254 TUs.
5 : Do not include outside src/ballet/bn254.
6 : The additive Fp2 ops are force-inlined into every caller. fp2_mul,
7 : fp2_sqr, fp2_inv and fp6_mul are kept out of line, one copy per TU:
8 : inlining those bloats their callers enough to cost both compile time
9 : and runtime. */
10 :
11 : #include "./fd_bn254_internal.h"
12 : #include "../../third_party/fiat-crypto/bn254_64.c"
13 : #if FD_HAS_S2NBIGNUM
14 : #include "../../third_party/s2n-bignum/include/s2n-bignum.h"
15 : #endif
16 : /* Fp = base field */
17 :
18 305886 : #define FLAG_INF ((uchar)(1 << 6))
19 305751 : #define FLAG_NEG ((uchar)(1 << 7))
20 245685 : #define FLAG_MASK 0x3F
21 :
22 : /* Consts defined in fd_bn254_field.c */
23 : extern const fd_bn254_fp_t fd_bn254_const_zero [1];
24 : extern const fd_bn254_fp_t fd_bn254_const_one [1];
25 : extern const fd_bn254_fp_t fd_bn254_const_rr [1];
26 : extern const fd_bn254_fp_t fd_bn254_const_p [1];
27 : extern const fd_bn254_scalar_t fd_bn254_const_x [1];
28 : extern const fd_bn254_fp_t fd_bn254_const_b_mont [1];
29 : extern const fd_bn254_fp_t fd_bn254_const_p_minus_one_mont[1];
30 : extern const fd_bn254_fp_t fd_bn254_const_p_minus_one_half[1];
31 : extern const fd_uint256_t fd_bn254_const_sqrt_exp [1];
32 :
33 : /* Consts defined in fd_bn254_field_ext.c */
34 : extern const fd_bn254_fp2_t fd_bn254_const_twist_b_mont [1];
35 : extern const fd_bn254_fp2_t fd_bn254_const_frob_gamma1_mont[5];
36 : extern const fd_bn254_fp_t fd_bn254_const_frob_gamma2_mont[5];
37 :
38 : /* const 1/p for CIOS mul */
39 : static const ulong fd_bn254_const_p_inv = 0x87D20782E4866389UL;
40 :
41 : static inline int
42 93372 : fd_bn254_fp_is_neg_nm( fd_bn254_fp_t * x ) {
43 93372 : return fd_uint256_cmp( x, fd_bn254_const_p_minus_one_half ) > 0;
44 93372 : }
45 :
46 : static inline fd_bn254_fp_t *
47 : fd_bn254_fp_frombytes_nm( fd_bn254_fp_t * r,
48 : uchar const buf[32],
49 : int big_endian,
50 : int * is_inf,
51 643935 : int * is_neg ) {
52 : /* Flags (optional) */
53 643935 : if( is_inf != NULL /* && is_neg != NULL */ ) {
54 245685 : *is_inf = !!(buf[ big_endian ? 0 : 31 ] & FLAG_INF);
55 245685 : *is_neg = !!(buf[ big_endian ? 0 : 31 ] & FLAG_NEG);
56 : /* If both flags are set (bit 6, 7), return error.
57 : https://github.com/arkworks-rs/algebra/blob/v0.4.2/ec/src/models/short_weierstrass/serialization_flags.rs#L75 */
58 245685 : if( FD_UNLIKELY( *is_inf && *is_neg ) ) {
59 0 : return NULL;
60 0 : }
61 245685 : }
62 :
63 643935 : fd_memcpy( r, buf, 32 );
64 643935 : if( FD_BIG_ENDIAN_LIKELY( big_endian ) ) {
65 1500 : fd_uint256_bswap( r, r );
66 1500 : }
67 643935 : if( is_inf != NULL ) {
68 245685 : r->buf[ 31 ] &= FLAG_MASK;
69 245685 : }
70 :
71 : /* Field element */
72 643935 : if( FD_UNLIKELY( fd_uint256_cmp( r, fd_bn254_const_p ) >= 0 ) ) {
73 0 : return NULL;
74 0 : }
75 643935 : return r;
76 643935 : }
77 :
78 : static inline uchar *
79 : fd_bn254_fp_tobytes_nm( uchar buf[32],
80 : fd_bn254_fp_t * a,
81 404511 : int big_endian ) {
82 404511 : if( FD_BIG_ENDIAN_LIKELY( big_endian ) ) {
83 612 : fd_uint256_bswap( a, a );
84 612 : }
85 404511 : fd_memcpy( buf, a, 32 );
86 404511 : return buf;
87 404511 : }
88 :
89 : static inline int
90 : fd_bn254_fp_eq( fd_bn254_fp_t const * r,
91 2783226 : fd_bn254_fp_t const * a ) {
92 2783226 : return fd_uint256_eq( r, a );
93 2783226 : }
94 :
95 : static inline fd_bn254_fp_t *
96 : fd_bn254_fp_neg_nm( fd_bn254_fp_t * r,
97 6129 : fd_bn254_fp_t const * a ) {
98 6129 : if( FD_UNLIKELY( fd_bn254_fp_is_zero( a ) ) ) {
99 0 : return fd_bn254_fp_set_zero( r );
100 0 : }
101 : /* compute p-a */
102 30645 : for( ulong i=0, cy=0; i<4; i++ ) {
103 24516 : ulong p = fd_bn254_const_p->limbs[i];
104 24516 : ulong b = a->limbs[i];
105 24516 : b += cy;
106 24516 : cy = (b < cy);
107 24516 : cy += (p < b);
108 24516 : r->limbs[i] = p - b;
109 24516 : }
110 6129 : return r;
111 6129 : }
112 :
113 : static inline fd_bn254_fp_t *
114 : fd_bn254_fp_set( fd_bn254_fp_t * r,
115 5021253 : fd_bn254_fp_t const * a ) {
116 5021253 : r->limbs[0] = a->limbs[0];
117 5021253 : r->limbs[1] = a->limbs[1];
118 5021253 : r->limbs[2] = a->limbs[2];
119 5021253 : r->limbs[3] = a->limbs[3];
120 5021253 : return r;
121 5021253 : }
122 :
123 : /* r = a + b mod p, output in [0, p). */
124 : INLINE fd_bn254_fp_t *
125 : fd_bn254_fp_add( fd_bn254_fp_t * r,
126 : fd_bn254_fp_t const * a,
127 76096932 : fd_bn254_fp_t const * b ) {
128 25365644 : #if FD_HAS_X86 && defined(__ADX__)
129 : /* t = a + b (a,b < p < 2^254 so no carry out of 254 bits)
130 : then r = min(t, t - p) via a branchless borrow-select.
131 : This ends up being a shorter dependency chain than fiat's wide-add
132 : + cmov strategy. */
133 25365644 : ulong t0,t1,t2,t3, s0,s1,s2,s3;
134 25365644 : int c = 0;
135 25365644 : fd_ulong_add_carry( &t0, &c, a->limbs[0], b->limbs[0], c );
136 25365644 : fd_ulong_add_carry( &t1, &c, a->limbs[1], b->limbs[1], c );
137 25365644 : fd_ulong_add_carry( &t2, &c, a->limbs[2], b->limbs[2], c );
138 25365644 : fd_ulong_add_carry( &t3, &c, a->limbs[3], b->limbs[3], c );
139 25365644 : int br = 0;
140 25365644 : fd_ulong_sub_borrow( &s0, &br, t0, fd_bn254_const_p->limbs[0], br );
141 25365644 : fd_ulong_sub_borrow( &s1, &br, t1, fd_bn254_const_p->limbs[1], br );
142 25365644 : fd_ulong_sub_borrow( &s2, &br, t2, fd_bn254_const_p->limbs[2], br );
143 25365644 : fd_ulong_sub_borrow( &s3, &br, t3, fd_bn254_const_p->limbs[3], br );
144 :
145 25365644 : r->limbs[0] = br ? t0 : s0;
146 25365644 : r->limbs[1] = br ? t1 : s1;
147 25365644 : r->limbs[2] = br ? t2 : s2;
148 25365644 : r->limbs[3] = br ? t3 : s3;
149 25365644 : return r;
150 : #else
151 50731288 : fiat_bn254_add( r->limbs, a->limbs, b->limbs );
152 50731288 : return r;
153 50731288 : #endif
154 76096932 : }
155 :
156 : /* r = a + b, output in [0, 2p).
157 : Safe only if the result feeds into a multiplication, but should not
158 : be fed into fp_sub, fp_neg, fp_eq, frombytes, halve, etc. */
159 : INLINE fd_bn254_fp_t *
160 : fd_bn254_fp_add_lazy( fd_bn254_fp_t * r,
161 : fd_bn254_fp_t const * a,
162 9406389 : fd_bn254_fp_t const * b ) {
163 9406389 : #if FD_HAS_X86
164 9406389 : int c = 0;
165 9406389 : fd_ulong_add_carry( &r->limbs[0], &c, a->limbs[0], b->limbs[0], c );
166 9406389 : fd_ulong_add_carry( &r->limbs[1], &c, a->limbs[1], b->limbs[1], c );
167 9406389 : fd_ulong_add_carry( &r->limbs[2], &c, a->limbs[2], b->limbs[2], c );
168 9406389 : fd_ulong_add_carry( &r->limbs[3], &c, a->limbs[3], b->limbs[3], c );
169 9406389 : (void)c; /* p < 2^254 so c is always 0 for a, b < 2p */
170 9406389 : return r;
171 : #else
172 : /* We find no performance improvement on non-x86 targets, so we
173 : fallback to the original fp_add. */
174 : return fd_bn254_fp_add( r, a, b );
175 : #endif
176 9406389 : }
177 :
178 : INLINE fd_bn254_fp_t *
179 : fd_bn254_fp_sub( fd_bn254_fp_t * r,
180 : fd_bn254_fp_t const * a,
181 57513741 : fd_bn254_fp_t const * b ) {
182 19171247 : #if FD_HAS_X86 && defined(__ADX__)
183 19171247 : ulong t0,t1,t2,t3;
184 19171247 : int br = 0;
185 19171247 : fd_ulong_sub_borrow( &t0, &br, a->limbs[0], b->limbs[0], br );
186 19171247 : fd_ulong_sub_borrow( &t1, &br, a->limbs[1], b->limbs[1], br );
187 19171247 : fd_ulong_sub_borrow( &t2, &br, a->limbs[2], b->limbs[2], br );
188 19171247 : fd_ulong_sub_borrow( &t3, &br, a->limbs[3], b->limbs[3], br );
189 19171247 : ulong mask = (ulong)0 - (ulong)br; /* all-ones if borrow */
190 19171247 : int c = 0;
191 19171247 : fd_ulong_add_carry( &t0, &c, t0, mask & fd_bn254_const_p->limbs[0], c );
192 19171247 : fd_ulong_add_carry( &t1, &c, t1, mask & fd_bn254_const_p->limbs[1], c );
193 19171247 : fd_ulong_add_carry( &t2, &c, t2, mask & fd_bn254_const_p->limbs[2], c );
194 19171247 : fd_ulong_add_carry( &t3, &c, t3, mask & fd_bn254_const_p->limbs[3], c );
195 :
196 19171247 : r->limbs[0] = t0;
197 19171247 : r->limbs[1] = t1;
198 19171247 : r->limbs[2] = t2;
199 19171247 : r->limbs[3] = t3;
200 19171247 : return r;
201 : #else
202 38342494 : fiat_bn254_sub( r->limbs, a->limbs, b->limbs );
203 38342494 : return r;
204 38342494 : #endif
205 57513741 : }
206 :
207 : INLINE fd_bn254_fp_t *
208 : fd_bn254_fp_neg( fd_bn254_fp_t * r,
209 254961 : fd_bn254_fp_t const * a ) {
210 254961 : fiat_bn254_opp( r->limbs, a->limbs );
211 254961 : return r;
212 254961 : }
213 :
214 : static inline fd_bn254_fp_t *
215 : fd_bn254_fp_halve( fd_bn254_fp_t * r,
216 230442 : fd_bn254_fp_t const * a ) {
217 230442 : int is_odd = a->limbs[0] & 0x1;
218 230442 : fd_uint256_add( r, a, is_odd ? fd_bn254_const_p : fd_bn254_const_zero );
219 230442 : r->limbs[0] = (r->limbs[0] >> 1) | (r->limbs[1] << 63);
220 230442 : r->limbs[1] = (r->limbs[1] >> 1) | (r->limbs[2] << 63);
221 230442 : r->limbs[2] = (r->limbs[2] >> 1) | (r->limbs[3] << 63);
222 230442 : r->limbs[3] = (r->limbs[3] >> 1);
223 230442 : return r;
224 230442 : }
225 :
226 : FD_UINT256_FP_MUL_IMPL(fd_bn254_fp, fd_bn254_const_p, fd_bn254_const_p_inv)
227 :
228 : static inline fd_bn254_fp_t *
229 : fd_bn254_fp_sqr( fd_bn254_fp_t * r,
230 34229025 : fd_bn254_fp_t const * a ) {
231 34229025 : return fd_bn254_fp_mul( r, a, a );
232 34229025 : }
233 :
234 : /* Montgomery conversions via fp_mul rather than fiat's
235 : from/to_montgomery (their literal limbs are slow to compile). */
236 :
237 : /* r = a * R^-1 */
238 : static inline fd_bn254_fp_t *
239 : fd_bn254_fp_from_mont( fd_bn254_fp_t * r,
240 277953 : fd_bn254_fp_t const * a ) {
241 277953 : return fd_bn254_fp_mul( r, a, fd_bn254_const_one );
242 277953 : }
243 :
244 : /* r = a * R */
245 : static inline fd_bn254_fp_t *
246 : fd_bn254_fp_to_mont( fd_bn254_fp_t * r,
247 715071 : fd_bn254_fp_t const * a ) {
248 715071 : return fd_bn254_fp_mul( r, a, fd_bn254_const_rr );
249 715071 : }
250 :
251 : /* r = 1 / a mod p. a MUST not be 0. */
252 : static inline fd_bn254_fp_t *
253 : fd_bn254_fp_inv( fd_bn254_fp_t * r,
254 125865 : fd_bn254_fp_t const * a ) {
255 125865 : #if FD_HAS_S2NBIGNUM
256 : /* a is in montgomery form, giving a' = a*R mod p.
257 : bignum_modinv treats its inputs as canonical residues, so it computes:
258 : z = (a*R)^{-1} = a^{-1} * R^{-1}
259 : We can apply to_montgomery twice, each time multiplying by R, giving:
260 : r = a^{-1} * R^{-1} * R * R = a^{-1} * R = (a^{-1})' */
261 125865 : ulong tmp[12];
262 125865 : fd_bn254_fp_t z[1];
263 125865 : bignum_modinv( 4, z->limbs, a->limbs, fd_bn254_const_p->limbs, tmp );
264 125865 : fd_bn254_fp_to_mont( r, z );
265 125865 : fd_bn254_fp_to_mont( r, r );
266 125865 : return r;
267 : #else
268 : fd_uint256_t p_minus_2[1];
269 : fd_bn254_fp_set( p_minus_2, fd_bn254_const_p );
270 : p_minus_2->limbs[0] -= 2UL;
271 : return fd_bn254_fp_pow( r, a, p_minus_2 );
272 : #endif
273 125865 : }
274 :
275 : static inline fd_bn254_fp_t *
276 : fd_bn254_fp_sqrt( fd_bn254_fp_t * r,
277 36309 : fd_bn254_fp_t const * a ) {
278 : /* Alg. 2, https://eprint.iacr.org/2012/685 */
279 :
280 36309 : fd_bn254_fp_t a0[1], a1[1];
281 :
282 36309 : fd_bn254_fp_pow( a1, a, fd_bn254_const_sqrt_exp );
283 :
284 36309 : fd_bn254_fp_sqr( a0, a1 );
285 36309 : fd_bn254_fp_mul( a0, a0, a );
286 36309 : if( FD_UNLIKELY( fd_bn254_fp_eq( a0, fd_bn254_const_p_minus_one_mont ) ) ) {
287 30 : return NULL;
288 30 : }
289 :
290 36279 : fd_bn254_fp_mul( r, a1, a );
291 36279 : return r;
292 36309 : }
293 :
294 : /* Extension Fields Fp2, Fp6, Fp12.
295 :
296 : Mostly based on https://eprint.iacr.org/2010/354, Appendix A.
297 : See also, as a reference implementation:
298 : https://github.com/Consensys/gnark-crypto/tree/v0.12.1/ecc/bn254/internal/fptower
299 :
300 : Elements are in Montgomery form, unless otherwise specified. */
301 :
302 : /* Fp2 */
303 :
304 : static inline fd_bn254_fp2_t *
305 : fd_bn254_fp2_frombytes_nm( fd_bn254_fp2_t * r,
306 : uchar const buf[64],
307 : int big_endian,
308 : int * is_inf,
309 185754 : int * is_neg ) {
310 : /* validate fp2.el[0] without flags */
311 185754 : if( FD_UNLIKELY( !fd_bn254_fp_frombytes_nm( &r->el[0], &buf[ big_endian ? 32 : 0 ], big_endian, NULL, NULL ) ) ) {
312 0 : return NULL;
313 0 : }
314 : /* validate fp2.el[1] with flags */
315 185754 : if( FD_UNLIKELY( !fd_bn254_fp_frombytes_nm( &r->el[1], &buf[ big_endian ? 0 : 32 ], big_endian, is_inf, is_neg ) ) ) {
316 0 : return NULL;
317 0 : }
318 185754 : return r;
319 185754 : }
320 :
321 : static inline uchar *
322 : fd_bn254_fp2_tobytes_nm( uchar buf[64],
323 : fd_bn254_fp2_t * const a,
324 96951 : int big_endian ) {
325 96951 : fd_bn254_fp_tobytes_nm( &buf[ 0], &a->el[ big_endian ? 1 : 0 ], big_endian );
326 96951 : fd_bn254_fp_tobytes_nm( &buf[32], &a->el[ big_endian ? 0 : 1 ], big_endian );
327 96951 : return buf;
328 96951 : }
329 :
330 : /* fd_bn254_fp2_is_neg_nm checks whether x < 0 in Fp2.
331 : Note: x is NON Montgomery.
332 : Returns 1 if x < 0, 0 otherwise. */
333 : static inline int
334 33186 : fd_bn254_fp2_is_neg_nm( fd_bn254_fp2_t * x ) {
335 33186 : if( FD_UNLIKELY( fd_bn254_fp_is_zero( &x->el[1] ) ) ) {
336 0 : return fd_bn254_fp_is_neg_nm( &x->el[0] );
337 0 : }
338 33186 : return fd_bn254_fp_is_neg_nm( &x->el[1] );
339 33186 : }
340 :
341 : /* fd_bn254_fp2_is_minus_one checks whether a == -1 in Fp2.
342 : Returns 1 if a==-1, 0 otherwise. */
343 : static inline int
344 0 : fd_bn254_fp2_is_minus_one( fd_bn254_fp2_t const * a ) {
345 0 : return fd_uint256_eq( &a->el[0], fd_bn254_const_p_minus_one_mont )
346 0 : && fd_uint256_eq( &a->el[1], fd_bn254_const_zero );
347 0 : }
348 :
349 : /* fd_bn254_fp2_eq checks whether a == b in Fp2.
350 : Returns 1 if a == b, 0 otherwise. */
351 : static inline int
352 : fd_bn254_fp2_eq( fd_bn254_fp2_t const * a,
353 155196 : fd_bn254_fp2_t const * b ) {
354 155196 : return fd_bn254_fp_eq( &a->el[0], &b->el[0] )
355 155196 : && fd_bn254_fp_eq( &a->el[1], &b->el[1] );
356 155196 : }
357 :
358 : /* fd_bn254_fp2_set sets r = a. */
359 : static inline fd_bn254_fp2_t *
360 : fd_bn254_fp2_set( fd_bn254_fp2_t * r,
361 1722357 : fd_bn254_fp2_t const * a ) {
362 1722357 : fd_bn254_fp_set( &r->el[0], &a->el[0] );
363 1722357 : fd_bn254_fp_set( &r->el[1], &a->el[1] );
364 1722357 : return r;
365 1722357 : }
366 :
367 : /* fd_bn254_fp2_from_mont sets r = a, converting into NON Montgomery form. */
368 : static inline fd_bn254_fp2_t *
369 : fd_bn254_fp2_from_mont( fd_bn254_fp2_t * r,
370 63765 : fd_bn254_fp2_t const * a ) {
371 63765 : fd_bn254_fp_from_mont( &r->el[0], &a->el[0] );
372 63765 : fd_bn254_fp_from_mont( &r->el[1], &a->el[1] );
373 63765 : return r;
374 63765 : }
375 :
376 : /* fd_bn254_fp2_to_mont sets r = a, converting into Montgomery form. */
377 : static inline fd_bn254_fp2_t *
378 : fd_bn254_fp2_to_mont( fd_bn254_fp2_t * r,
379 125553 : fd_bn254_fp2_t const * a ) {
380 125553 : fd_bn254_fp_to_mont( &r->el[0], &a->el[0] );
381 125553 : fd_bn254_fp_to_mont( &r->el[1], &a->el[1] );
382 125553 : return r;
383 125553 : }
384 :
385 : /* fd_bn254_fp2_neg_nm sets r = -x in Fp2.
386 : Note: x is NON Montgomery. */
387 : static inline fd_bn254_fp2_t *
388 : fd_bn254_fp2_neg_nm( fd_bn254_fp2_t * r,
389 3060 : fd_bn254_fp2_t const * x ) {
390 3060 : fd_bn254_fp_neg_nm( &r->el[0], &x->el[0] );
391 3060 : fd_bn254_fp_neg_nm( &r->el[1], &x->el[1] );
392 3060 : return r;
393 3060 : }
394 :
395 : /* fd_bn254_fp2_neg sets r = -a in Fp2. */
396 : INLINE fd_bn254_fp2_t *
397 : fd_bn254_fp2_neg( fd_bn254_fp2_t * r,
398 102132 : fd_bn254_fp2_t const * a ) {
399 102132 : fd_bn254_fp_neg( &r->el[0], &a->el[0] );
400 102132 : fd_bn254_fp_neg( &r->el[1], &a->el[1] );
401 102132 : return r;
402 102132 : }
403 :
404 : /* fd_bn254_fp2_neg sets r = a/2 in Fp2. */
405 : static inline fd_bn254_fp2_t *
406 : fd_bn254_fp2_halve( fd_bn254_fp2_t * r,
407 112128 : fd_bn254_fp2_t const * a ) {
408 112128 : fd_bn254_fp_halve( &r->el[0], &a->el[0] );
409 112128 : fd_bn254_fp_halve( &r->el[1], &a->el[1] );
410 112128 : return r;
411 112128 : }
412 :
413 : /* fd_bn254_fp2_add computes r = a + b in Fp2. */
414 : INLINE fd_bn254_fp2_t *
415 : fd_bn254_fp2_add( fd_bn254_fp2_t * r,
416 : fd_bn254_fp2_t const * a,
417 8204916 : fd_bn254_fp2_t const * b ) {
418 8204916 : fd_bn254_fp_add( &r->el[0], &a->el[0], &b->el[0] );
419 8204916 : fd_bn254_fp_add( &r->el[1], &a->el[1], &b->el[1] );
420 8204916 : return r;
421 8204916 : }
422 :
423 : /* fd_bn254_fp2_sub computes r = a - b in Fp2. */
424 : INLINE fd_bn254_fp2_t *
425 : fd_bn254_fp2_sub( fd_bn254_fp2_t * r,
426 : fd_bn254_fp2_t const * a,
427 5136297 : fd_bn254_fp2_t const * b ) {
428 5136297 : fd_bn254_fp_sub( &r->el[0], &a->el[0], &b->el[0] );
429 5136297 : fd_bn254_fp_sub( &r->el[1], &a->el[1], &b->el[1] );
430 5136297 : return r;
431 5136297 : }
432 :
433 : /* fd_bn254_fp2_conj computes r = conj(a) in Fp2.
434 : If a = a0 + a1*i, conj(a) = a0 - a1*i. */
435 : INLINE fd_bn254_fp2_t *
436 : fd_bn254_fp2_conj( fd_bn254_fp2_t * r,
437 18180 : fd_bn254_fp2_t const * a ) {
438 18180 : fd_bn254_fp_set( &r->el[0], &a->el[0] );
439 18180 : fd_bn254_fp_neg( &r->el[1], &a->el[1] );
440 18180 : return r;
441 18180 : }
442 :
443 : /* fd_bn254_fp2_mul computes r = a * b in Fp2.
444 : Karatsuba mul + reduction given that i^2 = -1.
445 : Note: this can probably be optimized, see for ideas:
446 : https://eprint.iacr.org/2010/354 */
447 : static __attribute__((noinline,unused)) fd_bn254_fp2_t *
448 : fd_bn254_fp2_mul( fd_bn254_fp2_t * r,
449 : fd_bn254_fp2_t const * a,
450 3489696 : fd_bn254_fp2_t const * b ) {
451 3489696 : fd_bn254_fp_t const * a0 = &a->el[0];
452 3489696 : fd_bn254_fp_t const * a1 = &a->el[1];
453 3489696 : fd_bn254_fp_t const * b0 = &b->el[0];
454 3489696 : fd_bn254_fp_t const * b1 = &b->el[1];
455 3489696 : fd_bn254_fp_t * r0 = &r->el[0];
456 3489696 : fd_bn254_fp_t * r1 = &r->el[1];
457 3489696 : fd_bn254_fp_t a0b0[1], a1b1[1], sa[1], sb[1];
458 :
459 : /* sa, sb are lazy additions as they're only consumed by fp_mul */
460 3489696 : fd_bn254_fp_add_lazy( sa, a0, a1 );
461 3489696 : fd_bn254_fp_add_lazy( sb, b0, b1 );
462 :
463 3489696 : fd_bn254_fp_mul( a0b0, a0, b0 );
464 3489696 : fd_bn254_fp_mul( a1b1, a1, b1 );
465 3489696 : fd_bn254_fp_mul( r1, sa, sb );
466 :
467 3489696 : fd_bn254_fp_sub( r0, a0b0, a1b1 ); /* i^2 = -1 */
468 3489696 : fd_bn254_fp_sub( r1, r1, a0b0 );
469 3489696 : fd_bn254_fp_sub( r1, r1, a1b1 );
470 3489696 : return r;
471 3489696 : }
472 :
473 : /* fd_bn254_fp2_mul computes r = a^2 in Fp2.
474 : https://eprint.iacr.org/2010/354, Alg. 3.
475 : This is done with 2mul in Fp, instead of 2sqr+1mul. */
476 : static __attribute__((noinline,unused)) fd_bn254_fp2_t *
477 : fd_bn254_fp2_sqr( fd_bn254_fp2_t * r,
478 2426997 : fd_bn254_fp2_t const * a ) {
479 2426997 : fd_bn254_fp_t p[1], m[1];
480 : /* p is a lazy addition as it's only consumed by fp_mul */
481 2426997 : fd_bn254_fp_add_lazy( p, &a->el[0], &a->el[1] );
482 2426997 : fd_bn254_fp_sub ( m, &a->el[0], &a->el[1] );
483 : /* r1 = 2 a0*a1 */
484 2426997 : fd_bn254_fp_mul( &r->el[1], &a->el[0], &a->el[1] );
485 2426997 : fd_bn254_fp_add( &r->el[1], &r->el[1], &r->el[1] );
486 : /* r0 = (a0-a1)*(a0+a1) */
487 2426997 : fd_bn254_fp_mul( &r->el[0], p, m );
488 2426997 : return r;
489 2426997 : }
490 :
491 : /* fd_bn254_fp2_mul_by_i computes r = a * i in Fp2. */
492 : static inline fd_bn254_fp2_t *
493 : fd_bn254_fp2_mul_by_i( fd_bn254_fp2_t * r,
494 0 : fd_bn254_fp2_t const * a ) {
495 0 : fd_bn254_fp_t t[1];
496 0 : fd_bn254_fp_neg( t, &a->el[1] );
497 0 : fd_bn254_fp_set( &r->el[1], &a->el[0] );
498 0 : fd_bn254_fp_set( &r->el[0], t );
499 0 : return r;
500 0 : }
501 :
502 : /* fd_bn254_fp2_inv computes r = 1 / a in Fp2.
503 : a MUST not be 0.
504 : https://eprint.iacr.org/2010/354, Alg. 8. */
505 : static __attribute__((noinline,unused)) fd_bn254_fp2_t *
506 : fd_bn254_fp2_inv( fd_bn254_fp2_t * r,
507 32517 : fd_bn254_fp2_t const * a ) {
508 32517 : fd_bn254_fp_t t0[1], t1[1];
509 32517 : fd_bn254_fp_sqr( t0, &a->el[0] );
510 32517 : fd_bn254_fp_sqr( t1, &a->el[1] );
511 32517 : fd_bn254_fp_add( t0, t0, t1 );
512 32517 : fd_bn254_fp_inv( t1, t0 );
513 32517 : fd_bn254_fp_mul( &r->el[0], &a->el[0], t1 );
514 32517 : fd_bn254_fp_mul( &r->el[1], &a->el[1], t1 );
515 32517 : fd_bn254_fp_neg( &r->el[1], &r->el[1] );
516 32517 : return r;
517 32517 : }
518 :
519 : /* fd_bn254_fp2_sqrt computes r = sqrt(a) in Fp2.
520 : https://eprint.iacr.org/2012/685, Alg. 8.
521 :
522 : For bn254 the non-residue is i with i^2 = -1, so norm(c) = c0^2 + c1^2.
523 : This method costs us 2 fp_sqrt + 1 fp_inv + a few fp_mul/sqr.
524 : The method described in Alg. 9 is 2 fp2_pow, which is more expensive. */
525 : static inline fd_bn254_fp2_t *
526 : fd_bn254_fp2_sqrt( fd_bn254_fp2_t * r,
527 3093 : fd_bn254_fp2_t const * a ) {
528 3093 : fd_bn254_fp_t const * c0 = &a->el[0];
529 3093 : fd_bn254_fp_t const * c1 = &a->el[1];
530 3093 : fd_bn254_fp_t norm[1], alpha[1], delta[1], tmp[1];
531 3093 : fd_bn254_fp_t x[1], y[1], xinv[1];
532 :
533 : /* c1 == 0, sqrt reduces to Fp sqrt on c0 (or sqrt(-c0) shifted to imaginary). */
534 3093 : if( FD_UNLIKELY( fd_bn254_fp_is_zero( c1 ) ) ) {
535 0 : if( fd_bn254_fp_sqrt( x, c0 ) ) {
536 0 : fd_bn254_fp_set( &r->el[0], x );
537 0 : fd_bn254_fp_set_zero( &r->el[1] );
538 0 : return r;
539 0 : }
540 0 : fd_bn254_fp_neg( y, c0 );
541 0 : if( !fd_bn254_fp_sqrt( y, y ) ) return NULL;
542 0 : fd_bn254_fp_set_zero( &r->el[0] );
543 0 : fd_bn254_fp_set( &r->el[1], y );
544 0 : return r;
545 0 : }
546 :
547 : /* norm = c0^2 + c1^2 */
548 3093 : fd_bn254_fp_sqr( norm, c0 );
549 3093 : fd_bn254_fp_sqr( tmp, c1 );
550 3093 : fd_bn254_fp_add( norm, norm, tmp );
551 :
552 : /* alpha = sqrt(norm); NULL means a is a non-square in Fp2. */
553 3093 : if( !fd_bn254_fp_sqrt( alpha, norm ) ) return NULL;
554 :
555 : /* delta = (alpha + c0) / 2
556 : If delta is not a quadratic residue, use (c0 - alpha) / 2 instead.
557 : We test this by trying sqrt(delta) first. */
558 3093 : fd_bn254_fp_add( delta, alpha, c0 );
559 3093 : fd_bn254_fp_halve( delta, delta );
560 :
561 3093 : if( !fd_bn254_fp_sqrt( x, delta ) ) {
562 30 : fd_bn254_fp_sub( delta, delta, alpha );
563 30 : if( !fd_bn254_fp_sqrt( x, delta ) ) return NULL;
564 30 : }
565 :
566 : /* y = c1 / (2x) = c1 * (1/x) / 2 */
567 3093 : fd_bn254_fp_inv ( xinv, x );
568 3093 : fd_bn254_fp_mul ( y, c1, xinv );
569 3093 : fd_bn254_fp_halve( y, y );
570 :
571 3093 : fd_bn254_fp_set( &r->el[0], x );
572 3093 : fd_bn254_fp_set( &r->el[1], y );
573 3093 : return r;
574 3093 : }
575 :
576 : /* fd_bn254_fp2_mul_by_xi computes r = a * (9+i) in Fp2.
577 : xi = (9+i) is the const used to build Fp6.
578 : Note: this can probably be optimized (less reductions mod p). */
579 : INLINE fd_bn254_fp2_t *
580 : fd_bn254_fp2_mul_by_xi( fd_bn254_fp2_t * r,
581 1221111 : fd_bn254_fp2_t const * a ) {
582 : /* xi = 9 + i
583 : r = (9*a0 - a1) + (9*a1 + a0) i */
584 1221111 : fd_bn254_fp_t r0[1], r1[1];
585 :
586 1221111 : fd_bn254_fp_add( r0, &a->el[0], &a->el[0] );
587 1221111 : fd_bn254_fp_add( r0, r0, r0 );
588 1221111 : fd_bn254_fp_add( r0, r0, r0 );
589 1221111 : fd_bn254_fp_add( r0, r0, &a->el[0] );
590 1221111 : fd_bn254_fp_sub( r0, r0, &a->el[1] );
591 :
592 1221111 : fd_bn254_fp_add( r1, &a->el[1], &a->el[1] );
593 1221111 : fd_bn254_fp_add( r1, r1, r1 );
594 1221111 : fd_bn254_fp_add( r1, r1, r1 );
595 1221111 : fd_bn254_fp_add( r1, r1, &a->el[1] );
596 1221111 : fd_bn254_fp_add( &r->el[1], r1, &a->el[0] );
597 :
598 1221111 : fd_bn254_fp_set( &r->el[0], r0 );
599 1221111 : return r;
600 1221111 : }
601 :
602 : /* Fp6 */
603 :
604 : static inline fd_bn254_fp6_t *
605 : fd_bn254_fp6_set( fd_bn254_fp6_t * r,
606 3465 : fd_bn254_fp6_t const * a ) {
607 3465 : fd_bn254_fp2_set( &r->el[0], &a->el[0] );
608 3465 : fd_bn254_fp2_set( &r->el[1], &a->el[1] );
609 3465 : fd_bn254_fp2_set( &r->el[2], &a->el[2] );
610 3465 : return r;
611 3465 : }
612 :
613 : static inline fd_bn254_fp6_t *
614 : fd_bn254_fp6_neg( fd_bn254_fp6_t * r,
615 4158 : fd_bn254_fp6_t const * a ) {
616 4158 : fd_bn254_fp2_neg( &r->el[0], &a->el[0] );
617 4158 : fd_bn254_fp2_neg( &r->el[1], &a->el[1] );
618 4158 : fd_bn254_fp2_neg( &r->el[2], &a->el[2] );
619 4158 : return r;
620 4158 : }
621 :
622 : static inline fd_bn254_fp6_t *
623 : fd_bn254_fp6_add( fd_bn254_fp6_t * r,
624 : fd_bn254_fp6_t const * a,
625 360618 : fd_bn254_fp6_t const * b ) {
626 360618 : fd_bn254_fp2_add( &r->el[0], &a->el[0], &b->el[0] );
627 360618 : fd_bn254_fp2_add( &r->el[1], &a->el[1], &b->el[1] );
628 360618 : fd_bn254_fp2_add( &r->el[2], &a->el[2], &b->el[2] );
629 360618 : return r;
630 360618 : }
631 :
632 : static inline fd_bn254_fp6_t *
633 : fd_bn254_fp6_sub( fd_bn254_fp6_t * r,
634 : fd_bn254_fp6_t const * a,
635 292497 : fd_bn254_fp6_t const * b ) {
636 292497 : fd_bn254_fp2_sub( &r->el[0], &a->el[0], &b->el[0] );
637 292497 : fd_bn254_fp2_sub( &r->el[1], &a->el[1], &b->el[1] );
638 292497 : fd_bn254_fp2_sub( &r->el[2], &a->el[2], &b->el[2] );
639 292497 : return r;
640 292497 : }
641 :
642 : static inline fd_bn254_fp6_t *
643 : fd_bn254_fp6_mul_by_gamma( fd_bn254_fp6_t * r,
644 171363 : fd_bn254_fp6_t const * a ) {
645 : /* https://eprint.iacr.org/2010/354, Alg. 12 */
646 171363 : fd_bn254_fp2_t t[1];
647 171363 : fd_bn254_fp2_mul_by_xi( t, &a->el[2] );
648 171363 : fd_bn254_fp2_set( &r->el[2], &a->el[1] );
649 171363 : fd_bn254_fp2_set( &r->el[1], &a->el[0] );
650 171363 : fd_bn254_fp2_set( &r->el[0], t );
651 171363 : return r;
652 171363 : }
653 :
654 : static __attribute__((noinline,unused)) fd_bn254_fp6_t *
655 : fd_bn254_fp6_mul( fd_bn254_fp6_t * r,
656 : fd_bn254_fp6_t const * a,
657 183060 : fd_bn254_fp6_t const * b ) {
658 : /* https://eprint.iacr.org/2010/354, Alg. 13 */
659 183060 : fd_bn254_fp2_t const * a0 = &a->el[0];
660 183060 : fd_bn254_fp2_t const * a1 = &a->el[1];
661 183060 : fd_bn254_fp2_t const * a2 = &a->el[2];
662 183060 : fd_bn254_fp2_t const * b0 = &b->el[0];
663 183060 : fd_bn254_fp2_t const * b1 = &b->el[1];
664 183060 : fd_bn254_fp2_t const * b2 = &b->el[2];
665 183060 : fd_bn254_fp2_t a0b0[1], a1b1[1], a2b2[1];
666 183060 : fd_bn254_fp2_t sa[1], sb[1];
667 183060 : fd_bn254_fp2_t r0[1], r1[1], r2[1];
668 :
669 183060 : fd_bn254_fp2_mul( a0b0, a0, b0 );
670 183060 : fd_bn254_fp2_mul( a1b1, a1, b1 );
671 183060 : fd_bn254_fp2_mul( a2b2, a2, b2 );
672 :
673 : /* fp2_mul has its own internal lazy additions, so we cannot compound
674 : here as it would push intermediate values past our [0, 2p) bound. */
675 183060 : fd_bn254_fp2_add( sa, a1, a2 );
676 183060 : fd_bn254_fp2_add( sb, b1, b2 );
677 183060 : fd_bn254_fp2_mul( r0, sa, sb );
678 183060 : fd_bn254_fp2_sub( r0, r0, a1b1 );
679 183060 : fd_bn254_fp2_sub( r0, r0, a2b2 );
680 183060 : fd_bn254_fp2_mul_by_xi( r0, r0 );
681 183060 : fd_bn254_fp2_add( r0, r0, a0b0 );
682 :
683 183060 : fd_bn254_fp2_add( sa, a0, a2 );
684 183060 : fd_bn254_fp2_add( sb, b0, b2 );
685 183060 : fd_bn254_fp2_mul( r2, sa, sb );
686 183060 : fd_bn254_fp2_sub( r2, r2, a0b0 );
687 183060 : fd_bn254_fp2_sub( r2, r2, a2b2 );
688 183060 : fd_bn254_fp2_add( r2, r2, a1b1 );
689 :
690 183060 : fd_bn254_fp2_add( sa, a0, a1 );
691 183060 : fd_bn254_fp2_add( sb, b0, b1 );
692 183060 : fd_bn254_fp2_mul( r1, sa, sb );
693 183060 : fd_bn254_fp2_sub( r1, r1, a0b0 );
694 183060 : fd_bn254_fp2_sub( r1, r1, a1b1 );
695 183060 : fd_bn254_fp2_mul_by_xi( a2b2, a2b2 );
696 183060 : fd_bn254_fp2_add( r1, r1, a2b2 );
697 :
698 183060 : fd_bn254_fp2_set( &r->el[0], r0 );
699 183060 : fd_bn254_fp2_set( &r->el[1], r1 );
700 183060 : fd_bn254_fp2_set( &r->el[2], r2 );
701 183060 : return r;
702 183060 : }
703 :
704 : static inline fd_bn254_fp6_t *
705 : fd_bn254_fp6_sqr( fd_bn254_fp6_t * r,
706 1386 : fd_bn254_fp6_t const * a ) {
707 : /* https://eprint.iacr.org/2010/354, Alg. 16 */
708 1386 : fd_bn254_fp2_t const * a0 = &a->el[0];
709 1386 : fd_bn254_fp2_t const * a1 = &a->el[1];
710 1386 : fd_bn254_fp2_t const * a2 = &a->el[2];
711 1386 : fd_bn254_fp2_t c0[1], c1[1], c2[1];
712 1386 : fd_bn254_fp2_t c3[1], c4[1], c5[1];
713 :
714 1386 : fd_bn254_fp2_mul( c4, a0, a1 );
715 1386 : fd_bn254_fp2_add( c4, c4, c4 );
716 1386 : fd_bn254_fp2_sqr( c5, a2 );
717 :
718 1386 : fd_bn254_fp2_sub( c2, c4, c5 );
719 1386 : fd_bn254_fp2_mul_by_xi( c5, c5 );
720 1386 : fd_bn254_fp2_add( c1, c4, c5 );
721 :
722 1386 : fd_bn254_fp2_sqr( c3, a0 );
723 1386 : fd_bn254_fp2_sub( c4, a0, a1 );
724 : /* not lazy for the same reasons as fd_bn254_fp6_mul. */
725 1386 : fd_bn254_fp2_add( c4, c4, a2 );
726 :
727 1386 : fd_bn254_fp2_mul( c5, a1, a2 );
728 1386 : fd_bn254_fp2_add( c5, c5, c5 );
729 1386 : fd_bn254_fp2_sqr( c4, c4 );
730 :
731 1386 : fd_bn254_fp2_add( c2, c2, c4 );
732 1386 : fd_bn254_fp2_add( c2, c2, c5 );
733 1386 : fd_bn254_fp2_sub( c2, c2, c3 );
734 1386 : fd_bn254_fp2_mul_by_xi( c5, c5 );
735 1386 : fd_bn254_fp2_add( c0, c3, c5 );
736 :
737 1386 : fd_bn254_fp2_set( &r->el[0], c0 );
738 1386 : fd_bn254_fp2_set( &r->el[1], c1 );
739 1386 : fd_bn254_fp2_set( &r->el[2], c2 );
740 1386 : return r;
741 1386 : }
742 :
743 : static inline fd_bn254_fp6_t *
744 : fd_bn254_fp6_inv( fd_bn254_fp6_t * r,
745 693 : fd_bn254_fp6_t const * a ) {
746 : /* https://eprint.iacr.org/2010/354, Alg. 17 */
747 693 : fd_bn254_fp2_t t[6];
748 693 : fd_bn254_fp2_sqr( &t[0], &a->el[0] );
749 693 : fd_bn254_fp2_sqr( &t[1], &a->el[1] );
750 693 : fd_bn254_fp2_sqr( &t[2], &a->el[2] );
751 693 : fd_bn254_fp2_mul( &t[3], &a->el[0], &a->el[1] );
752 693 : fd_bn254_fp2_mul( &t[4], &a->el[0], &a->el[2] );
753 693 : fd_bn254_fp2_mul( &t[5], &a->el[1], &a->el[2] );
754 : /* t0 := c0 = t0 - xi * t5 */
755 693 : fd_bn254_fp2_mul_by_xi( &t[5], &t[5] );
756 693 : fd_bn254_fp2_sub( &t[0], &t[0], &t[5] );
757 : /* t2 := c1 = xi * t2 - t3 */
758 693 : fd_bn254_fp2_mul_by_xi( &t[2], &t[2] );
759 693 : fd_bn254_fp2_sub( &t[2], &t[2], &t[3] );
760 : /* t1 := c2 = t1 - t4 (note: paper says t1*t4, but that's a misprint) */
761 693 : fd_bn254_fp2_sub( &t[1], &t[1], &t[4] );
762 : /* t3 := t6 = a0 * c0 */
763 693 : fd_bn254_fp2_mul( &t[3], &a->el[0], &t[0] );
764 : /* t3 := t6 = t6 + (xi * a2 * c1 =: t4) */
765 693 : fd_bn254_fp2_mul( &t[4], &a->el[2], &t[2] );
766 693 : fd_bn254_fp2_mul_by_xi( &t[4], &t[4] );
767 693 : fd_bn254_fp2_add( &t[3], &t[3], &t[4] );
768 : /* t3 := t6 = t6 + (xi * a2 * c1 =: t4) */
769 693 : fd_bn254_fp2_mul( &t[5], &a->el[1], &t[1] );
770 693 : fd_bn254_fp2_mul_by_xi( &t[5], &t[5] );
771 693 : fd_bn254_fp2_add( &t[3], &t[3], &t[5] );
772 : /* t4 := t6^-1 */
773 693 : fd_bn254_fp2_inv( &t[4], &t[3] );
774 :
775 693 : fd_bn254_fp2_mul( &r->el[0], &t[0], &t[4] );
776 693 : fd_bn254_fp2_mul( &r->el[1], &t[2], &t[4] );
777 693 : fd_bn254_fp2_mul( &r->el[2], &t[1], &t[4] );
778 693 : return r;
779 693 : }
780 :
781 : /* Fp12 */
782 :
783 : static inline fd_bn254_fp12_t *
784 : fd_bn254_fp12_conj( fd_bn254_fp12_t * r,
785 3465 : fd_bn254_fp12_t const * a ) {
786 3465 : fd_bn254_fp6_set( &r->el[0], &a->el[0] );
787 3465 : fd_bn254_fp6_neg( &r->el[1], &a->el[1] );
788 3465 : return r;
789 3465 : }
790 :
791 : /*
792 : static inline fd_bn254_fp12_t *
793 : fd_bn254_fp12_add( fd_bn254_fp12_t * r,
794 : fd_bn254_fp12_t const * a,
795 : fd_bn254_fp12_t const * b ) {
796 : fd_bn254_fp6_add( &r->el[0], &a->el[0], &b->el[0] );
797 : fd_bn254_fp6_add( &r->el[1], &a->el[1], &b->el[1] );
798 : return r;
799 : }
800 :
801 : static inline fd_bn254_fp12_t *
802 : fd_bn254_fp12_sub( fd_bn254_fp12_t * r,
803 : fd_bn254_fp12_t const * a,
804 : fd_bn254_fp12_t const * b ) {
805 : fd_bn254_fp6_sub( &r->el[0], &a->el[0], &b->el[0] );
806 : fd_bn254_fp6_sub( &r->el[1], &a->el[1], &b->el[1] );
807 : return r;
808 : }
809 : */
810 :
811 :
812 :
813 :
814 :
815 :
816 : static inline fd_bn254_fp12_t *
817 : fd_bn254_fp12_frob( fd_bn254_fp12_t * r,
818 1386 : fd_bn254_fp12_t const * a ) {
819 : /* https://eprint.iacr.org/2010/354, Alg. 28 */
820 1386 : fd_bn254_fp2_t t[5];
821 :
822 : /* conj(g0) */
823 1386 : fd_bn254_fp2_conj( &r->el[0].el[0], &a->el[0].el[0] );
824 1386 : fd_bn254_fp2_conj( &t[0], &a->el[0].el[1] );
825 1386 : fd_bn254_fp2_conj( &t[1], &a->el[0].el[2] );
826 1386 : fd_bn254_fp2_conj( &t[2], &a->el[1].el[0] );
827 1386 : fd_bn254_fp2_conj( &t[3], &a->el[1].el[1] );
828 1386 : fd_bn254_fp2_conj( &t[4], &a->el[1].el[2] );
829 :
830 : /* conj(g1) * gamma_1,2 */
831 1386 : fd_bn254_fp2_mul( &r->el[0].el[1], &t[0], &fd_bn254_const_frob_gamma1_mont[1] );
832 :
833 : /* conj(g2) * gamma_1,4 */
834 1386 : fd_bn254_fp2_mul( &r->el[0].el[2], &t[1], &fd_bn254_const_frob_gamma1_mont[3] );
835 :
836 : /* conj(h0) * gamma_1,1 */
837 1386 : fd_bn254_fp2_mul( &r->el[1].el[0], &t[2], &fd_bn254_const_frob_gamma1_mont[0] );
838 :
839 : /* conj(h1) * gamma_1,3 */
840 1386 : fd_bn254_fp2_mul( &r->el[1].el[1], &t[3], &fd_bn254_const_frob_gamma1_mont[2] );
841 :
842 : /* conj(h2) * gamma_1,5 */
843 1386 : fd_bn254_fp2_mul( &r->el[1].el[2], &t[4], &fd_bn254_const_frob_gamma1_mont[4] );
844 1386 : return r;
845 1386 : }
846 :
847 : static inline fd_bn254_fp12_t *
848 : fd_bn254_fp12_frob2( fd_bn254_fp12_t * r,
849 2079 : fd_bn254_fp12_t const * a ) {
850 : /* https://eprint.iacr.org/2010/354, Alg. 29 */
851 :
852 : /* g0 */
853 2079 : fd_bn254_fp2_set( &r->el[0].el[0], &a->el[0].el[0] );
854 :
855 : /* g1 * gamma_2,2 */
856 2079 : fd_bn254_fp_mul( &r->el[0].el[1].el[0], &a->el[0].el[1].el[0], &fd_bn254_const_frob_gamma2_mont[1] );
857 2079 : fd_bn254_fp_mul( &r->el[0].el[1].el[1], &a->el[0].el[1].el[1], &fd_bn254_const_frob_gamma2_mont[1] );
858 :
859 : /* g2 * gamma_2,4 */
860 2079 : fd_bn254_fp_mul( &r->el[0].el[2].el[0], &a->el[0].el[2].el[0], &fd_bn254_const_frob_gamma2_mont[3] );
861 2079 : fd_bn254_fp_mul( &r->el[0].el[2].el[1], &a->el[0].el[2].el[1], &fd_bn254_const_frob_gamma2_mont[3] );
862 :
863 : /* h0 * gamma_2,1 */
864 2079 : fd_bn254_fp_mul( &r->el[1].el[0].el[0], &a->el[1].el[0].el[0], &fd_bn254_const_frob_gamma2_mont[0] );
865 2079 : fd_bn254_fp_mul( &r->el[1].el[0].el[1], &a->el[1].el[0].el[1], &fd_bn254_const_frob_gamma2_mont[0] );
866 :
867 : /* h1 * gamma_2,3 */
868 2079 : fd_bn254_fp_mul( &r->el[1].el[1].el[0], &a->el[1].el[1].el[0], &fd_bn254_const_frob_gamma2_mont[2] );
869 2079 : fd_bn254_fp_mul( &r->el[1].el[1].el[1], &a->el[1].el[1].el[1], &fd_bn254_const_frob_gamma2_mont[2] );
870 :
871 : /* h2 * gamma_2,5 */
872 2079 : fd_bn254_fp_mul( &r->el[1].el[2].el[0], &a->el[1].el[2].el[0], &fd_bn254_const_frob_gamma2_mont[4] );
873 2079 : fd_bn254_fp_mul( &r->el[1].el[2].el[1], &a->el[1].el[2].el[1], &fd_bn254_const_frob_gamma2_mont[4] );
874 2079 : return r;
875 2079 : }
876 :
877 :
878 : #endif /* HEADER_fd_src_ballet_bn254_fd_bn254_field_inl_h */
|