// SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe* a, const secp256k1_fe* b) // { // secp256k1_fe na; // secp256k1_fe_negate(na, a, 1); // secp256k1_fe_add(na, b); // return secp256k1_fe_normalizes_to_zero_var(na); // } public static bool secp256k1_fe_sqrt(secp256k1_fe r, secp256k1_fe a) { /** Given that p is congruent to 3 mod 4, we can compute the square root of * a mod p as the (p+1)/4'th power of a. * * As (p+1)/4 is an even number, it will have the same result for a and for * (-a). Only one of these two numbers actually has a square root however, * so we test at the end by squaring and comparing to the input. * Also because (p+1)/4 is an even number, the computed square root is * itself always a square (a ** ((p+1)/4) is the square of a ** ((p+1)/8)). */ secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; int j; /** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in * { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block: * 1, [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223] */ x2 = new secp256k1_fe(); secp256k1_fe_sqr(x2, a); secp256k1_fe_mul(x2, x2, a); x3 = new secp256k1_fe(); secp256k1_fe_sqr(x3, x2); secp256k1_fe_mul(x3, x3, a); x6 = x3.Clone(); for (j = 0; j < 3; j++) { secp256k1_fe_sqr(x6, x6); } secp256k1_fe_mul(x6, x6, x3); x9 = x6.Clone(); for (j = 0; j < 3; j++) { secp256k1_fe_sqr(x9, x9); } secp256k1_fe_mul(x9, x9, x3); x11 = x9.Clone(); for (j = 0; j < 2; j++) { secp256k1_fe_sqr(x11, x11); } secp256k1_fe_mul(x11, x11, x2); x22 = x11.Clone(); for (j = 0; j < 11; j++) { secp256k1_fe_sqr(x22, x22); } secp256k1_fe_mul(x22, x22, x11); x44 = x22.Clone(); for (j = 0; j < 22; j++) { secp256k1_fe_sqr(x44, x44); } secp256k1_fe_mul(x44, x44, x22); x88 = x44.Clone(); for (j = 0; j < 44; j++) { secp256k1_fe_sqr(x88, x88); } secp256k1_fe_mul(x88, x88, x44); x176 = x88.Clone(); for (j = 0; j < 88; j++) { secp256k1_fe_sqr(x176, x176); } secp256k1_fe_mul(x176, x176, x88); x220 = x176.Clone(); for (j = 0; j < 44; j++) { secp256k1_fe_sqr(x220, x220); } secp256k1_fe_mul(x220, x220, x44); x223 = x220.Clone(); for (j = 0; j < 3; j++) { secp256k1_fe_sqr(x223, x223); } secp256k1_fe_mul(x223, x223, x3); /* The final result is then assembled using a sliding window over the blocks. */ t1 = x223.Clone(); for (j = 0; j < 23; j++) { secp256k1_fe_sqr(t1, t1); } secp256k1_fe_mul(t1, t1, x22); for (j = 0; j < 6; j++) { secp256k1_fe_sqr(t1, t1); } secp256k1_fe_mul(t1, t1, x2); secp256k1_fe_sqr(t1, t1); secp256k1_fe_sqr(r, t1); /* Check that a square root was actually calculated */ secp256k1_fe_sqr(t1, r); return(secp256k1_fe_equal(t1, a)); }
public static void secp256k1_fe_inv(secp256k1_fe r, secp256k1_fe a) { secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; int j; /** The binary representation of (p - 2) has 5 blocks of 1s, with lengths in * { 1, 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block: * [1], [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223] */ x2 = new secp256k1_fe(); secp256k1_fe_sqr(x2, a); secp256k1_fe_mul(x2, x2, a); x3 = new secp256k1_fe(); secp256k1_fe_sqr(x3, x2); secp256k1_fe_mul(x3, x3, a); x6 = x3.Clone(); for (j = 0; j < 3; j++) { secp256k1_fe_sqr(x6, x6); } secp256k1_fe_mul(x6, x6, x3); x9 = x6.Clone(); for (j = 0; j < 3; j++) { secp256k1_fe_sqr(x9, x9); } secp256k1_fe_mul(x9, x9, x3); x11 = x9.Clone(); for (j = 0; j < 2; j++) { secp256k1_fe_sqr(x11, x11); } secp256k1_fe_mul(x11, x11, x2); x22 = x11.Clone(); for (j = 0; j < 11; j++) { secp256k1_fe_sqr(x22, x22); } secp256k1_fe_mul(x22, x22, x11); x44 = x22.Clone(); for (j = 0; j < 22; j++) { secp256k1_fe_sqr(x44, x44); } secp256k1_fe_mul(x44, x44, x22); x88 = x44.Clone(); for (j = 0; j < 44; j++) { secp256k1_fe_sqr(x88, x88); } secp256k1_fe_mul(x88, x88, x44); x176 = x88.Clone(); for (j = 0; j < 88; j++) { secp256k1_fe_sqr(x176, x176); } secp256k1_fe_mul(x176, x176, x88); x220 = x176.Clone(); for (j = 0; j < 44; j++) { secp256k1_fe_sqr(x220, x220); } secp256k1_fe_mul(x220, x220, x44); x223 = x220.Clone(); for (j = 0; j < 3; j++) { secp256k1_fe_sqr(x223, x223); } secp256k1_fe_mul(x223, x223, x3); /* The final result is then assembled using a sliding window over the blocks. */ t1 = x223.Clone(); for (j = 0; j < 23; j++) { secp256k1_fe_sqr(t1, t1); } secp256k1_fe_mul(t1, t1, x22); for (j = 0; j < 5; j++) { secp256k1_fe_sqr(t1, t1); } secp256k1_fe_mul(t1, t1, a); for (j = 0; j < 3; j++) { secp256k1_fe_sqr(t1, t1); } secp256k1_fe_mul(t1, t1, x2); for (j = 0; j < 2; j++) { secp256k1_fe_sqr(t1, t1); } secp256k1_fe_mul(r, a, t1); }