diff --git a/Src/Autarkysoft.Bitcoin/Cryptography/EllipticCurve/ModInv32.cs b/Src/Autarkysoft.Bitcoin/Cryptography/EllipticCurve/ModInv32.cs index b16d58a..81af446 100644 --- a/Src/Autarkysoft.Bitcoin/Cryptography/EllipticCurve/ModInv32.cs +++ b/Src/Autarkysoft.Bitcoin/Cryptography/EllipticCurve/ModInv32.cs @@ -74,7 +74,7 @@ private static int MulCmp30(in ModInv32Signed30 a, int alen, in ModInv32Signed30 // to it to bring it to range [0,modulus). If sign < 0, the input will also be negated in the // process. The input must have limbs in range (-2^30,2^30). The output will have limbs in range // [0,2^30). - static ModInv32Signed30 secp256k1_modinv32_normalize_30(in ModInv32Signed30 r, int sign, in ModInv32ModInfo modinfo) + private static ModInv32Signed30 Normalize30(in ModInv32Signed30 r, int sign, in ModInv32ModInfo modinfo) { const int M30 = (int)(uint.MaxValue >> 2); int r0 = r.v0, r1 = r.v1, r2 = r.v2, r3 = r.v3, r4 = r.v4, r5 = r.v5, r6 = r.v6, r7 = r.v7, r8 = r.v8; @@ -83,7 +83,7 @@ static ModInv32Signed30 secp256k1_modinv32_normalize_30(in ModInv32Signed30 r, i #if DEBUG // Verify that all limbs are in range (-2^30,2^30). int[] rv = r.GetArray(); - for (int i = 0; i < 9; ++i) + for (int i = 0; i < 9; i++) { Debug.Assert(rv[i] >= -M30); Debug.Assert(rv[i] <= M30); @@ -127,8 +127,8 @@ static ModInv32Signed30 secp256k1_modinv32_normalize_30(in ModInv32Signed30 r, i r7 += r6 >> 30; r6 &= M30; r8 += r7 >> 30; r7 &= M30; - // In a second step add the modulus again if the result is still negative, bringing r to range - // [0,modulus). + // In a second step add the modulus again if the result is still negative, + // bringing r to range [0,modulus). cond_add = r8 >> 31; r0 += modinfo.modulus.v0 & cond_add; r1 += modinfo.modulus.v1 & cond_add; @@ -160,8 +160,8 @@ static ModInv32Signed30 secp256k1_modinv32_normalize_30(in ModInv32Signed30 r, i Debug.Assert(r6 >> 30 == 0); Debug.Assert(r7 >> 30 == 0); Debug.Assert(r8 >> 30 == 0); - Debug.Assert(MulCmp30(result, 9, modinfo.modulus, 0) >= 0); /* r >= 0 */ - Debug.Assert(MulCmp30(result, 9, modinfo.modulus, 1) < 0); /* r < modulus */ + Debug.Assert(MulCmp30(result, 9, modinfo.modulus, 0) >= 0); // r >= 0 + Debug.Assert(MulCmp30(result, 9, modinfo.modulus, 1) < 0); // r < modulus #endif return result; } @@ -176,7 +176,7 @@ static ModInv32Signed30 secp256k1_modinv32_normalize_30(in ModInv32Signed30 r, i // Return: final zeta // // Implements the divsteps_n_matrix function from the explanation. - private static int DivSteps30(int zeta, uint f0, uint g0, out secp256k1_modinv32_trans2x2 t) + private static int DivSteps30(int zeta, uint f0, uint g0, out ModInv32Trans2x2 t) { // u,v,q,r are the elements of the transformation matrix being built up, // starting with the identity matrix. Semantically they are signed integers @@ -218,7 +218,7 @@ private static int DivSteps30(int zeta, uint f0, uint g0, out secp256k1_modinv32 Debug.Assert(zeta >= -601 && zeta <= 601); } // Return data in t and return value. - t = new secp256k1_modinv32_trans2x2(u, v, q, r); + t = new ModInv32Trans2x2(u, v, q, r); // The determinant of t must be a power of two. This guarantees that multiplication with t // does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which @@ -229,7 +229,7 @@ private static int DivSteps30(int zeta, uint f0, uint g0, out secp256k1_modinv32 } // secp256k1_modinv32_inv256[i] = -(2*i+1)^-1 (mod 256) - private static readonly byte[] secp256k1_modinv32_inv256 = new byte[128] + private static readonly byte[] Inv256 = new byte[128] { 0xFF, 0x55, 0x33, 0x49, 0xC7, 0x5D, 0x3B, 0x11, 0x0F, 0xE5, 0xC3, 0x59, 0xD7, 0xED, 0xCB, 0x21, 0x1F, 0x75, 0x53, 0x69, 0xE7, 0x7D, 0x5B, 0x31, @@ -245,8 +245,8 @@ private static int DivSteps30(int zeta, uint f0, uint g0, out secp256k1_modinv32 }; - //https://github.com/bitcoin-core/secp256k1/blob/b314cf28334a91db2fe144d04f86077e2bfd7a25/src/util.h#L310 - static readonly byte[] debruijn = new byte[32] + //https://github.com/bitcoin-core/secp256k1/blob/1a81df826e2a24a1656fc28fc3076b62562216d9/src/util.h#L305 + static readonly byte[] DeBruijn = new byte[32] { 0x00, 0x01, 0x02, 0x18, 0x03, 0x13, 0x06, 0x19, 0x16, 0x04, 0x14, 0x0A, 0x10, 0x07, 0x0C, 0x1A, 0x1F, 0x17, 0x12, 0x05, 0x15, 0x09, 0x0F, 0x0B, @@ -254,11 +254,12 @@ private static int DivSteps30(int zeta, uint f0, uint g0, out secp256k1_modinv32 }; // Determine the number of trailing zero bits in a (non-zero) 32-bit x. [MethodImpl(MethodImplOptions.AggressiveInlining)] - static int secp256k1_ctz32_var(uint x) + static int Ctz32Var(uint x) { // TODO: dotnet 3.0+ have: BitOperations.TrailingZeroCount() Debug.Assert(x != 0); - return debruijn[(uint)((x & -x) * 0x04D7651FU) >> 27]; + // Multi-cast below mitigates the redundant conv.u8 + return DeBruijn[((x & (uint)-(int)x) * 0x04D7651FU) >> 27]; } @@ -271,34 +272,37 @@ static int secp256k1_ctz32_var(uint x) // Return: final eta // // Implements the divsteps_n_matrix_var function from the explanation. - static int secp256k1_modinv32_divsteps_30_var(int eta, uint f0, uint g0, out secp256k1_modinv32_trans2x2 t) + static int DivSteps30Var(int eta, uint f0, uint g0, out ModInv32Trans2x2 t) { - // Transformation matrix; see comments in secp256k1_modinv32_divsteps_30. + // Transformation matrix; see comments in DivSteps30(). uint u = 1, v = 0, q = 0, r = 1; uint f = f0, g = g0, m; ushort w; int i = 30, limit, zeros; - for (; ; ) + while (true) { // Use a sentinel bit to count zeros only up to i. - zeros = secp256k1_ctz32_var(g | (uint.MaxValue << i)); - /* Perform zeros divsteps at once; they all just divide g by two. */ + zeros = Ctz32Var(g | (uint.MaxValue << i)); + // Perform zeros divsteps at once; they all just divide g by two. g >>= zeros; u <<= zeros; v <<= zeros; eta -= zeros; i -= zeros; - /* We're done once we've done 30 divsteps. */ + // We're done once we've done 30 divsteps. if (i == 0) + { break; + } + Debug.Assert((f & 1) == 1); Debug.Assert((g & 1) == 1); Debug.Assert((u * f0 + v * g0) == f << (30 - i)); Debug.Assert((q * f0 + r * g0) == g << (30 - i)); - /* Bounds on eta that follow from the bounds on iteration count (max 25*30 divsteps). */ + // Bounds on eta that follow from the bounds on iteration count (max 25*30 divsteps). Debug.Assert(eta >= -751 && eta <= 751); - /* If eta is negative, negate it and replace f,g with g,-f. */ + // If eta is negative, negate it and replace f,g with g,-f. if (eta < 0) { uint tmp; @@ -307,23 +311,23 @@ static int secp256k1_modinv32_divsteps_30_var(int eta, uint f0, uint g0, out sec tmp = u; u = q; q = (uint)-tmp; tmp = v; v = r; r = (uint)-tmp; } - /* eta is now >= 0. In what follows we're going to cancel out the bottom bits of g. No more - * than i can be cancelled out (as we'd be done before that point), and no more than eta+1 - * can be done as its sign will flip once that happens. */ + // eta is now >= 0. In what follows we're going to cancel out the bottom bits of g. No more + // than i can be cancelled out (as we'd be done before that point), and no more than eta+1 + // can be done as its sign will flip once that happens. limit = (eta + 1) > i ? i : (eta + 1); - /* m is a mask for the bottom min(limit, 8) bits (our table only supports 8 bits). */ + // m is a mask for the bottom min(limit, 8) bits (our table only supports 8 bits). Debug.Assert(limit > 0 && limit <= 30); m = (uint.MaxValue >> (32 - limit)) & 255U; - /* Find what multiple of f must be added to g to cancel its bottom min(limit, 8) bits. */ - w = (ushort)((g * secp256k1_modinv32_inv256[(f >> 1) & 127]) & m); - /* Do so. */ + // Find what multiple of f must be added to g to cancel its bottom min(limit, 8) bits. + w = (ushort)((g * Inv256[(f >> 1) & 127]) & m); + // Do so g += f * w; q += u * w; r += v * w; Debug.Assert((g & m) == 0); } // Return data in t and return value. - t = new secp256k1_modinv32_trans2x2(u, v, q, r); + t = new ModInv32Trans2x2(u, v, q, r); // The determinant of t must be a power of two. This guarantees that multiplication with t // does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which // will be divided out again). As each divstep's individual matrix has determinant 2, the @@ -332,20 +336,24 @@ static int secp256k1_modinv32_divsteps_30_var(int eta, uint f0, uint g0, out sec return eta; } - /* Compute the transition matrix and eta for 30 posdivsteps (variable time, eta=-delta), and keeps track - * of the Jacobi symbol along the way. f0 and g0 must be f and g mod 2^32 rather than 2^30, because - * Jacobi tracking requires knowing (f mod 8) rather than just (f mod 2). - * - * Input: eta: initial eta - * f0: bottom limb of initial f - * g0: bottom limb of initial g - * Output: t: transition matrix - * Input/Output: (*jacp & 1) is bitflipped if and only if the Jacobi symbol of (f | g) changes sign - * by applying the returned transformation matrix to it. The other bits of *jacp may - * change, but are meaningless. - * Return: final eta - */ - static int secp256k1_modinv32_posdivsteps_30_var(int eta, uint f0, uint g0, secp256k1_modinv32_trans2x2 t, ref int jacp) + + /// + /// Compute the transition matrix and eta for 30 posdivsteps (variable time, eta=-delta), and keeps track + /// of the Jacobi symbol along the way. f0 and g0 must be f and g mod 2^32 rather than 2^30, because + /// Jacobi tracking requires knowing (f mod 8) rather than just (f mod 2). + /// + /// + /// (*jacp & 1) is bitflipped if and only if the Jacobi symbol of (f | g) changes sign + /// by applying the returned transformation matrix to it. The other bits of *jacp may + /// change, but are meaningless. + /// + /// initial eta + /// bottom limb of initial f + /// bottom limb of initial g + /// transition matrix + /// + /// final eta + static int PosDivSteps30Var(int eta, uint f0, uint g0, ModInv32Trans2x2 t, ref int jacp) { /* Transformation matrix. */ uint u = 1, v = 0, q = 0, r = 1; @@ -354,10 +362,10 @@ static int secp256k1_modinv32_posdivsteps_30_var(int eta, uint f0, uint g0, secp int i = 30, limit, zeros; int jac = jacp; - for (; ; ) + while (true) { /* Use a sentinel bit to count zeros only up to i. */ - zeros = secp256k1_ctz32_var(g | (uint.MaxValue << i)); + zeros = Ctz32Var(g | (uint.MaxValue << i)); /* Perform zeros divsteps at once; they all just divide g by two. */ g >>= zeros; u <<= zeros; @@ -393,7 +401,7 @@ static int secp256k1_modinv32_posdivsteps_30_var(int eta, uint f0, uint g0, secp Debug.Assert(limit > 0 && limit <= 30); m = (uint.MaxValue >> (32 - limit)) & 255U; /* Find what multiple of f must be added to g to cancel its bottom min(limit, 8) bits. */ - w = (ushort)((g * secp256k1_modinv32_inv256[(f >> 1) & 127]) & m); + w = (ushort)((g * Inv256[(f >> 1) & 127]) & m); /* Do so. */ g += f * w; q += u * w; @@ -416,22 +424,15 @@ static int secp256k1_modinv32_posdivsteps_30_var(int eta, uint f0, uint g0, secp } - /// - /// Compute (t/2^30) * [d, e] mod modulus, where t is a transition matrix for 30 divsteps. - /// - /// On input and output, d and e are in range (-2*modulus,modulus). All output limbs will be - /// in range (-2^30,2^30). - /// - /// This implements the update_de function from the explanation. - /// - /// - /// - /// - /// - internal static void UpdateDE30(ref ModInv32Signed30 d, ref ModInv32Signed30 e, secp256k1_modinv32_trans2x2 t, in ModInv32ModInfo modinfo) + // Compute (t/2^30) * [d, e] mod modulus, where t is a transition matrix for 30 divsteps. + // + // On input and output, d and e are in range (-2*modulus,modulus). All output limbs will be + // in range (-2^30,2^30). + // + // This implements the update_de function from the explanation. + internal static void UpdateDE30(ref ModInv32Signed30 d, ref ModInv32Signed30 e, ModInv32Trans2x2 t, in ModInv32ModInfo modinfo) { const int M30 = (int)(uint.MaxValue >> 2); - int u = t.u, v = t.v, q = t.q, r = t.r; int di, ei, md, me, sd, se; long cd, ce; #if DEBUG @@ -439,19 +440,19 @@ internal static void UpdateDE30(ref ModInv32Signed30 d, ref ModInv32Signed30 e, Debug.Assert(MulCmp30(d, 9, modinfo.modulus, 1) < 0); // d < modulus Debug.Assert(MulCmp30(e, 9, modinfo.modulus, -2) > 0); // e > -2*modulus Debug.Assert(MulCmp30(e, 9, modinfo.modulus, 1) < 0); // e < modulus - Debug.Assert(Math.Abs(u) <= (M30 + 1 - Math.Abs(v))); // |u|+|v| <= 2^30 - Debug.Assert(Math.Abs(q) <= (M30 + 1 - Math.Abs(r))); // |q|+|r| <= 2^30 + Debug.Assert(Math.Abs(t.u) <= (M30 + 1 - Math.Abs(t.v))); // |u|+|v| <= 2^30 + Debug.Assert(Math.Abs(t.q) <= (M30 + 1 - Math.Abs(t.r))); // |q|+|r| <= 2^30 #endif // [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. sd = d.v8 >> 31; se = e.v8 >> 31; - md = (u & sd) + (v & se); - me = (q & sd) + (r & se); + md = (t.u & sd) + (t.v & se); + me = (t.q & sd) + (t.r & se); // Begin computing t*[d,e] di = d.v0; ei = e.v0; - cd = (long)u * di + (long)v * ei; - ce = (long)q * di + (long)r * ei; + cd = (long)t.u * di + (long)t.v * ei; + ce = (long)t.q * di + (long)t.r * ei; // Correct md,me so that t*[d,e]+modulus*[md,me] has 30 zero bottom bits. md -= (int)((modinfo.modulus_inv30 * (uint)cd + md) & M30); me -= (int)((modinfo.modulus_inv30 * (uint)ce + me) & M30); @@ -466,65 +467,62 @@ internal static void UpdateDE30(ref ModInv32Signed30 d, ref ModInv32Signed30 e, int[] dv = d.GetArray(); int[] ev = e.GetArray(); int[] modv = modinfo.modulus.GetArray(); - for (int i = 1; i < 9; ++i) + for (int i = 1; i < 9; i++) { di = dv[i]; ei = ev[i]; - cd += (long)u * di + (long)v * ei; - ce += (long)q * di + (long)r * ei; + cd += (long)t.u * di + (long)t.v * ei; + ce += (long)t.q * di + (long)t.r * ei; cd += (long)modv[i] * md; ce += (long)modv[i] * me; dv[i - 1] = (int)cd & M30; cd >>= 30; ev[i - 1] = (int)ce & M30; ce >>= 30; } - /* What remains is limb 9 of t*[d,e]+modulus*[md,me]; store it as output limb 8. */ + // What remains is limb 9 of t*[d,e]+modulus*[md,me]; store it as output limb 8. dv[8] = (int)cd; ev[8] = (int)ce; d = new ModInv32Signed30(dv); e = new ModInv32Signed30(ev); #if DEBUG - Debug.Assert(MulCmp30(d, 9, modinfo.modulus, -2) > 0); /* d > -2*modulus */ - Debug.Assert(MulCmp30(d, 9, modinfo.modulus, 1) < 0); /* d < modulus */ - Debug.Assert(MulCmp30(e, 9, modinfo.modulus, -2) > 0); /* e > -2*modulus */ - Debug.Assert(MulCmp30(e, 9, modinfo.modulus, 1) < 0); /* e < modulus */ + Debug.Assert(MulCmp30(d, 9, modinfo.modulus, -2) > 0); // d > -2*modulus + Debug.Assert(MulCmp30(d, 9, modinfo.modulus, 1) < 0); // d < modulus + Debug.Assert(MulCmp30(e, 9, modinfo.modulus, -2) > 0); // e > -2*modulus + Debug.Assert(MulCmp30(e, 9, modinfo.modulus, 1) < 0); // e < modulus #endif } - /* Compute (t/2^30) * [f, g], where t is a transition matrix for 30 divsteps. - * - * This implements the update_fg function from the explanation. - */ - static void secp256k1_modinv32_update_fg_30(ref ModInv32Signed30 f, ref ModInv32Signed30 g, secp256k1_modinv32_trans2x2 t) + // Compute (t/2^30) * [f, g], where t is a transition matrix for 30 divsteps. + // + // This implements the update_fg function from the explanation. + static void UpdateFG30(ref ModInv32Signed30 f, ref ModInv32Signed30 g, ModInv32Trans2x2 t) { const int M30 = (int)(uint.MaxValue >> 2); - int u = t.u, v = t.v, q = t.q, r = t.r; int fi, gi; long cf, cg; - int i; - /* Start computing t*[f,g]. */ + // Start computing t*[f,g]. fi = f.v0; gi = g.v0; - cf = (long)u * fi + (long)v * gi; - cg = (long)q * fi + (long)r * gi; - /* Verify that the bottom 30 bits of the result are zero, and then throw them away. */ + cf = (long)t.u * fi + (long)t.v * gi; + cg = (long)t.q * fi + (long)t.r * gi; + // Verify that the bottom 30 bits of the result are zero, and then throw them away. Debug.Assert(((int)cf & M30) == 0); cf >>= 30; Debug.Assert(((int)cg & M30) == 0); cg >>= 30; - /* Now iteratively compute limb i=1..8 of t*[f,g], and store them in output limb i-1 (shifting - * down by 30 bits). */ + // Now iteratively compute limb i=1..8 of t*[f,g], and store them in output limb i-1 (shifting + // down by 30 bits). int[] fv = f.GetArray(); int[] gv = g.GetArray(); - for (i = 1; i < 9; ++i) + for (int i = 1; i < 9; i++) { fi = fv[i]; gi = gv[i]; - cf += (long)u * fi + (long)v * gi; - cg += (long)q * fi + (long)r * gi; + cf += (long)t.u * fi + (long)t.v * gi; + cg += (long)t.q * fi + (long)t.r * gi; fv[i - 1] = (int)cf & M30; cf >>= 30; gv[i - 1] = (int)cg & M30; cg >>= 30; } - /* What remains is limb 9 of t*[f,g]; store it as output limb 8. */ + // What remains is limb 9 of t*[f,g]; store it as output limb 8. fv[8] = (int)cf; gv[8] = (int)cg; @@ -532,42 +530,39 @@ static void secp256k1_modinv32_update_fg_30(ref ModInv32Signed30 f, ref ModInv32 g = new ModInv32Signed30(gv); } - /* Compute (t/2^30) * [f, g], where t is a transition matrix for 30 divsteps. - * - * Version that operates on a variable number of limbs in f and g. - * - * This implements the update_fg function from the explanation in modinv64_impl.h. - */ - static void secp256k1_modinv32_update_fg_30_var(int len, ref ModInv32Signed30 f, ref ModInv32Signed30 g, secp256k1_modinv32_trans2x2 t) + // Compute (t/2^30) * [f, g], where t is a transition matrix for 30 divsteps. + // + // Version that operates on a variable number of limbs in f and g. + // + // This implements the update_fg function from the explanation in modinv64_impl.h. + static void UpdateFG30Var(int len, ref ModInv32Signed30 f, ref ModInv32Signed30 g, ModInv32Trans2x2 t) { const int M30 = (int)(uint.MaxValue >> 2); - int u = t.u, v = t.v, q = t.q, r = t.r; int fi, gi; long cf, cg; - int i; Debug.Assert(len > 0); - /* Start computing t*[f,g]. */ + // Start computing t*[f,g]. fi = f.v0; gi = g.v0; - cf = (long)u * fi + (long)v * gi; - cg = (long)q * fi + (long)r * gi; - /* Verify that the bottom 62 bits of the result are zero, and then throw them away. */ + cf = (long)t.u * fi + (long)t.v * gi; + cg = (long)t.q * fi + (long)t.r * gi; + // Verify that the bottom 62 bits of the result are zero, and then throw them away. Debug.Assert(((int)cf & M30) == 0); cf >>= 30; Debug.Assert(((int)cg & M30) == 0); cg >>= 30; - /* Now iteratively compute limb i=1..len of t*[f,g], and store them in output limb i-1 (shifting - * down by 30 bits). */ + // Now iteratively compute limb i=1..len of t*[f,g], and store them in output limb i-1 (shifting + // down by 30 bits). int[] fv = f.GetArray(); int[] gv = g.GetArray(); - for (i = 1; i < len; ++i) + for (int i = 1; i < len; i++) { fi = fv[i]; gi = gv[i]; - cf += (long)u * fi + (long)v * gi; - cg += (long)q * fi + (long)r * gi; + cf += (long)t.u * fi + (long)t.v * gi; + cg += (long)t.q * fi + (long)t.r * gi; fv[i - 1] = (int)cf & M30; cf >>= 30; gv[i - 1] = (int)cg & M30; cg >>= 30; } - /* What remains is limb (len) of t*[f,g]; store it as output limb (len-1). */ + // What remains is limb (len) of t*[f,g]; store it as output limb (len-1). fv[len - 1] = (int)cf; gv[len - 1] = (int)cg; @@ -599,32 +594,32 @@ public static void Compute(ref ModInv32Signed30 x, in ModInv32ModInfo modinfo) for (int i = 0; i < 20; i++) { // Compute transition matrix and new zeta after 30 divsteps. - zeta = DivSteps30(zeta, (uint)f.v0, (uint)g.v0, out secp256k1_modinv32_trans2x2 t); + zeta = DivSteps30(zeta, (uint)f.v0, (uint)g.v0, out ModInv32Trans2x2 t); // Update d,e using that transition matrix. UpdateDE30(ref d, ref e, t, modinfo); - /* Update f,g using that transition matrix. */ + // Update f,g using that transition matrix. #if DEBUG - Debug.Assert(MulCmp30(f, 9, modinfo.modulus, -1) > 0); /* f > -modulus */ - Debug.Assert(MulCmp30(f, 9, modinfo.modulus, 1) <= 0); /* f <= modulus */ - Debug.Assert(MulCmp30(g, 9, modinfo.modulus, -1) > 0); /* g > -modulus */ - Debug.Assert(MulCmp30(g, 9, modinfo.modulus, 1) < 0); /* g < modulus */ + Debug.Assert(MulCmp30(f, 9, modinfo.modulus, -1) > 0); // f > -modulus + Debug.Assert(MulCmp30(f, 9, modinfo.modulus, 1) <= 0); // f <= modulus + Debug.Assert(MulCmp30(g, 9, modinfo.modulus, -1) > 0); // g > -modulus + Debug.Assert(MulCmp30(g, 9, modinfo.modulus, 1) < 0); // g < modulus #endif - secp256k1_modinv32_update_fg_30(ref f, ref g, t); + UpdateFG30(ref f, ref g, t); #if DEBUG - Debug.Assert(MulCmp30(f, 9, modinfo.modulus, -1) > 0); /* f > -modulus */ - Debug.Assert(MulCmp30(f, 9, modinfo.modulus, 1) <= 0); /* f <= modulus */ - Debug.Assert(MulCmp30(g, 9, modinfo.modulus, -1) > 0); /* g > -modulus */ - Debug.Assert(MulCmp30(g, 9, modinfo.modulus, 1) < 0); /* g < modulus */ + Debug.Assert(MulCmp30(f, 9, modinfo.modulus, -1) > 0); // f > -modulus + Debug.Assert(MulCmp30(f, 9, modinfo.modulus, 1) <= 0); // f <= modulus + Debug.Assert(MulCmp30(g, 9, modinfo.modulus, -1) > 0); // g > -modulus + Debug.Assert(MulCmp30(g, 9, modinfo.modulus, 1) < 0); // g < modulus #endif } - /* At this point sufficient iterations have been performed that g must have reached 0 - * and (if g was not originally 0) f must now equal +/- GCD of the initial f, g - * values i.e. +/- 1, and d now contains +/- the modular inverse. */ + // At this point sufficient iterations have been performed that g must have reached 0 + // and (if g was not originally 0) f must now equal +/- GCD of the initial f, g + // values i.e. +/- 1, and d now contains +/- the modular inverse. #if DEBUG - /* g == 0 */ + // g == 0 Debug.Assert(MulCmp30(g, 9, ModInv32Signed30.One, 0) == 0); - /* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */ + // |f| == 1, or (x == 0 and d == 0 and |f|=modulus) Debug.Assert(MulCmp30(f, 9, ModInv32Signed30.One, -1) == 0 || MulCmp30(f, 9, ModInv32Signed30.One, 1) == 0 || (MulCmp30(x, 9, ModInv32Signed30.One, 0) == 0 && @@ -633,9 +628,8 @@ public static void Compute(ref ModInv32Signed30 x, in ModInv32ModInfo modinfo) MulCmp30(f, 9, modinfo.modulus, -1) == 0))); #endif - /* Optionally negate d, normalize to [0,modulus), and return it. */ - x = secp256k1_modinv32_normalize_30(d, f.v8, modinfo); - + // Optionally negate d, normalize to [0,modulus), and return it. + x = Normalize30(d, f.v8, modinfo); } @@ -650,7 +644,7 @@ public static void Compute(ref ModInv32Signed30 x, in ModInv32ModInfo modinfo) /// public static void ComputeVar(ref ModInv32Signed30 x, ModInv32ModInfo modinfo) { - /* Start with d=0, e=1, f=modulus, g=x, eta=-1. */ + // Start with d=0, e=1, f=modulus, g=x, eta=-1. ModInv32Signed30 d = ModInv32Signed30.Zero; ModInv32Signed30 e = ModInv32Signed30.One; ModInv32Signed30 f = modinfo.modulus; @@ -659,48 +653,47 @@ public static void ComputeVar(ref ModInv32Signed30 x, ModInv32ModInfo modinfo) int i = 0; #endif int j, len = 9; - int eta = -1; /* eta = -delta; delta is initially 1 (faster for the variable-time code) */ + int eta = -1; // eta = -delta; delta is initially 1 (faster for the variable-time code) int cond, fn, gn; - /* Do iterations of 30 divsteps each until g=0. */ + // Do iterations of 30 divsteps each until g=0. while (true) { - /* Compute transition matrix and new eta after 30 divsteps. */ - secp256k1_modinv32_trans2x2 t; - eta = secp256k1_modinv32_divsteps_30_var(eta, (uint)f.v0, (uint)g.v0, out t); - /* Update d,e using that transition matrix. */ + // Compute transition matrix and new eta after 30 divsteps. + eta = DivSteps30Var(eta, (uint)f.v0, (uint)g.v0, out ModInv32Trans2x2 t); + // Update d,e using that transition matrix. UpdateDE30(ref d, ref e, t, modinfo); - /* Update f,g using that transition matrix. */ + // Update f,g using that transition matrix. # if DEBUG Debug.Assert(MulCmp30(f, len, modinfo.modulus, -1) > 0); /* f > -modulus */ Debug.Assert(MulCmp30(f, len, modinfo.modulus, 1) <= 0); /* f <= modulus */ Debug.Assert(MulCmp30(g, len, modinfo.modulus, -1) > 0); /* g > -modulus */ Debug.Assert(MulCmp30(g, len, modinfo.modulus, 1) < 0); /* g < modulus */ #endif - secp256k1_modinv32_update_fg_30_var(len, ref f, ref g, t); + UpdateFG30Var(len, ref f, ref g, t); - /* If the bottom limb of g is 0, there is a chance g=0. */ + // If the bottom limb of g is 0, there is a chance g=0. int[] fv = f.GetArray(); int[] gv = g.GetArray(); if (gv[0] == 0) { cond = 0; - /* Check if all other limbs are also 0. */ + // Check if all other limbs are also 0. for (j = 1; j < len; ++j) { cond |= gv[j]; } - /* If so, we're done. */ + // If so, we're done. if (cond == 0) break; } - /* Determine if len>1 and limb (len-1) of both f and g is 0 or -1. */ + // Determine if len>1 and limb (len-1) of both f and g is 0 or -1. fn = fv[len - 1]; gn = gv[len - 1]; cond = (len - 2) >> 31; cond |= fn ^ (fn >> 31); cond |= gn ^ (gn >> 31); - /* If so, reduce length, propagating the sign of f and g's top limb into the one below. */ + // If so, reduce length, propagating the sign of f and g's top limb into the one below. if (cond == 0) { fv[len - 2] |= fn << 30; @@ -711,20 +704,20 @@ public static void ComputeVar(ref ModInv32Signed30 x, ModInv32ModInfo modinfo) f = new ModInv32Signed30(fv); g = new ModInv32Signed30(gv); #if DEBUG - Debug.Assert(++i < 25); /* We should never need more than 25*30 = 750 divsteps */ - Debug.Assert(MulCmp30(f, len, modinfo.modulus, -1) > 0); /* f > -modulus */ - Debug.Assert(MulCmp30(f, len, modinfo.modulus, 1) <= 0); /* f <= modulus */ - Debug.Assert(MulCmp30(g, len, modinfo.modulus, -1) > 0); /* g > -modulus */ - Debug.Assert(MulCmp30(g, len, modinfo.modulus, 1) < 0); /* g < modulus */ + Debug.Assert(++i < 25); // We should never need more than 25*30 = 750 divsteps + Debug.Assert(MulCmp30(f, len, modinfo.modulus, -1) > 0); // f > -modulus + Debug.Assert(MulCmp30(f, len, modinfo.modulus, 1) <= 0); // f <= modulus + Debug.Assert(MulCmp30(g, len, modinfo.modulus, -1) > 0); // g > -modulus + Debug.Assert(MulCmp30(g, len, modinfo.modulus, 1) < 0); // g < modulus #endif } - /* At this point g is 0 and (if g was not originally 0) f must now equal +/- GCD of - * the initial f, g values i.e. +/- 1, and d now contains +/- the modular inverse. */ + // At this point g is 0 and (if g was not originally 0) f must now equal +/- GCD of + // the initial f, g values i.e. +/- 1, and d now contains +/- the modular inverse. #if DEBUG - /* g == 0 */ + // g == 0 Debug.Assert(MulCmp30(g, len, ModInv32Signed30.One, 0) == 0); - /* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */ + // |f| == 1, or (x == 0 and d == 0 and |f|=modulus) Debug.Assert(MulCmp30(f, len, ModInv32Signed30.One, -1) == 0 || MulCmp30(f, len, ModInv32Signed30.One, 1) == 0 || (MulCmp30(x, 9, ModInv32Signed30.One, 0) == 0 && @@ -733,9 +726,9 @@ public static void ComputeVar(ref ModInv32Signed30 x, ModInv32ModInfo modinfo) MulCmp30(f, len, modinfo.modulus, -1) == 0))); #endif - /* Optionally negate d, normalize to [0,modulus), and return it. */ + // Optionally negate d, normalize to [0,modulus), and return it. int[] tempArr = f.GetArray(); - x = secp256k1_modinv32_normalize_30(d, tempArr[len - 1], modinfo); + x = Normalize30(d, tempArr[len - 1], modinfo); } } } diff --git a/Src/Autarkysoft.Bitcoin/Cryptography/EllipticCurve/ModInv32ModInfo.cs b/Src/Autarkysoft.Bitcoin/Cryptography/EllipticCurve/ModInv32ModInfo.cs index e09b976..56d1b43 100644 --- a/Src/Autarkysoft.Bitcoin/Cryptography/EllipticCurve/ModInv32ModInfo.cs +++ b/Src/Autarkysoft.Bitcoin/Cryptography/EllipticCurve/ModInv32ModInfo.cs @@ -23,16 +23,16 @@ public ModInv32ModInfo(in ModInv32Signed30 mod, uint modinv30) internal static ref readonly ModInv32ModInfo Constant => ref _const; } - internal class secp256k1_modinv32_trans2x2 + internal class ModInv32Trans2x2 { - internal secp256k1_modinv32_trans2x2(uint u, uint v, uint q, uint r) + internal ModInv32Trans2x2(uint u, uint v, uint q, uint r) { this.u = (int)u; this.v = (int)v; this.q = (int)q; this.r = (int)r; } - internal secp256k1_modinv32_trans2x2(int u, int v, int q, int r) + internal ModInv32Trans2x2(int u, int v, int q, int r) { this.u = u; this.v = v; diff --git a/Src/Autarkysoft.Bitcoin/Cryptography/EllipticCurve/ModInv32Signed30.cs b/Src/Autarkysoft.Bitcoin/Cryptography/EllipticCurve/ModInv32Signed30.cs index bc6840e..5168559 100644 --- a/Src/Autarkysoft.Bitcoin/Cryptography/EllipticCurve/ModInv32Signed30.cs +++ b/Src/Autarkysoft.Bitcoin/Cryptography/EllipticCurve/ModInv32Signed30.cs @@ -3,6 +3,7 @@ // Distributed under the MIT software license, see the accompanying // file LICENCE or http://www.opensource.org/licenses/mit-license.php. +using System; using System.Diagnostics; namespace Autarkysoft.Bitcoin.Cryptography.EllipticCurve @@ -30,7 +31,7 @@ public ModInv32Signed30(int a0, int a1, int a2, int a3, int a4, int a5, int a6, v4 = a4; v5 = a5; v6 = a6; v7 = a7; v8 = a8; } - public ModInv32Signed30(int[] arr) + public ModInv32Signed30(ReadOnlySpan arr) { Debug.Assert(arr.Length == 9); v0 = arr[0]; v1 = arr[1]; v2 = arr[2]; v3 = arr[3];