/// <summary> /// Constructs an ECCGroup. /// <param name="p">The p parameter, representing the prime field domain for the /// x and y coordinate spaces.</param> /// <param name="a">The a parameter for the eliptic curve.</param> /// <param name="b">The b parameter for the eliptic curve.</param> /// <param name="g_x">The x coordinate of the generator point.</param> /// <param name="g_y">The y coordinate of the generator point.</param> /// <param name="n">The order of the group.</param> /// <param name="groupName">The known name of the group, or null.</param> /// <param name="curveName">The known name of the curve, or null.</param> /// </summary> public ECGroupBCImpl( byte[] p, byte[] a, byte[] b, byte[] g_x, byte[] g_y, byte[] n, string groupName, string curveName) : base(p, a, b, g_x, g_y, n, groupName, curveName) { this.curve = new BouncyCastle.FpCurve( new BCBigInt(1, p), new BCBigInt(1, a), new BCBigInt(1, b)); BouncyCastle.ECPoint generator = this.curve.CreatePoint( new BCBigInt(1, g_x), new BCBigInt(1, g_y), false); this.domainParams = new BouncyCastle.ECDomainParameters( this.curve, generator, new BCBigInt(1, n)); this.g = new ECGroupElementBCImpl( this.domainParams.G as BouncyCastle.FpPoint); }
/// <summary> /// Derives an unpredictable element of the group, using the input. Each /// construction defines its own derivation mechanism, but each takes an /// optional context string and an index, and returns a counter. Calling /// this method with the same parameter values returns the same element /// and counter, calling it with a different context or index value must /// return a different element. /// </summary> /// <param name="context">An optional context used by the derivation /// mechanism, can be null.</param> /// <param name="index">An 8-bit integer index value.</param> /// <param name="counter">A counter value indicating the state at which the /// derivation mechanism stopped.</param> /// <returns>A random group element.</returns> public override GroupElement DeriveElement(byte[] context, byte index, out int counter) { // concatenate context and curve name BouncyCastle.FpCurve curve = this.domainParams.Curve as BouncyCastle.FpCurve; int count = 0; BouncyCastle.ECFieldElement x = null, y = null; while (y == null) { x = GetX(context, curve, index, count); BouncyCastle.ECFieldElement alpha = x.Multiply(x.Square().Add(curve.A)).Add(curve.B); if (alpha.ToBigInteger() == BCBigInt.Zero) { y = alpha; } else { y = alpha.Sqrt(); // returns null if sqrt does not exist } count++; } // determine which sqrt to return, i.e., Min(y, -y) BouncyCastle.ECFieldElement minusY = y.Negate(); counter = count - 1; return(new ECGroupElementBCImpl(new BouncyCastle.FpPoint(curve, x, y.ToBigInteger() < minusY.ToBigInteger() ? y : minusY))); }
private BouncyCastle.FpFieldElement GetX( byte[] input, BouncyCastle.FpCurve curve, int index, int counter) { int numIterations = (int)System.Math.Ceiling( (double)(curve.Q.BitLength / 8) / (double)hashByteSize); byte[] digest = new byte[numIterations * hashByteSize]; for (int iteration = 0; iteration < numIterations; iteration++) { byte[] hashInput = ProtocolHelper.Concatenate( input, encoding.GetBytes( index.ToString() + counter.ToString() + iteration.ToString())); hash.HashWithoutFormatting(hashInput); Array.Copy(hash.Digest, 0, digest, hashByteSize * iteration, hashByteSize); } BCBigInt x = new BCBigInt(1, digest).Mod(curve.Q); return(curve.FromBigInteger(x) as BouncyCastle.FpFieldElement); }
/// <summary> /// Returns the group element encoded as two byte arrays, one for /// each coordinate. /// </summary> /// <param name="x">A byte array encoding the x coordinate.</param> /// <param name="y">A byte array encoding the y coordinate.</param> /// <returns>A group element.</returns> public override GroupElement CreateGroupElement(byte[] x, byte[] y) { BouncyCastle.FpCurve curve = (BouncyCastle.FpCurve)domainParams.Curve; return(new ECGroupElementBCImpl( new BouncyCastle.FpPoint( domainParams.Curve, new BouncyCastle.FpFieldElement(curve.Q, new BCBigInt(1, x)), new BouncyCastle.FpFieldElement(curve.Q, new BCBigInt(1, y))))); }