use of com.github.zhenwei.core.pqc.math.ntru.polynomial.Polynomial in project LinLong-Java by zhenwei1108.
the class NTRUEncryptionKeyPairGenerator method generateKeyPair.
/**
* Generates a new encryption key pair.
*
* @return a key pair
*/
public AsymmetricCipherKeyPair generateKeyPair() {
int N = params.N;
int q = params.q;
int df = params.df;
int df1 = params.df1;
int df2 = params.df2;
int df3 = params.df3;
int dg = params.dg;
boolean fastFp = params.fastFp;
boolean sparse = params.sparse;
Polynomial t;
IntegerPolynomial fq;
IntegerPolynomial fp = null;
// choose a random f that is invertible mod 3 and q
while (true) {
IntegerPolynomial f;
// choose random t, calculate f and fp
if (fastFp) {
// if fastFp=true, f is always invertible mod 3
t = params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE ? Util.generateRandomTernary(N, df, df, sparse, params.getRandom()) : ProductFormPolynomial.generateRandom(N, df1, df2, df3, df3, params.getRandom());
f = t.toIntegerPolynomial();
f.mult(3);
f.coeffs[0] += 1;
} else {
t = params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE ? Util.generateRandomTernary(N, df, df - 1, sparse, params.getRandom()) : ProductFormPolynomial.generateRandom(N, df1, df2, df3, df3 - 1, params.getRandom());
f = t.toIntegerPolynomial();
fp = f.invertF3();
if (fp == null) {
continue;
}
}
fq = f.invertFq(q);
if (fq == null) {
continue;
}
break;
}
// if fastFp=true, fp=1
if (fastFp) {
fp = new IntegerPolynomial(N);
fp.coeffs[0] = 1;
}
// choose a random g that is invertible mod q
DenseTernaryPolynomial g;
while (true) {
g = DenseTernaryPolynomial.generateRandom(N, dg, dg - 1, params.getRandom());
if (g.invertFq(q) != null) {
break;
}
}
IntegerPolynomial h = g.mult(fq, q);
h.mult3(q);
h.ensurePositive(q);
g.clear();
fq.clear();
NTRUEncryptionPrivateKeyParameters priv = new NTRUEncryptionPrivateKeyParameters(h, t, fp, params.getEncryptionParameters());
NTRUEncryptionPublicKeyParameters pub = new NTRUEncryptionPublicKeyParameters(h, params.getEncryptionParameters());
return new AsymmetricCipherKeyPair(pub, priv);
}
use of com.github.zhenwei.core.pqc.math.ntru.polynomial.Polynomial in project LinLong-Java by zhenwei1108.
the class NTRUSigningKeyPairGenerator method generateBasis.
/**
* Creates a NTRUSigner basis consisting of polynomials <code>f, g, F, G, h</code>.<br/> If
* <code>KeyGenAlg=FLOAT</code>, the basis may not be valid and this method must be rerun if that
* is the case.<br/>
*
* @see #generateBoundedBasis()
*/
private FGBasis generateBasis() {
int N = params.N;
int q = params.q;
int d = params.d;
int d1 = params.d1;
int d2 = params.d2;
int d3 = params.d3;
int basisType = params.basisType;
Polynomial f;
IntegerPolynomial fInt;
Polynomial g;
IntegerPolynomial gInt;
IntegerPolynomial fq;
Resultant rf;
Resultant rg;
BigIntEuclidean r;
int _2n1 = 2 * N + 1;
boolean primeCheck = params.primeCheck;
do {
do {
f = params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE ? DenseTernaryPolynomial.generateRandom(N, d + 1, d, CryptoServicesRegistrar.getSecureRandom()) : ProductFormPolynomial.generateRandom(N, d1, d2, d3 + 1, d3, CryptoServicesRegistrar.getSecureRandom());
fInt = f.toIntegerPolynomial();
} while (primeCheck && fInt.resultant(_2n1).res.equals(ZERO));
fq = fInt.invertFq(q);
} while (fq == null);
rf = fInt.resultant();
do {
do {
do {
g = params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE ? DenseTernaryPolynomial.generateRandom(N, d + 1, d, CryptoServicesRegistrar.getSecureRandom()) : ProductFormPolynomial.generateRandom(N, d1, d2, d3 + 1, d3, CryptoServicesRegistrar.getSecureRandom());
gInt = g.toIntegerPolynomial();
} while (primeCheck && gInt.resultant(_2n1).res.equals(ZERO));
} while (gInt.invertFq(q) == null);
rg = gInt.resultant();
r = BigIntEuclidean.calculate(rf.res, rg.res);
} while (!r.gcd.equals(ONE));
BigIntPolynomial A = (BigIntPolynomial) rf.rho.clone();
A.mult(r.x.multiply(BigInteger.valueOf(q)));
BigIntPolynomial B = (BigIntPolynomial) rg.rho.clone();
B.mult(r.y.multiply(BigInteger.valueOf(-q)));
BigIntPolynomial C;
if (params.keyGenAlg == NTRUSigningKeyGenerationParameters.KEY_GEN_ALG_RESULTANT) {
int[] fRevCoeffs = new int[N];
int[] gRevCoeffs = new int[N];
fRevCoeffs[0] = fInt.coeffs[0];
gRevCoeffs[0] = gInt.coeffs[0];
for (int i = 1; i < N; i++) {
fRevCoeffs[i] = fInt.coeffs[N - i];
gRevCoeffs[i] = gInt.coeffs[N - i];
}
IntegerPolynomial fRev = new IntegerPolynomial(fRevCoeffs);
IntegerPolynomial gRev = new IntegerPolynomial(gRevCoeffs);
IntegerPolynomial t = f.mult(fRev);
t.add(g.mult(gRev));
Resultant rt = t.resultant();
C = fRev.mult(// fRev.mult(B) is actually faster than new SparseTernaryPolynomial(fRev).mult(B), possibly due to cache locality?
B);
C.add(gRev.mult(A));
C = C.mult(rt.rho);
C.div(rt.res);
} else {
// KeyGenAlg.FLOAT
// calculate ceil(log10(N))
int log10N = 0;
for (int i = 1; i < N; i *= 10) {
log10N++;
}
// * Cdec needs to be accurate to 1 decimal place so it can be correctly rounded;
// * fInv loses up to (#digits of longest coeff of B) places in fInv.mult(B);
// * multiplying fInv by B also multiplies the rounding error by a factor of N;
// so make #decimal places of fInv the sum of the above.
BigDecimalPolynomial fInv = rf.rho.div(new BigDecimal(rf.res), B.getMaxCoeffLength() + 1 + log10N);
BigDecimalPolynomial gInv = rg.rho.div(new BigDecimal(rg.res), A.getMaxCoeffLength() + 1 + log10N);
BigDecimalPolynomial Cdec = fInv.mult(B);
Cdec.add(gInv.mult(A));
Cdec.halve();
C = Cdec.round();
}
BigIntPolynomial F = (BigIntPolynomial) B.clone();
F.sub(f.mult(C));
BigIntPolynomial G = (BigIntPolynomial) A.clone();
G.sub(g.mult(C));
IntegerPolynomial FInt = new IntegerPolynomial(F);
IntegerPolynomial GInt = new IntegerPolynomial(G);
minimizeFG(fInt, gInt, FInt, GInt, N);
Polynomial fPrime;
IntegerPolynomial h;
if (basisType == NTRUSigningKeyGenerationParameters.BASIS_TYPE_STANDARD) {
fPrime = FInt;
h = g.mult(fq, q);
} else {
fPrime = g;
h = FInt.mult(fq, q);
}
h.modPositive(q);
return new FGBasis(f, fPrime, h, FInt, GInt, params);
}
use of com.github.zhenwei.core.pqc.math.ntru.polynomial.Polynomial in project LinLong-Java by zhenwei1108.
the class NTRUEngine method encrypt.
/**
* Encrypts a message.<br/> See P1363.1 section 9.2.2.
*
* @param m The message to encrypt
* @param pubKey the public key to encrypt the message with
* @return the encrypted message
*/
private byte[] encrypt(byte[] m, NTRUEncryptionPublicKeyParameters pubKey) {
IntegerPolynomial pub = pubKey.h;
int N = params.N;
int q = params.q;
int maxLenBytes = params.maxMsgLenBytes;
int db = params.db;
int bufferLenBits = params.bufferLenBits;
int dm0 = params.dm0;
int pkLen = params.pkLen;
int minCallsMask = params.minCallsMask;
boolean hashSeed = params.hashSeed;
byte[] oid = params.oid;
int l = m.length;
if (maxLenBytes > 255) {
throw new IllegalArgumentException("llen values bigger than 1 are not supported");
}
if (l > maxLenBytes) {
throw new DataLengthException("Message too long: " + l + ">" + maxLenBytes);
}
while (true) {
// M = b|octL|m|p0
byte[] b = new byte[db / 8];
random.nextBytes(b);
byte[] p0 = new byte[maxLenBytes + 1 - l];
byte[] M = new byte[bufferLenBits / 8];
System.arraycopy(b, 0, M, 0, b.length);
M[b.length] = (byte) l;
System.arraycopy(m, 0, M, b.length + 1, m.length);
System.arraycopy(p0, 0, M, b.length + 1 + m.length, p0.length);
IntegerPolynomial mTrin = IntegerPolynomial.fromBinary3Sves(M, N);
// sData = OID|m|b|hTrunc
byte[] bh = pub.toBinary(q);
byte[] hTrunc = copyOf(bh, pkLen / 8);
byte[] sData = buildSData(oid, m, l, b, hTrunc);
Polynomial r = generateBlindingPoly(sData, M);
IntegerPolynomial R = r.mult(pub, q);
IntegerPolynomial R4 = (IntegerPolynomial) R.clone();
R4.modPositive(4);
byte[] oR4 = R4.toBinary(4);
IntegerPolynomial mask = MGF(oR4, N, minCallsMask, hashSeed);
mTrin.add(mask);
mTrin.mod3();
if (mTrin.count(-1) < dm0) {
continue;
}
if (mTrin.count(0) < dm0) {
continue;
}
if (mTrin.count(1) < dm0) {
continue;
}
R.add(mTrin, q);
R.ensurePositive(q);
return R.toBinary(q);
}
}
use of com.github.zhenwei.core.pqc.math.ntru.polynomial.Polynomial in project LinLong-Java by zhenwei1108.
the class NTRUEngine method decrypt.
/**
* Decrypts a message.<br/> See P1363.1 section 9.2.3.
*
* @param data The message to decrypt
* @param privKey the corresponding private key
* @return the decrypted message
* @throws InvalidCipherTextException if the encrypted data is invalid, or <code>maxLenBytes</code>
* is greater than 255
*/
private byte[] decrypt(byte[] data, NTRUEncryptionPrivateKeyParameters privKey) throws InvalidCipherTextException {
Polynomial priv_t = privKey.t;
IntegerPolynomial priv_fp = privKey.fp;
IntegerPolynomial pub = privKey.h;
int N = params.N;
int q = params.q;
int db = params.db;
int maxMsgLenBytes = params.maxMsgLenBytes;
int dm0 = params.dm0;
int pkLen = params.pkLen;
int minCallsMask = params.minCallsMask;
boolean hashSeed = params.hashSeed;
byte[] oid = params.oid;
if (maxMsgLenBytes > 255) {
throw new DataLengthException("maxMsgLenBytes values bigger than 255 are not supported");
}
int bLen = db / 8;
IntegerPolynomial e = IntegerPolynomial.fromBinary(data, N, q);
IntegerPolynomial ci = decrypt(e, priv_t, priv_fp);
if (ci.count(-1) < dm0) {
throw new InvalidCipherTextException("Less than dm0 coefficients equal -1");
}
if (ci.count(0) < dm0) {
throw new InvalidCipherTextException("Less than dm0 coefficients equal 0");
}
if (ci.count(1) < dm0) {
throw new InvalidCipherTextException("Less than dm0 coefficients equal 1");
}
IntegerPolynomial cR = (IntegerPolynomial) e.clone();
cR.sub(ci);
cR.modPositive(q);
IntegerPolynomial cR4 = (IntegerPolynomial) cR.clone();
cR4.modPositive(4);
byte[] coR4 = cR4.toBinary(4);
IntegerPolynomial mask = MGF(coR4, N, minCallsMask, hashSeed);
IntegerPolynomial cMTrin = ci;
cMTrin.sub(mask);
cMTrin.mod3();
byte[] cM = cMTrin.toBinary3Sves();
byte[] cb = new byte[bLen];
System.arraycopy(cM, 0, cb, 0, bLen);
// llen=1, so read one byte
int cl = cM[bLen] & 0xFF;
if (cl > maxMsgLenBytes) {
throw new InvalidCipherTextException("Message too long: " + cl + ">" + maxMsgLenBytes);
}
byte[] cm = new byte[cl];
System.arraycopy(cM, bLen + 1, cm, 0, cl);
byte[] p0 = new byte[cM.length - (bLen + 1 + cl)];
System.arraycopy(cM, bLen + 1 + cl, p0, 0, p0.length);
if (!Arrays.constantTimeAreEqual(p0, new byte[p0.length])) {
throw new InvalidCipherTextException("The message is not followed by zeroes");
}
// sData = OID|m|b|hTrunc
byte[] bh = pub.toBinary(q);
byte[] hTrunc = copyOf(bh, pkLen / 8);
byte[] sData = buildSData(oid, cm, cl, cb, hTrunc);
Polynomial cr = generateBlindingPoly(sData, cm);
IntegerPolynomial cRPrime = cr.mult(pub);
cRPrime.modPositive(q);
if (!cRPrime.equals(cR)) {
throw new InvalidCipherTextException("Invalid message encoding");
}
return cm;
}
use of com.github.zhenwei.core.pqc.math.ntru.polynomial.Polynomial in project LinLong-Java by zhenwei1108.
the class NTRUSigner method sign.
private IntegerPolynomial sign(IntegerPolynomial i, NTRUSigningPrivateKeyParameters kp) {
int N = params.N;
int q = params.q;
int perturbationBases = params.B;
NTRUSigningPrivateKeyParameters kPriv = kp;
NTRUSigningPublicKeyParameters kPub = kp.getPublicKey();
IntegerPolynomial s = new IntegerPolynomial(N);
int iLoop = perturbationBases;
while (iLoop >= 1) {
Polynomial f = kPriv.getBasis(iLoop).f;
Polynomial fPrime = kPriv.getBasis(iLoop).fPrime;
IntegerPolynomial y = f.mult(i);
y.div(q);
y = fPrime.mult(y);
IntegerPolynomial x = fPrime.mult(i);
x.div(q);
x = f.mult(x);
IntegerPolynomial si = y;
si.sub(x);
s.add(si);
IntegerPolynomial hi = (IntegerPolynomial) kPriv.getBasis(iLoop).h.clone();
if (iLoop > 1) {
hi.sub(kPriv.getBasis(iLoop - 1).h);
} else {
hi.sub(kPub.h);
}
i = si.mult(hi, q);
iLoop--;
}
Polynomial f = kPriv.getBasis(0).f;
Polynomial fPrime = kPriv.getBasis(0).fPrime;
IntegerPolynomial y = f.mult(i);
y.div(q);
y = fPrime.mult(y);
IntegerPolynomial x = fPrime.mult(i);
x.div(q);
x = f.mult(x);
y.sub(x);
s.add(y);
s.modPositive(q);
return s;
}
Aggregations