//		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);
		}