![JAR search and dependency download from the Maven repository](/logo.png)
org.bouncycastle.crypto.agreement.ecjpake.ECJPAKECurve Maven / Gradle / Ivy
Show all versions of bcprov-jdk14 Show documentation
package org.bouncycastle.crypto.agreement.ecjpake;
import java.math.BigInteger;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
/**
* A pre-computed elliptic curve over a prime field, in short-Weierstrass form for use during an EC J-PAKE exchange.
*
* In general, J-PAKE can use any elliptic curve or prime order group
* that is suitable for public key cryptography.
*
* See {@link ECJPAKECurves} for convenient standard curves.
*
* NIST publishes
* many curves with different forms and levels of security.
*/
public class ECJPAKECurve
{
private final ECCurve.Fp curve;
private final ECPoint g;
/**
* Constructs a new {@link ECJPAKECurve}.
*
* In general, you should use one of the pre-approved curves from
* {@link ECJPAKECurves}, rather than manually constructing one.
*
* The following basic checks are performed:
*
* q must be prime
* n must be prime
* The curve must not be singular i.e. the discriminant is equal to 0 mod q
* G must lie on the curve
* n*h must equal the order of the curve
* a must be in [0, q-1]
* b must be in [0, q-1]
*
*
* The prime checks are performed using {@link BigInteger#isProbablePrime(int)},
* and are therefore subject to the same probability guarantees.
*
* These checks prevent trivial mistakes.
* However, due to the small uncertainties if p and q are not prime,
* advanced attacks are not prevented.
* Use it at your own risk.
*
* @throws NullPointerException if any argument is null
* @throws IllegalArgumentException if any of the above validations fail
*/
public ECJPAKECurve(BigInteger q, BigInteger a, BigInteger b, BigInteger n, BigInteger h, BigInteger g_x, BigInteger g_y)
{
ECJPAKEUtil.validateNotNull(a, "a");
ECJPAKEUtil.validateNotNull(b, "b");
ECJPAKEUtil.validateNotNull(q, "q");
ECJPAKEUtil.validateNotNull(n, "n");
ECJPAKEUtil.validateNotNull(h, "h");
ECJPAKEUtil.validateNotNull(g_x, "g_x");
ECJPAKEUtil.validateNotNull(g_y, "g_y");
/*
* Don't skip the checks on user-specified groups.
*/
/*
* Note that these checks do not guarantee that n and q are prime.
* We just have reasonable certainty that they are prime.
*/
if (!q.isProbablePrime(20))
{
throw new IllegalArgumentException("Field size q must be prime");
}
if (a.compareTo(BigInteger.ZERO) < 0 || a.compareTo(q) >= 0)
{
throw new IllegalArgumentException("The parameter 'a' is not in the field [0, q-1]");
}
if (b.compareTo(BigInteger.ZERO) < 0 || b.compareTo(q) >= 0)
{
throw new IllegalArgumentException("The parameter 'b' is not in the field [0, q-1]");
}
BigInteger d = calculateDeterminant(q, a, b);
if (d.equals(BigInteger.ZERO))
{
throw new IllegalArgumentException("The curve is singular, i.e the discriminant is equal to 0 mod q.");
}
if (!n.isProbablePrime(20))
{
throw new IllegalArgumentException("The order n must be prime");
}
/*
* TODO It's expensive to calculate the actual total number of points. Probably the best that could be done is
* checking that the point count is within the Hasse bound?
*/
// BigInteger totalPoints = n.multiply(h);
ECCurve.Fp curve = new ECCurve.Fp(q, a, b, n, h);
ECPoint g = curve.createPoint(g_x, g_y);
if (!g.isValid())
{
throw new IllegalArgumentException("The base point G does not lie on the curve.");
}
this.curve = curve;
this.g = g;
}
/**
* Internal package-private constructor used by the pre-approved
* groups in {@link ECJPAKECurves}.
* These pre-approved curves can avoid the expensive checks.
*/
ECJPAKECurve(ECCurve.Fp curve, ECPoint g)
{
ECJPAKEUtil.validateNotNull(curve, "curve");
ECJPAKEUtil.validateNotNull(g, "g");
ECJPAKEUtil.validateNotNull(curve.getOrder(), "n");
ECJPAKEUtil.validateNotNull(curve.getCofactor(), "h");
this.curve = curve;
this.g = g;
}
public ECCurve.Fp getCurve()
{
return curve;
}
public ECPoint getG()
{
return g;
}
public BigInteger getA()
{
return curve.getA().toBigInteger();
}
public BigInteger getB()
{
return curve.getB().toBigInteger();
}
public BigInteger getN()
{
return curve.getOrder();
}
public BigInteger getH()
{
return curve.getCofactor();
}
public BigInteger getQ()
{
return curve.getQ();
}
private static BigInteger calculateDeterminant(BigInteger q, BigInteger a, BigInteger b)
{
BigInteger a3x4 = a.multiply(a).mod(q).multiply(a).mod(q).shiftLeft(2);
BigInteger b2x27 = b.multiply(b).mod(q).multiply(BigInteger.valueOf(27));
return a3x4.add(b2x27).mod(q);
}
}