public static void MontgomeryTrick(ECFieldElement[] zs, int off, int len) { /* * Uses the "Montgomery Trick" to invert many field elements, with only a single actual * field inversion. See e.g. the paper: * "Fast Multi-scalar Multiplication Methods on Elliptic Curves with Precomputation Strategy Using Montgomery Trick" * by Katsuyuki Okeya, Kouichi Sakurai. */ ECFieldElement[] c = new ECFieldElement[len]; c[0] = zs[off]; int i = 0; while (++i < len) { c[i] = c[i - 1].Multiply(zs[off + i]); } ECFieldElement u = c[--i].Invert(); while (i > 0) { int j = off + i--; ECFieldElement tmp = zs[j]; zs[j] = c[i].Multiply(u); u = u.Multiply(tmp); } zs[off] = u; }
public virtual bool Equals(ECFieldElement other) { if (this == other) return true; if (null == other) return false; return ToBigInteger().Equals(other.ToBigInteger()); }
protected FpCurve(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor) : base(q) { this.m_q = q; this.m_r = r; this.m_infinity = new FpPoint(this, null, null); this.m_a = a; this.m_b = b; this.m_order = order; this.m_cofactor = cofactor; this.m_coord = FP_DEFAULT_COORDS; }
public override ECPoint ScaleY(ECFieldElement scale) { if (this.IsInfinity) return this; switch (CurveCoordinateSystem) { case ECCurve.COORD_LAMBDA_AFFINE: case ECCurve.COORD_LAMBDA_PROJECTIVE: { ECFieldElement X = RawXCoord, L = RawYCoord; // Y is actually Lambda (X + Y/X) here ECFieldElement L2 = L.Add(X).Multiply(scale).Add(X); return Curve.CreateRawPoint(X, L2, RawZCoords, IsCompressed); } default: { return base.ScaleY(scale); } } }
internal F2mPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression) : base(curve, x, y, zs, withCompression) { }
/** * @param curve base curve * @param x x point * @param y y point */ public F2mPoint( ECCurve curve, ECFieldElement x, ECFieldElement y) : this(curve, x, y, false) { }
protected virtual ECPoint CreateScaledPoint(ECFieldElement sx, ECFieldElement sy) { return Curve.CreateRawPoint(RawXCoord.Multiply(sx), RawYCoord.Multiply(sy), IsCompressed); }
public virtual ECPoint ScaleY(ECFieldElement scale) { return IsInfinity ? this : Curve.CreateRawPoint(RawXCoord, RawYCoord.Multiply(scale), RawZCoords, IsCompressed); }
protected AbstractF2mPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression) : base(curve, x, y, zs, withCompression) { }
// B.3 pg 62 public override ECPoint Add(ECPoint b) { if (this.IsInfinity) return b; if (b.IsInfinity) return this; if (this == b) return Twice(); ECCurve curve = this.Curve; int coord = curve.CoordinateSystem; ECFieldElement X1 = this.RawXCoord, Y1 = this.RawYCoord; ECFieldElement X2 = b.RawXCoord, Y2 = b.RawYCoord; switch (coord) { case ECCurve.COORD_AFFINE: { ECFieldElement dx = X2.Subtract(X1), dy = Y2.Subtract(Y1); if (dx.IsZero) { if (dy.IsZero) { // this == b, i.e. this must be doubled return Twice(); } // this == -b, i.e. the result is the point at infinity return Curve.Infinity; } ECFieldElement gamma = dy.Divide(dx); ECFieldElement X3 = gamma.Square().Subtract(X1).Subtract(X2); ECFieldElement Y3 = gamma.Multiply(X1.Subtract(X3)).Subtract(Y1); return new FpPoint(Curve, X3, Y3, IsCompressed); } case ECCurve.COORD_HOMOGENEOUS: { ECFieldElement Z1 = this.RawZCoords[0]; ECFieldElement Z2 = b.RawZCoords[0]; bool Z1IsOne = Z1.IsOne; bool Z2IsOne = Z2.IsOne; ECFieldElement u1 = Z1IsOne ? Y2 : Y2.Multiply(Z1); ECFieldElement u2 = Z2IsOne ? Y1 : Y1.Multiply(Z2); ECFieldElement u = u1.Subtract(u2); ECFieldElement v1 = Z1IsOne ? X2 : X2.Multiply(Z1); ECFieldElement v2 = Z2IsOne ? X1 : X1.Multiply(Z2); ECFieldElement v = v1.Subtract(v2); // Check if b == this or b == -this if (v.IsZero) { if (u.IsZero) { // this == b, i.e. this must be doubled return this.Twice(); } // this == -b, i.e. the result is the point at infinity return curve.Infinity; } // TODO Optimize for when w == 1 ECFieldElement w = Z1IsOne ? Z2 : Z2IsOne ? Z1 : Z1.Multiply(Z2); ECFieldElement vSquared = v.Square(); ECFieldElement vCubed = vSquared.Multiply(v); ECFieldElement vSquaredV2 = vSquared.Multiply(v2); ECFieldElement A = u.Square().Multiply(w).Subtract(vCubed).Subtract(Two(vSquaredV2)); ECFieldElement X3 = v.Multiply(A); ECFieldElement Y3 = vSquaredV2.Subtract(A).MultiplyMinusProduct(u, u2, vCubed); ECFieldElement Z3 = vCubed.Multiply(w); return new FpPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed); } case ECCurve.COORD_JACOBIAN: case ECCurve.COORD_JACOBIAN_MODIFIED: { ECFieldElement Z1 = this.RawZCoords[0]; ECFieldElement Z2 = b.RawZCoords[0]; bool Z1IsOne = Z1.IsOne; ECFieldElement X3, Y3, Z3, Z3Squared = null; if (!Z1IsOne && Z1.Equals(Z2)) { // TODO Make this available as public method coZAdd? ECFieldElement dx = X1.Subtract(X2), dy = Y1.Subtract(Y2); if (dx.IsZero) { if (dy.IsZero) { return Twice(); } return curve.Infinity; } ECFieldElement C = dx.Square(); ECFieldElement W1 = X1.Multiply(C), W2 = X2.Multiply(C); ECFieldElement A1 = W1.Subtract(W2).Multiply(Y1); X3 = dy.Square().Subtract(W1).Subtract(W2); Y3 = W1.Subtract(X3).Multiply(dy).Subtract(A1); Z3 = dx; if (Z1IsOne) { Z3Squared = C; } else { Z3 = Z3.Multiply(Z1); } } else { ECFieldElement Z1Squared, U2, S2; if (Z1IsOne) { Z1Squared = Z1; U2 = X2; S2 = Y2; } else { Z1Squared = Z1.Square(); U2 = Z1Squared.Multiply(X2); ECFieldElement Z1Cubed = Z1Squared.Multiply(Z1); S2 = Z1Cubed.Multiply(Y2); } bool Z2IsOne = Z2.IsOne; ECFieldElement Z2Squared, U1, S1; if (Z2IsOne) { Z2Squared = Z2; U1 = X1; S1 = Y1; } else { Z2Squared = Z2.Square(); U1 = Z2Squared.Multiply(X1); ECFieldElement Z2Cubed = Z2Squared.Multiply(Z2); S1 = Z2Cubed.Multiply(Y1); } ECFieldElement H = U1.Subtract(U2); ECFieldElement R = S1.Subtract(S2); // Check if b == this or b == -this if (H.IsZero) { if (R.IsZero) { // this == b, i.e. this must be doubled return this.Twice(); } // this == -b, i.e. the result is the point at infinity return curve.Infinity; } ECFieldElement HSquared = H.Square(); ECFieldElement G = HSquared.Multiply(H); ECFieldElement V = HSquared.Multiply(U1); X3 = R.Square().Add(G).Subtract(Two(V)); Y3 = V.Subtract(X3).MultiplyMinusProduct(R, G, S1); Z3 = H; if (!Z1IsOne) { Z3 = Z3.Multiply(Z1); } if (!Z2IsOne) { Z3 = Z3.Multiply(Z2); } // Alternative calculation of Z3 using fast square //X3 = four(X3); //Y3 = eight(Y3); //Z3 = doubleProductFromSquares(Z1, Z2, Z1Squared, Z2Squared).Multiply(H); if (Z3 == H) { Z3Squared = HSquared; } } ECFieldElement[] zs; if (coord == ECCurve.COORD_JACOBIAN_MODIFIED) { // TODO If the result will only be used in a subsequent addition, we don't need W3 ECFieldElement W3 = CalculateJacobianModifiedW(Z3, Z3Squared); zs = new ECFieldElement[] { Z3, W3 }; } else { zs = new ECFieldElement[] { Z3 }; } return new FpPoint(curve, X3, Y3, zs, IsCompressed); } default: { throw new InvalidOperationException("unsupported coordinate system"); } } }
/** * Create a point that encodes with or without point compression. * * @param curve the curve to use * @param x affine x co-ordinate * @param y affine y co-ordinate * @param withCompression if true encode with point compression */ public FpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression) : base(curve, x, y, withCompression) { if ((x == null) != (y == null)) throw new ArgumentException("Exactly one of the field elements is null"); }
protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression) { return new F2mPoint(this, x, y, zs, withCompression); }
protected F2mCurve(int m, int k1, int k2, int k3, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor) : base(m, k1, k2, k3) { this.m = m; this.k1 = k1; this.k2 = k2; this.k3 = k3; this.m_order = order; this.m_cofactor = cofactor; this.m_infinity = new F2mPoint(this, null, null); this.m_a = a; this.m_b = b; this.m_coord = F2M_DEFAULT_COORDS; }
protected internal abstract ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression);
/** * Normalization ensures that any projective coordinate is 1, and therefore that the x, y * coordinates reflect those of the equivalent point in an affine coordinate system. Where more * than one point is to be normalized, this method will generally be more efficient than * normalizing each point separately. * * @param points * An array of points that will be updated in place with their normalized versions, * where necessary */ public virtual void NormalizeAll(ECPoint[] points) { CheckPoints(points); if (this.CoordinateSystem == ECCurve.COORD_AFFINE) { return; } /* * Figure out which of the points actually need to be normalized */ ECFieldElement[] zs = new ECFieldElement[points.Length]; int[] indices = new int[points.Length]; int count = 0; for (int i = 0; i < points.Length; ++i) { ECPoint p = points[i]; if (null != p && !p.IsNormalized()) { zs[count] = p.GetZCoord(0); indices[count++] = i; } } if (count == 0) { return; } ECAlgorithms.MontgomeryTrick(zs, 0, count); for (int j = 0; j < count; ++j) { int index = indices[j]; points[index] = points[index].Normalize(zs[j]); } }
protected virtual ECFieldElement Two(ECFieldElement x) { return x.Add(x); }
public virtual ECFieldElement[] GetZCoords() { int zsLen = m_zs.Length; if (zsLen == 0) { return m_zs; } ECFieldElement[] copy = new ECFieldElement[zsLen]; Array.Copy(m_zs, 0, copy, 0, zsLen); return copy; }
internal ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression) { this.m_curve = curve; this.m_x = x; this.m_y = y; this.m_zs = zs; this.m_withCompression = withCompression; }
internal virtual ECPoint Normalize(ECFieldElement zInv) { switch (this.CurveCoordinateSystem) { case ECCurve.COORD_HOMOGENEOUS: case ECCurve.COORD_LAMBDA_PROJECTIVE: { return CreateScaledPoint(zInv, zInv); } case ECCurve.COORD_JACOBIAN: case ECCurve.COORD_JACOBIAN_CHUDNOVSKY: case ECCurve.COORD_JACOBIAN_MODIFIED: { ECFieldElement zInv2 = zInv.Square(), zInv3 = zInv2.Multiply(zInv); return CreateScaledPoint(zInv2, zInv3); } default: { throw new InvalidOperationException("not a projective coordinate system"); } } }
protected virtual ECFieldElement CalculateJacobianModifiedW(ECFieldElement Z, ECFieldElement ZSquared) { ECFieldElement a4 = this.Curve.A; if (a4.IsZero || Z.IsOne) return a4; if (ZSquared == null) { ZSquared = Z.Square(); } ECFieldElement W = ZSquared.Square(); ECFieldElement a4Neg = a4.Negate(); if (a4Neg.BitLength < a4.BitLength) { W = W.Multiply(a4Neg).Negate(); } else { W = W.Multiply(a4); } return W; }
protected internal ECPointBase(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression) : base(curve, x, y, zs, withCompression) { }
protected virtual ECFieldElement DoubleProductFromSquares(ECFieldElement a, ECFieldElement b, ECFieldElement aSquared, ECFieldElement bSquared) { /* * NOTE: If squaring in the field is faster than multiplication, then this is a quicker * way to calculate 2.A.B, if A^2 and B^2 are already known. */ return a.Add(b).Square().Subtract(aSquared).Subtract(bSquared); }
/** * @param curve base curve * @param x x point * @param y y point * @param withCompression true if encode with point compression. */ public F2mPoint( ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression) : base(curve, x, y, withCompression) { if ((x == null) != (y == null)) { throw new ArgumentException("Exactly one of the field elements is null"); } if (x != null) { // Check if x and y are elements of the same field F2mFieldElement.CheckFieldElements(x, y); // Check if x and a are elements of the same field if (curve != null) { F2mFieldElement.CheckFieldElements(x, curve.A); } } }
protected virtual ECFieldElement Eight(ECFieldElement x) { return Four(Two(x)); }
public override ECPoint ScaleX(ECFieldElement scale) { if (this.IsInfinity) return this; switch (CurveCoordinateSystem) { case ECCurve.COORD_LAMBDA_AFFINE: { // Y is actually Lambda (X + Y/X) here ECFieldElement X = RawXCoord, L = RawYCoord; ECFieldElement X2 = X.Multiply(scale); ECFieldElement L2 = L.Add(X).Divide(scale).Add(X2); return Curve.CreateRawPoint(X, L2, RawZCoords, IsCompressed); } case ECCurve.COORD_LAMBDA_PROJECTIVE: { // Y is actually Lambda (X + Y/X) here ECFieldElement X = RawXCoord, L = RawYCoord, Z = RawZCoords[0]; // We scale the Z coordinate also, to avoid an inversion ECFieldElement X2 = X.Multiply(scale.Square()); ECFieldElement L2 = L.Add(X).Add(X2); ECFieldElement Z2 = Z.Multiply(scale); return Curve.CreateRawPoint(X, L2, new ECFieldElement[] { Z2 }, IsCompressed); } default: { return base.ScaleX(scale); } } }
protected virtual ECFieldElement Four(ECFieldElement x) { return Two(Two(x)); }
public static int GetByteLength(ECFieldElement fe) { return (fe.FieldSize + 7) / 8; }
protected ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression) : this(curve, x, y, GetInitialZCoords(curve), withCompression) { }
public X9FieldElement( ECFieldElement f) { this.f = f; }
protected virtual ECFieldElement Three(ECFieldElement x) { return Two(x).Add(x); }