// private static BigInteger W(BigInteger n, BigInteger wOne, BigInteger p) // { // if (n.Equals(BigInteger.One)) // return wOne; // // bool isEven = !n.TestBit(0); // n = n.ShiftRight(1); // if (isEven) // { // BigInteger w = W(n, wOne, p); // return w.Multiply(w).Subtract(BigInteger.Two).Mod(p); // } // BigInteger w1 = W(n.Add(BigInteger.One), wOne, p); // BigInteger w2 = W(n, wOne, p); // return w1.Multiply(w2).Subtract(wOne).Mod(p); // } // // private BigInteger WOne(BigInteger r, BigInteger x, BigInteger p) // { // return r.Multiply(r).Multiply(x.ModPow(q.Subtract(BigInteger.Two), q)).Subtract(BigInteger.Two).Mod(p); // } private static BigInteger[] fastLucasSequence( BigInteger p, BigInteger P, BigInteger Q, BigInteger k) { // TODO Research and apply "common-multiplicand multiplication here" int n = k.BitLength; int s = k.GetLowestSetBit(); Debug.Assert(k.TestBit(s)); BigInteger Uh = BigInteger.One; BigInteger Vl = BigInteger.Two; BigInteger Vh = P; BigInteger Ql = BigInteger.One; BigInteger Qh = BigInteger.One; for (int j = n - 1; j >= s + 1; --j) { Ql = Ql.Multiply(Qh).Mod(p); if (k.TestBit(j)) { Qh = Ql.Multiply(Q).Mod(p); Uh = Uh.Multiply(Vh).Mod(p); Vl = Vh.Multiply(Vl).Subtract(P.Multiply(Ql)).Mod(p); Vh = Vh.Multiply(Vh).Subtract(Qh.ShiftLeft(1)).Mod(p); } else { Qh = Ql; Uh = Uh.Multiply(Vl).Subtract(Ql).Mod(p); Vh = Vh.Multiply(Vl).Subtract(P.Multiply(Ql)).Mod(p); Vl = Vl.Multiply(Vl).Subtract(Ql.ShiftLeft(1)).Mod(p); } } Ql = Ql.Multiply(Qh).Mod(p); Qh = Ql.Multiply(Q).Mod(p); Uh = Uh.Multiply(Vl).Subtract(Ql).Mod(p); Vl = Vh.Multiply(Vl).Subtract(P.Multiply(Ql)).Mod(p); Ql = Ql.Multiply(Qh).Mod(p); for (int j = 1; j <= s; ++j) { Uh = Uh.Multiply(Vl).Mod(p); Vl = Vl.Multiply(Vl).Subtract(Ql.ShiftLeft(1)).Mod(p); Ql = Ql.Multiply(Ql).Mod(p); } return new BigInteger[]{ Uh, Vl }; }
// D.1.4 91 /** * return a sqrt root - the routine verifies that the calculation * returns the right value - if none exists it returns null. */ public override ECFieldElement Sqrt() { if (!q.TestBit(0)) throw new NotImplementedException("even value of q"); // p mod 4 == 3 if (q.TestBit(1)) { // TODO Can this be optimised (inline the Square?) // z = g^(u+1) + p, p = 4u + 3 ECFieldElement z = new FpFieldElement(q, x.ModPow(q.ShiftRight(2).Add(BigInteger.One), q)); return z.Square().Equals(this) ? z : null; } // p mod 4 == 1 BigInteger qMinusOne = q.Subtract(BigInteger.One); BigInteger legendreExponent = qMinusOne.ShiftRight(1); if (!(x.ModPow(legendreExponent, q).Equals(BigInteger.One))) return null; BigInteger u = qMinusOne.ShiftRight(2); BigInteger k = u.ShiftLeft(1).Add(BigInteger.One); BigInteger Q = this.x; BigInteger fourQ = Q.ShiftLeft(2).Mod(q); BigInteger U, V; do { Random rand = new Random(); BigInteger P; do { P = new BigInteger(q.BitLength, rand); } while (P.CompareTo(q) >= 0 || !(P.Multiply(P).Subtract(fourQ).ModPow(legendreExponent, q).Equals(qMinusOne))); BigInteger[] result = fastLucasSequence(q, P, Q, k); U = result[0]; V = result[1]; if (V.Multiply(V).Mod(q).Equals(fourQ)) { // Integer division by 2, mod q if (V.TestBit(0)) { V = V.Add(q); } V = V.ShiftRight(1); Debug.Assert(V.Multiply(V).Mod(q).Equals(x)); return new FpFieldElement(q, V); } } while (U.Equals(BigInteger.One) || U.Equals(qMinusOne)); return null; // BigInteger qMinusOne = q.Subtract(BigInteger.One); // // BigInteger legendreExponent = qMinusOne.ShiftRight(1); // if (!(x.ModPow(legendreExponent, q).Equals(BigInteger.One))) // return null; // // Random rand = new Random(); // BigInteger fourX = x.ShiftLeft(2); // // BigInteger r; // do // { // r = new BigInteger(q.BitLength, rand); // } // while (r.CompareTo(q) >= 0 // || !(r.Multiply(r).Subtract(fourX).ModPow(legendreExponent, q).Equals(qMinusOne))); // // BigInteger n1 = qMinusOne.ShiftRight(2); // BigInteger n2 = n1.Add(BigInteger.One); // // BigInteger wOne = WOne(r, x, q); // BigInteger wSum = W(n1, wOne, q).Add(W(n2, wOne, q)).Mod(q); // BigInteger twoR = r.ShiftLeft(1); // // BigInteger root = twoR.ModPow(q.Subtract(BigInteger.Two), q) // .Multiply(x).Mod(q) // .Multiply(wSum).Mod(q); // // return new FpFieldElement(q, root); }