org.bouncycastle.pqc.crypto.hqc.FastFourierTransform Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bcprov-ext-debug-jdk18on Show documentation
Show all versions of bcprov-ext-debug-jdk18on Show documentation
The Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. This jar contains JCE provider and lightweight API for the Bouncy Castle Cryptography APIs for Java 1.8 and later with debug enabled.
The newest version!
package org.bouncycastle.pqc.crypto.hqc;
class FastFourierTransform
{
static void fastFourierTransform(int[] output, int[] elements, int noCoefs, int fft)
{
int m = HQCParameters.PARAM_M;
int mSize = 1 << (HQCParameters.PARAM_M - 1);
int fftSize = 1 << fft;
int[] f0 = new int[fftSize];
int[] f1 = new int[fftSize];
int[] deltas = new int[m - 1];
int[] u = new int[mSize];
int[] v = new int[mSize];
// Step 1: Compute betas
int[] betas = new int[m - 1];
int[] betaSum = new int[mSize];
computeFFTBetas(betas, m);
computeSubsetSum(betaSum, betas, m - 1);
// Step 2: Compute radix
computeRadix(f0, f1, elements, fft, fft);
// Step 3: Compute deltas
for (int i = 0; i < m - 1; i++)
{
deltas[i] = GFCalculator.mult(betas[i], betas[i]) ^ betas[i];
}
// Step 5:
computeFFTRec(u, f0, (noCoefs + 1) / 2, m - 1, fft - 1, deltas, fft, m);
computeFFTRec(v, f1, noCoefs / 2, m - 1, fft - 1, deltas, fft, m);
// Step 6.7
int k = 1;
k = 1 << (m - 1);
System.arraycopy(v, 0, output, k, k);
output[0] = u[0];
output[k] ^= u[0];
for (int i = 1; i < k; i++)
{
output[i] = u[i] ^ GFCalculator.mult(betaSum[i], v[i]);
output[k + i] ^= output[i];
}
}
static void computeFFTBetas(int[] betas, int m)
{
for (int i = 0; i < m - 1; i++)
{
betas[i] = 1 << (m - 1 - i);
}
}
static void computeSubsetSum(int[] subsetSum, int[] set, int size)
{
subsetSum[0] = 0;
for (int i = 0; i < size; i++)
{
for (int j = 0; j < (1 << i); j++)
{
subsetSum[(1 << i) + j] = set[i] ^ subsetSum[j];
}
}
}
static void computeRadix(int[] f0, int[] f1, int[] f, int mf, int fft)
{
switch (mf)
{
case 4:
f0[4] = f[8] ^ f[12];
f0[6] = f[12] ^ f[14];
f0[7] = f[14] ^ f[15];
f1[5] = f[11] ^ f[13];
f1[6] = f[13] ^ f[14];
f1[7] = f[15];
f0[5] = f[10] ^ f[12] ^ f1[5];
f1[4] = f[9] ^ f[13] ^ f0[5];
f0[0] = f[0];
f1[3] = f[7] ^ f[11] ^ f[15];
f0[3] = f[6] ^ f[10] ^ f[14] ^ f1[3];
f0[2] = f[4] ^ f0[4] ^ f0[3] ^ f1[3];
f1[1] = f[3] ^ f[5] ^ f[9] ^ f[13] ^ f1[3];
f1[2] = f[3] ^ f1[1] ^ f0[3];
f0[1] = f[2] ^ f0[2] ^ f1[1];
f1[0] = f[1] ^ f0[1];
return;
case 3:
f0[0] = f[0];
f0[2] = f[4] ^ f[6];
f0[3] = f[6] ^ f[7];
f1[1] = f[3] ^ f[5] ^ f[7];
f1[2] = f[5] ^ f[6];
f1[3] = f[7];
f0[1] = f[2] ^ f0[2] ^ f1[1];
f1[0] = f[1] ^ f0[1];
return;
case 2:
f0[0] = f[0];
f0[1] = f[2] ^ f[3];
f1[0] = f[1] ^ f0[1];
f1[1] = f[3];
return;
case 1:
f0[0] = f[0];
f1[0] = f[1];
return;
default:
computeRadixBig(f0, f1, f, mf, fft);
break;
}
}
static void computeRadixBig(int[] f0, int[] f1, int[] f, int mf, int fft)
{
int n = 1;
n <<= (mf - 2);
int fftSize = 1 << (fft - 2);
int Q[] = new int[2 * fftSize];
int R[] = new int[2 * fftSize];
int Q0[] = new int[fftSize];
int Q1[] = new int[fftSize];
int R0[] = new int[fftSize];
int R1[] = new int[fftSize];
Utils.copyBytes(f, 3 * n, Q, 0, 2 * n);
Utils.copyBytes(f, 3 * n, Q, n, 2 * n);
Utils.copyBytes(f, 0, R, 0, 4 * n);
for (int i = 0; i < n; ++i)
{
Q[i] ^= f[2 * n + i];
R[n + i] ^= Q[i];
}
computeRadix(Q0, Q1, Q, mf - 1, fft);
computeRadix(R0, R1, R, mf - 1, fft);
Utils.copyBytes(R0, 0, f0, 0, 2 * n);
Utils.copyBytes(Q0, 0, f0, n, 2 * n);
Utils.copyBytes(R1, 0, f1, 0, 2 * n);
Utils.copyBytes(Q1, 0, f1, n, 2 * n);
}
static void computeFFTRec(int[] output, int[] func, int noCoeffs, int noOfBetas, int noCoeffsPlus, int[] betaSet, int fft, int m)
{
int fftSize = 1 << (fft - 2);
int mSize = 1 << (m - 2);
int[] fx0 = new int[fftSize];
int[] fx1 = new int[fftSize];
int[] gammaSet = new int[m - 2];
int[] deltaSet = new int[m - 2];
int k = 1;
int[] gammaSumSet = new int[mSize];
int[] uSet = new int[mSize];
int[] vSet = new int[mSize];
int[] tempSet = new int[m - fft + 1];
int x = 0;
if (noCoeffsPlus == 1)
{
for (int i = 0; i < noOfBetas; i++)
{
tempSet[i] = GFCalculator.mult(betaSet[i], func[1]);
}
output[0] = func[0];
x = 1;
for (int j = 0; j < noOfBetas; j++)
{
for (int t = 0; t < x; t++)
{
output[x + t] = output[t] ^ tempSet[j];
}
x <<= 1;
}
return;
}
if (betaSet[noOfBetas - 1] != 1)
{
int betaMPow = 1;
x = 1;
x <<= noCoeffsPlus;
for (int i = 1; i < x; i++)
{
betaMPow = GFCalculator.mult(betaMPow, betaSet[noOfBetas - 1]);
func[i] = GFCalculator.mult(betaMPow, func[i]);
}
}
computeRadix(fx0, fx1, func, noCoeffsPlus, fft);
for (int i = 0; i < noOfBetas - 1; i++)
{
gammaSet[i] = GFCalculator.mult(betaSet[i], GFCalculator.inverse(betaSet[noOfBetas - 1]));
deltaSet[i] = GFCalculator.mult(gammaSet[i], gammaSet[i]) ^ gammaSet[i];
}
computeSubsetSum(gammaSumSet, gammaSet, noOfBetas - 1);
computeFFTRec(uSet, fx0, (noCoeffs + 1) / 2, noOfBetas - 1, noCoeffsPlus - 1, deltaSet, fft, m);
k = 1;
k <<= ((noOfBetas - 1) & 0xf);
if (noCoeffs <= 3)
{
output[0] = uSet[0];
output[k] = uSet[0] ^ fx1[0];
for (int i = 1; i < k; i++)
{
output[i] = uSet[i] ^ GFCalculator.mult(gammaSumSet[i], fx1[0]);
output[k + i] = output[i] ^ fx1[0];
}
}
else
{
computeFFTRec(vSet, fx1, noCoeffs / 2, noOfBetas - 1, noCoeffsPlus - 1, deltaSet, fft, m);
// int[] tmp = new int[3*k];
// System.arraycopy(output, 0, tmp, 0 , output.length);
// System.arraycopy(vSet, 0, tmp, k , 2*k);
System.arraycopy(vSet, 0, output, k, k);
output[0] = uSet[0];
output[k] ^= uSet[0];
for (int i = 1; i < k; i++)
{
output[i] = uSet[i] ^ GFCalculator.mult(gammaSumSet[i], vSet[i]);
output[k + i] ^= output[i];
}
}
}
static void fastFourierTransformGetError(byte[] errorSet, int[] input, int mSize, int[] logArrays)
{
int m = HQCParameters.PARAM_M;
int gfMulOrder = HQCParameters.GF_MUL_ORDER;
int[] gammaSet = new int[m - 1];
int[] gammaSumSet = new int[mSize];
int k = mSize;
computeFFTBetas(gammaSet, m);
computeSubsetSum(gammaSumSet, gammaSet, m - 1);
errorSet[0] ^= 1 ^ Utils.toUnsigned16Bits(-input[0] >> 15);
errorSet[0] ^= 1 ^ Utils.toUnsigned16Bits(-input[k] >> 15);
for (int i = 1; i < k; i++)
{
int tmp = gfMulOrder - logArrays[gammaSumSet[i]];
errorSet[tmp] ^= 1 ^ Math.abs(-input[i] >> 15);
tmp = gfMulOrder - logArrays[gammaSumSet[i] ^ 1];
errorSet[tmp] ^= 1 ^ Math.abs(-input[k + i] >> 15);
}
}
}