LCOV - code coverage report
Current view: top level - ballet/bn254 - fd_bn254_field_inl.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 445 479 92.9 %
Date: 2026-10-24 04:27:19 Functions: 141 423 33.3 %

          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 */

Generated by: LCOV version 1.14