blob: b6ff8c5aeac1b2a99e6a435fc38cf945b6c3d22f [file] [log] [blame]
package org.bouncycastle.pqc.crypto.ntru;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.SecureRandom;
import java.text.DecimalFormat;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.KeyGenerationParameters;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.digests.SHA512Digest;
/**
* A set of parameters for NtruSign. Several predefined parameter sets are available and new ones can be created as well.
*/
public class NTRUSigningKeyGenerationParameters
extends KeyGenerationParameters
implements Cloneable
{
public static final int BASIS_TYPE_STANDARD = 0;
public static final int BASIS_TYPE_TRANSPOSE = 1;
public static final int KEY_GEN_ALG_RESULTANT = 0;
public static final int KEY_GEN_ALG_FLOAT = 1;
/**
* Gives 128 bits of security
*/
public static final NTRUSigningKeyGenerationParameters APR2011_439 = new NTRUSigningKeyGenerationParameters(439, 2048, 146, 1, BASIS_TYPE_TRANSPOSE, 0.165, 490, 280, false, true, KEY_GEN_ALG_RESULTANT, new SHA256Digest());
/**
* Like <code>APR2011_439</code>, this parameter set gives 128 bits of security but uses product-form polynomials
*/
public static final NTRUSigningKeyGenerationParameters APR2011_439_PROD = new NTRUSigningKeyGenerationParameters(439, 2048, 9, 8, 5, 1, BASIS_TYPE_TRANSPOSE, 0.165, 490, 280, false, true, KEY_GEN_ALG_RESULTANT, new SHA256Digest());
/**
* Gives 256 bits of security
*/
public static final NTRUSigningKeyGenerationParameters APR2011_743 = new NTRUSigningKeyGenerationParameters(743, 2048, 248, 1, BASIS_TYPE_TRANSPOSE, 0.127, 560, 360, true, false, KEY_GEN_ALG_RESULTANT, new SHA512Digest());
/**
* Like <code>APR2011_439</code>, this parameter set gives 256 bits of security but uses product-form polynomials
*/
public static final NTRUSigningKeyGenerationParameters APR2011_743_PROD = new NTRUSigningKeyGenerationParameters(743, 2048, 11, 11, 15, 1, BASIS_TYPE_TRANSPOSE, 0.127, 560, 360, true, false, KEY_GEN_ALG_RESULTANT, new SHA512Digest());
/**
* Generates key pairs quickly. Use for testing only.
*/
public static final NTRUSigningKeyGenerationParameters TEST157 = new NTRUSigningKeyGenerationParameters(157, 256, 29, 1, BASIS_TYPE_TRANSPOSE, 0.38, 200, 80, false, false, KEY_GEN_ALG_RESULTANT, new SHA256Digest());
/**
* Generates key pairs quickly. Use for testing only.
*/
public static final NTRUSigningKeyGenerationParameters TEST157_PROD = new NTRUSigningKeyGenerationParameters(157, 256, 5, 5, 8, 1, BASIS_TYPE_TRANSPOSE, 0.38, 200, 80, false, false, KEY_GEN_ALG_RESULTANT, new SHA256Digest());
public int N;
public int q;
public int d, d1, d2, d3, B;
double beta;
public double betaSq;
double normBound;
public double normBoundSq;
public int signFailTolerance = 100;
double keyNormBound;
public double keyNormBoundSq;
public boolean primeCheck; // true if N and 2N+1 are prime
public int basisType;
int bitsF = 6; // max #bits needed to encode one coefficient of the polynomial F
public boolean sparse; // whether to treat ternary polynomials as sparsely populated
public int keyGenAlg;
public Digest hashAlg;
public int polyType;
/**
* Constructs a parameter set that uses ternary private keys (i.e. <code>polyType=SIMPLE</code>).
*
* @param N number of polynomial coefficients
* @param q modulus
* @param d number of -1's in the private polynomials <code>f</code> and <code>g</code>
* @param B number of perturbations
* @param basisType whether to use the standard or transpose lattice
* @param beta balancing factor for the transpose lattice
* @param normBound maximum norm for valid signatures
* @param keyNormBound maximum norm for the ploynomials <code>F</code> and <code>G</code>
* @param primeCheck whether <code>2N+1</code> is prime
* @param sparse whether to treat ternary polynomials as sparsely populated ({@link org.bouncycastle.pqc.math.ntru.polynomial.SparseTernaryPolynomial} vs {@link org.bouncycastle.pqc.math.ntru.polynomial.DenseTernaryPolynomial})
* @param keyGenAlg <code>RESULTANT</code> produces better bases, <code>FLOAT</code> is slightly faster. <code>RESULTANT</code> follows the EESS standard while <code>FLOAT</code> is described in Hoffstein et al: An Introduction to Mathematical Cryptography.
* @param hashAlg a valid identifier for a <code>java.security.MessageDigest</code> instance such as <code>SHA-256</code>. The <code>MessageDigest</code> must support the <code>getDigestLength()</code> method.
*/
public NTRUSigningKeyGenerationParameters(int N, int q, int d, int B, int basisType, double beta, double normBound, double keyNormBound, boolean primeCheck, boolean sparse, int keyGenAlg, Digest hashAlg)
{
super(new SecureRandom(), N);
this.N = N;
this.q = q;
this.d = d;
this.B = B;
this.basisType = basisType;
this.beta = beta;
this.normBound = normBound;
this.keyNormBound = keyNormBound;
this.primeCheck = primeCheck;
this.sparse = sparse;
this.keyGenAlg = keyGenAlg;
this.hashAlg = hashAlg;
polyType = NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE;
init();
}
/**
* Constructs a parameter set that uses product-form private keys (i.e. <code>polyType=PRODUCT</code>).
*
* @param N number of polynomial coefficients
* @param q modulus
* @param d1 number of -1's in the private polynomials <code>f</code> and <code>g</code>
* @param d2 number of -1's in the private polynomials <code>f</code> and <code>g</code>
* @param d3 number of -1's in the private polynomials <code>f</code> and <code>g</code>
* @param B number of perturbations
* @param basisType whether to use the standard or transpose lattice
* @param beta balancing factor for the transpose lattice
* @param normBound maximum norm for valid signatures
* @param keyNormBound maximum norm for the ploynomials <code>F</code> and <code>G</code>
* @param primeCheck whether <code>2N+1</code> is prime
* @param sparse whether to treat ternary polynomials as sparsely populated ({@link org.bouncycastle.pqc.math.ntru.polynomial.SparseTernaryPolynomial} vs {@link org.bouncycastle.pqc.math.ntru.polynomial.DenseTernaryPolynomial})
* @param keyGenAlg <code>RESULTANT</code> produces better bases, <code>FLOAT</code> is slightly faster. <code>RESULTANT</code> follows the EESS standard while <code>FLOAT</code> is described in Hoffstein et al: An Introduction to Mathematical Cryptography.
* @param hashAlg a valid identifier for a <code>java.security.MessageDigest</code> instance such as <code>SHA-256</code>. The <code>MessageDigest</code> must support the <code>getDigestLength()</code> method.
*/
public NTRUSigningKeyGenerationParameters(int N, int q, int d1, int d2, int d3, int B, int basisType, double beta, double normBound, double keyNormBound, boolean primeCheck, boolean sparse, int keyGenAlg, Digest hashAlg)
{
super(new SecureRandom(), N);
this.N = N;
this.q = q;
this.d1 = d1;
this.d2 = d2;
this.d3 = d3;
this.B = B;
this.basisType = basisType;
this.beta = beta;
this.normBound = normBound;
this.keyNormBound = keyNormBound;
this.primeCheck = primeCheck;
this.sparse = sparse;
this.keyGenAlg = keyGenAlg;
this.hashAlg = hashAlg;
polyType = NTRUParameters.TERNARY_POLYNOMIAL_TYPE_PRODUCT;
init();
}
private void init()
{
betaSq = beta * beta;
normBoundSq = normBound * normBound;
keyNormBoundSq = keyNormBound * keyNormBound;
}
/**
* Reads a parameter set from an input stream.
*
* @param is an input stream
* @throws java.io.IOException
*/
public NTRUSigningKeyGenerationParameters(InputStream is)
throws IOException
{
super(new SecureRandom(), 0); // TODO:
DataInputStream dis = new DataInputStream(is);
N = dis.readInt();
q = dis.readInt();
d = dis.readInt();
d1 = dis.readInt();
d2 = dis.readInt();
d3 = dis.readInt();
B = dis.readInt();
basisType = dis.readInt();
beta = dis.readDouble();
normBound = dis.readDouble();
keyNormBound = dis.readDouble();
signFailTolerance = dis.readInt();
primeCheck = dis.readBoolean();
sparse = dis.readBoolean();
bitsF = dis.readInt();
keyGenAlg = dis.read();
String alg = dis.readUTF();
if ("SHA-512".equals(alg))
{
hashAlg = new SHA512Digest();
}
else if ("SHA-256".equals(alg))
{
hashAlg = new SHA256Digest();
}
polyType = dis.read();
init();
}
/**
* Writes the parameter set to an output stream
*
* @param os an output stream
* @throws java.io.IOException
*/
public void writeTo(OutputStream os)
throws IOException
{
DataOutputStream dos = new DataOutputStream(os);
dos.writeInt(N);
dos.writeInt(q);
dos.writeInt(d);
dos.writeInt(d1);
dos.writeInt(d2);
dos.writeInt(d3);
dos.writeInt(B);
dos.writeInt(basisType);
dos.writeDouble(beta);
dos.writeDouble(normBound);
dos.writeDouble(keyNormBound);
dos.writeInt(signFailTolerance);
dos.writeBoolean(primeCheck);
dos.writeBoolean(sparse);
dos.writeInt(bitsF);
dos.write(keyGenAlg);
dos.writeUTF(hashAlg.getAlgorithmName());
dos.write(polyType);
}
public NTRUSigningParameters getSigningParameters()
{
return new NTRUSigningParameters(N, q, d, B, beta, normBound, hashAlg);
}
public NTRUSigningKeyGenerationParameters clone()
{
if (polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE)
{
return new NTRUSigningKeyGenerationParameters(N, q, d, B, basisType, beta, normBound, keyNormBound, primeCheck, sparse, keyGenAlg, hashAlg);
}
else
{
return new NTRUSigningKeyGenerationParameters(N, q, d1, d2, d3, B, basisType, beta, normBound, keyNormBound, primeCheck, sparse, keyGenAlg, hashAlg);
}
}
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + B;
result = prime * result + N;
result = prime * result + basisType;
long temp;
temp = Double.doubleToLongBits(beta);
result = prime * result + (int)(temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(betaSq);
result = prime * result + (int)(temp ^ (temp >>> 32));
result = prime * result + bitsF;
result = prime * result + d;
result = prime * result + d1;
result = prime * result + d2;
result = prime * result + d3;
result = prime * result + ((hashAlg == null) ? 0 : hashAlg.getAlgorithmName().hashCode());
result = prime * result + keyGenAlg;
temp = Double.doubleToLongBits(keyNormBound);
result = prime * result + (int)(temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(keyNormBoundSq);
result = prime * result + (int)(temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(normBound);
result = prime * result + (int)(temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(normBoundSq);
result = prime * result + (int)(temp ^ (temp >>> 32));
result = prime * result + polyType;
result = prime * result + (primeCheck ? 1231 : 1237);
result = prime * result + q;
result = prime * result + signFailTolerance;
result = prime * result + (sparse ? 1231 : 1237);
return result;
}
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (obj == null)
{
return false;
}
if (!(obj instanceof NTRUSigningKeyGenerationParameters))
{
return false;
}
NTRUSigningKeyGenerationParameters other = (NTRUSigningKeyGenerationParameters)obj;
if (B != other.B)
{
return false;
}
if (N != other.N)
{
return false;
}
if (basisType != other.basisType)
{
return false;
}
if (Double.doubleToLongBits(beta) != Double.doubleToLongBits(other.beta))
{
return false;
}
if (Double.doubleToLongBits(betaSq) != Double.doubleToLongBits(other.betaSq))
{
return false;
}
if (bitsF != other.bitsF)
{
return false;
}
if (d != other.d)
{
return false;
}
if (d1 != other.d1)
{
return false;
}
if (d2 != other.d2)
{
return false;
}
if (d3 != other.d3)
{
return false;
}
if (hashAlg == null)
{
if (other.hashAlg != null)
{
return false;
}
}
else if (!hashAlg.getAlgorithmName().equals(other.hashAlg.getAlgorithmName()))
{
return false;
}
if (keyGenAlg != other.keyGenAlg)
{
return false;
}
if (Double.doubleToLongBits(keyNormBound) != Double.doubleToLongBits(other.keyNormBound))
{
return false;
}
if (Double.doubleToLongBits(keyNormBoundSq) != Double.doubleToLongBits(other.keyNormBoundSq))
{
return false;
}
if (Double.doubleToLongBits(normBound) != Double.doubleToLongBits(other.normBound))
{
return false;
}
if (Double.doubleToLongBits(normBoundSq) != Double.doubleToLongBits(other.normBoundSq))
{
return false;
}
if (polyType != other.polyType)
{
return false;
}
if (primeCheck != other.primeCheck)
{
return false;
}
if (q != other.q)
{
return false;
}
if (signFailTolerance != other.signFailTolerance)
{
return false;
}
if (sparse != other.sparse)
{
return false;
}
return true;
}
public String toString()
{
DecimalFormat format = new DecimalFormat("0.00");
StringBuilder output = new StringBuilder("SignatureParameters(N=" + N + " q=" + q);
if (polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE)
{
output.append(" polyType=SIMPLE d=" + d);
}
else
{
output.append(" polyType=PRODUCT d1=" + d1 + " d2=" + d2 + " d3=" + d3);
}
output.append(" B=" + B + " basisType=" + basisType + " beta=" + format.format(beta) +
" normBound=" + format.format(normBound) + " keyNormBound=" + format.format(keyNormBound) +
" prime=" + primeCheck + " sparse=" + sparse + " keyGenAlg=" + keyGenAlg + " hashAlg=" + hashAlg + ")");
return output.toString();
}
}