org.bouncycastle.pqc.crypto.crystals.kyber.KyberIndCpa 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.crystals.kyber;
import org.bouncycastle.crypto.digests.SHAKEDigest;
import org.bouncycastle.util.Arrays;
class KyberIndCpa
{
private KyberEngine engine;
private int kyberK;
private int eta1;
private int indCpaPublicKeyBytes;
private int polyVecBytes;
private int indCpaBytes;
private int polyVecCompressedBytes;
private int polyCompressedBytes;
private Symmetric symmetric;
public KyberIndCpa(KyberEngine engine)
{
this.engine = engine;
this.kyberK = engine.getKyberK();
this.eta1 = engine.getKyberEta1();
this.indCpaPublicKeyBytes = engine.getKyberPublicKeyBytes();
this.polyVecBytes = engine.getKyberPolyVecBytes();
this.indCpaBytes = engine.getKyberIndCpaBytes();
this.polyVecCompressedBytes = engine.getKyberPolyVecCompressedBytes();
this.polyCompressedBytes = engine.getKyberPolyCompressedBytes();
this.symmetric = engine.getSymmetric();
KyberGenerateMatrixNBlocks =
(
(
12 * KyberEngine.KyberN
/ 8 * (1 << 12)
/ KyberEngine.KyberQ + symmetric.xofBlockBytes
)
/ symmetric.xofBlockBytes
);
}
/**
* Generates IndCpa Key Pair
*
* @return KeyPair where each key is represented as bytes
*/
byte[][] generateKeyPair()
{
PolyVec secretKey = new PolyVec(engine),
publicKey = new PolyVec(engine),
e = new PolyVec(engine);
byte[] d = new byte[32];
// (p, sigma) <- G(d)
engine.getRandomBytes(d);
byte[] buf = new byte[64];
symmetric.hash_g(buf, d);
byte[] publicSeed = new byte[32]; // p in docs
byte[] noiseSeed = new byte[32]; // sigma in docs
System.arraycopy(buf, 0, publicSeed, 0, 32);
System.arraycopy(buf, 32, noiseSeed, 0, 32);
byte count = (byte)0;
// Helper.printByteArray(buf);
PolyVec[] aMatrix = new PolyVec[kyberK];
int i;
for (i = 0; i < kyberK; i++)
{
aMatrix[i] = new PolyVec(engine);
}
generateMatrix(aMatrix, publicSeed, false);
// System.out.println("aMatrix = ");
// for(i = 0; i < kyberK; i++) {
// System.out.print("[");
// for (int j = 0; j < kyberK; j++) {
// System.out.print("[");
// for (int k = 0; k < KyberEngine.KyberN; k++) {
// System.out.printf("%d ,", aMatrix[i].getVectorIndex(j).getCoeffIndex(k));
// }
// System.out.print("], \n");
// }
// System.out.print("]\n");
// }
for (i = 0; i < kyberK; i++)
{
secretKey.getVectorIndex(i).getEta1Noise(noiseSeed, count);
// System.out.print("SecretKeyPolyVec["+i+"] = [");
// for (int j =0; j < KyberEngine.KyberN; j++) {
// System.out.print(secretKey.getVectorIndex(i).getCoeffIndex(j) + ", ");
// }
// System.out.println("]");
count = (byte)(count + (byte)1);
}
for (i = 0; i < kyberK; i++)
{
e.getVectorIndex(i).getEta1Noise(noiseSeed, count);
count = (byte)(count + (byte)1);
}
secretKey.polyVecNtt();
// System.out.print("SecretKeyPolyVec = [");
// for (i = 0; i < kyberK; i++) {
// System.out.print("[");
// for (int j =0; j < KyberEngine.KyberN; j++) {
// System.out.print(secretKey.getVectorIndex(i).getCoeffIndex(j) + ", ");
// }
// System.out.println("],");
// }
// System.out.println("]");
e.polyVecNtt();
for (i = 0; i < kyberK; i++)
{
PolyVec.pointwiseAccountMontgomery(publicKey.getVectorIndex(i), aMatrix[i], secretKey, engine);
publicKey.getVectorIndex(i).convertToMont();
}
// System.out.print("PublicKey PolyVec = [");
// Helper.printPolyVec(publicKey, kyberK);
publicKey.addPoly(e);
publicKey.reducePoly();
return new byte[][]{packPublicKey(publicKey, publicSeed), packSecretKey(secretKey)};
}
public byte[] encrypt(byte[] msg, byte[] publicKeyInput, byte[] coins)
{
int i;
byte[] seed;
byte nonce = (byte)0;
PolyVec sp = new PolyVec(engine),
publicKeyPolyVec = new PolyVec(engine),
errorPolyVector = new PolyVec(engine),
bp = new PolyVec(engine);
PolyVec[] aMatrixTranspose = new PolyVec[engine.getKyberK()];
Poly errorPoly = new Poly(engine),
v = new Poly(engine),
k = new Poly(engine);
// System.out.print("publickeyinput = ");
// Helper.printByteArray(publicKeyInput);
// System.out.println();
seed = unpackPublicKey(publicKeyPolyVec, publicKeyInput);
// System.out.print("publickeyPolyVec = [");
// for (i = 0; i < kyberK; i++) {
// Helper.printShortArray(publicKeyPolyVec.getVectorIndex(i).getCoeffs());
// System.out.print("], \n");
// }
// System.out.println("]");
// System.out.print("seed = ");
// Helper.printByteArray(seed);
// System.out.println();
k.fromMsg(msg);
for (i = 0; i < kyberK; i++)
{
aMatrixTranspose[i] = new PolyVec(engine);
}
generateMatrix(aMatrixTranspose, seed, true);
// System.out.print("matrix transposed = ");
// for (i = 0; i < kyberK; i++) {
// System.out.print("[");
// for(int j = 0; j < kyberK; j++) {
// System.out.print("[");
// for (int l = 0; l < 256; l++) {
// System.out.printf("%d ,", aMatrixTranspose[i].getVectorIndex(j).getCoeffIndex(l));
// }
// System.out.print("] ,\n");
// }
// System.out.println("] ,");
// }
for (i = 0; i < kyberK; i++)
{
sp.getVectorIndex(i).getEta1Noise(coins, nonce);
nonce = (byte)(nonce + (byte)1);
}
for (i = 0; i < kyberK; i++)
{
errorPolyVector.getVectorIndex(i).getEta2Noise(coins, nonce);
nonce = (byte)(nonce + (byte)1);
}
errorPoly.getEta2Noise(coins, nonce);
sp.polyVecNtt();
// System.out.print("sp = [");
// for (i = 0; i < kyberK; i++) {
// Helper.printShortArray(sp.getVectorIndex(i).getCoeffs());
// System.out.print("], \n");
// }
// System.out.println("]");
// System.out.print("sp = [");
// for (i = 0; i < kyberK; i++) {
// Helper.printShortArray(sp.getVectorIndex(i).getCoeffs());
// System.out.print("], \n");
// }
// System.out.println("]");
for (i = 0; i < kyberK; i++)
{
PolyVec.pointwiseAccountMontgomery(bp.getVectorIndex(i), aMatrixTranspose[i], sp, engine);
}
// System.out.print("bp = [");
// for (i = 0; i < kyberK; i++) {
// Helper.printShortArray(bp.getVectorIndex(i).getCoeffs());
// System.out.print("], \n");
// }
// System.out.println("]");
PolyVec.pointwiseAccountMontgomery(v, publicKeyPolyVec, sp, engine);
bp.polyVecInverseNttToMont();
v.polyInverseNttToMont();
bp.addPoly(errorPolyVector);
v.addCoeffs(errorPoly);
v.addCoeffs(k);
bp.reducePoly();
v.reduce();
// System.out.print("bp = [");
// for (i = 0; i < kyberK; i++) {
// Helper.printShortArray(bp.getVectorIndex(i).getCoeffs());
// System.out.print("], \n");
// }
// System.out.println("]");
// System.out.print("v = ");
// Helper.printShortArray(v.getCoeffs());
// System.out.println();
byte[] outputCipherText = packCipherText(bp, v);
return outputCipherText;
}
private byte[] packCipherText(PolyVec b, Poly v)
{
byte[] outBuf = new byte[indCpaBytes];
System.arraycopy(b.compressPolyVec(), 0, outBuf, 0, polyVecCompressedBytes);
System.arraycopy(v.compressPoly(), 0, outBuf, polyVecCompressedBytes, polyCompressedBytes);
// System.out.print("outBuf = [");
// Helper.printByteArray(outBuf);
return outBuf;
}
private void unpackCipherText(PolyVec b, Poly v, byte[] cipherText)
{
byte[] compressedPolyVecCipherText = Arrays.copyOfRange(cipherText, 0, engine.getKyberPolyVecCompressedBytes());
b.decompressPolyVec(compressedPolyVecCipherText);
byte[] compressedPolyCipherText = Arrays.copyOfRange(cipherText, engine.getKyberPolyVecCompressedBytes(), cipherText.length);
v.decompressPoly(compressedPolyCipherText);
}
public byte[] packPublicKey(PolyVec publicKeyPolyVec, byte[] seed)
{
byte[] buf = new byte[indCpaPublicKeyBytes];
System.arraycopy(publicKeyPolyVec.toBytes(), 0, buf, 0, polyVecBytes);
System.arraycopy(seed, 0, buf, polyVecBytes, KyberEngine.KyberSymBytes);
return buf;
}
public byte[] unpackPublicKey(PolyVec publicKeyPolyVec, byte[] publicKey)
{
byte[] outputSeed = new byte[KyberEngine.KyberSymBytes];
publicKeyPolyVec.fromBytes(publicKey);
System.arraycopy(publicKey, polyVecBytes, outputSeed, 0, KyberEngine.KyberSymBytes);
return outputSeed;
}
public byte[] packSecretKey(PolyVec secretKeyPolyVec)
{
return secretKeyPolyVec.toBytes();
}
public void unpackSecretKey(PolyVec secretKeyPolyVec, byte[] secretKey)
{
secretKeyPolyVec.fromBytes(secretKey);
}
public final int KyberGenerateMatrixNBlocks;
public void generateMatrix(PolyVec[] aMatrix, byte[] seed, boolean transposed)
{
int i, j, k, ctr, off;
SHAKEDigest kyberXOF;
byte[] buf = new byte[KyberGenerateMatrixNBlocks * symmetric.xofBlockBytes + 2];
for (i = 0; i < kyberK; i++)
{
for (j = 0; j < kyberK; j++)
{
if (transposed)
{
symmetric.xofAbsorb(seed, (byte) i, (byte) j);
}
else
{
symmetric.xofAbsorb(seed, (byte) j, (byte) i);
}
symmetric.xofSqueezeBlocks(buf, 0, symmetric.xofBlockBytes * KyberGenerateMatrixNBlocks);
int buflen = KyberGenerateMatrixNBlocks * symmetric.xofBlockBytes;
ctr = rejectionSampling(aMatrix[i].getVectorIndex(j), 0, KyberEngine.KyberN, buf, buflen);
while (ctr < KyberEngine.KyberN)
{
off = buflen % 3;
for (k = 0; k < off; k++)
{
buf[k] = buf[buflen - off + k];
}
symmetric.xofSqueezeBlocks(buf, off, symmetric.xofBlockBytes * 2);
buflen = off + symmetric.xofBlockBytes;
// Error in code Section Unsure
ctr += rejectionSampling(aMatrix[i].getVectorIndex(j), ctr, KyberEngine.KyberN - ctr, buf, buflen);
}
}
}
}
private static int rejectionSampling(Poly outputBuffer, int coeffOff, int len, byte[] inpBuf, int inpBufLen)
{
int ctr, pos;
short val0, val1;
ctr = pos = 0;
while (ctr < len && pos + 3 <= inpBufLen)
{
val0 = (short)(((((short)(inpBuf[pos] & 0xFF)) >> 0) | (((short)(inpBuf[pos + 1] & 0xFF)) << 8)) & 0xFFF);
val1 = (short)(((((short)(inpBuf[pos + 1] & 0xFF)) >> 4) | (((short)(inpBuf[pos + 2] & 0xFF)) << 4)) & 0xFFF);
pos = pos + 3;
if (val0 < (short)KyberEngine.KyberQ)
{
outputBuffer.setCoeffIndex(coeffOff + ctr, (short)val0);
ctr++;
}
if (ctr < len && val1 < (short)KyberEngine.KyberQ)
{
outputBuffer.setCoeffIndex(coeffOff + ctr, (short)val1);
ctr++;
}
}
return ctr;
}
public byte[] decrypt(byte[] cipherText, byte[] secretKey)
{
int i;
byte[] outputMessage = new byte[KyberEngine.getKyberIndCpaMsgBytes()];
PolyVec bp = new PolyVec(engine), secretKeyPolyVec = new PolyVec(engine);
Poly v = new Poly(engine), mp = new Poly(engine);
unpackCipherText(bp, v, cipherText);
// System.out.print("bp = [");
// for (i = 0; i < kyberK; i++) {
// Helper.printShortArray(bp.getVectorIndex(i).getCoeffs());
// System.out.print("], \n");
// }
// System.out.println("]");
// System.out.print("v = ");
// Helper.printShortArray(v.getCoeffs());
// System.out.println();
unpackSecretKey(secretKeyPolyVec, secretKey);
// System.out.print("decrypt secretkey = ");;
// Helper.printByteArray(secretKey);
// System.out.print("SecretKeyPolyVec = [");
// for (i = 0; i < kyberK; i++) {
// System.out.print("[");
// for (int j =0; j < KyberEngine.KyberN; j++) {
// System.out.print(secretKeyPolyVec.getVectorIndex(i).getCoeffIndex(j) + ", ");
// }
// System.out.println("],");
// }
// System.out.println("]");
// System.out.print("bp before ntt = [");
// for (i = 0; i < kyberK; i++) {
// Helper.printShortArray(bp.getVectorIndex(i).getCoeffs());
// System.out.print("], \n");
// }
// System.out.println("]");
bp.polyVecNtt();
// System.out.print("bp after ntt = [");
// for (i = 0; i < kyberK; i++) {
// Helper.printShortArray(bp.getVectorIndex(i).getCoeffs());
// System.out.print("], \n");
// }
// System.out.println("]");
PolyVec.pointwiseAccountMontgomery(mp, secretKeyPolyVec, bp, engine);
mp.polyInverseNttToMont();
mp.polySubtract(v);
mp.reduce();
outputMessage = mp.toMsg();
return outputMessage;
}
}