/* * Mixed comparison: P1 is in Jacobian coordinates, P2 is in * affine coordinates. */ uint EqCTMixed(MutableECPointPrime P1, MutableECPointPrime P2) { /* * If either P1 or P2 is infinity, then they are equal * if and only if they both are infinity. * * If neither is infinity, then we must check the following: * X1 = X2*(Z1^2) * Y1 = Y2*(Z1^3) * Beware that X1, Y1 and Z1 are in Montgomery representation, * while X2 and Y2 are not. */ mt1.Set(P1.mz); mt1.MontySquare(); mt2.Set(P2.mx); mt2.MontyMul(mt1); mt3.Set(P1.mx); mt3.FromMonty(); uint r = mt2.EqCT(mt3); mt1.MontyMul(P1.mz); mt1.MontyMul(P2.my); mt2.Set(P1.my); mt2.FromMonty(); r &= mt1.EqCT(mt2); uint z1z = P1.mz.IsZeroCT; uint z2z = P2.mz.IsZeroCT; return((r & ~(z1z | z2z)) ^ (z1z & z2z)); }
internal override MutableECPoint Dup() { MutableECPointPrime Q = new MutableECPointPrime(curve); Q.Set(this); return(Q); }
internal override MutableECPoint Decode(byte[] enc) { MutableECPointPrime P = new MutableECPointPrime(this); P.Decode(enc); return(P); }
void SetMuxInner(uint ctl, MutableECPointPrime P1, MutableECPointPrime P2) { mx.CopyMux(ctl, P1.mx, P2.mx); my.CopyMux(ctl, P1.my, P2.my); mz.CopyMux(ctl, P1.mz, P2.mz); affine = P2.affine ^ (ctl & (P1.affine ^ P2.affine)); }
internal override void Set(MutableECPoint Q, uint ctl) { MutableECPointPrime R = SameCurve(Q); mx.CondCopy(R.mx, ctl); my.CondCopy(R.my, ctl); mz.CondCopy(R.mz, ctl); affine ^= ctl & (affine ^ R.affine); }
internal override void Set(MutableECPoint Q) { MutableECPointPrime R = SameCurve(Q); mx.Set(R.mx); my.Set(R.my); mz.Set(R.mz); affine = R.affine; }
MutableECPointPrime SameCurve(MutableECPoint Q) { MutableECPointPrime R = Q as MutableECPointPrime; if (R == null || !curve.Equals(R.curve)) { throw new CryptoException("Mixed curves"); } return(R); }
internal override uint EqCT(MutableECPoint Q) { MutableECPointPrime R = SameCurve(Q); if (affine != 0) { if (R.affine != 0) { return(mx.EqCT(R.mx) & my.EqCT(R.my) & mz.EqCT(R.mz)); } else { return(EqCTMixed(R, this)); } } else if (R.affine != 0) { return(EqCTMixed(this, R)); } /* * Both points are in Jacobian coordinates. * If Z1 and Z2 are non-zero, then equality is * achieved if and only if both following equations * are true: * X1*(Z2^2) = X2*(Z1^2) * Y1*(Z2^3) = Y2*(Z1^3) * If Z1 or Z2 is zero, then equality is achieved * if and only if both are zero. */ mt1.Set(mz); mt1.MontySquare(); mt2.Set(R.mz); mt2.MontySquare(); mt3.Set(mx); mt3.MontyMul(mt2); mt4.Set(R.mx); mt4.MontyMul(mt1); uint r = mt3.EqCT(mt4); mt1.MontyMul(mz); mt2.MontyMul(R.mz); mt3.Set(my); mt3.MontyMul(mt2); mt4.Set(R.my); mt4.MontyMul(mt1); r &= mt3.EqCT(mt4); uint z1z = mz.IsZeroCT; uint z2z = R.mz.IsZeroCT; return((r & ~(z1z | z2z)) ^ (z1z & z2z)); }
internal override MutableECPoint MakeGenerator() { /* * We do not have to check the generator, since * it was already done in the constructor. */ MutableECPointPrime G = new MutableECPointPrime(this); G.Set(gx, gy, false); return(G); }
/* * Extra checks: * -- modulus is prime * -- subgroup order is prime * -- generator indeed generates subgroup */ public override void CheckValid() { /* * Check that the modulus is prime. */ if (!BigInt.IsPrime(mod)) { throw new CryptoException( "Invalid curve: modulus is not prime"); } /* * Check that the subgroup order is prime. */ if (!BigInt.IsPrime(SubgroupOrder)) { throw new CryptoException( "Invalid curve: subgroup order is not prime"); } /* * Check that the G point is indeed a generator of the * subgroup. Note that since it has explicit coordinates, * it cannot be the point at infinity; it suffices to * verify that, when multiplied by the subgroup order, * it yields infinity. */ MutableECPointPrime G = new MutableECPointPrime(this); G.Set(gx, gy, false); if (G.MulSpecCT(SubgroupOrder) == 0 || !G.IsInfinity) { throw new CryptoException( "Invalid curve: generator does not match" + " subgroup order"); } /* * TODO: check cofactor. * * If the cofactor is small, then we can simply compute * the complete curve order by multiplying the cofactor * with the subgroup order, and see whether it is in the * proper range with regards to the field cardinal (by * using Hasse's theorem). However, if the cofactor is * larger than the subgroup order, then detecting a * wrong cofactor value is a bit more complex. We could * generate a few random points and multiply them by * the computed order, but this may be expensive. */ }
internal override uint AddCT(MutableECPoint Q) { MutableECPointPrime P2 = SameCurve(Q); if (P2.affine != 0) { ms4.Set(P2.mx); ms5.Set(P2.my); ms6.Set(P2.mz); ms4.ToMonty(); ms5.ToMonty(); ms6.SetMonty(~ms6.IsZeroCT); return(AddCTInner(ms4, ms5, ms6, true)); } else { return(AddCTInner(P2.mx, P2.my, P2.mz, false)); } }
internal override uint MulSpecCT(byte[] n) { uint good = 0xFFFFFFFF; /* * Create and populate window. * * If this instance is 0, then we only add 0 to 0 and * double 0, for which DoubleCT() and AddCT() work * properly. * * If this instance (P) is non-zero, then x*P for all * x in the 1..16 range shall be non-zero and distinct, * since the subgroup order is prime and at least 17. * Thus, we never add two equal points together in the * window construction. * * We MUST ensure that all points are in the same * coordinate convention (affine or Jacobian) to ensure * constant-time execution. TODO: measure to see which * is best: all affine or all Jacobian. All affine implies * 14 or 15 extra divisions, but saves a few hundreds of * multiplications. */ MutableECPointPrime[] w = new MutableECPointPrime[16]; w[0] = new MutableECPointPrime(curve); w[0].ToJacobian(); w[1] = new MutableECPointPrime(curve); w[1].Set(this); w[1].ToJacobian(); for (int i = 2; (i + 1) < w.Length; i += 2) { w[i] = new MutableECPointPrime(curve); w[i].Set(w[i >> 1]); w[i].DoubleCT(); w[i + 1] = new MutableECPointPrime(curve); w[i + 1].Set(w[i]); good &= w[i + 1].AddCT(this); } /* obsolete * for (int i = 0; i < w.Length; i ++) { * w[i].ToAffine(); * w[i].Print("Win " + i); * w[i].ToJacobian(); * } * Console.WriteLine("good = {0}", (int)good); */ /* * Set this value to 0. We also set it already to * Jacobian coordinates, since it will be done that * way anyway. This instance will serve as accumulator. */ mx.Set(0); my.Set(0); mz.Set(0); affine = 0x00000000; /* * We process the multiplier by 4-bit nibbles, starting * with the most-significant one (the high nibble of the * first byte, since we use big-endian notation). * * For each nibble, we perform a constant-time lookup * in the window, to obtain the point to add to the * current value of the accumulator. Thanks to the * conditions on the operands (prime subgroup order and * so on), all the additions below must work. */ MutableECPointPrime t = new MutableECPointPrime(curve); for (int i = (n.Length << 1) - 1; i >= 0; i--) { int b = n[n.Length - 1 - (i >> 1)]; int j = (b >> ((i & 1) << 2)) & 0x0F; for (int k = 0; k < 16; k++) { t.Set(w[k], ~(uint)(((j - k) | (k - j)) >> 31)); } good &= AddCT(t); if (i > 0) { DoubleCT(); DoubleCT(); DoubleCT(); DoubleCT(); } } return(good); }
/* * Checks enforced by the constructor: * -- modulus is odd and at least 80-bit long * -- subgroup order is odd and at least 30-bit long * -- parameters a[] and b[] are lower than modulus * -- coordinates gx and gy are lower than modulus * -- coordinates gx and gy match curve equation */ internal ECCurvePrime(string name, byte[] mod, byte[] a, byte[] b, byte[] gx, byte[] gy, byte[] subgroupOrder, byte[] cofactor) : base(subgroupOrder, cofactor) { this.mod = mod = BigInt.NormalizeBE(mod); int modLen = BigInt.BitLength(mod); if (modLen < 80) { throw new CryptoException( "Invalid curve: modulus is too small"); } if ((mod[mod.Length - 1] & 0x01) == 0) { throw new CryptoException( "Invalid curve: modulus is even"); } int sgLen = BigInt.BitLength(subgroupOrder); if (sgLen < 30) { throw new CryptoException( "Invalid curve: subgroup is too small"); } if ((subgroupOrder[subgroupOrder.Length - 1] & 0x01) == 0) { throw new CryptoException( "Invalid curve: subgroup order is even"); } mp = new ModInt(mod); flen = (modLen + 7) >> 3; pMod4 = mod[mod.Length - 1] & 3; this.a = a = BigInt.NormalizeBE(a); this.b = b = BigInt.NormalizeBE(b); if (BigInt.CompareCT(a, mod) >= 0 || BigInt.CompareCT(b, mod) >= 0) { throw new CryptoException( "Invalid curve: out-of-range parameter"); } ma = mp.Dup(); ma.Decode(a); ma.Add(3); aIsM3 = ma.IsZero; ma.Sub(3); mb = mp.Dup(); mb.Decode(b); this.gx = gx = BigInt.NormalizeBE(gx); this.gy = gy = BigInt.NormalizeBE(gy); if (BigInt.CompareCT(gx, mod) >= 0 || BigInt.CompareCT(gy, mod) >= 0) { throw new CryptoException( "Invalid curve: out-of-range coordinates"); } MutableECPointPrime G = new MutableECPointPrime(this); G.Set(gx, gy, true); hashCode = (int)(BigInt.HashInt(mod) ^ BigInt.HashInt(a) ^ BigInt.HashInt(b) ^ BigInt.HashInt(gx) ^ BigInt.HashInt(gy)); if (name == null) { name = string.Format("generic prime {0}/{1}", modLen, sgLen); } this.name = name; }