use of com.github.zhenwei.core.pqc.math.ntru.euclid.BigIntEuclidean in project LinLong-Java by zhenwei1108.
the class ModularResultant method combineRho.
/**
* Calculates a <code>rho</code> modulo <code>m1*m2</code> from two resultants whose
* <code>rho</code>s are modulo <code>m1</code> and <code>m2</code>.<br/>
* </code>res</code> is set to <code>null</code>.
*
* @param modRes1
* @param modRes2
* @return <code>rho</code> modulo <code>modRes1.modulus * modRes2.modulus</code>, and
* <code>null</code> for </code>res</code>.
*/
static ModularResultant combineRho(ModularResultant modRes1, ModularResultant modRes2) {
BigInteger mod1 = modRes1.modulus;
BigInteger mod2 = modRes2.modulus;
BigInteger prod = mod1.multiply(mod2);
BigIntEuclidean er = BigIntEuclidean.calculate(mod2, mod1);
BigIntPolynomial rho1 = (BigIntPolynomial) modRes1.rho.clone();
rho1.mult(er.x.multiply(mod2));
BigIntPolynomial rho2 = (BigIntPolynomial) modRes2.rho.clone();
rho2.mult(er.y.multiply(mod1));
rho1.add(rho2);
rho1.mod(prod);
return new ModularResultant(rho1, null, prod);
}
use of com.github.zhenwei.core.pqc.math.ntru.euclid.BigIntEuclidean 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.euclid.BigIntEuclidean in project LinLong-Java by zhenwei1108.
the class IntegerPolynomial method resultant.
/**
* Resultant of this polynomial with <code>x^n-1</code> using a probabilistic algorithm.
* <p>
* Unlike EESS, this implementation does not compute all resultants modulo primes such that their
* product exceeds the maximum possible resultant, but rather stops when
* <code>NUM_EQUAL_RESULTANTS</code> consecutive modular resultants are equal.<br> This means the
* return value may be incorrect. Experiments show this happens in about 1 out of 100 cases when
* <code>N=439</code> and <code>NUM_EQUAL_RESULTANTS=2</code>, so the likelyhood of leaving the
* loop too early is <code>(1/100)^(NUM_EQUAL_RESULTANTS-1)</code>.
* <p>
* Because of the above, callers must verify the output and try a different polynomial if
* necessary.
*
* @return <code>(rho, res)</code> satisfying <code>res = rho*this + t*(x^n-1)</code> for some
* integer <code>t</code>.
*/
public Resultant resultant() {
int N = coeffs.length;
// Compute resultants modulo prime numbers. Continue until NUM_EQUAL_RESULTANTS consecutive modular resultants are equal.
LinkedList<ModularResultant> modResultants = new LinkedList<ModularResultant>();
BigInteger pProd = Constants.BIGINT_ONE;
BigInteger res = Constants.BIGINT_ONE;
// number of consecutive modular resultants equal to each other
int numEqual = 1;
PrimeGenerator primes = new PrimeGenerator();
while (true) {
BigInteger prime = primes.nextPrime();
ModularResultant crr = resultant(prime.intValue());
modResultants.add(crr);
BigInteger temp = pProd.multiply(prime);
BigIntEuclidean er = BigIntEuclidean.calculate(prime, pProd);
BigInteger resPrev = res;
res = res.multiply(er.x.multiply(prime));
BigInteger res2 = crr.res.multiply(er.y.multiply(pProd));
res = res.add(res2).mod(temp);
pProd = temp;
BigInteger pProd2 = pProd.divide(BigInteger.valueOf(2));
BigInteger pProd2n = pProd2.negate();
if (res.compareTo(pProd2) > 0) {
res = res.subtract(pProd);
} else if (res.compareTo(pProd2n) < 0) {
res = res.add(pProd);
}
if (res.equals(resPrev)) {
numEqual++;
if (numEqual >= NUM_EQUAL_RESULTANTS) {
break;
}
} else {
numEqual = 1;
}
}
// then combine pairs of those, etc. until only one is left.
while (modResultants.size() > 1) {
ModularResultant modRes1 = modResultants.removeFirst();
ModularResultant modRes2 = modResultants.removeFirst();
ModularResultant modRes3 = ModularResultant.combineRho(modRes1, modRes2);
modResultants.addLast(modRes3);
}
BigIntPolynomial rhoP = modResultants.getFirst().rho;
BigInteger pProd2 = pProd.divide(BigInteger.valueOf(2));
BigInteger pProd2n = pProd2.negate();
if (res.compareTo(pProd2) > 0) {
res = res.subtract(pProd);
}
if (res.compareTo(pProd2n) < 0) {
res = res.add(pProd);
}
for (int i = 0; i < N; i++) {
BigInteger c = rhoP.coeffs[i];
if (c.compareTo(pProd2) > 0) {
rhoP.coeffs[i] = c.subtract(pProd);
}
if (c.compareTo(pProd2n) < 0) {
rhoP.coeffs[i] = c.add(pProd);
}
}
return new Resultant(rhoP, res);
}
Aggregations