Date: Thu, 27 Feb 2025 17:21:18 +1030
Subject: [PATCH 136/890] Pass Key Pair Generation of Mayo
---
.../pqc/crypto/mayo/GF16Utils.java | 185 +++++++++
.../pqc/crypto/mayo/MayoEngine.java | 190 +++++++++
.../mayo/MayoKeyGenerationParameters.java | 24 ++
.../pqc/crypto/mayo/MayoKeyPairGenerator.java | 177 +++++++++
.../pqc/crypto/mayo/MayoKeyParameters.java | 22 ++
.../pqc/crypto/mayo/MayoParameters.java | 364 ++++++++++++++++++
.../crypto/mayo/MayoPrivateKeyParameter.java | 41 ++
.../crypto/mayo/MayoPublicKeyParameter.java | 26 ++
.../bouncycastle/pqc/crypto/mayo/Utils.java | 169 ++++++++
.../util/SubjectPublicKeyInfoFactory.java | 5 +-
.../pqc/crypto/test/MayoTest.java | 67 ++++
.../pqc/crypto/test/TestUtils.java | 93 +++++
12 files changed, 1361 insertions(+), 2 deletions(-)
create mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java
create mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoEngine.java
create mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyGenerationParameters.java
create mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
create mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyParameters.java
create mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoParameters.java
create mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPrivateKeyParameter.java
create mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPublicKeyParameter.java
create mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/mayo/Utils.java
create mode 100644 core/src/test/java/org/bouncycastle/pqc/crypto/test/MayoTest.java
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java
new file mode 100644
index 0000000000..9d42c4a5ca
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java
@@ -0,0 +1,185 @@
+package org.bouncycastle.pqc.crypto.mayo;
+
+public class GF16Utils
+{
+
+ /**
+ * Multiplies a 64-bit limb by a GF(16) element (represented as an int, 0–255).
+ * This emulates gf16v_mul_u64 from C.
+ *
+ * @param a a 64-bit limb
+ * @param b an 8-bit GF(16) element (only the low 4 bits are used)
+ * @return the product as a 64-bit limb
+ */
+ public static long gf16vMulU64(long a, int b)
+ {
+ long maskMsb = 0x8888888888888888L;
+ long a64 = a;
+ // In the original code there is a conditional XOR with unsigned_char_blocker;
+ // here we simply use b directly.
+ long b32 = b & 0x00000000FFFFFFFFL;
+ long r64 = a64 * (b32 & 1);
+
+ long a_msb = a64 & maskMsb;
+ a64 ^= a_msb;
+ a64 = (a64 << 1) ^ ((a_msb >>> 3) * 3);
+ r64 ^= a64 * ((b32 >> 1) & 1);
+
+ a_msb = a64 & maskMsb;
+ a64 ^= a_msb;
+ a64 = (a64 << 1) ^ ((a_msb >>> 3) * 3);
+ r64 ^= a64 * ((b32 >>> 2) & 1);
+
+ a_msb = a64 & maskMsb;
+ a64 ^= a_msb;
+ a64 = (a64 << 1) ^ ((a_msb >>> 3) * 3);
+ r64 ^= a64 * ((b32 >> 3) & 1);
+
+ return r64;
+ }
+
+ /**
+ * Multiplies each limb of a GF(16) vector (subarray of 'in') by the GF(16) element 'a'
+ * and XORs the result into the corresponding subarray of acc.
+ *
+ * This version uses explicit array offsets.
+ *
+ * @param mVecLimbs the number of limbs in the vector
+ * @param in the input long array containing the vector; the vector starts at index inOffset
+ * @param inOffset the starting index in 'in'
+ * @param a the GF(16) element (0–255) to multiply by
+ * @param acc the accumulator long array; the target vector starts at index accOffset
+ * @param accOffset the starting index in 'acc'
+ */
+ public static void mVecMulAdd(int mVecLimbs, long[] in, int inOffset, int a, long[] acc, int accOffset)
+ {
+ for (int i = 0; i < mVecLimbs; i++)
+ {
+ acc[accOffset + i] ^= gf16vMulU64(in[inOffset + i], a);
+ }
+ }
+
+ /**
+ * Convenience overload of mVecMulAdd that assumes zero offsets.
+ *
+ * @param mVecLimbs the number of limbs
+ * @param in the input vector
+ * @param a the GF(16) element to multiply by
+ * @param acc the accumulator vector
+ */
+ public static void mVecMulAdd(int mVecLimbs, long[] in, int a, long[] acc)
+ {
+ mVecMulAdd(mVecLimbs, in, 0, a, acc, 0);
+ }
+
+ /**
+ * Performs the multiplication and accumulation of a block of an upper‐triangular matrix
+ * times a second matrix.
+ *
+ * @param mVecLimbs number of limbs per m-vector.
+ * @param bsMat the “basis” matrix (as a flat long[] array); each entry occupies mVecLimbs elements.
+ * @param mat the second matrix (as a flat byte[] array) stored row‐major,
+ * with dimensions (bsMatCols x matCols).
+ * @param acc the accumulator (as a flat long[] array) with dimensions (bsMatRows x matCols);
+ * each “entry” is an m‐vector (length mVecLimbs).
+ * @param bsMatRows number of rows in the bsMat (the “triangular” matrix’s row count).
+ * @param bsMatCols number of columns in bsMat.
+ * @param matCols number of columns in the matrix “mat.”
+ * @param triangular if 1, start column index for each row is (r * triangular); otherwise use 0.
+ */
+ public static void mulAddMUpperTriangularMatXMat(int mVecLimbs, long[] bsMat, byte[] mat, long[] acc,
+ int bsMatRows, int bsMatCols, int matCols, int triangular)
+ {
+ int bsMatEntriesUsed = 0;
+ for (int r = 0; r < bsMatRows; r++)
+ {
+ // For each row r, the inner loop goes from column triangular*r to bsMatCols-1.
+ for (int c = triangular * r; c < bsMatCols; c++)
+ {
+ for (int k = 0; k < matCols; k++)
+ {
+ // Calculate the offsets:
+ // For bsMat: the m-vector starting at index bsMatEntriesUsed * mVecLimbs.
+ int bsMatOffset = bsMatEntriesUsed * mVecLimbs;
+ // For mat: element at row c, column k (row-major layout).
+ int a = mat[c * matCols + k] & 0xFF;
+ // For acc: add into the m-vector at row r, column k.
+ int accOffset = (r * matCols + k) * mVecLimbs;
+ GF16Utils.mVecMulAdd(mVecLimbs, bsMat, bsMatOffset, a, acc, accOffset);
+ }
+ bsMatEntriesUsed++;
+ }
+ }
+ }
+
+ /**
+ * Computes P1_times_O.
+ *
+ * In C:
+ * P1_times_O(p, P1, O, acc) calls:
+ * mul_add_m_upper_triangular_mat_x_mat(PARAM_m_vec_limbs(p), P1, O, acc, PARAM_v(p), PARAM_v(p), PARAM_o(p), 1);
+ *
+ * @param p the parameter object.
+ * @param P1 the P1 matrix as a long[] array.
+ * @param O the O matrix as a byte[] array.
+ * @param acc the output accumulator (long[] array).
+ */
+ public static void P1TimesO(MayoParameters p, long[] P1, byte[] O, long[] acc)
+ {
+ int mVecLimbs = p.getMVecLimbs();
+ int paramV = p.getV();
+ int paramO = p.getO();
+ // Here, bsMatRows and bsMatCols are both paramV, and matCols is paramO, triangular=1.
+ mulAddMUpperTriangularMatXMat(mVecLimbs, P1, O, acc, paramV, paramV, paramO, 1);
+ }
+
+ /**
+ * Multiplies the transpose of a single matrix with m matrices and adds the result into acc.
+ *
+ * @param mVecLimbs number of limbs per m-vector.
+ * @param mat the matrix to be transposed (as a flat byte[] array), dimensions: (matRows x matCols).
+ * @param bsMat the m-matrix (as a flat long[] array), with each entry of length mVecLimbs.
+ * Its logical dimensions: (matRows x bsMatCols).
+ * @param acc the accumulator (as a flat long[] array) with dimensions (matCols x bsMatCols);
+ * each entry is an m-vector.
+ * @param matRows number of rows in the matrix “mat.”
+ * @param matCols number of columns in “mat.”
+ * @param bsMatCols number of columns in the bsMat matrix.
+ */
+ public static void mulAddMatTransXMMat(int mVecLimbs, byte[] mat, long[] bsMat, long[] acc,
+ int matRows, int matCols, int bsMatCols)
+ {
+ // Loop over each column r of mat (which becomes row of mat^T)
+ for (int r = 0; r < matCols; r++)
+ {
+ for (int c = 0; c < matRows; c++)
+ {
+ for (int k = 0; k < bsMatCols; k++)
+ {
+ // For bsMat: the m-vector at index (c * bsMatCols + k)
+ int bsMatOffset = (c * bsMatCols + k) * mVecLimbs;
+ // For mat: element at row c, column r.
+ int a = mat[c * matCols + r] & 0xFF;
+ // For acc: add into the m-vector at index (r * bsMatCols + k)
+ int accOffset = (r * bsMatCols + k) * mVecLimbs;
+ GF16Utils.mVecMulAdd(mVecLimbs, bsMat, bsMatOffset, a, acc, accOffset);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Adds (bitwise XOR) mVecLimbs elements from the source array (starting at srcOffset)
+ * into the destination array (starting at destOffset).
+ */
+ public static void mVecAdd(int mVecLimbs, long[] src, int srcOffset, long[] dest, int destOffset)
+ {
+ for (int i = 0; i < mVecLimbs; i++)
+ {
+ dest[destOffset + i] ^= src[srcOffset + i];
+ }
+ }
+
+}
+
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoEngine.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoEngine.java
new file mode 100644
index 0000000000..51cf98bc74
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoEngine.java
@@ -0,0 +1,190 @@
+package org.bouncycastle.pqc.crypto.mayo;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.engines.AESEngine;
+import org.bouncycastle.crypto.modes.CTRModeCipher;
+import org.bouncycastle.crypto.modes.SICBlockCipher;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Pack;
+
+public class MayoEngine
+{
+ /**
+ * Expands P1 and P2 using AES_128_CTR as a PRF and then unpacks the resulting bytes
+ * into an array of 64-bit limbs.
+ *
+ * @param p Mayo parameters
+ * @param P The output long array which will hold the unpacked limbs.
+ * Its length should be at least ((P1_bytes + P2_bytes) / 8) limbs.
+ * @param seed_pk The seed (used as the key) for the PRF.
+ * @return The number of bytes produced, i.e., P1_bytes + P2_bytes.
+ */
+ public static int expandP1P2(MayoParameters p, long[] P, byte[] seed_pk)
+ {
+ // Compute total number of bytes to generate: P1_bytes + P2_bytes.
+ int outLen = p.getP1Bytes() + p.getP2Bytes();
+ // Temporary byte array to hold the PRF output.
+ byte[] temp = new byte[outLen];
+
+ // Call AES_128_CTR (our previously defined function using BouncyCastle)
+ // to fill temp with outLen pseudorandom bytes using seed_pk as key.
+ AES_128_CTR(temp, outLen, seed_pk, p.getPkSeedBytes());
+
+ // The number of vectors is the total limbs divided by mVecLimbs.
+ int numVectors = (p.getP1Limbs() + p.getP2Limbs()) / p.getMVecLimbs();
+
+ // Unpack the byte array 'temp' into the long array 'P'
+ // using our previously defined unpackMVecs method.
+ Utils.unpackMVecs(temp, P, numVectors, p.getM());
+
+ // Return the number of output bytes produced.
+ return outLen;
+ }
+
+ /**
+ * AES_128_CTR generates outputByteLen bytes using AES-128 in CTR mode.
+ * The key (of length keyLen) is used to expand the AES key.
+ * A 16-byte IV (all zeros) is used.
+ *
+ * @param output the output buffer which will be filled with the keystream
+ * @param outputByteLen the number of bytes to produce
+ * @param key the AES key (should be 16 bytes for AES-128)
+ * @param keyLen the length of the key (unused here but kept for similarity)
+ * @return the number of output bytes produced (i.e. outputByteLen)
+ */
+ public static int AES_128_CTR(byte[] output, int outputByteLen, byte[] key, int keyLen)
+ {
+ // Create a 16-byte IV (all zeros)
+ byte[] iv = new byte[16]; // automatically zero-initialized
+
+ // Set up AES engine in CTR (SIC) mode.
+ BlockCipher aesEngine = AESEngine.newInstance();
+ // SICBlockCipher implements CTR mode for AES.
+ CTRModeCipher ctrCipher = SICBlockCipher.newInstance(aesEngine);
+ // Wrap the key with the IV.
+ ParametersWithIV params = new ParametersWithIV(new KeyParameter(Arrays.copyOf(key, keyLen)), iv);
+ ctrCipher.init(true, params);
+
+ // CTR mode is a stream cipher: encrypting zero bytes produces the keystream.
+ int blockSize = ctrCipher.getBlockSize(); // typically 16 bytes
+ byte[] zeroBlock = new byte[blockSize]; // block of zeros
+ byte[] blockOut = new byte[blockSize];
+
+ int offset = 0;
+ // Process full blocks
+ while (offset + blockSize <= outputByteLen)
+ {
+ ctrCipher.processBlock(zeroBlock, 0, blockOut, 0);
+ System.arraycopy(blockOut, 0, output, offset, blockSize);
+ offset += blockSize;
+ }
+ // Process any remaining partial block.
+ if (offset < outputByteLen)
+ {
+ ctrCipher.processBlock(zeroBlock, 0, blockOut, 0);
+ int remaining = outputByteLen - offset;
+ System.arraycopy(blockOut, 0, output, offset, remaining);
+ }
+ return outputByteLen;
+ }
+
+ public static final int MAYO_OK = 0;
+ public static final int PK_SEED_BYTES_MAX = 16; // Adjust as needed
+ public static final int O_BYTES_MAX = 312; // Adjust as needed
+
+ /**
+ * Expands the secret key.
+ *
+ * @param p the MayoParameters instance.
+ * @param csk the input secret key seed (byte array).
+ * @param sk the Sk object that holds the expanded secret key components.
+ * @return MAYO_OK on success.
+ */
+// public static int mayoExpandSk(MayoParameters p, byte[] csk, MayoPrivateKeyParameter sk)
+// {
+// int ret = MAYO_OK;
+// int totalS = PK_SEED_BYTES_MAX + O_BYTES_MAX;
+// byte[] S = new byte[totalS];
+//
+// // sk.p is the long[] array, sk.O is the byte[] array.
+//
+// long[] P = new long[p.getPkSeedBytes() >> 3];
+// Pack.littleEndianToLong(sk.getP(), 0, P);
+// byte[] O = sk.getO();
+//
+// int param_o = p.getO();
+// int param_v = p.getV();
+// int param_O_bytes = p.getOBytes();
+// int param_pk_seed_bytes = p.getPkSeedBytes();
+// int param_sk_seed_bytes = p.getSkSeedBytes();
+//
+// // In C, seed_sk = csk and seed_pk = S (the beginning of S)
+// byte[] seed_sk = csk;
+// byte[] seed_pk = S; // first param_pk_seed_bytes of S
+//
+// // Generate S = seed_pk || (additional bytes), using SHAKE256.
+// // Output length is param_pk_seed_bytes + param_O_bytes.
+// Utils.shake256(S, param_pk_seed_bytes + param_O_bytes, seed_sk, param_sk_seed_bytes);
+//
+// // Decode the portion of S after the first param_pk_seed_bytes into O.
+// // (In C, this is: decode(S + param_pk_seed_bytes, O, param_v * param_o))
+// Utils.decode(S, param_pk_seed_bytes, O, param_v * param_o);
+//
+// // Expand P1 and P2 into the long array P using seed_pk.
+// MayoEngine.expandP1P2(p, P, seed_pk);
+//
+// // Let P2 start at offset = PARAM_P1_limbs(p)
+// int p1Limbs = p.getP1Limbs();
+// int offsetP2 = p1Limbs;
+//
+// // Compute L_i = (P1 + P1^t)*O + P2.
+// // Here, we assume that P1P1tTimesO writes into the portion of P starting at offsetP2.
+// P1P1tTimesO(p, P, O, P, offsetP2);
+//
+// // Securely clear sensitive temporary data.
+// java.util.Arrays.fill(S, (byte)0);
+// return ret;
+// }
+
+ /**
+ * Multiplies and accumulates the product (P1 + P1^t)*O into the accumulator.
+ * This version writes into the 'acc' array starting at the specified offset.
+ *
+ * @param p the MayoParameters.
+ * @param P1 the P1 vector as a long[] array.
+ * @param O the O array (each byte represents a GF(16) element).
+ * @param acc the accumulator array where results are XORed in.
+ * @param accOffset the starting index in acc.
+ */
+ public static void P1P1tTimesO(MayoParameters p, long[] P1, byte[] O, long[] acc, int accOffset)
+ {
+ int paramO = p.getO();
+ int paramV = p.getV();
+ int mVecLimbs = p.getMVecLimbs();
+ int bsMatEntriesUsed = 0;
+ for (int r = 0; r < paramV; r++)
+ {
+ for (int c = r; c < paramV; c++)
+ {
+ if (c == r)
+ {
+ bsMatEntriesUsed++;
+ continue;
+ }
+ for (int k = 0; k < paramO; k++)
+ {
+ // Multiply the m-vector at P1 for the current matrix entry,
+ // and accumulate into acc for row r.
+ GF16Utils.mVecMulAdd(mVecLimbs, P1, bsMatEntriesUsed * mVecLimbs,
+ O[c * paramO + k] & 0xFF, acc, accOffset + (r * paramO + k) * mVecLimbs);
+ // Similarly, accumulate into acc for row c.
+ GF16Utils.mVecMulAdd(mVecLimbs, P1, bsMatEntriesUsed * mVecLimbs,
+ O[r * paramO + k] & 0xFF, acc, accOffset + (c * paramO + k) * mVecLimbs);
+ }
+ bsMatEntriesUsed++;
+ }
+ }
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyGenerationParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyGenerationParameters.java
new file mode 100644
index 0000000000..0ca1b7f1b4
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyGenerationParameters.java
@@ -0,0 +1,24 @@
+package org.bouncycastle.pqc.crypto.mayo;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.KeyGenerationParameters;
+
+public class MayoKeyGenerationParameters
+ extends KeyGenerationParameters
+{
+ private final MayoParameters params;
+
+ public MayoKeyGenerationParameters(
+ SecureRandom random,
+ MayoParameters mayoParameters)
+ {
+ super(random, 256);
+ this.params = mayoParameters;
+ }
+
+ public MayoParameters getParameters()
+ {
+ return params;
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
new file mode 100644
index 0000000000..96e4e9fb01
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
@@ -0,0 +1,177 @@
+package org.bouncycastle.pqc.crypto.mayo;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bouncycastle.crypto.KeyGenerationParameters;
+import org.bouncycastle.util.Pack;
+
+public class MayoKeyPairGenerator
+ implements AsymmetricCipherKeyPairGenerator
+{
+ private MayoParameters p;
+ private SecureRandom random;
+
+
+ public void init(KeyGenerationParameters param)
+ {
+ this.p = ((MayoKeyGenerationParameters)param).getParameters();
+ this.random = param.getRandom();
+ }
+
+
+ @Override
+ public AsymmetricCipherKeyPair generateKeyPair()
+ {
+ int ret = MayoEngine.MAYO_OK;
+ byte[] cpk = new byte[p.getCpkBytes()];
+ // seed_sk points to csk.
+ byte[] seed_sk = new byte[p.getCskBytes()];
+
+ // Allocate S = new byte[PK_SEED_BYTES_MAX + O_BYTES_MAX]
+ byte[] S = new byte[p.getPkSeedBytes() + p.getOBytes()];
+
+ // Allocate P as a long array of size (P1_LIMBS_MAX + P2_LIMBS_MAX)
+ long[] P = new long[p.getP1Limbs() + p.getP2Limbs()];
+
+ // Allocate P3 as a long array of size (O_MAX * O_MAX * M_VEC_LIMBS_MAX), zero-initialized.
+ long[] P3 = new long[p.getO() * p.getO() * p.getMVecLimbs()];
+
+ // seed_pk will be a reference into S.
+ byte[] seed_pk;
+
+ // Allocate O as a byte array of size (V_MAX * O_MAX).
+ // Here we assume V_MAX is given by p.getV() (or replace with a constant if needed).
+ byte[] O = new byte[p.getV() * p.getO()];
+
+ // Retrieve parameters from p.
+ int m_vec_limbs = p.getMVecLimbs();
+ int param_m = p.getM();
+ int param_v = p.getV();
+ int param_o = p.getO();
+ int param_O_bytes = p.getOBytes();
+ int param_P1_limbs = p.getP1Limbs();
+ int param_P3_limbs = p.getP3Limbs();
+ int param_pk_seed_bytes = p.getPkSeedBytes();
+ int param_sk_seed_bytes = p.getSkSeedBytes();
+
+ // In the C code, P1 is P and P2 is P offset by param_P1_limbs.
+ // In Java, we will have functions (like expandP1P2) work on the full array P.
+
+ // Generate secret key seed (seed_sk) using a secure random generator.
+ random.nextBytes(seed_sk);
+
+ // S ← shake256(seed_sk, pk_seed_bytes + O_bytes)
+ Utils.shake256(S, param_pk_seed_bytes + param_O_bytes, seed_sk, param_sk_seed_bytes);
+
+ // seed_pk is the beginning of S.
+ seed_pk = S;
+
+ // o ← Decode_o(S[ param_pk_seed_bytes : param_pk_seed_bytes + O_bytes ])
+ // Decode nibbles from S starting at offset param_pk_seed_bytes into O,
+ // with expected output length = param_v * param_o.
+ Utils.decode(S, param_pk_seed_bytes, O, param_v * param_o);
+
+ // Expand P1 and P2 into the array P using seed_pk.
+ MayoEngine.expandP1P2(p, P, seed_pk);
+
+ // For compute_P3, we need to separate P1 and P2.
+ // Here, we treat P1 as the first param_P1_limbs elements of P,
+ // and P2 as the remaining elements.
+ long[] P1 = P;
+ long[] P2 = new long[P.length - param_P1_limbs];
+ System.arraycopy(P, param_P1_limbs, P2, 0, P2.length);
+
+ // Compute P3, which (in the process) modifies P2.
+ computeP3(p, P1, P2, O, P3);
+
+ // Store seed_pk into the public key cpk.
+ System.arraycopy(seed_pk, 0, cpk, 0, param_pk_seed_bytes);
+
+ // Allocate an array for the "upper" part of P3.
+ long[] P3_upper = new long[p.getP3Limbs()];
+
+ // Compute Upper(P3) and store the result in P3_upper.
+ mUpper(p, P3, P3_upper, param_o);
+
+ // Pack the m-vectors in P3_upper into cpk (after the seed_pk).
+ // The number of m-vectors to pack is (param_P3_limbs / m_vec_limbs),
+ // and param_m is used as the m value.
+ Utils.packMVecs(P3_upper, cpk, param_pk_seed_bytes, param_P3_limbs / m_vec_limbs, param_m);
+ // Securely clear sensitive data.
+// secureClear(O);
+// secureClear(P2);
+// secureClear(P3);
+
+ return new AsymmetricCipherKeyPair(new MayoPublicKeyParameter(p, cpk), new MayoPrivateKeyParameter(p, seed_sk));
+ }
+
+ /**
+ * Computes P3 from P1, P2, and O.
+ *
+ * In C, compute_P3 does:
+ * 1. Compute P1*O + P2, storing result in P2.
+ * 2. Compute P3 = O^T * (P1*O + P2).
+ *
+ * @param p the parameter object.
+ * @param P1 the P1 matrix as a long[] array.
+ * @param P2 the P2 matrix as a long[] array; on output, P1*O is added to it.
+ * @param O the O matrix as a byte[] array.
+ * @param P3 the output matrix (as a long[] array) which will receive O^T*(P1*O + P2).
+ */
+ public static void computeP3(MayoParameters p, long[] P1, long[] P2, byte[] O, long[] P3)
+ {
+ int mVecLimbs = p.getMVecLimbs();
+ int paramV = p.getV();
+ int paramO = p.getO();
+
+ // Compute P1 * O + P2 and store the result in P2.
+ GF16Utils.P1TimesO(p, P1, O, P2);
+
+ // Compute P3 = O^T * (P1*O + P2).
+ // Here, treat P2 as the bsMat for the multiplication.
+ // Dimensions: mat = O (size: paramV x paramO), bsMat = P2 (size: paramV x paramO),
+ // and acc (P3) will have dimensions: (paramO x paramO), each entry being an m-vector.
+ GF16Utils.mulAddMatTransXMMat(mVecLimbs, O, P2, P3, paramV, paramO, paramO);
+ }
+
+ /**
+ * Reproduces the behavior of the C function m_upper.
+ *
+ * For each pair (r, c) with 0 <= r <= c < size, it copies the m-vector at
+ * position (r, c) from 'in' to the next position in 'out' and, if r != c,
+ * it adds (XORs) the m-vector at position (c, r) into that same output vector.
+ *
+ * @param p the parameter object (used to get mVecLimbs)
+ * @param in the input long array (each vector is mVecLimbs in length)
+ * @param out the output long array (must be large enough to store all output vectors)
+ * @param size the size parameter defining the matrix dimensions.
+ */
+ public static void mUpper(MayoParameters p, long[] in, long[] out, int size)
+ {
+ int mVecLimbs = p.getMVecLimbs();
+ int mVecsStored = 0;
+ for (int r = 0; r < size; r++)
+ {
+ for (int c = r; c < size; c++)
+ {
+ // Compute the starting index for the (r, c) vector in the input array.
+ int srcOffset = mVecLimbs * (r * size + c);
+ // Compute the output offset for the current stored vector.
+ int destOffset = mVecLimbs * mVecsStored;
+
+ // Copy the vector at (r, c) into the output.
+ System.arraycopy(in, srcOffset, out, destOffset, mVecLimbs);
+
+ // If off-diagonal, add (XOR) the vector at (c, r) into the same output vector.
+ if (r != c)
+ {
+ int srcOffset2 = mVecLimbs * (c * size + r);
+ GF16Utils.mVecAdd(mVecLimbs, in, srcOffset2, out, destOffset);
+ }
+ mVecsStored++;
+ }
+ }
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyParameters.java
new file mode 100644
index 0000000000..4b932949dc
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyParameters.java
@@ -0,0 +1,22 @@
+package org.bouncycastle.pqc.crypto.mayo;
+
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+
+public class MayoKeyParameters
+ extends AsymmetricKeyParameter
+{
+ private final MayoParameters params;
+
+ public MayoKeyParameters(
+ boolean isPrivate,
+ MayoParameters params)
+ {
+ super(isPrivate);
+ this.params = params;
+ }
+
+ public MayoParameters getParameters()
+ {
+ return params;
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoParameters.java
new file mode 100644
index 0000000000..e6e285167f
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoParameters.java
@@ -0,0 +1,364 @@
+package org.bouncycastle.pqc.crypto.mayo;
+
+public class MayoParameters
+{
+ public static final MayoParameters MAYO1 = new MayoParameters(
+ "MAYO_1", // name
+ 86, // n
+ 78, // m
+ 5, // m_vec_limbs
+ 8, // o
+ 86 - 8, // v = n - o = 78
+ 10 * 8 + 1, // A_cols = k * o + 1 = 10 * 8 + 1 = 81
+ 10, // k
+ 16, // q
+ 39, // m_bytes
+ 312, // O_bytes
+ 39, // v_bytes
+ 40, // r_bytes
+ 120159, // P1_bytes
+ 24336, // P2_bytes
+ 1404, // P3_bytes
+ 24, // csk_bytes
+ 1420, // cpk_bytes
+ 454, // sig_bytes
+ new int[]{8, 1, 1, 0}, // F_TAIL_78
+ new byte[]{8, 1, 1, 0}, // f_tail_arr
+ 24, // salt_bytes
+ 32, // digest_bytes
+ 16, // pk_seed_bytes
+ 24 // sk_seed_bytes
+ );
+
+ public static final MayoParameters MAYO2 = new MayoParameters(
+ "MAYO_2", // name
+ 81, // n
+ 64, // m
+ 4, // m_vec_limbs
+ 17, // o
+ 81 - 17, // v = 64
+ 4 * 17 + 1, // A_cols = 4 * 17 + 1 = 69
+ 4, // k
+ 16, // q
+ 32, // m_bytes
+ 544, // O_bytes
+ 32, // v_bytes
+ 34, // r_bytes
+ 66560, // P1_bytes
+ 34816, // P2_bytes
+ 4896, // P3_bytes
+ 24, // csk_bytes
+ 4912, // cpk_bytes
+ 186, // sig_bytes
+ new int[]{8, 0, 2, 8}, //F_TAIL_64
+ new byte[]{8, 0, 2, 8}, // f_tail_arr
+ 24, // salt_bytes
+ 32, // digest_bytes
+ 16, // pk_seed_bytes
+ 24 // sk_seed_bytes
+ );
+
+ public static final MayoParameters MAYO3 = new MayoParameters(
+ "MAYO_3", // name
+ 118, // n
+ 108, // m
+ 7, // m_vec_limbs
+ 10, // o
+ 118 - 10, // v = 108
+ 11 * 10 + 1, // A_cols = 11 * 10 + 1 = 111
+ 11, // k
+ 16, // q
+ 54, // m_bytes
+ 540, // O_bytes
+ 54, // v_bytes
+ 55, // r_bytes
+ 317844, // P1_bytes
+ 58320, // P2_bytes
+ 2970, // P3_bytes
+ 32, // csk_bytes
+ 2986, // cpk_bytes
+ 681, // sig_bytes
+ new int[]{8, 0, 1, 7}, //F_TAIL_108
+ new byte[]{8, 0, 1, 7}, // f_tail_arr
+ 32, // salt_bytes
+ 48, // digest_bytes
+ 16, // pk_seed_bytes
+ 32 // sk_seed_bytes
+ );
+
+ public static final MayoParameters MAYO5 = new MayoParameters(
+ "MAYO_5", // name
+ 154, // n
+ 142, // m
+ 9, // m_vec_limbs
+ 12, // o
+ 154 - 12, // v = 142
+ 12 * 12 + 1, // A_cols = 12 * 12 + 1 = 145
+ 12, // k
+ 16, // q
+ 71, // m_bytes
+ 852, // O_bytes
+ 71, // v_bytes
+ 72, // r_bytes
+ 720863, // P1_bytes
+ 120984, // P2_bytes
+ 5538, // P3_bytes
+ 40, // csk_bytes
+ 5554, // cpk_bytes
+ 964, // sig_bytes
+ new int[]{4, 0, 8, 1}, //F_TAIL_142
+ new byte[]{4, 0, 8, 1}, // f_tail_arr
+ 40, // salt_bytes
+ 64, // digest_bytes
+ 16, // pk_seed_bytes
+ 40 // sk_seed_bytes
+ );
+
+ private final String name;
+ private final int n;
+ private final int m;
+ private final int mVecLimbs;
+ private final int o;
+ private final int v;
+ private final int ACols;
+ private final int k;
+ private final int q;
+ private final int mBytes;
+ private final int OBytes;
+ private final int vBytes;
+ private final int rBytes;
+ private final int P1Bytes;
+ private final int P2Bytes;
+ private final int P3Bytes;
+ private final int cskBytes;
+ private final int cpkBytes;
+ private final int sigBytes;
+ private final int[] fTail;
+ private final byte[] fTailArr;
+ private final int saltBytes;
+ private final int digestBytes;
+ private final int pkSeedBytes;
+ private final int skSeedBytes;
+
+ private MayoParameters(String name, int n, int m, int mVecLimbs, int o, int v, int ACols, int k, int q,
+ int mBytes, int OBytes, int vBytes, int rBytes, int P1Bytes, int P2Bytes, int P3Bytes,
+ int cskBytes, int cpkBytes, int sigBytes, int[] fTail, byte[] fTailArr,
+ int saltBytes, int digestBytes, int pkSeedBytes, int skSeedBytes)
+ {
+ this.name = name;
+ this.n = n;
+ this.m = m;
+ this.mVecLimbs = mVecLimbs;
+ this.o = o;
+ this.v = v;
+ this.ACols = ACols;
+ this.k = k;
+ this.q = q;
+ this.mBytes = mBytes;
+ this.OBytes = OBytes;
+ this.vBytes = vBytes;
+ this.rBytes = rBytes;
+ this.P1Bytes = P1Bytes;
+ this.P2Bytes = P2Bytes;
+ this.P3Bytes = P3Bytes;
+ this.cskBytes = cskBytes;
+ this.cpkBytes = cpkBytes;
+ this.sigBytes = sigBytes;
+ this.fTail = fTail;
+ this.fTailArr = fTailArr;
+ this.saltBytes = saltBytes;
+ this.digestBytes = digestBytes;
+ this.pkSeedBytes = pkSeedBytes;
+ this.skSeedBytes = skSeedBytes;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public int getN()
+ {
+ return n;
+ }
+
+ public int getM()
+ {
+ return m;
+ }
+
+ public int getMVecLimbs()
+ {
+ return mVecLimbs;
+ }
+
+ public int getO()
+ {
+ return o;
+ }
+
+ public int getV()
+ {
+ return v;
+ }
+
+ public int getACols()
+ {
+ return ACols;
+ }
+
+ public int getK()
+ {
+ return k;
+ }
+
+ public int getQ()
+ {
+ return q;
+ }
+
+ public int getMBytes()
+ {
+ return mBytes;
+ }
+
+ public int getOBytes()
+ {
+ return OBytes;
+ }
+
+ public int getVBytes()
+ {
+ return vBytes;
+ }
+
+ public int getRBytes()
+ {
+ return rBytes;
+ }
+
+ public int getP1Bytes()
+ {
+ return P1Bytes;
+ }
+
+ public int getP2Bytes()
+ {
+ return P2Bytes;
+ }
+
+ public int getP3Bytes()
+ {
+ return P3Bytes;
+ }
+
+ public int getCskBytes()
+ {
+ return cskBytes;
+ }
+
+ public int getCpkBytes()
+ {
+ return cpkBytes;
+ }
+
+ public int getSigBytes()
+ {
+ return sigBytes;
+ }
+
+ public int[] getFTail()
+ {
+ return fTail;
+ }
+
+ public byte[] getFTailArr()
+ {
+ return fTailArr;
+ }
+
+ public int getSaltBytes()
+ {
+ return saltBytes;
+ }
+
+ public int getDigestBytes()
+ {
+ return digestBytes;
+ }
+
+ public int getPkSeedBytes()
+ {
+ return pkSeedBytes;
+ }
+
+ public int getSkSeedBytes()
+ {
+ return skSeedBytes;
+ }
+
+ /**
+ * Computes: (v * (v + 1) / 2) * mVecLimbs
+ */
+ public int getP1Limbs()
+ {
+ return ((v * (v + 1)) / 2) * mVecLimbs;
+ }
+
+ /**
+ * Computes: v * o * mVecLimbs
+ */
+ public int getP2Limbs()
+ {
+ return v * o * mVecLimbs;
+ }
+
+ /**
+ * Computes: (o * (o + 1) / 2) * mVecLimbs
+ */
+ public int getP3Limbs()
+ {
+ return ((o * (o + 1)) / 2) * mVecLimbs;
+ }
+
+ /**
+ * Computes: P1_limbs + P2_limbs + P3_limbs
+ */
+ public int getEPKLimbs()
+ {
+ return getP1Limbs() + getP2Limbs() + getP3Limbs();
+ }
+
+ @Override
+ public String toString()
+ {
+ return "MayoParameters{" +
+ "name='" + name + '\'' +
+ ", n=" + n +
+ ", m=" + m +
+ ", mVecLimbs=" + mVecLimbs +
+ ", o=" + o +
+ ", v=" + v +
+ ", ACols=" + ACols +
+ ", k=" + k +
+ ", q=" + q +
+ ", mBytes=" + mBytes +
+ ", OBytes=" + OBytes +
+ ", vBytes=" + vBytes +
+ ", rBytes=" + rBytes +
+ ", P1Bytes=" + P1Bytes +
+ ", P2Bytes=" + P2Bytes +
+ ", P3Bytes=" + P3Bytes +
+ ", cskBytes=" + cskBytes +
+ ", cpkBytes=" + cpkBytes +
+ ", sigBytes=" + sigBytes +
+ ", fTail='{" + fTail[0] + "," + fTail[1] + "," + fTail[2] + "," + fTail[3] + "}'" +
+ ", fTailArr='{" + fTailArr[0] + "," + fTailArr[1] + "," + fTailArr[2] + "," + fTailArr[3] + "}'" +
+ ", saltBytes=" + saltBytes +
+ ", digestBytes=" + digestBytes +
+ ", pkSeedBytes=" + pkSeedBytes +
+ ", skSeedBytes=" + skSeedBytes +
+ '}';
+ }
+}
+
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPrivateKeyParameter.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPrivateKeyParameter.java
new file mode 100644
index 0000000000..7954094a38
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPrivateKeyParameter.java
@@ -0,0 +1,41 @@
+package org.bouncycastle.pqc.crypto.mayo;
+
+import org.bouncycastle.util.Arrays;
+
+public class MayoPrivateKeyParameter
+ extends MayoKeyParameters
+{
+ // Represents the field: uint64_t p[P1_LIMBS_MAX + P2_LIMBS_MAX];
+// private final byte[] p;
+ // Represents the field: uint8_t O[V_MAX * O_MAX];
+// private final byte[] O;
+ private final byte[] seed_sk;
+
+ public MayoPrivateKeyParameter(MayoParameters params, byte[] seed_sk)
+ {
+ super(true, params);
+ this.seed_sk = seed_sk;
+// this.p = p;
+// this.O = O;
+ }
+
+// public byte[] getP()
+// {
+// return p;
+// }
+//
+// public byte[] getO()
+// {
+// return O;
+// }
+
+ public byte[] getEncoded()
+ {
+ return Arrays.clone(seed_sk);
+ }
+
+ public byte[] getSeedSk()
+ {
+ return Arrays.clone(seed_sk);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPublicKeyParameter.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPublicKeyParameter.java
new file mode 100644
index 0000000000..68613b35bd
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPublicKeyParameter.java
@@ -0,0 +1,26 @@
+package org.bouncycastle.pqc.crypto.mayo;
+
+import org.bouncycastle.util.Arrays;
+
+public class MayoPublicKeyParameter
+ extends MayoKeyParameters
+{
+ // Represents the field: uint64_t p[P1_LIMBS_MAX + P2_LIMBS_MAX + P3_LIMBS_MAX];
+ private final byte[] p;
+
+ public MayoPublicKeyParameter(MayoParameters params, byte[] p)
+ {
+ super(false, params);
+ this.p = p;
+ }
+
+ public byte[] getP()
+ {
+ return p;
+ }
+
+ public byte[] getEncoded()
+ {
+ return Arrays.clone(p);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/Utils.java
new file mode 100644
index 0000000000..d3de862432
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/Utils.java
@@ -0,0 +1,169 @@
+package org.bouncycastle.pqc.crypto.mayo;
+
+import org.bouncycastle.crypto.digests.SHAKEDigest;
+import org.bouncycastle.util.Pack;
+
+public class Utils
+{
+ /**
+ * Decodes an encoded byte array.
+ * Each byte in the input contains two nibbles (4-bit values); the lower nibble is stored first,
+ * followed by the upper nibble.
+ *
+ * @param m the input byte array (each byte holds two 4-bit values)
+ * @param mdec the output array that will hold the decoded nibbles (one per byte)
+ * @param mdecLen the total number of nibbles to decode
+ */
+ public static void decode(byte[] m, byte[] mdec, int mdecLen)
+ {
+ int i;
+ int decIndex = 0;
+ // Process pairs of nibbles from each byte
+ for (i = 0; i < mdecLen / 2; i++)
+ {
+ // Extract the lower nibble
+ mdec[decIndex++] = (byte)((m[i] & 0xFF) & 0x0F);
+ // Extract the upper nibble (shift right 4 bits)
+ mdec[decIndex++] = (byte)(((m[i] & 0xFF) >> 4) & 0x0F);
+ }
+ // If there is an extra nibble (odd number of nibbles), decode only the lower nibble
+ if (mdecLen % 2 == 1)
+ {
+ mdec[decIndex] = (byte)((m[i] & 0xFF) & 0x0F);
+ }
+ }
+
+ /**
+ * Decodes a nibble-packed byte array into an output array.
+ *
+ * @param input the input byte array.
+ * @param inputOffset the offset in input from which to start decoding.
+ * @param output the output byte array to hold the decoded nibbles.
+ * @param mdecLen the total number of nibbles to decode.
+ */
+ public static void decode(byte[] input, int inputOffset, byte[] output, int mdecLen)
+ {
+ int decIndex = 0;
+ int blocks = mdecLen / 2;
+ for (int i = 0; i < blocks; i++)
+ {
+ output[decIndex++] = (byte)(input[inputOffset + i] & 0x0F);
+ output[decIndex++] = (byte)((input[inputOffset + i] >> 4) & 0x0F);
+ }
+ if (mdecLen % 2 == 1)
+ {
+ output[decIndex] = (byte)(input[inputOffset + blocks] & 0x0F);
+ }
+ }
+
+ /**
+ * Encodes an array of 4-bit values into a byte array.
+ * Two 4-bit values are packed into one byte, with the first nibble stored in the lower 4 bits
+ * and the second nibble stored in the upper 4 bits.
+ *
+ * @param m the input array of 4-bit values (stored as bytes, only lower 4 bits used)
+ * @param menc the output byte array that will hold the encoded bytes
+ * @param mlen the number of nibbles in the input array
+ */
+ public static void encode(byte[] m, byte[] menc, int mlen)
+ {
+ int i;
+ int srcIndex = 0;
+ // Process pairs of 4-bit values
+ for (i = 0; i < mlen / 2; i++)
+ {
+ int lowerNibble = m[srcIndex] & 0x0F;
+ int upperNibble = (m[srcIndex + 1] & 0x0F) << 4;
+ menc[i] = (byte)(lowerNibble | upperNibble);
+ srcIndex += 2;
+ }
+ // If there is an extra nibble (odd number of nibbles), store it directly in lower 4 bits.
+ if (mlen % 2 == 1)
+ {
+ menc[i] = (byte)(m[srcIndex] & 0x0F);
+ }
+ }
+
+ /**
+ * Unpacks m-vectors from a packed byte array into an array of 64-bit limbs.
+ *
+ * @param in the input byte array containing packed data
+ * @param out the output long array where unpacked limbs are stored
+ * @param vecs the number of vectors
+ * @param m the m parameter (used to compute m_vec_limbs and copy lengths)
+ */
+ public static void unpackMVecs(byte[] in, long[] out, int vecs, int m)
+ {
+ int mVecLimbs = (m + 15) / 16;
+ int bytesToCopy = m / 2; // Number of bytes to copy per vector
+
+ // Process vectors in reverse order
+ for (int i = vecs - 1; i >= 0; i--)
+ {
+ // Temporary buffer to hold mVecLimbs longs (each long is 8 bytes)
+ byte[] tmp = new byte[mVecLimbs * 8];
+ // Copy m/2 bytes from the input into tmp. The rest remains zero.
+ System.arraycopy(in, i * bytesToCopy, tmp, 0, bytesToCopy);
+
+ // Convert each 8-byte block in tmp into a long using Pack
+ for (int j = 0; j < mVecLimbs; j++)
+ {
+ out[i * mVecLimbs + j] = Pack.littleEndianToLong(tmp, j * 8);
+ }
+ }
+ }
+
+ /**
+ * Packs m-vectors from an array of 64-bit limbs into a packed byte array.
+ *
+ * @param in the input long array containing the m-vectors
+ * @param out the output byte array that will contain the packed data
+ * @param vecs the number of vectors
+ * @param m the m parameter (used to compute m_vec_limbs and copy lengths)
+ */
+ public static void packMVecs(long[] in, byte[] out, int outOff, int vecs, int m)
+ {
+ int mVecLimbs = (m + 15) / 16;
+ int bytesToCopy = m / 2; // Number of bytes per vector to write
+
+ // Process each vector in order
+ for (int i = 0; i < vecs; i++)
+ {
+ // Temporary buffer to hold the bytes for this vector
+ byte[] tmp = new byte[mVecLimbs * 8];
+
+ // Convert each long into 8 bytes using Pack
+ for (int j = 0; j < mVecLimbs; j++)
+ {
+ Pack.longToLittleEndian(in[i * mVecLimbs + j], tmp, j * 8);
+ }
+
+ // Copy the first m/2 bytes from tmp to the output array
+ System.arraycopy(tmp, 0, out, i * bytesToCopy + outOff, bytesToCopy);
+ }
+ }
+
+ /**
+ * Computes the SHAKE256 XOF on the given input.
+ *
+ * @param output the output buffer that will be filled with the result.
+ * @param outlen the number of bytes to produce.
+ * @param input the input byte array.
+ * @param inlen the number of input bytes.
+ * @return the number of output bytes produced (equals outlen).
+ */
+ public static int shake256(byte[] output, int outlen, byte[] input, int inlen)
+ {
+ // Create a new SHAKE256 digest instance.
+ SHAKEDigest shake = new SHAKEDigest(256);
+
+ // Absorb the input.
+ shake.update(input, 0, inlen);
+
+ // Squeeze out outlen bytes into the output array.
+ shake.doFinal(output, 0, outlen);
+
+ return outlen;
+ }
+
+}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java b/core/src/main/java/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java
index f46a283c5d..ff782c74af 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java
@@ -25,6 +25,7 @@
import org.bouncycastle.pqc.crypto.lms.Composer;
import org.bouncycastle.pqc.crypto.lms.HSSPublicKeyParameters;
import org.bouncycastle.pqc.crypto.lms.LMSPublicKeyParameters;
+import org.bouncycastle.pqc.crypto.mayo.MayoPublicKeyParameter;
import org.bouncycastle.pqc.crypto.mldsa.MLDSAPublicKeyParameters;
import org.bouncycastle.pqc.crypto.mlkem.MLKEMPublicKeyParameters;
import org.bouncycastle.pqc.crypto.newhope.NHPublicKeyParameters;
@@ -196,7 +197,7 @@ else if (publicKey instanceof SABERPublicKeyParameters)
byte[] encoding = params.getEncoded();
AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(Utils.saberOidLookup(params.getParameters()));
-
+
return new SubjectPublicKeyInfo(algorithmIdentifier, new DERSequence(new DEROctetString(encoding)));
}
else if (publicKey instanceof PicnicPublicKeyParameters)
@@ -274,7 +275,7 @@ else if (publicKey instanceof MLDSAPublicKeyParameters)
}
else if (publicKey instanceof BIKEPublicKeyParameters)
{
- BIKEPublicKeyParameters params = (BIKEPublicKeyParameters) publicKey;
+ BIKEPublicKeyParameters params = (BIKEPublicKeyParameters)publicKey;
byte[] encoding = params.getEncoded();
diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/MayoTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/MayoTest.java
new file mode 100644
index 0000000000..8f720f844e
--- /dev/null
+++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/MayoTest.java
@@ -0,0 +1,67 @@
+package org.bouncycastle.pqc.crypto.test;
+
+import java.io.IOException;
+
+import junit.framework.TestCase;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.pqc.crypto.mayo.MayoKeyGenerationParameters;
+import org.bouncycastle.pqc.crypto.mayo.MayoKeyPairGenerator;
+import org.bouncycastle.pqc.crypto.mayo.MayoParameters;
+import org.bouncycastle.pqc.crypto.mayo.MayoPrivateKeyParameter;
+import org.bouncycastle.pqc.crypto.mayo.MayoPublicKeyParameter;
+
+public class MayoTest
+ extends TestCase
+{
+ public static void main(String[] args)
+ throws Exception
+ {
+ MayoTest test = new MayoTest();
+ test.testKeyGen();
+ }
+
+ private static final MayoParameters[] PARAMETER_SETS = new MayoParameters[]
+ {
+ MayoParameters.MAYO1,
+ MayoParameters.MAYO2,
+ MayoParameters.MAYO3,
+ MayoParameters.MAYO5
+ };
+
+ public void testKeyGen()
+ throws IOException
+ {
+ String[] files = new String[]{
+ "PQCsignKAT_24_MAYO_1.rsp",
+ "PQCsignKAT_24_MAYO_2.rsp",
+ "PQCsignKAT_32_MAYO_3.rsp",
+ "PQCsignKAT_40_MAYO_5.rsp",
+ };
+ TestUtils.testKeyGen(false, "pqc/crypto/mayo", files, new TestUtils.KeyGenerationOperation()
+ {
+ @Override
+ public AsymmetricCipherKeyPairGenerator getAsymmetricCipherKeyPairGenerator(int fileIndex, byte[] seed)
+ {
+ NISTSecureRandom random = new NISTSecureRandom(seed, null);
+ MayoParameters parameters = PARAMETER_SETS[fileIndex];
+
+ MayoKeyPairGenerator kpGen = new MayoKeyPairGenerator();
+ kpGen.init(new MayoKeyGenerationParameters(random, parameters));
+ return kpGen;
+ }
+
+ @Override
+ public byte[] getPublicKeyEncoded(AsymmetricKeyParameter pubParams)
+ {
+ return ((MayoPublicKeyParameter)pubParams).getEncoded();
+ }
+
+ @Override
+ public byte[] getPrivateKeyEncoded(AsymmetricKeyParameter privParams)
+ {
+ return ((MayoPrivateKeyParameter)privParams).getEncoded();
+ }
+ });
+ }
+}
diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/TestUtils.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/TestUtils.java
index 743f936caf..966b7bf455 100644
--- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/TestUtils.java
+++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/TestUtils.java
@@ -1,9 +1,102 @@
package org.bouncycastle.pqc.crypto.test;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.security.SecureRandom;
+import java.util.HashMap;
+
+import junit.framework.Assert;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.pqc.crypto.util.PrivateKeyFactory;
+import org.bouncycastle.pqc.crypto.util.PrivateKeyInfoFactory;
+import org.bouncycastle.pqc.crypto.util.PublicKeyFactory;
+import org.bouncycastle.pqc.crypto.util.SubjectPublicKeyInfoFactory;
+import org.bouncycastle.test.TestResourceFinder;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.encoders.Hex;
+import org.bouncycastle.util.test.FixedSecureRandom;
+
class TestUtils
{
static boolean parseBoolean(String value)
{
return "true".equalsIgnoreCase(value);
}
+
+ public interface KeyGenerationOperation
+ {
+ AsymmetricCipherKeyPairGenerator getAsymmetricCipherKeyPairGenerator(int fileIndex, byte[] seed);
+
+ byte[] getPublicKeyEncoded(AsymmetricKeyParameter pubParams);
+
+ byte[] getPrivateKeyEncoded(AsymmetricKeyParameter privParams);
+ }
+
+ public static void testKeyGen(boolean enableFactory, String homeDir, String[] files, KeyGenerationOperation operation)
+ throws IOException
+ {
+ for (int fileIndex = 0; fileIndex != files.length; fileIndex++)
+ {
+ String name = files[fileIndex];
+ InputStream src = TestResourceFinder.findTestResource(homeDir, name);
+ BufferedReader bin = new BufferedReader(new InputStreamReader(src));
+
+ String line;
+ HashMap buf = new HashMap();
+ while ((line = bin.readLine()) != null)
+ {
+ line = line.trim();
+
+ if (line.startsWith("#"))
+ {
+ continue;
+ }
+ if (line.length() == 0)
+ {
+ if (buf.size() > 0)
+ {
+ byte[] seed = Hex.decode((String)buf.get("seed"));
+ byte[] pk = Hex.decode((String)buf.get("pk"));
+ byte[] sk = Hex.decode((String)buf.get("sk"));
+
+ AsymmetricCipherKeyPairGenerator kpGen = operation.getAsymmetricCipherKeyPairGenerator(fileIndex, seed);
+
+ //
+ // Generate keys and test.
+ //
+ AsymmetricCipherKeyPair kp = kpGen.generateKeyPair();
+ AsymmetricKeyParameter pubParams, privParams;
+ if (enableFactory)
+ {
+ pubParams = PublicKeyFactory.createKey(
+ SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(kp.getPublic()));
+ privParams = PrivateKeyFactory.createKey(
+ PrivateKeyInfoFactory.createPrivateKeyInfo(kp.getPrivate()));
+ }
+ else
+ {
+ pubParams = kp.getPublic();
+ privParams = kp.getPrivate();
+ }
+
+ Assert.assertTrue(name + ": public key", Arrays.areEqual(pk, operation.getPublicKeyEncoded(pubParams)));
+ Assert.assertTrue(name + ": secret key", Arrays.areEqual(sk, operation.getPrivateKeyEncoded(privParams)));
+ }
+ buf.clear();
+ continue;
+ }
+
+ int a = line.indexOf("=");
+ if (a > -1)
+ {
+ buf.put(line.substring(0, a).trim(), line.substring(a + 1).trim());
+ }
+ }
+ }
+ }
}
From bab5138c12c95c1f6881637e058037b0903d7f39 Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Fri, 28 Feb 2025 11:41:18 +0700
Subject: [PATCH 137/890] Migrate tls test data to bc-test-data
---
.../bouncycastle/test/TestResourceFinder.java | 39 ++++
.../bouncycastle/tls/test/TlsTestUtils.java | 3 +-
.../org/bouncycastle/tls/test/README.txt | 181 ------------------
.../org/bouncycastle/tls/test/ca.tmpl | 4 -
.../bouncycastle/tls/test/client_agree.tmpl | 4 -
.../org/bouncycastle/tls/test/client_enc.tmpl | 4 -
.../bouncycastle/tls/test/client_sign.tmpl | 4 -
.../bouncycastle/tls/test/server_agree.tmpl | 4 -
.../org/bouncycastle/tls/test/server_enc.tmpl | 4 -
.../bouncycastle/tls/test/server_sign.tmpl | 4 -
.../org/bouncycastle/tls/test/x509-ca-dsa.pem | 26 ---
.../bouncycastle/tls/test/x509-ca-ecdsa.pem | 11 --
.../bouncycastle/tls/test/x509-ca-ed25519.pem | 9 -
.../bouncycastle/tls/test/x509-ca-ed448.pem | 11 --
.../bouncycastle/tls/test/x509-ca-key-dsa.pem | 15 --
.../tls/test/x509-ca-key-ecdsa.pem | 6 -
.../tls/test/x509-ca-key-ed25519.pem | 25 ---
.../tls/test/x509-ca-key-ed448.pem | 28 ---
.../bouncycastle/tls/test/x509-ca-key-rsa.pem | 28 ---
.../tls/test/x509-ca-key-rsa_pss_256.pem | 138 -------------
.../tls/test/x509-ca-key-rsa_pss_384.pem | 138 -------------
.../tls/test/x509-ca-key-rsa_pss_512.pem | 138 -------------
.../org/bouncycastle/tls/test/x509-ca-rsa.pem | 19 --
.../tls/test/x509-ca-rsa_pss_256.pem | 22 ---
.../tls/test/x509-ca-rsa_pss_384.pem | 22 ---
.../tls/test/x509-ca-rsa_pss_512.pem | 22 ---
.../bouncycastle/tls/test/x509-client-dsa.pem | 27 ---
.../tls/test/x509-client-ecdh.pem | 12 --
.../tls/test/x509-client-ecdsa.pem | 12 --
.../tls/test/x509-client-ed25519.pem | 11 --
.../tls/test/x509-client-ed448.pem | 12 --
.../tls/test/x509-client-key-dsa.pem | 15 --
.../tls/test/x509-client-key-ecdh.pem | 6 -
.../tls/test/x509-client-key-ecdsa.pem | 6 -
.../tls/test/x509-client-key-ed25519.pem | 25 ---
.../tls/test/x509-client-key-ed448.pem | 28 ---
.../tls/test/x509-client-key-rsa.pem | 28 ---
.../tls/test/x509-client-key-rsa_pss_256.pem | 138 -------------
.../tls/test/x509-client-key-rsa_pss_384.pem | 138 -------------
.../tls/test/x509-client-key-rsa_pss_512.pem | 138 -------------
.../bouncycastle/tls/test/x509-client-rsa.pem | 20 --
.../tls/test/x509-client-rsa_pss_256.pem | 23 ---
.../tls/test/x509-client-rsa_pss_384.pem | 23 ---
.../tls/test/x509-client-rsa_pss_512.pem | 23 ---
.../bouncycastle/tls/test/x509-server-dsa.pem | 27 ---
.../tls/test/x509-server-ecdh.pem | 12 --
.../tls/test/x509-server-ecdsa.pem | 12 --
.../tls/test/x509-server-ed25519.pem | 11 --
.../tls/test/x509-server-ed448.pem | 12 --
.../tls/test/x509-server-key-dsa.pem | 15 --
.../tls/test/x509-server-key-ecdh.pem | 6 -
.../tls/test/x509-server-key-ecdsa.pem | 6 -
.../tls/test/x509-server-key-ed25519.pem | 25 ---
.../tls/test/x509-server-key-ed448.pem | 28 ---
.../tls/test/x509-server-key-rsa-enc.pem | 28 ---
.../tls/test/x509-server-key-rsa-sign.pem | 28 ---
.../tls/test/x509-server-key-rsa_pss_256.pem | 138 -------------
.../tls/test/x509-server-key-rsa_pss_384.pem | 138 -------------
.../tls/test/x509-server-key-rsa_pss_512.pem | 138 -------------
.../tls/test/x509-server-rsa-enc.pem | 20 --
.../tls/test/x509-server-rsa-sign.pem | 20 --
.../tls/test/x509-server-rsa_pss_256.pem | 23 ---
.../tls/test/x509-server-rsa_pss_384.pem | 23 ---
.../tls/test/x509-server-rsa_pss_512.pem | 23 ---
64 files changed, 41 insertions(+), 2286 deletions(-)
create mode 100644 tls/src/test/java/org/bouncycastle/test/TestResourceFinder.java
delete mode 100755 tls/src/test/resources/org/bouncycastle/tls/test/README.txt
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/ca.tmpl
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/client_agree.tmpl
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/client_enc.tmpl
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/client_sign.tmpl
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/server_agree.tmpl
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/server_enc.tmpl
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/server_sign.tmpl
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-dsa.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-ecdsa.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-ed25519.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-ed448.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-dsa.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-ecdsa.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-ed25519.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-ed448.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa_pss_256.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa_pss_384.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa_pss_512.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa_pss_256.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa_pss_384.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa_pss_512.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-client-dsa.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ecdh.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ecdsa.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ed25519.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ed448.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-dsa.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ecdh.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ecdsa.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ed25519.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ed448.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa_pss_256.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa_pss_384.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa_pss_512.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa_pss_256.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa_pss_384.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa_pss_512.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-server-dsa.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ecdh.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ecdsa.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ed25519.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ed448.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-dsa.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ecdh.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ecdsa.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ed25519.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ed448.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa-enc.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa-sign.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa_pss_256.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa_pss_384.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa_pss_512.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa-enc.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa-sign.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa_pss_256.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa_pss_384.pem
delete mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa_pss_512.pem
diff --git a/tls/src/test/java/org/bouncycastle/test/TestResourceFinder.java b/tls/src/test/java/org/bouncycastle/test/TestResourceFinder.java
new file mode 100644
index 0000000000..14214bafae
--- /dev/null
+++ b/tls/src/test/java/org/bouncycastle/test/TestResourceFinder.java
@@ -0,0 +1,39 @@
+package org.bouncycastle.test;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+
+public class TestResourceFinder
+{
+ private static final String dataDirName = "bc-test-data";
+
+ /**
+ * We search starting at the working directory looking for the bc-test-data directory.
+ *
+ * @throws FileNotFoundException
+ */
+ public static InputStream findTestResource(String homeDir, String fileName)
+ throws FileNotFoundException
+ {
+ String wrkDirName = System.getProperty("user.dir");
+ String separator = System.getProperty("file.separator");
+ File wrkDir = new File(wrkDirName);
+ File dataDir = new File(wrkDir, dataDirName);
+ while (!dataDir.exists() && wrkDirName.length() > 1)
+ {
+ wrkDirName = wrkDirName.substring(0, wrkDirName.lastIndexOf(separator));
+ wrkDir = new File(wrkDirName);
+ dataDir = new File(wrkDir, dataDirName);
+ }
+
+ if (!dataDir.exists())
+ {
+ String ln = System.getProperty("line.separator");
+ throw new FileNotFoundException("Test data directory " + dataDirName + " not found." + ln + "Test data available from: https://github.com/bcgit/bc-test-data.git");
+ }
+
+ return new FileInputStream(new File(dataDir, homeDir + separator + fileName));
+ }
+}
diff --git a/tls/src/test/java/org/bouncycastle/tls/test/TlsTestUtils.java b/tls/src/test/java/org/bouncycastle/tls/test/TlsTestUtils.java
index 918983da2a..84ab7539ee 100644
--- a/tls/src/test/java/org/bouncycastle/tls/test/TlsTestUtils.java
+++ b/tls/src/test/java/org/bouncycastle/tls/test/TlsTestUtils.java
@@ -29,6 +29,7 @@
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
import org.bouncycastle.crypto.util.PrivateKeyFactory;
+import org.bouncycastle.test.TestResourceFinder;
import org.bouncycastle.tls.AlertDescription;
import org.bouncycastle.tls.Certificate;
import org.bouncycastle.tls.CertificateEntry;
@@ -493,7 +494,7 @@ else if (EdECObjectIdentifiers.id_Ed448.equals(oid))
static PemObject loadPemResource(String resource)
throws IOException
{
- InputStream s = TlsTestUtils.class.getResourceAsStream(resource);
+ InputStream s = TestResourceFinder.findTestResource("tls/credentials", resource);
PemReader p = new PemReader(new InputStreamReader(s));
PemObject o = p.readPemObject();
p.close();
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/README.txt b/tls/src/test/resources/org/bouncycastle/tls/test/README.txt
deleted file mode 100755
index 538325645f..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/README.txt
+++ /dev/null
@@ -1,181 +0,0 @@
-# The key and certificate .pem files here were generated using GnuTLS certtool and the accompanying
-# template files. (Note that the ed25519 files needed GnuTLS 3.6+, 3.6.12+ for ed448)
-
-# CA (signing) credentials:
-
- certtool --generate-privkey --outfile x509-ca-key-dsa.pem \
- --pkcs8 --password '' --dsa --bits 2048
- certtool --generate-self-signed --template ca.tmpl --outfile x509-ca-dsa.pem \
- --load-privkey x509-ca-key-dsa.pem --hash sha256
-
- certtool --generate-privkey --outfile x509-ca-key-ecdsa.pem \
- --pkcs8 --password '' --ecdsa --curve secp256r1
- certtool --generate-self-signed --template ca.tmpl --outfile x509-ca-ecdsa.pem \
- --load-privkey x509-ca-key-ecdsa.pem --hash sha256
-
- certtool --generate-privkey --outfile x509-ca-key-ed25519.pem \
- --pkcs8 --password '' --key-type=ed25519
- certtool --generate-self-signed --template ca.tmpl --outfile x509-ca-ed25519.pem \
- --load-privkey x509-ca-key-ed25519.pem
-
- certtool --generate-privkey --outfile x509-ca-key-ed448.pem \
- --pkcs8 --password '' --key-type=ed448
- certtool --generate-self-signed --template ca.tmpl --outfile x509-ca-ed448.pem \
- --load-privkey x509-ca-key-ed448.pem
-
- certtool --generate-privkey --outfile x509-ca-key-rsa.pem \
- --pkcs8 --password '' --rsa --bits 2048
- certtool --generate-self-signed --template ca.tmpl --outfile x509-ca-rsa.pem \
- --load-privkey x509-ca-key-rsa.pem --hash sha256
-
- certtool --generate-privkey --outfile x509-ca-key-rsa_pss_256.pem \
- --pkcs8 --password '' --key-type='rsa-pss' --bits=2048 --hash=sha256 --salt-size=32
- certtool --generate-self-signed --template ca.tmpl --outfile x509-ca-rsa_pss_256.pem \
- --load-privkey x509-ca-key-rsa_pss_256.pem
-
- certtool --generate-privkey --outfile x509-ca-key-rsa_pss_384.pem \
- --pkcs8 --password '' --key-type='rsa-pss' --bits=2048 --hash=sha384 --salt-size=48
- certtool --generate-self-signed --template ca.tmpl --outfile x509-ca-rsa_pss_384.pem \
- --load-privkey x509-ca-key-rsa_pss_384.pem
-
- certtool --generate-privkey --outfile x509-ca-key-rsa_pss_512.pem \
- --pkcs8 --password '' --key-type='rsa-pss' --bits=2048 --hash=sha512 --salt-size=64
- certtool --generate-self-signed --template ca.tmpl --outfile x509-ca-rsa_pss_512.pem \
- --load-privkey x509-ca-key-rsa_pss_512.pem
-
-# Client agreement credentials:
-
- certtool --generate-privkey --outfile x509-client-key-ecdh.pem \
- --pkcs8 --password '' --ecc --curve secp256r1
- certtool --generate-certificate --template client_agree.tmpl --outfile x509-client-ecdh.pem \
- --load-privkey x509-client-key-ecdh.pem --hash sha256 \
- --load-ca-privkey x509-ca-key-ecdsa.pem --load-ca-certificate x509-ca-ecdsa.pem
-
-# Client signing credentials:
-
- certtool --generate-privkey --outfile x509-client-key-dsa.pem \
- --pkcs8 --password '' --dsa --bits 2048
- certtool --generate-certificate --template client_sign.tmpl --outfile x509-client-dsa.pem \
- --load-privkey x509-client-key-dsa.pem --hash sha256 \
- --load-ca-privkey x509-ca-key-dsa.pem --load-ca-certificate x509-ca-dsa.pem
-
- certtool --generate-privkey --outfile x509-client-key-ecdsa.pem \
- --pkcs8 --password '' --ecdsa --curve secp256r1
- certtool --generate-certificate --template client_sign.tmpl --outfile x509-client-ecdsa.pem \
- --load-privkey x509-client-key-ecdsa.pem --hash sha256 \
- --load-ca-privkey x509-ca-key-ecdsa.pem --load-ca-certificate x509-ca-ecdsa.pem
-
- certtool --generate-privkey --outfile x509-client-key-ed25519.pem \
- --pkcs8 --password '' --key-type=ed25519
- certtool --generate-certificate --template client_sign.tmpl --outfile x509-client-ed25519.pem \
- --load-privkey x509-client-key-ed25519.pem \
- --load-ca-privkey x509-ca-key-ed25519.pem --load-ca-certificate x509-ca-ed25519.pem
-
- certtool --generate-privkey --outfile x509-client-key-ed448.pem \
- --pkcs8 --password '' --key-type=ed448
- certtool --generate-certificate --template client_sign.tmpl --outfile x509-client-ed448.pem \
- --load-privkey x509-client-key-ed448.pem \
- --load-ca-privkey x509-ca-key-ed448.pem --load-ca-certificate x509-ca-ed448.pem
-
- certtool --generate-privkey --outfile x509-client-key-rsa.pem \
- --pkcs8 --password '' --rsa --bits 2048
- certtool --generate-certificate --template client_sign.tmpl --outfile x509-client-rsa.pem \
- --load-privkey x509-client-key-rsa.pem --hash sha256 \
- --load-ca-privkey x509-ca-key-rsa.pem --load-ca-certificate x509-ca-rsa.pem
-
- certtool --generate-privkey --outfile x509-client-key-rsa_pss_256.pem \
- --pkcs8 --password '' --key-type='rsa-pss' --bits=2048 --hash=sha256 --salt-size=32
- certtool --generate-certificate --template client_sign.tmpl \
- --outfile x509-client-rsa_pss_256.pem \
- --load-privkey x509-client-key-rsa_pss_256.pem \
- --load-ca-privkey x509-ca-key-rsa_pss_256.pem \
- --load-ca-certificate x509-ca-rsa_pss_256.pem
-
- certtool --generate-privkey --outfile x509-client-key-rsa_pss_384.pem \
- --pkcs8 --password '' --key-type='rsa-pss' --bits=2048 --hash=sha384 --salt-size=48
- certtool --generate-certificate --template client_sign.tmpl \
- --outfile x509-client-rsa_pss_384.pem \
- --load-privkey x509-client-key-rsa_pss_384.pem \
- --load-ca-privkey x509-ca-key-rsa_pss_384.pem \
- --load-ca-certificate x509-ca-rsa_pss_384.pem
-
- certtool --generate-privkey --outfile x509-client-key-rsa_pss_512.pem \
- --pkcs8 --password '' --key-type='rsa-pss' --bits=2048 --hash=sha512 --salt-size=64
- certtool --generate-certificate --template client_sign.tmpl \
- --outfile x509-client-rsa_pss_512.pem \
- --load-privkey x509-client-key-rsa_pss_512.pem \
- --load-ca-privkey x509-ca-key-rsa_pss_512.pem \
- --load-ca-certificate x509-ca-rsa_pss_512.pem
-
-# Server agreement credentials:
-
- certtool --generate-privkey --outfile x509-server-key-ecdh.pem \
- --pkcs8 --password '' --ecc --curve secp256r1
- certtool --generate-certificate --template server_agree.tmpl --outfile x509-server-ecdh.pem \
- --load-privkey x509-server-key-ecdh.pem --hash sha256 \
- --load-ca-privkey x509-ca-key-ecdsa.pem --load-ca-certificate x509-ca-ecdsa.pem
-
-# Server encryption credentials:
-
- certtool --generate-privkey --outfile x509-server-key-rsa-enc.pem \
- --pkcs8 --password '' --rsa --bits 2048
- certtool --generate-certificate --outfile x509-server-rsa-enc.pem \
- --load-privkey x509-server-key-rsa-enc.pem --template server_enc.tmpl \
- --load-ca-privkey x509-ca-key-rsa.pem --load-ca-certificate x509-ca-rsa.pem \
- --hash sha256
-
-# Server signing credentials:
-
- certtool --generate-privkey --outfile x509-server-key-dsa.pem \
- --pkcs8 --password '' --dsa --bits 2048
- certtool --generate-certificate --template server_sign.tmpl --outfile x509-server-dsa.pem \
- --load-privkey x509-server-key-dsa.pem --hash sha256 \
- --load-ca-privkey x509-ca-key-dsa.pem --load-ca-certificate x509-ca-dsa.pem
-
- certtool --generate-privkey --outfile x509-server-key-ecdsa.pem \
- --pkcs8 --password '' --ecdsa --curve secp256r1
- certtool --generate-certificate --template server_sign.tmpl --outfile x509-server-ecdsa.pem \
- --load-privkey x509-server-key-ecdsa.pem --hash sha256 \
- --load-ca-privkey x509-ca-key-ecdsa.pem --load-ca-certificate x509-ca-ecdsa.pem
-
- certtool --generate-privkey --outfile x509-server-key-ed25519.pem \
- --pkcs8 --password '' --key-type=ed25519
- certtool --generate-certificate --template server_sign.tmpl --outfile x509-server-ed25519.pem \
- --load-privkey x509-server-key-ed25519.pem \
- --load-ca-privkey x509-ca-key-ed25519.pem --load-ca-certificate x509-ca-ed25519.pem
-
- certtool --generate-privkey --outfile x509-server-key-ed448.pem \
- --pkcs8 --password '' --key-type=ed448
- certtool --generate-certificate --template server_sign.tmpl --outfile x509-server-ed448.pem \
- --load-privkey x509-server-key-ed448.pem \
- --load-ca-privkey x509-ca-key-ed448.pem --load-ca-certificate x509-ca-ed448.pem
-
- certtool --generate-privkey --outfile x509-server-key-rsa-sign.pem \
- --pkcs8 --password '' --rsa --bits 2048
- certtool --generate-certificate --template server_sign.tmpl --outfile x509-server-rsa-sign.pem \
- --load-privkey x509-server-key-rsa-sign.pem --hash sha256 \
- --load-ca-privkey x509-ca-key-rsa.pem --load-ca-certificate x509-ca-rsa.pem
-
- certtool --generate-privkey --outfile x509-server-key-rsa_pss_256.pem \
- --pkcs8 --password '' --key-type='rsa-pss' --bits=2048 --hash=sha256 --salt-size=32
- certtool --generate-certificate --template server_sign.tmpl \
- --outfile x509-server-rsa_pss_256.pem \
- --load-privkey x509-server-key-rsa_pss_256.pem \
- --load-ca-privkey x509-ca-key-rsa_pss_256.pem \
- --load-ca-certificate x509-ca-rsa_pss_256.pem
-
- certtool --generate-privkey --outfile x509-server-key-rsa_pss_384.pem \
- --pkcs8 --password '' --key-type='rsa-pss' --bits=2048 --hash=sha384 --salt-size=48
- certtool --generate-certificate --template server_sign.tmpl \
- --outfile x509-server-rsa_pss_384.pem \
- --load-privkey x509-server-key-rsa_pss_384.pem \
- --load-ca-privkey x509-ca-key-rsa_pss_384.pem \
- --load-ca-certificate x509-ca-rsa_pss_384.pem
-
- certtool --generate-privkey --outfile x509-server-key-rsa_pss_512.pem \
- --pkcs8 --password '' --key-type='rsa-pss' --bits=2048 --hash=sha512 --salt-size=64
- certtool --generate-certificate --template server_sign.tmpl \
- --outfile x509-server-rsa_pss_512.pem \
- --load-privkey x509-server-key-rsa_pss_512.pem \
- --load-ca-privkey x509-ca-key-rsa_pss_512.pem \
- --load-ca-certificate x509-ca-rsa_pss_512.pem
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/ca.tmpl b/tls/src/test/resources/org/bouncycastle/tls/test/ca.tmpl
deleted file mode 100644
index 72e41e69ee..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/ca.tmpl
+++ /dev/null
@@ -1,4 +0,0 @@
-cn = BouncyCastle TLS Test CA
-ca
-cert_signing_key
-expiration_days = 7301
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/client_agree.tmpl b/tls/src/test/resources/org/bouncycastle/tls/test/client_agree.tmpl
deleted file mode 100644
index 1718041888..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/client_agree.tmpl
+++ /dev/null
@@ -1,4 +0,0 @@
-cn = BouncyCastle Test Client
-tls_www_client
-key_agreement
-expiration_days = 7300
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/client_enc.tmpl b/tls/src/test/resources/org/bouncycastle/tls/test/client_enc.tmpl
deleted file mode 100644
index 1a6f2efd8d..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/client_enc.tmpl
+++ /dev/null
@@ -1,4 +0,0 @@
-cn = BouncyCastle Test Client
-tls_www_client
-encryption_key
-expiration_days = 7300
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/client_sign.tmpl b/tls/src/test/resources/org/bouncycastle/tls/test/client_sign.tmpl
deleted file mode 100644
index 5a320b1113..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/client_sign.tmpl
+++ /dev/null
@@ -1,4 +0,0 @@
-cn = BouncyCastle Test Client
-tls_www_client
-signing_key
-expiration_days = 7300
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/server_agree.tmpl b/tls/src/test/resources/org/bouncycastle/tls/test/server_agree.tmpl
deleted file mode 100644
index 44f12f6509..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/server_agree.tmpl
+++ /dev/null
@@ -1,4 +0,0 @@
-cn = BouncyCastle Test Server
-tls_www_server
-key_agreement
-expiration_days = 7300
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/server_enc.tmpl b/tls/src/test/resources/org/bouncycastle/tls/test/server_enc.tmpl
deleted file mode 100644
index 4bfc58e073..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/server_enc.tmpl
+++ /dev/null
@@ -1,4 +0,0 @@
-cn = BouncyCastle Test Server
-tls_www_server
-encryption_key
-expiration_days = 7300
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/server_sign.tmpl b/tls/src/test/resources/org/bouncycastle/tls/test/server_sign.tmpl
deleted file mode 100644
index 1d12addabc..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/server_sign.tmpl
+++ /dev/null
@@ -1,4 +0,0 @@
-cn = BouncyCastle Test Server
-tls_www_server
-signing_key
-expiration_days = 7300
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-dsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-dsa.pem
deleted file mode 100644
index d9cb013a2a..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-dsa.pem
+++ /dev/null
@@ -1,26 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIEdDCCBBqgAwIBAgIMWYGU7zZX3YAzRZ8VMAsGCWCGSAFlAwQDAjAjMSEwHwYD
-VQQDExhCb3VuY3lDYXN0bGUgVExTIFRlc3QgQ0EwHhcNMTcwODAyMDkwMTM1WhcN
-MzcwNzI5MDkwMTM1WjAjMSEwHwYDVQQDExhCb3VuY3lDYXN0bGUgVExTIFRlc3Qg
-Q0EwggNHMIICOQYHKoZIzjgEATCCAiwCggEBAO5dNk+YfyPOeIK54F9Wg6Zl5+cu
-80tSk1fZBSQE1nFBblnGifl39LTmwkHL7XNZmUUFtrScY7Qlk0/cRsEqsl647fAy
-XNhqpZAOMPJs4NBx6nzQvKlprxU9JYO5kvTIoJNBR4GCUDxX/DWLffFqvwbBmrZ3
-BgNAHhAHj/wDm0sfxKDXHgfUwmVJgBOne7xwh86SJJojw+MN33ILuSfNFePv2AeQ
-kw+bY93tPpouyfskyBLdWs7DeGXmjftFSmpS68j36RAL0+4QZVwDyX/aIwK1bxAH
-XLgRnono7NfGxzqlPiQXfb5ewUmZPyjJ3P06WMU3kgj6ZMoyfmJOHCSwjAECIQCg
-NiET6OM1ljsc4tvOXtDSyXXqQ4YtRT5o41Gal8kv+QKCAQAbvM2Az1+PzOhrySA5
-PATwWWDMIXlxFx3U1gXIczu4lGGRaoVzfmSGsDZ6A/0j+/ZtmpjGH3B+jb0Rab0n
-yZBDUzK+39w+YI7s+K6yGkKlSuyhpB/UokDP0h5Pf6MEVAU2bIcuuWTLMJmleWLw
-zHKJTjUDnrC6txeVAbsW+O4l04jMHLTZMXg2OTk9urUtJzeJNkEEMNA8sv7h+yrA
-oX2FqvhfDg/oLdfwXQULkKJc/ec6IQaXrtHm+oYwDQxsr9ap4FlET1nz91MMAXon
-hB2Yfl7dRKJtKMUKGWGbCliTnJAPUHI1URltnEg387G/YbnnEBUnZlNBJeDrpZFg
-+v2ZA4IBBgACggEBAJQi1dv4plwRKrP2fU/76FLcx++60cA4oajNm0f4Vyyaz2xF
-7hPiFNj2H0nLNJAtPtdn/wC7KHNWmDx0OiUFIseAqPPoQvfaSrFun1F2iUJhlrKU
-FOJ3RC2URoD+M7IbR1SXAyuWOVenhoYyky1mausApUhUjoLO3mMOyBDdXMGWMq7p
-SHfyziAnySzwZ2bwOrVz4XL41w4cPbjdEzd4MLIfpPaqqW43y4MNlgLLspm9vBO5
-6Fbq9c0bDUa18jkSi7DU7uH43S9tq3HrPQh127XZ5SstNPU2uV0o+ZXAS8V9sBOM
-LGZMjkiQ8bozYtUVAlhLFBnzMB/BOCWxe2yJGSyjQzBBMA8GA1UdEwEB/wQFMAMB
-Af8wDwYDVR0PAQH/BAUDAwcEADAdBgNVHQ4EFgQUAOVmarDrz1YtyjvnX4C9cDcX
-lagwCwYJYIZIAWUDBAMCA0cAMEQCIFEz1ogza6zKwImQS9tKVlPNjU4QSDEfPjZP
-aSwIVMCyAiB+TcGoJvBEAdkzIeQQDdQLldrR+tO/WbayMeqPZHG6ww==
------END CERTIFICATE-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-ecdsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-ecdsa.pem
deleted file mode 100644
index 019ada2707..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-ecdsa.pem
+++ /dev/null
@@ -1,11 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIBgzCCASmgAwIBAgIMWYGU7zek17Bcz64zMAoGCCqGSM49BAMCMCMxITAfBgNV
-BAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0xNzA4MDIwOTAxMzVaFw0z
-NzA3MjkwOTAxMzVaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBD
-QTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABDOjvFecZj9RsxsIZSygfmv/GX9M
-oJkQeMk+sI6QRVv7YbzL7QUxKa4gRb2x2e3iKPi+Mi2x2wGAPJajJO6nj8ujQzBB
-MA8GA1UdEwEB/wQFMAMBAf8wDwYDVR0PAQH/BAUDAwcEADAdBgNVHQ4EFgQU0ma/
-FGcW5gGlL//B26Xmj0JISecwCgYIKoZIzj0EAwIDSAAwRQIhAJPFYIENHNONgDNy
-1565P/2N0TMAkcENL2zyCEDnYVG4AiBiA3BuThR1Rgnvn1qRGaivzoIiMvDVRQb7
-p76OkZ8Igw==
------END CERTIFICATE-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-ed25519.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-ed25519.pem
deleted file mode 100644
index c117a2649f..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-ed25519.pem
+++ /dev/null
@@ -1,9 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIBSjCB/aADAgECAhQ4EsBmtAbEpUqx/8m96XRPinrybTAFBgMrZXAwIzEhMB8G
-A1UEAxMYQm91bmN5Q2FzdGxlIFRMUyBUZXN0IENBMB4XDTE4MDgyMzA5Mjk0N1oX
-DTM4MDgxOTA5Mjk0N1owIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxlIFRMUyBUZXN0
-IENBMCowBQYDK2VwAyEA8ZleePPCqzYeCARxwHP10sYfQhcCQ4YXjyOxrb53I0qj
-QzBBMA8GA1UdEwEB/wQFMAMBAf8wDwYDVR0PAQH/BAUDAwcEADAdBgNVHQ4EFgQU
-6nm+PvoHITBuh26gdYBbNqOczWYwBQYDK2VwA0EAoUgBYkz0bcLAC+kTmbwE05ga
-u2SmQtPaiXGykqY+3RhoZVthxQyEzWT0N5KJ322l6mjs0CZRat0ai4hR1Yj7BA==
------END CERTIFICATE-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-ed448.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-ed448.pem
deleted file mode 100644
index e72fcc6d98..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-ed448.pem
+++ /dev/null
@@ -1,11 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIBljCCARagAwIBAgIUWxqMqdy/tO71K3Iz4GYJiWrc42wwBQYDK2VxMCMxITAf
-BgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0yMDAyMTMwNzMzMDJa
-Fw00MDAyMDkwNzMzMDJaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVz
-dCBDQTBDMAUGAytlcQM6AKSetNrq+LCrx62FFnDlmUG/gZUa6LkaIHnfVM3w7/Wl
-c1RONMpgGRUeNMqM8YBlgDzUrHjVkHfOAKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAP
-BgNVHQ8BAf8EBQMDBwQAMB0GA1UdDgQWBBS+BSv++BEWlTJ53q6rwnDLVnR5JTAF
-BgMrZXEDcwCFAtJNOZDtSYHm/Mf/L2PEbXNDDNrieJGWbixz/QXYoXjNBFB0D521
-IGH0o6Gdh0ZaQvdktpXc9wDs9xAbzh/w6+hLROTj8UvxyvPuZbGgVYH/tvE++NH/
-H0EQMi0FnLI/iBGv/bEPm8VJ1e24qEiEAAA=
------END CERTIFICATE-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-dsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-dsa.pem
deleted file mode 100644
index 4c378da7a6..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-dsa.pem
+++ /dev/null
@@ -1,15 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIICZQIBADCCAjkGByqGSM44BAEwggIsAoIBAQDuXTZPmH8jzniCueBfVoOmZefn
-LvNLUpNX2QUkBNZxQW5Zxon5d/S05sJBy+1zWZlFBba0nGO0JZNP3EbBKrJeuO3w
-MlzYaqWQDjDybODQcep80Lypaa8VPSWDuZL0yKCTQUeBglA8V/w1i33xar8GwZq2
-dwYDQB4QB4/8A5tLH8Sg1x4H1MJlSYATp3u8cIfOkiSaI8PjDd9yC7knzRXj79gH
-kJMPm2Pd7T6aLsn7JMgS3VrOw3hl5o37RUpqUuvI9+kQC9PuEGVcA8l/2iMCtW8Q
-B1y4EZ6J6OzXxsc6pT4kF32+XsFJmT8oydz9OljFN5II+mTKMn5iThwksIwBAiEA
-oDYhE+jjNZY7HOLbzl7Q0sl16kOGLUU+aONRmpfJL/kCggEAG7zNgM9fj8zoa8kg
-OTwE8FlgzCF5cRcd1NYFyHM7uJRhkWqFc35khrA2egP9I/v2bZqYxh9wfo29EWm9
-J8mQQ1Myvt/cPmCO7PiushpCpUrsoaQf1KJAz9IeT3+jBFQFNmyHLrlkyzCZpXli
-8MxyiU41A56wurcXlQG7FvjuJdOIzBy02TF4Njk5Pbq1LSc3iTZBBDDQPLL+4fsq
-wKF9har4Xw4P6C3X8F0FC5CiXP3nOiEGl67R5vqGMA0MbK/WqeBZRE9Z8/dTDAF6
-J4QdmH5e3USibSjFChlhmwpYk5yQD1ByNVEZbZxIN/Oxv2G55xAVJ2ZTQSXg66WR
-YPr9mQQjAiEAnZYHGZPTcKWTzPTfMa5UQkZgqKU1jqyOOWWtHc50fPE=
------END PRIVATE KEY-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-ecdsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-ecdsa.pem
deleted file mode 100644
index 42132d48f5..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-ecdsa.pem
+++ /dev/null
@@ -1,6 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgXP0gFZhM/8/F0imI
-9EPD/er+bEFS8m2nY9JzJlricXigCgYIKoZIzj0DAQehRANCAAQzo7xXnGY/UbMb
-CGUsoH5r/xl/TKCZEHjJPrCOkEVb+2G8y+0FMSmuIEW9sdnt4ij4vjItsdsBgDyW
-oyTup4/L
------END PRIVATE KEY-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-ed25519.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-ed25519.pem
deleted file mode 100644
index 027bb835ea..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-ed25519.pem
+++ /dev/null
@@ -1,25 +0,0 @@
-Public Key Info:
- Public Key Algorithm: EdDSA (Ed25519)
- Key Security Level: High (256 bits)
-
-curve: Ed25519
-private key:
- a9:19:76:8a:f7:cf:95:c7:e3:94:3c:ce:3c:71:59:44
- 89:08:34:e5:49:0b:0a:44:56:d6:1d:05:f4:af:5d:85
-
-
-x:
- f1:99:5e:78:f3:c2:ab:36:1e:08:04:71:c0:73:f5:d2
- c6:1f:42:17:02:43:86:17:8f:23:b1:ad:be:77:23:4a
-
-
-
-Public Key PIN:
- pin-sha256:XFgN/8/bw68mn6K+U4zDmMa+HSGjXI0bejzTOxFQf0U=
-Public Key ID:
- sha256:5c580dffcfdbc3af269fa2be538cc398c6be1d21a35c8d1b7a3cd33b11507f45
- sha1:ea79be3efa0721306e876ea075805b36a39ccd66
-
------BEGIN PRIVATE KEY-----
-MC4CAQAwBQYDK2VwBCIEIKkZdor3z5XH45Q8zjxxWUSJCDTlSQsKRFbWHQX0r12F
------END PRIVATE KEY-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-ed448.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-ed448.pem
deleted file mode 100644
index 6974289736..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-ed448.pem
+++ /dev/null
@@ -1,28 +0,0 @@
-Public Key Info:
- Public Key Algorithm: EdDSA (Ed448)
- Key Security Level: Ultra (456 bits)
-
-curve: Ed448
-private key:
- d8:36:a1:a6:12:8b:25:7a:86:eb:8a:b2:93:4a:71:df
- 44:b7:9e:be:59:09:61:58:43:d2:3f:80:04:59:7b:37
- 89:cc:d9:6b:84:26:ae:b9:75:3c:b7:6d:eb:4b:c9:d8
- 36:94:5e:63:44:7b:7f:4b:e0:
-
-x:
- a4:9e:b4:da:ea:f8:b0:ab:c7:ad:85:16:70:e5:99:41
- bf:81:95:1a:e8:b9:1a:20:79:df:54:cd:f0:ef:f5:a5
- 73:54:4e:34:ca:60:19:15:1e:34:ca:8c:f1:80:65:80
- 3c:d4:ac:78:d5:90:77:ce:00:
-
-
-Public Key PIN:
- pin-sha256:fnp0p/r6DXkqUgGSXDJih9BAOy/+ImGTT5dCbfH6H4w=
-Public Key ID:
- sha256:7e7a74a7fafa0d792a5201925c326287d0403b2ffe2261934f97426df1fa1f8c
- sha1:be052bfef81116953279deaeabc270cb56747925
-
------BEGIN PRIVATE KEY-----
-MEcCAQAwBQYDK2VxBDsEOdg2oaYSiyV6huuKspNKcd9Et56+WQlhWEPSP4AEWXs3
-iczZa4Qmrrl1PLdt60vJ2DaUXmNEe39L4A==
------END PRIVATE KEY-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa.pem
deleted file mode 100644
index 9b51726a1a..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa.pem
+++ /dev/null
@@ -1,28 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDjLlJpiydqUOH2
-IxH7iI9dUzJxvHaknGqXP8lPcxwg5+Q0CRjmv1+Y2KCV+JNj215OW23JNnGguCe/
-xlkboBnOCnDlSLQJp8W1cyarabHUa1VL086nL2kmTRxIElj+91ppQAl+sSB0cgba
-/j8KYoO93mZDlXBjrG7FpYn31UNH9H8/wBrGIeSFgTZSHwTlsDhAQyWr5bGK1RgM
-NTLl8ZJ8m7I1xUashTTxOkoXd1t3rXqPhTr0LMqKZl+hXD/hDmhUMUkO8kfsTbK3
-gssYuNIT37MDuk4oTfYS3VbdwvjhwycNsEdsTPksLFvB7uIxIttbmpEJfOOs/l3Y
-FaPg9793AgMBAAECggEBANR2XtacMFmKmTijZc7y0Pk7tKKP2flq23jmS7QE+FqB
-5HcRxvsOIS6F8fEvz1AFObZYZV1XkH75mxsMOgvO+DMsqpaUHuQkxo9CyPhoWcpK
-MzQ+Ozc57MHIPdndZuPUmvZx0C9vIeYlOeoW+wgQSBsK4mL0YG6nNdWcUmK4TTr9
-V62ZvqDYoZjtTsAoLkUVJAgByN3XNzc70RQKN5OyCC8iib0JpLEeLdOkGgxWE7/n
-KNLZ/9tbK9O4Mn3BWwZsTt8Hve0m/G9CbjlriEz9PYRBEg+JP6FmQIB5l0mjyRMQ
-F5uRqiZt6r1uUGwUifNDOqNyJzSolj32u+OG3m8/6qkCgYEA+Tof5Wtuq9Oc5zCF
-oVzm3cT1DZy3kJdGZWlMekLC9NMXhnA2huuNkln8Ph2qRx5pxmomRvX8ThaHNUdg
-IRjzUomTQ0IWPkn+7TT6CmeSIEOoT4Tyw/xVvBHKm/yHKxHsCkcSIzt1cXS1SGU7
-Dfsy2C+FBjkcW6UBHkNKUMxce/0CgYEA6VrShFfora0fUOibaas/YG7XnqQzFyvw
-mcBpqAbUXTneFdyssZDyfmQpE44KCywfPczz+34zIRkjnBX6mLyWx5rINE0KpOBK
-uwS2ob1g6J1x6I6btBzIhhgR+Zj9zxhD5f+jYmmBCU3yTvWMXL4c5YsaWvlG8doq
-bNo40cQykYMCgYEAmK8pV03n8VClMWWimGbn8Tl2v64hL23d7McD2WsJMSAZq30X
-irTIeL60MAHQjd1uA+aIKLUOq3BVySg/FkfI2en61BuqsOJ4US5BeRpWhXmtpXnX
-mIYAqEVmEQY2cQZ7yxgbXoZQvv83CHEsKraYQaVrI5Ldcq+17apf3vw0NKkCgYBH
-u6WPDT73dIp14qszlnLLAAfEOpGCA/3YJa/U+RR6+/jrG4TyqK4CcGO4ISexO4T3
-CHPP0YGCISozJwZ7wS1QeqIkgbJN8KzIRLCnk4GgwBVt+bifa2Gw5uFPqtoKuVjV
-8PmWnPwPkih0YUMel0pmvZYCdTJ70ibMg2CICxnIZQKBgQC7aMgcL5ORB/8fgOdy
-g0at1fmz5kKKbv0Z9cmk7trKW67NDM5kwVyFdUuc5Vp7alkRyW4SZPtwpOG+d5Xt
-M0DM77Qvom+sIYq5C5eSHPU6py2Ipn5HZzkHRnAM8qw3OrL6+iFklQUKEBXeqVEq
-6MfsH8P1/RIRfvcOMhPrNEzpTg==
------END PRIVATE KEY-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa_pss_256.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa_pss_256.pem
deleted file mode 100644
index 9243a1e32a..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa_pss_256.pem
+++ /dev/null
@@ -1,138 +0,0 @@
-Public Key Info:
- Public Key Algorithm: RSA-PSS
- Hash Algorithm: SHA256
- Salt Length: 32
- Key Security Level: Medium (2048 bits)
-
-modulus:
- 00:b7:b4:9a:4d:2d:3f:08:b8:1e:55:d6:b0:b2:b7:d0
- 33:cc:bb:de:56:24:04:1d:73:ac:6a:32:db:af:26:4f
- ef:b1:d6:10:90:79:dc:89:ac:60:e3:94:54:19:04:54
- 17:ea:18:0e:d9:46:be:60:9f:e6:33:ff:6e:60:6a:35
- c6:2d:dd:06:82:d5:80:c9:88:07:2f:27:4b:04:13:ba
- 4b:69:92:ce:bc:00:be:42:2c:e2:35:8d:60:11:66:3c
- 24:f8:3a:13:ad:49:e7:12:ca:c6:2a:52:84:ed:3d:7d
- 1e:06:de:a4:64:d6:17:14:b1:19:63:a0:e1:7c:49:d3
- 41:73:29:f8:b5:75:e0:93:fa:e3:df:3b:82:77:5e:83
- cb:da:52:26:eb:c3:20:13:11:6d:e9:aa:a5:d7:b6:c3
- a1:a5:04:fa:6e:ee:4f:39:52:4d:18:f9:ab:87:4a:4e
- d9:34:a7:c4:df:f5:1b:b6:57:71:7f:c3:c8:4f:2c:00
- c0:6e:e8:74:35:e2:71:1f:ef:c6:c1:62:7a:65:e7:c9
- c7:42:14:5f:16:c1:ab:4d:32:e5:e2:7c:38:a2:21:02
- 69:a3:81:f4:c8:78:48:58:0a:5d:99:85:f5:e6:2a:37
- be:23:e5:ff:15:ba:39:42:ac:9d:d0:11:7e:e4:2b:55
- db:
-
-public exponent:
- 01:00:01:
-
-private exponent:
- 00:9a:2e:3e:02:e0:22:b3:52:b4:43:1e:f9:16:46:27
- bc:11:ec:eb:62:28:c0:3b:67:c6:21:2b:a6:2d:8e:5e
- 30:b2:75:13:59:ee:ad:25:ef:43:32:3e:5f:86:cf:97
- 34:ab:08:9e:0d:c5:ce:2a:92:89:46:c2:ef:04:84:9f
- b5:40:f0:ec:72:0a:77:18:ad:ce:39:c9:24:b0:bb:4d
- f3:d5:1b:9d:df:34:50:7a:81:e9:29:41:0a:8c:0f:de
- 12:b9:33:25:28:9f:8a:0c:bf:9b:2a:12:2f:f6:5d:51
- 11:4e:7a:b6:46:db:58:6b:c9:67:a1:b2:79:0d:33:78
- d5:5d:69:38:91:d9:f0:37:28:da:67:56:96:dd:77:d4
- f0:cd:33:9a:a3:7d:cc:6a:5c:44:c1:bd:e3:d3:34:71
- 70:b1:ed:67:56:cc:02:28:3b:e2:2b:6d:d0:eb:69:9b
- e5:d9:27:e8:fc:2a:03:14:e1:f7:76:3f:b7:a7:87:1c
- 78:84:9e:17:60:71:84:b7:67:83:c5:41:27:40:18:96
- 3c:c5:13:9f:ff:fd:3f:ac:30:cd:e5:f7:b5:cb:ac:16
- 39:85:05:c1:59:46:ce:df:e8:67:9a:a2:56:88:73:a8
- 34:23:b2:54:2d:18:2c:c9:16:0c:d0:f6:46:55:9f:2a
- 01:
-
-prime1:
- 00:e1:11:b3:58:64:b9:77:3c:b9:f2:95:df:bb:0b:66
- f6:81:31:03:22:cb:eb:5a:a9:38:63:31:ff:f2:75:46
- 9a:dd:be:a7:d0:d4:c8:30:18:bf:6f:bf:c0:01:ba:27
- 0e:34:b2:7f:75:f0:aa:05:69:71:68:03:41:9b:47:5b
- 6a:7b:89:ef:f4:e0:84:c0:01:67:5c:46:c6:29:40:3d
- 55:15:48:d6:19:e9:22:d2:fd:88:1d:f6:cd:7e:9c:04
- c6:b0:d7:3d:1d:ea:42:44:8c:10:a8:6c:8a:d2:70:6d
- b6:fb:9b:1f:ce:d9:ec:3e:1a:3f:ee:02:17:e3:37:74
- 9b:
-
-prime2:
- 00:d0:f3:a9:3a:80:a3:ac:1f:e9:d8:29:f4:2f:1a:7c
- d6:61:77:c8:82:cb:fa:64:a0:ce:ef:ec:5c:e9:97:a0
- 1d:28:a6:49:5d:34:59:92:96:c1:b2:c2:14:f5:02:a2
- 2e:b9:ab:df:a7:79:e6:b3:fa:5c:3e:bd:50:b2:e4:c1
- ee:d3:b5:5d:38:a4:f6:d0:81:8a:e1:5a:45:da:19:06
- a3:fa:6a:84:8f:04:f4:56:2a:00:13:2b:76:8d:c1:c8
- d4:eb:42:c0:02:d5:c5:b4:83:7f:36:32:27:93:fc:49
- 11:f4:a3:4d:7d:bd:03:61:e7:40:28:15:10:ad:8f:97
- c1:
-
-coefficient:
- 00:d6:d9:e8:05:2e:4f:3c:27:59:e4:3a:5a:1a:15:59
- 0c:b7:fd:fa:23:ad:c1:64:07:e4:22:ae:35:9b:ac:e8
- 95:34:46:be:38:ba:99:07:4b:52:0f:f2:f9:cd:32:e7
- 99:2d:66:15:f1:f3:51:b5:4e:4a:d5:49:8f:a3:97:43
- ad:60:31:c7:c7:a7:4a:e0:2f:07:fe:40:24:22:5a:4e
- 76:ee:ef:df:95:85:e4:5a:81:7a:ab:61:e9:da:51:7e
- 2f:dd:d7:83:46:b2:76:13:ef:18:3a:64:45:31:e1:4f
- af:6e:f0:6e:34:d2:cf:59:e3:ee:88:f2:22:1e:c8:06
- f6:
-
-exp1:
- 00:96:25:00:c7:cf:2a:0a:e9:70:02:ed:08:bb:f6:f7
- 51:2b:0e:4f:51:3f:48:5a:ca:d8:db:13:d7:f3:1f:59
- 62:a6:db:31:88:96:ea:95:6b:6d:0a:57:98:f7:8d:ff
- cf:f2:47:c1:d0:24:24:c8:47:77:68:34:03:e8:5a:ca
- 19:57:20:c5:fb:4e:6c:40:ca:ae:f1:58:25:8a:0f:58
- db:11:bf:ed:54:8b:ba:b7:96:7a:df:c2:6d:84:31:00
- de:ab:ca:6a:f3:31:fb:d3:4e:bd:2e:1e:7a:dd:b8:32
- f9:07:10:8d:3f:a9:11:78:bc:7a:39:85:1b:fa:70:5c
- 51:
-
-exp2:
- 42:c5:ca:cb:8e:36:3f:98:07:33:73:dc:bb:7c:bc:6e
- 09:c1:ac:8a:d7:c2:51:8b:ed:f5:4f:d4:35:35:a6:0e
- 0b:62:70:49:5f:a4:4c:2a:ef:05:3f:ee:50:89:a1:e8
- 4a:9f:39:1e:9c:de:f3:9e:cb:01:a5:9f:f7:3b:11:1a
- 4f:ff:42:26:0a:d9:70:b2:24:fe:74:c9:a3:b3:a1:a2
- 9f:30:90:e1:df:54:71:80:84:7b:9b:c5:0b:f1:e4:4a
- de:4f:7b:6a:ac:83:bc:76:d5:1d:2d:93:e6:3f:95:de
- 2e:0e:4d:82:23:f7:c3:be:91:8a:fd:88:51:de:74:41
-
-
-
-Public Key PIN:
- pin-sha256:O4J2O7fbEdphitrCWZG7Jyi8t5S4daRsB8YQZknFYWk=
-Public Key ID:
- sha256:3b82763bb7db11da618adac25991bb2728bcb794b875a46c07c6106649c56169
- sha1:211a88b6de03c00180aadb708899a68f17ceaa6c
-
------BEGIN PRIVATE KEY-----
-MIIE7wIBADA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAaEaMBgGCSqGSIb3
-DQEBCDALBglghkgBZQMEAgGiAwIBIASCBKkwggSlAgEAAoIBAQC3tJpNLT8IuB5V
-1rCyt9AzzLveViQEHXOsajLbryZP77HWEJB53ImsYOOUVBkEVBfqGA7ZRr5gn+Yz
-/25gajXGLd0GgtWAyYgHLydLBBO6S2mSzrwAvkIs4jWNYBFmPCT4OhOtSecSysYq
-UoTtPX0eBt6kZNYXFLEZY6DhfEnTQXMp+LV14JP64987gndeg8vaUibrwyATEW3p
-qqXXtsOhpQT6bu5POVJNGPmrh0pO2TSnxN/1G7ZXcX/DyE8sAMBu6HQ14nEf78bB
-Ynpl58nHQhRfFsGrTTLl4nw4oiECaaOB9Mh4SFgKXZmF9eYqN74j5f8VujlCrJ3Q
-EX7kK1XbAgMBAAECggEBAJouPgLgIrNStEMe+RZGJ7wR7OtiKMA7Z8YhK6Ytjl4w
-snUTWe6tJe9DMj5fhs+XNKsIng3FziqSiUbC7wSEn7VA8OxyCncYrc45ySSwu03z
-1Rud3zRQeoHpKUEKjA/eErkzJSifigy/myoSL/ZdURFOerZG21hryWehsnkNM3jV
-XWk4kdnwNyjaZ1aW3XfU8M0zmqN9zGpcRMG949M0cXCx7WdWzAIoO+IrbdDraZvl
-2Sfo/CoDFOH3dj+3p4cceISeF2BxhLdng8VBJ0AYljzFE5///T+sMM3l97XLrBY5
-hQXBWUbO3+hnmqJWiHOoNCOyVC0YLMkWDND2RlWfKgECgYEA4RGzWGS5dzy58pXf
-uwtm9oExAyLL61qpOGMx//J1RprdvqfQ1MgwGL9vv8ABuicONLJ/dfCqBWlxaANB
-m0dbanuJ7/TghMABZ1xGxilAPVUVSNYZ6SLS/Ygd9s1+nATGsNc9HepCRIwQqGyK
-0nBttvubH87Z7D4aP+4CF+M3dJsCgYEA0POpOoCjrB/p2Cn0Lxp81mF3yILL+mSg
-zu/sXOmXoB0opkldNFmSlsGywhT1AqIuuavfp3nms/pcPr1QsuTB7tO1XTik9tCB
-iuFaRdoZBqP6aoSPBPRWKgATK3aNwcjU60LAAtXFtIN/NjInk/xJEfSjTX29A2Hn
-QCgVEK2Pl8ECgYEAliUAx88qCulwAu0Iu/b3USsOT1E/SFrK2NsT1/MfWWKm2zGI
-luqVa20KV5j3jf/P8kfB0CQkyEd3aDQD6FrKGVcgxftObEDKrvFYJYoPWNsRv+1U
-i7q3lnrfwm2EMQDeq8pq8zH70069Lh563bgy+QcQjT+pEXi8ejmFG/pwXFECgYBC
-xcrLjjY/mAczc9y7fLxuCcGsitfCUYvt9U/UNTWmDgticElfpEwq7wU/7lCJoehK
-nzkenN7znssBpZ/3OxEaT/9CJgrZcLIk/nTJo7Ohop8wkOHfVHGAhHubxQvx5Ere
-T3tqrIO8dtUdLZPmP5XeLg5NgiP3w76Riv2IUd50QQKBgQDW2egFLk88J1nkOloa
-FVkMt/36I63BZAfkIq41m6zolTRGvji6mQdLUg/y+c0y55ktZhXx81G1TkrVSY+j
-l0OtYDHHx6dK4C8H/kAkIlpOdu7v35WF5FqBeqth6dpRfi/d14NGsnYT7xg6ZEUx
-4U+vbvBuNNLPWePuiPIiHsgG9g==
------END PRIVATE KEY-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa_pss_384.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa_pss_384.pem
deleted file mode 100644
index b83a1059cf..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa_pss_384.pem
+++ /dev/null
@@ -1,138 +0,0 @@
-Public Key Info:
- Public Key Algorithm: RSA-PSS
- Hash Algorithm: SHA384
- Salt Length: 48
- Key Security Level: Medium (2048 bits)
-
-modulus:
- 00:ee:6d:c0:c9:44:dd:94:f8:40:af:9a:f4:43:3e:78
- 45:61:5f:6a:15:23:42:f4:f8:a0:c2:eb:6a:0a:ae:0c
- 43:a7:dc:e9:ac:ce:42:c4:c8:f5:4c:de:6c:52:4b:e5
- d3:2b:42:b8:f9:e5:5c:5f:5c:53:2f:0f:f7:f5:3d:04
- ed:2b:50:c9:ab:6b:74:2d:4b:42:71:57:7a:04:83:38
- 97:fa:5b:22:4a:14:d2:0d:dd:5c:66:c9:25:7d:e3:ff
- 05:84:02:ea:3c:82:97:45:0f:7c:b3:71:8e:7f:31:8d
- b5:eb:5e:b6:0d:91:9b:5d:51:bc:f7:e2:81:a2:5f:46
- 35:cf:9e:64:c4:3c:65:63:f6:ff:15:b0:e7:11:49:fa
- c1:cc:d9:54:9b:f8:13:3d:95:ce:f4:7f:58:66:23:cd
- bc:11:af:e1:3f:af:d8:5e:16:85:cd:7d:b7:7f:59:fa
- ff:29:e6:ef:4f:6e:6b:ef:b0:91:ef:81:63:6f:b2:0c
- 2b:47:a6:21:f7:1f:4b:fb:1d:e7:6f:f8:6f:0e:6a:8f
- 8a:54:5f:4b:a2:6d:36:20:bb:ba:11:87:06:f3:8d:95
- 6a:10:b7:27:8e:1d:02:b4:ce:1e:c2:09:73:c4:b6:5d
- c7:5f:e2:26:bd:4f:cd:7a:b0:c5:c0:d6:82:1f:d4:2e
- 59:
-
-public exponent:
- 01:00:01:
-
-private exponent:
- 6a:cf:72:10:f8:2f:c7:9f:9a:e2:d0:28:e2:c2:e6:80
- 36:49:d7:2d:16:f9:d4:e2:58:aa:59:69:cc:d5:01:9b
- 81:64:9e:ae:12:4c:a8:f9:59:a2:90:f5:b7:bc:56:7d
- ce:20:7a:db:40:1b:ac:80:a0:a7:31:a1:24:14:ac:d3
- 4e:97:47:70:ea:97:45:ff:34:09:b0:65:72:06:12:e1
- 4a:7f:6f:11:fe:d7:c6:ec:46:8b:a9:4a:89:66:0d:05
- bc:88:cd:c4:43:c0:5e:68:bc:b5:6a:86:aa:86:59:74
- 88:b7:8a:18:f4:04:c4:be:6c:48:24:09:6c:e2:ff:81
- 18:5f:a8:85:db:79:b0:14:66:1c:fb:f7:8f:a8:29:79
- 83:79:aa:65:45:05:5a:0f:03:30:e5:75:43:23:23:e1
- eb:09:5d:e6:be:0a:10:bd:34:4a:02:d5:60:f6:51:90
- 30:b5:2d:95:37:0e:aa:fb:8e:f3:4f:b4:2f:54:a4:c1
- 8c:a8:5a:46:0c:85:f0:d5:94:d0:ee:71:a2:c6:d7:b0
- de:81:04:66:43:4c:10:ba:ba:ec:91:57:93:bd:74:4f
- d4:ea:96:3b:53:a1:0c:0f:be:7d:70:9c:c2:ae:b2:13
- 4b:2b:c3:c9:8a:56:12:a0:ab:55:e4:4e:90:df:0c:01
-
-
-prime1:
- 00:f8:f5:75:8a:5e:fb:0f:2a:09:42:dc:eb:1e:0d:c9
- 97:6f:30:c9:55:28:af:15:4e:4a:db:9e:cd:17:6a:7f
- d1:be:1e:53:2b:79:d9:83:de:96:c9:9b:1f:7e:93:ce
- 02:f3:fb:9d:56:a2:19:cf:f2:d0:f2:3b:80:5f:b5:7b
- cb:df:d6:26:fb:e8:ba:2b:db:e5:c1:47:98:1d:2e:57
- 5d:26:19:72:2f:48:77:00:1d:8d:72:f6:48:68:97:62
- 0f:5d:30:e0:95:a4:00:34:e4:77:b9:47:81:30:63:48
- 29:64:a0:2f:4f:c0:42:4b:bb:a2:60:7b:ba:e4:79:6b
- 81:
-
-prime2:
- 00:f5:2c:0d:7a:8c:17:59:ac:95:20:ca:29:3e:45:23
- 23:6f:25:fe:a3:56:df:23:74:47:cd:38:47:a3:4d:06
- 0e:66:7a:9f:74:cc:86:3e:86:e3:c8:4b:45:09:93:2b
- 81:d3:fc:56:a2:29:b3:52:4d:f1:45:69:e2:d3:a3:b1
- 4e:1a:25:bd:1a:6c:2b:57:8a:93:11:b9:e9:6d:11:43
- 2c:aa:22:e9:20:10:bf:e4:fe:a6:c5:30:ec:42:5a:5c
- d9:3d:1d:e9:18:7e:10:5b:9d:59:cd:7f:7e:51:5c:c8
- 65:63:8b:4a:54:e8:c1:fa:5c:e9:36:23:20:20:87:0e
- d9:
-
-coefficient:
- 00:9f:a9:37:76:c0:24:33:8e:18:92:c5:4c:1e:05:fd
- 82:39:d9:40:4d:15:95:7e:92:59:44:1a:99:81:4b:0f
- 16:e0:16:99:23:45:91:04:76:f0:98:d7:f5:92:e4:af
- 39:3b:6f:49:0b:8f:22:02:aa:3a:da:72:04:9c:a4:cb
- 11:1a:44:f4:47:19:ed:a0:9c:94:58:06:cd:ca:b1:ff
- 48:7f:bf:2e:23:66:63:0e:cd:0b:a5:43:ee:23:75:32
- d5:93:08:23:51:e3:9e:d2:82:be:9b:c4:6d:53:a9:50
- 66:74:af:11:dd:f2:d5:a6:9f:6e:ca:11:ac:6d:a6:ca
- 0b:
-
-exp1:
- 00:ba:47:87:9c:72:77:2e:20:88:ef:73:b7:a5:34:31
- cb:d2:91:d1:83:9b:be:6d:95:b8:63:5e:0e:1d:60:3d
- a5:a5:b8:b1:08:8d:d2:d8:5d:db:bb:9c:0b:53:bd:aa
- 5f:01:4a:1a:af:30:f9:59:64:59:3d:76:92:16:8b:07
- c7:43:83:cc:85:9e:dc:76:66:c2:21:fd:bc:ee:d0:b6
- e3:e6:d7:11:5e:19:bd:98:e3:83:ec:2a:25:81:c5:0b
- c5:6d:38:5e:42:f9:84:82:0f:15:1a:18:4b:ac:f6:0c
- 8f:94:50:5b:36:34:28:26:dc:8d:a1:dd:d2:b8:93:b5
- 81:
-
-exp2:
- 5c:07:25:28:12:dd:d0:f3:4f:26:f7:bb:73:7c:50:2c
- 44:d4:66:38:b9:ab:18:8b:d5:47:db:10:48:e3:e8:9a
- 0f:2d:88:1d:37:88:4c:80:25:90:51:70:a0:9f:75:7d
- 4e:2d:31:f7:bc:df:6a:cd:86:fb:1f:3b:dd:65:5c:70
- 8c:b0:0d:c3:95:46:cf:9d:5c:87:12:d9:e3:ee:ce:e0
- 3d:1c:cd:95:13:b4:74:28:82:41:12:94:1c:73:fe:d6
- 2c:72:c5:c4:43:cd:b0:15:e8:57:92:bb:bf:9e:ac:3a
- 22:9b:6e:53:60:eb:2f:27:21:03:09:3c:4d:f9:64:41
-
-
-
-Public Key PIN:
- pin-sha256:wv5nADHzPA1LzmxBzNO9BTLNYGb9g0W8L55XearJ5C8=
-Public Key ID:
- sha256:c2fe670031f33c0d4bce6c41ccd3bd0532cd6066fd8345bc2f9e5779aac9e42f
- sha1:a9f05d6f61a0f001e874b25a7ed411431c2a89e7
-
------BEGIN PRIVATE KEY-----
-MIIE7gIBADA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAqEaMBgGCSqGSIb3
-DQEBCDALBglghkgBZQMEAgKiAwIBMASCBKgwggSkAgEAAoIBAQDubcDJRN2U+ECv
-mvRDPnhFYV9qFSNC9PigwutqCq4MQ6fc6azOQsTI9UzebFJL5dMrQrj55VxfXFMv
-D/f1PQTtK1DJq2t0LUtCcVd6BIM4l/pbIkoU0g3dXGbJJX3j/wWEAuo8gpdFD3yz
-cY5/MY216162DZGbXVG89+KBol9GNc+eZMQ8ZWP2/xWw5xFJ+sHM2VSb+BM9lc70
-f1hmI828Ea/hP6/YXhaFzX23f1n6/ynm709ua++wke+BY2+yDCtHpiH3H0v7Hedv
-+G8Oao+KVF9Lom02ILu6EYcG842VahC3J44dArTOHsIJc8S2Xcdf4ia9T816sMXA
-1oIf1C5ZAgMBAAECggEAas9yEPgvx5+a4tAo4sLmgDZJ1y0W+dTiWKpZaczVAZuB
-ZJ6uEkyo+VmikPW3vFZ9ziB620AbrICgpzGhJBSs006XR3Dql0X/NAmwZXIGEuFK
-f28R/tfG7EaLqUqJZg0FvIjNxEPAXmi8tWqGqoZZdIi3ihj0BMS+bEgkCWzi/4EY
-X6iF23mwFGYc+/ePqCl5g3mqZUUFWg8DMOV1QyMj4esJXea+ChC9NEoC1WD2UZAw
-tS2VNw6q+47zT7QvVKTBjKhaRgyF8NWU0O5xosbXsN6BBGZDTBC6uuyRV5O9dE/U
-6pY7U6EMD759cJzCrrITSyvDyYpWEqCrVeROkN8MAQKBgQD49XWKXvsPKglC3Ose
-DcmXbzDJVSivFU5K257NF2p/0b4eUyt52YPelsmbH36TzgLz+51WohnP8tDyO4Bf
-tXvL39Ym++i6K9vlwUeYHS5XXSYZci9IdwAdjXL2SGiXYg9dMOCVpAA05He5R4Ew
-Y0gpZKAvT8BCS7uiYHu65HlrgQKBgQD1LA16jBdZrJUgyik+RSMjbyX+o1bfI3RH
-zThHo00GDmZ6n3TMhj6G48hLRQmTK4HT/FaiKbNSTfFFaeLTo7FOGiW9GmwrV4qT
-EbnpbRFDLKoi6SAQv+T+psUw7EJaXNk9HekYfhBbnVnNf35RXMhlY4tKVOjB+lzp
-NiMgIIcO2QKBgQC6R4eccncuIIjvc7elNDHL0pHRg5u+bZW4Y14OHWA9paW4sQiN
-0thd27ucC1O9ql8BShqvMPlZZFk9dpIWiwfHQ4PMhZ7cdmbCIf287tC24+bXEV4Z
-vZjjg+wqJYHFC8VtOF5C+YSCDxUaGEus9gyPlFBbNjQoJtyNod3SuJO1gQKBgFwH
-JSgS3dDzTyb3u3N8UCxE1GY4uasYi9VH2xBI4+iaDy2IHTeITIAlkFFwoJ91fU4t
-Mfe832rNhvsfO91lXHCMsA3DlUbPnVyHEtnj7s7gPRzNlRO0dCiCQRKUHHP+1ixy
-xcRDzbAV6FeSu7+erDoim25TYOsvJyEDCTxN+WRBAoGBAJ+pN3bAJDOOGJLFTB4F
-/YI52UBNFZV+kllEGpmBSw8W4BaZI0WRBHbwmNf1kuSvOTtvSQuPIgKqOtpyBJyk
-yxEaRPRHGe2gnJRYBs3Ksf9If78uI2ZjDs0LpUPuI3Uy1ZMII1HjntKCvpvEbVOp
-UGZ0rxHd8tWmn27KEaxtpsoL
------END PRIVATE KEY-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa_pss_512.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa_pss_512.pem
deleted file mode 100644
index 1bd1bcfc95..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa_pss_512.pem
+++ /dev/null
@@ -1,138 +0,0 @@
-Public Key Info:
- Public Key Algorithm: RSA-PSS
- Hash Algorithm: SHA512
- Salt Length: 64
- Key Security Level: Medium (2048 bits)
-
-modulus:
- 00:ea:1f:fc:30:5f:ff:19:db:9a:30:46:1b:fa:34:de
- 6b:56:44:ff:a1:06:d1:5c:6a:a7:b9:f8:7d:ac:bc:0f
- 2b:9c:d8:9b:90:2d:31:a0:41:c7:74:73:01:ba:ea:e4
- c6:9e:bf:9b:41:62:07:54:b4:53:cb:a2:d7:8b:df:3a
- a4:6d:b6:95:71:32:21:ee:3c:9a:9d:9b:9b:4d:d5:ef
- d3:70:84:ba:c2:0e:a7:2f:07:aa:29:69:20:46:f8:da
- 87:49:e0:cf:00:d3:c0:26:a0:71:35:00:06:45:56:56
- 8f:93:60:75:42:f5:78:61:ee:ad:fb:d2:38:de:79:2d
- 9b:5b:07:e6:2b:be:b5:a8:a7:95:df:9f:2a:1a:9f:62
- 55:26:35:53:88:33:8c:1c:f9:93:e6:ea:45:39:3c:09
- 7a:e1:4a:41:de:a6:38:fd:56:e4:d5:0d:ee:ff:28:81
- dc:b0:ca:a9:84:42:5f:7a:68:72:32:1e:05:4f:07:36
- 58:71:76:a4:c8:b3:d2:18:3e:c8:3d:7b:2e:18:44:8c
- dc:df:b4:53:54:72:ee:78:11:68:94:92:f6:de:41:5b
- 1c:e8:dc:1b:41:fe:8f:b4:7d:8d:59:56:ed:07:96:20
- bd:0b:18:cb:3f:40:d3:02:62:7a:50:2e:52:66:68:ab
- a1:
-
-public exponent:
- 01:00:01:
-
-private exponent:
- 33:87:46:a1:fe:fe:ce:5a:1e:dd:71:10:c7:48:cb:8b
- 24:39:9b:69:7d:6e:a6:c0:72:99:e3:af:05:4d:7e:a9
- 42:a4:09:d8:f9:99:6a:84:0f:b9:f9:75:f0:05:b2:c4
- 64:3c:17:97:94:53:b8:b8:d7:98:82:06:9e:aa:4a:e5
- d5:9f:d1:d4:50:0c:57:ba:ce:ec:d1:4a:a5:1e:e8:e1
- c8:69:ee:10:b7:d8:e3:e8:f3:f2:99:48:99:56:3c:02
- 7a:a8:17:e7:3e:b3:93:cc:cc:1d:b6:1b:ab:37:0d:66
- 1c:31:a6:9d:4e:19:68:b4:77:66:6d:26:47:10:b4:90
- 88:f9:af:65:d3:16:07:f2:6b:59:6e:ba:03:20:ba:a5
- 80:87:75:ae:92:42:bd:64:e1:5a:48:7b:73:33:c3:70
- 74:cc:14:05:c0:d2:42:01:7f:82:4e:e0:8b:f9:2b:12
- 4d:71:4f:55:86:fd:28:0a:8f:a6:ad:66:32:4b:5e:f3
- 22:58:b1:09:51:1f:77:b5:d8:76:e9:80:ea:25:24:09
- 2d:70:ef:5d:89:20:7d:49:4b:52:c1:26:36:c4:c3:95
- 38:80:ef:6d:15:43:5e:dc:bd:5e:06:56:42:6a:59:00
- 13:e3:99:3f:b1:c0:a6:e3:d5:fc:72:38:d1:ea:0d:61
-
-
-prime1:
- 00:f1:54:7d:6d:25:84:c2:37:16:bc:18:04:8b:a2:5e
- 09:bd:cc:98:4c:44:ef:8a:9f:b4:6a:72:ac:cf:c8:2f
- b4:6b:a6:fd:e9:df:6e:98:42:6c:b4:95:b5:72:21:e0
- 21:e9:71:99:c6:8a:66:f5:06:96:35:9f:15:87:46:7a
- 66:cd:3d:ba:1e:96:28:35:ab:fd:07:fd:ab:11:31:50
- 93:a6:6c:67:5e:dd:b6:a9:87:f0:9c:c6:46:cb:7d:83
- 5e:58:c6:16:81:03:64:f5:c6:01:a6:e2:54:7c:be:93
- 65:02:66:89:86:e8:c8:56:bd:cb:d0:bc:7e:df:cb:9c
- f7:
-
-prime2:
- 00:f8:5b:5f:19:24:20:60:41:4c:86:07:70:c7:2a:7d
- dd:98:bc:f5:e8:ba:c3:7b:5b:2c:50:b3:fa:be:17:04
- 27:6e:75:3f:61:4f:3d:11:aa:f2:73:6a:f8:2f:da:59
- 65:b8:60:13:74:0e:d1:7e:01:07:d6:7e:fd:fb:f9:ca
- 4f:9c:e9:c5:49:62:a7:99:36:ed:0f:1e:86:cb:e6:d3
- 87:d0:2c:93:3e:d6:b5:59:a6:b4:f3:2d:38:85:dc:ca
- 5c:cd:e1:e9:3e:69:c4:04:25:5e:12:16:86:7f:30:3b
- 84:63:80:78:77:d4:45:dd:f7:f0:cc:d2:b5:7e:53:ce
- 27:
-
-coefficient:
- 54:6b:6a:51:c7:7e:e2:d9:0b:b8:7e:ea:c8:1b:1b:a8
- 97:06:67:87:da:6a:f7:b2:15:7c:ae:91:4a:46:4a:bd
- 79:3b:3a:d7:80:c6:95:2d:e7:92:97:76:cf:24:04:09
- e3:5c:11:68:77:0a:67:21:5a:82:57:80:d1:66:42:d5
- a7:03:1a:20:56:90:c2:e6:97:31:21:3e:a0:4f:41:43
- f8:07:41:92:48:39:ac:1c:8d:c1:a6:0d:be:5d:45:96
- 65:4b:b7:31:0c:c8:2d:f0:72:ca:ba:0e:f0:5a:7c:1a
- 7e:23:20:98:1e:c0:55:72:f2:18:b3:22:de:ec:47:21
-
-
-exp1:
- 00:90:e0:d8:2b:9e:4a:85:0d:ed:68:1e:43:1c:50:ed
- 83:8b:9e:38:10:11:92:7c:f6:43:a9:64:0e:ba:ee:c3
- 34:dd:2b:f3:63:63:ef:51:19:0f:89:9a:16:c3:dd:f2
- 60:69:74:f9:8c:67:aa:47:8f:1c:be:34:33:08:73:17
- 28:80:2e:7e:7d:be:47:85:71:2b:06:91:13:11:cf:39
- 40:6a:b8:c9:95:fa:24:9e:c2:2d:80:f0:c7:af:82:3a
- 4b:79:9f:f2:02:a1:b7:0a:95:44:88:9b:77:7d:2c:2b
- f0:87:f0:66:bf:c7:1f:fe:73:12:d8:cd:50:9d:a9:ef
- 21:
-
-exp2:
- 2f:9e:a5:6f:56:a3:f6:90:ce:b1:6c:3f:cd:90:72:2d
- c9:19:82:35:2b:8a:4b:de:c1:72:7f:ef:f5:fe:c7:c7
- 1f:c0:cf:74:43:13:3c:8e:00:8a:ec:d9:c5:a3:22:3d
- 04:cb:37:2f:ab:9f:b3:7f:53:17:67:a6:1f:68:57:c8
- 48:17:f2:c2:0d:6e:81:4c:2c:cc:17:58:55:44:5f:0e
- cd:75:9e:8e:0f:f1:19:cd:83:28:95:65:1f:15:a4:9f
- 82:c2:6c:4c:91:4f:0a:54:77:e3:13:fa:99:ec:8f:9c
- e4:cf:3f:4a:0a:a3:92:d9:f5:8b:f0:62:e8:63:fd:45
-
-
-
-Public Key PIN:
- pin-sha256:rS98yeSr3aoarf12o4jbIXeADc53+k2lu/+TB71kG0w=
-Public Key ID:
- sha256:ad2f7cc9e4abddaa1aadfd76a388db2177800dce77fa4da5bbff9307bd641b4c
- sha1:a558e1b80dd69fbc34e5e83dd8fa0ca583b1c045
-
------BEGIN PRIVATE KEY-----
-MIIE7QIBADA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCA6EaMBgGCSqGSIb3
-DQEBCDALBglghkgBZQMEAgOiAwIBQASCBKcwggSjAgEAAoIBAQDqH/wwX/8Z25ow
-Rhv6NN5rVkT/oQbRXGqnufh9rLwPK5zYm5AtMaBBx3RzAbrq5Maev5tBYgdUtFPL
-oteL3zqkbbaVcTIh7jyanZubTdXv03CEusIOpy8HqilpIEb42odJ4M8A08AmoHE1
-AAZFVlaPk2B1QvV4Ye6t+9I43nktm1sH5iu+tainld+fKhqfYlUmNVOIM4wc+ZPm
-6kU5PAl64UpB3qY4/Vbk1Q3u/yiB3LDKqYRCX3pocjIeBU8HNlhxdqTIs9IYPsg9
-ey4YRIzc37RTVHLueBFolJL23kFbHOjcG0H+j7R9jVlW7QeWIL0LGMs/QNMCYnpQ
-LlJmaKuhAgMBAAECggEAM4dGof7+zloe3XEQx0jLiyQ5m2l9bqbAcpnjrwVNfqlC
-pAnY+ZlqhA+5+XXwBbLEZDwXl5RTuLjXmIIGnqpK5dWf0dRQDFe6zuzRSqUe6OHI
-ae4Qt9jj6PPymUiZVjwCeqgX5z6zk8zMHbYbqzcNZhwxpp1OGWi0d2ZtJkcQtJCI
-+a9l0xYH8mtZbroDILqlgId1rpJCvWThWkh7czPDcHTMFAXA0kIBf4JO4Iv5KxJN
-cU9Vhv0oCo+mrWYyS17zIlixCVEfd7XYdumA6iUkCS1w712JIH1JS1LBJjbEw5U4
-gO9tFUNe3L1eBlZCalkAE+OZP7HApuPV/HI40eoNYQKBgQDxVH1tJYTCNxa8GASL
-ol4JvcyYTETvip+0anKsz8gvtGum/enfbphCbLSVtXIh4CHpcZnGimb1BpY1nxWH
-RnpmzT26HpYoNav9B/2rETFQk6ZsZ17dtqmH8JzGRst9g15YxhaBA2T1xgGm4lR8
-vpNlAmaJhujIVr3L0Lx+38uc9wKBgQD4W18ZJCBgQUyGB3DHKn3dmLz16LrDe1ss
-ULP6vhcEJ251P2FPPRGq8nNq+C/aWWW4YBN0DtF+AQfWfv37+cpPnOnFSWKnmTbt
-Dx6Gy+bTh9Askz7WtVmmtPMtOIXcylzN4ek+acQEJV4SFoZ/MDuEY4B4d9RF3ffw
-zNK1flPOJwKBgQCQ4NgrnkqFDe1oHkMcUO2Di544EBGSfPZDqWQOuu7DNN0r82Nj
-71EZD4maFsPd8mBpdPmMZ6pHjxy+NDMIcxcogC5+fb5HhXErBpETEc85QGq4yZX6
-JJ7CLYDwx6+COkt5n/ICobcKlUSIm3d9LCvwh/Bmv8cf/nMS2M1QnanvIQKBgC+e
-pW9Wo/aQzrFsP82Qci3JGYI1K4pL3sFyf+/1/sfHH8DPdEMTPI4AiuzZxaMiPQTL
-Ny+rn7N/Uxdnph9oV8hIF/LCDW6BTCzMF1hVRF8OzXWejg/xGc2DKJVlHxWkn4LC
-bEyRTwpUd+MT+pnsj5zkzz9KCqOS2fWL8GLoY/1FAoGAVGtqUcd+4tkLuH7qyBsb
-qJcGZ4faaveyFXyukUpGSr15OzrXgMaVLeeSl3bPJAQJ41wRaHcKZyFagleA0WZC
-1acDGiBWkMLmlzEhPqBPQUP4B0GSSDmsHI3Bpg2+XUWWZUu3MQzILfByyroO8Fp8
-Gn4jIJgewFVy8hizIt7sRyE=
------END PRIVATE KEY-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa.pem
deleted file mode 100644
index ffda4f2e40..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa.pem
+++ /dev/null
@@ -1,19 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDDzCCAfegAwIBAgIMWYGU7zoymvg+Z63iMA0GCSqGSIb3DQEBCwUAMCMxITAf
-BgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0xNzA4MDIwOTAxMzVa
-Fw0zNzA3MjkwOTAxMzVaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVz
-dCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOMuUmmLJ2pQ4fYj
-EfuIj11TMnG8dqScapc/yU9zHCDn5DQJGOa/X5jYoJX4k2PbXk5bbck2caC4J7/G
-WRugGc4KcOVItAmnxbVzJqtpsdRrVUvTzqcvaSZNHEgSWP73WmlACX6xIHRyBtr+
-Pwpig73eZkOVcGOsbsWliffVQ0f0fz/AGsYh5IWBNlIfBOWwOEBDJavlsYrVGAw1
-MuXxknybsjXFRqyFNPE6Shd3W3eteo+FOvQsyopmX6FcP+EOaFQxSQ7yR+xNsreC
-yxi40hPfswO6TihN9hLdVt3C+OHDJw2wR2xM+SwsW8Hu4jEi21uakQl846z+XdgV
-o+D3v3cCAwEAAaNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNVHQ8BAf8EBQMDBwQA
-MB0GA1UdDgQWBBQrQlWadXqqzBV+2iw7BZXrvFHaQjANBgkqhkiG9w0BAQsFAAOC
-AQEArUVXn2oI5hgSkDwDrhQFijHBT3d37SX0eji//lkLPTHSEXHv+6kAoxVKmSnG
-hAAxuLKxtAjNlXi4FAxSpQPX17/199JHUd/Ue63Tetc8DfaFc6MaFNxWkNrY6LUX
-bEhbI/vB1kBu7sc8SW7N694WSpe/OmD/lB6GYW6ZV68hrTB0gfmfB6SfcGbQ69ss
-YUsNU7Yo1GZnJTz0FZzybjx/T85NnVvpfVqjjaGRFeSva9GAU+5uO5DdbSpbkCcw
-6QFFfvcJ7VD6qFqtLG1TfcdOuCaUB8cmDhDtTB/Ax96wGdJvp6ca3YaboZag9HOZ
-4csuzHIJQyd5HT6xLbUBeskgWw==
------END CERTIFICATE-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa_pss_256.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa_pss_256.pem
deleted file mode 100644
index 0e5966a77c..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa_pss_256.pem
+++ /dev/null
@@ -1,22 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDpzCCAl+gAwIBAgIUIyISxx5PRQREJEmN08CNp74twmcwPQYJKoZIhvcNAQEK
-MDCgDTALBglghkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMC
-ASAwIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxlIFRMUyBUZXN0IENBMB4XDTE4MTAy
-NDA2MDY0MloXDTM4MTAyMDA2MDY0MlowIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxl
-IFRMUyBUZXN0IENBMIIBUjA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAaEa
-MBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgGiAwIBIAOCAQ8AMIIBCgKCAQEAt7Sa
-TS0/CLgeVdawsrfQM8y73lYkBB1zrGoy268mT++x1hCQedyJrGDjlFQZBFQX6hgO
-2Ua+YJ/mM/9uYGo1xi3dBoLVgMmIBy8nSwQTuktpks68AL5CLOI1jWARZjwk+DoT
-rUnnEsrGKlKE7T19HgbepGTWFxSxGWOg4XxJ00FzKfi1deCT+uPfO4J3XoPL2lIm
-68MgExFt6aql17bDoaUE+m7uTzlSTRj5q4dKTtk0p8Tf9Ru2V3F/w8hPLADAbuh0
-NeJxH+/GwWJ6ZefJx0IUXxbBq00y5eJ8OKIhAmmjgfTIeEhYCl2ZhfXmKje+I+X/
-Fbo5Qqyd0BF+5CtV2wIDAQABo0MwQTAPBgNVHRMBAf8EBTADAQH/MA8GA1UdDwEB
-/wQFAwMHBAAwHQYDVR0OBBYEFCEaiLbeA8ABgKrbcIiZpo8XzqpsMD0GCSqGSIb3
-DQEBCjAwoA0wCwYJYIZIAWUDBAIBoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFlAwQC
-AaIDAgEgA4IBAQCpl2XsRpIAR5cD0YRWOg2hNg1+oMNAj1wtuBOiaD84doN07sFl
-ta3lnweoA1rZZNLtAOUu5Fs7FwetzhuA5+iHVRAU8qqoSojP5fZgTriOFK/7rEUu
-ZTxL1IzXEuiQO2iCkTXslg5HP5QAsYV4iqGe6erSAgzD5tP2mpgQJudUiuvCdWGz
-lgroWjDAklQHIXITCrLgnMieYIbILZXXMZLfIrMfZOPCd7IDPTjb8/k1j3N4Wuld
-qZWSPeNhuUUTKniXy4GVBE1obMDyBRarR4jkeeKdsuYbdf0oSTMK/rcuZMrZfjAR
-uH3sqZ1Ovw4rbYzjk/ET4QlolFnFexgZ5QcH
------END CERTIFICATE-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa_pss_384.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa_pss_384.pem
deleted file mode 100644
index 5e8bb89007..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa_pss_384.pem
+++ /dev/null
@@ -1,22 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDpzCCAl+gAwIBAgIUWplyXkxgG/630tCmc0xgpFKshNYwPQYJKoZIhvcNAQEK
-MDCgDTALBglghkgBZQMEAgKhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAICogMC
-ATAwIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxlIFRMUyBUZXN0IENBMB4XDTE4MTAy
-NDA2MDY0MloXDTM4MTAyMDA2MDY0MlowIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxl
-IFRMUyBUZXN0IENBMIIBUjA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAqEa
-MBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgKiAwIBMAOCAQ8AMIIBCgKCAQEA7m3A
-yUTdlPhAr5r0Qz54RWFfahUjQvT4oMLragquDEOn3OmszkLEyPVM3mxSS+XTK0K4
-+eVcX1xTLw/39T0E7StQyatrdC1LQnFXegSDOJf6WyJKFNIN3VxmySV94/8FhALq
-PIKXRQ98s3GOfzGNtetetg2Rm11RvPfigaJfRjXPnmTEPGVj9v8VsOcRSfrBzNlU
-m/gTPZXO9H9YZiPNvBGv4T+v2F4Whc19t39Z+v8p5u9PbmvvsJHvgWNvsgwrR6Yh
-9x9L+x3nb/hvDmqPilRfS6JtNiC7uhGHBvONlWoQtyeOHQK0zh7CCXPEtl3HX+Im
-vU/NerDFwNaCH9QuWQIDAQABo0MwQTAPBgNVHRMBAf8EBTADAQH/MA8GA1UdDwEB
-/wQFAwMHBAAwHQYDVR0OBBYEFKnwXW9hoPAB6HSyWn7UEUMcKonnMD0GCSqGSIb3
-DQEBCjAwoA0wCwYJYIZIAWUDBAICoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFlAwQC
-AqIDAgEwA4IBAQAwyVTh4HCTN1FnLLY3iUSEWHNqYNCdAmP/qMYDgwZAdS3hRHEt
-9mE0a0/52bYEY9QMol4eGIGKjiXuxZpJKjK2WBgnUvyV7fEDcKy8UqB+ULFGNRxR
-9tR3MRMSFrQl+W6q2ABPwmqvAtJHSiIRA30ZuwxSyX4ulzxThRYnkfp2eSKKHp2x
-J6xUEnN5vnoXvpa1sFccKorPITF0r8OWzIi+GGzHz4Wq0Fqov4TOhnU/u6Xqw0xX
-CXshQ0pN6+XWT0Ea0OuZk1/cKy2nyk+oHSmo/HhKJ8lGc3P2dLgCV9jjbM2WYCHs
-O2rKlDWMxkd1Zx/I0ZzUI3Km+Qb8a+88KOtg
------END CERTIFICATE-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa_pss_512.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa_pss_512.pem
deleted file mode 100644
index 690d25654a..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa_pss_512.pem
+++ /dev/null
@@ -1,22 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDpzCCAl+gAwIBAgIUJ6gfVYLgx1UAxuxNNmuo6mUQP/gwPQYJKoZIhvcNAQEK
-MDCgDTALBglghkgBZQMEAgOhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIDogMC
-AUAwIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxlIFRMUyBUZXN0IENBMB4XDTE4MTAy
-NDA2MDY0M1oXDTM4MTAyMDA2MDY0M1owIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxl
-IFRMUyBUZXN0IENBMIIBUjA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCA6Ea
-MBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgOiAwIBQAOCAQ8AMIIBCgKCAQEA6h/8
-MF//GduaMEYb+jTea1ZE/6EG0Vxqp7n4fay8Dyuc2JuQLTGgQcd0cwG66uTGnr+b
-QWIHVLRTy6LXi986pG22lXEyIe48mp2bm03V79NwhLrCDqcvB6opaSBG+NqHSeDP
-ANPAJqBxNQAGRVZWj5NgdUL1eGHurfvSON55LZtbB+YrvrWop5Xfnyoan2JVJjVT
-iDOMHPmT5upFOTwJeuFKQd6mOP1W5NUN7v8ogdywyqmEQl96aHIyHgVPBzZYcXak
-yLPSGD7IPXsuGESM3N+0U1Ry7ngRaJSS9t5BWxzo3BtB/o+0fY1ZVu0HliC9CxjL
-P0DTAmJ6UC5SZmiroQIDAQABo0MwQTAPBgNVHRMBAf8EBTADAQH/MA8GA1UdDwEB
-/wQFAwMHBAAwHQYDVR0OBBYEFKVY4bgN1p+8NOXoPdj6DKWDscBFMD0GCSqGSIb3
-DQEBCjAwoA0wCwYJYIZIAWUDBAIDoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFlAwQC
-A6IDAgFAA4IBAQAIi+3zyTk8NR5w5a109GHz4wpACxafirJkr6wkAIzzU95OKLiw
-fogX/ECW9UaIfJMHrnEADhKcMSRd7HcNpDg/E8GKr4IhtbkFhNjAjE10Ham6fLzw
-SgvN34QpDT6iVP83Cx+SzlSDQLjq4es8diZXP39C0T2a9iskDXMF+ZcaZMwd1TLe
-MI7HMIiLCoyVP7LOI39e6E0ho0W0FRrMtZuXIIvZjwkb+SGhAmlJiATmpLmtzuoK
-oI/UE1gNglJFjA6HWHStHd7hEJrtGHNa061G130kOFGIJhGf8fHiGaWvWYfZ5/jc
-egUo5t7rA6wg6KPwA2JjH2jxUp3NUzTRzV72
------END CERTIFICATE-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-dsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-dsa.pem
deleted file mode 100644
index 782fe4ef98..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-dsa.pem
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIEpzCCBE2gAwIBAgIMWYGU8Awsp0jsH7C+MAsGCWCGSAFlAwQDAjAjMSEwHwYD
-VQQDExhCb3VuY3lDYXN0bGUgVExTIFRlc3QgQ0EwHhcNMTcwODAyMDkwMTM2WhcN
-MzcwNzI4MDkwMTM2WjAjMSEwHwYDVQQDExhCb3VuY3lDYXN0bGUgVGVzdCBDbGll
-bnQwggNHMIICOQYHKoZIzjgEATCCAiwCggEBANIzNyBmt0q+w79byPcXWN5ETG80
-4OJFYhOAdUl5gv90ACofvnojmLaOu2AnbwEUVMlV5xBdeuanPl0ESmH+yFoDwwwA
-3uNhPutZ91Yml5PPpks48Fj8IV8Mnnp+0LGC1Ug9IgeXkPSrGm1aIJjMNvK3xc7q
-MGI8aeL//pFSoH4vNvRqi+QzZBW/FaXeWdRvkT0c1YACvdl0rnF3SPbi7bn45ceG
-GEenq6dFjbZZG1e+bZyzd8/UGO01BLZxftG0IiWWqKi1BlP1Lgc8LyUIrza+Ie1a
-vLk0jbjuhhQsYebpvnO84uhDOdavpxnHCqcEm8sElRctIFYY1xB3PD3bG8ECIQCI
-pXijcj1zNsncR7roSHNeer5B3c1N92F2hTLedYbzwQKCAQB7PCrFF3u7oJq/64EL
-8EMlnv81vgWnet/Ux5zzY2OEdtDOOR4YnrWXcs/rsjio/blHTf/CeMX3pTVV8GE3
-f0C4+Hx6mWb+okL7UgEPmen8dGHD//yn3e6wYBG7aqd8DtBkicmgd9eKlY+xgbww
-rDN8dz9RbJ9oAOXbzASw1GvLbZ6UWsMTZ7WWoAbLOf+0gfiA+eRjC9x0HbaN0jLy
-ztQJhEvWqGSynNfkB2xopRtoyYCvtEVDtQEC9H6PtIG9oKyiwLAtVOmbj6pf1/V3
-ZJJEPiFfKD8CHcS8Z87JXMbjTolIf1A+/Bjn+FKOS2zdIQ+rAOFdptUyU68CWkAV
-6trbA4IBBgACggEBAKprryuOBKnrY00s9y+HM6UMvS/exCjzmQrlQ9rQMuwVG+lz
-GKKWFu7shIQqneaNNUuNAXRK0NABkPjIBLfvdDmkXweU4/oi2mZQaIUPEWceHrmL
-FliI3+VtqC3rPvXzVGvbBdUvqSCJrYD84EK6Ahs3LGIB0OC1Wldi6x8FtKewbn7B
-23twnAsvNx4QzFt7W6j05EorWCvs+cwbTttptRiruNcPYLQweMIrcNvzApq+sgoW
-traZdTS7rBklrgfi7/4JJNN+jV21XqDQYGugN8PnbORyuETGHEf1wk4HFL7eweHO
-4KzTpaNeqsJfilOe9PV1SgDhv9oyKj6957xK1WSjdjB0MAwGA1UdEwEB/wQCMAAw
-EwYDVR0lBAwwCgYIKwYBBQUHAwIwDwYDVR0PAQH/BAUDAweAADAdBgNVHQ4EFgQU
-iU8ApXTLLe07mPDvg7O9CsNwS0EwHwYDVR0jBBgwFoAUAOVmarDrz1YtyjvnX4C9
-cDcXlagwCwYJYIZIAWUDBAMCA0cAMEQCIGlXUYEccybo2azMk3f6Zl6bpxERr/FU
-+/2k+mbBeo7TAiA9/aIWf0bdED8AH0KNKFfcpKMsvnJHTCOPr7fBPU84lQ==
------END CERTIFICATE-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ecdh.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ecdh.pem
deleted file mode 100644
index a3b1b346b9..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ecdh.pem
+++ /dev/null
@@ -1,12 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIBtTCCAVygAwIBAgIMWYGU7ztLkMAhmmRDMAoGCCqGSM49BAMCMCMxITAfBgNV
-BAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0xNzA4MDIwOTAxMzVaFw0z
-NzA3MjgwOTAxMzVaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUZXN0IENsaWVu
-dDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLRekMsBjYf7GXhy7ZqnX9lAvXyL
-sC9VfMUIcfGNluSN2C3O9fjqN5FMary/eU49ij6L2mRUjZz6kQK0ZM68pL6jdjB0
-MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDwYDVR0PAQH/BAUD
-AweIADAdBgNVHQ4EFgQU7ZRZoI8czdH0szeb+t3EwaXNUG8wHwYDVR0jBBgwFoAU
-0ma/FGcW5gGlL//B26Xmj0JISecwCgYIKoZIzj0EAwIDRwAwRAIgVij5xSPQrUgo
-VsbOgVdLGLJeiHo065dtdt87PSCJtusCID+c1QShYOgBkI/Bv3gotVhTP4mtjhp2
-2v442jTclSfT
------END CERTIFICATE-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ecdsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ecdsa.pem
deleted file mode 100644
index 261db1ce00..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ecdsa.pem
+++ /dev/null
@@ -1,12 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIBtTCCAVygAwIBAgIMWYGU8A09KQDW+svJMAoGCCqGSM49BAMCMCMxITAfBgNV
-BAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0xNzA4MDIwOTAxMzZaFw0z
-NzA3MjgwOTAxMzZaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUZXN0IENsaWVu
-dDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLenUtWqfkGp0iFncfdsvBsfaXHv
-Ne5gV7U/zUO0OQ71V1c8WpOx9f0rhpOSCN9GCqQNL3yd+nWf+pu40JMMrZKjdjB0
-MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDwYDVR0PAQH/BAUD
-AweAADAdBgNVHQ4EFgQUtK5VEuBZJUDbU8gN9dleZeXDf2swHwYDVR0jBBgwFoAU
-0ma/FGcW5gGlL//B26Xmj0JISecwCgYIKoZIzj0EAwIDRwAwRAIgNnj/nlAbCd0R
-fCG6n5s5Sdsh4dR7KRhncCj8wjGYZMYCICUXU05FIr3bM9bELX2We3rv1ookK9rC
-7ZVjCgt7YbHi
------END CERTIFICATE-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ed25519.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ed25519.pem
deleted file mode 100644
index e419a7b32a..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ed25519.pem
+++ /dev/null
@@ -1,11 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIBfjCCATCgAwIBAgIUO1XUdvEupfCQwrrPHXE28BoO+TswBQYDK2VwMCMxITAf
-BgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0xODA4MjMwOTI5NDda
-Fw0zODA4MTgwOTI5NDdaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUZXN0IENs
-aWVudDAqMAUGAytlcAMhAJe53GEkXEVP7L7FbVZ1BCGvvIZac+6k41CncucJ3BJ2
-o3YwdDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMCMA8GA1UdDwEB
-/wQFAwMHgAAwHQYDVR0OBBYEFNo2OYJ4FLTBdu5lozbqL2aAXsqzMB8GA1UdIwQY
-MBaAFOp5vj76ByEwboduoHWAWzajnM1mMAUGAytlcANBAJrgAof3yetck8DDLNTG
-dwLQdCNjEg5/xgvKVcTPuUC4rirgCoYtPY36lfPhd0v5Ev8v1Jjrxshyi/yVCsLb
-mQ8=
------END CERTIFICATE-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ed448.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ed448.pem
deleted file mode 100644
index e7442fce53..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ed448.pem
+++ /dev/null
@@ -1,12 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIByTCCAUmgAwIBAgIUbl3fESW+2UIW9SzaxnhuhiGygLIwBQYDK2VxMCMxITAf
-BgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0yMDAyMTMwNzMzMDJa
-Fw00MDAyMDgwNzMzMDJaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUZXN0IENs
-aWVudDBDMAUGAytlcQM6AFbp8qV7nVhmDWZUsXTfqU8aOaP4XSmGUnKqdlQPR5O4
-3lMlUukbrclV5v5+b4Z8Qy4Abe+PZU+AgKN2MHQwDAYDVR0TAQH/BAIwADATBgNV
-HSUEDDAKBggrBgEFBQcDAjAPBgNVHQ8BAf8EBQMDB4AAMB0GA1UdDgQWBBSlCh5L
-f6BeaHQxiEe5B9ZjbbCKODAfBgNVHSMEGDAWgBS+BSv++BEWlTJ53q6rwnDLVnR5
-JTAFBgMrZXEDcwAC3Tugpa+pS0ExsLdh/6GsVAVvhYICLc+tWGExM+f3gzFU7yvO
-uM7xwRR78ItbQyRkfLeL+6GYGgDzhjwQ6XzilwGibLtGuooLAMo3uOgW8N4mQslf
-GqEW2V3VocPjmNYanAMJnTd68t5Wc0ow153cNgA=
------END CERTIFICATE-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-dsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-dsa.pem
deleted file mode 100644
index fd1a45b906..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-dsa.pem
+++ /dev/null
@@ -1,15 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIICZAIBADCCAjkGByqGSM44BAEwggIsAoIBAQDSMzcgZrdKvsO/W8j3F1jeRExv
-NODiRWITgHVJeYL/dAAqH756I5i2jrtgJ28BFFTJVecQXXrmpz5dBEph/shaA8MM
-AN7jYT7rWfdWJpeTz6ZLOPBY/CFfDJ56ftCxgtVIPSIHl5D0qxptWiCYzDbyt8XO
-6jBiPGni//6RUqB+Lzb0aovkM2QVvxWl3lnUb5E9HNWAAr3ZdK5xd0j24u25+OXH
-hhhHp6unRY22WRtXvm2cs3fP1BjtNQS2cX7RtCIllqiotQZT9S4HPC8lCK82viHt
-Wry5NI247oYULGHm6b5zvOLoQznWr6cZxwqnBJvLBJUXLSBWGNcQdzw92xvBAiEA
-iKV4o3I9czbJ3Ee66EhzXnq+Qd3NTfdhdoUy3nWG88ECggEAezwqxRd7u6Cav+uB
-C/BDJZ7/Nb4Fp3rf1Mec82NjhHbQzjkeGJ61l3LP67I4qP25R03/wnjF96U1VfBh
-N39AuPh8eplm/qJC+1IBD5np/HRhw//8p93usGARu2qnfA7QZInJoHfXipWPsYG8
-MKwzfHc/UWyfaADl28wEsNRry22elFrDE2e1lqAGyzn/tIH4gPnkYwvcdB22jdIy
-8s7UCYRL1qhkspzX5AdsaKUbaMmAr7RFQ7UBAvR+j7SBvaCsosCwLVTpm4+qX9f1
-d2SSRD4hXyg/Ah3EvGfOyVzG406JSH9QPvwY5/hSjkts3SEPqwDhXabVMlOvAlpA
-Fera2wQiAiAFTXpu+duj6u8P3wMsd7fOOStBEV6hPUh+RLdOjGslXw==
------END PRIVATE KEY-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ecdh.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ecdh.pem
deleted file mode 100644
index 2a28a9f102..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ecdh.pem
+++ /dev/null
@@ -1,6 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgAuAT+3hSra1qS+XA
-iAUT+W6MSZ2rnoeQGjFe6FX7z8qgCgYIKoZIzj0DAQehRANCAAS0XpDLAY2H+xl4
-cu2ap1/ZQL18i7AvVXzFCHHxjZbkjdgtzvX46jeRTGq8v3lOPYo+i9pkVI2c+pEC
-tGTOvKS+
------END PRIVATE KEY-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ecdsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ecdsa.pem
deleted file mode 100644
index d9aceb301e..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ecdsa.pem
+++ /dev/null
@@ -1,6 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIGUAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHoweAIBAQQhAJxpy2FD0ePz3c9j
-6fVPTSpHAmdiRIqnskVP0PjiBAEvoAoGCCqGSM49AwEHoUQDQgAEt6dS1ap+QanS
-IWdx92y8Gx9pce817mBXtT/NQ7Q5DvVXVzxak7H1/SuGk5II30YKpA0vfJ36dZ/6
-m7jQkwytkg==
------END PRIVATE KEY-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ed25519.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ed25519.pem
deleted file mode 100644
index a08f3c44a8..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ed25519.pem
+++ /dev/null
@@ -1,25 +0,0 @@
-Public Key Info:
- Public Key Algorithm: EdDSA (Ed25519)
- Key Security Level: High (256 bits)
-
-curve: Ed25519
-private key:
- b6:9d:94:c8:9d:c9:7a:5d:b3:58:92:af:67:8e:c2:bd
- 63:c1:81:55:3d:b2:5c:e0:c8:91:f1:40:34:5a:6d:b9
-
-
-x:
- 97:b9:dc:61:24:5c:45:4f:ec:be:c5:6d:56:75:04:21
- af:bc:86:5a:73:ee:a4:e3:50:a7:72:e7:09:dc:12:76
-
-
-
-Public Key PIN:
- pin-sha256:aWaJiTGI21SUAEt2VgTiRGAnczFMD8axA/4hrKMpfno=
-Public Key ID:
- sha256:696689893188db5494004b765604e244602773314c0fc6b103fe21aca3297e7a
- sha1:da3639827814b4c176ee65a336ea2f66805ecab3
-
------BEGIN PRIVATE KEY-----
-MC4CAQAwBQYDK2VwBCIEILadlMidyXpds1iSr2eOwr1jwYFVPbJc4MiR8UA0Wm25
------END PRIVATE KEY-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ed448.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ed448.pem
deleted file mode 100644
index be3c8638b2..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ed448.pem
+++ /dev/null
@@ -1,28 +0,0 @@
-Public Key Info:
- Public Key Algorithm: EdDSA (Ed448)
- Key Security Level: Ultra (456 bits)
-
-curve: Ed448
-private key:
- b1:9c:73:a3:54:a0:33:05:b1:b0:ad:6f:1f:c0:ad:14
- db:d4:55:bb:eb:fa:d4:33:8c:e5:bc:68:03:d1:ca:25
- 19:75:0f:94:4f:e3:fd:3a:62:b5:77:23:d7:b0:d6:75
- 92:9c:98:86:2a:08:c5:b2:6e:
-
-x:
- 56:e9:f2:a5:7b:9d:58:66:0d:66:54:b1:74:df:a9:4f
- 1a:39:a3:f8:5d:29:86:52:72:aa:76:54:0f:47:93:b8
- de:53:25:52:e9:1b:ad:c9:55:e6:fe:7e:6f:86:7c:43
- 2e:00:6d:ef:8f:65:4f:80:80:
-
-
-Public Key PIN:
- pin-sha256:4r2UflhSms9yYj4SMc7tE9lkFxXR/ziPw1bhZGfI/qw=
-Public Key ID:
- sha256:e2bd947e58529acf72623e1231ceed13d9641715d1ff388fc356e16467c8feac
- sha1:a50a1e4b7fa05e6874318847b907d6636db08a38
-
------BEGIN PRIVATE KEY-----
-MEcCAQAwBQYDK2VxBDsEObGcc6NUoDMFsbCtbx/ArRTb1FW76/rUM4zlvGgD0col
-GXUPlE/j/TpitXcj17DWdZKcmIYqCMWybg==
------END PRIVATE KEY-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa.pem
deleted file mode 100644
index d2d19bf0eb..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa.pem
+++ /dev/null
@@ -1,28 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDP8Yo5l5ez1W2c
-EgROodwNqRLL+ALvOorSEuKm+xiTbzmdqcMdtvwDhq/yb7GBhpzrFcUOt5hPcQc9
-pYz7Khg4UHiw+wqbV2QHMGGupNs+kvdUndBgjToD7hYlyhV7fUovNrjQeNq+5Bxt
-OHsZmO7ilHTKdSMVG2eO5XgZk+1uSOuZStmnMZM0Sum3TxK5zRs2beLf5OhNDqMH
-+hJVH9FL4bF9LaxQfTvMrwnIqgEKBlMO29cs1gPW1otQEFD4MefHhjK0YEF3xZ7r
-hnnx6lPv5wFQLeaRx1NBqgdPY3L9ZSUkKQzLQgWubbKK1b8vDookicdebSMjTrVX
-HPcv6B93AgMBAAECggEAQZZe0cGFwNwdoW9xWlflL43Xduw4CLq/VHlOcfqbCs23
-L4p/F11C6d3Omzotk7wgvGl2aSjxaoUtEn2oFQR29TQ0jSXxd4O98iKJfOtUl80F
-I/RO6FVDKkArTioKUpP3FSM+ccrcu/75FF4PPcil+GN43u7JbPvi0wh/tBmbdwAJ
-aK2wskjaJAbQz8lnIEVZkz3uYLc32BD2FoCC+HyIPAYFbryus1m+TsXWVk3rDKst
-85x4jadS7g3a1OvsDXqj8lHlom9dlxcMqTtSaJr1XJgMwztnc0FVuMOqs0MZpa2U
-Mu/0EJQYLW98a1bDkXbLtbXjx2gWpO64gZqQn6aYAQKBgQDfgA2xVv7nmVuOkojJ
-rJTS4muPG1BhXY7/MD13eopmjPk8rpVZt97RHfMHp3CCzuQVy9g398kBvCBtO9Ba
-3/ab9ZrNMN3Rwm7vwUa4TBOvN17bRSeIPUenJJ42SDM2fmN4m8c91iiSyb9AVPmk
-zSksQYtZr/8m9mQ0VOguzOxcAQKBgQDuLmDFSYDl4DO4cOZANpDYk1MkCtrW37xM
-IUS6vnPFkRg3t57Og9tddj81VoMNeakGRvWmcDA1yuVdo52pqjlSXzQuSYAh7ZTC
-KMzesLt1uilXQW2MNNvmZMjltgkHMiuY1cIvQLFC0o4AI5DLR5+5/w/lm/Qe9pfU
-++B3XVVbdwKBgF5Yfu86ixYW/bg8kTOY/6XZ4I+jdxXy2ZdNtNTHzL6nidqc0/zw
-ikV6QAoeG3eMgGnXB+nwVlC+Km4SDs0dt8t0LSmrFCgkzJG24/SOYMzZMdib46k2
-PRYIdiTx63R4e+MA12V6DtyP/4TXmh6AYH4HGRz+F1ZKMliI8w42gRwBAoGAN9sG
-dJ21LbNzTZikVoC1XSTHhZdKFMPpO409ufF54uYQ4Ngd1N5VLkjRr+d22k0il0dC
-ymJa2/KV8WyyR5yUzr1m1kgEVXCKxzGcQcj+XTBoC39belrXCuOtvTkASwC3+qJ+
-ZGhuaXZJOL0ecp18Vrj6+GSnTi+UEa1zyWpI3ycCgYAxJgHa3CGaGqbdzgkRTnWd
-FMptvqaNd4POyy/TJ1Jf0ydZwgRpRMZTv8hJKZHh4lUkSOF6bE0qDhrxzUjpI9GT
-SGYYX27pfVThoM421S7bvgVmneeLSz1S50Hg0jawHA2ixjne/7kQcMjQzYjjMfDy
-FgVOrBIQnpUddGEpu1z5pw==
------END PRIVATE KEY-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa_pss_256.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa_pss_256.pem
deleted file mode 100644
index 86f66f7d25..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa_pss_256.pem
+++ /dev/null
@@ -1,138 +0,0 @@
-Public Key Info:
- Public Key Algorithm: RSA-PSS
- Hash Algorithm: SHA256
- Salt Length: 32
- Key Security Level: Medium (2048 bits)
-
-modulus:
- 00:d7:7a:3a:01:8b:5e:59:0f:10:7d:95:5c:ce:c6:ea
- c8:29:2e:75:6e:fe:6c:f9:83:d5:3e:72:6c:fc:56:95
- 43:d4:62:34:df:05:7c:b3:b3:a6:4a:37:ca:b6:e0:23
- 44:19:fc:2c:ea:cf:fc:f9:26:1a:ac:5a:8d:83:f8:4f
- d9:0b:ae:fc:e9:9d:75:37:2d:a4:93:02:5d:69:10:df
- b7:7a:4c:b6:05:64:73:46:45:b2:fe:a4:b3:33:9e:68
- 6b:14:35:8e:ee:df:bb:e0:77:23:76:b8:6e:fd:fc:f2
- dd:02:59:5e:dc:a1:b3:5d:93:c6:2c:e2:4a:85:21:7f
- ca:59:36:e8:77:dd:fe:cd:fe:f6:b0:96:fe:14:6a:5c
- 68:4c:cf:bc:fd:fe:ec:e3:2f:51:10:cf:46:db:1d:3a
- 3d:cd:87:ec:67:4a:7d:20:5e:79:6c:ea:d3:24:d3:82
- 05:bc:d9:79:e5:cd:df:6a:bb:62:9b:20:b3:35:34:61
- ae:69:a9:ab:b9:b6:27:ac:7b:33:f5:be:df:9a:b4:12
- 68:06:55:79:b3:ba:52:f0:91:90:69:b1:f1:5a:11:e3
- 8b:de:dd:f1:99:ca:5a:ad:87:ba:65:52:27:a6:07:12
- 60:10:24:93:4b:df:12:db:49:0f:fc:21:ff:9f:e6:92
- 75:
-
-public exponent:
- 01:00:01:
-
-private exponent:
- 3f:9d:f9:84:3d:36:84:ca:ba:ce:a9:0b:76:8d:2a:02
- 20:8e:73:e3:6a:40:98:46:40:ee:27:f0:5f:6b:dc:b3
- e2:ff:7f:a6:9c:c3:1d:77:1b:d0:6b:ba:70:d5:a9:f3
- d0:4c:30:a2:be:f7:6c:43:c0:ba:44:1d:e5:e9:a9:01
- 66:be:aa:32:fa:e7:01:7c:7b:4b:5f:f6:5e:2f:ba:2d
- 3c:71:6b:88:1a:09:22:a5:2f:5c:99:19:c3:52:b0:77
- 74:c6:ff:45:2d:4f:15:cd:76:ed:f5:33:e7:cf:07:91
- 12:c1:7a:0d:5f:bc:4a:13:77:fe:06:6d:83:f2:c8:fc
- 55:3b:f2:3f:9d:48:4b:b5:1b:22:ad:a5:7f:c6:29:b0
- 05:b8:e2:82:5c:b9:66:48:8e:05:d1:5a:ea:3d:63:c7
- 94:81:0e:c3:0a:33:d2:a8:a5:2f:a2:83:26:59:19:1b
- 89:bc:8d:02:e1:c7:0c:53:64:6b:a2:d1:8b:ef:70:d6
- d5:94:bb:df:5b:49:4b:a5:cf:d4:df:0c:0c:ac:ed:8a
- 39:61:b8:15:cb:64:b6:02:6f:21:e2:46:d6:c9:d1:d8
- 62:ca:1b:f6:3f:3b:74:c0:5a:ca:cb:a5:c5:aa:80:89
- e2:66:a8:7a:57:61:5e:5d:e3:0c:b2:4f:48:01:18:21
-
-
-prime1:
- 00:e8:cf:45:ff:39:35:03:62:2f:2a:63:b6:14:95:22
- e7:30:6f:a1:d3:65:f1:8c:0e:13:a3:67:a2:1a:86:24
- 70:1c:97:64:15:9b:12:1b:59:66:de:05:42:6e:fe:ee
- 77:a0:bd:1e:8c:5b:de:45:c7:4b:05:ff:ce:39:45:ee
- 96:15:4b:96:df:b3:20:62:0c:90:bd:f8:1d:0a:ac:83
- 47:34:cb:63:0e:cf:1a:b9:20:62:59:1c:7b:a2:52:b0
- 4d:d7:c3:d5:90:32:9a:a5:3f:26:d6:66:f9:45:16:7d
- a4:4f:2e:4d:87:4c:d3:8b:b4:00:5e:d8:5b:29:cc:a3
- 3d:
-
-prime2:
- 00:ec:f0:f9:c9:43:a9:c5:fd:56:bc:57:d2:6d:18:9d
- 90:bb:17:74:19:80:1f:e2:21:b9:b6:13:6b:b5:02:62
- b3:51:97:4d:29:dc:85:ee:bf:15:98:f8:21:78:00:0f
- 3d:78:94:23:27:2f:52:a8:35:82:02:73:44:21:07:c6
- ab:61:fc:d1:1f:67:8f:43:5a:33:fd:ee:fe:d8:5c:a1
- 1e:b0:7d:6f:0b:6f:d6:47:25:1d:71:5f:b8:77:2f:8f
- 4c:6a:0f:8e:03:ce:f3:cd:dc:02:fc:21:c6:ce:10:07
- 0d:ee:1f:d1:82:94:21:41:10:9a:76:62:80:cc:f1:3f
- 99:
-
-coefficient:
- 4b:89:17:37:c2:77:4d:99:ec:95:4d:d7:7f:c7:0b:8a
- fc:67:ee:59:0d:66:7d:5c:33:36:6d:90:00:6e:3b:d4
- 79:9e:94:05:61:e6:e5:8d:f9:70:3d:7b:4d:be:7d:7f
- 0f:ef:e8:e3:93:1e:42:da:d1:9f:12:6b:51:d9:7c:ef
- 5b:c6:f1:e9:ab:9f:87:6f:d6:eb:29:4d:51:2b:f9:0d
- b7:e5:96:fb:c9:4a:21:a4:b0:4a:af:b3:2b:3c:41:45
- 19:d5:3d:cb:fe:15:4a:f7:a4:52:e6:d6:0c:c9:cc:5b
- 62:fd:b0:1d:ed:98:13:0f:9a:27:92:5e:a8:6b:bc:b8
-
-
-exp1:
- 00:8a:f6:c6:32:5d:24:5e:bb:a9:a9:a4:d1:17:a2:19
- ae:64:04:0e:55:50:21:89:57:11:b3:d4:f5:36:dd:e1
- 3c:26:64:db:71:e6:19:3d:c7:f4:96:0c:0f:a6:8f:77
- 2a:63:00:e0:0e:29:fc:18:2c:a8:84:91:37:b8:8a:1c
- aa:eb:55:2e:5e:a2:de:6e:88:4f:91:85:5b:58:76:b6
- f9:b6:f2:bc:53:27:9e:2c:e8:be:ab:b0:4b:c0:0d:99
- 7d:2d:90:90:96:bd:0e:00:1b:1d:04:97:7c:ad:17:8a
- b1:9c:2d:e8:4b:1d:b9:9c:47:3a:7d:62:a9:af:de:9d
- 85:
-
-exp2:
- 6c:52:0a:4f:b9:b0:3e:c4:7f:c7:a0:fa:a1:47:74:99
- 3a:ff:10:e3:ab:90:67:e7:f5:27:c9:1f:1f:64:54:cd
- 17:ca:ec:ca:eb:77:0b:5b:ae:3a:fd:8d:07:78:37:7f
- 69:c5:87:80:9d:80:d3:47:8b:05:25:bf:0a:be:ac:53
- a3:7b:59:fb:5a:73:c3:5d:d4:91:0d:96:d2:41:1e:a3
- 92:19:f6:0f:2b:74:b1:97:c5:2b:14:90:97:64:55:c5
- a0:63:36:10:85:a7:2e:00:9c:18:ba:34:51:f6:3f:d3
- 5d:7e:8c:60:7e:e9:e8:fd:f7:2f:91:fe:c2:32:b4:59
-
-
-
-Public Key PIN:
- pin-sha256:V1OZkBgmgMWlbg+RZ0Dx3sw/b4WHbrN4NHttN6QbsGM=
-Public Key ID:
- sha256:57539990182680c5a56e0f916740f1decc3f6f85876eb378347b6d37a41bb063
- sha1:028b616b894849cbca9103fcf919fdda20ca101e
-
------BEGIN PRIVATE KEY-----
-MIIE7QIBADA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAaEaMBgGCSqGSIb3
-DQEBCDALBglghkgBZQMEAgGiAwIBIASCBKcwggSjAgEAAoIBAQDXejoBi15ZDxB9
-lVzOxurIKS51bv5s+YPVPnJs/FaVQ9RiNN8FfLOzpko3yrbgI0QZ/Czqz/z5Jhqs
-Wo2D+E/ZC6786Z11Ny2kkwJdaRDft3pMtgVkc0ZFsv6kszOeaGsUNY7u37vgdyN2
-uG79/PLdAlle3KGzXZPGLOJKhSF/ylk26Hfd/s3+9rCW/hRqXGhMz7z9/uzjL1EQ
-z0bbHTo9zYfsZ0p9IF55bOrTJNOCBbzZeeXN32q7YpsgszU0Ya5pqau5tiesezP1
-vt+atBJoBlV5s7pS8JGQabHxWhHji97d8ZnKWq2HumVSJ6YHEmAQJJNL3xLbSQ/8
-If+f5pJ1AgMBAAECggEAP535hD02hMq6zqkLdo0qAiCOc+NqQJhGQO4n8F9r3LPi
-/3+mnMMddxvQa7pw1anz0Ewwor73bEPAukQd5empAWa+qjL65wF8e0tf9l4vui08
-cWuIGgkipS9cmRnDUrB3dMb/RS1PFc127fUz588HkRLBeg1fvEoTd/4GbYPyyPxV
-O/I/nUhLtRsiraV/ximwBbjigly5ZkiOBdFa6j1jx5SBDsMKM9KopS+igyZZGRuJ
-vI0C4ccMU2RrotGL73DW1ZS731tJS6XP1N8MDKztijlhuBXLZLYCbyHiRtbJ0dhi
-yhv2Pzt0wFrKy6XFqoCJ4maoeldhXl3jDLJPSAEYIQKBgQDoz0X/OTUDYi8qY7YU
-lSLnMG+h02XxjA4To2eiGoYkcByXZBWbEhtZZt4FQm7+7negvR6MW95Fx0sF/845
-Re6WFUuW37MgYgyQvfgdCqyDRzTLYw7PGrkgYlkce6JSsE3Xw9WQMpqlPybWZvlF
-Fn2kTy5Nh0zTi7QAXthbKcyjPQKBgQDs8PnJQ6nF/Va8V9JtGJ2Quxd0GYAf4iG5
-thNrtQJis1GXTSnche6/FZj4IXgADz14lCMnL1KoNYICc0QhB8arYfzRH2ePQ1oz
-/e7+2FyhHrB9bwtv1kclHXFfuHcvj0xqD44DzvPN3AL8IcbOEAcN7h/RgpQhQRCa
-dmKAzPE/mQKBgQCK9sYyXSReu6mppNEXohmuZAQOVVAhiVcRs9T1Nt3hPCZk23Hm
-GT3H9JYMD6aPdypjAOAOKfwYLKiEkTe4ihyq61UuXqLebohPkYVbWHa2+bbyvFMn
-nizovquwS8ANmX0tkJCWvQ4AGx0El3ytF4qxnC3oSx25nEc6fWKpr96dhQKBgGxS
-Ck+5sD7Ef8eg+qFHdJk6/xDjq5Bn5/UnyR8fZFTNF8rsyut3C1uuOv2NB3g3f2nF
-h4CdgNNHiwUlvwq+rFOje1n7WnPDXdSRDZbSQR6jkhn2Dyt0sZfFKxSQl2RVxaBj
-NhCFpy4AnBi6NFH2P9Ndfoxgfuno/fcvkf7CMrRZAoGAS4kXN8J3TZnslU3Xf8cL
-ivxn7lkNZn1cMzZtkABuO9R5npQFYebljflwPXtNvn1/D+/o45MeQtrRnxJrUdl8
-71vG8emrn4dv1uspTVEr+Q235Zb7yUohpLBKr7MrPEFFGdU9y/4VSvekUubWDMnM
-W2L9sB3tmBMPmieSXqhrvLg=
------END PRIVATE KEY-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa_pss_384.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa_pss_384.pem
deleted file mode 100644
index 5cdedc5ad2..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa_pss_384.pem
+++ /dev/null
@@ -1,138 +0,0 @@
-Public Key Info:
- Public Key Algorithm: RSA-PSS
- Hash Algorithm: SHA384
- Salt Length: 48
- Key Security Level: Medium (2048 bits)
-
-modulus:
- 00:dd:07:da:a8:65:55:09:ee:be:0b:c6:9d:95:05:28
- f6:d6:0b:d6:dd:31:7f:e9:b4:3c:53:0b:2d:ef:f1:bf
- 92:13:14:9f:09:11:08:a1:d4:49:ff:8a:51:5e:45:62
- e0:63:7e:9d:18:68:bd:93:fe:42:a5:46:de:5b:06:d6
- 90:28:98:10:fd:ef:5d:0b:f9:a4:7c:f9:ce:68:2a:6c
- 5d:78:5a:11:a7:d3:77:3a:49:c9:01:73:80:40:50:56
- df:1e:e6:21:d7:7b:9b:14:0b:00:fc:09:f7:97:9a:39
- 50:6d:ea:e9:c1:b1:47:ca:1a:c5:49:79:8e:42:2a:74
- e9:51:81:14:07:f2:51:59:72:b1:de:5a:09:72:de:77
- 90:62:e0:f7:96:64:07:7f:6d:83:c0:ed:82:6f:61:20
- 65:2a:09:ef:bd:8a:66:74:4c:2a:60:63:b9:91:6f:f7
- 55:aa:bd:d4:a0:a1:d5:a2:2f:20:8f:f8:19:45:60:93
- ba:19:2d:b4:eb:cf:8c:ea:1d:3b:2e:1f:99:82:66:79
- cb:c8:1b:1c:b2:a9:1d:bd:67:a0:39:e4:a2:59:14:67
- 69:0e:62:45:53:e2:8b:63:9f:38:cf:c0:dd:d1:c6:76
- b8:a2:87:78:08:31:38:28:e9:cc:25:98:69:fa:20:c8
- f1:
-
-public exponent:
- 01:00:01:
-
-private exponent:
- 54:12:88:b9:44:d1:f3:d5:3b:b4:7e:f7:b1:97:24:dd
- be:cd:02:0d:60:a6:a6:de:47:93:ce:cc:ca:57:c9:e6
- 66:1b:91:e2:80:f8:27:95:f8:0f:9b:2d:18:0e:8c:6d
- 8d:6a:bb:96:6d:40:ae:ea:27:af:76:25:5d:ba:5c:22
- b9:4e:1e:28:78:c3:8b:aa:89:46:80:3e:62:a0:c0:57
- 4d:4f:f5:27:40:e8:38:e3:97:f1:55:5d:93:18:fb:f2
- 22:6e:a6:b0:af:f3:6c:cc:42:b3:9b:96:f1:b3:57:d9
- 9f:f5:9a:b4:72:1a:3c:65:b2:65:20:37:5c:33:8a:03
- ff:ee:a7:73:42:38:40:0f:3e:af:73:c0:38:b0:21:c0
- 24:30:04:85:d5:01:0e:4e:4b:98:db:19:fb:88:39:de
- c1:b0:ca:94:1a:f6:be:8d:c3:bb:b7:10:34:6f:53:c3
- 77:b8:ed:f2:b1:66:8f:f6:6e:a8:b4:d2:70:51:8c:b2
- 27:59:5e:01:9e:7e:b2:4d:a4:2a:7a:09:2f:cb:e7:f7
- d8:dd:a1:f7:97:61:cb:17:2c:5f:02:19:84:1c:54:c8
- 31:e3:50:b0:26:26:4f:7a:d9:c0:fe:4e:7b:b6:7d:b5
- bb:86:d9:67:10:47:7d:62:7b:e4:b4:9a:5e:c9:aa:01
-
-
-prime1:
- 00:dd:5c:98:01:6c:e3:b1:f0:37:8b:d1:37:78:77:9b
- 1a:f2:26:c2:b5:8a:58:9b:f0:f2:bb:cc:66:23:ea:8a
- 9c:50:62:e6:d6:ea:11:ba:f3:ee:84:fd:9d:45:3e:ca
- 55:65:11:46:46:1e:03:58:23:54:44:03:d9:85:50:43
- ac:97:27:bf:e1:5e:a9:17:a9:43:cf:e4:6e:d3:09:0c
- 6c:11:74:8c:7d:dd:ed:be:96:bb:5b:d3:b9:c1:83:b3
- a3:70:52:d4:74:1c:d5:78:31:73:2b:1b:c0:dc:28:f8
- 51:55:4a:cf:16:b3:03:b1:58:d2:b7:df:bc:cb:6f:5f
- bd:
-
-prime2:
- 00:ff:9e:00:1d:18:dd:09:08:e6:20:10:b5:ea:c9:d5
- b8:17:2c:ce:c7:9c:d1:08:22:95:e0:41:1f:59:3e:2b
- 91:07:80:21:7f:61:73:ae:74:24:c1:7d:a6:33:e0:e8
- 20:07:ed:e4:fd:d9:55:65:ae:7b:76:a3:c9:10:35:26
- 47:78:0b:d1:45:a1:31:dc:d7:a3:52:17:24:ff:55:4b
- d0:c0:9e:12:73:f5:51:d1:89:ab:75:6a:0b:08:b7:8d
- 9a:d3:d6:3b:c3:ee:e3:0c:47:8e:7a:01:4c:57:d2:cc
- 7d:b7:bf:3d:02:cf:8e:0a:b0:43:4b:b4:15:d0:aa:17
- 45:
-
-coefficient:
- 00:d2:c8:fc:3a:8c:28:d3:15:6f:0b:7b:51:7f:a9:8b
- 3c:f5:ed:f5:6b:d1:d7:e4:e9:c8:46:16:80:1c:f8:78
- fc:10:bf:55:13:67:5a:a2:e6:2b:51:86:ca:d1:53:20
- 1e:e4:f8:82:ca:cd:4a:56:ba:bc:7a:dc:16:ba:16:43
- ca:66:21:f2:73:1b:ca:de:60:95:d1:b8:7b:ad:e1:1d
- d5:48:2f:87:83:40:00:a4:ea:ac:2e:4b:a6:c8:b1:4a
- 90:16:aa:e5:9c:91:a9:ee:57:ec:5d:13:b6:6d:bc:a6
- ef:b9:1b:b5:7c:44:21:24:06:c7:08:97:16:57:22:5f
- d3:
-
-exp1:
- 35:1f:b3:9b:23:f6:c1:0d:55:47:48:be:77:3a:bd:0e
- 8a:6e:a2:eb:ce:77:d5:74:cd:cc:24:11:9f:2c:fa:76
- e9:13:d3:32:60:9a:40:b3:a9:da:60:c3:0d:8b:34:23
- aa:4d:aa:ff:c8:d4:24:a2:d5:e6:3c:c6:47:28:2c:15
- 8f:71:0a:ab:9b:7c:19:21:96:14:9e:4d:ba:77:c1:73
- 6d:fc:fa:7a:7a:78:43:f5:08:a1:d0:fe:13:62:f8:09
- 91:3b:4f:a1:4e:0a:2c:fe:31:15:77:63:a1:72:73:a5
- 91:42:92:d0:6f:c5:c3:19:fd:f8:02:c9:dc:48:ae:41
-
-
-exp2:
- 00:b4:33:35:8f:4d:ac:dd:26:a9:dc:a7:0b:28:06:bb
- a4:b8:a9:bc:e8:59:b3:be:d1:6a:e9:19:df:b8:b1:2c
- 53:64:7f:3e:9e:27:1c:3f:3a:df:82:8c:4a:b3:bd:f4
- c6:47:f0:bc:82:fc:48:c8:92:f5:b4:d0:87:f8:e6:0f
- 23:49:0c:c3:ae:1b:92:24:46:dc:7b:0d:97:e6:6c:c2
- 32:da:e7:54:c8:ec:83:8e:7d:48:23:50:eb:90:6c:9d
- e6:2d:3a:95:0d:6e:86:1f:6c:fe:93:22:01:28:d4:91
- 96:7b:07:d5:41:fb:01:fe:a4:fd:fc:0b:6b:69:9b:cf
- 25:
-
-
-Public Key PIN:
- pin-sha256:KV163ICyMOUr6z/cxe1yQ1x2GIwCrmZAG9iOyW244lg=
-Public Key ID:
- sha256:295d7adc80b230e52beb3fdcc5ed72435c76188c02ae66401bd88ec96db8e258
- sha1:0c3cb2bad4f2115a013b50d9cb9f7ddf183e6012
-
------BEGIN PRIVATE KEY-----
-MIIE7gIBADA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAqEaMBgGCSqGSIb3
-DQEBCDALBglghkgBZQMEAgKiAwIBMASCBKgwggSkAgEAAoIBAQDdB9qoZVUJ7r4L
-xp2VBSj21gvW3TF/6bQ8Uwst7/G/khMUnwkRCKHUSf+KUV5FYuBjfp0YaL2T/kKl
-Rt5bBtaQKJgQ/e9dC/mkfPnOaCpsXXhaEafTdzpJyQFzgEBQVt8e5iHXe5sUCwD8
-CfeXmjlQberpwbFHyhrFSXmOQip06VGBFAfyUVlysd5aCXLed5Bi4PeWZAd/bYPA
-7YJvYSBlKgnvvYpmdEwqYGO5kW/3Vaq91KCh1aIvII/4GUVgk7oZLbTrz4zqHTsu
-H5mCZnnLyBscsqkdvWegOeSiWRRnaQ5iRVPii2OfOM/A3dHGdriih3gIMTgo6cwl
-mGn6IMjxAgMBAAECggEAVBKIuUTR89U7tH73sZck3b7NAg1gpqbeR5POzMpXyeZm
-G5HigPgnlfgPmy0YDoxtjWq7lm1Aruonr3YlXbpcIrlOHih4w4uqiUaAPmKgwFdN
-T/UnQOg445fxVV2TGPvyIm6msK/zbMxCs5uW8bNX2Z/1mrRyGjxlsmUgN1wzigP/
-7qdzQjhADz6vc8A4sCHAJDAEhdUBDk5LmNsZ+4g53sGwypQa9r6Nw7u3EDRvU8N3
-uO3ysWaP9m6otNJwUYyyJ1leAZ5+sk2kKnoJL8vn99jdofeXYcsXLF8CGYQcVMgx
-41CwJiZPetnA/k57tn21u4bZZxBHfWJ75LSaXsmqAQKBgQDdXJgBbOOx8DeL0Td4
-d5sa8ibCtYpYm/Dyu8xmI+qKnFBi5tbqEbrz7oT9nUU+ylVlEUZGHgNYI1REA9mF
-UEOslye/4V6pF6lDz+Ru0wkMbBF0jH3d7b6Wu1vTucGDs6NwUtR0HNV4MXMrG8Dc
-KPhRVUrPFrMDsVjSt9+8y29fvQKBgQD/ngAdGN0JCOYgELXqydW4FyzOx5zRCCKV
-4EEfWT4rkQeAIX9hc650JMF9pjPg6CAH7eT92VVlrnt2o8kQNSZHeAvRRaEx3Nej
-Uhck/1VL0MCeEnP1UdGJq3VqCwi3jZrT1jvD7uMMR456AUxX0sx9t789As+OCrBD
-S7QV0KoXRQKBgDUfs5sj9sENVUdIvnc6vQ6KbqLrznfVdM3MJBGfLPp26RPTMmCa
-QLOp2mDDDYs0I6pNqv/I1CSi1eY8xkcoLBWPcQqrm3wZIZYUnk26d8Fzbfz6enp4
-Q/UIodD+E2L4CZE7T6FOCiz+MRV3Y6Fyc6WRQpLQb8XDGf34AsncSK5BAoGBALQz
-NY9NrN0mqdynCygGu6S4qbzoWbO+0WrpGd+4sSxTZH8+niccPzrfgoxKs730xkfw
-vIL8SMiS9bTQh/jmDyNJDMOuG5IkRtx7DZfmbMIy2udUyOyDjn1II1DrkGyd5i06
-lQ1uhh9s/pMiASjUkZZ7B9VB+wH+pP38C2tpm88lAoGBANLI/DqMKNMVbwt7UX+p
-izz17fVr0dfk6chGFoAc+Hj8EL9VE2daouYrUYbK0VMgHuT4gsrNSla6vHrcFroW
-Q8pmIfJzG8reYJXRuHut4R3VSC+Hg0AApOqsLkumyLFKkBaq5ZyRqe5X7F0Ttm28
-pu+5G7V8RCEkBscIlxZXIl/T
------END PRIVATE KEY-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa_pss_512.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa_pss_512.pem
deleted file mode 100644
index 82ab5d95bb..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa_pss_512.pem
+++ /dev/null
@@ -1,138 +0,0 @@
-Public Key Info:
- Public Key Algorithm: RSA-PSS
- Hash Algorithm: SHA512
- Salt Length: 64
- Key Security Level: Medium (2048 bits)
-
-modulus:
- 00:d4:ed:b5:a7:85:5a:ba:9c:02:b8:fc:02:46:1e:e3
- 6c:54:34:72:3c:fc:56:eb:0b:ad:9d:95:83:a3:09:15
- 9d:f1:e7:1a:93:21:3e:b5:b3:64:7f:98:83:97:a2:b7
- ca:02:c4:48:a2:55:3f:29:b8:b1:87:61:6d:72:5f:7a
- 9f:20:69:f4:82:2c:7e:48:0d:d6:57:40:92:2c:13:9f
- e5:44:75:d4:ad:41:f6:c9:f4:74:c4:31:14:dd:44:8c
- ec:25:5b:4f:07:51:bc:4e:21:bd:47:c9:e8:56:b2:1e
- f1:5d:e0:56:36:c8:18:18:86:71:41:bb:c2:3c:06:ca
- e4:71:f2:cd:ec:9f:09:a0:05:6e:b4:d9:32:65:53:9b
- 5a:7a:b9:a2:30:7a:cd:06:a6:47:3f:f4:05:9e:87:b7
- 2f:b2:e0:fc:63:c5:ec:2c:19:ed:32:ad:ee:71:9c:37
- d1:34:f3:aa:1a:ba:ed:cf:40:28:82:43:11:54:83:74
- 42:db:70:f7:58:12:c5:11:af:1a:05:26:24:ef:81:8a
- 26:ee:2c:f3:8a:c4:2c:0c:47:cc:76:2b:7a:ce:e0:bb
- 80:d2:d0:5e:c8:8f:1d:03:c5:4c:47:1b:7b:90:c4:d3
- 0b:9f:8b:6e:29:bd:ab:25:cd:aa:1e:ad:72:19:02:c0
- 11:
-
-public exponent:
- 01:00:01:
-
-private exponent:
- 01:23:1b:db:3f:2d:12:de:0e:6d:aa:7a:e0:a0:fd:99
- f0:81:2f:33:00:2d:fe:a7:5b:50:02:22:67:d6:7e:95
- 0f:5b:aa:9a:aa:8c:c9:2f:a2:13:c4:5e:bf:8a:90:ec
- b5:43:13:18:3a:d8:51:82:b8:ff:fe:17:35:8b:28:fe
- 7c:8f:d4:4c:75:ac:5e:fa:23:f0:e7:59:60:7e:e2:55
- b9:1d:df:fa:e4:e5:4a:82:d1:b4:d2:86:48:00:3b:b8
- 6f:22:a3:b3:68:4e:57:24:7a:fc:4d:29:be:7c:c9:09
- 84:f4:d3:c1:0b:24:85:cd:02:01:d5:dc:dd:b1:33:98
- 2e:3c:e5:7c:69:e2:e7:e4:02:83:b5:e8:d0:05:c5:cd
- 5b:8e:72:f7:ee:b2:d4:11:15:85:b3:b3:4f:ac:cf:77
- 81:73:68:a9:70:fc:b3:94:24:f9:77:f5:38:4f:af:ab
- cb:4e:7f:c2:79:76:87:f9:0f:a3:3b:5c:95:61:64:11
- 3a:40:98:28:51:86:48:11:41:30:e2:1a:94:94:06:d0
- 0a:15:de:19:13:9f:f3:06:b8:03:68:8f:87:b2:3a:4f
- f3:75:bc:f7:5a:e4:1e:b4:49:29:09:da:57:e4:43:ea
- 96:bd:74:e3:f3:38:5a:bd:b3:da:cc:09:99:f6:09:19
-
-
-prime1:
- 00:f0:d9:0a:ee:11:50:da:c9:01:1f:5c:3d:c8:82:3b
- 1c:0c:27:17:80:69:fa:d1:9d:ca:d2:7f:12:90:e9:a8
- e5:36:f0:b7:8f:8e:90:f0:0a:78:53:0f:93:51:f0:f4
- 72:a3:1a:de:ea:0f:5e:8f:84:c3:57:39:38:93:73:cf
- 94:6e:1a:56:ef:36:d9:22:39:75:76:5b:4e:f6:54:e7
- 02:32:9f:54:5f:1b:02:37:50:f0:49:1b:e0:e6:d1:bd
- b8:07:9b:7f:15:fd:ea:53:08:59:e8:17:66:d5:10:e4
- a2:f1:3e:c3:c8:7e:68:a2:a1:5f:04:f1:7b:a6:c5:3c
- 73:
-
-prime2:
- 00:e2:53:03:dd:5d:f1:fc:27:a6:d7:01:b1:5e:f3:26
- 5d:9e:fc:f2:45:85:4b:10:86:97:a5:9d:2b:19:3b:35
- 8e:91:36:67:50:d0:da:16:de:c7:13:99:76:b8:9b:2f
- 44:fc:6b:c3:29:ec:a7:11:38:05:de:3d:2e:85:1a:49
- 88:28:b6:e0:1b:8f:6a:0a:21:56:ec:ee:56:34:b5:20
- e6:a2:c0:b0:08:c1:48:13:60:e3:65:b1:4a:b9:6c:9b
- a4:63:92:2f:5a:e6:6d:80:2a:c2:97:53:87:05:dd:08
- 1d:98:52:c9:88:a9:d3:5d:18:d7:2b:5e:0c:63:e0:94
- 6b:
-
-coefficient:
- 00:8e:60:92:ac:a2:02:d9:67:c7:c5:70:13:d2:b6:2f
- 5d:b2:a1:68:0e:46:db:33:f6:8a:a4:bd:06:07:db:5b
- 39:62:14:e6:81:95:32:ca:89:b7:dd:87:60:bd:98:33
- 5d:a8:21:25:d9:64:fb:5f:52:a5:28:e8:05:e2:7b:5d
- 43:ae:fd:d2:98:fe:20:9e:4e:65:96:11:c4:ae:91:a7
- 36:cb:3d:8d:fe:29:7c:91:bf:8b:45:17:f6:7c:29:41
- 1a:4b:87:85:c2:95:96:d5:8d:c7:5b:7a:29:6e:c3:6a
- c6:6f:38:55:f7:9f:aa:27:c4:a7:18:8c:42:f1:b2:94
- 9d:
-
-exp1:
- 7c:76:ed:9b:11:ff:c2:d0:d5:6f:ab:6f:92:4b:1a:d8
- e7:be:db:fa:54:ca:75:c1:21:ab:9e:57:ad:e3:d2:90
- 81:cf:ec:4c:97:d4:76:f8:32:2e:5a:82:3b:7a:56:19
- 58:08:ee:e1:ee:87:63:8b:ac:97:4a:ce:de:04:9f:65
- 89:70:bb:34:6c:17:d2:03:f7:9b:ee:9b:e3:d9:04:78
- b2:48:7c:85:99:a3:8f:8a:98:62:6f:b1:ce:16:de:00
- 58:8e:17:22:fa:51:3a:0f:ba:c6:a2:31:56:32:a0:b5
- 44:0e:b7:86:c9:2c:b1:be:cb:27:f6:d3:7b:df:b9:d9
-
-
-exp2:
- 32:88:88:9f:5f:bf:8d:26:a9:58:ee:76:d5:15:83:66
- 79:fe:4e:75:f9:5a:16:59:86:f8:a2:8c:21:f9:17:6f
- 3a:bb:23:fc:66:75:9b:8f:a8:71:96:dd:6c:40:b2:20
- 3c:20:2f:96:67:d1:b1:c5:89:81:e2:b5:45:60:e6:34
- 31:ab:0b:84:fb:d3:98:69:73:48:39:bb:23:cf:a1:85
- fd:a6:fa:67:2a:08:d6:d2:d6:53:39:6f:ce:d1:12:3b
- 75:44:09:b0:c9:2c:7f:e6:8c:46:4f:8f:21:5f:05:d5
- dd:d1:f6:4f:be:63:84:30:ec:b2:31:30:a1:08:5e:fb
-
-
-
-Public Key PIN:
- pin-sha256:xZynWKbgc/clJ1vmaUuUrDqVNLkKBsbEVke+Uj4T30M=
-Public Key ID:
- sha256:c59ca758a6e073f725275be6694b94ac3a9534b90a06c6c45647be523e13df43
- sha1:c19f5569864001b25aad7ff9de9d200574d2b257
-
------BEGIN PRIVATE KEY-----
-MIIE7QIBADA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCA6EaMBgGCSqGSIb3
-DQEBCDALBglghkgBZQMEAgOiAwIBQASCBKcwggSjAgEAAoIBAQDU7bWnhVq6nAK4
-/AJGHuNsVDRyPPxW6wutnZWDowkVnfHnGpMhPrWzZH+Yg5eit8oCxEiiVT8puLGH
-YW1yX3qfIGn0gix+SA3WV0CSLBOf5UR11K1B9sn0dMQxFN1EjOwlW08HUbxOIb1H
-yehWsh7xXeBWNsgYGIZxQbvCPAbK5HHyzeyfCaAFbrTZMmVTm1p6uaIwes0Gpkc/
-9AWeh7cvsuD8Y8XsLBntMq3ucZw30TTzqhq67c9AKIJDEVSDdELbcPdYEsURrxoF
-JiTvgYom7izzisQsDEfMdit6zuC7gNLQXsiPHQPFTEcbe5DE0wufi24pvaslzaoe
-rXIZAsARAgMBAAECggEAASMb2z8tEt4Obap64KD9mfCBLzMALf6nW1ACImfWfpUP
-W6qaqozJL6ITxF6/ipDstUMTGDrYUYK4//4XNYso/nyP1Ex1rF76I/DnWWB+4lW5
-Hd/65OVKgtG00oZIADu4byKjs2hOVyR6/E0pvnzJCYT008ELJIXNAgHV3N2xM5gu
-POV8aeLn5AKDtejQBcXNW45y9+6y1BEVhbOzT6zPd4FzaKlw/LOUJPl39ThPr6vL
-Tn/CeXaH+Q+jO1yVYWQROkCYKFGGSBFBMOIalJQG0AoV3hkTn/MGuANoj4eyOk/z
-dbz3WuQetEkpCdpX5EPqlr104/M4Wr2z2swJmfYJGQKBgQDw2QruEVDayQEfXD3I
-gjscDCcXgGn60Z3K0n8SkOmo5Tbwt4+OkPAKeFMPk1Hw9HKjGt7qD16PhMNXOTiT
-c8+UbhpW7zbZIjl1dltO9lTnAjKfVF8bAjdQ8Ekb4ObRvbgHm38V/epTCFnoF2bV
-EOSi8T7DyH5ooqFfBPF7psU8cwKBgQDiUwPdXfH8J6bXAbFe8yZdnvzyRYVLEIaX
-pZ0rGTs1jpE2Z1DQ2hbexxOZdribL0T8a8Mp7KcROAXePS6FGkmIKLbgG49qCiFW
-7O5WNLUg5qLAsAjBSBNg42WxSrlsm6Rjki9a5m2AKsKXU4cF3QgdmFLJiKnTXRjX
-K14MY+CUawKBgHx27ZsR/8LQ1W+rb5JLGtjnvtv6VMp1wSGrnlet49KQgc/sTJfU
-dvgyLlqCO3pWGVgI7uHuh2OLrJdKzt4En2WJcLs0bBfSA/eb7pvj2QR4skh8hZmj
-j4qYYm+xzhbeAFiOFyL6UToPusaiMVYyoLVEDreGySyxvssn9tN737nZAoGAMoiI
-n1+/jSapWO521RWDZnn+TnX5WhZZhviijCH5F286uyP8ZnWbj6hxlt1sQLIgPCAv
-lmfRscWJgeK1RWDmNDGrC4T705hpc0g5uyPPoYX9pvpnKgjW0tZTOW/O0RI7dUQJ
-sMksf+aMRk+PIV8F1d3R9k++Y4Qw7LIxMKEIXvsCgYEAjmCSrKIC2WfHxXAT0rYv
-XbKhaA5G2zP2iqS9BgfbWzliFOaBlTLKibfdh2C9mDNdqCEl2WT7X1KlKOgF4ntd
-Q6790pj+IJ5OZZYRxK6RpzbLPY3+KXyRv4tFF/Z8KUEaS4eFwpWW1Y3HW3opbsNq
-xm84VfefqifEpxiMQvGylJ0=
------END PRIVATE KEY-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa.pem
deleted file mode 100644
index d49498959c..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa.pem
+++ /dev/null
@@ -1,20 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDQjCCAiqgAwIBAgIMWYGU8BDBJ3AgFnsvMA0GCSqGSIb3DQEBCwUAMCMxITAf
-BgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0xNzA4MDIwOTAxMzZa
-Fw0zNzA3MjgwOTAxMzZaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUZXN0IENs
-aWVudDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM/xijmXl7PVbZwS
-BE6h3A2pEsv4Au86itIS4qb7GJNvOZ2pwx22/AOGr/JvsYGGnOsVxQ63mE9xBz2l
-jPsqGDhQeLD7CptXZAcwYa6k2z6S91Sd0GCNOgPuFiXKFXt9Si82uNB42r7kHG04
-exmY7uKUdMp1IxUbZ47leBmT7W5I65lK2acxkzRK6bdPErnNGzZt4t/k6E0Oowf6
-ElUf0UvhsX0trFB9O8yvCciqAQoGUw7b1yzWA9bWi1AQUPgx58eGMrRgQXfFnuuG
-efHqU+/nAVAt5pHHU0GqB09jcv1lJSQpDMtCBa5tsorVvy8OiiSJx15tIyNOtVcc
-9y/oH3cCAwEAAaN2MHQwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcD
-AjAPBgNVHQ8BAf8EBQMDB4AAMB0GA1UdDgQWBBSoiZsEL0tgug7IyLHTI1fA+tNH
-OjAfBgNVHSMEGDAWgBQrQlWadXqqzBV+2iw7BZXrvFHaQjANBgkqhkiG9w0BAQsF
-AAOCAQEAx3E9wM3ASFrxZ8Zw/036WHeJUjgOL+W9TM4Y4GZpQDkyMqKxs3pmyqcU
-xuXWV+SmTCkOAvrH/kWhmgDxSs3eGrGBsRPEZcUolcedDWqPJpy0qZH6mv3Ge0+v
-V+YOcd0qSVHaLpR1LQHrDnatASaVVRF4Ohk2IRSvjzYYJ158D3+erB79Txt4kqK2
-oDMp59uI2K4VwNiXeuWQgolaoKTEtPSrjuuKzetrwLN8ajii5rkiOKyuKlkZ2SyE
-BYp/ye1hzmqXRHNrObbfMmggwimrShYWUSwHp0/gKMEhen+yqd9C2KEVj7dqm+oL
-Jo+TGr6L77LBgZ5r7vfzj4tzL877mg==
------END CERTIFICATE-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa_pss_256.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa_pss_256.pem
deleted file mode 100644
index 77ec9737dd..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa_pss_256.pem
+++ /dev/null
@@ -1,23 +0,0 @@
------BEGIN CERTIFICATE-----
-MIID2jCCApKgAwIBAgIUej61CoI5BANd5v/ceHNxIOtR8d0wPQYJKoZIhvcNAQEK
-MDCgDTALBglghkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMC
-ASAwIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxlIFRMUyBUZXN0IENBMB4XDTE4MTAy
-NDA2MDY0MloXDTM4MTAxOTA2MDY0MlowIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxl
-IFRlc3QgQ2xpZW50MIIBUjA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAaEa
-MBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgGiAwIBIAOCAQ8AMIIBCgKCAQEA13o6
-AYteWQ8QfZVczsbqyCkudW7+bPmD1T5ybPxWlUPUYjTfBXyzs6ZKN8q24CNEGfws
-6s/8+SYarFqNg/hP2Quu/OmddTctpJMCXWkQ37d6TLYFZHNGRbL+pLMznmhrFDWO
-7t+74Hcjdrhu/fzy3QJZXtyhs12TxiziSoUhf8pZNuh33f7N/vawlv4UalxoTM+8
-/f7s4y9REM9G2x06Pc2H7GdKfSBeeWzq0yTTggW82Xnlzd9qu2KbILM1NGGuaamr
-ubYnrHsz9b7fmrQSaAZVebO6UvCRkGmx8VoR44ve3fGZylqth7plUiemBxJgECST
-S98S20kP/CH/n+aSdQIDAQABo3YwdDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoG
-CCsGAQUFBwMCMA8GA1UdDwEB/wQFAwMHgAAwHQYDVR0OBBYEFAKLYWuJSEnLypED
-/PkZ/dogyhAeMB8GA1UdIwQYMBaAFCEaiLbeA8ABgKrbcIiZpo8XzqpsMD0GCSqG
-SIb3DQEBCjAwoA0wCwYJYIZIAWUDBAIBoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFl
-AwQCAaIDAgEgA4IBAQCFjsx2JQ+AtT2AD7harhhhuCH8ah9hTLz1n+ynkmq1lmYP
-JCudOJfgWjMFlSv1ptzkvOst+Ig2BCCJrwX1akMX1cMsR/eoDUxxkqREU/irEYPj
-ePvVk0+bd6C4+nCvs/J0bv5P/16z2NLmAq8BUidi4ULPyzVn/+nAAUpAVlYi/mHP
-RQCy8UMj2ENACc4LIP1tek9cp+t5JMjsv2ogy+SPCXtq7VTMAFrckrALv9b1QLE6
-J06bp7+Q7GIkn0gTm+Z5AaddHH1ZDjqpYFcngx7wVuQCbZwTqnVJx5nQrKz+HQYt
-87KWIhR2nbtygp2oZESXQg9huH395f/h+foYArPG
------END CERTIFICATE-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa_pss_384.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa_pss_384.pem
deleted file mode 100644
index dda273d859..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa_pss_384.pem
+++ /dev/null
@@ -1,23 +0,0 @@
------BEGIN CERTIFICATE-----
-MIID2jCCApKgAwIBAgIUbdDLDIxL8QBkB4RFPZ3TaeInTUcwPQYJKoZIhvcNAQEK
-MDCgDTALBglghkgBZQMEAgKhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAICogMC
-ATAwIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxlIFRMUyBUZXN0IENBMB4XDTE4MTAy
-NDA2MDY0MloXDTM4MTAxOTA2MDY0MlowIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxl
-IFRlc3QgQ2xpZW50MIIBUjA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAqEa
-MBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgKiAwIBMAOCAQ8AMIIBCgKCAQEA3Qfa
-qGVVCe6+C8adlQUo9tYL1t0xf+m0PFMLLe/xv5ITFJ8JEQih1En/ilFeRWLgY36d
-GGi9k/5CpUbeWwbWkCiYEP3vXQv5pHz5zmgqbF14WhGn03c6SckBc4BAUFbfHuYh
-13ubFAsA/An3l5o5UG3q6cGxR8oaxUl5jkIqdOlRgRQH8lFZcrHeWgly3neQYuD3
-lmQHf22DwO2Cb2EgZSoJ772KZnRMKmBjuZFv91WqvdSgodWiLyCP+BlFYJO6GS20
-68+M6h07Lh+ZgmZ5y8gbHLKpHb1noDnkolkUZ2kOYkVT4otjnzjPwN3Rxna4ood4
-CDE4KOnMJZhp+iDI8QIDAQABo3YwdDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoG
-CCsGAQUFBwMCMA8GA1UdDwEB/wQFAwMHgAAwHQYDVR0OBBYEFAw8srrU8hFaATtQ
-2cuffd8YPmASMB8GA1UdIwQYMBaAFKnwXW9hoPAB6HSyWn7UEUMcKonnMD0GCSqG
-SIb3DQEBCjAwoA0wCwYJYIZIAWUDBAICoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFl
-AwQCAqIDAgEwA4IBAQAHS+4AoR5A0sNaCrhuB8rfDfI+kcO0SqwT98d5QTJnsiqu
-/2OHecJbN7nkYKh9K+8ccWVCWncWV1dFP1fVnCibFpAF+750wLhSpb/RVfm8Gd8F
-CLuZNC6i9w7ssQzus7SpBx2viY615zxRJ6kdhGhPSxc98tPAHkdkdWGWq0R8Q3u9
-hP/mj/oAxskhvF/Lofwk5uyYSNIcZ9w3YPmb70OUWDH1yreF7s0J3hOPZZiC7ZA4
-Nao6UPpwKk1IdZix63xHFwCN21AtQIHoL/aRcVSlHlol5VOgaWbetb1BTBqEoKux
-s4hJIMFIslA++GDX/qj7JrYr+FJTOqFF2B+Rm7wO
------END CERTIFICATE-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa_pss_512.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa_pss_512.pem
deleted file mode 100644
index 2bc13ae96f..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa_pss_512.pem
+++ /dev/null
@@ -1,23 +0,0 @@
------BEGIN CERTIFICATE-----
-MIID2jCCApKgAwIBAgIUWlbiagMGpRhGjEwawdwRz964ObEwPQYJKoZIhvcNAQEK
-MDCgDTALBglghkgBZQMEAgOhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIDogMC
-AUAwIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxlIFRMUyBUZXN0IENBMB4XDTE4MTAy
-NDA2MDY0M1oXDTM4MTAxOTA2MDY0M1owIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxl
-IFRlc3QgQ2xpZW50MIIBUjA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCA6Ea
-MBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgOiAwIBQAOCAQ8AMIIBCgKCAQEA1O21
-p4VaupwCuPwCRh7jbFQ0cjz8VusLrZ2Vg6MJFZ3x5xqTIT61s2R/mIOXorfKAsRI
-olU/Kbixh2Ftcl96nyBp9IIsfkgN1ldAkiwTn+VEddStQfbJ9HTEMRTdRIzsJVtP
-B1G8TiG9R8noVrIe8V3gVjbIGBiGcUG7wjwGyuRx8s3snwmgBW602TJlU5taermi
-MHrNBqZHP/QFnoe3L7Lg/GPF7CwZ7TKt7nGcN9E086oauu3PQCiCQxFUg3RC23D3
-WBLFEa8aBSYk74GKJu4s84rELAxHzHYres7gu4DS0F7Ijx0DxUxHG3uQxNMLn4tu
-Kb2rJc2qHq1yGQLAEQIDAQABo3YwdDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoG
-CCsGAQUFBwMCMA8GA1UdDwEB/wQFAwMHgAAwHQYDVR0OBBYEFMGfVWmGQAGyWq1/
-+d6dIAV00rJXMB8GA1UdIwQYMBaAFKVY4bgN1p+8NOXoPdj6DKWDscBFMD0GCSqG
-SIb3DQEBCjAwoA0wCwYJYIZIAWUDBAIDoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFl
-AwQCA6IDAgFAA4IBAQBm9QAlG/xd8O6/TgJwnxmjKcSNhWgFHz4yY2uSMRP51VR/
-SzoXIY3drTWz3fuXSxbjAcVSlfmSX3KMVm1M6IKOw37PwUD8C5oVpLEY/NpwTjfb
-WS5RR0XpAi2JJhPa9vJEO8PMdDV5C07u3fs5QvysNPZqJJvn+i2rU44JTeeJzBf8
-hesUVx4m+16C4cdU80prTnq9QYnZi08vIJ0iW0czxrsRikcqAnb+FEsrnbl1t3Wy
-PcdYUq7SkQ3B3pnreOMRnRGGP0dq4YOPto6nKD2h70TQ2rH2JhSlDy7aPNx9jUKO
-dwz0hfct7G7Wyoz2U+rI7ulHt3Mck4DyOam+TMEJ
------END CERTIFICATE-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-dsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-dsa.pem
deleted file mode 100644
index 029d88ac24..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-dsa.pem
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIEpjCCBEygAwIBAgIMWYGU8C09TIACbzDkMAsGCWCGSAFlAwQDAjAjMSEwHwYD
-VQQDExhCb3VuY3lDYXN0bGUgVExTIFRlc3QgQ0EwHhcNMTcwODAyMDkwMTM2WhcN
-MzcwNzI4MDkwMTM2WjAjMSEwHwYDVQQDExhCb3VuY3lDYXN0bGUgVGVzdCBTZXJ2
-ZXIwggNGMIICOQYHKoZIzjgEATCCAiwCggEBAKIJ4msqhhMj/QtISZhmqwZzwvxo
-9G4/z6zraDROzwt4KfCM+4Iplzb54xi4iifAKFjzegL066KAYuZEu3c5oU+1t2WT
-Uz4WaD/F8jpA/p8/iMp7d/Aj+qwHoIewZmtFN7OyTvIgPFUtzKShwsA/FGxQzDbw
-XOtsQ77WFdLa7B+1ZjFC776KbzNzZG0iClfZL0NweKYAGjdkJ6GKDJsKwkzWJ/wV
-2fKew8GzvUKiUVamMN6QXVx8x7odGETBu5FB0bP4wCKqnQKLarfHRspynA8rCNHF
-mW5CMGDQm+zaehpcgIOnsJE8xb9C7bzzFmkWxEy5DJmYPtnKEBDWz6XjdmUCIQCn
-T2W/xqEt+tix4k4f/a/0D3i7iawNewwccUb4C5RcYQKCAQAs4tv1yBjpGvsspRpL
-rxdAcIXhCeBQCzoYMI4CFH3lSjotUT5T30h2fA3qi3bm0GhnuAw7a1s3H749MAKm
-P9RgskHkeyFoWWKJ5rVqz+KOBXQkhRDkGND5hYdBgMq5YnnDQ7O0D0621AovPOex
-UQFVl2/4bJ/FRCPZ3NL790XwZNL0v/XFTDU1eL5CcSOwsENTfCpPa+6nnO4K/Gtr
-QV4mCpY8dwtQB9lTB6BuhuMQ5Bmu+JVaVaGDIP8pd1ZXxPg9WQcZY+sFRz5zkiBm
-Fs/+rbTnUC6Lx5T3tMBGhWC7+VmJNeT3eVzvMU7tgGGIElsQC1/5xU6pzRAL4/It
-ijN3A4IBBQACggEAYi/1HWMttEK5mU2B6IpU6pgUmkUleSVrQo3tdMViiSlGPtB6
-c+yoZc3GxruCUHIYbN+rFNIsdoJQ2k9Ah4VkX6mBytopd5eulwG63DDrXCRgxqMm
-BHFNvcZ/OG1Lj8Upnf9x9GbJwzoV+4J/tF/al9XlUk9gJf2zfr7oq6NAqvHXsaHj
-4oC3FQV0enQdfnC325wVie+BrV5hE/YUgcYF5m2R3a0o4UokGqyJzxDjxLlrtMHe
-6Rn7JngDfq7oFNXN1BMu9RD0Ll2KwZFURzZMAzj5DNc8eAScTC7omVrk6/lsQ1TW
-tnlOm7QXoBcRINwrA9hoTAgPh7iyqr8497M2yqN2MHQwDAYDVR0TAQH/BAIwADAT
-BgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHQ8BAf8EBQMDB4AAMB0GA1UdDgQWBBQL
-IkWyCawkb1V1BkwW61qMAd3TnTAfBgNVHSMEGDAWgBQA5WZqsOvPVi3KO+dfgL1w
-NxeVqDALBglghkgBZQMEAwIDRwAwRAIgUHB/GqyakK8awZlbR6MsLGDz0UiCvfCR
-eK2qrGSqsfICICKrf9+KyfiDh5HoB4pPZDOAAd5yQIEclw/aOD1yq0wT
------END CERTIFICATE-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ecdh.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ecdh.pem
deleted file mode 100644
index 7c8f044352..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ecdh.pem
+++ /dev/null
@@ -1,12 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIBtjCCAVygAwIBAgIMWYGU8BHdfIBy0aZkMAoGCCqGSM49BAMCMCMxITAfBgNV
-BAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0xNzA4MDIwOTAxMzZaFw0z
-NzA3MjgwOTAxMzZaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUZXN0IFNlcnZl
-cjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLWCgejCbKGDGpoTzBtYGeQt3OSZ
-B3aPwiAaQog3VfsSsERXWAiUdogMibtR4lLl6s9QbWDorQWXhejIUi7woY2jdjB0
-MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0PAQH/BAUD
-AweIADAdBgNVHQ4EFgQU0L5LXF6oiQE1eNyzRztmBOoHiR0wHwYDVR0jBBgwFoAU
-0ma/FGcW5gGlL//B26Xmj0JISecwCgYIKoZIzj0EAwIDSAAwRQIhAM6F/DDKK7H9
-HbkqCcUsxTCTakQ1wcAkkRDMCI/lKLxCAiAUjBMndyVRzNlY6h4+2NP0A3RT2Q87
-2mnmiPSuW9Q4iw==
------END CERTIFICATE-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ecdsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ecdsa.pem
deleted file mode 100644
index ffaa81e9f6..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ecdsa.pem
+++ /dev/null
@@ -1,12 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIBtjCCAVygAwIBAgIMWYGU8C5XSABmYVGJMAoGCCqGSM49BAMCMCMxITAfBgNV
-BAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0xNzA4MDIwOTAxMzZaFw0z
-NzA3MjgwOTAxMzZaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUZXN0IFNlcnZl
-cjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABKzro1Qhiu2IrXTK1X9xZ20T0eL0
-vxwmwTGcr7EvI9kRnhXDsV5Har9CmzInfIcOhL9VlS4K2WUhxNMuLYr5EIKjdjB0
-MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0PAQH/BAUD
-AweAADAdBgNVHQ4EFgQUNjGYYKninT7GGg2A3pGsO2xPByIwHwYDVR0jBBgwFoAU
-0ma/FGcW5gGlL//B26Xmj0JISecwCgYIKoZIzj0EAwIDSAAwRQIgWYw3r0KqlS60
-h4RON2Ycq7oH2qxf+b9mWaehP8sebHoCIQDJyu+qUegmitkVqbenVV2ypPL7x2nP
-qvghAKPod/72bg==
------END CERTIFICATE-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ed25519.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ed25519.pem
deleted file mode 100644
index df3a379c4b..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ed25519.pem
+++ /dev/null
@@ -1,11 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIBfjCCATCgAwIBAgIUEOZLZhsVbmqCJUugm0oRFrWPO8swBQYDK2VwMCMxITAf
-BgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0xODA4MjMwOTI5NDda
-Fw0zODA4MTgwOTI5NDdaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUZXN0IFNl
-cnZlcjAqMAUGAytlcAMhAM2PquzCzWQdU5dEG7JMCCfvaaNyfRlcIhsCzF8RLWiw
-o3YwdDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1UdDwEB
-/wQFAwMHgAAwHQYDVR0OBBYEFFsSy04J6VkN2IiqBJKGV26iMRYyMB8GA1UdIwQY
-MBaAFOp5vj76ByEwboduoHWAWzajnM1mMAUGAytlcANBAOhCpwpdClN4+DFhtwLf
-br8//ymNpCOf8W4vE4pZACueKIooh2S4WnbkFwBloOntxX+4TXnD06SBlpcmoQg2
-NwY=
------END CERTIFICATE-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ed448.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ed448.pem
deleted file mode 100644
index 3ba371f662..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ed448.pem
+++ /dev/null
@@ -1,12 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIByTCCAUmgAwIBAgIUdWna0n25+zzo6pW93hOpSKLfU0swBQYDK2VxMCMxITAf
-BgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0yMDAyMTMwNzMzMDJa
-Fw00MDAyMDgwNzMzMDJaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUZXN0IFNl
-cnZlcjBDMAUGAytlcQM6AETFuJ7D3g4EgZnNVbPW3j81X6VpJane2pY04n8bzYcs
-kAvfb5lGogDBoczMsB9opnPMdSwZQs6CAKN2MHQwDAYDVR0TAQH/BAIwADATBgNV
-HSUEDDAKBggrBgEFBQcDATAPBgNVHQ8BAf8EBQMDB4AAMB0GA1UdDgQWBBTHz9U/
-S0PulhuJNX8vOdBOjnLCqjAfBgNVHSMEGDAWgBS+BSv++BEWlTJ53q6rwnDLVnR5
-JTAFBgMrZXEDcwAp/84ZggkOUHT0qCL/8a3Qmj6HyXeb8NNVyPNSbBgW6HVQsn9c
-wquAbara1d9VFJ+ucpSdQfYPs4DVfxADVcVfaunEGujBoL9U3q/9XIJ5IT70HL1O
-+PUERelTyKywKQI8Y2YYKUH6UYsesLhcAQ8DBwA=
------END CERTIFICATE-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-dsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-dsa.pem
deleted file mode 100644
index 73247089ce..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-dsa.pem
+++ /dev/null
@@ -1,15 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIICZAIBADCCAjkGByqGSM44BAEwggIsAoIBAQCiCeJrKoYTI/0LSEmYZqsGc8L8
-aPRuP8+s62g0Ts8LeCnwjPuCKZc2+eMYuIonwChY83oC9OuigGLmRLt3OaFPtbdl
-k1M+Fmg/xfI6QP6fP4jKe3fwI/qsB6CHsGZrRTezsk7yIDxVLcykocLAPxRsUMw2
-8FzrbEO+1hXS2uwftWYxQu++im8zc2RtIgpX2S9DcHimABo3ZCehigybCsJM1if8
-FdnynsPBs71ColFWpjDekF1cfMe6HRhEwbuRQdGz+MAiqp0Ci2q3x0bKcpwPKwjR
-xZluQjBg0Jvs2noaXICDp7CRPMW/Qu288xZpFsRMuQyZmD7ZyhAQ1s+l43ZlAiEA
-p09lv8ahLfrYseJOH/2v9A94u4msDXsMHHFG+AuUXGECggEALOLb9cgY6Rr7LKUa
-S68XQHCF4QngUAs6GDCOAhR95Uo6LVE+U99IdnwN6ot25tBoZ7gMO2tbNx++PTAC
-pj/UYLJB5HshaFliiea1as/ijgV0JIUQ5BjQ+YWHQYDKuWJ5w0OztA9OttQKLzzn
-sVEBVZdv+GyfxUQj2dzS+/dF8GTS9L/1xUw1NXi+QnEjsLBDU3wqT2vup5zuCvxr
-a0FeJgqWPHcLUAfZUwegbobjEOQZrviVWlWhgyD/KXdWV8T4PVkHGWPrBUc+c5Ig
-ZhbP/q2051Aui8eU97TARoVgu/lZiTXk93lc7zFO7YBhiBJbEAtf+cVOqc0QC+Py
-LYozdwQiAiAxcsCPJCsRaG0j1eDW0xomfipUvAM3Ws9MZ38R8fxQ/A==
------END PRIVATE KEY-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ecdh.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ecdh.pem
deleted file mode 100644
index 669fc5cd0d..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ecdh.pem
+++ /dev/null
@@ -1,6 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIGUAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHoweAIBAQQhAJsXqInsRDYS26zX
-d4tHYu+WKbw2gyrnMvDOamsRyZg5oAoGCCqGSM49AwEHoUQDQgAEtYKB6MJsoYMa
-mhPMG1gZ5C3c5JkHdo/CIBpCiDdV+xKwRFdYCJR2iAyJu1HiUuXqz1BtYOitBZeF
-6MhSLvChjQ==
------END PRIVATE KEY-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ecdsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ecdsa.pem
deleted file mode 100644
index ca898da2fe..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ecdsa.pem
+++ /dev/null
@@ -1,6 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgHJsLqw/ZeIlLMmMZ
-u+LqjbxD7OY2VhD055Icbpp5HBmgCgYIKoZIzj0DAQehRANCAASs66NUIYrtiK10
-ytV/cWdtE9Hi9L8cJsExnK+xLyPZEZ4Vw7FeR2q/QpsyJ3yHDoS/VZUuCtllIcTT
-Li2K+RCC
------END PRIVATE KEY-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ed25519.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ed25519.pem
deleted file mode 100644
index e1784c5efd..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ed25519.pem
+++ /dev/null
@@ -1,25 +0,0 @@
-Public Key Info:
- Public Key Algorithm: EdDSA (Ed25519)
- Key Security Level: High (256 bits)
-
-curve: Ed25519
-private key:
- f8:32:a1:54:10:e9:b2:b2:31:10:9d:05:c0:3b:58:c5
- 1d:1b:7a:67:d1:53:5e:6b:58:fe:85:1f:4a:4e:71:13
-
-
-x:
- cd:8f:aa:ec:c2:cd:64:1d:53:97:44:1b:b2:4c:08:27
- ef:69:a3:72:7d:19:5c:22:1b:02:cc:5f:11:2d:68:b0
-
-
-
-Public Key PIN:
- pin-sha256:tt5u5+ynOHjlD3uadUUmN2V5yZLekOkkwyyk8sZH7cI=
-Public Key ID:
- sha256:b6de6ee7eca73878e50f7b9a754526376579c992de90e924c32ca4f2c647edc2
- sha1:5b12cb4e09e9590dd888aa049286576ea2311632
-
------BEGIN PRIVATE KEY-----
-MC4CAQAwBQYDK2VwBCIEIPgyoVQQ6bKyMRCdBcA7WMUdG3pn0VNea1j+hR9KTnET
------END PRIVATE KEY-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ed448.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ed448.pem
deleted file mode 100644
index 382cdd6189..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ed448.pem
+++ /dev/null
@@ -1,28 +0,0 @@
-Public Key Info:
- Public Key Algorithm: EdDSA (Ed448)
- Key Security Level: Ultra (456 bits)
-
-curve: Ed448
-private key:
- af:0f:44:88:c8:11:f7:e4:87:19:b2:e5:f2:17:a4:e5
- 0a:69:78:ed:1c:34:f1:dd:8a:b1:c6:92:92:64:26:94
- 8f:46:45:af:b6:58:d5:b1:20:ce:5e:d6:b7:8e:48:e9
- 0e:14:a7:94:56:d5:14:c8:9d:
-
-x:
- 44:c5:b8:9e:c3:de:0e:04:81:99:cd:55:b3:d6:de:3f
- 35:5f:a5:69:25:a9:de:da:96:34:e2:7f:1b:cd:87:2c
- 90:0b:df:6f:99:46:a2:00:c1:a1:cc:cc:b0:1f:68:a6
- 73:cc:75:2c:19:42:ce:82:00:
-
-
-Public Key PIN:
- pin-sha256:un7RlIHaUdVuKc7nlN4TlmbH42dUsl+RH5jeVUKSyiA=
-Public Key ID:
- sha256:ba7ed19481da51d56e29cee794de139666c7e36754b25f911f98de554292ca20
- sha1:c7cfd53f4b43ee961b89357f2f39d04e8e72c2aa
-
------BEGIN PRIVATE KEY-----
-MEcCAQAwBQYDK2VxBDsEOa8PRIjIEffkhxmy5fIXpOUKaXjtHDTx3YqxxpKSZCaU
-j0ZFr7ZY1bEgzl7Wt45I6Q4Up5RW1RTInQ==
------END PRIVATE KEY-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa-enc.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa-enc.pem
deleted file mode 100644
index d1e835252a..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa-enc.pem
+++ /dev/null
@@ -1,28 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC3mOPbXv2BWujn
-fNGxYw/JNbyW7qQTaKnZogE/aIh5m86hinj7agtV2UDsBXvaQSTrp8vXwKNr9IYX
-VLEvT5lM8mj+GDlJ1jhKbo1ODbZPY7b1q5e1RtMUhNX3GgZDevrLL0Tt/g912KD4
-U7vTsS2TQ35hXOQ6bknN9VWNhat0lQ/L60q2QofPdk9PydFZV9CxkoGvwV1BqiTp
-JiEloFAf3h07Gim/e3K6OlU2ci+Lb6/uvSDPiOIVYPBURmVjs49sLha2jDj51II4
-9KpPbJwNUT902VrvoRwhrWP8FxYO0QxG9J07IdsNLQLzVWBxz03qK3v+U/akO1QQ
-uyrWmw69AgMBAAECggEBAJd3t2RgddymV8fDHmyuQXPKtY//ybWJf7dhBI5/ezh4
-5nw3daBV2Iw29GzECW4CmKcig/W3pBuIXKga4yMZFGx7AUvASGM2LLKbilB+142f
-wm3j5wFTMQmYnb2C5u/9IbNHiCKgm7ipxAObcTYw0lzQLg+9Rz09h/43DSH4yX8f
-ov1ANiERjkjTMYfaoMbdVrik3MrzBx3lNa0wShS3WebdLIBGv1pk6U2b0bCVJUPP
-OJ9n9bs4+kzJBofDHad6N1UszQoHB+1xHthKC5YHyEbnkWlJoyiNWELcADCKYxWY
-lsbH1b6zUXlQ+/IYe7uD9Y9nOa/6kXwmyPGuFVBXGgECgYEAwMvMRVkFArycrgd1
-mmYyewuGKQyOonj6qlKDjpuZ829CPwZ7xEpSBNQcKn1vHW52IxJizVh5fHWG/8ga
-p2uVGdNUbtjlazrZXDm7xBEAYke+vxgrLHzwCvk3MxFF639nmN9khX+cceLkAaZm
-AEye8thr6IN7TVMt43E4G7Bd5OECgYEA88kWgFRvY7rB3oRnMEuLKaTIAdJM81Tt
-lQ3PQNTAdt9HenJE5E5y884xQsYCfmvkTGrd7bWHBzRgA0slJQExAaLBNrqm2evw
-AshQRVY2mR4TUuKadrWVDV6IF9IDeGZpCEmz1A0RY5M77l2jJ+pAd8Pd8wM07QLV
-KqjpDRLTCV0CgYA8xkGPPr+QnEo7pchRspOJLBnPiNDRsJc756Tm6HAAR/s3COEt
-AEyYjxCN6FqFiZOd/Ka+mnw5WocCzF5yljw7Ft4PzzmKstNf+icRaFaZpIohjQnX
-DU9R9juLUo+a69+JVipG1vJHCEHdr0mKIJ0ealChzAirWGQnxUHtoIwIoQKBgGH1
-JWN/ihrKymf9T/FqCYs8OVnyBRWpxKWmHOdyFbwuT+x1yhTrKOmqqsSoCAyAkgXa
-0z5XOOC+PO5V3aEW73g2y+iP68eZNKIJl6ek0t+H5D/j6ilVIYVzvL/Flbtle0Ln
-Sqkkbx5R5T0MxyicyjbVr3OckEHEZ59yq+Ki88XJAoGAIrVxwcg+b7FKvBhjrx68
-kBK0rFwTdcqq+82G5R5DGfK5nK9RON01aOM3ddZNy+q/xe5O0kzFPkEQhSsGXTJ2
-+O0cBtTSrQ8hMZKHH6Ol4y6rWjDObmhNZR5ms76l5Fi3EzUKcLbTcl1NXlihanmU
-rmQcSs0PKSGpZdraqdH+YrU=
------END PRIVATE KEY-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa-sign.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa-sign.pem
deleted file mode 100644
index 975638e550..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa-sign.pem
+++ /dev/null
@@ -1,28 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC8Xwb2eeVqVUHg
-obVcnfjv7C7nhlZAZWFEbrJJXCwqnbYTOUEywVTDkNr7cVp2Q0h1iLz1Dwpz8UfC
-LD77DPAVKkI8o9nfQnL7jTYMCjCM1ANdG0Cz0OumnNU+zFP9gOEfscSTeWTqeAfl
-MBMDQHgFX0PV2V/h5JlQIyjyYkc5o3c6ALJUEdBecy9dYI5kvEk8GbiftjKVIdPV
-RnRyfiwdQjVX5xMcD6kd8HdU0D1C12Tdw8fn9Ftu4JgOBkYrTLS5bQJY72cxrevs
-YW8iiSYzJ0wVpcxRYj/4IKXD7PqtoVvYt7zwhOXjhnZGw51yYt2ogcWKUynkueMB
-nPzpE7+VAgMBAAECggEBAJDChltL+d3pfyLdor52OCRI4RLTzdzXDBTG7QQrbVWi
-tZW4Xj5fDIDuBRtOVTKlKj4Iww2gbWwEdBzoW84adzYMr7JiSMCmFC70qiA+hGj1
-VVBr7SFC4JW92LLV24XpURhGSMb8d20oqQicFUBeft3CBCOHVYQHZTqMip8an5nO
-jWPEcxgp2hU5R1BzliMtpwtP3yLN8UD281CEdKy/nG5AfyI882mLbpiFtr0gymhw
-CEqJd62vmK1mvSYDYA2QHy3ki9CxCNog0raQy/sOX4JtgCDhmy06FOOqzyo3LFcN
-I7Ng2D3R+d7tCEJ8A3C7Z/HbET0MsZDolVljBoNEMlECgYEA+Kznpbm0Vd0Oew9S
-5HRzXeZbCnc1fjTOhrtL8o+gyZsXiJQfDWUJ+Mlac2GFDK2FhQofnpfRHlyJRr0b
-PSMzPMEB2nj/7Im0LpOUBt2TD69zK8INHIyFmu76ARgqE/rwyuxv+fyqDgUmQShP
-8XC2joqejZchvvtX9REj6lQ650sCgYEAwetol/72hrrLNycaVntq7GMmLZCtqIc9
-YcLwQQVjFPkf2eiAHrsdZSnOUYXUJfvsRY4OZ7IkOQp0isU8FqED9CCoLwZ7B67c
-DPhUYN6JgIqsH3CuxE9q/5sYb+d8HM9450pk8JrKHJDbBE3nwftLcay5iudkArjw
-2hCi4CqzSJ8CgYAdqjKwGGkk3Qv/LiLLUgD5MKOnqfTdq1r/w5QZyXx60F+MUW8q
-3+TCovKBVR7UFlcZOc3v01iE8LEHmUOIlYxlMPkRoOGWzA6Mh9pev0vt0RZCIBIE
-V9cQVnXIb6OFYqga7P2mqrd2mLKpjy+KM9HzSyIC7gZ+i+lAON059PZZ5QKBgBbA
-UMgscK4D8l2pJ8zns/bB9zO3WriADXKP1XI7eJF4XQVK4uU4HM3Gpt8nrWk7clAC
-x6vg2aEbmerCEzewcm9M+Y5y2zJekJCw/e1TjpxXKLSTmt2LV8lfX/GZHhWfPdcd
-AlS8RGQvlpKdtUgr/ID8u9QRK8mp+xAKjaFxQRGPAoGBALIBTZMU/kmvnO0PrzVL
-eR3yojWI/+743kMFxPYfD2sPo/3Dd9qg8J7d1B6wu36vSP2rWVWVGShY6qxiDINi
-RnLHzQILuztRbWnxRijP19KtmQctfw7/QIyUMkJ/Ur1bU2JpCjnRdoDVudk8nLvp
-dAVR+0swGkDk8ffY+jwZ4gMM
------END PRIVATE KEY-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa_pss_256.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa_pss_256.pem
deleted file mode 100644
index 40f795a162..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa_pss_256.pem
+++ /dev/null
@@ -1,138 +0,0 @@
-Public Key Info:
- Public Key Algorithm: RSA-PSS
- Hash Algorithm: SHA256
- Salt Length: 32
- Key Security Level: Medium (2048 bits)
-
-modulus:
- 00:a1:d4:bd:d5:9f:ca:7e:e5:d4:7f:49:52:78:33:d6
- b0:2f:37:a4:a2:f8:4b:32:b5:ef:d5:29:9c:7d:2e:ac
- 69:b0:b1:1a:09:7d:f1:92:3a:ae:c4:d1:29:63:1b:5d
- 60:d3:4d:06:3f:bc:7f:46:c7:22:c2:98:e0:2c:32:fb
- 9a:94:f1:ea:b9:3b:37:4b:44:8b:bf:60:28:13:6b:e9
- 31:a6:0f:e2:3d:82:60:9d:28:8b:d4:63:7f:e1:06:cf
- d6:81:a1:24:ef:b4:a5:3a:05:95:16:e5:c6:9d:e1:6e
- 31:56:92:13:16:c4:2b:53:20:73:57:96:9d:7a:4b:be
- e8:f0:50:1a:55:18:1e:d9:69:f2:f6:b5:e5:3a:98:b6
- 77:7b:ff:30:74:9f:6d:81:55:50:b5:3e:81:8d:54:f6
- cc:17:3d:1b:10:bf:69:77:09:d1:d8:be:79:11:ac:3b
- be:19:69:5c:b1:50:4d:ba:04:09:98:74:7a:e3:96:48
- 4d:fc:67:7a:34:73:76:48:5e:41:05:61:5a:68:59:39
- b3:86:aa:78:28:f4:a6:4a:db:6f:85:47:75:75:a2:24
- e9:21:3f:18:c9:46:87:91:80:1a:f5:fa:ed:2b:ab:03
- e8:ed:c3:dd:67:ad:46:eb:9b:7e:44:d2:5c:76:4b:3d
- 5f:
-
-public exponent:
- 01:00:01:
-
-private exponent:
- 69:92:00:19:18:f9:9f:98:cc:ec:10:68:05:54:43:ec
- 81:90:fa:0c:fa:8f:0b:d0:d6:59:27:a1:17:a4:d8:02
- c6:aa:72:02:d9:2f:3b:26:9f:16:74:20:5c:af:e0:55
- a6:e2:6b:7e:2e:b8:94:f2:99:81:7a:fb:5a:ba:13:9a
- bf:29:a5:e7:1a:73:32:dd:cf:90:93:e8:f0:ea:87:a0
- c4:e5:3d:c0:c4:89:c4:5c:4c:03:cc:b9:02:92:50:09
- 6e:5d:32:5c:51:6b:2c:13:b2:33:d2:c7:a3:fd:08:c6
- 94:e4:0c:21:e0:ed:26:78:57:e6:3e:b2:12:b2:d1:21
- d8:93:90:f5:8f:2f:c8:97:6b:f0:e6:b0:2a:df:02:18
- 7e:ce:98:8b:63:0c:15:7c:21:39:f9:6c:e2:61:93:fc
- 49:36:cd:9d:29:d8:a4:ed:65:12:6d:11:72:f8:13:47
- 6d:8e:20:d7:9f:01:29:3b:8f:dc:d5:b8:f5:58:6f:c1
- 5c:8b:36:40:c5:80:9c:1e:4b:9f:03:55:b5:ff:1c:46
- 1f:e3:b0:12:0c:44:f0:91:07:41:20:08:6a:99:5c:f2
- 11:50:30:4b:4a:84:8e:03:87:89:4e:60:5f:69:01:94
- 5f:82:41:1c:dc:7d:34:f9:02:02:ee:e0:e7:59:63:c9
-
-
-prime1:
- 00:c0:9b:4b:2f:d6:57:df:59:31:87:2a:4c:42:fa:4c
- 0c:f2:4d:17:07:90:9b:9c:db:8e:b4:aa:68:96:d1:16
- 01:27:92:e9:8a:26:d1:73:fd:68:21:c7:19:7c:46:f0
- 33:de:21:46:9c:0d:eb:84:8c:b9:6f:cb:47:d0:c5:b8
- 95:1a:e3:18:03:99:81:39:54:2f:c3:a1:14:74:c7:5f
- 82:2c:e8:b9:a9:7f:4c:ff:ac:a7:4f:7f:39:20:ee:3d
- b1:0f:83:33:fa:76:57:68:4d:8b:99:24:69:d2:08:1b
- 1c:36:e7:c9:be:ea:db:1d:38:61:a4:4c:7a:44:e1:82
- 53:
-
-prime2:
- 00:d7:18:59:39:b2:de:4d:0b:58:69:8c:33:af:51:ee
- c1:e2:3b:64:b6:36:dd:31:c5:9d:33:39:e2:88:c4:35
- b0:93:8a:6a:b2:c2:8b:ca:c0:0b:21:94:69:90:ae:19
- ab:7b:b8:48:eb:f3:27:3b:96:5c:17:1e:71:89:e7:c5
- 14:d8:d7:de:2b:89:1e:58:f4:4f:1a:95:a7:34:65:48
- 6a:94:f2:bb:33:3c:90:d6:99:4d:36:48:8f:0b:30:d9
- 5f:59:26:60:f0:97:8e:3e:d0:31:99:6f:93:c9:c4:ea
- 25:08:f9:48:2f:2a:77:57:93:03:d6:6a:22:fe:16:cf
- 45:
-
-coefficient:
- 5b:5d:58:5d:f8:be:1f:31:c4:e9:23:1e:34:41:60:1b
- 2d:57:2b:d7:3f:39:74:5f:fa:d6:71:4e:46:02:2d:1a
- cc:51:d5:96:7b:d7:0c:f1:8a:a9:31:e7:61:bd:0c:31
- 31:e3:5c:27:32:0b:bd:4a:67:ad:c0:31:db:91:a4:96
- b0:a4:9e:81:0e:75:2e:5f:0c:c5:9b:8e:4d:6c:b4:7e
- 2c:44:53:2d:b7:d7:82:20:ba:59:38:df:ec:99:8d:63
- 5f:e9:24:d1:8e:6e:e0:5b:fa:f2:12:16:75:ad:f3:a7
- 2d:fd:8f:55:5f:09:a3:42:4b:44:d2:c8:c8:41:7c:c8
-
-
-exp1:
- 7f:cc:4a:e6:31:e5:da:67:d7:4a:25:51:b6:bb:57:8c
- db:95:35:2b:aa:d2:e6:10:74:af:01:c7:26:13:13:f3
- ae:2b:77:d4:58:0f:70:53:fb:2d:36:6b:7d:9f:a0:2f
- fa:3a:c0:1c:39:cc:45:06:0e:e0:d3:d4:11:fd:af:8d
- 17:eb:08:fb:12:76:c0:f0:50:45:10:f3:7e:cc:ef:5d
- 73:a8:f3:d0:38:8c:81:b5:30:ca:b9:d2:d1:3b:e3:29
- 41:ee:bf:a5:77:b2:65:9d:d6:7b:c5:c2:85:3f:25:a5
- e1:f4:88:53:aa:87:ba:ea:b7:37:0a:1b:b2:ea:a2:cb
-
-
-exp2:
- 63:04:e8:7e:71:63:79:20:51:f1:35:03:ce:1f:ef:c3
- fd:bb:cd:df:3c:5e:93:bd:1f:63:27:b0:ab:b9:77:e5
- f3:e5:f2:bc:9c:66:f2:4d:7a:52:59:1a:47:ea:7e:12
- bd:7f:d6:c2:18:4b:e5:58:90:c8:6b:d1:64:e4:f7:8b
- 63:4f:ed:0d:29:b0:78:ce:ef:63:93:a5:47:af:a0:a8
- c0:2d:06:14:ce:3a:f7:2f:d7:a5:b7:bd:72:2f:68:c2
- 46:2e:2e:ce:53:56:be:7f:e5:75:77:32:17:de:b8:d3
- 97:cf:fa:75:0c:1d:a8:89:1b:69:27:af:38:3d:93:e9
-
-
-
-Public Key PIN:
- pin-sha256:KBIg1VxV9p1XXyGsX+MwqaE2DenjfwcmJzw2z8jOeT4=
-Public Key ID:
- sha256:281220d55c55f69d575f21ac5fe330a9a1360de9e37f0726273c36cfc8ce793e
- sha1:06c5f6d2f4f448fa67ba12fe955efbe15febd164
-
------BEGIN PRIVATE KEY-----
-MIIE7AIBADA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAaEaMBgGCSqGSIb3
-DQEBCDALBglghkgBZQMEAgGiAwIBIASCBKYwggSiAgEAAoIBAQCh1L3Vn8p+5dR/
-SVJ4M9awLzekovhLMrXv1SmcfS6sabCxGgl98ZI6rsTRKWMbXWDTTQY/vH9GxyLC
-mOAsMvualPHquTs3S0SLv2AoE2vpMaYP4j2CYJ0oi9Rjf+EGz9aBoSTvtKU6BZUW
-5cad4W4xVpITFsQrUyBzV5adeku+6PBQGlUYHtlp8va15TqYtnd7/zB0n22BVVC1
-PoGNVPbMFz0bEL9pdwnR2L55Eaw7vhlpXLFQTboECZh0euOWSE38Z3o0c3ZIXkEF
-YVpoWTmzhqp4KPSmSttvhUd1daIk6SE/GMlGh5GAGvX67SurA+jtw91nrUbrm35E
-0lx2Sz1fAgMBAAECggEAaZIAGRj5n5jM7BBoBVRD7IGQ+gz6jwvQ1lknoRek2ALG
-qnIC2S87Jp8WdCBcr+BVpuJrfi64lPKZgXr7WroTmr8ppecaczLdz5CT6PDqh6DE
-5T3AxInEXEwDzLkCklAJbl0yXFFrLBOyM9LHo/0IxpTkDCHg7SZ4V+Y+shKy0SHY
-k5D1jy/Il2vw5rAq3wIYfs6Yi2MMFXwhOfls4mGT/Ek2zZ0p2KTtZRJtEXL4E0dt
-jiDXnwEpO4/c1bj1WG/BXIs2QMWAnB5LnwNVtf8cRh/jsBIMRPCRB0EgCGqZXPIR
-UDBLSoSOA4eJTmBfaQGUX4JBHNx9NPkCAu7g51ljyQKBgQDAm0sv1lffWTGHKkxC
-+kwM8k0XB5CbnNuOtKpoltEWASeS6Yom0XP9aCHHGXxG8DPeIUacDeuEjLlvy0fQ
-xbiVGuMYA5mBOVQvw6EUdMdfgizoual/TP+sp09/OSDuPbEPgzP6dldoTYuZJGnS
-CBscNufJvurbHThhpEx6ROGCUwKBgQDXGFk5st5NC1hpjDOvUe7B4jtktjbdMcWd
-MzniiMQ1sJOKarLCi8rACyGUaZCuGat7uEjr8yc7llwXHnGJ58UU2NfeK4keWPRP
-GpWnNGVIapTyuzM8kNaZTTZIjwsw2V9ZJmDwl44+0DGZb5PJxOolCPlILyp3V5MD
-1moi/hbPRQKBgH/MSuYx5dpn10olUba7V4zblTUrqtLmEHSvAccmExPzrit31FgP
-cFP7LTZrfZ+gL/o6wBw5zEUGDuDT1BH9r40X6wj7EnbA8FBFEPN+zO9dc6jz0DiM
-gbUwyrnS0TvjKUHuv6V3smWd1nvFwoU/JaXh9IhTqoe66rc3Chuy6qLLAoGAYwTo
-fnFjeSBR8TUDzh/vw/27zd88XpO9H2MnsKu5d+Xz5fK8nGbyTXpSWRpH6n4SvX/W
-whhL5ViQyGvRZOT3i2NP7Q0psHjO72OTpUevoKjALQYUzjr3L9elt71yL2jCRi4u
-zlNWvn/ldXcyF96405fP+nUMHaiJG2knrzg9k+kCgYBbXVhd+L4fMcTpIx40QWAb
-LVcr1z85dF/61nFORgItGsxR1ZZ71wzxiqkx52G9DDEx41wnMgu9SmetwDHbkaSW
-sKSegQ51Ll8MxZuOTWy0fixEUy2314Igulk43+yZjWNf6STRjm7gW/ryEhZ1rfOn
-Lf2PVV8Jo0JLRNLIyEF8yA==
------END PRIVATE KEY-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa_pss_384.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa_pss_384.pem
deleted file mode 100644
index 49f5ca8c5d..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa_pss_384.pem
+++ /dev/null
@@ -1,138 +0,0 @@
-Public Key Info:
- Public Key Algorithm: RSA-PSS
- Hash Algorithm: SHA384
- Salt Length: 48
- Key Security Level: Medium (2048 bits)
-
-modulus:
- 00:e7:f5:99:8b:69:95:62:3a:54:80:b9:4c:21:a3:dc
- 50:b9:ac:8d:50:a4:98:ea:da:87:55:82:2c:c6:68:e4
- 36:6c:7a:b8:1e:21:db:e6:fa:1f:c2:54:3a:c0:8d:2d
- 94:ce:15:66:76:82:d3:27:39:ff:11:f8:19:99:95:6d
- 63:7e:35:3d:17:b6:2d:59:3f:c2:b4:b3:73:75:b8:b2
- e7:9d:4d:7d:0d:98:e3:bb:da:e2:44:69:bd:15:52:0c
- 45:eb:24:70:5d:47:55:79:67:56:1e:4f:2f:d5:e2:8e
- c2:96:db:5f:2b:6e:c5:cf:4f:20:61:6f:22:50:05:8c
- e5:ef:5d:e2:bb:e9:af:79:9d:89:ec:19:b4:ed:7d:e7
- f7:f7:20:b4:b0:7c:57:a2:c4:66:67:bb:e2:29:e3:9c
- 07:9c:b0:df:30:36:40:b2:45:12:ed:53:5d:75:4d:a6
- 04:e4:2f:db:92:96:94:be:cb:e8:ac:ee:8d:28:5d:95
- a6:9f:9c:28:d3:c2:87:5e:7b:72:de:f1:ff:16:f8:49
- e4:9d:de:e7:7a:20:23:69:a4:9f:68:b2:db:b0:fc:fb
- c2:77:0d:41:0a:ff:66:02:ea:9e:6b:c3:09:dd:7c:bc
- 1f:47:66:66:8b:a3:72:e9:94:50:62:97:50:5a:5e:2e
- d3:
-
-public exponent:
- 01:00:01:
-
-private exponent:
- 69:3a:96:ec:92:fa:8c:f4:4f:4f:92:40:42:66:96:d5
- 1c:56:76:49:66:52:65:00:bc:32:83:7a:92:8c:15:33
- c7:64:a8:d0:2a:a6:1b:13:cf:82:96:39:8d:0e:be:e5
- e9:d3:f5:86:bf:f4:d0:af:d3:d2:30:0e:55:09:5f:f5
- a9:d4:b7:21:61:a9:12:fb:04:f6:7b:0e:5f:12:6a:3e
- fe:b2:9f:8f:a2:93:75:ae:67:c5:87:7e:9b:04:7c:c2
- df:58:c9:8c:d7:86:a4:2b:c7:fa:ba:0b:c6:69:20:40
- 90:b5:76:68:3a:b9:8c:41:a6:3b:ed:71:d0:81:a4:17
- f2:a1:1d:b8:b4:6b:01:6d:a2:e7:9a:6e:9f:b5:a1:14
- 61:7c:66:50:dc:e8:27:67:55:36:50:cc:19:d4:c7:71
- d5:8f:a7:5f:96:f1:74:90:a1:38:1c:8d:b6:37:04:23
- 81:70:24:29:62:b6:e4:85:8d:46:e9:4a:a0:26:12:0f
- 40:69:42:25:eb:18:0a:97:93:dc:50:12:85:ff:74:6d
- 71:31:d8:45:f8:94:74:ff:43:55:f6:fc:a3:ce:1e:cb
- b9:d7:b8:2b:e5:c6:ab:d3:ab:77:60:9c:6b:4c:8e:c0
- 67:a2:37:41:a0:b8:ad:4a:bd:20:1c:29:c8:49:cc:69
-
-
-prime1:
- 00:ed:49:8c:54:96:6b:fe:77:60:f1:93:dd:3d:bc:46
- b2:ec:9e:35:20:cc:8f:63:55:66:90:a4:1e:e3:50:b1
- 51:a3:a7:8b:b1:81:cd:93:cf:0d:4a:ac:c0:a1:81:49
- cb:71:0e:6b:4f:16:75:04:ae:89:53:c1:1d:ac:44:bc
- ae:9d:85:85:e9:8c:aa:8e:b9:a8:3e:3d:86:28:b5:c3
- da:35:98:67:70:5a:8b:1f:c2:18:ed:b0:6a:0c:74:b9
- 33:6b:08:e5:93:87:39:b0:44:79:5c:eb:4c:f0:f1:db
- c1:41:76:b0:12:46:38:4f:bd:68:db:70:53:13:e8:5f
- 95:
-
-prime2:
- 00:fa:40:7d:45:ec:7b:68:68:31:02:9a:ef:b7:a4:35
- a5:7d:d0:be:75:82:39:44:5f:31:98:4d:ff:3b:ec:76
- ce:c3:32:f9:d4:ce:bc:be:4c:3a:72:2f:1d:f6:2c:85
- 0d:15:50:2e:14:19:bb:cc:b5:ad:6c:bc:59:3f:a0:ba
- 8b:82:e3:9d:36:93:40:b8:ec:d4:eb:15:59:da:ca:a7
- 10:1e:8e:de:22:c0:96:a5:cb:d3:37:37:4a:4b:58:aa
- 13:76:84:58:21:0b:be:8a:b7:c9:04:fd:d9:99:0e:0c
- 8a:28:52:50:23:9e:df:80:54:db:16:46:34:18:3b:da
- c7:
-
-coefficient:
- 7e:b9:c8:22:2e:b4:07:cd:a1:11:43:4d:48:79:e6:86
- a2:6d:3e:41:85:1e:01:3e:05:77:3d:88:2e:8c:a1:43
- b1:5c:03:3c:d9:37:d8:48:06:fa:bf:de:3e:ad:33:63
- b4:03:f7:84:02:26:22:95:66:03:1d:91:73:20:42:97
- 0e:5d:dd:37:1e:f3:60:80:1b:e4:19:0c:cb:75:bf:30
- fd:38:73:67:9c:c2:68:4c:ff:70:cb:78:6c:b7:5a:1c
- a3:a2:cb:a1:f1:f4:17:06:9b:53:96:c3:19:0f:36:98
- 1e:11:f9:ba:a6:cb:5d:d5:82:ae:43:4f:cd:9e:e3:66
-
-
-exp1:
- 2e:c1:d9:67:29:a4:ea:25:b7:f2:a2:82:6c:11:d7:94
- 96:4f:ae:84:62:0a:b7:36:32:d9:b9:9d:64:89:98:07
- 50:4a:49:9a:96:cb:5d:9e:e5:2d:9b:d0:f1:82:3a:7a
- 5e:32:cb:2e:70:6c:6a:99:c1:f1:c1:12:09:ca:19:ac
- 06:da:32:c3:0c:b6:e7:1c:ea:6c:29:4f:70:62:30:cf
- a4:d3:fd:3e:04:79:79:ae:93:9e:f2:ae:52:fa:05:2c
- 7e:a0:e8:2c:23:ef:58:2e:86:03:ab:52:24:00:64:9f
- 36:39:1f:04:da:d5:69:d1:17:02:76:a5:c8:3c:77:e9
-
-
-exp2:
- 00:84:d4:6a:2a:0d:45:cb:bb:52:18:51:e8:df:8e:d7
- b2:c9:bf:5c:f8:be:70:6b:2c:24:04:f5:91:7e:5b:1b
- 0c:d0:6b:64:54:62:8f:a8:6a:89:b3:45:f3:1f:51:ae
- 25:ad:a4:6b:70:db:df:e4:de:a1:f8:cf:58:87:ff:66
- 44:da:ea:b9:ed:d7:e7:48:c0:dc:9b:13:30:28:83:dc
- 7d:1f:db:31:69:3c:d4:39:98:a0:b9:f4:2d:09:25:3c
- d1:2b:dd:3f:71:fa:eb:de:71:82:cf:95:76:44:59:42
- aa:aa:90:56:5d:31:dc:ec:1f:1e:53:0a:5c:68:68:8c
- cd:
-
-
-Public Key PIN:
- pin-sha256:ehI/YLeqtW2fBULTjESCxxpNnhvQYw9LOVxfrWzyV/g=
-Public Key ID:
- sha256:7a123f60b7aab56d9f0542d38c4482c71a4d9e1bd0630f4b395c5fad6cf257f8
- sha1:7ec2c93bfa8195429459015e334ef8d5735430b0
-
------BEGIN PRIVATE KEY-----
-MIIE7QIBADA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAqEaMBgGCSqGSIb3
-DQEBCDALBglghkgBZQMEAgKiAwIBMASCBKcwggSjAgEAAoIBAQDn9ZmLaZViOlSA
-uUwho9xQuayNUKSY6tqHVYIsxmjkNmx6uB4h2+b6H8JUOsCNLZTOFWZ2gtMnOf8R
-+BmZlW1jfjU9F7YtWT/CtLNzdbiy551NfQ2Y47va4kRpvRVSDEXrJHBdR1V5Z1Ye
-Ty/V4o7ClttfK27Fz08gYW8iUAWM5e9d4rvpr3mdiewZtO195/f3ILSwfFeixGZn
-u+Ip45wHnLDfMDZAskUS7VNddU2mBOQv25KWlL7L6KzujShdlaafnCjTwodee3Le
-8f8W+Enknd7neiAjaaSfaLLbsPz7wncNQQr/ZgLqnmvDCd18vB9HZmaLo3LplFBi
-l1BaXi7TAgMBAAECggEAaTqW7JL6jPRPT5JAQmaW1RxWdklmUmUAvDKDepKMFTPH
-ZKjQKqYbE8+CljmNDr7l6dP1hr/00K/T0jAOVQlf9anUtyFhqRL7BPZ7Dl8Saj7+
-sp+PopN1rmfFh36bBHzC31jJjNeGpCvH+roLxmkgQJC1dmg6uYxBpjvtcdCBpBfy
-oR24tGsBbaLnmm6ftaEUYXxmUNzoJ2dVNlDMGdTHcdWPp1+W8XSQoTgcjbY3BCOB
-cCQpYrbkhY1G6UqgJhIPQGlCJesYCpeT3FAShf90bXEx2EX4lHT/Q1X2/KPOHsu5
-17gr5car06t3YJxrTI7AZ6I3QaC4rUq9IBwpyEnMaQKBgQDtSYxUlmv+d2Dxk909
-vEay7J41IMyPY1VmkKQe41CxUaOni7GBzZPPDUqswKGBSctxDmtPFnUErolTwR2s
-RLyunYWF6YyqjrmoPj2GKLXD2jWYZ3Baix/CGO2wagx0uTNrCOWThzmwRHlc60zw
-8dvBQXawEkY4T71o23BTE+hflQKBgQD6QH1F7HtoaDECmu+3pDWlfdC+dYI5RF8x
-mE3/O+x2zsMy+dTOvL5MOnIvHfYshQ0VUC4UGbvMta1svFk/oLqLguOdNpNAuOzU
-6xVZ2sqnEB6O3iLAlqXL0zc3SktYqhN2hFghC76Kt8kE/dmZDgyKKFJQI57fgFTb
-FkY0GDvaxwKBgC7B2WcppOolt/KigmwR15SWT66EYgq3NjLZuZ1kiZgHUEpJmpbL
-XZ7lLZvQ8YI6el4yyy5wbGqZwfHBEgnKGawG2jLDDLbnHOpsKU9wYjDPpNP9PgR5
-ea6TnvKuUvoFLH6g6Cwj71guhgOrUiQAZJ82OR8E2tVp0RcCdqXIPHfpAoGBAITU
-aioNRcu7UhhR6N+O17LJv1z4vnBrLCQE9ZF+WxsM0GtkVGKPqGqJs0XzH1GuJa2k
-a3Db3+TeofjPWIf/ZkTa6rnt1+dIwNybEzAog9x9H9sxaTzUOZigufQtCSU80Svd
-P3H6695xgs+VdkRZQqqqkFZdMdzsHx5TClxoaIzNAoGAfrnIIi60B82hEUNNSHnm
-hqJtPkGFHgE+BXc9iC6MoUOxXAM82TfYSAb6v94+rTNjtAP3hAImIpVmAx2RcyBC
-lw5d3Tce82CAG+QZDMt1vzD9OHNnnMJoTP9wy3hst1oco6LLofH0FwabU5bDGQ82
-mB4R+bqmy13Vgq5DT82e42Y=
------END PRIVATE KEY-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa_pss_512.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa_pss_512.pem
deleted file mode 100644
index 923f6f92ea..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa_pss_512.pem
+++ /dev/null
@@ -1,138 +0,0 @@
-Public Key Info:
- Public Key Algorithm: RSA-PSS
- Hash Algorithm: SHA512
- Salt Length: 64
- Key Security Level: Medium (2048 bits)
-
-modulus:
- 00:c2:ce:73:69:95:63:26:85:bd:a0:23:25:5c:94:41
- 04:11:84:78:6c:c9:a3:47:13:47:3b:c4:fe:f3:27:6c
- eb:d7:41:a9:4c:e3:15:40:b8:bd:99:02:df:93:a9:bf
- 07:de:a2:f1:d1:1e:49:39:2b:64:c7:5e:bb:c7:dd:30
- 07:3c:10:2c:c9:bd:d9:8f:1e:04:60:c1:92:72:44:e6
- 3c:6e:6d:7f:b7:6f:fa:ab:2f:e3:69:7b:0d:1c:31:d5
- 5e:dd:ab:99:0d:4e:80:69:53:3d:d3:63:04:1f:d6:83
- fa:d7:04:c9:3f:75:9c:95:bd:45:34:39:1d:a0:1d:d7
- 06:8e:60:17:a3:94:8f:e9:30:1e:d2:ee:05:42:a4:08
- 86:b7:93:c2:5c:c2:5e:bc:c0:26:5e:98:56:c3:76:87
- e9:9b:1a:3b:f6:bf:c1:6a:4f:f8:46:ba:0b:a8:3a:5e
- bb:1d:af:e3:f3:9b:f1:b6:18:70:6d:af:30:62:5f:07
- a9:ff:7b:a2:dd:5f:7e:ff:33:19:80:a2:d7:f9:9e:c5
- a5:22:e7:79:3c:b7:ee:4a:33:c7:c4:72:e6:69:fd:ec
- 43:8b:85:86:07:95:15:b9:fe:ed:1c:12:38:ca:ed:cc
- 71:ef:9b:69:11:16:e5:1e:78:e0:b3:4d:4c:b4:79:ea
- 9f:
-
-public exponent:
- 01:00:01:
-
-private exponent:
- 00:84:ed:bb:73:60:ac:b7:ac:ab:28:8a:d3:03:c9:66
- 54:10:60:04:8c:b7:4a:e3:45:14:66:84:96:33:f5:c3
- 2d:6b:45:32:f1:74:43:1c:56:f3:89:65:9c:8a:76:5a
- 14:54:a7:7b:ba:e6:9f:b0:93:1b:c1:af:b3:13:3e:ab
- 77:44:55:05:3a:e4:81:80:57:4b:45:7a:d1:23:88:40
- 53:1c:47:3b:cf:40:6a:1c:46:21:37:e8:ef:99:3d:a8
- 0b:83:d7:84:28:c0:58:7f:86:7d:b9:b0:e7:2f:92:81
- 9c:b8:fc:5b:17:22:7a:26:f3:70:35:a2:83:c4:ae:97
- fa:7e:c6:3f:d2:39:9b:fe:f1:e9:c6:d1:68:3e:ac:26
- b4:69:27:c6:1f:50:fc:ab:32:bb:3c:90:13:7e:5c:c0
- 52:0c:34:5d:f7:bd:dd:84:ca:7c:c7:fe:91:8d:60:fe
- d7:a7:e3:95:46:b2:ce:a1:4b:af:ba:81:e5:52:7c:68
- 65:5b:9c:84:a5:b6:44:0c:28:b7:c4:19:aa:f5:f7:06
- 35:ac:92:fe:1b:12:f9:17:8f:28:b7:d0:66:3b:a8:5e
- 91:6e:c1:06:65:69:97:4e:75:26:59:12:76:3a:3d:9e
- ee:21:b4:df:1e:e5:c1:73:5f:cd:e7:4a:2b:66:d8:cc
- 81:
-
-prime1:
- 00:c8:9b:6c:7f:a0:08:ce:09:9b:2a:ea:f3:2c:62:d1
- ec:1e:61:7f:da:d1:3a:38:a8:31:4c:57:fa:b9:1c:d8
- 27:fc:ff:d7:79:82:f1:3b:3a:b6:93:f3:61:c8:17:e2
- 73:c8:bc:66:ff:98:9d:5e:31:4f:6b:d5:98:d3:1a:eb
- cc:30:ab:f6:ed:1b:62:a4:24:6c:cd:eb:20:9e:d8:52
- 8e:49:b9:47:11:97:2d:0c:89:6c:01:0a:f2:0e:6f:cf
- 57:57:7c:57:ce:06:4b:a2:d1:e4:97:91:b2:3b:ef:2a
- 38:d1:64:ea:6e:b0:57:c0:93:ed:d6:27:ba:dd:9e:53
- 0b:
-
-prime2:
- 00:f8:98:fc:b3:55:a0:27:40:a8:e2:62:3d:80:4b:13
- 10:1c:a7:22:af:3d:47:57:c4:34:8c:76:4e:95:d7:ff
- e8:03:bb:cf:ac:9d:52:3a:c2:d0:91:5f:1c:1d:36:4a
- 7e:9d:6d:81:4a:6e:00:f8:96:85:a1:ab:3f:54:d2:03
- ad:0e:d2:c8:c6:fc:b4:62:7e:ab:57:aa:b7:2c:6b:10
- 01:66:5d:ab:d0:5a:9e:02:5b:ad:e1:ab:be:6e:b4:b4
- d1:61:d1:5f:19:22:5c:f5:4e:9e:bd:25:ab:94:a6:be
- 8c:a5:7a:2d:2f:f9:5f:55:d3:b8:d8:6d:e9:7c:b5:03
- 3d:
-
-coefficient:
- 7a:dc:e4:d8:ed:ce:71:72:63:b3:a8:4d:c0:1d:fa:a2
- 8a:c4:9f:77:1e:5a:e1:17:d3:1a:f8:20:32:54:30:a7
- 0d:69:40:92:d7:d6:43:bf:b5:83:7e:d5:19:44:bd:3c
- 8d:ff:31:ad:8b:bd:6d:ab:a7:34:d7:e3:75:57:02:85
- 8a:c0:78:2d:10:0f:6f:28:da:f7:22:69:40:f4:04:9f
- a5:f9:e2:a9:0d:88:06:b4:f3:3c:5e:c6:8c:96:69:7e
- f6:09:fa:9c:c6:87:de:a2:a5:9b:4d:22:2a:0b:27:7c
- 25:31:26:60:b6:6d:0f:97:6f:48:f2:bf:88:dc:f3:83
-
-
-exp1:
- 1a:20:e4:48:db:37:4a:5e:c5:ef:19:1b:03:34:fb:d2
- 9d:42:65:bc:c2:73:aa:dd:7d:4e:4c:47:43:c5:16:02
- 5f:59:93:5f:28:46:f3:47:fa:6f:da:cb:69:9c:72:ca
- 51:e2:f8:27:62:61:5c:db:5f:54:d4:45:4b:79:be:2c
- a2:4a:43:a7:2e:61:f2:af:2b:dc:c6:3b:41:75:3b:8b
- 7c:de:bc:fa:f5:8d:d0:8c:35:9d:0d:27:e9:e9:76:40
- 12:0d:08:02:b5:9f:34:5d:d2:40:4b:a1:c3:5c:ab:4b
- 2b:3a:d1:ae:09:19:e4:e3:5f:9e:fd:1d:c1:af:d5:71
-
-
-exp2:
- 00:f0:6c:55:08:c3:a8:ee:0d:74:c7:ec:a6:fa:2a:a1
- 37:15:de:f6:86:70:47:4d:34:6e:75:e1:fd:42:a1:f1
- d6:db:b5:89:b5:b1:38:d3:a7:91:ba:e6:36:f4:71:8b
- 3e:44:d6:a1:11:f0:ad:73:bd:6f:63:d9:90:98:61:bc
- 38:64:7b:aa:bd:f7:ac:25:0d:c8:7c:32:98:90:96:c2
- 95:f8:00:63:a8:4f:db:3d:00:99:7c:05:73:58:f1:df
- 66:18:aa:3a:c4:be:1d:15:09:82:2f:ff:fc:9e:f9:5c
- 93:fd:7d:d9:b1:ea:05:2f:a6:61:c0:bf:1b:ef:05:c9
- 29:
-
-
-Public Key PIN:
- pin-sha256:ucGhof6fwEGIty3XlESZXFYnapJIa30Xc+yIYUtVbKY=
-Public Key ID:
- sha256:b9c1a1a1fe9fc04188b72dd79444995c56276a92486b7d1773ec88614b556ca6
- sha1:f0f7effab3260ffefd0c2c57c196d20d0fd4bd3b
-
------BEGIN PRIVATE KEY-----
-MIIE7gIBADA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCA6EaMBgGCSqGSIb3
-DQEBCDALBglghkgBZQMEAgOiAwIBQASCBKgwggSkAgEAAoIBAQDCznNplWMmhb2g
-IyVclEEEEYR4bMmjRxNHO8T+8yds69dBqUzjFUC4vZkC35OpvwfeovHRHkk5K2TH
-XrvH3TAHPBAsyb3Zjx4EYMGSckTmPG5tf7dv+qsv42l7DRwx1V7dq5kNToBpUz3T
-YwQf1oP61wTJP3Wclb1FNDkdoB3XBo5gF6OUj+kwHtLuBUKkCIa3k8Jcwl68wCZe
-mFbDdofpmxo79r/Bak/4RroLqDpeux2v4/Ob8bYYcG2vMGJfB6n/e6LdX37/MxmA
-otf5nsWlIud5PLfuSjPHxHLmaf3sQ4uFhgeVFbn+7RwSOMrtzHHvm2kRFuUeeOCz
-TUy0eeqfAgMBAAECggEBAITtu3NgrLesqyiK0wPJZlQQYASMt0rjRRRmhJYz9cMt
-a0Uy8XRDHFbziWWcinZaFFSne7rmn7CTG8GvsxM+q3dEVQU65IGAV0tFetEjiEBT
-HEc7z0BqHEYhN+jvmT2oC4PXhCjAWH+Gfbmw5y+SgZy4/FsXInom83A1ooPErpf6
-fsY/0jmb/vHpxtFoPqwmtGknxh9Q/KsyuzyQE35cwFIMNF33vd2EynzH/pGNYP7X
-p+OVRrLOoUuvuoHlUnxoZVuchKW2RAwot8QZqvX3BjWskv4bEvkXjyi30GY7qF6R
-bsEGZWmXTnUmWRJ2Oj2e7iG03x7lwXNfzedKK2bYzIECgYEAyJtsf6AIzgmbKurz
-LGLR7B5hf9rROjioMUxX+rkc2Cf8/9d5gvE7OraT82HIF+JzyLxm/5idXjFPa9WY
-0xrrzDCr9u0bYqQkbM3rIJ7YUo5JuUcRly0MiWwBCvIOb89XV3xXzgZLotHkl5Gy
-O+8qONFk6m6wV8CT7dYnut2eUwsCgYEA+Jj8s1WgJ0Co4mI9gEsTEBynIq89R1fE
-NIx2TpXX/+gDu8+snVI6wtCRXxwdNkp+nW2BSm4A+JaFoas/VNIDrQ7SyMb8tGJ+
-q1eqtyxrEAFmXavQWp4CW63hq75utLTRYdFfGSJc9U6evSWrlKa+jKV6LS/5X1XT
-uNht6Xy1Az0CgYAaIORI2zdKXsXvGRsDNPvSnUJlvMJzqt19TkxHQ8UWAl9Zk18o
-RvNH+m/ay2mccspR4vgnYmFc219U1EVLeb4sokpDpy5h8q8r3MY7QXU7i3zevPr1
-jdCMNZ0NJ+npdkASDQgCtZ80XdJAS6HDXKtLKzrRrgkZ5ONfnv0dwa/VcQKBgQDw
-bFUIw6juDXTH7Kb6KqE3Fd72hnBHTTRudeH9QqHx1tu1ibWxONOnkbrmNvRxiz5E
-1qER8K1zvW9j2ZCYYbw4ZHuqvfesJQ3IfDKYkJbClfgAY6hP2z0AmXwFc1jx32YY
-qjrEvh0VCYIv//ye+VyT/X3ZseoFL6ZhwL8b7wXJKQKBgHrc5NjtznFyY7OoTcAd
-+qKKxJ93HlrhF9Ma+CAyVDCnDWlAktfWQ7+1g37VGUS9PI3/Ma2LvW2rpzTX43VX
-AoWKwHgtEA9vKNr3ImlA9ASfpfniqQ2IBrTzPF7GjJZpfvYJ+pzGh96ipZtNIioL
-J3wlMSZgtm0Pl29I8r+I3POD
------END PRIVATE KEY-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa-enc.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa-enc.pem
deleted file mode 100644
index bd4bee0a74..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa-enc.pem
+++ /dev/null
@@ -1,20 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDQjCCAiqgAwIBAgIMWYGU8Ba6TGDaJ+vVMA0GCSqGSIb3DQEBCwUAMCMxITAf
-BgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0xNzA4MDIwOTAxMzZa
-Fw0zNzA3MjgwOTAxMzZaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUZXN0IFNl
-cnZlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALeY49te/YFa6Od8
-0bFjD8k1vJbupBNoqdmiAT9oiHmbzqGKePtqC1XZQOwFe9pBJOuny9fAo2v0hhdU
-sS9PmUzyaP4YOUnWOEpujU4Ntk9jtvWrl7VG0xSE1fcaBkN6+ssvRO3+D3XYoPhT
-u9OxLZNDfmFc5DpuSc31VY2Fq3SVD8vrSrZCh892T0/J0VlX0LGSga/BXUGqJOkm
-ISWgUB/eHTsaKb97cro6VTZyL4tvr+69IM+I4hVg8FRGZWOzj2wuFraMOPnUgjj0
-qk9snA1RP3TZWu+hHCGtY/wXFg7RDEb0nTsh2w0tAvNVYHHPTeore/5T9qQ7VBC7
-KtabDr0CAwEAAaN2MHQwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcD
-ATAPBgNVHQ8BAf8EBQMDByAAMB0GA1UdDgQWBBQwgymoaNHkuh20njTXz48/R+kl
-yDAfBgNVHSMEGDAWgBQrQlWadXqqzBV+2iw7BZXrvFHaQjANBgkqhkiG9w0BAQsF
-AAOCAQEA3kf9yAMYuPlBW2/y7UiKZGu6IVuxpmy+IFKeNIH6MNN9AsEHM1Yx4F1O
-c4UGHxEPoKj5k1cEjiNH4hcaAR/Gukq7efHtf98WGlEp8E8ctjkK6Eu3+hOLHQ01
-YjV76BOkWzOI6DwFYNa71Jae44A8QUFhdq3c874KwwX2VkKcfenb7SzfWn/93DpR
-L899PIzXWggADuRGb2S6L35DNk6sHQR8CwkT/HxZr/xqeAVP0qaXtkSPoPntVw6Z
-MIUFcmC7XbDuyo1Or3iCMgdsuqP88KWDqP7vF2Bu8deES4wQeIGBSl4e6kweesbY
-ASRKL9Qf3tPtKVGp0zvJbfSsOc+wig==
------END CERTIFICATE-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa-sign.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa-sign.pem
deleted file mode 100644
index 09818af868..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa-sign.pem
+++ /dev/null
@@ -1,20 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDQjCCAiqgAwIBAgIMWYGU8DJRSWC13gO8MA0GCSqGSIb3DQEBCwUAMCMxITAf
-BgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0xNzA4MDIwOTAxMzZa
-Fw0zNzA3MjgwOTAxMzZaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUZXN0IFNl
-cnZlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALxfBvZ55WpVQeCh
-tVyd+O/sLueGVkBlYURusklcLCqdthM5QTLBVMOQ2vtxWnZDSHWIvPUPCnPxR8Is
-PvsM8BUqQjyj2d9CcvuNNgwKMIzUA10bQLPQ66ac1T7MU/2A4R+xxJN5ZOp4B+Uw
-EwNAeAVfQ9XZX+HkmVAjKPJiRzmjdzoAslQR0F5zL11gjmS8STwZuJ+2MpUh09VG
-dHJ+LB1CNVfnExwPqR3wd1TQPULXZN3Dx+f0W27gmA4GRitMtLltAljvZzGt6+xh
-byKJJjMnTBWlzFFiP/ggpcPs+q2hW9i3vPCE5eOGdkbDnXJi3aiBxYpTKeS54wGc
-/OkTv5UCAwEAAaN2MHQwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcD
-ATAPBgNVHQ8BAf8EBQMDB4AAMB0GA1UdDgQWBBTXwO7kKzgzAOC9j607abavBMKy
-aTAfBgNVHSMEGDAWgBQrQlWadXqqzBV+2iw7BZXrvFHaQjANBgkqhkiG9w0BAQsF
-AAOCAQEAAYRsE0f2BkOlNWj1SNiwoWkw4Ic6WW1X43yh3L17c5hRLOGPupDngJBA
-EYTmsEfq26XX4mGlKXKgKZW2ijcrIQSkHEjkXHYdU+OI+4xufeNtGMYLijcwVKXM
-mmSe8ERWODdCfzDJSRdLx/NgLeWphMQLaym1TkK29lASyqIbCNATXGnMw3bcMLvU
-cXnjHtNU1tlYtVNCStvm2buy+vdVEGIsusqk+aetniEttBlQcPwuRMvbYmIDuRJP
-Bxsst/t32W+s8Eb2dqbSKm6TucOG5o7oXKH6l15d+ARRJJ3C3nODBvsYgSqg1Vtm
-7H0K9I4dLZoMUb4tWjSA9ckNU0nuKQ==
------END CERTIFICATE-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa_pss_256.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa_pss_256.pem
deleted file mode 100644
index 0ebfa2e204..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa_pss_256.pem
+++ /dev/null
@@ -1,23 +0,0 @@
------BEGIN CERTIFICATE-----
-MIID2jCCApKgAwIBAgIUODLkLENJ2mZJLwlk5OXY6ebyHp8wPQYJKoZIhvcNAQEK
-MDCgDTALBglghkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMC
-ASAwIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxlIFRMUyBUZXN0IENBMB4XDTE4MTAy
-NDA2MDY0MloXDTM4MTAxOTA2MDY0MlowIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxl
-IFRlc3QgU2VydmVyMIIBUjA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAaEa
-MBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgGiAwIBIAOCAQ8AMIIBCgKCAQEAodS9
-1Z/KfuXUf0lSeDPWsC83pKL4SzK179UpnH0urGmwsRoJffGSOq7E0SljG11g000G
-P7x/RsciwpjgLDL7mpTx6rk7N0tEi79gKBNr6TGmD+I9gmCdKIvUY3/hBs/WgaEk
-77SlOgWVFuXGneFuMVaSExbEK1Mgc1eWnXpLvujwUBpVGB7ZafL2teU6mLZ3e/8w
-dJ9tgVVQtT6BjVT2zBc9GxC/aXcJ0di+eRGsO74ZaVyxUE26BAmYdHrjlkhN/Gd6
-NHN2SF5BBWFaaFk5s4aqeCj0pkrbb4VHdXWiJOkhPxjJRoeRgBr1+u0rqwPo7cPd
-Z61G65t+RNJcdks9XwIDAQABo3YwdDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoG
-CCsGAQUFBwMBMA8GA1UdDwEB/wQFAwMHgAAwHQYDVR0OBBYEFAbF9tL09Ej6Z7oS
-/pVe++Ff69FkMB8GA1UdIwQYMBaAFCEaiLbeA8ABgKrbcIiZpo8XzqpsMD0GCSqG
-SIb3DQEBCjAwoA0wCwYJYIZIAWUDBAIBoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFl
-AwQCAaIDAgEgA4IBAQBQJnvKt+zUFenmqBo8zGAUQdNYcIp5JhmTP2JbgWlNjTkj
-Tsc3i/rWKA0pxydWgQPL6VKBPiqFIQcuPEw6D9zQxRQpnOveRDTkDzcLbt/c5asO
-6TpHYqlSujeW7TEH0WLBg0uAHuRUclKYB1/2gSU0MUVtG/sZkh213vEx56F56iqx
-sXFDnt9pyu0tLE0nWWtY3dxGAYJpL1HGZ2ey//Tf0+lsS0t8iH0vAtUmssKJpA79
-76biXCHAVcL07O5jMwrF4v7ki/G7RQRQ+qrL03xBifAzKuczu4Ls++Wg7V4MUERj
-mpw4pbRBam9Sz3uwc1qA+Ul0TCHzMDAFWyMod0ND
------END CERTIFICATE-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa_pss_384.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa_pss_384.pem
deleted file mode 100644
index 3506f48b27..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa_pss_384.pem
+++ /dev/null
@@ -1,23 +0,0 @@
------BEGIN CERTIFICATE-----
-MIID2jCCApKgAwIBAgIUBSXp/i1JJIcj2ytjBNKJ0tbxKjYwPQYJKoZIhvcNAQEK
-MDCgDTALBglghkgBZQMEAgKhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAICogMC
-ATAwIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxlIFRMUyBUZXN0IENBMB4XDTE4MTAy
-NDA3NTY0OVoXDTM4MTAxOTA3NTY0OVowIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxl
-IFRlc3QgU2VydmVyMIIBUjA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAqEa
-MBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgKiAwIBMAOCAQ8AMIIBCgKCAQEA5/WZ
-i2mVYjpUgLlMIaPcULmsjVCkmOrah1WCLMZo5DZsergeIdvm+h/CVDrAjS2UzhVm
-doLTJzn/EfgZmZVtY341PRe2LVk/wrSzc3W4suedTX0NmOO72uJEab0VUgxF6yRw
-XUdVeWdWHk8v1eKOwpbbXytuxc9PIGFvIlAFjOXvXeK76a95nYnsGbTtfef39yC0
-sHxXosRmZ7viKeOcB5yw3zA2QLJFEu1TXXVNpgTkL9uSlpS+y+is7o0oXZWmn5wo
-08KHXnty3vH/FvhJ5J3e53ogI2mkn2iy27D8+8J3DUEK/2YC6p5rwwndfLwfR2Zm
-i6Ny6ZRQYpdQWl4u0wIDAQABo3YwdDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoG
-CCsGAQUFBwMBMA8GA1UdDwEB/wQFAwMHgAAwHQYDVR0OBBYEFH7CyTv6gZVClFkB
-XjNO+NVzVDCwMB8GA1UdIwQYMBaAFKnwXW9hoPAB6HSyWn7UEUMcKonnMD0GCSqG
-SIb3DQEBCjAwoA0wCwYJYIZIAWUDBAICoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFl
-AwQCAqIDAgEwA4IBAQAt1xrrBujilh2NVclsaRoqD+QJ7QhDdFVbS2zBJTVz7nds
-TMu9iU/dXAp2zdsmpXi3mKStgYWS1yjSdyKyBy4v7EwGx5qHrcnMzyfX2BelGDk7
-OYCXGaFweAqRUh8SchYA1+Dlwg7ub+SpGkDnA76LgBcHFoC7AMozLOeY6GNT4qdq
-64+jFvCFrDVC4xMvMB3+vwdlDIIyr9uY3z9Axw35IRPyVHJnyiLu/OIwD7Vw9A4n
-11WrUXZ2fvqJUcSvwqdHRAy1kj9LsagfEXatJ79ZC2En2XhEs+PHTgtqw5UdPk16
-dVIlgPTQ/Te+ttubJPsKOpgKj8YOiNtnEZdzpJUP
------END CERTIFICATE-----
diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa_pss_512.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa_pss_512.pem
deleted file mode 100644
index 51e323b43c..0000000000
--- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa_pss_512.pem
+++ /dev/null
@@ -1,23 +0,0 @@
------BEGIN CERTIFICATE-----
-MIID2jCCApKgAwIBAgIUV12PGXPx0Jj7USRKsKNrWFqJRHEwPQYJKoZIhvcNAQEK
-MDCgDTALBglghkgBZQMEAgOhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIDogMC
-AUAwIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxlIFRMUyBUZXN0IENBMB4XDTE4MTAy
-NDA2MDY0M1oXDTM4MTAxOTA2MDY0M1owIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxl
-IFRlc3QgU2VydmVyMIIBUjA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCA6Ea
-MBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgOiAwIBQAOCAQ8AMIIBCgKCAQEAws5z
-aZVjJoW9oCMlXJRBBBGEeGzJo0cTRzvE/vMnbOvXQalM4xVAuL2ZAt+Tqb8H3qLx
-0R5JOStkx167x90wBzwQLMm92Y8eBGDBknJE5jxubX+3b/qrL+Npew0cMdVe3auZ
-DU6AaVM902MEH9aD+tcEyT91nJW9RTQ5HaAd1waOYBejlI/pMB7S7gVCpAiGt5PC
-XMJevMAmXphWw3aH6ZsaO/a/wWpP+Ea6C6g6Xrsdr+Pzm/G2GHBtrzBiXwep/3ui
-3V9+/zMZgKLX+Z7FpSLneTy37kozx8Ry5mn97EOLhYYHlRW5/u0cEjjK7cxx75tp
-ERblHnjgs01MtHnqnwIDAQABo3YwdDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoG
-CCsGAQUFBwMBMA8GA1UdDwEB/wQFAwMHgAAwHQYDVR0OBBYEFPD37/qzJg/+/Qws
-V8GW0g0P1L07MB8GA1UdIwQYMBaAFKVY4bgN1p+8NOXoPdj6DKWDscBFMD0GCSqG
-SIb3DQEBCjAwoA0wCwYJYIZIAWUDBAIDoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFl
-AwQCA6IDAgFAA4IBAQCVRYStZNCUKNzu+kBiHBVJn5Dbu97s3jHBw0ACphUp+M75
-O1ohoT+ny3wgIJx4sN1Fc80cT24o1V48nI4nJTlgAhYyjYjaMilHpwLP4oLclQX8
-OUoyoTPIIRfP4UNRmxAtH+2eEGieO1QDsYyqsGKR9DeWme4t4dc/NTuZ8/E3UW9C
-m0VO0ev3m8ZGfWANRP0yyjnvke4I5awFur9ncGn3vwZYJLDlV9dwi3B68VUzt4Um
-jz4yhgCU+kOqID/HXgWUCosreQGN+KqungUlENOVvBV4sTfQpnaAJaKpT4zkEYMP
-sRkBrV12dCYh4NIpqDsnjSpWEuDlpT4F3hJx2BqU
------END CERTIFICATE-----
From e356f4ab9d151b2276f989f32aad2c2ca26187dd Mon Sep 17 00:00:00 2001
From: gefeili
Date: Mon, 3 Mar 2025 11:02:36 +1030
Subject: [PATCH 138/890] Pass all test vectors of Mayo
---
.../pqc/crypto/mayo/GF16Utils.java | 281 ++++-
.../pqc/crypto/mayo/MayoEngine.java | 89 +-
.../pqc/crypto/mayo/MayoSigner.java | 1085 +++++++++++++++++
.../bouncycastle/pqc/crypto/mayo/Utils.java | 39 +
.../pqc/crypto/test/AllTests.java | 1 +
.../pqc/crypto/test/MayoTest.java | 53 +-
.../pqc/crypto/test/TestUtils.java | 67 +-
7 files changed, 1545 insertions(+), 70 deletions(-)
create mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java
index 9d42c4a5ca..cdcc073d8e 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java
@@ -1,5 +1,7 @@
package org.bouncycastle.pqc.crypto.mayo;
+import org.bouncycastle.util.Pack;
+
public class GF16Utils
{
@@ -105,7 +107,7 @@ public static void mulAddMUpperTriangularMatXMat(int mVecLimbs, long[] bsMat, by
int a = mat[c * matCols + k] & 0xFF;
// For acc: add into the m-vector at row r, column k.
int accOffset = (r * matCols + k) * mVecLimbs;
- GF16Utils.mVecMulAdd(mVecLimbs, bsMat, bsMatOffset, a, acc, accOffset);
+ mVecMulAdd(mVecLimbs, bsMat, bsMatOffset, a, acc, accOffset);
}
bsMatEntriesUsed++;
}
@@ -162,7 +164,7 @@ public static void mulAddMatTransXMMat(int mVecLimbs, byte[] mat, long[] bsMat,
int a = mat[c * matCols + r] & 0xFF;
// For acc: add into the m-vector at index (r * bsMatCols + k)
int accOffset = (r * bsMatCols + k) * mVecLimbs;
- GF16Utils.mVecMulAdd(mVecLimbs, bsMat, bsMatOffset, a, acc, accOffset);
+ mVecMulAdd(mVecLimbs, bsMat, bsMatOffset, a, acc, accOffset);
}
}
}
@@ -181,5 +183,280 @@ public static void mVecAdd(int mVecLimbs, long[] src, int srcOffset, long[] dest
}
}
+ /**
+ * Multiplies a matrix (given as a byte array) with a bit‐sliced matrix (given as a long array)
+ * and accumulates the result into the acc array.
+ *
+ *
+ * The operation iterates over the rows and columns of the matrix. For each element in the matrix,
+ * it multiplies a corresponding vector (from bsMat) by the scalar value (from mat) and adds the
+ * result to the accumulator vector in acc.
+ *
+ *
+ * @param mVecLimbs the number of limbs (elements) in each vector
+ * @param mat the matrix as a byte array with dimensions [matRows x matCols]
+ * @param bsMat the bit‐sliced matrix as a long array
+ * @param acc the accumulator array (long[]) where results are accumulated
+ * @param matRows the number of rows in the matrix
+ * @param matCols the number of columns in the matrix
+ * @param bsMatCols the number of columns in the bit‐sliced matrix (per block)
+ */
+ public static void mulAddMatXMMat(int mVecLimbs, byte[] mat, long[] bsMat, long[] acc,
+ int matRows, int matCols, int bsMatCols)
+ {
+ for (int r = 0; r < matRows; r++)
+ {
+ for (int c = 0; c < matCols; c++)
+ {
+ // Retrieve the scalar from the matrix for row r and column c.
+ byte matVal = mat[r * matCols + c];
+ for (int k = 0; k < bsMatCols; k++)
+ {
+ // Compute the starting index for the vector in bsMat.
+ int bsMatOffset = mVecLimbs * (c * bsMatCols + k);
+ // Compute the starting index for the accumulator vector in acc.
+ int accOffset = mVecLimbs * (r * bsMatCols + k);
+ // Multiply the vector by the scalar and add the result to the accumulator.
+ mVecMulAdd(mVecLimbs, bsMat, bsMatOffset, matVal, acc, accOffset);
+ }
+ }
+ }
+ }
+
+ public static void mulAddMatXMMat(int mVecLimbs, byte[] mat, long[] bsMat, int bsMatOff, long[] acc,
+ int matRows, int matCols, int bsMatCols)
+ {
+ for (int r = 0; r < matRows; r++)
+ {
+ for (int c = 0; c < matCols; c++)
+ {
+ // Retrieve the scalar from the matrix for row r and column c.
+ byte matVal = mat[r * matCols + c];
+ for (int k = 0; k < bsMatCols; k++)
+ {
+ // Compute the starting index for the vector in bsMat.
+ int bsMatOffset = mVecLimbs * (c * bsMatCols + k) + bsMatOff;
+ // Compute the starting index for the accumulator vector in acc.
+ int accOffset = mVecLimbs * (r * bsMatCols + k);
+ // Multiply the vector by the scalar and add the result to the accumulator.
+ mVecMulAdd(mVecLimbs, bsMat, bsMatOffset, matVal, acc, accOffset);
+ }
+ }
+ }
+ }
+
+ /**
+ * Multiplies m (possibly upper triangular) matrices with the transpose of a single matrix
+ * and adds the result to the accumulator.
+ *
+ *
+ * For each row {@code r} in the bit‑sliced matrix and for each column {@code c} (starting from
+ * {@code triangular * r}) in the bit‑sliced matrix, this method iterates over all rows {@code k}
+ * of the single matrix, and for each element, it multiplies the vector (from {@code bsMat})
+ * by the scalar (from {@code mat}) and adds the result to the corresponding vector in {@code acc}.
+ *
+ *
+ * @param mVecLimbs the number of limbs (elements) in each vector.
+ * @param bsMat the bit‑sliced matrix stored as a long array.
+ * @param mat the matrix stored as a byte array.
+ * @param acc the accumulator array where the results are added.
+ * @param bsMatRows the number of rows in the bit‑sliced matrix.
+ * @param bsMatCols the number of columns in the bit‑sliced matrix.
+ * @param matRows the number of rows in the matrix.
+ * @param triangular if non‑zero, indicates that the matrix is upper triangular (i.e. the loop for {@code c}
+ * starts at {@code triangular * r}).
+ */
+ public static void mulAddMUpperTriangularMatXMatTrans(int mVecLimbs, long[] bsMat, byte[] mat, long[] acc,
+ int bsMatRows, int bsMatCols, int matRows, int triangular)
+ {
+ int bsMatEntriesUsed = 0;
+ for (int r = 0; r < bsMatRows; r++)
+ {
+ // For upper triangular, start c at triangular * r; otherwise, triangular is zero.
+ for (int c = triangular * r; c < bsMatCols; c++)
+ {
+ for (int k = 0; k < matRows; k++)
+ {
+ int bsMatOffset = mVecLimbs * bsMatEntriesUsed;
+ int accOffset = mVecLimbs * (r * matRows + k);
+ // Get the matrix element at row k and column c
+ byte matVal = mat[k * bsMatCols + c];
+ mVecMulAdd(mVecLimbs, bsMat, bsMatOffset, matVal, acc, accOffset);
+ }
+ bsMatEntriesUsed++;
+ }
+ }
+ }
+
+ /**
+ * Multiplies a vector (from bsMat) by an unsigned scalar (from mat) and adds the result
+ * to the corresponding vector in acc.
+ *
+ *
+ * This method corresponds to the C function m_vec_mul_add.
+ * It processes {@code mVecLimbs} elements starting from the given offsets in the source and accumulator arrays.
+ *
+ *
+ * @param mVecLimbs the number of limbs (elements) in the vector
+ * @param bsMat the source array (bit-sliced matrix) of long values
+ * @param bsMatOffset the starting index in bsMat for the vector
+ * @param scalar the scalar value (from mat), as a byte
+ * @param acc the accumulator array where the result is added
+ * @param accOffset the starting index in the accumulator array for the current vector
+ */
+ public static void mVecMulAdd(int mVecLimbs, long[] bsMat, int bsMatOffset, byte scalar, long[] acc, int accOffset)
+ {
+ for (int i = 0; i < mVecLimbs; i++)
+ {
+ acc[accOffset + i] ^= gf16vMulU64(bsMat[bsMatOffset + i], scalar);
+ }
+ }
+
+ /**
+ * GF(16) multiplication mod x^4 + x + 1.
+ *
+ * This method multiplies two elements in GF(16) (represented as integers 0–15)
+ * using carryless multiplication followed by reduction modulo x^4 + x + 1.
+ *
+ * @param a an element in GF(16) (only the lower 4 bits are used)
+ * @param b an element in GF(16) (only the lower 4 bits are used)
+ * @return the product a * b in GF(16)
+ */
+ public static int mulF(int a, int b)
+ {
+ // In C there is a conditional XOR with unsigned_char_blocker to work around
+ // compiler-specific behavior. In Java we can omit it (or define it as needed).
+ // a ^= unsignedCharBlocker; // Omitted in Java
+
+ // Perform carryless multiplication:
+ // Multiply b by each bit of a and XOR the results.
+ int p = ((a & 1) * b) ^
+ ((a & 2) * b) ^
+ ((a & 4) * b) ^
+ ((a & 8) * b);
+
+ // Reduce modulo f(X) = x^4 + x + 1.
+ // Extract the upper nibble (bits 4 to 7).
+ int topP = p & 0xF0;
+ // The reduction: XOR p with (topP shifted right by 4 and by 3) and mask to 4 bits.
+ int out = (p ^ (topP >> 4) ^ (topP >> 3)) & 0x0F;
+ return out;
+ }
+
+ /**
+ * Performs a GF(16) carryless multiplication of a nibble (lower 4 bits of a)
+ * with a 64-bit word b, then reduces modulo the polynomial x⁴ + x + 1 on each byte.
+ *
+ * @param a a GF(16) element (only the low 4 bits are used)
+ * @param b a 64-bit word representing 16 GF(16) elements (packed 4 bits per element)
+ * @return the reduced 64-bit word after multiplication
+ */
+ public static long mulFx8(byte a, long b)
+ {
+ // Convert 'a' to an unsigned int so that bit operations work as expected.
+ int aa = a & 0xFF;
+ // Carryless multiplication: for each bit in 'aa' (considering only the lower 4 bits),
+ // if that bit is set, multiply 'b' (by 1, 2, 4, or 8) and XOR the result.
+ long p = ((aa & 1) * b)
+ ^ ((aa & 2) * b)
+ ^ ((aa & 4) * b)
+ ^ ((aa & 8) * b);
+
+ // Reduction mod (x^4 + x + 1): process each byte in parallel.
+ long topP = p & 0xf0f0f0f0f0f0f0f0L;
+ long out = (p ^ (topP >> 4) ^ (topP >> 3)) & 0x0f0f0f0f0f0f0f0fL;
+ return out;
+ }
+
+ public static void matMul(byte[] a, byte[] b, byte[] c,
+ int colrowAB, int rowA, int colB)
+ {
+ int cIndex = 0;
+ for (int i = 0; i < rowA; i++)
+ {
+ int aRowStart = i * colrowAB;
+ for (int j = 0; j < colB; j++)
+ {
+ c[cIndex++] = lincomb(a, aRowStart, b, j, colrowAB, colB);
+ }
+ }
+ }
+
+ public static void matMul(byte[] a, int aOff, byte[] b, int bOff, byte[] c, int cOff,
+ int colrowAB, int rowA, int colB)
+ {
+ int cIndex = 0;
+ for (int i = 0; i < rowA; i++)
+ {
+ int aRowStart = i * colrowAB;
+ for (int j = 0; j < colB; j++)
+ {
+ c[cOff + cIndex++] = lincomb(a, aOff + aRowStart, b, bOff + j, colrowAB, colB);
+ }
+ }
+ }
+
+
+ private static byte lincomb(byte[] a, int aStart, byte[] b, int bStart,
+ int colrowAB, int colB)
+ {
+ byte result = 0;
+ for (int k = 0; k < colrowAB; k++)
+ {
+ result ^= mulF(a[aStart + k], b[bStart + k * colB]);
+ }
+ return result;
+ }
+
+ public static void matAdd(byte[] a, int aOff, byte[] b, int bOff, byte[] c, int cOff, int m, int n)
+ {
+ for (int i = 0; i < m; i++)
+ {
+ for (int j = 0; j < n; j++)
+ {
+ int idx = i * n + j;
+ c[idx + cOff] = (byte)(a[idx + aOff] ^ b[idx + bOff]);
+ }
+ }
+ }
+
+ // Define the blocker constant as needed (set to 0 if not used).
+ private static final byte UNSIGNED_CHAR_BLOCKER = 0;
+
+ /**
+ * Returns 0x00 if a equals b, otherwise returns 0xFF.
+ * This operation is performed in constant time.
+ *
+ * @param a an 8-bit value
+ * @param b an 8-bit value
+ * @return 0x00 if a == b, 0xFF if a != b
+ */
+ public static byte ctCompare8(byte a, byte b)
+ {
+ // Compute the difference between a and b using XOR.
+ // Masking with 0xFF ensures we work with values in 0..255.
+ int diff = (a ^ b) & 0xFF;
+ // Negate the difference.
+ int negDiff = -diff;
+ // Right shift by 31 bits (since 8*sizeof(uint32_t)-1 equals 31 for 32-bit integers).
+ // If diff is 0, then -diff is 0, and shifting yields 0.
+ // If diff is nonzero, -diff is negative, so the arithmetic shift yields -1 (0xFFFFFFFF),
+ // which when cast to a byte becomes 0xFF.
+ int result = negDiff >> 31;
+ // XOR with UNSIGNED_CHAR_BLOCKER (assumed 0 here) and cast to byte.
+ return (byte)(result ^ UNSIGNED_CHAR_BLOCKER);
+ }
+
+ public static void efUnpackMVector(int legs, long[] packedRow, int packedRowOff, byte[] out)
+ {
+ int outIndex = 0;
+ byte[] bytes = new byte[out.length >> 1];
+ Pack.longToLittleEndian(packedRow, packedRowOff, out.length >> 4, bytes, 0);
+ for (int i = 0; i < legs * 16; i += 2)
+ {
+ out[outIndex++] = (byte)(bytes[i / 2] & 0x0F); // Lower nibble
+ out[outIndex++] = (byte)((bytes[i / 2] >> 4) & 0x0F); // Upper nibble
+ }
+ }
}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoEngine.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoEngine.java
index 51cf98bc74..f93e2848da 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoEngine.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoEngine.java
@@ -91,62 +91,55 @@ public static int AES_128_CTR(byte[] output, int outputByteLen, byte[] key, int
}
public static final int MAYO_OK = 0;
- public static final int PK_SEED_BYTES_MAX = 16; // Adjust as needed
- public static final int O_BYTES_MAX = 312; // Adjust as needed
/**
* Expands the secret key.
*
* @param p the MayoParameters instance.
* @param csk the input secret key seed (byte array).
- * @param sk the Sk object that holds the expanded secret key components.
* @return MAYO_OK on success.
*/
-// public static int mayoExpandSk(MayoParameters p, byte[] csk, MayoPrivateKeyParameter sk)
-// {
-// int ret = MAYO_OK;
-// int totalS = PK_SEED_BYTES_MAX + O_BYTES_MAX;
-// byte[] S = new byte[totalS];
-//
-// // sk.p is the long[] array, sk.O is the byte[] array.
-//
-// long[] P = new long[p.getPkSeedBytes() >> 3];
-// Pack.littleEndianToLong(sk.getP(), 0, P);
-// byte[] O = sk.getO();
-//
-// int param_o = p.getO();
-// int param_v = p.getV();
-// int param_O_bytes = p.getOBytes();
-// int param_pk_seed_bytes = p.getPkSeedBytes();
-// int param_sk_seed_bytes = p.getSkSeedBytes();
-//
-// // In C, seed_sk = csk and seed_pk = S (the beginning of S)
-// byte[] seed_sk = csk;
-// byte[] seed_pk = S; // first param_pk_seed_bytes of S
-//
-// // Generate S = seed_pk || (additional bytes), using SHAKE256.
-// // Output length is param_pk_seed_bytes + param_O_bytes.
-// Utils.shake256(S, param_pk_seed_bytes + param_O_bytes, seed_sk, param_sk_seed_bytes);
-//
-// // Decode the portion of S after the first param_pk_seed_bytes into O.
-// // (In C, this is: decode(S + param_pk_seed_bytes, O, param_v * param_o))
-// Utils.decode(S, param_pk_seed_bytes, O, param_v * param_o);
-//
-// // Expand P1 and P2 into the long array P using seed_pk.
-// MayoEngine.expandP1P2(p, P, seed_pk);
-//
-// // Let P2 start at offset = PARAM_P1_limbs(p)
-// int p1Limbs = p.getP1Limbs();
-// int offsetP2 = p1Limbs;
-//
-// // Compute L_i = (P1 + P1^t)*O + P2.
-// // Here, we assume that P1P1tTimesO writes into the portion of P starting at offsetP2.
-// P1P1tTimesO(p, P, O, P, offsetP2);
-//
-// // Securely clear sensitive temporary data.
-// java.util.Arrays.fill(S, (byte)0);
-// return ret;
-// }
+ public static int mayoExpandSk(MayoParameters p, byte[] csk, long[] P, byte[] O)
+ {
+ int ret = MAYO_OK;
+ int totalS = p.getPkSeedBytes() + p.getOBytes();
+ byte[] S = new byte[totalS];
+
+ // sk.p is the long[] array, sk.O is the byte[] array.
+
+ int param_o = p.getO();
+ int param_v = p.getV();
+ int param_O_bytes = p.getOBytes();
+ int param_pk_seed_bytes = p.getPkSeedBytes();
+ int param_sk_seed_bytes = p.getSkSeedBytes();
+
+ // In C, seed_sk = csk and seed_pk = S (the beginning of S)
+ byte[] seed_sk = csk;
+ byte[] seed_pk = S; // first param_pk_seed_bytes of S
+
+ // Generate S = seed_pk || (additional bytes), using SHAKE256.
+ // Output length is param_pk_seed_bytes + param_O_bytes.
+ Utils.shake256(S, param_pk_seed_bytes + param_O_bytes, seed_sk, param_sk_seed_bytes);
+
+ // Decode the portion of S after the first param_pk_seed_bytes into O.
+ // (In C, this is: decode(S + param_pk_seed_bytes, O, param_v * param_o))
+ Utils.decode(S, param_pk_seed_bytes, O, param_v * param_o);
+
+ // Expand P1 and P2 into the long array P using seed_pk.
+ MayoEngine.expandP1P2(p, P, seed_pk);
+
+ // Let P2 start at offset = PARAM_P1_limbs(p)
+ int p1Limbs = p.getP1Limbs();
+ int offsetP2 = p1Limbs;
+
+ // Compute L_i = (P1 + P1^t)*O + P2.
+ // Here, we assume that P1P1tTimesO writes into the portion of P starting at offsetP2.
+ P1P1tTimesO(p, P, O, P, offsetP2);
+
+ // Securely clear sensitive temporary data.
+ java.util.Arrays.fill(S, (byte)0);
+ return ret;
+ }
/**
* Multiplies and accumulates the product (P1 + P1^t)*O into the accumulator.
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
new file mode 100644
index 0000000000..0b2c9196f2
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
@@ -0,0 +1,1085 @@
+package org.bouncycastle.pqc.crypto.mayo;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.digests.SHAKEDigest;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.pqc.crypto.MessageSigner;
+
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Pack;
+
+public class MayoSigner
+ implements MessageSigner
+{
+ private SecureRandom random;
+ MayoParameters params;
+ MayoEngine engine;
+ private MayoPublicKeyParameter pubKey;
+ private MayoPrivateKeyParameter privKey;
+
+ @Override
+ public void init(boolean forSigning, CipherParameters param)
+ {
+
+ if (forSigning)
+ {
+ pubKey = null;
+
+ if (param instanceof ParametersWithRandom)
+ {
+ ParametersWithRandom withRandom = (ParametersWithRandom)param;
+ privKey = (MayoPrivateKeyParameter)withRandom.getParameters();
+ random = withRandom.getRandom();
+ }
+ else
+ {
+ privKey = (MayoPrivateKeyParameter)param;
+ random = null;
+ }
+ params = privKey.getParameters();
+ }
+ else
+ {
+ pubKey = (MayoPublicKeyParameter)param;
+ params = pubKey.getParameters();
+ privKey = null;
+ random = null;
+ }
+ }
+
+ @Override
+ public byte[] generateSignature(byte[] message)
+ {
+ byte[] tenc = new byte[params.getMBytes()];
+ byte[] t = new byte[params.getM()];
+ byte[] y = new byte[params.getM()];
+ byte[] salt = new byte[params.getSaltBytes()];
+ byte[] V = new byte[params.getK() * params.getVBytes() + params.getRBytes()];
+ byte[] Vdec = new byte[params.getV() * params.getK()];
+ byte[] A = new byte[((params.getM() + 7) / 8 * 8) * (params.getK() * params.getO() + 1)];
+ byte[] x = new byte[params.getK() * params.getN()];
+ byte[] r = new byte[params.getK() * params.getO() + 1];
+ byte[] s = new byte[params.getK() * params.getN()];
+ byte[] tmp = new byte[params.getDigestBytes() + params.getSaltBytes() +
+ params.getSkSeedBytes() + 1];
+ byte[] sig = new byte[params.getSigBytes()];
+
+ try
+ {
+ long[] P = new long[params.getP1Limbs() + params.getP2Limbs()];
+ byte[] O = new byte[params.getV() * params.getO()];
+ // Expand secret key
+ MayoEngine.mayoExpandSk(params, privKey.getSeedSk(), P, O);
+
+ // Hash message
+ SHAKEDigest shake = new SHAKEDigest(256);
+ shake.update(message, 0, message.length);
+ shake.doFinal(tmp, 0, params.getDigestBytes());
+
+ // Generate random salt
+ random.nextBytes(salt);
+
+ System.arraycopy(salt, 0, tmp, params.getDigestBytes(), salt.length);
+
+ // Hash to salt
+ System.arraycopy(privKey.getSeedSk(), 0, tmp, params.getDigestBytes() + params.getSaltBytes(),
+ params.getSkSeedBytes());
+
+ shake.update(tmp, 0, params.getDigestBytes() + params.getSaltBytes() +
+ params.getSkSeedBytes());
+ shake.doFinal(salt, 0, params.getSaltBytes());
+
+ // Hash to t
+ System.arraycopy(salt, 0, tmp, params.getDigestBytes(), params.getSaltBytes());
+ shake.update(tmp, 0, params.getDigestBytes() + params.getSaltBytes());
+ shake.doFinal(tenc, 0, params.getMBytes());
+ Utils.decode(tenc, t, params.getM());
+
+ for (int ctr = 0; ctr <= 255; ctr++)
+ {
+ tmp[tmp.length - 1] = (byte)ctr;
+
+ // Generate V
+ shake.update(tmp, 0, tmp.length);
+ shake.doFinal(V, 0, V.length);
+
+ // Decode vectors
+ for (int i = 0; i < params.getK(); i++)
+ {
+ Utils.decode(V, i * params.getVBytes(), Vdec, i * params.getV(), params.getV());
+ }
+
+ // Compute matrices
+ long[] Mtmp = new long[params.getK() * params.getO() * params.getMVecLimbs()];
+ long[] vPv = new long[params.getK() * params.getK() * params.getMVecLimbs()];
+ computeMandVPV(params, Vdec, P, params.getP1Limbs(), P, Mtmp, vPv);
+
+ computeRHS(params, vPv, t, y);
+ computeA(params, Mtmp, A);
+
+ // Clear trailing bytes
+ for (int i = 0; i < params.getM(); ++i)
+ {
+ A[(i + 1) * (params.getK() * params.getO() + 1) - 1] = 0;
+ }
+
+ Utils.decode(V, params.getK() * params.getVBytes(), r, 0,
+ params.getK() * params.getO());
+
+ if (sampleSolution(params, A, y, r, x) != 0)
+ {
+ break;
+ }
+ else
+ {
+ Arrays.fill(Mtmp, 0L);
+ Arrays.fill(vPv, 0L);
+ }
+ }
+
+ // Compute final signature components
+ byte[] Ox = new byte[params.getV()];
+ for (int i = 0; i < params.getK(); i++)
+ {
+ byte[] vi = Arrays.copyOfRange(Vdec, i * params.getV(),
+ (i + 1) * params.getV());
+ GF16Utils.matMul(O, 0, x, i * params.getO(), Ox, 0,
+ params.getO(), params.getN() - params.getO(), 1);
+ GF16Utils.matAdd(vi, 0, Ox, 0, s, i * params.getN(), params.getV(), 1);
+ System.arraycopy(x, i * params.getO(), s,
+ i * params.getN() + params.getN() - params.getO(), params.getO());
+ }
+
+ // Encode and add salt
+ Utils.encode(s, sig, params.getN() * params.getK());
+ System.arraycopy(salt, 0, sig, sig.length - params.getSaltBytes(),
+ params.getSaltBytes());
+
+ return Arrays.concatenate(sig, message);
+ }
+ finally
+ {
+ // Secure cleanup
+ Arrays.fill(tenc, (byte)0);
+ Arrays.fill(t, (byte)0);
+ Arrays.fill(y, (byte)0);
+ Arrays.fill(salt, (byte)0);
+ Arrays.fill(V, (byte)0);
+ Arrays.fill(Vdec, (byte)0);
+ Arrays.fill(A, (byte)0);
+ Arrays.fill(x, (byte)0);
+ Arrays.fill(r, (byte)0);
+ Arrays.fill(s, (byte)0);
+ Arrays.fill(tmp, (byte)0);
+ }
+ }
+
+
+ @Override
+ public boolean verifySignature(byte[] message, byte[] signature)
+ {
+ final int paramM = params.getM();
+ final int paramN = params.getN();
+ final int paramK = params.getK();
+ final int paramMBytes = params.getMBytes();
+ final int paramSigBytes = params.getSigBytes();
+ final int paramDigestBytes = params.getDigestBytes();
+ final int paramSaltBytes = params.getSaltBytes();
+
+ byte[] tEnc = new byte[params.getMBytes()];
+ byte[] t = new byte[params.getM()];
+ byte[] y = new byte[2 * params.getM()];
+ byte[] s = new byte[params.getK() * params.getN()];
+ long[] pk = new long[params.getP1Limbs() + params.getP2Limbs() + params.getP3Limbs()];
+ byte[] tmp = new byte[params.getDigestBytes() + params.getSaltBytes()];
+ byte[] cpk = pubKey.getEncoded();
+
+ // Expand public key
+ // mayo_expand_pk
+ MayoEngine.expandP1P2(params, pk, cpk);
+ Utils.unpackMVecs(cpk, params.getPkSeedBytes(), pk, params.getP1Limbs() + params.getP2Limbs(), params.getP3Limbs() / params.getMVecLimbs(), params.getM());
+
+ // Split pk into P1, P2, P3
+ int p1Limbs = params.getP1Limbs();
+ int p2Limbs = params.getP2Limbs();
+ int p3Limbs = params.getP3Limbs();
+
+ long[] P1 = new long[p1Limbs];
+ long[] P2 = new long[p2Limbs];
+ long[] P3 = new long[p3Limbs];
+ System.arraycopy(pk, 0, P1, 0, p1Limbs);
+ System.arraycopy(pk, p1Limbs, P2, 0, p2Limbs);
+ System.arraycopy(pk, p1Limbs + p2Limbs, P3, 0, p3Limbs);
+
+ // Hash message
+ Utils.shake256(tmp, paramDigestBytes, message, message.length);
+
+ // Compute t
+ System.arraycopy(signature, paramSigBytes - paramSaltBytes, tmp, paramDigestBytes, paramSaltBytes);
+ Utils.shake256(tEnc, paramMBytes, tmp, paramDigestBytes + paramSaltBytes);
+ Utils.decode(tEnc, t, paramM);
+
+ // Decode signature
+ Utils.decode(signature, s, paramK * paramN);
+
+ // Evaluate public map
+ evalPublicMap(params, s, P1, P2, P3, y);
+
+ // Compare results
+ return Arrays.constantTimeAreEqual(paramM, y, 0, t, 0);
+ }
+
+
+ /**
+ * Computes the product of the matrix P1 (bit-sliced) with the transpose of matrix V and adds the result to acc.
+ *
+ * @param p the parameters object
+ * @param P1 the bit-sliced matrix P1 as a long array
+ * @param V the matrix V as a byte array
+ * @param acc the accumulator array where the result is added
+ */
+ public static void P1TimesVt(MayoParameters p, long[] P1, byte[] V, long[] acc)
+ {
+ int mVecLimbs = p.getMVecLimbs();
+ int paramV = p.getV();
+ int paramK = p.getK();
+ // triangular parameter is set to 1
+ GF16Utils.mulAddMUpperTriangularMatXMatTrans(mVecLimbs, P1, V, acc, paramV, paramV, paramK, 1);
+ }
+
+ /**
+ * Computes the matrices M and VP1V from the given input matrices.
+ *
+ * @param p the parameters object
+ * @param Vdec the decoded V matrix as a byte array
+ * @param L the matrix L as a long array
+ * @param P1 the bit-sliced matrix P1 as a long array
+ * @param VL the output accumulator for VL
+ * @param VP1V the output accumulator for VP1V
+ */
+ public static void computeMandVPV(MayoParameters p, byte[] Vdec, long[] L, int Loff, long[] P1, long[] VL, long[] VP1V)
+ {
+ int paramK = p.getK();
+ int paramV = p.getV();
+ int paramO = p.getO();
+ int mVecLimbs = p.getMVecLimbs();
+
+ // Compute VL: VL = Vdec * L
+ GF16Utils.mulAddMatXMMat(mVecLimbs, Vdec, L, Loff, VL, paramK, paramV, paramO);
+
+ // Compute VP1V:
+ // Allocate temporary array for Pv. Its length is V_MAX * K_MAX * M_VEC_LIMBS_MAX.
+ int size = p.getV() * p.getK() * p.getMVecLimbs();
+ long[] Pv = new long[size]; // automatically initialized to zero in Java
+
+ // Compute Pv = P1 * V^T (using upper triangular multiplication)
+ P1TimesVt(p, P1, Vdec, Pv);
+
+ // Compute VP1V = Vdec * Pv
+ GF16Utils.mulAddMatXMMat(mVecLimbs, Vdec, Pv, VP1V, paramK, paramV, paramK);
+ }
+
+ public static void computeRHS(MayoParameters p, long[] vPv, byte[] t, byte[] y)
+ {
+ final int m = p.getM();
+ final int mVecLimbs = p.getMVecLimbs();
+ final int k = p.getK();
+ final int[] fTail = p.getFTail();
+
+ final int topPos = ((m - 1) % 16) * 4;
+
+ // Zero out tails of m_vecs if necessary
+ if (m % 16 != 0)
+ {
+ long mask = 1L;
+ mask <<= ((m % 16) * 4);
+ mask -= 1;
+ final int kSquared = k * k;
+
+ for (int i = 0; i < kSquared; i++)
+ {
+ int index = i * mVecLimbs + mVecLimbs - 1;
+ vPv[index] &= mask;
+ }
+ }
+
+ long[] temp = new long[mVecLimbs];
+ byte[] tempBytes = new byte[mVecLimbs << 3];
+
+ for (int i = k - 1; i >= 0; i--)
+ {
+ for (int j = i; j < k; j++)
+ {
+ // Multiply by X (shift up 4 bits)
+ int top = (int)((temp[mVecLimbs - 1] >>> topPos) & 0xF);
+ temp[mVecLimbs - 1] <<= 4;
+
+ for (int limb = mVecLimbs - 2; limb >= 0; limb--)
+ {
+ temp[limb + 1] ^= temp[limb] >>> 60;
+ temp[limb] <<= 4;
+ }
+ Pack.longToLittleEndian(temp, tempBytes, 0);
+
+ // Reduce mod f(X)
+ for (int jj = 0; jj < 4; jj++)
+ {
+ int ft = fTail[jj];
+ if (ft == 0)
+ {
+ continue;
+ }
+
+ long product = GF16Utils.mulF(top, ft);
+ if (jj % 2 == 0)
+ {
+ tempBytes[jj / 2] ^= (byte)(product & 0xF);
+ }
+ else
+ {
+ tempBytes[jj / 2] ^= (byte)((product & 0xF) << 4);
+ }
+ }
+ Pack.littleEndianToLong(tempBytes, 0, temp);
+
+ // Extract from vPv and add
+ int matrixIndex = i * k + j;
+ int symmetricIndex = j * k + i;
+ boolean isDiagonal = (i == j);
+
+ for (int limb = 0; limb < mVecLimbs; limb++)
+ {
+ long value = vPv[matrixIndex * mVecLimbs + limb];
+ if (!isDiagonal)
+ {
+ value ^= vPv[symmetricIndex * mVecLimbs + limb];
+ }
+ temp[limb] ^= value;
+ }
+ }
+ }
+ Pack.longToLittleEndian(temp, tempBytes, 0);
+ // Compute y
+ for (int i = 0; i < m; i += 2)
+ {
+ int bytePos = i / 2;
+ y[i] = (byte)(t[i] ^ (tempBytes[bytePos] & 0xF));
+ y[i + 1] = (byte)(t[i + 1] ^ ((tempBytes[bytePos] >>> 4) & 0xF));
+ }
+ }
+
+
+ private static final int F_TAIL_LEN = 4;
+ private static final long EVEN_NIBBLES = 0x0F0F0F0F0F0F0F0FL;
+ private static final long EVEN_BYTES = 0x00FF00FF00FF00FFL;
+ private static final long EVEN_2BYTES = 0x0000FFFF0000FFFFL;
+ private static final long EVEN_HALF = 0x00000000FFFFFFFFL;
+ private static final long LOW_BIT_IN_NIBBLE = 0x1111111111111111L;
+
+ public static void computeA(MayoParameters p, long[] VtL, byte[] AOut)
+ {
+ final int k = p.getK();
+ final int o = p.getO();
+ final int m = p.getM();
+ final int mVecLimbs = p.getMVecLimbs();
+ final int ACols = p.getACols();
+ final byte[] fTailArr = p.getFTailArr();
+
+ int bitsToShift = 0;
+ int wordsToShift = 0;
+ final int MAYO_M_OVER_8 = (m + 7) / 8;
+ final int AWidth = ((o * k + 15) / 16) * 16;
+ long[] A = new long[AWidth * MAYO_M_OVER_8 * 16];
+
+ // Zero out tails of m_vecs if necessary
+ if (m % 16 != 0)
+ {
+ long mask = 1L << ((m % 16) * 4);
+ mask -= 1;
+ for (int i = 0; i < o * k; i++)
+ {
+ int idx = i * mVecLimbs + mVecLimbs - 1;
+ VtL[idx] &= mask;
+ }
+ }
+
+ for (int i = 0; i < k; i++)
+ {
+ for (int j = k - 1; j >= i; j--)
+ {
+ // Process Mj
+ int mjOffset = j * mVecLimbs * o;
+ for (int c = 0; c < o; c++)
+ {
+ for (int limb = 0; limb < mVecLimbs; limb++)
+ {
+ int idx = mjOffset + limb + c * mVecLimbs;
+ long value = VtL[idx];
+
+ int aIndex = o * i + c + (limb + wordsToShift) * AWidth;
+ A[aIndex] ^= value << bitsToShift;
+
+ if (bitsToShift > 0)
+ {
+ A[aIndex + AWidth] ^= value >>> (64 - bitsToShift);
+ }
+ }
+ }
+
+ if (i != j)
+ {
+ // Process Mi
+ int miOffset = i * mVecLimbs * o;
+ for (int c = 0; c < o; c++)
+ {
+ for (int limb = 0; limb < mVecLimbs; limb++)
+ {
+ int idx = miOffset + limb + c * mVecLimbs;
+ long value = VtL[idx];
+
+ int aIndex = o * j + c + (limb + wordsToShift) * AWidth;
+ A[aIndex] ^= value << bitsToShift;
+
+ if (bitsToShift > 0)
+ {
+ A[aIndex + AWidth] ^= value >>> (64 - bitsToShift);
+ }
+ }
+ }
+ }
+
+ bitsToShift += 4;
+ if (bitsToShift == 64)
+ {
+ wordsToShift++;
+ bitsToShift = 0;
+ }
+ }
+ }
+
+ // Transpose blocks
+ for (int c = 0; c < AWidth * ((m + (k + 1) * k / 2 + 15) / 16); c += 16)
+ {
+ transpose16x16Nibbles(A, c);
+ }
+
+ // Generate tab array
+ byte[] tab = new byte[F_TAIL_LEN * 4];
+ for (int i = 0; i < F_TAIL_LEN; i++)
+ {
+ byte ft = fTailArr[i];
+ tab[4 * i] = (byte)GF16Utils.mulF(ft, 1);
+ tab[4 * i + 1] = (byte)GF16Utils.mulF(ft, 2);
+ tab[4 * i + 2] = (byte)GF16Utils.mulF(ft, 4);
+ tab[4 * i + 3] = (byte)GF16Utils.mulF(ft, 8);
+ }
+
+ // Final processing
+ for (int c = 0; c < AWidth; c += 16)
+ {
+ for (int r = m; r < m + (k + 1) * k / 2; r++)
+ {
+ int pos = (r / 16) * AWidth + c + (r % 16);
+ long t0 = A[pos] & LOW_BIT_IN_NIBBLE;
+ long t1 = (A[pos] >>> 1) & LOW_BIT_IN_NIBBLE;
+ long t2 = (A[pos] >>> 2) & LOW_BIT_IN_NIBBLE;
+ long t3 = (A[pos] >>> 3) & LOW_BIT_IN_NIBBLE;
+
+ for (int t = 0; t < F_TAIL_LEN; t++)
+ {
+ int targetRow = r + t - m;
+ int targetPos = (targetRow / 16) * AWidth + c + (targetRow % 16);
+ long xorValue = (t0 * tab[4 * t]) ^ (t1 * tab[4 * t + 1])
+ ^ (t2 * tab[4 * t + 2]) ^ (t3 * tab[4 * t + 3]);
+ A[targetPos] ^= xorValue;
+ }
+ }
+ }
+
+ byte[] Abytes = Pack.longToLittleEndian(A);
+ // Decode to output
+ for (int r = 0; r < m; r += 16)
+ {
+ for (int c = 0; c < ACols - 1; c += 16)
+ {
+ for (int i = 0; i + r < m; i++)
+ {
+ Utils.decode(Abytes, (r * AWidth / 16 + c + i) * 8,
+ AOut, (r + i) * ACols + c,
+ Math.min(16, ACols - 1 - c));
+ }
+ }
+ }
+ }
+
+ private static void transpose16x16Nibbles(long[] M, int offset)
+ {
+ for (int i = 0; i < 16; i += 2)
+ {
+ int idx1 = offset + i;
+ int idx2 = offset + i + 1;
+ long t = ((M[idx1] >>> 4) ^ M[idx2]) & EVEN_NIBBLES;
+ M[idx1] ^= t << 4;
+ M[idx2] ^= t;
+ }
+
+ for (int i = 0; i < 16; i += 4)
+ {
+ int base = offset + i;
+ long t0 = ((M[base] >>> 8) ^ M[base + 2]) & EVEN_BYTES;
+ long t1 = ((M[base + 1] >>> 8) ^ M[base + 3]) & EVEN_BYTES;
+ M[base] ^= t0 << 8;
+ M[base + 1] ^= t1 << 8;
+ M[base + 2] ^= t0;
+ M[base + 3] ^= t1;
+ }
+
+ for (int i = 0; i < 4; i++)
+ {
+ int base = offset + i;
+ long t0 = ((M[base] >>> 16) ^ M[base + 4]) & EVEN_2BYTES;
+ long t1 = ((M[base + 8] >>> 16) ^ M[base + 12]) & EVEN_2BYTES;
+ M[base] ^= t0 << 16;
+ M[base + 8] ^= t1 << 16;
+ M[base + 4] ^= t0;
+ M[base + 12] ^= t1;
+ }
+
+ for (int i = 0; i < 8; i++)
+ {
+ int base = offset + i;
+ long t = ((M[base] >>> 32) ^ M[base + 8]) & EVEN_HALF;
+ M[base] ^= t << 32;
+ M[base + 8] ^= t;
+ }
+ }
+
+ public int sampleSolution(MayoParameters params, byte[] A, byte[] y,
+ byte[] r, byte[] x)
+ {
+ final int k = params.getK();
+ final int o = params.getO();
+ final int m = params.getM();
+ final int aCols = params.getACols();
+
+ // Initialize x with r values
+ System.arraycopy(r, 0, x, 0, k * o);
+
+ // Compute Ar matrix product
+ byte[] Ar = new byte[m];
+// Arrays.fill(Ar, (byte)0);
+
+ // Clear last column of A
+ for (int i = 0; i < m; i++)
+ {
+ A[k * o + i * (k * o + 1)] = 0;
+ }
+ GF16Utils.matMul(A, r, Ar, k * o + 1, m, 1);
+
+ // Update last column of A with y - Ar
+ for (int i = 0; i < m; i++)
+ {
+ A[k * o + i * (k * o + 1)] = (byte)(y[i] ^ Ar[i]);
+ }
+
+ // Perform row echelon form transformation
+ ef(A, m, aCols);
+
+ // Check matrix rank
+ boolean fullRank = false;
+ for (int i = 0; i < aCols - 1; i++)
+ {
+ fullRank |= (A[(m - 1) * aCols + i] != 0);
+ }
+ if (!fullRank)
+ {
+ return 0;
+ }
+
+ // Constant-time back substitution
+ for (int row = m - 1; row >= 0; row--)
+ {
+ byte finished = 0;
+ int colUpperBound = Math.min(row + (32 / (m - row)), k * o);
+
+ for (int col = row; col <= colUpperBound; col++)
+ {
+ byte correctCol = GF16Utils.ctCompare8(A[row * aCols + col], (byte)0);
+ byte mask = (byte)(correctCol & ~finished);
+
+ // Update x[col] using constant-time mask
+ byte u = (byte)(mask & A[row * aCols + aCols - 1]);
+ //System.out.println("x[col]: " + x[col] + ", u: " + u);
+ x[col] ^= u;
+
+
+ // Update matrix entries
+ for (int i = 0; i < row; i += 8)
+ {
+ long tmp = 0;
+ // Pack 8 GF(16) elements into long
+ for (int j = 0; j < 8; j++)
+ {
+ tmp ^= (long)(A[(i + j) * aCols + col] & 0xFF) << (j * 8);
+ }
+
+ // GF(16) multiplication
+ tmp = GF16Utils.mulFx8(u, tmp);
+
+ // Unpack and update
+ for (int j = 0; j < 8; j++)
+ {
+ A[(i + j) * aCols + aCols - 1] ^= (byte)((tmp >> (j * 8)) & 0x0F);
+ }
+ }
+ finished |= correctCol;
+ }
+ }
+ return 1;
+ }
+
+ // Adjust these as needed. In our translation we compute rowLen from ncols.
+ // These blockers are used in the C code for constant-time masking.
+ private static final long UINT64_BLOCKER = 0L;
+ private static final int UNSIGNED_CHAR_BLOCKER = 0; // Not used in our Java version.
+
+ /**
+ * Converts a matrix A (given as a flat array of GF(16) elements, one per byte)
+ * into row echelon form (with ones on the first nonzero entries) in constant time.
+ *
+ * @param A the input matrix, stored rowwise; each element is in [0,15]
+ * @param nrows the number of rows
+ * @param ncols the number of columns (GF(16) elements per row)
+ */
+ public void ef(byte[] A, int nrows, int ncols)
+ {
+ // Each 64-bit long can hold 16 nibbles (16 GF(16) elements).
+ int rowLen = (ncols + 15) / 16;
+
+ // Allocate temporary arrays.
+ long[] pivotRow = new long[rowLen];
+ long[] pivotRow2 = new long[rowLen];
+ // The packed matrix: one contiguous array storing nrows rows, each rowLen longs long.
+ long[] packedA = new long[nrows * rowLen];
+
+ // Pack the matrix rows.
+ for (int i = 0; i < nrows; i++)
+ {
+ long[] packedRow = packRow(A, i, ncols);
+ System.arraycopy(packedRow, 0, packedA, i * rowLen, rowLen);
+ }
+
+ int pivotRowIndex = 0;
+ // Loop over each pivot column (each column corresponds to one GF(16) element)
+ for (int pivotCol = 0; pivotCol < ncols; pivotCol++)
+ {
+ int lowerBound = Math.max(0, pivotCol + nrows - ncols);
+ int upperBound = Math.min(nrows - 1, pivotCol);
+
+ // Zero out pivot row buffers.
+ for (int i = 0; i < rowLen; i++)
+ {
+ pivotRow[i] = 0;
+ pivotRow2[i] = 0;
+ }
+
+ // Try to select a pivot row in constant time.
+ int pivot = 0;
+ long pivotIsZero = -1L; // all bits set (0xFFFFFFFFFFFFFFFF)
+ int searchUpper = Math.min(nrows - 1, upperBound + 32);
+ for (int row = lowerBound; row <= searchUpper; row++)
+ {
+ long isPivotRow = ~ctCompare64(row, pivotRowIndex);
+ long belowPivotRow = ct64IsGreaterThan(row, pivotRowIndex);
+ for (int j = 0; j < rowLen; j++)
+ {
+ // The expression below accumulates (in constant time) the candidate pivot row.
+ pivotRow[j] ^= (isPivotRow | (belowPivotRow & pivotIsZero))
+ & packedA[row * rowLen + j];
+ }
+ // Extract candidate pivot element from the packed row.
+ pivot = mExtractElement(pivotRow, pivotCol);
+ pivotIsZero = ~ctCompare64(pivot, 0);
+ }
+
+ // Multiply the pivot row by the inverse of the pivot element.
+ int inv = inverseF(pivot);
+ vecMulAddU64(rowLen, pivotRow, (byte)inv, pivotRow2);
+
+ // Conditionally write the pivot row back into the correct row (if pivot is nonzero).
+ for (int row = lowerBound; row <= upperBound; row++)
+ {
+ long doCopy = ~ctCompare64(row, pivotRowIndex) & ~pivotIsZero;
+ long doNotCopy = ~doCopy;
+ for (int col = 0; col < rowLen; col++)
+ {
+ // Since the masks are disjoint, addition is equivalent to OR.
+ packedA[row * rowLen + col] =
+ (doNotCopy & packedA[row * rowLen + col]) |
+ (doCopy & pivotRow2[col]);
+ }
+ }
+
+ // Eliminate entries below the pivot.
+ for (int row = lowerBound; row < nrows; row++)
+ {
+ int belowPivot = (row > pivotRowIndex) ? 1 : 0;
+ int eltToElim = mExtractElementFromPacked(packedA, row, rowLen, pivotCol);
+ vecMulAddU64(rowLen, pivotRow2, (byte)(belowPivot * eltToElim), packedA, row * rowLen);
+ }
+
+ // If pivot is nonzero, increment pivotRowIndex.
+ if (pivot != 0)
+ {
+ pivotRowIndex++;
+ }
+ }
+
+ byte[] temp = new byte[params.getO() * params.getK() + 1 + 15];
+ // At this point, packedA holds the row-echelon form of the original matrix.
+ // (Depending on your application you might want to unpack it back to A.)
+ for (int i = 0; i < nrows; i++)
+ {
+ GF16Utils.efUnpackMVector(rowLen, packedA, i * rowLen, temp);
+ for (int j = 0; j < ncols; j++)
+ {
+ A[i * ncols + j] = temp[j];
+ }
+ }
+ }
+
+ /**
+ * Packs one row of GF(16) elements (stored in A) into a long[].
+ * Each long holds 16 GF(16) elements (4 bits each).
+ *
+ * @param A the flat input matrix (row-major)
+ * @param row the row index to pack
+ * @param ncols the number of columns (GF(16) elements) in a row
+ * @return an array of longs representing the packed row.
+ */
+ private static long[] packRow(byte[] A, int row, int ncols)
+ {
+ int rowLen = (ncols + 15) / 16; // number of longs needed for this row
+ long[] packed = new long[rowLen];
+ // Process each 64-bit word (each holds 16 nibbles).
+ for (int word = 0; word < rowLen; word++)
+ {
+ long wordVal = 0;
+ for (int nibble = 0; nibble < 16; nibble++)
+ {
+ int col = word * 16 + nibble;
+ if (col < ncols)
+ {
+ int element = A[row * ncols + col] & 0xF;
+ wordVal |= ((long)element) << (4 * nibble);
+ }
+ }
+ packed[word] = wordVal;
+ }
+ return packed;
+ }
+
+ /**
+ * Constant-time comparison: returns 0 if a==b, else returns all 1s (0xFFFFFFFFFFFFFFFF).
+ */
+ private static long ctCompare64(int a, int b)
+ {
+ // Compute (-(a XOR b)) >> 63 then XOR with UINT64_BLOCKER.
+ long diff = -(long)(a ^ b);
+ long shift = diff >> 63; // arithmetic shift; results in 0 or -1.
+ return shift ^ UINT64_BLOCKER;
+ }
+
+ /**
+ * Returns 0xFFFFFFFFFFFFFFFF if a > b, 0 otherwise.
+ */
+ private static long ct64IsGreaterThan(int a, int b)
+ {
+ long diff = (long)b - (long)a;
+ long shift = diff >> 63;
+ return shift ^ UINT64_BLOCKER;
+ }
+
+ /**
+ * Extracts the GF(16) element at a given column index from a packed row.
+ *
+ * @param in the packed row (array of longs)
+ * @param index the column index (0-indexed)
+ * @return the GF(16) element (an int in 0..15)
+ */
+ private static int mExtractElement(long[] in, int index)
+ {
+ int leg = index / 16;
+ int offset = index % 16;
+ return (int)((in[leg] >>> (4 * offset)) & 0xF);
+ }
+
+ /**
+ * Extracts an element from the packed matrix for a given row and column.
+ *
+ * @param packedA the packed matrix stored in row-major order
+ * @param row the row index
+ * @param rowLen the number of longs per row
+ * @param index the column index
+ * @return the GF(16) element at that position.
+ */
+ private static int mExtractElementFromPacked(long[] packedA, int row, int rowLen, int index)
+ {
+ int leg = index / 16;
+ int offset = index % 16;
+ return (int)((packedA[row * rowLen + leg] >>> (4 * offset)) & 0xF);
+ }
+
+ /**
+ * Computes the multiplicative inverse in GF(16) for a GF(16) element.
+ */
+ private static int inverseF(int a)
+ {
+ // In GF(16), the inverse can be computed via exponentiation.
+ int a2 = mulF(a, a);
+ int a4 = mulF(a2, a2);
+ int a8 = mulF(a4, a4);
+ int a6 = mulF(a2, a4);
+ int a14 = mulF(a8, a6);
+ return a14;
+ }
+
+ /**
+ * GF(16) multiplication mod (x^4 + x + 1).
+ *
+ * Multiplies two GF(16) elements (only the lower 4 bits are used).
+ */
+ public static int mulF(int a, int b)
+ {
+ // Carryless multiply: multiply b by each bit of a and XOR.
+ int p = ((a & 1) * b) ^
+ ((a & 2) * b) ^
+ ((a & 4) * b) ^
+ ((a & 8) * b);
+ // Reduce modulo f(X) = x^4 + x + 1.
+ int topP = p & 0xF0;
+ int out = (p ^ (topP >> 4) ^ (topP >> 3)) & 0x0F;
+ return out;
+ }
+
+ /**
+ * Multiplies each word of the input vector (in) by a GF(16) scalar (a),
+ * then XORs the result into the accumulator vector (acc).
+ *
+ * This version updates the acc array starting at index 0.
+ *
+ * @param legs the number of 64-bit words in the vector.
+ * @param in the input vector.
+ * @param a the GF(16) scalar (as a byte; only low 4 bits used).
+ * @param acc the accumulator vector which is updated.
+ */
+ private static void vecMulAddU64(int legs, long[] in, byte a, long[] acc)
+ {
+ int tab = mulTable(a & 0xFF);
+ long lsbAsk = 0x1111111111111111L;
+ for (int i = 0; i < legs; i++)
+ {
+ long val = ((in[i] & lsbAsk) * (tab & 0xFF))
+ ^ (((in[i] >>> 1) & lsbAsk) * ((tab >>> 8) & 0xF))
+ ^ (((in[i] >>> 2) & lsbAsk) * ((tab >>> 16) & 0xF))
+ ^ (((in[i] >>> 3) & lsbAsk) * ((tab >>> 24) & 0xF));
+ acc[i] ^= val;
+ }
+ }
+
+ /**
+ * Overloaded version of vecMulAddU64 that writes to acc starting at accOffset.
+ *
+ * @param legs the number of 64-bit words.
+ * @param in the input vector.
+ * @param a the GF(16) scalar.
+ * @param acc the accumulator vector.
+ * @param accOffset the starting index in acc.
+ */
+ private static void vecMulAddU64(int legs, long[] in, byte a, long[] acc, int accOffset)
+ {
+ int tab = mulTable(a & 0xFF);
+ long lsbAsk = 0x1111111111111111L;
+ for (int i = 0; i < legs; i++)
+ {
+ long val = ((in[i] & lsbAsk) * (tab & 0xFF))
+ ^ (((in[i] >>> 1) & lsbAsk) * ((tab >>> 8) & 0xF))
+ ^ (((in[i] >>> 2) & lsbAsk) * ((tab >>> 16) & 0xF))
+ ^ (((in[i] >>> 3) & lsbAsk) * ((tab >>> 24) & 0xF));
+ acc[accOffset + i] ^= val;
+ }
+ }
+
+ /**
+ * Computes a multiplication table for nibble-packed vectors.
+ *
+ * Implements arithmetic for GF(16) elements modulo (x^4 + x + 1).
+ *
+ * @param b a GF(16) element (only lower 4 bits are used)
+ * @return a 32-bit integer representing the multiplication table.
+ */
+ private static int mulTable(int b)
+ {
+ int x = b * 0x08040201;
+ int highNibbleMask = 0xf0f0f0f0;
+ int highHalf = x & highNibbleMask;
+ return x ^ (highHalf >>> 4) ^ (highHalf >>> 3);
+ }
+
+ private static void evalPublicMap(MayoParameters p, byte[] s, long[] P1, long[] P2, long[] P3, byte[] eval)
+ {
+ int mVecLimbs = (p.getM() + 15) / 16;
+ long[] SPS = new long[p.getK() * p.getK() * mVecLimbs];
+ mCalculatePsSps(p, P1, P2, P3, s, SPS);
+ byte[] zero = new byte[p.getM()];
+ computeRHS(p, SPS, zero, eval);
+ }
+
+ private static void mCalculatePsSps(MayoParameters p, long[] P1, long[] P2, long[] P3, byte[] s, long[] SPS)
+ {
+ int m = p.getM();
+ int v = p.getV();
+ int o = p.getO();
+ int k = p.getK();
+ int mVecLimbs = (m + 15) / 16;
+
+ long[] PS = new long[p.getN() * p.getK() * mVecLimbs];
+ mayoGenericMCalculatePS(p, P1, P2, P3, s, m, v, o, k, PS);
+ mayoGenericMCalculateSPS(PS, s, m, k, p.getN(), SPS);
+ }
+
+ private static void mayoGenericMCalculatePS(MayoParameters p, long[] P1, long[] P2, long[] P3, byte[] S,
+ int m, int v, int o, int k, long[] PS)
+ {
+ int n = o + v;
+ int mVecLimbs = (m + 15) / 16;
+ long[] accumulator = new long[16 * ((p.getM() + 15) / 16 * p.getK() * p.getN() * mVecLimbs)];
+
+ int p1Used = 0;
+ for (int row = 0; row < v; row++)
+ {
+ for (int j = row; j < v; j++)
+ {
+ for (int col = 0; col < k; col++)
+ {
+ GF16Utils.mVecAdd(mVecLimbs, P1, p1Used * mVecLimbs,
+ accumulator, ((row * k + col) * 16 + (S[col * n + j] & 0xFF)) * mVecLimbs);
+ }
+ p1Used++;
+ }
+
+ for (int j = 0; j < o; j++)
+ {
+ for (int col = 0; col < k; col++)
+ {
+ GF16Utils.mVecAdd(mVecLimbs, P2, (row * o + j) * mVecLimbs,
+ accumulator, ((row * k + col) * 16 + (S[(col * n) + j + v] & 0xFF)) * mVecLimbs);
+ }
+ }
+ }
+
+ int p3Used = 0;
+ for (int row = v; row < n; row++)
+ {
+ for (int j = row; j < n; j++)
+ {
+ for (int col = 0; col < k; col++)
+ {
+ GF16Utils.mVecAdd(mVecLimbs, P3, p3Used * mVecLimbs,
+ accumulator, ((row * k + col) * 16 + (S[col * n + j] & 0xFF)) * mVecLimbs);
+ }
+ p3Used++;
+ }
+ }
+
+ for (int i = 0; i < n * k; i++)
+ {
+ mVecMultiplyBins(mVecLimbs, accumulator, i * 16 * mVecLimbs, PS, i * mVecLimbs);
+ }
+ }
+
+ private static void mayoGenericMCalculateSPS(long[] PS, byte[] S, int m, int k, int n, long[] SPS)
+ {
+ final int mVecLimbs = (m + 15) / 16;
+ final int accumulatorSize = 16 * mVecLimbs * k * k;
+ final long[] accumulator = new long[accumulatorSize];
+
+ // Accumulation phase
+ for (int row = 0; row < k; row++)
+ {
+ for (int j = 0; j < n; j++)
+ {
+ final int sVal = S[row * n + j] & 0xFF; // Unsigned byte value
+ for (int col = 0; col < k; col++)
+ {
+ final int psOffset = (j * k + col) * mVecLimbs;
+ final int accOffset = ((row * k + col) * 16 + sVal) * mVecLimbs;
+ mVecAdd(mVecLimbs, PS, psOffset, accumulator, accOffset);
+ }
+ }
+ }
+
+ // Processing phase
+ for (int i = 0; i < k * k; i++)
+ {
+ mVecMultiplyBins(mVecLimbs, accumulator, i * 16 * mVecLimbs, SPS, i * mVecLimbs);
+ }
+ }
+
+ // Helper method for vector addition (XOR)
+ private static void mVecAdd(int limbs, long[] src, int srcOffset, long[] dest, int destOffset)
+ {
+ for (int i = 0; i < limbs; i++)
+ {
+ dest[destOffset + i] ^= src[srcOffset + i];
+ }
+ }
+
+ // Main bin processing method
+ private static void mVecMultiplyBins(int mVecLimbs, long[] bins, int binOffset, long[] ps, int psOff)
+ {
+ // Series of modular operations as per original C code
+ mVecMulAddXInv(mVecLimbs, bins, binOffset + 5 * mVecLimbs, bins, binOffset + 10 * mVecLimbs);
+ mVecMulAddX(mVecLimbs, bins, binOffset + 11 * mVecLimbs, bins, binOffset + 12 * mVecLimbs);
+ mVecMulAddXInv(mVecLimbs, bins, binOffset + 10 * mVecLimbs, bins, binOffset + 7 * mVecLimbs);
+ mVecMulAddX(mVecLimbs, bins, binOffset + 12 * mVecLimbs, bins, binOffset + 6 * mVecLimbs);
+ mVecMulAddXInv(mVecLimbs, bins, binOffset + 7 * mVecLimbs, bins, binOffset + 14 * mVecLimbs);
+ mVecMulAddX(mVecLimbs, bins, binOffset + 6 * mVecLimbs, bins, binOffset + 3 * mVecLimbs);
+ mVecMulAddXInv(mVecLimbs, bins, binOffset + 14 * mVecLimbs, bins, binOffset + 15 * mVecLimbs);
+ mVecMulAddX(mVecLimbs, bins, binOffset + 3 * mVecLimbs, bins, binOffset + 8 * mVecLimbs);
+ mVecMulAddXInv(mVecLimbs, bins, binOffset + 15 * mVecLimbs, bins, binOffset + 13 * mVecLimbs);
+ mVecMulAddX(mVecLimbs, bins, binOffset + 8 * mVecLimbs, bins, binOffset + 4 * mVecLimbs);
+ mVecMulAddXInv(mVecLimbs, bins, binOffset + 13 * mVecLimbs, bins, binOffset + 9 * mVecLimbs);
+ mVecMulAddX(mVecLimbs, bins, binOffset + 4 * mVecLimbs, bins, binOffset + 2 * mVecLimbs);
+ mVecMulAddXInv(mVecLimbs, bins, binOffset + 9 * mVecLimbs, bins, binOffset + 1 * mVecLimbs);
+ mVecMulAddX(mVecLimbs, bins, binOffset + 2 * mVecLimbs, bins, binOffset + 1 * mVecLimbs);
+ System.arraycopy(bins, mVecLimbs + binOffset, ps, psOff, mVecLimbs);
+ }
+
+ // Modular arithmetic operations
+ private static void mVecMulAddXInv(int limbs, long[] in, int inOffset,
+ long[] acc, int accOffset)
+ {
+ final long maskLsb = 0x1111111111111111L;
+ for (int i = 0; i < limbs; i++)
+ {
+ final long t = in[inOffset + i] & maskLsb;
+ acc[accOffset + i] ^= ((in[inOffset + i] ^ t) >>> 1) ^ (t * 9);
+ }
+ }
+
+ private static void mVecMulAddX(int limbs, long[] in, int inOffset,
+ long[] acc, int accOffset)
+ {
+ final long maskMsb = 0x8888888888888888L;
+ for (int i = 0; i < limbs; i++)
+ {
+ final long t = in[inOffset + i] & maskMsb;
+ acc[accOffset + i] ^= ((in[inOffset + i] ^ t) << 1) ^ ((t >>> 3) * 3);
+ }
+ }
+
+
+}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/Utils.java
index d3de862432..320204911a 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/Utils.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/Utils.java
@@ -33,6 +33,24 @@ public static void decode(byte[] m, byte[] mdec, int mdecLen)
}
}
+ public static void decode(byte[] m, int mOff, byte[] mdec, int decIndex, int mdecLen)
+ {
+ int i;
+ // Process pairs of nibbles from each byte
+ for (i = 0; i < mdecLen / 2; i++)
+ {
+ // Extract the lower nibble
+ mdec[decIndex++] = (byte)((m[i + mOff] & 0xFF) & 0x0F);
+ // Extract the upper nibble (shift right 4 bits)
+ mdec[decIndex++] = (byte)(((m[i + mOff] & 0xFF) >> 4) & 0x0F);
+ }
+ // If there is an extra nibble (odd number of nibbles), decode only the lower nibble
+ if (mdecLen % 2 == 1)
+ {
+ mdec[decIndex] = (byte)((m[i + mOff] & 0xFF) & 0x0F);
+ }
+ }
+
/**
* Decodes a nibble-packed byte array into an output array.
*
@@ -113,6 +131,27 @@ public static void unpackMVecs(byte[] in, long[] out, int vecs, int m)
}
}
+ public static void unpackMVecs(byte[] in, int inOff, long[] out, int outOff, int vecs, int m)
+ {
+ int mVecLimbs = (m + 15) / 16;
+ int bytesToCopy = m / 2; // Number of bytes to copy per vector
+
+ // Process vectors in reverse order
+ for (int i = vecs - 1; i >= 0; i--)
+ {
+ // Temporary buffer to hold mVecLimbs longs (each long is 8 bytes)
+ byte[] tmp = new byte[mVecLimbs * 8];
+ // Copy m/2 bytes from the input into tmp. The rest remains zero.
+ System.arraycopy(in, inOff + i * bytesToCopy, tmp, 0, bytesToCopy);
+
+ // Convert each 8-byte block in tmp into a long using Pack
+ for (int j = 0; j < mVecLimbs; j++)
+ {
+ out[outOff + i * mVecLimbs + j] = Pack.littleEndianToLong(tmp, j * 8);
+ }
+ }
+ }
+
/**
* Packs m-vectors from an array of 64-bit limbs into a packed byte array.
*
diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/AllTests.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/AllTests.java
index 08a3b0e5b4..fbf60a3de7 100644
--- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/AllTests.java
+++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/AllTests.java
@@ -51,6 +51,7 @@ public static Test suite()
suite.addTestSuite(XWingTest.class);
suite.addTestSuite(AllTests.SimpleTestTest.class);
suite.addTestSuite(SLHDSATest.class);
+ suite.addTestSuite(MayoTest.class);
return new BCTestSetup(suite);
}
diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/MayoTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/MayoTest.java
index 8f720f844e..ceb91d4601 100644
--- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/MayoTest.java
+++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/MayoTest.java
@@ -1,15 +1,22 @@
package org.bouncycastle.pqc.crypto.test;
import java.io.IOException;
+import java.security.SecureRandom;
+import java.util.HashMap;
+import java.util.Map;
import junit.framework.TestCase;
import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Signer;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.pqc.crypto.MessageSigner;
import org.bouncycastle.pqc.crypto.mayo.MayoKeyGenerationParameters;
import org.bouncycastle.pqc.crypto.mayo.MayoKeyPairGenerator;
import org.bouncycastle.pqc.crypto.mayo.MayoParameters;
import org.bouncycastle.pqc.crypto.mayo.MayoPrivateKeyParameter;
import org.bouncycastle.pqc.crypto.mayo.MayoPublicKeyParameter;
+import org.bouncycastle.pqc.crypto.mayo.MayoSigner;
public class MayoTest
extends TestCase
@@ -18,7 +25,8 @@ public static void main(String[] args)
throws Exception
{
MayoTest test = new MayoTest();
- test.testKeyGen();
+ test.testTestVectors();
+ //test.testKeyGen();
}
private static final MayoParameters[] PARAMETER_SETS = new MayoParameters[]
@@ -29,21 +37,28 @@ public static void main(String[] args)
MayoParameters.MAYO5
};
- public void testKeyGen()
- throws IOException
+ private static final String[] files = new String[]{
+ "PQCsignKAT_24_MAYO_1.rsp",
+ "PQCsignKAT_24_MAYO_2.rsp",
+ "PQCsignKAT_32_MAYO_3.rsp",
+ "PQCsignKAT_40_MAYO_5.rsp",
+ };
+
+
+ public void testTestVectors()
+ throws Exception
{
- String[] files = new String[]{
- "PQCsignKAT_24_MAYO_1.rsp",
- "PQCsignKAT_24_MAYO_2.rsp",
- "PQCsignKAT_32_MAYO_3.rsp",
- "PQCsignKAT_40_MAYO_5.rsp",
- };
- TestUtils.testKeyGen(false, "pqc/crypto/mayo", files, new TestUtils.KeyGenerationOperation()
+ TestUtils.testTestVector(false, false, "pqc/crypto/mayo", files, new TestUtils.KeyGenerationOperation()
{
@Override
- public AsymmetricCipherKeyPairGenerator getAsymmetricCipherKeyPairGenerator(int fileIndex, byte[] seed)
+ public SecureRandom getSecureRanom(byte[] seed)
+ {
+ return new NISTSecureRandom(seed, null);
+ }
+
+ @Override
+ public AsymmetricCipherKeyPairGenerator getAsymmetricCipherKeyPairGenerator(int fileIndex, SecureRandom random)
{
- NISTSecureRandom random = new NISTSecureRandom(seed, null);
MayoParameters parameters = PARAMETER_SETS[fileIndex];
MayoKeyPairGenerator kpGen = new MayoKeyPairGenerator();
@@ -58,10 +73,22 @@ public byte[] getPublicKeyEncoded(AsymmetricKeyParameter pubParams)
}
@Override
- public byte[] getPrivateKeyEncoded(AsymmetricKeyParameter privParams)
+ public byte[] getPrivateKeyEncoded(CipherParameters privParams)
{
return ((MayoPrivateKeyParameter)privParams).getEncoded();
}
+
+ @Override
+ public Signer getSigner()
+ {
+ return null;
+ }
+
+ @Override
+ public MessageSigner getMessageSigner()
+ {
+ return new MayoSigner();
+ }
});
}
}
diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/TestUtils.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/TestUtils.java
index 966b7bf455..aeb9d09fbf 100644
--- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/TestUtils.java
+++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/TestUtils.java
@@ -6,12 +6,17 @@
import java.io.InputStreamReader;
import java.security.SecureRandom;
import java.util.HashMap;
+import java.util.Map;
import junit.framework.Assert;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Signer;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.pqc.crypto.MessageSigner;
import org.bouncycastle.pqc.crypto.util.PrivateKeyFactory;
import org.bouncycastle.pqc.crypto.util.PrivateKeyInfoFactory;
import org.bouncycastle.pqc.crypto.util.PublicKeyFactory;
@@ -19,7 +24,6 @@
import org.bouncycastle.test.TestResourceFinder;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
-import org.bouncycastle.util.test.FixedSecureRandom;
class TestUtils
{
@@ -30,15 +34,21 @@ static boolean parseBoolean(String value)
public interface KeyGenerationOperation
{
- AsymmetricCipherKeyPairGenerator getAsymmetricCipherKeyPairGenerator(int fileIndex, byte[] seed);
+ SecureRandom getSecureRanom(byte[] seed);
+
+ AsymmetricCipherKeyPairGenerator getAsymmetricCipherKeyPairGenerator(int fileIndex, SecureRandom random);
byte[] getPublicKeyEncoded(AsymmetricKeyParameter pubParams);
- byte[] getPrivateKeyEncoded(AsymmetricKeyParameter privParams);
+ byte[] getPrivateKeyEncoded(CipherParameters privParams);
+
+ Signer getSigner();
+
+ MessageSigner getMessageSigner();
}
- public static void testKeyGen(boolean enableFactory, String homeDir, String[] files, KeyGenerationOperation operation)
- throws IOException
+ public static void testTestVector(boolean enableFactory, boolean isSigner, String homeDir, String[] files, KeyGenerationOperation operation)
+ throws Exception
{
for (int fileIndex = 0; fileIndex != files.length; fileIndex++)
{
@@ -60,17 +70,27 @@ public static void testKeyGen(boolean enableFactory, String homeDir, String[] fi
{
if (buf.size() > 0)
{
+ int count = Integer.parseInt(buf.get("count"));
+ if (count == 99)
+ {
+ System.out.println("break");
+ }
byte[] seed = Hex.decode((String)buf.get("seed"));
byte[] pk = Hex.decode((String)buf.get("pk"));
byte[] sk = Hex.decode((String)buf.get("sk"));
+ byte[] message = Hex.decode((String)buf.get("msg"));
+ byte[] signature = Hex.decode((String)buf.get("sm"));
- AsymmetricCipherKeyPairGenerator kpGen = operation.getAsymmetricCipherKeyPairGenerator(fileIndex, seed);
+ SecureRandom random = operation.getSecureRanom(seed);
+
+ AsymmetricCipherKeyPairGenerator kpGen = operation.getAsymmetricCipherKeyPairGenerator(fileIndex, random);
//
// Generate keys and test.
//
AsymmetricCipherKeyPair kp = kpGen.generateKeyPair();
- AsymmetricKeyParameter pubParams, privParams;
+ AsymmetricKeyParameter pubParams;
+ CipherParameters privParams;
if (enableFactory)
{
pubParams = PublicKeyFactory.createKey(
@@ -86,6 +106,39 @@ public static void testKeyGen(boolean enableFactory, String homeDir, String[] fi
Assert.assertTrue(name + ": public key", Arrays.areEqual(pk, operation.getPublicKeyEncoded(pubParams)));
Assert.assertTrue(name + ": secret key", Arrays.areEqual(sk, operation.getPrivateKeyEncoded(privParams)));
+
+ byte[] sigGenerated;
+ privParams = new ParametersWithRandom(privParams, random);
+ if (isSigner)
+ {
+ Signer signer = operation.getSigner();
+ signer.init(true, privParams);
+ signer.update(message, 0, message.length);
+ sigGenerated = signer.generateSignature();
+ }
+ else
+ {
+ MessageSigner signer = operation.getMessageSigner();
+ signer.init(true, privParams);
+ sigGenerated = signer.generateSignature(message);
+ }
+
+ Assert.assertTrue(Arrays.areEqual(sigGenerated, signature));
+
+ if (isSigner)
+ {
+ Signer signer = operation.getSigner();
+ signer.init(false, pubParams);
+ signer.update(message, 0, message.length);
+ Assert.assertTrue(signer.verifySignature(sigGenerated));
+ }
+ else
+ {
+ MessageSigner signer = operation.getMessageSigner();
+ signer.init(false, pubParams);
+ Assert.assertTrue(signer.verifySignature(message, sigGenerated));
+ }
+ System.out.println("Count " + count + " pass");
}
buf.clear();
continue;
From 01dbe523f48a4af9703ca6c4ad01513f5b630a17 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Mon, 3 Mar 2025 11:51:02 +1030
Subject: [PATCH 139/890] Refactor for Mayo
---
.../pqc/crypto/mayo/GF16Utils.java | 95 +++--------
.../pqc/crypto/mayo/MayoKeyPairGenerator.java | 147 ++++++------------
.../pqc/crypto/mayo/MayoParameters.java | 37 -----
.../pqc/crypto/mayo/MayoSigner.java | 15 +-
.../java/org/bouncycastle/util/Arrays.java | 8 +
.../java/org/bouncycastle/util/Longs.java | 8 +
.../pqc/crypto/test/TestUtils.java | 12 +-
7 files changed, 94 insertions(+), 228 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java
index cdcc073d8e..d7f08cf296 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java
@@ -16,26 +16,25 @@ public class GF16Utils
public static long gf16vMulU64(long a, int b)
{
long maskMsb = 0x8888888888888888L;
- long a64 = a;
// In the original code there is a conditional XOR with unsigned_char_blocker;
// here we simply use b directly.
long b32 = b & 0x00000000FFFFFFFFL;
- long r64 = a64 * (b32 & 1);
+ long r64 = a * (b32 & 1);
- long a_msb = a64 & maskMsb;
- a64 ^= a_msb;
- a64 = (a64 << 1) ^ ((a_msb >>> 3) * 3);
- r64 ^= a64 * ((b32 >> 1) & 1);
+ long a_msb = a & maskMsb;
+ a ^= a_msb;
+ a = (a << 1) ^ ((a_msb >>> 3) * 3);
+ r64 ^= a * ((b32 >> 1) & 1);
- a_msb = a64 & maskMsb;
- a64 ^= a_msb;
- a64 = (a64 << 1) ^ ((a_msb >>> 3) * 3);
- r64 ^= a64 * ((b32 >>> 2) & 1);
+ a_msb = a & maskMsb;
+ a ^= a_msb;
+ a = (a << 1) ^ ((a_msb >>> 3) * 3);
+ r64 ^= a * ((b32 >>> 2) & 1);
- a_msb = a64 & maskMsb;
- a64 ^= a_msb;
- a64 = (a64 << 1) ^ ((a_msb >>> 3) * 3);
- r64 ^= a64 * ((b32 >> 3) & 1);
+ a_msb = a & maskMsb;
+ a ^= a_msb;
+ a = (a << 1) ^ ((a_msb >>> 3) * 3);
+ r64 ^= a * ((b32 >> 3) & 1);
return r64;
}
@@ -61,18 +60,6 @@ public static void mVecMulAdd(int mVecLimbs, long[] in, int inOffset, int a, lon
}
}
- /**
- * Convenience overload of mVecMulAdd that assumes zero offsets.
- *
- * @param mVecLimbs the number of limbs
- * @param in the input vector
- * @param a the GF(16) element to multiply by
- * @param acc the accumulator vector
- */
- public static void mVecMulAdd(int mVecLimbs, long[] in, int a, long[] acc)
- {
- mVecMulAdd(mVecLimbs, in, 0, a, acc, 0);
- }
/**
* Performs the multiplication and accumulation of a block of an upper‐triangular matrix
@@ -156,33 +143,18 @@ public static void mulAddMatTransXMMat(int mVecLimbs, byte[] mat, long[] bsMat,
{
for (int c = 0; c < matRows; c++)
{
+ byte matVal = mat[c * matCols + r];
for (int k = 0; k < bsMatCols; k++)
{
- // For bsMat: the m-vector at index (c * bsMatCols + k)
int bsMatOffset = (c * bsMatCols + k) * mVecLimbs;
- // For mat: element at row c, column r.
- int a = mat[c * matCols + r] & 0xFF;
// For acc: add into the m-vector at index (r * bsMatCols + k)
int accOffset = (r * bsMatCols + k) * mVecLimbs;
- mVecMulAdd(mVecLimbs, bsMat, bsMatOffset, a, acc, accOffset);
+ mVecMulAdd(mVecLimbs, bsMat, bsMatOffset, matVal, acc, accOffset);
}
}
}
}
-
- /**
- * Adds (bitwise XOR) mVecLimbs elements from the source array (starting at srcOffset)
- * into the destination array (starting at destOffset).
- */
- public static void mVecAdd(int mVecLimbs, long[] src, int srcOffset, long[] dest, int destOffset)
- {
- for (int i = 0; i < mVecLimbs; i++)
- {
- dest[destOffset + i] ^= src[srcOffset + i];
- }
- }
-
/**
* Multiplies a matrix (given as a byte array) with a bit‐sliced matrix (given as a long array)
* and accumulates the result into the acc array.
@@ -288,30 +260,6 @@ public static void mulAddMUpperTriangularMatXMatTrans(int mVecLimbs, long[] bsMa
}
}
- /**
- * Multiplies a vector (from bsMat) by an unsigned scalar (from mat) and adds the result
- * to the corresponding vector in acc.
- *
- *
- * This method corresponds to the C function m_vec_mul_add.
- * It processes {@code mVecLimbs} elements starting from the given offsets in the source and accumulator arrays.
- *
- *
- * @param mVecLimbs the number of limbs (elements) in the vector
- * @param bsMat the source array (bit-sliced matrix) of long values
- * @param bsMatOffset the starting index in bsMat for the vector
- * @param scalar the scalar value (from mat), as a byte
- * @param acc the accumulator array where the result is added
- * @param accOffset the starting index in the accumulator array for the current vector
- */
- public static void mVecMulAdd(int mVecLimbs, long[] bsMat, int bsMatOffset, byte scalar, long[] acc, int accOffset)
- {
- for (int i = 0; i < mVecLimbs; i++)
- {
- acc[accOffset + i] ^= gf16vMulU64(bsMat[bsMatOffset + i], scalar);
- }
- }
-
/**
* GF(16) multiplication mod x^4 + x + 1.
*
@@ -339,8 +287,7 @@ public static int mulF(int a, int b)
// Extract the upper nibble (bits 4 to 7).
int topP = p & 0xF0;
// The reduction: XOR p with (topP shifted right by 4 and by 3) and mask to 4 bits.
- int out = (p ^ (topP >> 4) ^ (topP >> 3)) & 0x0F;
- return out;
+ return (p ^ (topP >> 4) ^ (topP >> 3)) & 0x0F;
}
/**
@@ -364,8 +311,7 @@ public static long mulFx8(byte a, long b)
// Reduction mod (x^4 + x + 1): process each byte in parallel.
long topP = p & 0xf0f0f0f0f0f0f0f0L;
- long out = (p ^ (topP >> 4) ^ (topP >> 3)) & 0x0f0f0f0f0f0f0f0fL;
- return out;
+ return (p ^ (topP >> 4) ^ (topP >> 3)) & 0x0f0f0f0f0f0f0f0fL;
}
public static void matMul(byte[] a, byte[] b, byte[] c,
@@ -420,9 +366,6 @@ public static void matAdd(byte[] a, int aOff, byte[] b, int bOff, byte[] c, int
}
}
- // Define the blocker constant as needed (set to 0 if not used).
- private static final byte UNSIGNED_CHAR_BLOCKER = 0;
-
/**
* Returns 0x00 if a equals b, otherwise returns 0xFF.
* This operation is performed in constant time.
@@ -442,9 +385,7 @@ public static byte ctCompare8(byte a, byte b)
// If diff is 0, then -diff is 0, and shifting yields 0.
// If diff is nonzero, -diff is negative, so the arithmetic shift yields -1 (0xFFFFFFFF),
// which when cast to a byte becomes 0xFF.
- int result = negDiff >> 31;
- // XOR with UNSIGNED_CHAR_BLOCKER (assumed 0 here) and cast to byte.
- return (byte)(result ^ UNSIGNED_CHAR_BLOCKER);
+ return (byte) (negDiff >> 31);
}
public static void efUnpackMVector(int legs, long[] packedRow, int packedRowOff, byte[] out)
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
index 96e4e9fb01..80dab0898b 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
@@ -5,7 +5,8 @@
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
import org.bouncycastle.crypto.KeyGenerationParameters;
-import org.bouncycastle.util.Pack;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Longs;
public class MayoKeyPairGenerator
implements AsymmetricCipherKeyPairGenerator
@@ -13,65 +14,53 @@ public class MayoKeyPairGenerator
private MayoParameters p;
private SecureRandom random;
-
public void init(KeyGenerationParameters param)
{
this.p = ((MayoKeyGenerationParameters)param).getParameters();
this.random = param.getRandom();
}
-
@Override
public AsymmetricCipherKeyPair generateKeyPair()
{
- int ret = MayoEngine.MAYO_OK;
+ // Retrieve parameters from p.
+ int mVecLimbs = p.getMVecLimbs();
+ int m = p.getM();
+ int v = p.getV();
+ int o = p.getO();
+ int oBytes = p.getOBytes();
+ int p1Limbs = p.getP1Limbs();
+ int p3Limbs = p.getP3Limbs();
+ int pkSeedBytes = p.getPkSeedBytes();
+ int skSeedBytes = p.getSkSeedBytes();
+
byte[] cpk = new byte[p.getCpkBytes()];
// seed_sk points to csk.
byte[] seed_sk = new byte[p.getCskBytes()];
// Allocate S = new byte[PK_SEED_BYTES_MAX + O_BYTES_MAX]
- byte[] S = new byte[p.getPkSeedBytes() + p.getOBytes()];
+ byte[] seed_pk = new byte[pkSeedBytes + oBytes];
// Allocate P as a long array of size (P1_LIMBS_MAX + P2_LIMBS_MAX)
- long[] P = new long[p.getP1Limbs() + p.getP2Limbs()];
+ long[] P = new long[p1Limbs + p.getP2Limbs()];
// Allocate P3 as a long array of size (O_MAX * O_MAX * M_VEC_LIMBS_MAX), zero-initialized.
- long[] P3 = new long[p.getO() * p.getO() * p.getMVecLimbs()];
-
- // seed_pk will be a reference into S.
- byte[] seed_pk;
+ long[] P3 = new long[o * o * mVecLimbs];
// Allocate O as a byte array of size (V_MAX * O_MAX).
// Here we assume V_MAX is given by p.getV() (or replace with a constant if needed).
- byte[] O = new byte[p.getV() * p.getO()];
-
- // Retrieve parameters from p.
- int m_vec_limbs = p.getMVecLimbs();
- int param_m = p.getM();
- int param_v = p.getV();
- int param_o = p.getO();
- int param_O_bytes = p.getOBytes();
- int param_P1_limbs = p.getP1Limbs();
- int param_P3_limbs = p.getP3Limbs();
- int param_pk_seed_bytes = p.getPkSeedBytes();
- int param_sk_seed_bytes = p.getSkSeedBytes();
-
- // In the C code, P1 is P and P2 is P offset by param_P1_limbs.
- // In Java, we will have functions (like expandP1P2) work on the full array P.
+ byte[] O = new byte[v * o];
// Generate secret key seed (seed_sk) using a secure random generator.
random.nextBytes(seed_sk);
// S ← shake256(seed_sk, pk_seed_bytes + O_bytes)
- Utils.shake256(S, param_pk_seed_bytes + param_O_bytes, seed_sk, param_sk_seed_bytes);
-
- // seed_pk is the beginning of S.
- seed_pk = S;
+ Utils.shake256(seed_pk, pkSeedBytes + oBytes, seed_sk, skSeedBytes);
// o ← Decode_o(S[ param_pk_seed_bytes : param_pk_seed_bytes + O_bytes ])
// Decode nibbles from S starting at offset param_pk_seed_bytes into O,
// with expected output length = param_v * param_o.
- Utils.decode(S, param_pk_seed_bytes, O, param_v * param_o);
+ Utils.decode(seed_pk, pkSeedBytes, O, v * o);
// Expand P1 and P2 into the array P using seed_pk.
MayoEngine.expandP1P2(p, P, seed_pk);
@@ -79,99 +68,57 @@ public AsymmetricCipherKeyPair generateKeyPair()
// For compute_P3, we need to separate P1 and P2.
// Here, we treat P1 as the first param_P1_limbs elements of P,
// and P2 as the remaining elements.
- long[] P1 = P;
- long[] P2 = new long[P.length - param_P1_limbs];
- System.arraycopy(P, param_P1_limbs, P2, 0, P2.length);
-
- // Compute P3, which (in the process) modifies P2.
- computeP3(p, P1, P2, O, P3);
-
- // Store seed_pk into the public key cpk.
- System.arraycopy(seed_pk, 0, cpk, 0, param_pk_seed_bytes);
-
- // Allocate an array for the "upper" part of P3.
- long[] P3_upper = new long[p.getP3Limbs()];
-
- // Compute Upper(P3) and store the result in P3_upper.
- mUpper(p, P3, P3_upper, param_o);
-
- // Pack the m-vectors in P3_upper into cpk (after the seed_pk).
- // The number of m-vectors to pack is (param_P3_limbs / m_vec_limbs),
- // and param_m is used as the m value.
- Utils.packMVecs(P3_upper, cpk, param_pk_seed_bytes, param_P3_limbs / m_vec_limbs, param_m);
- // Securely clear sensitive data.
-// secureClear(O);
-// secureClear(P2);
-// secureClear(P3);
-
- return new AsymmetricCipherKeyPair(new MayoPublicKeyParameter(p, cpk), new MayoPrivateKeyParameter(p, seed_sk));
- }
-
- /**
- * Computes P3 from P1, P2, and O.
- *
- * In C, compute_P3 does:
- * 1. Compute P1*O + P2, storing result in P2.
- * 2. Compute P3 = O^T * (P1*O + P2).
- *
- * @param p the parameter object.
- * @param P1 the P1 matrix as a long[] array.
- * @param P2 the P2 matrix as a long[] array; on output, P1*O is added to it.
- * @param O the O matrix as a byte[] array.
- * @param P3 the output matrix (as a long[] array) which will receive O^T*(P1*O + P2).
- */
- public static void computeP3(MayoParameters p, long[] P1, long[] P2, byte[] O, long[] P3)
- {
- int mVecLimbs = p.getMVecLimbs();
- int paramV = p.getV();
- int paramO = p.getO();
+ long[] P2 = new long[P.length - p1Limbs];
+ System.arraycopy(P, p1Limbs, P2, 0, P2.length);
// Compute P1 * O + P2 and store the result in P2.
- GF16Utils.P1TimesO(p, P1, O, P2);
+ GF16Utils.P1TimesO(p, P, O, P2);
// Compute P3 = O^T * (P1*O + P2).
// Here, treat P2 as the bsMat for the multiplication.
// Dimensions: mat = O (size: paramV x paramO), bsMat = P2 (size: paramV x paramO),
// and acc (P3) will have dimensions: (paramO x paramO), each entry being an m-vector.
- GF16Utils.mulAddMatTransXMMat(mVecLimbs, O, P2, P3, paramV, paramO, paramO);
- }
+ GF16Utils.mulAddMatTransXMMat(mVecLimbs, O, P2, P3, v, o, o);
- /**
- * Reproduces the behavior of the C function m_upper.
- *
- * For each pair (r, c) with 0 <= r <= c < size, it copies the m-vector at
- * position (r, c) from 'in' to the next position in 'out' and, if r != c,
- * it adds (XORs) the m-vector at position (c, r) into that same output vector.
- *
- * @param p the parameter object (used to get mVecLimbs)
- * @param in the input long array (each vector is mVecLimbs in length)
- * @param out the output long array (must be large enough to store all output vectors)
- * @param size the size parameter defining the matrix dimensions.
- */
- public static void mUpper(MayoParameters p, long[] in, long[] out, int size)
- {
- int mVecLimbs = p.getMVecLimbs();
+ // Store seed_pk into the public key cpk.
+ System.arraycopy(seed_pk, 0, cpk, 0, pkSeedBytes);
+
+ // Allocate an array for the "upper" part of P3.
+ long[] P3_upper = new long[p3Limbs];
+
+ // Compute Upper(P3) and store the result in P3_upper.
int mVecsStored = 0;
- for (int r = 0; r < size; r++)
+ for (int r = 0; r < o; r++)
{
- for (int c = r; c < size; c++)
+ for (int c = r; c < o; c++)
{
// Compute the starting index for the (r, c) vector in the input array.
- int srcOffset = mVecLimbs * (r * size + c);
+ int srcOffset = mVecLimbs * (r * o + c);
// Compute the output offset for the current stored vector.
int destOffset = mVecLimbs * mVecsStored;
// Copy the vector at (r, c) into the output.
- System.arraycopy(in, srcOffset, out, destOffset, mVecLimbs);
+ System.arraycopy(P3, srcOffset, P3_upper, destOffset, mVecLimbs);
// If off-diagonal, add (XOR) the vector at (c, r) into the same output vector.
if (r != c)
{
- int srcOffset2 = mVecLimbs * (c * size + r);
- GF16Utils.mVecAdd(mVecLimbs, in, srcOffset2, out, destOffset);
+ int srcOffset2 = mVecLimbs * (c * o + r);
+ Longs.xorTo(mVecLimbs, P3, srcOffset2, P3_upper, destOffset);
}
mVecsStored++;
}
}
+
+ // Pack the m-vectors in P3_upper into cpk (after the seed_pk).
+ // The number of m-vectors to pack is (param_P3_limbs / m_vec_limbs),
+ // and param_m is used as the m value.
+ Utils.packMVecs(P3_upper, cpk, pkSeedBytes, p3Limbs / mVecLimbs, m);
+ // Securely clear sensitive data.
+ Arrays.clear(O);
+ Arrays.clear(P2);
+ Arrays.clear(P3);
+
+ return new AsymmetricCipherKeyPair(new MayoPublicKeyParameter(p, cpk), new MayoPrivateKeyParameter(p, seed_sk));
}
}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoParameters.java
index e6e285167f..23aeac4dfd 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoParameters.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoParameters.java
@@ -247,11 +247,6 @@ public int getP2Bytes()
return P2Bytes;
}
- public int getP3Bytes()
- {
- return P3Bytes;
- }
-
public int getCskBytes()
{
return cskBytes;
@@ -328,37 +323,5 @@ public int getEPKLimbs()
{
return getP1Limbs() + getP2Limbs() + getP3Limbs();
}
-
- @Override
- public String toString()
- {
- return "MayoParameters{" +
- "name='" + name + '\'' +
- ", n=" + n +
- ", m=" + m +
- ", mVecLimbs=" + mVecLimbs +
- ", o=" + o +
- ", v=" + v +
- ", ACols=" + ACols +
- ", k=" + k +
- ", q=" + q +
- ", mBytes=" + mBytes +
- ", OBytes=" + OBytes +
- ", vBytes=" + vBytes +
- ", rBytes=" + rBytes +
- ", P1Bytes=" + P1Bytes +
- ", P2Bytes=" + P2Bytes +
- ", P3Bytes=" + P3Bytes +
- ", cskBytes=" + cskBytes +
- ", cpkBytes=" + cpkBytes +
- ", sigBytes=" + sigBytes +
- ", fTail='{" + fTail[0] + "," + fTail[1] + "," + fTail[2] + "," + fTail[3] + "}'" +
- ", fTailArr='{" + fTailArr[0] + "," + fTailArr[1] + "," + fTailArr[2] + "," + fTailArr[3] + "}'" +
- ", saltBytes=" + saltBytes +
- ", digestBytes=" + digestBytes +
- ", pkSeedBytes=" + pkSeedBytes +
- ", skSeedBytes=" + skSeedBytes +
- '}';
- }
}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
index 0b2c9196f2..f9a727888a 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
@@ -8,6 +8,7 @@
import org.bouncycastle.pqc.crypto.MessageSigner;
import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Longs;
import org.bouncycastle.util.Pack;
public class MayoSigner
@@ -15,7 +16,6 @@ public class MayoSigner
{
private SecureRandom random;
MayoParameters params;
- MayoEngine engine;
private MayoPublicKeyParameter pubKey;
private MayoPrivateKeyParameter privKey;
@@ -62,14 +62,13 @@ public byte[] generateSignature(byte[] message)
byte[] x = new byte[params.getK() * params.getN()];
byte[] r = new byte[params.getK() * params.getO() + 1];
byte[] s = new byte[params.getK() * params.getN()];
- byte[] tmp = new byte[params.getDigestBytes() + params.getSaltBytes() +
- params.getSkSeedBytes() + 1];
+ byte[] tmp = new byte[params.getDigestBytes() + params.getSaltBytes() + params.getSkSeedBytes() + 1];
byte[] sig = new byte[params.getSigBytes()];
+ long[] P = new long[params.getP1Limbs() + params.getP2Limbs()];
+ byte[] O = new byte[params.getV() * params.getO()];
try
{
- long[] P = new long[params.getP1Limbs() + params.getP2Limbs()];
- byte[] O = new byte[params.getV() * params.getO()];
// Expand secret key
MayoEngine.mayoExpandSk(params, privKey.getSeedSk(), P, O);
@@ -964,7 +963,7 @@ private static void mayoGenericMCalculatePS(MayoParameters p, long[] P1, long[]
{
for (int col = 0; col < k; col++)
{
- GF16Utils.mVecAdd(mVecLimbs, P1, p1Used * mVecLimbs,
+ Longs.xorTo(mVecLimbs, P1, p1Used * mVecLimbs,
accumulator, ((row * k + col) * 16 + (S[col * n + j] & 0xFF)) * mVecLimbs);
}
p1Used++;
@@ -974,7 +973,7 @@ private static void mayoGenericMCalculatePS(MayoParameters p, long[] P1, long[]
{
for (int col = 0; col < k; col++)
{
- GF16Utils.mVecAdd(mVecLimbs, P2, (row * o + j) * mVecLimbs,
+ Longs.xorTo(mVecLimbs, P2, (row * o + j) * mVecLimbs,
accumulator, ((row * k + col) * 16 + (S[(col * n) + j + v] & 0xFF)) * mVecLimbs);
}
}
@@ -987,7 +986,7 @@ private static void mayoGenericMCalculatePS(MayoParameters p, long[] P1, long[]
{
for (int col = 0; col < k; col++)
{
- GF16Utils.mVecAdd(mVecLimbs, P3, p3Used * mVecLimbs,
+ Longs.xorTo(mVecLimbs, P3, p3Used * mVecLimbs,
accumulator, ((row * k + col) * 16 + (S[col * n + j] & 0xFF)) * mVecLimbs);
}
p3Used++;
diff --git a/core/src/main/java/org/bouncycastle/util/Arrays.java b/core/src/main/java/org/bouncycastle/util/Arrays.java
index 2067a9adb6..1fbd229188 100644
--- a/core/src/main/java/org/bouncycastle/util/Arrays.java
+++ b/core/src/main/java/org/bouncycastle/util/Arrays.java
@@ -1209,6 +1209,14 @@ public static void clear(int[] data)
}
}
+ public static void clear(long[] data)
+ {
+ if (null != data)
+ {
+ java.util.Arrays.fill(data, 0);
+ }
+ }
+
public static boolean isNullOrContainsNull(Object[] array)
{
if (null == array)
diff --git a/core/src/main/java/org/bouncycastle/util/Longs.java b/core/src/main/java/org/bouncycastle/util/Longs.java
index 443e310f4f..eaaada9b0e 100644
--- a/core/src/main/java/org/bouncycastle/util/Longs.java
+++ b/core/src/main/java/org/bouncycastle/util/Longs.java
@@ -52,4 +52,12 @@ public static Long valueOf(long value)
{
return Long.valueOf(value);
}
+
+ public static void xorTo(int len, long[] x, int xOff, long[] z, int zOff)
+ {
+ for (int i = 0; i < len; ++i)
+ {
+ z[zOff + i] ^= x[xOff + i];
+ }
+ }
}
diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/TestUtils.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/TestUtils.java
index aeb9d09fbf..986de28ed2 100644
--- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/TestUtils.java
+++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/TestUtils.java
@@ -70,11 +70,11 @@ public static void testTestVector(boolean enableFactory, boolean isSigner, Strin
{
if (buf.size() > 0)
{
- int count = Integer.parseInt(buf.get("count"));
- if (count == 99)
- {
- System.out.println("break");
- }
+// int count = Integer.parseInt(buf.get("count"));
+// if (count == 99)
+// {
+// System.out.println("break");
+// }
byte[] seed = Hex.decode((String)buf.get("seed"));
byte[] pk = Hex.decode((String)buf.get("pk"));
byte[] sk = Hex.decode((String)buf.get("sk"));
@@ -138,7 +138,7 @@ public static void testTestVector(boolean enableFactory, boolean isSigner, Strin
signer.init(false, pubParams);
Assert.assertTrue(signer.verifySignature(message, sigGenerated));
}
- System.out.println("Count " + count + " pass");
+ //System.out.println("Count " + count + " pass");
}
buf.clear();
continue;
From d1b12046e6a3e7bec2ac32d6ba25254bfd017cb9 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Mon, 3 Mar 2025 14:20:44 +1030
Subject: [PATCH 140/890] Refactor for Mayo
---
.../pqc/crypto/mayo/GF16Utils.java | 48 +--
.../pqc/crypto/mayo/MayoKeyPairGenerator.java | 4 +-
.../pqc/crypto/mayo/MayoParameters.java | 20 +-
.../pqc/crypto/mayo/MayoSigner.java | 406 ++++++------------
.../pqc/crypto/test/MayoTest.java | 3 +
5 files changed, 153 insertions(+), 328 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java
index d7f08cf296..f17d0608da 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java
@@ -101,27 +101,6 @@ public static void mulAddMUpperTriangularMatXMat(int mVecLimbs, long[] bsMat, by
}
}
- /**
- * Computes P1_times_O.
- *
- * In C:
- * P1_times_O(p, P1, O, acc) calls:
- * mul_add_m_upper_triangular_mat_x_mat(PARAM_m_vec_limbs(p), P1, O, acc, PARAM_v(p), PARAM_v(p), PARAM_o(p), 1);
- *
- * @param p the parameter object.
- * @param P1 the P1 matrix as a long[] array.
- * @param O the O matrix as a byte[] array.
- * @param acc the output accumulator (long[] array).
- */
- public static void P1TimesO(MayoParameters p, long[] P1, byte[] O, long[] acc)
- {
- int mVecLimbs = p.getMVecLimbs();
- int paramV = p.getV();
- int paramO = p.getO();
- // Here, bsMatRows and bsMatCols are both paramV, and matCols is paramO, triangular=1.
- mulAddMUpperTriangularMatXMat(mVecLimbs, P1, O, acc, paramV, paramV, paramO, 1);
- }
-
/**
* Multiplies the transpose of a single matrix with m matrices and adds the result into acc.
*
@@ -304,10 +283,7 @@ public static long mulFx8(byte a, long b)
int aa = a & 0xFF;
// Carryless multiplication: for each bit in 'aa' (considering only the lower 4 bits),
// if that bit is set, multiply 'b' (by 1, 2, 4, or 8) and XOR the result.
- long p = ((aa & 1) * b)
- ^ ((aa & 2) * b)
- ^ ((aa & 4) * b)
- ^ ((aa & 8) * b);
+ long p = ((aa & 1) * b) ^ ((aa & 2) * b) ^ ((aa & 4) * b) ^ ((aa & 8) * b);
// Reduction mod (x^4 + x + 1): process each byte in parallel.
long topP = p & 0xf0f0f0f0f0f0f0f0L;
@@ -366,28 +342,6 @@ public static void matAdd(byte[] a, int aOff, byte[] b, int bOff, byte[] c, int
}
}
- /**
- * Returns 0x00 if a equals b, otherwise returns 0xFF.
- * This operation is performed in constant time.
- *
- * @param a an 8-bit value
- * @param b an 8-bit value
- * @return 0x00 if a == b, 0xFF if a != b
- */
- public static byte ctCompare8(byte a, byte b)
- {
- // Compute the difference between a and b using XOR.
- // Masking with 0xFF ensures we work with values in 0..255.
- int diff = (a ^ b) & 0xFF;
- // Negate the difference.
- int negDiff = -diff;
- // Right shift by 31 bits (since 8*sizeof(uint32_t)-1 equals 31 for 32-bit integers).
- // If diff is 0, then -diff is 0, and shifting yields 0.
- // If diff is nonzero, -diff is negative, so the arithmetic shift yields -1 (0xFFFFFFFF),
- // which when cast to a byte becomes 0xFF.
- return (byte) (negDiff >> 31);
- }
-
public static void efUnpackMVector(int legs, long[] packedRow, int packedRowOff, byte[] out)
{
int outIndex = 0;
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
index 80dab0898b..dac5454c11 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
@@ -72,7 +72,9 @@ public AsymmetricCipherKeyPair generateKeyPair()
System.arraycopy(P, p1Limbs, P2, 0, P2.length);
// Compute P1 * O + P2 and store the result in P2.
- GF16Utils.P1TimesO(p, P, O, P2);
+// GF16Utils.P1TimesO(p, P, O, P2);
+ // Here, bsMatRows and bsMatCols are both paramV, and matCols is paramO, triangular=1.
+ GF16Utils.mulAddMUpperTriangularMatXMat(mVecLimbs, P, O, P2, v, v, o, 1);
// Compute P3 = O^T * (P1*O + P2).
// Here, treat P2 as the bsMat for the multiplication.
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoParameters.java
index 23aeac4dfd..f1a1def99d 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoParameters.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoParameters.java
@@ -18,7 +18,7 @@ public class MayoParameters
40, // r_bytes
120159, // P1_bytes
24336, // P2_bytes
- 1404, // P3_bytes
+ // P3_bytes
24, // csk_bytes
1420, // cpk_bytes
454, // sig_bytes
@@ -46,7 +46,7 @@ public class MayoParameters
34, // r_bytes
66560, // P1_bytes
34816, // P2_bytes
- 4896, // P3_bytes
+ // P3_bytes
24, // csk_bytes
4912, // cpk_bytes
186, // sig_bytes
@@ -74,7 +74,7 @@ public class MayoParameters
55, // r_bytes
317844, // P1_bytes
58320, // P2_bytes
- 2970, // P3_bytes
+ // P3_bytes
32, // csk_bytes
2986, // cpk_bytes
681, // sig_bytes
@@ -102,7 +102,7 @@ public class MayoParameters
72, // r_bytes
720863, // P1_bytes
120984, // P2_bytes
- 5538, // P3_bytes
+ // P3_bytes
40, // csk_bytes
5554, // cpk_bytes
964, // sig_bytes
@@ -129,7 +129,6 @@ public class MayoParameters
private final int rBytes;
private final int P1Bytes;
private final int P2Bytes;
- private final int P3Bytes;
private final int cskBytes;
private final int cpkBytes;
private final int sigBytes;
@@ -141,7 +140,7 @@ public class MayoParameters
private final int skSeedBytes;
private MayoParameters(String name, int n, int m, int mVecLimbs, int o, int v, int ACols, int k, int q,
- int mBytes, int OBytes, int vBytes, int rBytes, int P1Bytes, int P2Bytes, int P3Bytes,
+ int mBytes, int OBytes, int vBytes, int rBytes, int P1Bytes, int P2Bytes,
int cskBytes, int cpkBytes, int sigBytes, int[] fTail, byte[] fTailArr,
int saltBytes, int digestBytes, int pkSeedBytes, int skSeedBytes)
{
@@ -160,7 +159,6 @@ private MayoParameters(String name, int n, int m, int mVecLimbs, int o, int v, i
this.rBytes = rBytes;
this.P1Bytes = P1Bytes;
this.P2Bytes = P2Bytes;
- this.P3Bytes = P3Bytes;
this.cskBytes = cskBytes;
this.cpkBytes = cpkBytes;
this.sigBytes = sigBytes;
@@ -315,13 +313,5 @@ public int getP3Limbs()
{
return ((o * (o + 1)) / 2) * mVecLimbs;
}
-
- /**
- * Computes: P1_limbs + P2_limbs + P3_limbs
- */
- public int getEPKLimbs()
- {
- return getP1Limbs() + getP2Limbs() + getP3Limbs();
- }
}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
index f9a727888a..a68d01d15c 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
@@ -52,20 +52,27 @@ public void init(boolean forSigning, CipherParameters param)
@Override
public byte[] generateSignature(byte[] message)
{
+ int k = params.getK();
+ int v = params.getV();
+ int o = params.getO();
+ int saltBytes = params.getSaltBytes();
+ int mVecLimbs = params.getMVecLimbs();
byte[] tenc = new byte[params.getMBytes()];
byte[] t = new byte[params.getM()];
byte[] y = new byte[params.getM()];
- byte[] salt = new byte[params.getSaltBytes()];
- byte[] V = new byte[params.getK() * params.getVBytes() + params.getRBytes()];
- byte[] Vdec = new byte[params.getV() * params.getK()];
- byte[] A = new byte[((params.getM() + 7) / 8 * 8) * (params.getK() * params.getO() + 1)];
- byte[] x = new byte[params.getK() * params.getN()];
- byte[] r = new byte[params.getK() * params.getO() + 1];
- byte[] s = new byte[params.getK() * params.getN()];
- byte[] tmp = new byte[params.getDigestBytes() + params.getSaltBytes() + params.getSkSeedBytes() + 1];
+ byte[] salt = new byte[saltBytes];
+ byte[] V = new byte[k * params.getVBytes() + params.getRBytes()];
+ byte[] Vdec = new byte[v * k];
+ byte[] A = new byte[((params.getM() + 7) / 8 * 8) * (k * o + 1)];
+ byte[] x = new byte[k * params.getN()];
+ byte[] r = new byte[k * o + 1];
+ byte[] s = new byte[k * params.getN()];
+ byte[] tmp = new byte[params.getDigestBytes() + saltBytes + params.getSkSeedBytes() + 1];
byte[] sig = new byte[params.getSigBytes()];
long[] P = new long[params.getP1Limbs() + params.getP2Limbs()];
- byte[] O = new byte[params.getV() * params.getO()];
+ byte[] O = new byte[v * o];
+ long[] Mtmp = new long[k * o * params.getMVecLimbs()];
+ long[] vPv = new long[k * k * params.getMVecLimbs()];
try
{
@@ -83,16 +90,16 @@ public byte[] generateSignature(byte[] message)
System.arraycopy(salt, 0, tmp, params.getDigestBytes(), salt.length);
// Hash to salt
- System.arraycopy(privKey.getSeedSk(), 0, tmp, params.getDigestBytes() + params.getSaltBytes(),
+ System.arraycopy(privKey.getSeedSk(), 0, tmp, params.getDigestBytes() + saltBytes,
params.getSkSeedBytes());
- shake.update(tmp, 0, params.getDigestBytes() + params.getSaltBytes() +
+ shake.update(tmp, 0, params.getDigestBytes() + saltBytes +
params.getSkSeedBytes());
- shake.doFinal(salt, 0, params.getSaltBytes());
+ shake.doFinal(salt, 0, saltBytes);
// Hash to t
- System.arraycopy(salt, 0, tmp, params.getDigestBytes(), params.getSaltBytes());
- shake.update(tmp, 0, params.getDigestBytes() + params.getSaltBytes());
+ System.arraycopy(salt, 0, tmp, params.getDigestBytes(), saltBytes);
+ shake.update(tmp, 0, params.getDigestBytes() + saltBytes);
shake.doFinal(tenc, 0, params.getMBytes());
Utils.decode(tenc, t, params.getM());
@@ -105,27 +112,36 @@ public byte[] generateSignature(byte[] message)
shake.doFinal(V, 0, V.length);
// Decode vectors
- for (int i = 0; i < params.getK(); i++)
+ for (int i = 0; i < k; i++)
{
- Utils.decode(V, i * params.getVBytes(), Vdec, i * params.getV(), params.getV());
+ Utils.decode(V, i * params.getVBytes(), Vdec, i * v, v);
}
- // Compute matrices
- long[] Mtmp = new long[params.getK() * params.getO() * params.getMVecLimbs()];
- long[] vPv = new long[params.getK() * params.getK() * params.getMVecLimbs()];
- computeMandVPV(params, Vdec, P, params.getP1Limbs(), P, Mtmp, vPv);
+ //computeMandVPV(params, Vdec, P, params.getP1Limbs(), P, Mtmp, vPv);
+ // Compute VL: VL = Vdec * L
+ GF16Utils.mulAddMatXMMat(mVecLimbs, Vdec, P, params.getP1Limbs(), Mtmp, k, v, o);
+
+ // Compute VP1V:
+ // Allocate temporary array for Pv. Its length is V_MAX * K_MAX * M_VEC_LIMBS_MAX.
+ int size = v * k * mVecLimbs;
+ long[] Pv = new long[size]; // automatically initialized to zero in Java
+
+ // Compute Pv = P1 * V^T (using upper triangular multiplication)
+ GF16Utils.mulAddMUpperTriangularMatXMatTrans(mVecLimbs, P, Vdec, Pv, v, v, k, 1);
+ // Compute VP1V = Vdec * Pv
+ GF16Utils.mulAddMatXMMat(mVecLimbs, Vdec, Pv, vPv, k, v, k);
- computeRHS(params, vPv, t, y);
+ computeRHS(vPv, t, y);
computeA(params, Mtmp, A);
// Clear trailing bytes
for (int i = 0; i < params.getM(); ++i)
{
- A[(i + 1) * (params.getK() * params.getO() + 1) - 1] = 0;
+ A[(i + 1) * (k * o + 1) - 1] = 0;
}
- Utils.decode(V, params.getK() * params.getVBytes(), r, 0,
- params.getK() * params.getO());
+ Utils.decode(V, k * params.getVBytes(), r, 0,
+ k * o);
if (sampleSolution(params, A, y, r, x) != 0)
{
@@ -139,22 +155,20 @@ public byte[] generateSignature(byte[] message)
}
// Compute final signature components
- byte[] Ox = new byte[params.getV()];
- for (int i = 0; i < params.getK(); i++)
+ byte[] Ox = new byte[v];
+ for (int i = 0; i < k; i++)
{
- byte[] vi = Arrays.copyOfRange(Vdec, i * params.getV(),
- (i + 1) * params.getV());
- GF16Utils.matMul(O, 0, x, i * params.getO(), Ox, 0,
- params.getO(), params.getN() - params.getO(), 1);
- GF16Utils.matAdd(vi, 0, Ox, 0, s, i * params.getN(), params.getV(), 1);
- System.arraycopy(x, i * params.getO(), s,
- i * params.getN() + params.getN() - params.getO(), params.getO());
+ byte[] vi = Arrays.copyOfRange(Vdec, i * v, (i + 1) * v);
+ GF16Utils.matMul(O, 0, x, i * o, Ox, 0, o, params.getN() - o, 1);
+ GF16Utils.matAdd(vi, 0, Ox, 0, s, i * params.getN(), v, 1);
+ System.arraycopy(x, i * o, s,
+ i * params.getN() + params.getN() - o, o);
}
// Encode and add salt
- Utils.encode(s, sig, params.getN() * params.getK());
- System.arraycopy(salt, 0, sig, sig.length - params.getSaltBytes(),
- params.getSaltBytes());
+ Utils.encode(s, sig, params.getN() * k);
+ System.arraycopy(salt, 0, sig, sig.length - saltBytes,
+ saltBytes);
return Arrays.concatenate(sig, message);
}
@@ -175,13 +189,15 @@ public byte[] generateSignature(byte[] message)
}
}
-
@Override
public boolean verifySignature(byte[] message, byte[] signature)
{
- final int paramM = params.getM();
- final int paramN = params.getN();
- final int paramK = params.getK();
+ final int m = params.getM();
+ final int n = params.getN();
+ final int k = params.getK();
+ int p1Limbs = params.getP1Limbs();
+ int p2Limbs = params.getP2Limbs();
+ int p3Limbs = params.getP3Limbs();
final int paramMBytes = params.getMBytes();
final int paramSigBytes = params.getSigBytes();
final int paramDigestBytes = params.getDigestBytes();
@@ -191,20 +207,16 @@ public boolean verifySignature(byte[] message, byte[] signature)
byte[] t = new byte[params.getM()];
byte[] y = new byte[2 * params.getM()];
byte[] s = new byte[params.getK() * params.getN()];
- long[] pk = new long[params.getP1Limbs() + params.getP2Limbs() + params.getP3Limbs()];
+ long[] pk = new long[p1Limbs + params.getP2Limbs() + params.getP3Limbs()];
byte[] tmp = new byte[params.getDigestBytes() + params.getSaltBytes()];
byte[] cpk = pubKey.getEncoded();
// Expand public key
// mayo_expand_pk
MayoEngine.expandP1P2(params, pk, cpk);
- Utils.unpackMVecs(cpk, params.getPkSeedBytes(), pk, params.getP1Limbs() + params.getP2Limbs(), params.getP3Limbs() / params.getMVecLimbs(), params.getM());
+ Utils.unpackMVecs(cpk, params.getPkSeedBytes(), pk, p1Limbs + params.getP2Limbs(), params.getP3Limbs() / params.getMVecLimbs(), params.getM());
// Split pk into P1, P2, P3
- int p1Limbs = params.getP1Limbs();
- int p2Limbs = params.getP2Limbs();
- int p3Limbs = params.getP3Limbs();
-
long[] P1 = new long[p1Limbs];
long[] P2 = new long[p2Limbs];
long[] P3 = new long[p3Limbs];
@@ -218,74 +230,31 @@ public boolean verifySignature(byte[] message, byte[] signature)
// Compute t
System.arraycopy(signature, paramSigBytes - paramSaltBytes, tmp, paramDigestBytes, paramSaltBytes);
Utils.shake256(tEnc, paramMBytes, tmp, paramDigestBytes + paramSaltBytes);
- Utils.decode(tEnc, t, paramM);
+ Utils.decode(tEnc, t, m);
// Decode signature
- Utils.decode(signature, s, paramK * paramN);
+ Utils.decode(signature, s, k * n);
// Evaluate public map
- evalPublicMap(params, s, P1, P2, P3, y);
+// evalPublicMap(params, s, P1, P2, P3, y);
+ int mVecLimbs = (params.getM() + 15) / 16;
+ long[] SPS = new long[k * k * mVecLimbs];
+ long[] PS = new long[n * k * mVecLimbs];
+ mayoGenericMCalculatePS(params, P1, P2, P3, s, m, params.getV(), params.getO(), k, PS);
+ mayoGenericMCalculateSPS(PS, s, m, k, n, SPS);
+ byte[] zero = new byte[m];
+ computeRHS(SPS, zero, y);
// Compare results
- return Arrays.constantTimeAreEqual(paramM, y, 0, t, 0);
+ return Arrays.constantTimeAreEqual(m, y, 0, t, 0);
}
-
- /**
- * Computes the product of the matrix P1 (bit-sliced) with the transpose of matrix V and adds the result to acc.
- *
- * @param p the parameters object
- * @param P1 the bit-sliced matrix P1 as a long array
- * @param V the matrix V as a byte array
- * @param acc the accumulator array where the result is added
- */
- public static void P1TimesVt(MayoParameters p, long[] P1, byte[] V, long[] acc)
+ public void computeRHS(long[] vPv, byte[] t, byte[] y)
{
- int mVecLimbs = p.getMVecLimbs();
- int paramV = p.getV();
- int paramK = p.getK();
- // triangular parameter is set to 1
- GF16Utils.mulAddMUpperTriangularMatXMatTrans(mVecLimbs, P1, V, acc, paramV, paramV, paramK, 1);
- }
-
- /**
- * Computes the matrices M and VP1V from the given input matrices.
- *
- * @param p the parameters object
- * @param Vdec the decoded V matrix as a byte array
- * @param L the matrix L as a long array
- * @param P1 the bit-sliced matrix P1 as a long array
- * @param VL the output accumulator for VL
- * @param VP1V the output accumulator for VP1V
- */
- public static void computeMandVPV(MayoParameters p, byte[] Vdec, long[] L, int Loff, long[] P1, long[] VL, long[] VP1V)
- {
- int paramK = p.getK();
- int paramV = p.getV();
- int paramO = p.getO();
- int mVecLimbs = p.getMVecLimbs();
-
- // Compute VL: VL = Vdec * L
- GF16Utils.mulAddMatXMMat(mVecLimbs, Vdec, L, Loff, VL, paramK, paramV, paramO);
-
- // Compute VP1V:
- // Allocate temporary array for Pv. Its length is V_MAX * K_MAX * M_VEC_LIMBS_MAX.
- int size = p.getV() * p.getK() * p.getMVecLimbs();
- long[] Pv = new long[size]; // automatically initialized to zero in Java
-
- // Compute Pv = P1 * V^T (using upper triangular multiplication)
- P1TimesVt(p, P1, Vdec, Pv);
-
- // Compute VP1V = Vdec * Pv
- GF16Utils.mulAddMatXMMat(mVecLimbs, Vdec, Pv, VP1V, paramK, paramV, paramK);
- }
-
- public static void computeRHS(MayoParameters p, long[] vPv, byte[] t, byte[] y)
- {
- final int m = p.getM();
- final int mVecLimbs = p.getMVecLimbs();
- final int k = p.getK();
- final int[] fTail = p.getFTail();
+ final int m = params.getM();
+ final int mVecLimbs = params.getMVecLimbs();
+ final int k = params.getK();
+ final int[] fTail = params.getFTail();
final int topPos = ((m - 1) % 16) * 4;
@@ -363,28 +332,25 @@ public static void computeRHS(MayoParameters p, long[] vPv, byte[] t, byte[] y)
// Compute y
for (int i = 0; i < m; i += 2)
{
- int bytePos = i / 2;
+ int bytePos = i >> 1;
y[i] = (byte)(t[i] ^ (tempBytes[bytePos] & 0xF));
y[i + 1] = (byte)(t[i + 1] ^ ((tempBytes[bytePos] >>> 4) & 0xF));
}
}
-
private static final int F_TAIL_LEN = 4;
- private static final long EVEN_NIBBLES = 0x0F0F0F0F0F0F0F0FL;
private static final long EVEN_BYTES = 0x00FF00FF00FF00FFL;
private static final long EVEN_2BYTES = 0x0000FFFF0000FFFFL;
- private static final long EVEN_HALF = 0x00000000FFFFFFFFL;
private static final long LOW_BIT_IN_NIBBLE = 0x1111111111111111L;
- public static void computeA(MayoParameters p, long[] VtL, byte[] AOut)
+ public static void computeA(MayoParameters params, long[] Mtmp, byte[] AOut)
{
- final int k = p.getK();
- final int o = p.getO();
- final int m = p.getM();
- final int mVecLimbs = p.getMVecLimbs();
- final int ACols = p.getACols();
- final byte[] fTailArr = p.getFTailArr();
+ final int k = params.getK();
+ final int o = params.getO();
+ final int m = params.getM();
+ final int mVecLimbs = params.getMVecLimbs();
+ final int ACols = params.getACols();
+ final byte[] fTailArr = params.getFTailArr();
int bitsToShift = 0;
int wordsToShift = 0;
@@ -400,7 +366,7 @@ public static void computeA(MayoParameters p, long[] VtL, byte[] AOut)
for (int i = 0; i < o * k; i++)
{
int idx = i * mVecLimbs + mVecLimbs - 1;
- VtL[idx] &= mask;
+ Mtmp[idx] &= mask;
}
}
@@ -415,7 +381,7 @@ public static void computeA(MayoParameters p, long[] VtL, byte[] AOut)
for (int limb = 0; limb < mVecLimbs; limb++)
{
int idx = mjOffset + limb + c * mVecLimbs;
- long value = VtL[idx];
+ long value = Mtmp[idx];
int aIndex = o * i + c + (limb + wordsToShift) * AWidth;
A[aIndex] ^= value << bitsToShift;
@@ -436,7 +402,7 @@ public static void computeA(MayoParameters p, long[] VtL, byte[] AOut)
for (int limb = 0; limb < mVecLimbs; limb++)
{
int idx = miOffset + limb + c * mVecLimbs;
- long value = VtL[idx];
+ long value = Mtmp[idx];
int aIndex = o * j + c + (limb + wordsToShift) * AWidth;
A[aIndex] ^= value << bitsToShift;
@@ -519,7 +485,7 @@ private static void transpose16x16Nibbles(long[] M, int offset)
{
int idx1 = offset + i;
int idx2 = offset + i + 1;
- long t = ((M[idx1] >>> 4) ^ M[idx2]) & EVEN_NIBBLES;
+ long t = ((M[idx1] >>> 4) ^ M[idx2]) & 0x0F0F0F0F0F0F0F0FL;
M[idx1] ^= t << 4;
M[idx2] ^= t;
}
@@ -549,7 +515,7 @@ private static void transpose16x16Nibbles(long[] M, int offset)
for (int i = 0; i < 8; i++)
{
int base = offset + i;
- long t = ((M[base] >>> 32) ^ M[base + 8]) & EVEN_HALF;
+ long t = ((M[base] >>> 32) ^ M[base + 8]) & 0x00000000FFFFFFFFL;
M[base] ^= t << 32;
M[base + 8] ^= t;
}
@@ -568,7 +534,6 @@ public int sampleSolution(MayoParameters params, byte[] A, byte[] y,
// Compute Ar matrix product
byte[] Ar = new byte[m];
-// Arrays.fill(Ar, (byte)0);
// Clear last column of A
for (int i = 0; i < m; i++)
@@ -605,11 +570,10 @@ public int sampleSolution(MayoParameters params, byte[] A, byte[] y,
for (int col = row; col <= colUpperBound; col++)
{
- byte correctCol = GF16Utils.ctCompare8(A[row * aCols + col], (byte)0);
- byte mask = (byte)(correctCol & ~finished);
+ byte correctCol = (byte)((-(A[row * aCols + col] & 0xFF)) >> 31);
// Update x[col] using constant-time mask
- byte u = (byte)(mask & A[row * aCols + aCols - 1]);
+ byte u = (byte)(correctCol & ~finished & A[row * aCols + aCols - 1]);
//System.out.println("x[col]: " + x[col] + ", u: " + u);
x[col] ^= u;
@@ -639,11 +603,6 @@ public int sampleSolution(MayoParameters params, byte[] A, byte[] y,
return 1;
}
- // Adjust these as needed. In our translation we compute rowLen from ncols.
- // These blockers are used in the C code for constant-time masking.
- private static final long UINT64_BLOCKER = 0L;
- private static final int UNSIGNED_CHAR_BLOCKER = 0; // Not used in our Java version.
-
/**
* Converts a matrix A (given as a flat array of GF(16) elements, one per byte)
* into row echelon form (with ones on the first nonzero entries) in constant time.
@@ -666,8 +625,21 @@ public void ef(byte[] A, int nrows, int ncols)
// Pack the matrix rows.
for (int i = 0; i < nrows; i++)
{
- long[] packedRow = packRow(A, i, ncols);
- System.arraycopy(packedRow, 0, packedA, i * rowLen, rowLen);
+ //packRow(A, i, ncols);
+ // Process each 64-bit word (each holds 16 nibbles).
+ for (int word = 0; word < rowLen; word++)
+ {
+ long wordVal = 0;
+ for (int nibble = 0; nibble < 16; nibble++)
+ {
+ int col = (word << 4) + nibble;
+ if (col < ncols)
+ {
+ wordVal |= ((long)A[i * ncols + col] & 0xF) << (nibble << 2);
+ }
+ }
+ packedA[word + i * rowLen] = wordVal;
+ }
}
int pivotRowIndex = 0;
@@ -691,7 +663,8 @@ public void ef(byte[] A, int nrows, int ncols)
for (int row = lowerBound; row <= searchUpper; row++)
{
long isPivotRow = ~ctCompare64(row, pivotRowIndex);
- long belowPivotRow = ct64IsGreaterThan(row, pivotRowIndex);
+ //ct64IsGreaterThan(a, b): Returns 0xFFFFFFFFFFFFFFFF if a > b, 0 otherwise.
+ long belowPivotRow = ((long)pivotRowIndex - (long)row) >> 63;
for (int j = 0; j < rowLen; j++)
{
// The expression below accumulates (in constant time) the candidate pivot row.
@@ -699,7 +672,7 @@ public void ef(byte[] A, int nrows, int ncols)
& packedA[row * rowLen + j];
}
// Extract candidate pivot element from the packed row.
- pivot = mExtractElement(pivotRow, pivotCol);
+ pivot = (int)((pivotRow[pivotCol >>> 4] >>> ((pivotCol & 15) << 2)) & 0xF);
pivotIsZero = ~ctCompare64(pivot, 0);
}
@@ -715,9 +688,8 @@ public void ef(byte[] A, int nrows, int ncols)
for (int col = 0; col < rowLen; col++)
{
// Since the masks are disjoint, addition is equivalent to OR.
- packedA[row * rowLen + col] =
- (doNotCopy & packedA[row * rowLen + col]) |
- (doCopy & pivotRow2[col]);
+ packedA[row * rowLen + col] = (doNotCopy & packedA[row * rowLen + col]) |
+ (doCopy & pivotRow2[col]);
}
}
@@ -742,77 +714,20 @@ public void ef(byte[] A, int nrows, int ncols)
for (int i = 0; i < nrows; i++)
{
GF16Utils.efUnpackMVector(rowLen, packedA, i * rowLen, temp);
- for (int j = 0; j < ncols; j++)
+ if (ncols >= 0)
{
- A[i * ncols + j] = temp[j];
+ System.arraycopy(temp, 0, A, i * ncols, ncols);
}
}
}
- /**
- * Packs one row of GF(16) elements (stored in A) into a long[].
- * Each long holds 16 GF(16) elements (4 bits each).
- *
- * @param A the flat input matrix (row-major)
- * @param row the row index to pack
- * @param ncols the number of columns (GF(16) elements) in a row
- * @return an array of longs representing the packed row.
- */
- private static long[] packRow(byte[] A, int row, int ncols)
- {
- int rowLen = (ncols + 15) / 16; // number of longs needed for this row
- long[] packed = new long[rowLen];
- // Process each 64-bit word (each holds 16 nibbles).
- for (int word = 0; word < rowLen; word++)
- {
- long wordVal = 0;
- for (int nibble = 0; nibble < 16; nibble++)
- {
- int col = word * 16 + nibble;
- if (col < ncols)
- {
- int element = A[row * ncols + col] & 0xF;
- wordVal |= ((long)element) << (4 * nibble);
- }
- }
- packed[word] = wordVal;
- }
- return packed;
- }
-
/**
* Constant-time comparison: returns 0 if a==b, else returns all 1s (0xFFFFFFFFFFFFFFFF).
*/
private static long ctCompare64(int a, int b)
{
// Compute (-(a XOR b)) >> 63 then XOR with UINT64_BLOCKER.
- long diff = -(long)(a ^ b);
- long shift = diff >> 63; // arithmetic shift; results in 0 or -1.
- return shift ^ UINT64_BLOCKER;
- }
-
- /**
- * Returns 0xFFFFFFFFFFFFFFFF if a > b, 0 otherwise.
- */
- private static long ct64IsGreaterThan(int a, int b)
- {
- long diff = (long)b - (long)a;
- long shift = diff >> 63;
- return shift ^ UINT64_BLOCKER;
- }
-
- /**
- * Extracts the GF(16) element at a given column index from a packed row.
- *
- * @param in the packed row (array of longs)
- * @param index the column index (0-indexed)
- * @return the GF(16) element (an int in 0..15)
- */
- private static int mExtractElement(long[] in, int index)
- {
- int leg = index / 16;
- int offset = index % 16;
- return (int)((in[leg] >>> (4 * offset)) & 0xF);
+ return (-(long)(a ^ b)) >> 63;
}
/**
@@ -826,9 +741,7 @@ private static int mExtractElement(long[] in, int index)
*/
private static int mExtractElementFromPacked(long[] packedA, int row, int rowLen, int index)
{
- int leg = index / 16;
- int offset = index % 16;
- return (int)((packedA[row * rowLen + leg] >>> (4 * offset)) & 0xF);
+ return (int)((packedA[row * rowLen + (index >>> 4)] >>> ((index & 15) << 2)) & 0xF);
}
/**
@@ -841,8 +754,7 @@ private static int inverseF(int a)
int a4 = mulF(a2, a2);
int a8 = mulF(a4, a4);
int a6 = mulF(a2, a4);
- int a14 = mulF(a8, a6);
- return a14;
+ return mulF(a8, a6);
}
/**
@@ -859,8 +771,7 @@ public static int mulF(int a, int b)
((a & 8) * b);
// Reduce modulo f(X) = x^4 + x + 1.
int topP = p & 0xF0;
- int out = (p ^ (topP >> 4) ^ (topP >> 3)) & 0x0F;
- return out;
+ return (p ^ (topP >> 4) ^ (topP >> 3)) & 0x0F;
}
/**
@@ -927,82 +838,57 @@ private static int mulTable(int b)
return x ^ (highHalf >>> 4) ^ (highHalf >>> 3);
}
- private static void evalPublicMap(MayoParameters p, byte[] s, long[] P1, long[] P2, long[] P3, byte[] eval)
- {
- int mVecLimbs = (p.getM() + 15) / 16;
- long[] SPS = new long[p.getK() * p.getK() * mVecLimbs];
- mCalculatePsSps(p, P1, P2, P3, s, SPS);
- byte[] zero = new byte[p.getM()];
- computeRHS(p, SPS, zero, eval);
- }
-
- private static void mCalculatePsSps(MayoParameters p, long[] P1, long[] P2, long[] P3, byte[] s, long[] SPS)
- {
- int m = p.getM();
- int v = p.getV();
- int o = p.getO();
- int k = p.getK();
- int mVecLimbs = (m + 15) / 16;
-
- long[] PS = new long[p.getN() * p.getK() * mVecLimbs];
- mayoGenericMCalculatePS(p, P1, P2, P3, s, m, v, o, k, PS);
- mayoGenericMCalculateSPS(PS, s, m, k, p.getN(), SPS);
- }
-
private static void mayoGenericMCalculatePS(MayoParameters p, long[] P1, long[] P2, long[] P3, byte[] S,
int m, int v, int o, int k, long[] PS)
{
int n = o + v;
int mVecLimbs = (m + 15) / 16;
long[] accumulator = new long[16 * ((p.getM() + 15) / 16 * p.getK() * p.getN() * mVecLimbs)];
-
- int p1Used = 0;
- for (int row = 0; row < v; row++)
+ int o_mVecLimbs = o * mVecLimbs;
+ int pUsed = 0;
+ for (int row = 0, krow = 0, orow_mVecLimbs = 0; row < v; row++, krow += k, orow_mVecLimbs += o_mVecLimbs)
{
for (int j = row; j < v; j++)
{
- for (int col = 0; col < k; col++)
+ for (int col = 0, ncol = 0; col < k; col++, ncol += n)
{
- Longs.xorTo(mVecLimbs, P1, p1Used * mVecLimbs,
- accumulator, ((row * k + col) * 16 + (S[col * n + j] & 0xFF)) * mVecLimbs);
+ Longs.xorTo(mVecLimbs, P1, pUsed, accumulator, (((krow + col) << 4) + (S[ncol + j] & 0xFF)) * mVecLimbs);
}
- p1Used++;
+ pUsed += mVecLimbs;
}
- for (int j = 0; j < o; j++)
+ for (int j = 0, orow_j_mVecLimbs = orow_mVecLimbs; j < o; j++, orow_j_mVecLimbs += mVecLimbs)
{
- for (int col = 0; col < k; col++)
+ for (int col = 0, ncol = 0; col < k; col++, ncol += n)
{
- Longs.xorTo(mVecLimbs, P2, (row * o + j) * mVecLimbs,
- accumulator, ((row * k + col) * 16 + (S[(col * n) + j + v] & 0xFF)) * mVecLimbs);
+ Longs.xorTo(mVecLimbs, P2, orow_j_mVecLimbs, accumulator, (((krow + col) << 4) + (S[ncol + j + v] & 0xFF)) * mVecLimbs);
}
}
}
- int p3Used = 0;
- for (int row = v; row < n; row++)
+ pUsed = 0;
+ for (int row = v, krow = v * k; row < n; row++, krow += k)
{
for (int j = row; j < n; j++)
{
- for (int col = 0; col < k; col++)
+ for (int col = 0, ncol = 0; col < k; col++, ncol += n)
{
- Longs.xorTo(mVecLimbs, P3, p3Used * mVecLimbs,
- accumulator, ((row * k + col) * 16 + (S[col * n + j] & 0xFF)) * mVecLimbs);
+ Longs.xorTo(mVecLimbs, P3, pUsed, accumulator, (((krow + col) << 4) + (S[ncol + j] & 0xFF)) * mVecLimbs);
}
- p3Used++;
+ pUsed += mVecLimbs;
}
}
- for (int i = 0; i < n * k; i++)
+ for (int i = 0, imVecLimbs = 0; i < n * k; i++, imVecLimbs += mVecLimbs)
{
- mVecMultiplyBins(mVecLimbs, accumulator, i * 16 * mVecLimbs, PS, i * mVecLimbs);
+ mVecMultiplyBins(mVecLimbs, accumulator, imVecLimbs << 4, PS, imVecLimbs);
}
}
private static void mayoGenericMCalculateSPS(long[] PS, byte[] S, int m, int k, int n, long[] SPS)
{
final int mVecLimbs = (m + 15) / 16;
- final int accumulatorSize = 16 * mVecLimbs * k * k;
+ final int accumulatorSize = (mVecLimbs * k * k) << 4;
final long[] accumulator = new long[accumulatorSize];
// Accumulation phase
@@ -1015,7 +901,7 @@ private static void mayoGenericMCalculateSPS(long[] PS, byte[] S, int m, int k,
{
final int psOffset = (j * k + col) * mVecLimbs;
final int accOffset = ((row * k + col) * 16 + sVal) * mVecLimbs;
- mVecAdd(mVecLimbs, PS, psOffset, accumulator, accOffset);
+ Longs.xorTo(mVecLimbs, PS, psOffset, accumulator, accOffset);
}
}
}
@@ -1027,16 +913,6 @@ private static void mayoGenericMCalculateSPS(long[] PS, byte[] S, int m, int k,
}
}
- // Helper method for vector addition (XOR)
- private static void mVecAdd(int limbs, long[] src, int srcOffset, long[] dest, int destOffset)
- {
- for (int i = 0; i < limbs; i++)
- {
- dest[destOffset + i] ^= src[srcOffset + i];
- }
- }
-
- // Main bin processing method
private static void mVecMultiplyBins(int mVecLimbs, long[] bins, int binOffset, long[] ps, int psOff)
{
// Series of modular operations as per original C code
@@ -1052,8 +928,8 @@ private static void mVecMultiplyBins(int mVecLimbs, long[] bins, int binOffset,
mVecMulAddX(mVecLimbs, bins, binOffset + 8 * mVecLimbs, bins, binOffset + 4 * mVecLimbs);
mVecMulAddXInv(mVecLimbs, bins, binOffset + 13 * mVecLimbs, bins, binOffset + 9 * mVecLimbs);
mVecMulAddX(mVecLimbs, bins, binOffset + 4 * mVecLimbs, bins, binOffset + 2 * mVecLimbs);
- mVecMulAddXInv(mVecLimbs, bins, binOffset + 9 * mVecLimbs, bins, binOffset + 1 * mVecLimbs);
- mVecMulAddX(mVecLimbs, bins, binOffset + 2 * mVecLimbs, bins, binOffset + 1 * mVecLimbs);
+ mVecMulAddXInv(mVecLimbs, bins, binOffset + 9 * mVecLimbs, bins, binOffset + mVecLimbs);
+ mVecMulAddX(mVecLimbs, bins, binOffset + 2 * mVecLimbs, bins, binOffset + mVecLimbs);
System.arraycopy(bins, mVecLimbs + binOffset, ps, psOff, mVecLimbs);
}
@@ -1064,8 +940,9 @@ private static void mVecMulAddXInv(int limbs, long[] in, int inOffset,
final long maskLsb = 0x1111111111111111L;
for (int i = 0; i < limbs; i++)
{
- final long t = in[inOffset + i] & maskLsb;
- acc[accOffset + i] ^= ((in[inOffset + i] ^ t) >>> 1) ^ (t * 9);
+ long input = in[inOffset + i];
+ long t = input & maskLsb;
+ acc[accOffset + i] ^= ((input ^ t) >>> 1) ^ (t * 9);
}
}
@@ -1075,10 +952,9 @@ private static void mVecMulAddX(int limbs, long[] in, int inOffset,
final long maskMsb = 0x8888888888888888L;
for (int i = 0; i < limbs; i++)
{
- final long t = in[inOffset + i] & maskMsb;
- acc[accOffset + i] ^= ((in[inOffset + i] ^ t) << 1) ^ ((t >>> 3) * 3);
+ long input = in[inOffset + i];
+ long t = input & maskMsb;
+ acc[accOffset + i] ^= ((input ^ t) << 1) ^ ((t >>> 3) * 3);
}
}
-
-
}
diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/MayoTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/MayoTest.java
index ceb91d4601..e479221220 100644
--- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/MayoTest.java
+++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/MayoTest.java
@@ -48,6 +48,7 @@ public static void main(String[] args)
public void testTestVectors()
throws Exception
{
+ long start = System.currentTimeMillis();
TestUtils.testTestVector(false, false, "pqc/crypto/mayo", files, new TestUtils.KeyGenerationOperation()
{
@Override
@@ -90,5 +91,7 @@ public MessageSigner getMessageSigner()
return new MayoSigner();
}
});
+ long end = System.currentTimeMillis();
+ System.out.println("time cost: " + (end - start) +"\n");
}
}
From 7a48919f76b90f952aee41bb2597e9bb87e03d40 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Mon, 3 Mar 2025 18:01:29 +1030
Subject: [PATCH 141/890] Refactor for Mayo
---
.../pqc/crypto/mayo/GF16Utils.java | 140 +++++++-----------
.../pqc/crypto/mayo/MayoKeyPairGenerator.java | 34 ++---
.../pqc/crypto/mayo/MayoSigner.java | 108 +++++++-------
3 files changed, 115 insertions(+), 167 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java
index f17d0608da..7882cc472a 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java
@@ -1,44 +1,8 @@
package org.bouncycastle.pqc.crypto.mayo;
-import org.bouncycastle.util.Pack;
-
public class GF16Utils
{
- /**
- * Multiplies a 64-bit limb by a GF(16) element (represented as an int, 0–255).
- * This emulates gf16v_mul_u64 from C.
- *
- * @param a a 64-bit limb
- * @param b an 8-bit GF(16) element (only the low 4 bits are used)
- * @return the product as a 64-bit limb
- */
- public static long gf16vMulU64(long a, int b)
- {
- long maskMsb = 0x8888888888888888L;
- // In the original code there is a conditional XOR with unsigned_char_blocker;
- // here we simply use b directly.
- long b32 = b & 0x00000000FFFFFFFFL;
- long r64 = a * (b32 & 1);
-
- long a_msb = a & maskMsb;
- a ^= a_msb;
- a = (a << 1) ^ ((a_msb >>> 3) * 3);
- r64 ^= a * ((b32 >> 1) & 1);
-
- a_msb = a & maskMsb;
- a ^= a_msb;
- a = (a << 1) ^ ((a_msb >>> 3) * 3);
- r64 ^= a * ((b32 >>> 2) & 1);
-
- a_msb = a & maskMsb;
- a ^= a_msb;
- a = (a << 1) ^ ((a_msb >>> 3) * 3);
- r64 ^= a * ((b32 >> 3) & 1);
-
- return r64;
- }
-
/**
* Multiplies each limb of a GF(16) vector (subarray of 'in') by the GF(16) element 'a'
* and XORs the result into the corresponding subarray of acc.
@@ -48,15 +12,40 @@ public static long gf16vMulU64(long a, int b)
* @param mVecLimbs the number of limbs in the vector
* @param in the input long array containing the vector; the vector starts at index inOffset
* @param inOffset the starting index in 'in'
- * @param a the GF(16) element (0–255) to multiply by
+ * @param b the GF(16) element (0–255) to multiply by
* @param acc the accumulator long array; the target vector starts at index accOffset
* @param accOffset the starting index in 'acc'
*/
- public static void mVecMulAdd(int mVecLimbs, long[] in, int inOffset, int a, long[] acc, int accOffset)
+ public static void mVecMulAdd(int mVecLimbs, long[] in, int inOffset, int b, long[] acc, int accOffset)
{
+ long maskMsb = 0x8888888888888888L;
+ long a, r64, a_msb;
+ long b32 = b & 0x00000000FFFFFFFFL;
+ long b32and1 = b32 & 1;
+ long b32_1_1 = ((b32 >>> 1) & 1);
+ long b32_2_1 = ((b32 >>> 2) & 1);
+ long b32_3_1 = ((b32 >>> 3) & 1);
for (int i = 0; i < mVecLimbs; i++)
{
- acc[accOffset + i] ^= gf16vMulU64(in[inOffset + i], a);
+ // In the original code there is a conditional XOR with unsigned_char_blocker;
+ // here we simply use b directly.
+ a = in[inOffset + i];
+ r64 = a * b32and1;
+
+ a_msb = a & maskMsb;
+ a ^= a_msb;
+ a = (a << 1) ^ ((a_msb >>> 3) * 3);
+ r64 ^= a * b32_1_1;
+
+ a_msb = a & maskMsb;
+ a ^= a_msb;
+ a = (a << 1) ^ ((a_msb >>> 3) * 3);
+ r64 ^= a * b32_2_1;
+
+ a_msb = a & maskMsb;
+ a ^= a_msb;
+ a = (a << 1) ^ ((a_msb >>> 3) * 3);
+ acc[accOffset + i] ^= r64 ^ (a * b32_3_1);
}
}
@@ -65,38 +54,32 @@ public static void mVecMulAdd(int mVecLimbs, long[] in, int inOffset, int a, lon
* Performs the multiplication and accumulation of a block of an upper‐triangular matrix
* times a second matrix.
*
- * @param mVecLimbs number of limbs per m-vector.
- * @param bsMat the “basis” matrix (as a flat long[] array); each entry occupies mVecLimbs elements.
- * @param mat the second matrix (as a flat byte[] array) stored row‐major,
- * with dimensions (bsMatCols x matCols).
- * @param acc the accumulator (as a flat long[] array) with dimensions (bsMatRows x matCols);
- * each “entry” is an m‐vector (length mVecLimbs).
- * @param bsMatRows number of rows in the bsMat (the “triangular” matrix’s row count).
- * @param bsMatCols number of columns in bsMat.
- * @param matCols number of columns in the matrix “mat.”
- * @param triangular if 1, start column index for each row is (r * triangular); otherwise use 0.
+ * @param mVecLimbs number of limbs per m-vector.
+ * @param bsMat the “basis” matrix (as a flat long[] array); each entry occupies mVecLimbs elements.
+ * @param mat the second matrix (as a flat byte[] array) stored row‐major,
+ * with dimensions (bsMatCols x matCols).
+ * @param acc the accumulator (as a flat long[] array) with dimensions (bsMatRows x matCols);
+ * each “entry” is an m‐vector (length mVecLimbs).
+ * @param bsMatRows number of rows in the bsMat (the “triangular” matrix’s row count).
+ * @param bsMatCols number of columns in bsMat.
+ * @param matCols number of columns in the matrix “mat.”
*/
- public static void mulAddMUpperTriangularMatXMat(int mVecLimbs, long[] bsMat, byte[] mat, long[] acc,
- int bsMatRows, int bsMatCols, int matCols, int triangular)
+ public static void mulAddMUpperTriangularMatXMat(int mVecLimbs, long[] bsMat, byte[] mat, long[] acc, int accOff,
+ int bsMatRows, int bsMatCols, int matCols)
{
int bsMatEntriesUsed = 0;
- for (int r = 0; r < bsMatRows; r++)
+ int matColsmVecLimbs = matCols * mVecLimbs;
+ for (int r = 0, rmatCols = 0, rmatColsmVecLimbs = 0; r < bsMatRows; r++, rmatCols += matCols, rmatColsmVecLimbs += matColsmVecLimbs)
{
// For each row r, the inner loop goes from column triangular*r to bsMatCols-1.
- for (int c = triangular * r; c < bsMatCols; c++)
+ for (int c = r, cmatCols = rmatCols; c < bsMatCols; c++, cmatCols += matCols)
{
- for (int k = 0; k < matCols; k++)
+ for (int k = 0, kmVecLimbs = 0; k < matCols; k++, kmVecLimbs += mVecLimbs)
{
- // Calculate the offsets:
- // For bsMat: the m-vector starting at index bsMatEntriesUsed * mVecLimbs.
- int bsMatOffset = bsMatEntriesUsed * mVecLimbs;
- // For mat: element at row c, column k (row-major layout).
- int a = mat[c * matCols + k] & 0xFF;
// For acc: add into the m-vector at row r, column k.
- int accOffset = (r * matCols + k) * mVecLimbs;
- mVecMulAdd(mVecLimbs, bsMat, bsMatOffset, a, acc, accOffset);
+ mVecMulAdd(mVecLimbs, bsMat, bsMatEntriesUsed, mat[cmatCols + k] & 0xFF, acc, accOff + rmatColsmVecLimbs + kmVecLimbs);
}
- bsMatEntriesUsed++;
+ bsMatEntriesUsed += mVecLimbs;
}
}
}
@@ -114,18 +97,18 @@ public static void mulAddMUpperTriangularMatXMat(int mVecLimbs, long[] bsMat, by
* @param matCols number of columns in “mat.”
* @param bsMatCols number of columns in the bsMat matrix.
*/
- public static void mulAddMatTransXMMat(int mVecLimbs, byte[] mat, long[] bsMat, long[] acc,
+ public static void mulAddMatTransXMMat(int mVecLimbs, byte[] mat, long[] bsMat, int bsMatOff, long[] acc,
int matRows, int matCols, int bsMatCols)
{
// Loop over each column r of mat (which becomes row of mat^T)
for (int r = 0; r < matCols; r++)
{
- for (int c = 0; c < matRows; c++)
+ for (int c = 0, cmatCols = 0; c < matRows; c++, cmatCols += matCols)
{
- byte matVal = mat[c * matCols + r];
+ byte matVal = mat[cmatCols + r];
for (int k = 0; k < bsMatCols; k++)
{
- int bsMatOffset = (c * bsMatCols + k) * mVecLimbs;
+ int bsMatOffset = bsMatOff + (c * bsMatCols + k) * mVecLimbs;
// For acc: add into the m-vector at index (r * bsMatCols + k)
int accOffset = (r * bsMatCols + k) * mVecLimbs;
mVecMulAdd(mVecLimbs, bsMat, bsMatOffset, matVal, acc, accOffset);
@@ -257,10 +240,7 @@ public static int mulF(int a, int b)
// Perform carryless multiplication:
// Multiply b by each bit of a and XOR the results.
- int p = ((a & 1) * b) ^
- ((a & 2) * b) ^
- ((a & 4) * b) ^
- ((a & 8) * b);
+ int p = ((a & 1) * b) ^ ((a & 2) * b) ^ ((a & 4) * b) ^ ((a & 8) * b);
// Reduce modulo f(X) = x^4 + x + 1.
// Extract the upper nibble (bits 4 to 7).
@@ -308,9 +288,8 @@ public static void matMul(byte[] a, int aOff, byte[] b, int bOff, byte[] c, int
int colrowAB, int rowA, int colB)
{
int cIndex = 0;
- for (int i = 0; i < rowA; i++)
+ for (int i = 0, aRowStart = 0; i < rowA; i++, aRowStart += colrowAB)
{
- int aRowStart = i * colrowAB;
for (int j = 0; j < colB; j++)
{
c[cOff + cIndex++] = lincomb(a, aOff + aRowStart, b, bOff + j, colrowAB, colB);
@@ -318,7 +297,6 @@ public static void matMul(byte[] a, int aOff, byte[] b, int bOff, byte[] c, int
}
}
-
private static byte lincomb(byte[] a, int aStart, byte[] b, int bStart,
int colrowAB, int colB)
{
@@ -332,26 +310,14 @@ private static byte lincomb(byte[] a, int aStart, byte[] b, int bStart,
public static void matAdd(byte[] a, int aOff, byte[] b, int bOff, byte[] c, int cOff, int m, int n)
{
- for (int i = 0; i < m; i++)
+ for (int i = 0, in = 0; i < m; i++, in += n)
{
for (int j = 0; j < n; j++)
{
- int idx = i * n + j;
+ int idx = in + j;
c[idx + cOff] = (byte)(a[idx + aOff] ^ b[idx + bOff]);
}
}
}
-
- public static void efUnpackMVector(int legs, long[] packedRow, int packedRowOff, byte[] out)
- {
- int outIndex = 0;
- byte[] bytes = new byte[out.length >> 1];
- Pack.longToLittleEndian(packedRow, packedRowOff, out.length >> 4, bytes, 0);
- for (int i = 0; i < legs * 16; i += 2)
- {
- out[outIndex++] = (byte)(bytes[i / 2] & 0x0F); // Lower nibble
- out[outIndex++] = (byte)((bytes[i / 2] >> 4) & 0x0F); // Upper nibble
- }
- }
}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
index dac5454c11..42a349d5a8 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
@@ -47,8 +47,6 @@ public AsymmetricCipherKeyPair generateKeyPair()
// Allocate P3 as a long array of size (O_MAX * O_MAX * M_VEC_LIMBS_MAX), zero-initialized.
long[] P3 = new long[o * o * mVecLimbs];
- // Allocate O as a byte array of size (V_MAX * O_MAX).
- // Here we assume V_MAX is given by p.getV() (or replace with a constant if needed).
byte[] O = new byte[v * o];
// Generate secret key seed (seed_sk) using a secure random generator.
@@ -60,27 +58,21 @@ public AsymmetricCipherKeyPair generateKeyPair()
// o ← Decode_o(S[ param_pk_seed_bytes : param_pk_seed_bytes + O_bytes ])
// Decode nibbles from S starting at offset param_pk_seed_bytes into O,
// with expected output length = param_v * param_o.
- Utils.decode(seed_pk, pkSeedBytes, O, v * o);
+ Utils.decode(seed_pk, pkSeedBytes, O, O.length);
// Expand P1 and P2 into the array P using seed_pk.
MayoEngine.expandP1P2(p, P, seed_pk);
- // For compute_P3, we need to separate P1 and P2.
- // Here, we treat P1 as the first param_P1_limbs elements of P,
- // and P2 as the remaining elements.
- long[] P2 = new long[P.length - p1Limbs];
- System.arraycopy(P, p1Limbs, P2, 0, P2.length);
-
// Compute P1 * O + P2 and store the result in P2.
-// GF16Utils.P1TimesO(p, P, O, P2);
+ // GF16Utils.P1TimesO(p, P, O, P2);
// Here, bsMatRows and bsMatCols are both paramV, and matCols is paramO, triangular=1.
- GF16Utils.mulAddMUpperTriangularMatXMat(mVecLimbs, P, O, P2, v, v, o, 1);
+ GF16Utils.mulAddMUpperTriangularMatXMat(mVecLimbs, P, O, P, p1Limbs, v, v, o);
// Compute P3 = O^T * (P1*O + P2).
// Here, treat P2 as the bsMat for the multiplication.
// Dimensions: mat = O (size: paramV x paramO), bsMat = P2 (size: paramV x paramO),
// and acc (P3) will have dimensions: (paramO x paramO), each entry being an m-vector.
- GF16Utils.mulAddMatTransXMMat(mVecLimbs, O, P2, P3, v, o, o);
+ GF16Utils.mulAddMatTransXMMat(mVecLimbs, O, P, p1Limbs, P3, v, o, o);
// Store seed_pk into the public key cpk.
System.arraycopy(seed_pk, 0, cpk, 0, pkSeedBytes);
@@ -90,25 +82,20 @@ public AsymmetricCipherKeyPair generateKeyPair()
// Compute Upper(P3) and store the result in P3_upper.
int mVecsStored = 0;
- for (int r = 0; r < o; r++)
+ int omVecLimbs = o * mVecLimbs;
+ for (int r = 0, rmVecLimbs = 0, romVecLimbs = 0; r < o; r++, romVecLimbs += omVecLimbs, rmVecLimbs += mVecLimbs)
{
- for (int c = r; c < o; c++)
+ for (int c = r, cmVecLimbs = rmVecLimbs, comVecLimbs = romVecLimbs; c < o; c++, cmVecLimbs += mVecLimbs, comVecLimbs += omVecLimbs)
{
- // Compute the starting index for the (r, c) vector in the input array.
- int srcOffset = mVecLimbs * (r * o + c);
- // Compute the output offset for the current stored vector.
- int destOffset = mVecLimbs * mVecsStored;
-
// Copy the vector at (r, c) into the output.
- System.arraycopy(P3, srcOffset, P3_upper, destOffset, mVecLimbs);
+ System.arraycopy(P3, romVecLimbs + cmVecLimbs, P3_upper, mVecsStored, mVecLimbs);
// If off-diagonal, add (XOR) the vector at (c, r) into the same output vector.
if (r != c)
{
- int srcOffset2 = mVecLimbs * (c * o + r);
- Longs.xorTo(mVecLimbs, P3, srcOffset2, P3_upper, destOffset);
+ Longs.xorTo(mVecLimbs, P3, comVecLimbs + rmVecLimbs, P3_upper, mVecsStored);
}
- mVecsStored++;
+ mVecsStored += mVecLimbs;
}
}
@@ -118,7 +105,6 @@ public AsymmetricCipherKeyPair generateKeyPair()
Utils.packMVecs(P3_upper, cpk, pkSeedBytes, p3Limbs / mVecLimbs, m);
// Securely clear sensitive data.
Arrays.clear(O);
- Arrays.clear(P2);
Arrays.clear(P3);
return new AsymmetricCipherKeyPair(new MayoPublicKeyParameter(p, cpk), new MayoPrivateKeyParameter(p, seed_sk));
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
index a68d01d15c..f6d2b77c3d 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
@@ -132,7 +132,7 @@ public byte[] generateSignature(byte[] message)
GF16Utils.mulAddMatXMMat(mVecLimbs, Vdec, Pv, vPv, k, v, k);
computeRHS(vPv, t, y);
- computeA(params, Mtmp, A);
+ computeA(Mtmp, A);
// Clear trailing bytes
for (int i = 0; i < params.getM(); ++i)
@@ -143,7 +143,7 @@ public byte[] generateSignature(byte[] message)
Utils.decode(V, k * params.getVBytes(), r, 0,
k * o);
- if (sampleSolution(params, A, y, r, x) != 0)
+ if (sampleSolution(params, A, y, r, x))
{
break;
}
@@ -216,13 +216,6 @@ public boolean verifySignature(byte[] message, byte[] signature)
MayoEngine.expandP1P2(params, pk, cpk);
Utils.unpackMVecs(cpk, params.getPkSeedBytes(), pk, p1Limbs + params.getP2Limbs(), params.getP3Limbs() / params.getMVecLimbs(), params.getM());
- // Split pk into P1, P2, P3
- long[] P1 = new long[p1Limbs];
- long[] P2 = new long[p2Limbs];
- long[] P3 = new long[p3Limbs];
- System.arraycopy(pk, 0, P1, 0, p1Limbs);
- System.arraycopy(pk, p1Limbs, P2, 0, p2Limbs);
- System.arraycopy(pk, p1Limbs + p2Limbs, P3, 0, p3Limbs);
// Hash message
Utils.shake256(tmp, paramDigestBytes, message, message.length);
@@ -240,7 +233,7 @@ public boolean verifySignature(byte[] message, byte[] signature)
int mVecLimbs = (params.getM() + 15) / 16;
long[] SPS = new long[k * k * mVecLimbs];
long[] PS = new long[n * k * mVecLimbs];
- mayoGenericMCalculatePS(params, P1, P2, P3, s, m, params.getV(), params.getO(), k, PS);
+ mayoGenericMCalculatePS(params, pk, p1Limbs, p1Limbs + p2Limbs, s, m, params.getV(), params.getO(), k, PS);
mayoGenericMCalculateSPS(PS, s, m, k, n, SPS);
byte[] zero = new byte[m];
computeRHS(SPS, zero, y);
@@ -343,7 +336,7 @@ public void computeRHS(long[] vPv, byte[] t, byte[] y)
private static final long EVEN_2BYTES = 0x0000FFFF0000FFFFL;
private static final long LOW_BIT_IN_NIBBLE = 0x1111111111111111L;
- public static void computeA(MayoParameters params, long[] Mtmp, byte[] AOut)
+ public void computeA(long[] Mtmp, byte[] AOut)
{
final int k = params.getK();
final int o = params.getO();
@@ -431,7 +424,7 @@ public static void computeA(MayoParameters params, long[] Mtmp, byte[] AOut)
}
// Generate tab array
- byte[] tab = new byte[F_TAIL_LEN * 4];
+ byte[] tab = new byte[F_TAIL_LEN << 2];
for (int i = 0; i < F_TAIL_LEN; i++)
{
byte ft = fTailArr[i];
@@ -521,8 +514,8 @@ private static void transpose16x16Nibbles(long[] M, int offset)
}
}
- public int sampleSolution(MayoParameters params, byte[] A, byte[] y,
- byte[] r, byte[] x)
+ public boolean sampleSolution(MayoParameters params, byte[] A, byte[] y,
+ byte[] r, byte[] x)
{
final int k = params.getK();
final int o = params.getO();
@@ -559,7 +552,7 @@ public int sampleSolution(MayoParameters params, byte[] A, byte[] y,
}
if (!fullRank)
{
- return 0;
+ return false;
}
// Constant-time back substitution
@@ -600,7 +593,7 @@ public int sampleSolution(MayoParameters params, byte[] A, byte[] y,
finished |= correctCol;
}
}
- return 1;
+ return true;
}
/**
@@ -621,9 +614,12 @@ public void ef(byte[] A, int nrows, int ncols)
long[] pivotRow2 = new long[rowLen];
// The packed matrix: one contiguous array storing nrows rows, each rowLen longs long.
long[] packedA = new long[nrows * rowLen];
+ int len = params.getO() * params.getK() + 16;
+ byte[] bytes = new byte[len >> 1];
+ int len_4 = len >> 4;
// Pack the matrix rows.
- for (int i = 0; i < nrows; i++)
+ for (int i = 0, incols = 0; i < nrows; i++, incols += ncols)
{
//packRow(A, i, ncols);
// Process each 64-bit word (each holds 16 nibbles).
@@ -635,7 +631,7 @@ public void ef(byte[] A, int nrows, int ncols)
int col = (word << 4) + nibble;
if (col < ncols)
{
- wordVal |= ((long)A[i * ncols + col] & 0xF) << (nibble << 2);
+ wordVal |= ((long)A[incols + col] & 0xF) << (nibble << 2);
}
}
packedA[word + i * rowLen] = wordVal;
@@ -681,14 +677,14 @@ public void ef(byte[] A, int nrows, int ncols)
vecMulAddU64(rowLen, pivotRow, (byte)inv, pivotRow2);
// Conditionally write the pivot row back into the correct row (if pivot is nonzero).
- for (int row = lowerBound; row <= upperBound; row++)
+ for (int row = lowerBound, rowRowLen = lowerBound * rowLen; row <= upperBound; row++, rowRowLen += rowLen)
{
long doCopy = ~ctCompare64(row, pivotRowIndex) & ~pivotIsZero;
long doNotCopy = ~doCopy;
- for (int col = 0; col < rowLen; col++)
+ for (int col = 0, rowRowLen_col = rowRowLen; col < rowLen; col++, rowRowLen_col++)
{
// Since the masks are disjoint, addition is equivalent to OR.
- packedA[row * rowLen + col] = (doNotCopy & packedA[row * rowLen + col]) |
+ packedA[rowRowLen_col] = (doNotCopy & packedA[rowRowLen_col]) |
(doCopy & pivotRow2[col]);
}
}
@@ -708,16 +704,19 @@ public void ef(byte[] A, int nrows, int ncols)
}
}
- byte[] temp = new byte[params.getO() * params.getK() + 1 + 15];
+ int outIndex = 0;
// At this point, packedA holds the row-echelon form of the original matrix.
// (Depending on your application you might want to unpack it back to A.)
- for (int i = 0; i < nrows; i++)
+ for (int i = 0, irowLen = 0; i < nrows; i++, irowLen += rowLen)
{
- GF16Utils.efUnpackMVector(rowLen, packedA, i * rowLen, temp);
- if (ncols >= 0)
+ Pack.longToLittleEndian(packedA, irowLen, len_4, bytes, 0);
+ int j = 0;
+ for (; j < ncols >> 1; j++)
{
- System.arraycopy(temp, 0, A, i * ncols, ncols);
+ A[outIndex++] = (byte)(bytes[j] & 0x0F); // Lower nibble
+ A[outIndex++] = (byte)((bytes[j] >> 4) & 0x0F); // Upper nibble
}
+ A[outIndex++] = (byte)(bytes[j] & 0x0F);
}
}
@@ -838,7 +837,7 @@ private static int mulTable(int b)
return x ^ (highHalf >>> 4) ^ (highHalf >>> 3);
}
- private static void mayoGenericMCalculatePS(MayoParameters p, long[] P1, long[] P2, long[] P3, byte[] S,
+ private static void mayoGenericMCalculatePS(MayoParameters p, long[] P1, int p2, int p3, byte[] S,
int m, int v, int o, int k, long[] PS)
{
int n = o + v;
@@ -861,7 +860,7 @@ private static void mayoGenericMCalculatePS(MayoParameters p, long[] P1, long[]
{
for (int col = 0, ncol = 0; col < k; col++, ncol += n)
{
- Longs.xorTo(mVecLimbs, P2, orow_j_mVecLimbs, accumulator, (((krow + col) << 4) + (S[ncol + j + v] & 0xFF)) * mVecLimbs);
+ Longs.xorTo(mVecLimbs, P1, p2 + orow_j_mVecLimbs, accumulator, (((krow + col) << 4) + (S[ncol + j + v] & 0xFF)) * mVecLimbs);
}
}
}
@@ -873,16 +872,13 @@ private static void mayoGenericMCalculatePS(MayoParameters p, long[] P1, long[]
{
for (int col = 0, ncol = 0; col < k; col++, ncol += n)
{
- Longs.xorTo(mVecLimbs, P3, pUsed, accumulator, (((krow + col) << 4) + (S[ncol + j] & 0xFF)) * mVecLimbs);
+ Longs.xorTo(mVecLimbs, P1, p3 + pUsed, accumulator, (((krow + col) << 4) + (S[ncol + j] & 0xFF)) * mVecLimbs);
}
pUsed += mVecLimbs;
}
}
- for (int i = 0, imVecLimbs = 0; i < n * k; i++, imVecLimbs += mVecLimbs)
- {
- mVecMultiplyBins(mVecLimbs, accumulator, imVecLimbs << 4, PS, imVecLimbs);
- }
+ mVecMultiplyBins(mVecLimbs, n * k, accumulator, PS);
}
private static void mayoGenericMCalculateSPS(long[] PS, byte[] S, int m, int k, int n, long[] SPS)
@@ -892,11 +888,11 @@ private static void mayoGenericMCalculateSPS(long[] PS, byte[] S, int m, int k,
final long[] accumulator = new long[accumulatorSize];
// Accumulation phase
- for (int row = 0; row < k; row++)
+ for (int row = 0, nrow = 0; row < k; row++, nrow += n)
{
for (int j = 0; j < n; j++)
{
- final int sVal = S[row * n + j] & 0xFF; // Unsigned byte value
+ final int sVal = S[nrow + j] & 0xFF; // Unsigned byte value
for (int col = 0; col < k; col++)
{
final int psOffset = (j * k + col) * mVecLimbs;
@@ -907,30 +903,30 @@ private static void mayoGenericMCalculateSPS(long[] PS, byte[] S, int m, int k,
}
// Processing phase
- for (int i = 0; i < k * k; i++)
- {
- mVecMultiplyBins(mVecLimbs, accumulator, i * 16 * mVecLimbs, SPS, i * mVecLimbs);
- }
+ mVecMultiplyBins(mVecLimbs, k * k, accumulator, SPS);
}
- private static void mVecMultiplyBins(int mVecLimbs, long[] bins, int binOffset, long[] ps, int psOff)
+ private static void mVecMultiplyBins(int mVecLimbs, int len, long[] bins, long[] ps)
{
- // Series of modular operations as per original C code
- mVecMulAddXInv(mVecLimbs, bins, binOffset + 5 * mVecLimbs, bins, binOffset + 10 * mVecLimbs);
- mVecMulAddX(mVecLimbs, bins, binOffset + 11 * mVecLimbs, bins, binOffset + 12 * mVecLimbs);
- mVecMulAddXInv(mVecLimbs, bins, binOffset + 10 * mVecLimbs, bins, binOffset + 7 * mVecLimbs);
- mVecMulAddX(mVecLimbs, bins, binOffset + 12 * mVecLimbs, bins, binOffset + 6 * mVecLimbs);
- mVecMulAddXInv(mVecLimbs, bins, binOffset + 7 * mVecLimbs, bins, binOffset + 14 * mVecLimbs);
- mVecMulAddX(mVecLimbs, bins, binOffset + 6 * mVecLimbs, bins, binOffset + 3 * mVecLimbs);
- mVecMulAddXInv(mVecLimbs, bins, binOffset + 14 * mVecLimbs, bins, binOffset + 15 * mVecLimbs);
- mVecMulAddX(mVecLimbs, bins, binOffset + 3 * mVecLimbs, bins, binOffset + 8 * mVecLimbs);
- mVecMulAddXInv(mVecLimbs, bins, binOffset + 15 * mVecLimbs, bins, binOffset + 13 * mVecLimbs);
- mVecMulAddX(mVecLimbs, bins, binOffset + 8 * mVecLimbs, bins, binOffset + 4 * mVecLimbs);
- mVecMulAddXInv(mVecLimbs, bins, binOffset + 13 * mVecLimbs, bins, binOffset + 9 * mVecLimbs);
- mVecMulAddX(mVecLimbs, bins, binOffset + 4 * mVecLimbs, bins, binOffset + 2 * mVecLimbs);
- mVecMulAddXInv(mVecLimbs, bins, binOffset + 9 * mVecLimbs, bins, binOffset + mVecLimbs);
- mVecMulAddX(mVecLimbs, bins, binOffset + 2 * mVecLimbs, bins, binOffset + mVecLimbs);
- System.arraycopy(bins, mVecLimbs + binOffset, ps, psOff, mVecLimbs);
+ for (int i = 0, imVecLimbs4 = 0; i < len; i++, imVecLimbs4 += (mVecLimbs << 4))
+ {
+ // Series of modular operations as per original C code
+ mVecMulAddXInv(mVecLimbs, bins, imVecLimbs4 + 5 * mVecLimbs, bins, imVecLimbs4 + 10 * mVecLimbs);
+ mVecMulAddX(mVecLimbs, bins, imVecLimbs4 + 11 * mVecLimbs, bins, imVecLimbs4 + 12 * mVecLimbs);
+ mVecMulAddXInv(mVecLimbs, bins, imVecLimbs4 + 10 * mVecLimbs, bins, imVecLimbs4 + 7 * mVecLimbs);
+ mVecMulAddX(mVecLimbs, bins, imVecLimbs4 + 12 * mVecLimbs, bins, imVecLimbs4 + 6 * mVecLimbs);
+ mVecMulAddXInv(mVecLimbs, bins, imVecLimbs4 + 7 * mVecLimbs, bins, imVecLimbs4 + 14 * mVecLimbs);
+ mVecMulAddX(mVecLimbs, bins, imVecLimbs4 + 6 * mVecLimbs, bins, imVecLimbs4 + 3 * mVecLimbs);
+ mVecMulAddXInv(mVecLimbs, bins, imVecLimbs4 + 14 * mVecLimbs, bins, imVecLimbs4 + 15 * mVecLimbs);
+ mVecMulAddX(mVecLimbs, bins, imVecLimbs4 + 3 * mVecLimbs, bins, imVecLimbs4 + 8 * mVecLimbs);
+ mVecMulAddXInv(mVecLimbs, bins, imVecLimbs4 + 15 * mVecLimbs, bins, imVecLimbs4 + 13 * mVecLimbs);
+ mVecMulAddX(mVecLimbs, bins, imVecLimbs4 + 8 * mVecLimbs, bins, imVecLimbs4 + 4 * mVecLimbs);
+ mVecMulAddXInv(mVecLimbs, bins, imVecLimbs4 + 13 * mVecLimbs, bins, imVecLimbs4 + 9 * mVecLimbs);
+ mVecMulAddX(mVecLimbs, bins, imVecLimbs4 + 4 * mVecLimbs, bins, imVecLimbs4 + 2 * mVecLimbs);
+ mVecMulAddXInv(mVecLimbs, bins, imVecLimbs4 + 9 * mVecLimbs, bins, imVecLimbs4 + mVecLimbs);
+ mVecMulAddX(mVecLimbs, bins, imVecLimbs4 + 2 * mVecLimbs, bins, imVecLimbs4 + mVecLimbs);
+ System.arraycopy(bins, mVecLimbs + imVecLimbs4, ps, imVecLimbs4 >> 4, mVecLimbs);
+ }
}
// Modular arithmetic operations
From 0a7476d4ab93df24fcbde791c8623e394a50335b Mon Sep 17 00:00:00 2001
From: Hawk Itzme
Date: Mon, 3 Mar 2025 17:35:15 +0530
Subject: [PATCH 142/890] Suppress Lint warning for TrustAllX509TrustManager in
JcaJceUtils
---
pkix/src/main/java/org/bouncycastle/est/jcajce/JcaJceUtils.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/pkix/src/main/java/org/bouncycastle/est/jcajce/JcaJceUtils.java b/pkix/src/main/java/org/bouncycastle/est/jcajce/JcaJceUtils.java
index d581c55aea..3f6024e21b 100644
--- a/pkix/src/main/java/org/bouncycastle/est/jcajce/JcaJceUtils.java
+++ b/pkix/src/main/java/org/bouncycastle/est/jcajce/JcaJceUtils.java
@@ -35,6 +35,7 @@
public class JcaJceUtils
{
+ @SuppressWarnings("TrustAllX509TrustManager")
public static X509TrustManager getTrustAllTrustManager()
{
From bec5d19acd2b806065944a7c57997385f78285a6 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Tue, 4 Mar 2025 07:30:58 +1030
Subject: [PATCH 143/890] Refactor for Mayo
---
.../pqc/crypto/mayo/GF16Utils.java | 64 ++--
.../pqc/crypto/mayo/MayoEngine.java | 183 ---------
.../pqc/crypto/mayo/MayoKeyPairGenerator.java | 7 +-
.../pqc/crypto/mayo/MayoSigner.java | 355 +++++++++---------
.../bouncycastle/pqc/crypto/mayo/Utils.java | 90 +++--
5 files changed, 287 insertions(+), 412 deletions(-)
delete mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoEngine.java
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java
index 7882cc472a..6595d412eb 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java
@@ -2,6 +2,10 @@
public class GF16Utils
{
+ static final long NIBBLE_MASK_MSB = 0x7777777777777777L;
+ static final long MASK_MSB = 0x8888888888888888L;
+ static final long MASK_LSB = 0x1111111111111111L;
+ static final long NIBBLE_MASK_LSB = ~MASK_LSB;
/**
* Multiplies each limb of a GF(16) vector (subarray of 'in') by the GF(16) element 'a'
@@ -18,8 +22,7 @@ public class GF16Utils
*/
public static void mVecMulAdd(int mVecLimbs, long[] in, int inOffset, int b, long[] acc, int accOffset)
{
- long maskMsb = 0x8888888888888888L;
- long a, r64, a_msb;
+ long a, r64, a_msb, a_msb3;
long b32 = b & 0x00000000FFFFFFFFL;
long b32and1 = b32 & 1;
long b32_1_1 = ((b32 >>> 1) & 1);
@@ -29,23 +32,26 @@ public static void mVecMulAdd(int mVecLimbs, long[] in, int inOffset, int b, lon
{
// In the original code there is a conditional XOR with unsigned_char_blocker;
// here we simply use b directly.
- a = in[inOffset + i];
- r64 = a * b32and1;
+ a = in[inOffset++];
+ r64 = a & -b32and1;
- a_msb = a & maskMsb;
- a ^= a_msb;
- a = (a << 1) ^ ((a_msb >>> 3) * 3);
- r64 ^= a * b32_1_1;
+ a_msb = a & MASK_MSB;
+ a &= NIBBLE_MASK_MSB;
+ a_msb3 = a_msb >>> 3;
+ a = (a << 1) ^ (a_msb3 + (a_msb3 << 1));
+ r64 ^= a & -b32_1_1;
- a_msb = a & maskMsb;
- a ^= a_msb;
- a = (a << 1) ^ ((a_msb >>> 3) * 3);
- r64 ^= a * b32_2_1;
+ a_msb = a & MASK_MSB;
+ a &= NIBBLE_MASK_MSB;
+ a_msb3 = a_msb >>> 3;
+ a = (a << 1) ^ (a_msb3 + (a_msb3 << 1));
+ r64 ^= a & -b32_2_1;
- a_msb = a & maskMsb;
- a ^= a_msb;
- a = (a << 1) ^ ((a_msb >>> 3) * 3);
- acc[accOffset + i] ^= r64 ^ (a * b32_3_1);
+ a_msb = a & MASK_MSB;
+ a &= NIBBLE_MASK_MSB;
+ a_msb3 = a_msb >>> 3;
+ a = (a << 1) ^ (a_msb3 + (a_msb3 << 1));
+ acc[accOffset++] ^= r64 ^ (a & -b32_3_1);
}
}
@@ -190,24 +196,22 @@ public static void mulAddMatXMMat(int mVecLimbs, byte[] mat, long[] bsMat, int b
* by the scalar (from {@code mat}) and adds the result to the corresponding vector in {@code acc}.
*
*
- * @param mVecLimbs the number of limbs (elements) in each vector.
- * @param bsMat the bit‑sliced matrix stored as a long array.
- * @param mat the matrix stored as a byte array.
- * @param acc the accumulator array where the results are added.
- * @param bsMatRows the number of rows in the bit‑sliced matrix.
- * @param bsMatCols the number of columns in the bit‑sliced matrix.
- * @param matRows the number of rows in the matrix.
- * @param triangular if non‑zero, indicates that the matrix is upper triangular (i.e. the loop for {@code c}
- * starts at {@code triangular * r}).
+ * @param mVecLimbs the number of limbs (elements) in each vector.
+ * @param bsMat the bit‑sliced matrix stored as a long array.
+ * @param mat the matrix stored as a byte array.
+ * @param acc the accumulator array where the results are added.
+ * @param bsMatRows the number of rows in the bit‑sliced matrix.
+ * @param bsMatCols the number of columns in the bit‑sliced matrix.
+ * @param matRows the number of rows in the matrix.
*/
public static void mulAddMUpperTriangularMatXMatTrans(int mVecLimbs, long[] bsMat, byte[] mat, long[] acc,
- int bsMatRows, int bsMatCols, int matRows, int triangular)
+ int bsMatRows, int bsMatCols, int matRows)
{
int bsMatEntriesUsed = 0;
for (int r = 0; r < bsMatRows; r++)
{
// For upper triangular, start c at triangular * r; otherwise, triangular is zero.
- for (int c = triangular * r; c < bsMatCols; c++)
+ for (int c = r; c < bsMatCols; c++)
{
for (int k = 0; k < matRows; k++)
{
@@ -270,8 +274,7 @@ public static long mulFx8(byte a, long b)
return (p ^ (topP >> 4) ^ (topP >> 3)) & 0x0f0f0f0f0f0f0f0fL;
}
- public static void matMul(byte[] a, byte[] b, byte[] c,
- int colrowAB, int rowA, int colB)
+ public static void matMul(byte[] a, byte[] b, byte[] c, int colrowAB, int rowA, int colB)
{
int cIndex = 0;
for (int i = 0; i < rowA; i++)
@@ -287,12 +290,11 @@ public static void matMul(byte[] a, byte[] b, byte[] c,
public static void matMul(byte[] a, int aOff, byte[] b, int bOff, byte[] c, int cOff,
int colrowAB, int rowA, int colB)
{
- int cIndex = 0;
for (int i = 0, aRowStart = 0; i < rowA; i++, aRowStart += colrowAB)
{
for (int j = 0; j < colB; j++)
{
- c[cOff + cIndex++] = lincomb(a, aOff + aRowStart, b, bOff + j, colrowAB, colB);
+ c[cOff++] = lincomb(a, aOff + aRowStart, b, bOff + j, colrowAB, colB);
}
}
}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoEngine.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoEngine.java
deleted file mode 100644
index f93e2848da..0000000000
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoEngine.java
+++ /dev/null
@@ -1,183 +0,0 @@
-package org.bouncycastle.pqc.crypto.mayo;
-
-import org.bouncycastle.crypto.BlockCipher;
-import org.bouncycastle.crypto.engines.AESEngine;
-import org.bouncycastle.crypto.modes.CTRModeCipher;
-import org.bouncycastle.crypto.modes.SICBlockCipher;
-import org.bouncycastle.crypto.params.KeyParameter;
-import org.bouncycastle.crypto.params.ParametersWithIV;
-import org.bouncycastle.util.Arrays;
-import org.bouncycastle.util.Pack;
-
-public class MayoEngine
-{
- /**
- * Expands P1 and P2 using AES_128_CTR as a PRF and then unpacks the resulting bytes
- * into an array of 64-bit limbs.
- *
- * @param p Mayo parameters
- * @param P The output long array which will hold the unpacked limbs.
- * Its length should be at least ((P1_bytes + P2_bytes) / 8) limbs.
- * @param seed_pk The seed (used as the key) for the PRF.
- * @return The number of bytes produced, i.e., P1_bytes + P2_bytes.
- */
- public static int expandP1P2(MayoParameters p, long[] P, byte[] seed_pk)
- {
- // Compute total number of bytes to generate: P1_bytes + P2_bytes.
- int outLen = p.getP1Bytes() + p.getP2Bytes();
- // Temporary byte array to hold the PRF output.
- byte[] temp = new byte[outLen];
-
- // Call AES_128_CTR (our previously defined function using BouncyCastle)
- // to fill temp with outLen pseudorandom bytes using seed_pk as key.
- AES_128_CTR(temp, outLen, seed_pk, p.getPkSeedBytes());
-
- // The number of vectors is the total limbs divided by mVecLimbs.
- int numVectors = (p.getP1Limbs() + p.getP2Limbs()) / p.getMVecLimbs();
-
- // Unpack the byte array 'temp' into the long array 'P'
- // using our previously defined unpackMVecs method.
- Utils.unpackMVecs(temp, P, numVectors, p.getM());
-
- // Return the number of output bytes produced.
- return outLen;
- }
-
- /**
- * AES_128_CTR generates outputByteLen bytes using AES-128 in CTR mode.
- * The key (of length keyLen) is used to expand the AES key.
- * A 16-byte IV (all zeros) is used.
- *
- * @param output the output buffer which will be filled with the keystream
- * @param outputByteLen the number of bytes to produce
- * @param key the AES key (should be 16 bytes for AES-128)
- * @param keyLen the length of the key (unused here but kept for similarity)
- * @return the number of output bytes produced (i.e. outputByteLen)
- */
- public static int AES_128_CTR(byte[] output, int outputByteLen, byte[] key, int keyLen)
- {
- // Create a 16-byte IV (all zeros)
- byte[] iv = new byte[16]; // automatically zero-initialized
-
- // Set up AES engine in CTR (SIC) mode.
- BlockCipher aesEngine = AESEngine.newInstance();
- // SICBlockCipher implements CTR mode for AES.
- CTRModeCipher ctrCipher = SICBlockCipher.newInstance(aesEngine);
- // Wrap the key with the IV.
- ParametersWithIV params = new ParametersWithIV(new KeyParameter(Arrays.copyOf(key, keyLen)), iv);
- ctrCipher.init(true, params);
-
- // CTR mode is a stream cipher: encrypting zero bytes produces the keystream.
- int blockSize = ctrCipher.getBlockSize(); // typically 16 bytes
- byte[] zeroBlock = new byte[blockSize]; // block of zeros
- byte[] blockOut = new byte[blockSize];
-
- int offset = 0;
- // Process full blocks
- while (offset + blockSize <= outputByteLen)
- {
- ctrCipher.processBlock(zeroBlock, 0, blockOut, 0);
- System.arraycopy(blockOut, 0, output, offset, blockSize);
- offset += blockSize;
- }
- // Process any remaining partial block.
- if (offset < outputByteLen)
- {
- ctrCipher.processBlock(zeroBlock, 0, blockOut, 0);
- int remaining = outputByteLen - offset;
- System.arraycopy(blockOut, 0, output, offset, remaining);
- }
- return outputByteLen;
- }
-
- public static final int MAYO_OK = 0;
-
- /**
- * Expands the secret key.
- *
- * @param p the MayoParameters instance.
- * @param csk the input secret key seed (byte array).
- * @return MAYO_OK on success.
- */
- public static int mayoExpandSk(MayoParameters p, byte[] csk, long[] P, byte[] O)
- {
- int ret = MAYO_OK;
- int totalS = p.getPkSeedBytes() + p.getOBytes();
- byte[] S = new byte[totalS];
-
- // sk.p is the long[] array, sk.O is the byte[] array.
-
- int param_o = p.getO();
- int param_v = p.getV();
- int param_O_bytes = p.getOBytes();
- int param_pk_seed_bytes = p.getPkSeedBytes();
- int param_sk_seed_bytes = p.getSkSeedBytes();
-
- // In C, seed_sk = csk and seed_pk = S (the beginning of S)
- byte[] seed_sk = csk;
- byte[] seed_pk = S; // first param_pk_seed_bytes of S
-
- // Generate S = seed_pk || (additional bytes), using SHAKE256.
- // Output length is param_pk_seed_bytes + param_O_bytes.
- Utils.shake256(S, param_pk_seed_bytes + param_O_bytes, seed_sk, param_sk_seed_bytes);
-
- // Decode the portion of S after the first param_pk_seed_bytes into O.
- // (In C, this is: decode(S + param_pk_seed_bytes, O, param_v * param_o))
- Utils.decode(S, param_pk_seed_bytes, O, param_v * param_o);
-
- // Expand P1 and P2 into the long array P using seed_pk.
- MayoEngine.expandP1P2(p, P, seed_pk);
-
- // Let P2 start at offset = PARAM_P1_limbs(p)
- int p1Limbs = p.getP1Limbs();
- int offsetP2 = p1Limbs;
-
- // Compute L_i = (P1 + P1^t)*O + P2.
- // Here, we assume that P1P1tTimesO writes into the portion of P starting at offsetP2.
- P1P1tTimesO(p, P, O, P, offsetP2);
-
- // Securely clear sensitive temporary data.
- java.util.Arrays.fill(S, (byte)0);
- return ret;
- }
-
- /**
- * Multiplies and accumulates the product (P1 + P1^t)*O into the accumulator.
- * This version writes into the 'acc' array starting at the specified offset.
- *
- * @param p the MayoParameters.
- * @param P1 the P1 vector as a long[] array.
- * @param O the O array (each byte represents a GF(16) element).
- * @param acc the accumulator array where results are XORed in.
- * @param accOffset the starting index in acc.
- */
- public static void P1P1tTimesO(MayoParameters p, long[] P1, byte[] O, long[] acc, int accOffset)
- {
- int paramO = p.getO();
- int paramV = p.getV();
- int mVecLimbs = p.getMVecLimbs();
- int bsMatEntriesUsed = 0;
- for (int r = 0; r < paramV; r++)
- {
- for (int c = r; c < paramV; c++)
- {
- if (c == r)
- {
- bsMatEntriesUsed++;
- continue;
- }
- for (int k = 0; k < paramO; k++)
- {
- // Multiply the m-vector at P1 for the current matrix entry,
- // and accumulate into acc for row r.
- GF16Utils.mVecMulAdd(mVecLimbs, P1, bsMatEntriesUsed * mVecLimbs,
- O[c * paramO + k] & 0xFF, acc, accOffset + (r * paramO + k) * mVecLimbs);
- // Similarly, accumulate into acc for row c.
- GF16Utils.mVecMulAdd(mVecLimbs, P1, bsMatEntriesUsed * mVecLimbs,
- O[r * paramO + k] & 0xFF, acc, accOffset + (c * paramO + k) * mVecLimbs);
- }
- bsMatEntriesUsed++;
- }
- }
- }
-}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
index 42a349d5a8..1a5f9ff037 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
@@ -5,6 +5,7 @@
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
import org.bouncycastle.crypto.KeyGenerationParameters;
+import org.bouncycastle.crypto.digests.SHAKEDigest;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Longs;
@@ -53,7 +54,9 @@ public AsymmetricCipherKeyPair generateKeyPair()
random.nextBytes(seed_sk);
// S ← shake256(seed_sk, pk_seed_bytes + O_bytes)
- Utils.shake256(seed_pk, pkSeedBytes + oBytes, seed_sk, skSeedBytes);
+ SHAKEDigest shake = new SHAKEDigest(256);
+ shake.update(seed_sk, 0, skSeedBytes);
+ shake.doFinal(seed_pk, 0, pkSeedBytes + oBytes);
// o ← Decode_o(S[ param_pk_seed_bytes : param_pk_seed_bytes + O_bytes ])
// Decode nibbles from S starting at offset param_pk_seed_bytes into O,
@@ -61,7 +64,7 @@ public AsymmetricCipherKeyPair generateKeyPair()
Utils.decode(seed_pk, pkSeedBytes, O, O.length);
// Expand P1 and P2 into the array P using seed_pk.
- MayoEngine.expandP1P2(p, P, seed_pk);
+ Utils.expandP1P2(p, P, seed_pk);
// Compute P1 * O + P2 and store the result in P2.
// GF16Utils.P1TimesO(p, P, O, P2);
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
index f6d2b77c3d..df6922625d 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
@@ -55,51 +55,98 @@ public byte[] generateSignature(byte[] message)
int k = params.getK();
int v = params.getV();
int o = params.getO();
+ int n = params.getN();
+ int vbytes = params.getVBytes();
+ int oBytes = params.getOBytes();
int saltBytes = params.getSaltBytes();
int mVecLimbs = params.getMVecLimbs();
+ int p1Limbs = params.getP1Limbs();
+ int pk_seed_bytes = params.getPkSeedBytes();
+ int digestBytes = params.getDigestBytes();
+ int skSeedBytes = params.getSkSeedBytes();
byte[] tenc = new byte[params.getMBytes()];
byte[] t = new byte[params.getM()];
byte[] y = new byte[params.getM()];
byte[] salt = new byte[saltBytes];
- byte[] V = new byte[k * params.getVBytes() + params.getRBytes()];
+ byte[] V = new byte[k * vbytes + params.getRBytes()];
byte[] Vdec = new byte[v * k];
byte[] A = new byte[((params.getM() + 7) / 8 * 8) * (k * o + 1)];
- byte[] x = new byte[k * params.getN()];
+ byte[] x = new byte[k * n];
byte[] r = new byte[k * o + 1];
- byte[] s = new byte[k * params.getN()];
- byte[] tmp = new byte[params.getDigestBytes() + saltBytes + params.getSkSeedBytes() + 1];
+ byte[] s = new byte[k * n];
+ byte[] tmp = new byte[digestBytes + saltBytes + skSeedBytes + 1];
byte[] sig = new byte[params.getSigBytes()];
- long[] P = new long[params.getP1Limbs() + params.getP2Limbs()];
+ long[] P = new long[p1Limbs + params.getP2Limbs()];
byte[] O = new byte[v * o];
- long[] Mtmp = new long[k * o * params.getMVecLimbs()];
- long[] vPv = new long[k * k * params.getMVecLimbs()];
-
+ long[] Mtmp = new long[k * o * mVecLimbs];
+ long[] vPv = new long[k * k * mVecLimbs];
+ SHAKEDigest shake = new SHAKEDigest(256);
try
{
+ byte[] seed_sk = privKey.getSeedSk();
// Expand secret key
- MayoEngine.mayoExpandSk(params, privKey.getSeedSk(), P, O);
+ //MayoEngine.mayoExpandSk(params, seed_sk, P, O);
+ int totalS = pk_seed_bytes + oBytes;
+ byte[] seed_pk = new byte[totalS];
+
+ // Generate S = seed_pk || (additional bytes), using SHAKE256.
+ // Output length is param_pk_seed_bytes + param_O_bytes.
+ shake.update(seed_sk, 0, seed_sk.length);
+ shake.doFinal(seed_pk, 0, pk_seed_bytes + oBytes);
+
+ // Decode the portion of S after the first param_pk_seed_bytes into O.
+ // (In C, this is: decode(S + param_pk_seed_bytes, O, param_v * param_o))
+ Utils.decode(seed_pk, pk_seed_bytes, O, v * o);
+
+ // Expand P1 and P2 into the long array P using seed_pk.
+ Utils.expandP1P2(params, P, seed_pk);
+
+ // Compute L_i = (P1 + P1^t)*O + P2.
+ // Here, we assume that P1P1tTimesO writes into the portion of P starting at offsetP2.
+ //MayoEngine.P1P1tTimesO(params, P, O, P, p1Limbs);
+ int bsMatEntriesUsed = 0;
+ int omVecLimbs = o * mVecLimbs;
+ for (int i = 0, io = 0, iomVecLimbs = 0; i < v; i++, io += o, iomVecLimbs += omVecLimbs)
+ {
+ for (int c = i, co = io, comVecLimbs = iomVecLimbs; c < v; c++, co += o, comVecLimbs += omVecLimbs)
+ {
+ if (c == i)
+ {
+ bsMatEntriesUsed += mVecLimbs;
+ continue;
+ }
+ for (int j = 0, jmVecLimbs = p1Limbs; j < o; j++, jmVecLimbs += mVecLimbs)
+ {
+ // Multiply the m-vector at P1 for the current matrix entry,
+ // and accumulate into acc for row r.
+ GF16Utils.mVecMulAdd(mVecLimbs, P, bsMatEntriesUsed, O[co + j] & 0xFF, P, iomVecLimbs + jmVecLimbs);
+ // Similarly, accumulate into acc for row c.
+ GF16Utils.mVecMulAdd(mVecLimbs, P, bsMatEntriesUsed, O[io + j] & 0xFF, P, comVecLimbs + jmVecLimbs);
+ }
+ bsMatEntriesUsed += mVecLimbs;
+ }
+ }
+ // Securely clear sensitive temporary data.
+ Arrays.fill(seed_pk, (byte)0);
// Hash message
- SHAKEDigest shake = new SHAKEDigest(256);
shake.update(message, 0, message.length);
- shake.doFinal(tmp, 0, params.getDigestBytes());
+ shake.doFinal(tmp, 0, digestBytes);
// Generate random salt
random.nextBytes(salt);
- System.arraycopy(salt, 0, tmp, params.getDigestBytes(), salt.length);
+ System.arraycopy(salt, 0, tmp, digestBytes, salt.length);
// Hash to salt
- System.arraycopy(privKey.getSeedSk(), 0, tmp, params.getDigestBytes() + saltBytes,
- params.getSkSeedBytes());
+ System.arraycopy(seed_sk, 0, tmp, digestBytes + saltBytes, skSeedBytes);
- shake.update(tmp, 0, params.getDigestBytes() + saltBytes +
- params.getSkSeedBytes());
+ shake.update(tmp, 0, digestBytes + saltBytes + skSeedBytes);
shake.doFinal(salt, 0, saltBytes);
// Hash to t
- System.arraycopy(salt, 0, tmp, params.getDigestBytes(), saltBytes);
- shake.update(tmp, 0, params.getDigestBytes() + saltBytes);
+ System.arraycopy(salt, 0, tmp, digestBytes, saltBytes);
+ shake.update(tmp, 0, digestBytes + saltBytes);
shake.doFinal(tenc, 0, params.getMBytes());
Utils.decode(tenc, t, params.getM());
@@ -114,12 +161,12 @@ public byte[] generateSignature(byte[] message)
// Decode vectors
for (int i = 0; i < k; i++)
{
- Utils.decode(V, i * params.getVBytes(), Vdec, i * v, v);
+ Utils.decode(V, i * vbytes, Vdec, i * v, v);
}
//computeMandVPV(params, Vdec, P, params.getP1Limbs(), P, Mtmp, vPv);
// Compute VL: VL = Vdec * L
- GF16Utils.mulAddMatXMMat(mVecLimbs, Vdec, P, params.getP1Limbs(), Mtmp, k, v, o);
+ GF16Utils.mulAddMatXMMat(mVecLimbs, Vdec, P, p1Limbs, Mtmp, k, v, o);
// Compute VP1V:
// Allocate temporary array for Pv. Its length is V_MAX * K_MAX * M_VEC_LIMBS_MAX.
@@ -127,7 +174,7 @@ public byte[] generateSignature(byte[] message)
long[] Pv = new long[size]; // automatically initialized to zero in Java
// Compute Pv = P1 * V^T (using upper triangular multiplication)
- GF16Utils.mulAddMUpperTriangularMatXMatTrans(mVecLimbs, P, Vdec, Pv, v, v, k, 1);
+ GF16Utils.mulAddMUpperTriangularMatXMatTrans(mVecLimbs, P, Vdec, Pv, v, v, k);
// Compute VP1V = Vdec * Pv
GF16Utils.mulAddMatXMMat(mVecLimbs, Vdec, Pv, vPv, k, v, k);
@@ -135,13 +182,12 @@ public byte[] generateSignature(byte[] message)
computeA(Mtmp, A);
// Clear trailing bytes
- for (int i = 0; i < params.getM(); ++i)
- {
- A[(i + 1) * (k * o + 1) - 1] = 0;
- }
+// for (int i = 0; i < params.getM(); ++i)
+// {
+// A[(i + 1) * (k * o + 1) - 1] = 0;
+// }
- Utils.decode(V, k * params.getVBytes(), r, 0,
- k * o);
+ Utils.decode(V, k * vbytes, r, 0, k * o);
if (sampleSolution(params, A, y, r, x))
{
@@ -158,17 +204,14 @@ public byte[] generateSignature(byte[] message)
byte[] Ox = new byte[v];
for (int i = 0; i < k; i++)
{
- byte[] vi = Arrays.copyOfRange(Vdec, i * v, (i + 1) * v);
- GF16Utils.matMul(O, 0, x, i * o, Ox, 0, o, params.getN() - o, 1);
- GF16Utils.matAdd(vi, 0, Ox, 0, s, i * params.getN(), v, 1);
- System.arraycopy(x, i * o, s,
- i * params.getN() + params.getN() - o, o);
+ GF16Utils.matMul(O, 0, x, i * o, Ox, 0, o, n - o, 1);
+ GF16Utils.matAdd(Vdec, i * v, Ox, 0, s, i * n, v, 1);
+ System.arraycopy(x, i * o, s, i * n + n - o, o);
}
// Encode and add salt
- Utils.encode(s, sig, params.getN() * k);
- System.arraycopy(salt, 0, sig, sig.length - saltBytes,
- saltBytes);
+ Utils.encode(s, sig, n * k);
+ System.arraycopy(salt, 0, sig, sig.length - saltBytes, saltBytes);
return Arrays.concatenate(sig, message);
}
@@ -195,46 +238,48 @@ public boolean verifySignature(byte[] message, byte[] signature)
final int m = params.getM();
final int n = params.getN();
final int k = params.getK();
+ int kn = k * n;
int p1Limbs = params.getP1Limbs();
int p2Limbs = params.getP2Limbs();
int p3Limbs = params.getP3Limbs();
- final int paramMBytes = params.getMBytes();
- final int paramSigBytes = params.getSigBytes();
- final int paramDigestBytes = params.getDigestBytes();
- final int paramSaltBytes = params.getSaltBytes();
-
- byte[] tEnc = new byte[params.getMBytes()];
- byte[] t = new byte[params.getM()];
- byte[] y = new byte[2 * params.getM()];
- byte[] s = new byte[params.getK() * params.getN()];
- long[] pk = new long[p1Limbs + params.getP2Limbs() + params.getP3Limbs()];
- byte[] tmp = new byte[params.getDigestBytes() + params.getSaltBytes()];
+ final int mBytes = params.getMBytes();
+ final int sigBytes = params.getSigBytes();
+ final int digestBytes = params.getDigestBytes();
+ final int saltBytes = params.getSaltBytes();
+ int mVecLimbs = params.getMVecLimbs();
+ byte[] tEnc = new byte[mBytes];
+ byte[] t = new byte[m];
+ byte[] y = new byte[m << 1];
+ byte[] s = new byte[kn];
+ long[] pk = new long[p1Limbs + p2Limbs + p3Limbs];
+ byte[] tmp = new byte[digestBytes + saltBytes];
byte[] cpk = pubKey.getEncoded();
// Expand public key
// mayo_expand_pk
- MayoEngine.expandP1P2(params, pk, cpk);
- Utils.unpackMVecs(cpk, params.getPkSeedBytes(), pk, p1Limbs + params.getP2Limbs(), params.getP3Limbs() / params.getMVecLimbs(), params.getM());
-
+ Utils.expandP1P2(params, pk, cpk);
+ Utils.unpackMVecs(cpk, params.getPkSeedBytes(), pk, p1Limbs + p2Limbs, p3Limbs / mVecLimbs, m);
// Hash message
- Utils.shake256(tmp, paramDigestBytes, message, message.length);
+ SHAKEDigest shake = new SHAKEDigest(256);
+ shake.update(message, 0, message.length);
+ shake.doFinal(tmp, 0, digestBytes);
// Compute t
- System.arraycopy(signature, paramSigBytes - paramSaltBytes, tmp, paramDigestBytes, paramSaltBytes);
- Utils.shake256(tEnc, paramMBytes, tmp, paramDigestBytes + paramSaltBytes);
+ shake.update(tmp, 0, digestBytes);
+ shake.update(signature, sigBytes - saltBytes, saltBytes);
+ shake.doFinal(tEnc, 0, mBytes);
Utils.decode(tEnc, t, m);
// Decode signature
- Utils.decode(signature, s, k * n);
+ Utils.decode(signature, s, kn);
// Evaluate public map
-// evalPublicMap(params, s, P1, P2, P3, y);
- int mVecLimbs = (params.getM() + 15) / 16;
+ //evalPublicMap(params, s, P1, P2, P3, y);
long[] SPS = new long[k * k * mVecLimbs];
- long[] PS = new long[n * k * mVecLimbs];
- mayoGenericMCalculatePS(params, pk, p1Limbs, p1Limbs + p2Limbs, s, m, params.getV(), params.getO(), k, PS);
- mayoGenericMCalculateSPS(PS, s, m, k, n, SPS);
+ long[] PS = new long[kn * mVecLimbs];
+ mayoGenericMCalculatePS(params, pk, p1Limbs, p1Limbs + p2Limbs, s, params.getV(), params.getO(), k, PS);
+ mayoGenericMCalculateSPS(PS, s, mVecLimbs, k, n, SPS);
byte[] zero = new byte[m];
computeRHS(SPS, zero, y);
@@ -249,13 +294,12 @@ public void computeRHS(long[] vPv, byte[] t, byte[] y)
final int k = params.getK();
final int[] fTail = params.getFTail();
- final int topPos = ((m - 1) % 16) * 4;
+ final int topPos = ((m - 1) & 15) * 4;
// Zero out tails of m_vecs if necessary
- if (m % 16 != 0)
+ if ((m & 15) != 0)
{
- long mask = 1L;
- mask <<= ((m % 16) * 4);
+ long mask = 1L << ((m & 15) << 2);
mask -= 1;
final int kSquared = k * k;
@@ -294,13 +338,13 @@ public void computeRHS(long[] vPv, byte[] t, byte[] y)
}
long product = GF16Utils.mulF(top, ft);
- if (jj % 2 == 0)
+ if ((jj & 1) == 0)
{
- tempBytes[jj / 2] ^= (byte)(product & 0xF);
+ tempBytes[jj >> 1] ^= (byte)(product & 0xF);
}
else
{
- tempBytes[jj / 2] ^= (byte)((product & 0xF) << 4);
+ tempBytes[jj >> 1] ^= (byte)((product & 0xF) << 4);
}
}
Pack.littleEndianToLong(tempBytes, 0, temp);
@@ -334,7 +378,6 @@ public void computeRHS(long[] vPv, byte[] t, byte[] y)
private static final int F_TAIL_LEN = 4;
private static final long EVEN_BYTES = 0x00FF00FF00FF00FFL;
private static final long EVEN_2BYTES = 0x0000FFFF0000FFFFL;
- private static final long LOW_BIT_IN_NIBBLE = 0x1111111111111111L;
public void computeA(long[] Mtmp, byte[] AOut)
{
@@ -347,18 +390,18 @@ public void computeA(long[] Mtmp, byte[] AOut)
int bitsToShift = 0;
int wordsToShift = 0;
- final int MAYO_M_OVER_8 = (m + 7) / 8;
- final int AWidth = ((o * k + 15) / 16) * 16;
- long[] A = new long[AWidth * MAYO_M_OVER_8 * 16];
+ final int MAYO_M_OVER_8 = (m + 7) >>> 3;
+ int ok = o * k;
+ final int AWidth = ((ok + 15) >> 4) << 4;
+ long[] A = new long[(AWidth * MAYO_M_OVER_8) << 4];
// Zero out tails of m_vecs if necessary
- if (m % 16 != 0)
+ if ((m & 15) != 0)
{
- long mask = 1L << ((m % 16) * 4);
+ long mask = 1L << ((m & 15) << 2);
mask -= 1;
- for (int i = 0; i < o * k; i++)
+ for (int i = 0, idx = mVecLimbs - 1; i < ok; i++, idx += mVecLimbs)
{
- int idx = i * mVecLimbs + mVecLimbs - 1;
Mtmp[idx] &= mask;
}
}
@@ -425,13 +468,13 @@ public void computeA(long[] Mtmp, byte[] AOut)
// Generate tab array
byte[] tab = new byte[F_TAIL_LEN << 2];
- for (int i = 0; i < F_TAIL_LEN; i++)
+ for (int i = 0, idx = 0; i < F_TAIL_LEN; i++)
{
byte ft = fTailArr[i];
- tab[4 * i] = (byte)GF16Utils.mulF(ft, 1);
- tab[4 * i + 1] = (byte)GF16Utils.mulF(ft, 2);
- tab[4 * i + 2] = (byte)GF16Utils.mulF(ft, 4);
- tab[4 * i + 3] = (byte)GF16Utils.mulF(ft, 8);
+ tab[idx++] = (byte)GF16Utils.mulF(ft, 1);
+ tab[idx++] = (byte)GF16Utils.mulF(ft, 2);
+ tab[idx++] = (byte)GF16Utils.mulF(ft, 4);
+ tab[idx++] = (byte)GF16Utils.mulF(ft, 8);
}
// Final processing
@@ -439,19 +482,18 @@ public void computeA(long[] Mtmp, byte[] AOut)
{
for (int r = m; r < m + (k + 1) * k / 2; r++)
{
- int pos = (r / 16) * AWidth + c + (r % 16);
- long t0 = A[pos] & LOW_BIT_IN_NIBBLE;
- long t1 = (A[pos] >>> 1) & LOW_BIT_IN_NIBBLE;
- long t2 = (A[pos] >>> 2) & LOW_BIT_IN_NIBBLE;
- long t3 = (A[pos] >>> 3) & LOW_BIT_IN_NIBBLE;
+ int pos = (r >>> 4) * AWidth + c + (r & 15);
+ long t0 = A[pos] & GF16Utils.MASK_LSB;
+ long t1 = (A[pos] >>> 1) & GF16Utils.MASK_LSB;
+ long t2 = (A[pos] >>> 2) & GF16Utils.MASK_LSB;
+ long t3 = (A[pos] >>> 3) & GF16Utils.MASK_LSB;
- for (int t = 0; t < F_TAIL_LEN; t++)
+ for (int t = 0, t4 = 0; t < F_TAIL_LEN; t++, t4 += 4)
{
int targetRow = r + t - m;
- int targetPos = (targetRow / 16) * AWidth + c + (targetRow % 16);
- long xorValue = (t0 * tab[4 * t]) ^ (t1 * tab[4 * t + 1])
- ^ (t2 * tab[4 * t + 2]) ^ (t3 * tab[4 * t + 3]);
- A[targetPos] ^= xorValue;
+ int targetPos = (targetRow >> 4) * AWidth + c + (targetRow & 15);
+ A[targetPos] ^= (t0 * tab[t4]) ^ (t1 * tab[t4 + 1])
+ ^ (t2 * tab[t4 + 2]) ^ (t3 * tab[t4 + 3]);
}
}
}
@@ -464,9 +506,8 @@ public void computeA(long[] Mtmp, byte[] AOut)
{
for (int i = 0; i + r < m; i++)
{
- Utils.decode(Abytes, (r * AWidth / 16 + c + i) * 8,
- AOut, (r + i) * ACols + c,
- Math.min(16, ACols - 1 - c));
+ Utils.decode(Abytes, (((r * AWidth) >> 4) + c + i) << 3,
+ AOut, (r + i) * ACols + c, Math.min(16, ACols - 1 - c));
}
}
}
@@ -477,21 +518,20 @@ private static void transpose16x16Nibbles(long[] M, int offset)
for (int i = 0; i < 16; i += 2)
{
int idx1 = offset + i;
- int idx2 = offset + i + 1;
+ int idx2 = idx1 + 1;
long t = ((M[idx1] >>> 4) ^ M[idx2]) & 0x0F0F0F0F0F0F0F0FL;
M[idx1] ^= t << 4;
M[idx2] ^= t;
}
- for (int i = 0; i < 16; i += 4)
+ for (int i = 0, base = offset; i < 16; i += 4)
{
- int base = offset + i;
long t0 = ((M[base] >>> 8) ^ M[base + 2]) & EVEN_BYTES;
long t1 = ((M[base + 1] >>> 8) ^ M[base + 3]) & EVEN_BYTES;
- M[base] ^= t0 << 8;
- M[base + 1] ^= t1 << 8;
- M[base + 2] ^= t0;
- M[base + 3] ^= t1;
+ M[base++] ^= t0 << 8;
+ M[base++] ^= t1 << 8;
+ M[base++] ^= t0;
+ M[base++] ^= t1;
}
for (int i = 0; i < 4; i++)
@@ -529,10 +569,10 @@ public boolean sampleSolution(MayoParameters params, byte[] A, byte[] y,
byte[] Ar = new byte[m];
// Clear last column of A
- for (int i = 0; i < m; i++)
- {
- A[k * o + i * (k * o + 1)] = 0;
- }
+// for (int i = 0; i < m; i++)
+// {
+// A[k * o + i * (k * o + 1)] = 0;
+// }
GF16Utils.matMul(A, r, Ar, k * o + 1, m, 1);
// Update last column of A with y - Ar
@@ -572,22 +612,23 @@ public boolean sampleSolution(MayoParameters params, byte[] A, byte[] y,
// Update matrix entries
- for (int i = 0; i < row; i += 8)
+ for (int i = 0, iaCols_col = col, iaCols_aCols1 = aCols - 1; i < row; i += 8,
+ iaCols_col += aCols << 3, iaCols_aCols1 += aCols << 3)
{
long tmp = 0;
// Pack 8 GF(16) elements into long
- for (int j = 0; j < 8; j++)
+ for (int j = 0, jaCols = 0; j < 8; j++, jaCols += aCols)
{
- tmp ^= (long)(A[(i + j) * aCols + col] & 0xFF) << (j * 8);
+ tmp ^= (long)(A[iaCols_col + jaCols] & 0xFF) << (j << 3);
}
// GF(16) multiplication
tmp = GF16Utils.mulFx8(u, tmp);
// Unpack and update
- for (int j = 0; j < 8; j++)
+ for (int j = 0, jaCols = 0; j < 8; j++, jaCols += aCols)
{
- A[(i + j) * aCols + aCols - 1] ^= (byte)((tmp >> (j * 8)) & 0x0F);
+ A[iaCols_aCols1 + jaCols] ^= (byte)((tmp >> (j << 3)) & 0x0F);
}
}
finished |= correctCol;
@@ -656,7 +697,7 @@ public void ef(byte[] A, int nrows, int ncols)
int pivot = 0;
long pivotIsZero = -1L; // all bits set (0xFFFFFFFFFFFFFFFF)
int searchUpper = Math.min(nrows - 1, upperBound + 32);
- for (int row = lowerBound; row <= searchUpper; row++)
+ for (int row = lowerBound, rowRowLen = lowerBound * rowLen; row <= searchUpper; row++, rowRowLen += rowLen)
{
long isPivotRow = ~ctCompare64(row, pivotRowIndex);
//ct64IsGreaterThan(a, b): Returns 0xFFFFFFFFFFFFFFFF if a > b, 0 otherwise.
@@ -664,8 +705,7 @@ public void ef(byte[] A, int nrows, int ncols)
for (int j = 0; j < rowLen; j++)
{
// The expression below accumulates (in constant time) the candidate pivot row.
- pivotRow[j] ^= (isPivotRow | (belowPivotRow & pivotIsZero))
- & packedA[row * rowLen + j];
+ pivotRow[j] ^= (isPivotRow | (belowPivotRow & pivotIsZero)) & packedA[rowRowLen + j];
}
// Extract candidate pivot element from the packed row.
pivot = (int)((pivotRow[pivotCol >>> 4] >>> ((pivotCol & 15) << 2)) & 0xF);
@@ -684,17 +724,17 @@ public void ef(byte[] A, int nrows, int ncols)
for (int col = 0, rowRowLen_col = rowRowLen; col < rowLen; col++, rowRowLen_col++)
{
// Since the masks are disjoint, addition is equivalent to OR.
- packedA[rowRowLen_col] = (doNotCopy & packedA[rowRowLen_col]) |
- (doCopy & pivotRow2[col]);
+ packedA[rowRowLen_col] = (doNotCopy & packedA[rowRowLen_col]) | (doCopy & pivotRow2[col]);
}
}
// Eliminate entries below the pivot.
- for (int row = lowerBound; row < nrows; row++)
+ for (int row = lowerBound, rowRowLen = lowerBound * rowLen; row < nrows; row++, rowRowLen += rowLen)
{
- int belowPivot = (row > pivotRowIndex) ? 1 : 0;
- int eltToElim = mExtractElementFromPacked(packedA, row, rowLen, pivotCol);
- vecMulAddU64(rowLen, pivotRow2, (byte)(belowPivot * eltToElim), packedA, row * rowLen);
+ int belowPivot = (row > pivotRowIndex) ? -1 : 0;
+ //int eltToElim = mExtractElementFromPacked(packedA, row, rowLen, pivotCol);
+ int eltToElim = (int)((packedA[rowRowLen + (pivotCol >>> 4)] >>> ((pivotCol & 15) << 2)) & 0xF);
+ vecMulAddU64(rowLen, pivotRow2, (byte)(belowPivot & eltToElim), packedA, rowRowLen);
}
// If pivot is nonzero, increment pivotRowIndex.
@@ -729,20 +769,6 @@ private static long ctCompare64(int a, int b)
return (-(long)(a ^ b)) >> 63;
}
- /**
- * Extracts an element from the packed matrix for a given row and column.
- *
- * @param packedA the packed matrix stored in row-major order
- * @param row the row index
- * @param rowLen the number of longs per row
- * @param index the column index
- * @return the GF(16) element at that position.
- */
- private static int mExtractElementFromPacked(long[] packedA, int row, int rowLen, int index)
- {
- return (int)((packedA[row * rowLen + (index >>> 4)] >>> ((index & 15) << 2)) & 0xF);
- }
-
/**
* Computes the multiplicative inverse in GF(16) for a GF(16) element.
*/
@@ -764,10 +790,7 @@ private static int inverseF(int a)
public static int mulF(int a, int b)
{
// Carryless multiply: multiply b by each bit of a and XOR.
- int p = ((a & 1) * b) ^
- ((a & 2) * b) ^
- ((a & 4) * b) ^
- ((a & 8) * b);
+ int p = (-(a & 1) & b) ^ (-((a >> 1) & 1) & (b << 1)) ^ (-((a >> 2) & 1) & (b << 2)) ^ (-((a >> 3) & 1) & (b << 3));
// Reduce modulo f(X) = x^4 + x + 1.
int topP = p & 0xF0;
return (p ^ (topP >> 4) ^ (topP >> 3)) & 0x0F;
@@ -787,13 +810,12 @@ public static int mulF(int a, int b)
private static void vecMulAddU64(int legs, long[] in, byte a, long[] acc)
{
int tab = mulTable(a & 0xFF);
- long lsbAsk = 0x1111111111111111L;
for (int i = 0; i < legs; i++)
{
- long val = ((in[i] & lsbAsk) * (tab & 0xFF))
- ^ (((in[i] >>> 1) & lsbAsk) * ((tab >>> 8) & 0xF))
- ^ (((in[i] >>> 2) & lsbAsk) * ((tab >>> 16) & 0xF))
- ^ (((in[i] >>> 3) & lsbAsk) * ((tab >>> 24) & 0xF));
+ long val = ((in[i] & GF16Utils.MASK_LSB) * (tab & 0xFF))
+ ^ (((in[i] >>> 1) & GF16Utils.MASK_LSB) * ((tab >>> 8) & 0xF))
+ ^ (((in[i] >>> 2) & GF16Utils.MASK_LSB) * ((tab >>> 16) & 0xF))
+ ^ (((in[i] >>> 3) & GF16Utils.MASK_LSB) * ((tab >>> 24) & 0xF));
acc[i] ^= val;
}
}
@@ -810,13 +832,12 @@ private static void vecMulAddU64(int legs, long[] in, byte a, long[] acc)
private static void vecMulAddU64(int legs, long[] in, byte a, long[] acc, int accOffset)
{
int tab = mulTable(a & 0xFF);
- long lsbAsk = 0x1111111111111111L;
for (int i = 0; i < legs; i++)
{
- long val = ((in[i] & lsbAsk) * (tab & 0xFF))
- ^ (((in[i] >>> 1) & lsbAsk) * ((tab >>> 8) & 0xF))
- ^ (((in[i] >>> 2) & lsbAsk) * ((tab >>> 16) & 0xF))
- ^ (((in[i] >>> 3) & lsbAsk) * ((tab >>> 24) & 0xF));
+ long val = ((in[i] & GF16Utils.MASK_LSB) * (tab & 0xFF))
+ ^ (((in[i] >>> 1) & GF16Utils.MASK_LSB) * ((tab >>> 8) & 0xF))
+ ^ (((in[i] >>> 2) & GF16Utils.MASK_LSB) * ((tab >>> 16) & 0xF))
+ ^ (((in[i] >>> 3) & GF16Utils.MASK_LSB) * ((tab >>> 24) & 0xF));
acc[accOffset + i] ^= val;
}
}
@@ -832,17 +853,16 @@ private static void vecMulAddU64(int legs, long[] in, byte a, long[] acc, int ac
private static int mulTable(int b)
{
int x = b * 0x08040201;
- int highNibbleMask = 0xf0f0f0f0;
- int highHalf = x & highNibbleMask;
+ int highHalf = x & 0xf0f0f0f0;
return x ^ (highHalf >>> 4) ^ (highHalf >>> 3);
}
private static void mayoGenericMCalculatePS(MayoParameters p, long[] P1, int p2, int p3, byte[] S,
- int m, int v, int o, int k, long[] PS)
+ int v, int o, int k, long[] PS)
{
int n = o + v;
- int mVecLimbs = (m + 15) / 16;
- long[] accumulator = new long[16 * ((p.getM() + 15) / 16 * p.getK() * p.getN() * mVecLimbs)];
+ int mVecLimbs = p.getMVecLimbs();
+ long[] accumulator = new long[(mVecLimbs * p.getK() * p.getN() * mVecLimbs) << 4];
int o_mVecLimbs = o * mVecLimbs;
int pUsed = 0;
for (int row = 0, krow = 0, orow_mVecLimbs = 0; row < v; row++, krow += k, orow_mVecLimbs += o_mVecLimbs)
@@ -881,29 +901,28 @@ private static void mayoGenericMCalculatePS(MayoParameters p, long[] P1, int p2,
mVecMultiplyBins(mVecLimbs, n * k, accumulator, PS);
}
- private static void mayoGenericMCalculateSPS(long[] PS, byte[] S, int m, int k, int n, long[] SPS)
+ private static void mayoGenericMCalculateSPS(long[] PS, byte[] S, int mVecLimbs, int k, int n, long[] SPS)
{
- final int mVecLimbs = (m + 15) / 16;
- final int accumulatorSize = (mVecLimbs * k * k) << 4;
+ int kk = k * k;
+ final int accumulatorSize = (mVecLimbs * kk) << 4;
final long[] accumulator = new long[accumulatorSize];
+ int kmVecLimbs = k * mVecLimbs;
// Accumulation phase
- for (int row = 0, nrow = 0; row < k; row++, nrow += n)
+ for (int row = 0, nrow = 0, krowmVecLimbs16 = 0; row < k; row++, nrow += n, krowmVecLimbs16 += kmVecLimbs << 4)
{
- for (int j = 0; j < n; j++)
+ for (int j = 0, jkmVecLimbs = 0; j < n; j++, jkmVecLimbs += kmVecLimbs)
{
- final int sVal = S[nrow + j] & 0xFF; // Unsigned byte value
- for (int col = 0; col < k; col++)
+ final int sValmVecLimbs = (S[nrow + j] & 0xFF) * mVecLimbs + krowmVecLimbs16; // Unsigned byte value
+ for (int col = 0, colmVecLimbs = 0; col < k; col++, colmVecLimbs += mVecLimbs)
{
- final int psOffset = (j * k + col) * mVecLimbs;
- final int accOffset = ((row * k + col) * 16 + sVal) * mVecLimbs;
- Longs.xorTo(mVecLimbs, PS, psOffset, accumulator, accOffset);
+ Longs.xorTo(mVecLimbs, PS, jkmVecLimbs + colmVecLimbs, accumulator, sValmVecLimbs + (colmVecLimbs << 4));
}
}
}
// Processing phase
- mVecMultiplyBins(mVecLimbs, k * k, accumulator, SPS);
+ mVecMultiplyBins(mVecLimbs, kk, accumulator, SPS);
}
private static void mVecMultiplyBins(int mVecLimbs, int len, long[] bins, long[] ps)
@@ -930,27 +949,23 @@ private static void mVecMultiplyBins(int mVecLimbs, int len, long[] bins, long[]
}
// Modular arithmetic operations
- private static void mVecMulAddXInv(int limbs, long[] in, int inOffset,
- long[] acc, int accOffset)
+ private static void mVecMulAddXInv(int limbs, long[] in, int inOffset, long[] acc, int accOffset)
{
- final long maskLsb = 0x1111111111111111L;
for (int i = 0; i < limbs; i++)
{
long input = in[inOffset + i];
- long t = input & maskLsb;
- acc[accOffset + i] ^= ((input ^ t) >>> 1) ^ (t * 9);
+ long t = input & GF16Utils.MASK_LSB;
+ acc[accOffset + i] ^= ((input & GF16Utils.NIBBLE_MASK_LSB) >>> 1) ^ ((t << 3) + t);
}
}
- private static void mVecMulAddX(int limbs, long[] in, int inOffset,
- long[] acc, int accOffset)
+ private static void mVecMulAddX(int limbs, long[] in, int inOffset, long[] acc, int accOffset)
{
- final long maskMsb = 0x8888888888888888L;
for (int i = 0; i < limbs; i++)
{
long input = in[inOffset + i];
- long t = input & maskMsb;
- acc[accOffset + i] ^= ((input ^ t) << 1) ^ ((t >>> 3) * 3);
+ long t = (input & GF16Utils.MASK_MSB) >>> 3;
+ acc[accOffset + i] ^= ((input & GF16Utils.NIBBLE_MASK_MSB) << 1) ^ ((t << 1) + t);
}
}
}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/Utils.java
index 320204911a..e48d019cda 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/Utils.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/Utils.java
@@ -1,6 +1,12 @@
package org.bouncycastle.pqc.crypto.mayo;
-import org.bouncycastle.crypto.digests.SHAKEDigest;
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.engines.AESEngine;
+import org.bouncycastle.crypto.modes.CTRModeCipher;
+import org.bouncycastle.crypto.modes.SICBlockCipher;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Pack;
public class Utils
@@ -40,14 +46,14 @@ public static void decode(byte[] m, int mOff, byte[] mdec, int decIndex, int mde
for (i = 0; i < mdecLen / 2; i++)
{
// Extract the lower nibble
- mdec[decIndex++] = (byte)((m[i + mOff] & 0xFF) & 0x0F);
+ mdec[decIndex++] = (byte)(m[i + mOff] & 0x0F);
// Extract the upper nibble (shift right 4 bits)
- mdec[decIndex++] = (byte)(((m[i + mOff] & 0xFF) >> 4) & 0x0F);
+ mdec[decIndex++] = (byte)((m[i + mOff] >> 4) & 0x0F);
}
// If there is an extra nibble (odd number of nibbles), decode only the lower nibble
if (mdecLen % 2 == 1)
{
- mdec[decIndex] = (byte)((m[i + mOff] & 0xFF) & 0x0F);
+ mdec[decIndex] = (byte)(m[i + mOff] & 0x0F);
}
}
@@ -114,19 +120,19 @@ public static void unpackMVecs(byte[] in, long[] out, int vecs, int m)
{
int mVecLimbs = (m + 15) / 16;
int bytesToCopy = m / 2; // Number of bytes to copy per vector
+ // Temporary buffer to hold mVecLimbs longs (each long is 8 bytes)
+ byte[] tmp = new byte[mVecLimbs << 3];
// Process vectors in reverse order
for (int i = vecs - 1; i >= 0; i--)
{
- // Temporary buffer to hold mVecLimbs longs (each long is 8 bytes)
- byte[] tmp = new byte[mVecLimbs * 8];
// Copy m/2 bytes from the input into tmp. The rest remains zero.
System.arraycopy(in, i * bytesToCopy, tmp, 0, bytesToCopy);
// Convert each 8-byte block in tmp into a long using Pack
for (int j = 0; j < mVecLimbs; j++)
{
- out[i * mVecLimbs + j] = Pack.littleEndianToLong(tmp, j * 8);
+ out[i * mVecLimbs + j] = Pack.littleEndianToLong(tmp, j << 3);
}
}
}
@@ -135,12 +141,11 @@ public static void unpackMVecs(byte[] in, int inOff, long[] out, int outOff, int
{
int mVecLimbs = (m + 15) / 16;
int bytesToCopy = m / 2; // Number of bytes to copy per vector
-
+ // Temporary buffer to hold mVecLimbs longs (each long is 8 bytes)
+ byte[] tmp = new byte[mVecLimbs << 3];
// Process vectors in reverse order
for (int i = vecs - 1; i >= 0; i--)
{
- // Temporary buffer to hold mVecLimbs longs (each long is 8 bytes)
- byte[] tmp = new byte[mVecLimbs * 8];
// Copy m/2 bytes from the input into tmp. The rest remains zero.
System.arraycopy(in, inOff + i * bytesToCopy, tmp, 0, bytesToCopy);
@@ -183,26 +188,59 @@ public static void packMVecs(long[] in, byte[] out, int outOff, int vecs, int m)
}
/**
- * Computes the SHAKE256 XOF on the given input.
+ * Expands P1 and P2 using AES_128_CTR as a PRF and then unpacks the resulting bytes
+ * into an array of 64-bit limbs.
*
- * @param output the output buffer that will be filled with the result.
- * @param outlen the number of bytes to produce.
- * @param input the input byte array.
- * @param inlen the number of input bytes.
- * @return the number of output bytes produced (equals outlen).
+ * @param p Mayo parameters
+ * @param P The output long array which will hold the unpacked limbs.
+ * Its length should be at least ((P1_bytes + P2_bytes) / 8) limbs.
+ * @param seed_pk The seed (used as the key) for the PRF.
*/
- public static int shake256(byte[] output, int outlen, byte[] input, int inlen)
+ public static void expandP1P2(MayoParameters p, long[] P, byte[] seed_pk)
{
- // Create a new SHAKE256 digest instance.
- SHAKEDigest shake = new SHAKEDigest(256);
-
- // Absorb the input.
- shake.update(input, 0, inlen);
+ // Compute total number of bytes to generate: P1_bytes + P2_bytes.
+ int outLen = p.getP1Bytes() + p.getP2Bytes();
+ // Temporary byte array to hold the PRF output.
+ byte[] temp = new byte[outLen];
+
+ //AES_128_CTR(temp, outLen, seed_pk, p.getPkSeedBytes());
+ // Create a 16-byte IV (all zeros)
+ byte[] iv = new byte[16]; // automatically zero-initialized
+
+ // Set up AES engine in CTR (SIC) mode.
+ BlockCipher aesEngine = AESEngine.newInstance();
+ // SICBlockCipher implements CTR mode for AES.
+ CTRModeCipher ctrCipher = SICBlockCipher.newInstance(aesEngine);
+ // Wrap the key with the IV.
+ ParametersWithIV params = new ParametersWithIV(new KeyParameter(Arrays.copyOf(seed_pk, p.getPkSeedBytes())), iv);
+ ctrCipher.init(true, params);
+
+ // CTR mode is a stream cipher: encrypting zero bytes produces the keystream.
+ int blockSize = ctrCipher.getBlockSize(); // typically 16 bytes
+ byte[] zeroBlock = new byte[blockSize]; // block of zeros
+ byte[] blockOut = new byte[blockSize];
+
+ int offset = 0;
+ // Process full blocks
+ while (offset + blockSize <= outLen)
+ {
+ ctrCipher.processBlock(zeroBlock, 0, blockOut, 0);
+ System.arraycopy(blockOut, 0, temp, offset, blockSize);
+ offset += blockSize;
+ }
+ // Process any remaining partial block.
+ if (offset < outLen)
+ {
+ ctrCipher.processBlock(zeroBlock, 0, blockOut, 0);
+ int remaining = outLen - offset;
+ System.arraycopy(blockOut, 0, temp, offset, remaining);
+ }
- // Squeeze out outlen bytes into the output array.
- shake.doFinal(output, 0, outlen);
+ // The number of vectors is the total limbs divided by mVecLimbs.
+ int numVectors = (p.getP1Limbs() + p.getP2Limbs()) / p.getMVecLimbs();
- return outlen;
+ // Unpack the byte array 'temp' into the long array 'P'
+ // using our previously defined unpackMVecs method.
+ unpackMVecs(temp, P, numVectors, p.getM());
}
-
}
From 13d5a190ba33843e340de59d0b93ed42a04b9eda Mon Sep 17 00:00:00 2001
From: gefeili
Date: Tue, 4 Mar 2025 13:10:46 +1030
Subject: [PATCH 144/890] Add Mayo to PQC Provider
---
.../asn1/bc/BCObjectIdentifiers.java | 16 +-
.../pqc/crypto/mayo/MayoKeyPairGenerator.java | 2 +-
.../pqc/crypto/mayo/MayoParameters.java | 8 +-
.../crypto/mayo/MayoPrivateKeyParameter.java | 41 ---
.../crypto/mayo/MayoPrivateKeyParameters.java | 25 ++
...eter.java => MayoPublicKeyParameters.java} | 5 +-
.../pqc/crypto/mayo/MayoSigner.java | 10 +-
.../pqc/crypto/util/PrivateKeyFactory.java | 10 +-
.../crypto/util/PrivateKeyInfoFactory.java | 8 +
.../pqc/crypto/util/PublicKeyFactory.java | 21 ++
.../util/SubjectPublicKeyInfoFactory.java | 9 +-
.../bouncycastle/pqc/crypto/util/Utils.java | 134 +++++----
.../pqc/crypto/test/MayoTest.java | 19 +-
.../jce/provider/BouncyCastleProvider.java | 6 +
.../pqc/jcajce/interfaces/MayoKey.java | 16 +
.../provider/BouncyCastlePQCProvider.java | 3 +-
.../pqc/jcajce/provider/Mayo.java | 44 +++
.../provider/cmce/BCCMCEPrivateKey.java | 2 +-
.../jcajce/provider/cmce/BCCMCEPublicKey.java | 2 +-
.../provider/falcon/FalconKeyFactorySpi.java | 1 -
.../provider/mayo/BCMayoPrivateKey.java | 131 +++++++++
.../jcajce/provider/mayo/BCMayoPublicKey.java | 127 ++++++++
.../provider/mayo/MayoKeyFactorySpi.java | 130 +++++++++
.../mayo/MayoKeyPairGeneratorSpi.java | 150 ++++++++++
.../jcajce/provider/mayo/SignatureSpi.java | 218 ++++++++++++++
.../pqc/jcajce/spec/MayoParameterSpec.java | 48 +++
.../test/MayoKeyPairGeneratorTest.java | 63 ++++
.../pqc/jcajce/provider/test/MayoTest.java | 276 ++++++++++++++++++
28 files changed, 1395 insertions(+), 130 deletions(-)
delete mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPrivateKeyParameter.java
create mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPrivateKeyParameters.java
rename core/src/main/java/org/bouncycastle/pqc/crypto/mayo/{MayoPublicKeyParameter.java => MayoPublicKeyParameters.java} (64%)
create mode 100644 prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/MayoKey.java
create mode 100644 prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/Mayo.java
create mode 100644 prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/BCMayoPrivateKey.java
create mode 100644 prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/BCMayoPublicKey.java
create mode 100644 prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/MayoKeyFactorySpi.java
create mode 100644 prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/MayoKeyPairGeneratorSpi.java
create mode 100644 prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/SignatureSpi.java
create mode 100644 prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/MayoParameterSpec.java
create mode 100644 prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/MayoKeyPairGeneratorTest.java
create mode 100644 prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/MayoTest.java
diff --git a/core/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java
index c5753d7dc7..b0e8f7726f 100644
--- a/core/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java
+++ b/core/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java
@@ -248,7 +248,7 @@ public interface BCObjectIdentifiers
ASN1ObjectIdentifier falcon = bc_sig.branch("7");
ASN1ObjectIdentifier falcon_512 = new ASN1ObjectIdentifier("1.3.9999.3.6"); // falcon.branch("1");
- ASN1ObjectIdentifier falcon_1024 = new ASN1ObjectIdentifier("1.3.9999.3.9"); // falcon.branch("2");
+ ASN1ObjectIdentifier falcon_1024 = new ASN1ObjectIdentifier("1.3.9999.3.9"); // falcon.branch("2");
/*
* Dilithium
@@ -403,7 +403,7 @@ public interface BCObjectIdentifiers
ASN1ObjectIdentifier ntrulpr953 = pqc_kem_ntrulprime.branch("4");
ASN1ObjectIdentifier ntrulpr1013 = pqc_kem_ntrulprime.branch("5");
ASN1ObjectIdentifier ntrulpr1277 = pqc_kem_ntrulprime.branch("6");
-
+
ASN1ObjectIdentifier pqc_kem_sntruprime = pqc_kem_ntruprime.branch("2");
ASN1ObjectIdentifier sntrup653 = pqc_kem_sntruprime.branch("1");
ASN1ObjectIdentifier sntrup761 = pqc_kem_sntruprime.branch("2");
@@ -411,7 +411,7 @@ public interface BCObjectIdentifiers
ASN1ObjectIdentifier sntrup953 = pqc_kem_sntruprime.branch("4");
ASN1ObjectIdentifier sntrup1013 = pqc_kem_sntruprime.branch("5");
ASN1ObjectIdentifier sntrup1277 = pqc_kem_sntruprime.branch("6");
-
+
/**
* BIKE
**/
@@ -432,7 +432,6 @@ public interface BCObjectIdentifiers
/**
* ML-KEM/ML-DSA seed parameters algorithms - temporary
- *
*/
//TODO: delete before release
ASN1ObjectIdentifier id_id_alg_seed = bc.branch("10");
@@ -443,4 +442,13 @@ public interface BCObjectIdentifiers
ASN1ObjectIdentifier id_id_alg_ml_kem_512_seed = id_id_alg_seed.branch("4");
ASN1ObjectIdentifier id_id_alg_ml_kem_768_seed = id_id_alg_seed.branch("5");
ASN1ObjectIdentifier id_id_alg_ml_kem_1024_seed = id_id_alg_seed.branch("6");
+
+ /**
+ * Mayo
+ */
+ ASN1ObjectIdentifier mayo = bc_sig.branch("10");
+ ASN1ObjectIdentifier mayo1 = mayo.branch("1");
+ ASN1ObjectIdentifier mayo2 = mayo.branch("2");
+ ASN1ObjectIdentifier mayo3 = mayo.branch("3");
+ ASN1ObjectIdentifier mayo5 = mayo.branch("4");
}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
index 1a5f9ff037..ffad286ab3 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
@@ -110,6 +110,6 @@ public AsymmetricCipherKeyPair generateKeyPair()
Arrays.clear(O);
Arrays.clear(P3);
- return new AsymmetricCipherKeyPair(new MayoPublicKeyParameter(p, cpk), new MayoPrivateKeyParameter(p, seed_sk));
+ return new AsymmetricCipherKeyPair(new MayoPublicKeyParameters(p, cpk), new MayoPrivateKeyParameters(p, seed_sk));
}
}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoParameters.java
index f1a1def99d..86e99704a7 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoParameters.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoParameters.java
@@ -2,7 +2,7 @@
public class MayoParameters
{
- public static final MayoParameters MAYO1 = new MayoParameters(
+ public static final MayoParameters mayo1 = new MayoParameters(
"MAYO_1", // name
86, // n
78, // m
@@ -30,7 +30,7 @@ public class MayoParameters
24 // sk_seed_bytes
);
- public static final MayoParameters MAYO2 = new MayoParameters(
+ public static final MayoParameters mayo2 = new MayoParameters(
"MAYO_2", // name
81, // n
64, // m
@@ -58,7 +58,7 @@ public class MayoParameters
24 // sk_seed_bytes
);
- public static final MayoParameters MAYO3 = new MayoParameters(
+ public static final MayoParameters mayo3 = new MayoParameters(
"MAYO_3", // name
118, // n
108, // m
@@ -86,7 +86,7 @@ public class MayoParameters
32 // sk_seed_bytes
);
- public static final MayoParameters MAYO5 = new MayoParameters(
+ public static final MayoParameters mayo5 = new MayoParameters(
"MAYO_5", // name
154, // n
142, // m
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPrivateKeyParameter.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPrivateKeyParameter.java
deleted file mode 100644
index 7954094a38..0000000000
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPrivateKeyParameter.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package org.bouncycastle.pqc.crypto.mayo;
-
-import org.bouncycastle.util.Arrays;
-
-public class MayoPrivateKeyParameter
- extends MayoKeyParameters
-{
- // Represents the field: uint64_t p[P1_LIMBS_MAX + P2_LIMBS_MAX];
-// private final byte[] p;
- // Represents the field: uint8_t O[V_MAX * O_MAX];
-// private final byte[] O;
- private final byte[] seed_sk;
-
- public MayoPrivateKeyParameter(MayoParameters params, byte[] seed_sk)
- {
- super(true, params);
- this.seed_sk = seed_sk;
-// this.p = p;
-// this.O = O;
- }
-
-// public byte[] getP()
-// {
-// return p;
-// }
-//
-// public byte[] getO()
-// {
-// return O;
-// }
-
- public byte[] getEncoded()
- {
- return Arrays.clone(seed_sk);
- }
-
- public byte[] getSeedSk()
- {
- return Arrays.clone(seed_sk);
- }
-}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPrivateKeyParameters.java
new file mode 100644
index 0000000000..f325f96dc4
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPrivateKeyParameters.java
@@ -0,0 +1,25 @@
+package org.bouncycastle.pqc.crypto.mayo;
+
+import org.bouncycastle.util.Arrays;
+
+public class MayoPrivateKeyParameters
+ extends MayoKeyParameters
+{
+ private final byte[] seed_sk;
+
+ public MayoPrivateKeyParameters(MayoParameters params, byte[] seed_sk)
+ {
+ super(true, params);
+ this.seed_sk = seed_sk;
+ }
+
+ public byte[] getEncoded()
+ {
+ return Arrays.clone(seed_sk);
+ }
+
+ public byte[] getSeedSk()
+ {
+ return Arrays.clone(seed_sk);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPublicKeyParameter.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPublicKeyParameters.java
similarity index 64%
rename from core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPublicKeyParameter.java
rename to core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPublicKeyParameters.java
index 68613b35bd..086660edfd 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPublicKeyParameter.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPublicKeyParameters.java
@@ -2,13 +2,12 @@
import org.bouncycastle.util.Arrays;
-public class MayoPublicKeyParameter
+public class MayoPublicKeyParameters
extends MayoKeyParameters
{
- // Represents the field: uint64_t p[P1_LIMBS_MAX + P2_LIMBS_MAX + P3_LIMBS_MAX];
private final byte[] p;
- public MayoPublicKeyParameter(MayoParameters params, byte[] p)
+ public MayoPublicKeyParameters(MayoParameters params, byte[] p)
{
super(false, params);
this.p = p;
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
index df6922625d..9d8656b26f 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
@@ -16,8 +16,8 @@ public class MayoSigner
{
private SecureRandom random;
MayoParameters params;
- private MayoPublicKeyParameter pubKey;
- private MayoPrivateKeyParameter privKey;
+ private MayoPublicKeyParameters pubKey;
+ private MayoPrivateKeyParameters privKey;
@Override
public void init(boolean forSigning, CipherParameters param)
@@ -30,19 +30,19 @@ public void init(boolean forSigning, CipherParameters param)
if (param instanceof ParametersWithRandom)
{
ParametersWithRandom withRandom = (ParametersWithRandom)param;
- privKey = (MayoPrivateKeyParameter)withRandom.getParameters();
+ privKey = (MayoPrivateKeyParameters)withRandom.getParameters();
random = withRandom.getRandom();
}
else
{
- privKey = (MayoPrivateKeyParameter)param;
+ privKey = (MayoPrivateKeyParameters)param;
random = null;
}
params = privKey.getParameters();
}
else
{
- pubKey = (MayoPublicKeyParameter)param;
+ pubKey = (MayoPublicKeyParameters)param;
params = pubKey.getParameters();
privKey = null;
random = null;
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/util/PrivateKeyFactory.java b/core/src/main/java/org/bouncycastle/pqc/crypto/util/PrivateKeyFactory.java
index fd5ca0146a..e582bfd41e 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/util/PrivateKeyFactory.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/util/PrivateKeyFactory.java
@@ -43,6 +43,8 @@
import org.bouncycastle.pqc.crypto.hqc.HQCParameters;
import org.bouncycastle.pqc.crypto.hqc.HQCPrivateKeyParameters;
import org.bouncycastle.pqc.crypto.lms.HSSPrivateKeyParameters;
+import org.bouncycastle.pqc.crypto.mayo.MayoParameters;
+import org.bouncycastle.pqc.crypto.mayo.MayoPrivateKeyParameters;
import org.bouncycastle.pqc.crypto.mldsa.MLDSAParameters;
import org.bouncycastle.pqc.crypto.mldsa.MLDSAPrivateKeyParameters;
import org.bouncycastle.pqc.crypto.mldsa.MLDSAPublicKeyParameters;
@@ -183,7 +185,7 @@ else if (algOID.on(BCObjectIdentifiers.sphincsPlus) || algOID.on(BCObjectIdentif
return new SPHINCSPlusPrivateKeyParameters(spParams, ASN1OctetString.getInstance(obj).getOctets());
}
}
- else if (Utils.shldsaParams.containsKey(algOID))
+ else if (Utils.slhdsaParams.containsKey(algOID))
{
SLHDSAParameters spParams = Utils.slhdsaParamsLookup(algOID);
ASN1OctetString slhdsaKey = parseOctetString(keyInfo.getPrivateKey(), spParams.getN() * 4);
@@ -479,6 +481,12 @@ else if (algOID.equals(PQCObjectIdentifiers.mcElieceCca2))
return new McElieceCCA2PrivateKeyParameters(mKey.getN(), mKey.getK(), mKey.getField(), mKey.getGoppaPoly(), mKey.getP(), Utils.getDigestName(mKey.getDigest().getAlgorithm()));
}
+ else if (algOID.on(BCObjectIdentifiers.mayo))
+ {
+ byte[] keyEnc = ASN1OctetString.getInstance(keyInfo.parsePrivateKey()).getOctets();
+ MayoParameters mayoParams = Utils.mayoParamsLookup(algOID);
+ return new MayoPrivateKeyParameters(mayoParams, keyEnc);
+ }
else
{
throw new RuntimeException("algorithm identifier in private key not recognised");
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/util/PrivateKeyInfoFactory.java b/core/src/main/java/org/bouncycastle/pqc/crypto/util/PrivateKeyInfoFactory.java
index cd41f2465e..9b3aaff843 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/util/PrivateKeyInfoFactory.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/util/PrivateKeyInfoFactory.java
@@ -33,6 +33,7 @@
import org.bouncycastle.pqc.crypto.lms.Composer;
import org.bouncycastle.pqc.crypto.lms.HSSPrivateKeyParameters;
import org.bouncycastle.pqc.crypto.lms.LMSPrivateKeyParameters;
+import org.bouncycastle.pqc.crypto.mayo.MayoPrivateKeyParameters;
import org.bouncycastle.pqc.crypto.mldsa.MLDSAPrivateKeyParameters;
import org.bouncycastle.pqc.crypto.mlkem.MLKEMPrivateKeyParameters;
import org.bouncycastle.pqc.crypto.newhope.NHPrivateKeyParameters;
@@ -336,6 +337,13 @@ else if (privateKey instanceof RainbowPrivateKeyParameters)
byte[] encoding = params.getEncoded();
return new PrivateKeyInfo(algorithmIdentifier, new DEROctetString(encoding), attributes);
}
+ else if (privateKey instanceof MayoPrivateKeyParameters)
+ {
+ MayoPrivateKeyParameters params = (MayoPrivateKeyParameters)privateKey;
+ AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(Utils.mayoOidLookup(params.getParameters()));
+ byte[] encoding = params.getEncoded();
+ return new PrivateKeyInfo(algorithmIdentifier, new DEROctetString(encoding), attributes);
+ }
else
{
throw new IOException("key parameters not recognized");
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java b/core/src/main/java/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java
index 38384b2f7b..fb8ebab79a 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java
@@ -40,6 +40,8 @@
import org.bouncycastle.pqc.crypto.hqc.HQCPublicKeyParameters;
import org.bouncycastle.pqc.crypto.lms.HSSPublicKeyParameters;
import org.bouncycastle.pqc.crypto.lms.LMSKeyParameters;
+import org.bouncycastle.pqc.crypto.mayo.MayoParameters;
+import org.bouncycastle.pqc.crypto.mayo.MayoPublicKeyParameters;
import org.bouncycastle.pqc.crypto.mldsa.MLDSAParameters;
import org.bouncycastle.pqc.crypto.mldsa.MLDSAPublicKeyParameters;
import org.bouncycastle.pqc.crypto.mlkem.MLKEMParameters;
@@ -253,6 +255,11 @@ public class PublicKeyFactory
converters.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_192f_with_shake256, new SLHDSAConverter());
converters.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_256s_with_shake256, new SLHDSAConverter());
converters.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_256f_with_shake256, new SLHDSAConverter());
+
+ converters.put(BCObjectIdentifiers.mayo1, new MayoConverter());
+ converters.put(BCObjectIdentifiers.mayo2, new MayoConverter());
+ converters.put(BCObjectIdentifiers.mayo3, new MayoConverter());
+ converters.put(BCObjectIdentifiers.mayo5, new MayoConverter());
}
/**
@@ -847,4 +854,18 @@ AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Obje
return new RainbowPublicKeyParameters(rainbowParams, keyEnc);
}
}
+
+ private static class MayoConverter
+ extends SubjectPublicKeyInfoConverter
+ {
+ AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams)
+ throws IOException
+ {
+ byte[] keyEnc = ASN1OctetString.getInstance(keyInfo.parsePublicKey()).getOctets();
+
+ MayoParameters mayoParams = Utils.mayoParamsLookup(keyInfo.getAlgorithm().getAlgorithm());
+
+ return new MayoPublicKeyParameters(mayoParams, keyEnc);
+ }
+ }
}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java b/core/src/main/java/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java
index ff782c74af..7edfd3599e 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java
@@ -25,7 +25,7 @@
import org.bouncycastle.pqc.crypto.lms.Composer;
import org.bouncycastle.pqc.crypto.lms.HSSPublicKeyParameters;
import org.bouncycastle.pqc.crypto.lms.LMSPublicKeyParameters;
-import org.bouncycastle.pqc.crypto.mayo.MayoPublicKeyParameter;
+import org.bouncycastle.pqc.crypto.mayo.MayoPublicKeyParameters;
import org.bouncycastle.pqc.crypto.mldsa.MLDSAPublicKeyParameters;
import org.bouncycastle.pqc.crypto.mlkem.MLKEMPublicKeyParameters;
import org.bouncycastle.pqc.crypto.newhope.NHPublicKeyParameters;
@@ -303,6 +303,13 @@ else if (publicKey instanceof RainbowPublicKeyParameters)
return new SubjectPublicKeyInfo(algorithmIdentifier, new DEROctetString(encoding));
}
+ else if (publicKey instanceof MayoPublicKeyParameters)
+ {
+ MayoPublicKeyParameters params = (MayoPublicKeyParameters)publicKey;
+ byte[] encoding = params.getEncoded();
+ AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(Utils.mayoOidLookup(params.getParameters()));
+ return new SubjectPublicKeyInfo(algorithmIdentifier, new DEROctetString(encoding));
+ }
else
{
throw new IOException("key parameters not recognized");
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/util/Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/util/Utils.java
index 496211c67d..750504067c 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/util/Utils.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/util/Utils.java
@@ -27,6 +27,7 @@
import org.bouncycastle.pqc.crypto.falcon.FalconParameters;
import org.bouncycastle.pqc.crypto.frodo.FrodoParameters;
import org.bouncycastle.pqc.crypto.hqc.HQCParameters;
+import org.bouncycastle.pqc.crypto.mayo.MayoParameters;
import org.bouncycastle.pqc.crypto.mldsa.MLDSAParameters;
import org.bouncycastle.pqc.crypto.mlkem.MLKEMParameters;
import org.bouncycastle.pqc.crypto.ntru.NTRUParameters;
@@ -105,8 +106,11 @@ class Utils
static final Map mldsaOids = new HashMap();
static final Map mldsaParams = new HashMap();
- static final Map shldsaOids = new HashMap();
- static final Map shldsaParams = new HashMap();
+ static final Map slhdsaOids = new HashMap();
+ static final Map slhdsaParams = new HashMap();
+
+ static final Map mayoOids = new HashMap();
+ static final Map mayoParams = new HashMap();
static
{
@@ -325,57 +329,57 @@ class Utils
rainbowOids.put(RainbowParameters.rainbowVcircumzenithal, BCObjectIdentifiers.rainbow_V_circumzenithal);
rainbowOids.put(RainbowParameters.rainbowVcompressed, BCObjectIdentifiers.rainbow_V_compressed);
- shldsaOids.put(SLHDSAParameters.sha2_128s, NISTObjectIdentifiers.id_slh_dsa_sha2_128s);
- shldsaOids.put(SLHDSAParameters.sha2_128f, NISTObjectIdentifiers.id_slh_dsa_sha2_128f);
- shldsaOids.put(SLHDSAParameters.sha2_192s, NISTObjectIdentifiers.id_slh_dsa_sha2_192s);
- shldsaOids.put(SLHDSAParameters.sha2_192f, NISTObjectIdentifiers.id_slh_dsa_sha2_192f);
- shldsaOids.put(SLHDSAParameters.sha2_256s, NISTObjectIdentifiers.id_slh_dsa_sha2_256s);
- shldsaOids.put(SLHDSAParameters.sha2_256f, NISTObjectIdentifiers.id_slh_dsa_sha2_256f);
- shldsaOids.put(SLHDSAParameters.shake_128s, NISTObjectIdentifiers.id_slh_dsa_shake_128s);
- shldsaOids.put(SLHDSAParameters.shake_128f, NISTObjectIdentifiers.id_slh_dsa_shake_128f);
- shldsaOids.put(SLHDSAParameters.shake_192s, NISTObjectIdentifiers.id_slh_dsa_shake_192s);
- shldsaOids.put(SLHDSAParameters.shake_192f, NISTObjectIdentifiers.id_slh_dsa_shake_192f);
- shldsaOids.put(SLHDSAParameters.shake_256s, NISTObjectIdentifiers.id_slh_dsa_shake_256s);
- shldsaOids.put(SLHDSAParameters.shake_256f, NISTObjectIdentifiers.id_slh_dsa_shake_256f);
-
- shldsaOids.put(SLHDSAParameters.sha2_128s_with_sha256, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_128s_with_sha256);
- shldsaOids.put(SLHDSAParameters.sha2_128f_with_sha256, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_128f_with_sha256);
- shldsaOids.put(SLHDSAParameters.sha2_192s_with_sha512, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_192s_with_sha512);
- shldsaOids.put(SLHDSAParameters.sha2_192f_with_sha512, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_192f_with_sha512);
- shldsaOids.put(SLHDSAParameters.sha2_256s_with_sha512, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_256s_with_sha512);
- shldsaOids.put(SLHDSAParameters.sha2_256f_with_sha512, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_256f_with_sha512);
- shldsaOids.put(SLHDSAParameters.shake_128s_with_shake128, NISTObjectIdentifiers.id_hash_slh_dsa_shake_128s_with_shake128);
- shldsaOids.put(SLHDSAParameters.shake_128f_with_shake128, NISTObjectIdentifiers.id_hash_slh_dsa_shake_128f_with_shake128);
- shldsaOids.put(SLHDSAParameters.shake_192s_with_shake256, NISTObjectIdentifiers.id_hash_slh_dsa_shake_192s_with_shake256);
- shldsaOids.put(SLHDSAParameters.shake_192f_with_shake256, NISTObjectIdentifiers.id_hash_slh_dsa_shake_192f_with_shake256);
- shldsaOids.put(SLHDSAParameters.shake_256s_with_shake256, NISTObjectIdentifiers.id_hash_slh_dsa_shake_256s_with_shake256);
- shldsaOids.put(SLHDSAParameters.shake_256f_with_shake256, NISTObjectIdentifiers.id_hash_slh_dsa_shake_256f_with_shake256);
-
- shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_128s, SLHDSAParameters.sha2_128s);
- shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_128f, SLHDSAParameters.sha2_128f);
- shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_192s, SLHDSAParameters.sha2_192s);
- shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_192f, SLHDSAParameters.sha2_192f);
- shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_256s, SLHDSAParameters.sha2_256s);
- shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_256f, SLHDSAParameters.sha2_256f);
- shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_128s, SLHDSAParameters.shake_128s);
- shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_128f, SLHDSAParameters.shake_128f);
- shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_192s, SLHDSAParameters.shake_192s);
- shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_192f, SLHDSAParameters.shake_192f);
- shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_256s, SLHDSAParameters.shake_256s);
- shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_256f, SLHDSAParameters.shake_256f);
-
- shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_128s_with_sha256, SLHDSAParameters.sha2_128s_with_sha256);
- shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_128f_with_sha256, SLHDSAParameters.sha2_128f_with_sha256);
- shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_192s_with_sha512, SLHDSAParameters.sha2_192s_with_sha512);
- shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_192f_with_sha512, SLHDSAParameters.sha2_192f_with_sha512);
- shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_256s_with_sha512, SLHDSAParameters.sha2_256s_with_sha512);
- shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_256f_with_sha512, SLHDSAParameters.sha2_256f_with_sha512);
- shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_128s_with_shake128, SLHDSAParameters.shake_128s_with_shake128);
- shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_128f_with_shake128, SLHDSAParameters.shake_128f_with_shake128);
- shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_192s_with_shake256, SLHDSAParameters.shake_192s_with_shake256);
- shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_192f_with_shake256, SLHDSAParameters.shake_192f_with_shake256);
- shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_256s_with_shake256, SLHDSAParameters.shake_256s_with_shake256);
- shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_256f_with_shake256, SLHDSAParameters.shake_256f_with_shake256);
+ slhdsaOids.put(SLHDSAParameters.sha2_128s, NISTObjectIdentifiers.id_slh_dsa_sha2_128s);
+ slhdsaOids.put(SLHDSAParameters.sha2_128f, NISTObjectIdentifiers.id_slh_dsa_sha2_128f);
+ slhdsaOids.put(SLHDSAParameters.sha2_192s, NISTObjectIdentifiers.id_slh_dsa_sha2_192s);
+ slhdsaOids.put(SLHDSAParameters.sha2_192f, NISTObjectIdentifiers.id_slh_dsa_sha2_192f);
+ slhdsaOids.put(SLHDSAParameters.sha2_256s, NISTObjectIdentifiers.id_slh_dsa_sha2_256s);
+ slhdsaOids.put(SLHDSAParameters.sha2_256f, NISTObjectIdentifiers.id_slh_dsa_sha2_256f);
+ slhdsaOids.put(SLHDSAParameters.shake_128s, NISTObjectIdentifiers.id_slh_dsa_shake_128s);
+ slhdsaOids.put(SLHDSAParameters.shake_128f, NISTObjectIdentifiers.id_slh_dsa_shake_128f);
+ slhdsaOids.put(SLHDSAParameters.shake_192s, NISTObjectIdentifiers.id_slh_dsa_shake_192s);
+ slhdsaOids.put(SLHDSAParameters.shake_192f, NISTObjectIdentifiers.id_slh_dsa_shake_192f);
+ slhdsaOids.put(SLHDSAParameters.shake_256s, NISTObjectIdentifiers.id_slh_dsa_shake_256s);
+ slhdsaOids.put(SLHDSAParameters.shake_256f, NISTObjectIdentifiers.id_slh_dsa_shake_256f);
+
+ slhdsaOids.put(SLHDSAParameters.sha2_128s_with_sha256, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_128s_with_sha256);
+ slhdsaOids.put(SLHDSAParameters.sha2_128f_with_sha256, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_128f_with_sha256);
+ slhdsaOids.put(SLHDSAParameters.sha2_192s_with_sha512, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_192s_with_sha512);
+ slhdsaOids.put(SLHDSAParameters.sha2_192f_with_sha512, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_192f_with_sha512);
+ slhdsaOids.put(SLHDSAParameters.sha2_256s_with_sha512, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_256s_with_sha512);
+ slhdsaOids.put(SLHDSAParameters.sha2_256f_with_sha512, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_256f_with_sha512);
+ slhdsaOids.put(SLHDSAParameters.shake_128s_with_shake128, NISTObjectIdentifiers.id_hash_slh_dsa_shake_128s_with_shake128);
+ slhdsaOids.put(SLHDSAParameters.shake_128f_with_shake128, NISTObjectIdentifiers.id_hash_slh_dsa_shake_128f_with_shake128);
+ slhdsaOids.put(SLHDSAParameters.shake_192s_with_shake256, NISTObjectIdentifiers.id_hash_slh_dsa_shake_192s_with_shake256);
+ slhdsaOids.put(SLHDSAParameters.shake_192f_with_shake256, NISTObjectIdentifiers.id_hash_slh_dsa_shake_192f_with_shake256);
+ slhdsaOids.put(SLHDSAParameters.shake_256s_with_shake256, NISTObjectIdentifiers.id_hash_slh_dsa_shake_256s_with_shake256);
+ slhdsaOids.put(SLHDSAParameters.shake_256f_with_shake256, NISTObjectIdentifiers.id_hash_slh_dsa_shake_256f_with_shake256);
+
+ slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_128s, SLHDSAParameters.sha2_128s);
+ slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_128f, SLHDSAParameters.sha2_128f);
+ slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_192s, SLHDSAParameters.sha2_192s);
+ slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_192f, SLHDSAParameters.sha2_192f);
+ slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_256s, SLHDSAParameters.sha2_256s);
+ slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_256f, SLHDSAParameters.sha2_256f);
+ slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_128s, SLHDSAParameters.shake_128s);
+ slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_128f, SLHDSAParameters.shake_128f);
+ slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_192s, SLHDSAParameters.shake_192s);
+ slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_192f, SLHDSAParameters.shake_192f);
+ slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_256s, SLHDSAParameters.shake_256s);
+ slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_256f, SLHDSAParameters.shake_256f);
+
+ slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_128s_with_sha256, SLHDSAParameters.sha2_128s_with_sha256);
+ slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_128f_with_sha256, SLHDSAParameters.sha2_128f_with_sha256);
+ slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_192s_with_sha512, SLHDSAParameters.sha2_192s_with_sha512);
+ slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_192f_with_sha512, SLHDSAParameters.sha2_192f_with_sha512);
+ slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_256s_with_sha512, SLHDSAParameters.sha2_256s_with_sha512);
+ slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_256f_with_sha512, SLHDSAParameters.sha2_256f_with_sha512);
+ slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_128s_with_shake128, SLHDSAParameters.shake_128s_with_shake128);
+ slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_128f_with_shake128, SLHDSAParameters.shake_128f_with_shake128);
+ slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_192s_with_shake256, SLHDSAParameters.shake_192s_with_shake256);
+ slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_192f_with_shake256, SLHDSAParameters.shake_192f_with_shake256);
+ slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_256s_with_shake256, SLHDSAParameters.shake_256s_with_shake256);
+ slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_256f_with_shake256, SLHDSAParameters.shake_256f_with_shake256);
sphincsPlusOids.put(SLHDSAParameters.sha2_128s, BCObjectIdentifiers.sphincsPlus_sha2_128s);
sphincsPlusOids.put(SLHDSAParameters.sha2_128f, BCObjectIdentifiers.sphincsPlus_sha2_128f);
@@ -476,16 +480,26 @@ class Utils
sphincsPlusParams.put(BCObjectIdentifiers.sphincsPlus_shake_256f_r3_simple, SPHINCSPlusParameters.shake_256f);
sphincsPlusParams.put(BCObjectIdentifiers.sphincsPlus_haraka_256s_r3_simple, SPHINCSPlusParameters.haraka_256s_simple);
sphincsPlusParams.put(BCObjectIdentifiers.sphincsPlus_haraka_256f_r3_simple, SPHINCSPlusParameters.haraka_256f_simple);
+
+ mayoOids.put(MayoParameters.mayo1, BCObjectIdentifiers.mayo1);
+ mayoOids.put(MayoParameters.mayo2, BCObjectIdentifiers.mayo2);
+ mayoOids.put(MayoParameters.mayo3, BCObjectIdentifiers.mayo3);
+ mayoOids.put(MayoParameters.mayo5, BCObjectIdentifiers.mayo5);
+
+ mayoParams.put(BCObjectIdentifiers.mayo1, MayoParameters.mayo1);
+ mayoParams.put(BCObjectIdentifiers.mayo2, MayoParameters.mayo2);
+ mayoParams.put(BCObjectIdentifiers.mayo3, MayoParameters.mayo3);
+ mayoParams.put(BCObjectIdentifiers.mayo5, MayoParameters.mayo5);
}
static ASN1ObjectIdentifier slhdsaOidLookup(SLHDSAParameters params)
{
- return (ASN1ObjectIdentifier)shldsaOids.get(params);
+ return (ASN1ObjectIdentifier)slhdsaOids.get(params);
}
static SLHDSAParameters slhdsaParamsLookup(ASN1ObjectIdentifier oid)
{
- return (SLHDSAParameters)shldsaParams.get(oid);
+ return (SLHDSAParameters)slhdsaParams.get(oid);
}
static int qTeslaLookupSecurityCategory(AlgorithmIdentifier algorithm)
@@ -788,6 +802,16 @@ static RainbowParameters rainbowParamsLookup(ASN1ObjectIdentifier oid)
return (RainbowParameters)rainbowParams.get(oid);
}
+ static ASN1ObjectIdentifier mayoOidLookup(MayoParameters params)
+ {
+ return (ASN1ObjectIdentifier)mayoOids.get(params);
+ }
+
+ static MayoParameters mayoParamsLookup(ASN1ObjectIdentifier oid)
+ {
+ return (MayoParameters)mayoParams.get(oid);
+ }
+
private static boolean isRaw(byte[] data)
{
// check well-formed first
diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/MayoTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/MayoTest.java
index e479221220..d68d04930f 100644
--- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/MayoTest.java
+++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/MayoTest.java
@@ -1,9 +1,6 @@
package org.bouncycastle.pqc.crypto.test;
-import java.io.IOException;
import java.security.SecureRandom;
-import java.util.HashMap;
-import java.util.Map;
import junit.framework.TestCase;
import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
@@ -14,8 +11,8 @@
import org.bouncycastle.pqc.crypto.mayo.MayoKeyGenerationParameters;
import org.bouncycastle.pqc.crypto.mayo.MayoKeyPairGenerator;
import org.bouncycastle.pqc.crypto.mayo.MayoParameters;
-import org.bouncycastle.pqc.crypto.mayo.MayoPrivateKeyParameter;
-import org.bouncycastle.pqc.crypto.mayo.MayoPublicKeyParameter;
+import org.bouncycastle.pqc.crypto.mayo.MayoPrivateKeyParameters;
+import org.bouncycastle.pqc.crypto.mayo.MayoPublicKeyParameters;
import org.bouncycastle.pqc.crypto.mayo.MayoSigner;
public class MayoTest
@@ -31,10 +28,10 @@ public static void main(String[] args)
private static final MayoParameters[] PARAMETER_SETS = new MayoParameters[]
{
- MayoParameters.MAYO1,
- MayoParameters.MAYO2,
- MayoParameters.MAYO3,
- MayoParameters.MAYO5
+ MayoParameters.mayo1,
+ MayoParameters.mayo2,
+ MayoParameters.mayo3,
+ MayoParameters.mayo5
};
private static final String[] files = new String[]{
@@ -70,13 +67,13 @@ public AsymmetricCipherKeyPairGenerator getAsymmetricCipherKeyPairGenerator(int
@Override
public byte[] getPublicKeyEncoded(AsymmetricKeyParameter pubParams)
{
- return ((MayoPublicKeyParameter)pubParams).getEncoded();
+ return ((MayoPublicKeyParameters)pubParams).getEncoded();
}
@Override
public byte[] getPrivateKeyEncoded(CipherParameters privParams)
{
- return ((MayoPrivateKeyParameter)privParams).getEncoded();
+ return ((MayoPrivateKeyParameters)privParams).getEncoded();
}
@Override
diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java b/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
index f26c929495..6af5a7297a 100644
--- a/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
+++ b/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
@@ -38,6 +38,7 @@
import org.bouncycastle.pqc.jcajce.provider.hqc.HQCKeyFactorySpi;
import org.bouncycastle.pqc.jcajce.provider.kyber.KyberKeyFactorySpi;
import org.bouncycastle.pqc.jcajce.provider.lms.LMSKeyFactorySpi;
+import org.bouncycastle.pqc.jcajce.provider.mayo.MayoKeyFactorySpi;
import org.bouncycastle.pqc.jcajce.provider.newhope.NHKeyFactorySpi;
import org.bouncycastle.pqc.jcajce.provider.ntru.NTRUKeyFactorySpi;
import org.bouncycastle.pqc.jcajce.provider.picnic.PicnicKeyFactorySpi;
@@ -437,6 +438,11 @@ private void loadPQCKeys()
addKeyInfoConverter(BCObjectIdentifiers.ntruhps2048677, new NTRUKeyFactorySpi());
addKeyInfoConverter(BCObjectIdentifiers.ntruhps4096821, new NTRUKeyFactorySpi());
addKeyInfoConverter(BCObjectIdentifiers.ntruhrss701, new NTRUKeyFactorySpi());
+
+ addKeyInfoConverter(BCObjectIdentifiers.mayo1, new MayoKeyFactorySpi());
+ addKeyInfoConverter(BCObjectIdentifiers.mayo2, new MayoKeyFactorySpi());
+ addKeyInfoConverter(BCObjectIdentifiers.mayo3, new MayoKeyFactorySpi());
+ addKeyInfoConverter(BCObjectIdentifiers.mayo5, new MayoKeyFactorySpi());
}
public void setParameter(String parameterName, Object parameter)
diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/MayoKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/MayoKey.java
new file mode 100644
index 0000000000..efe8e2fb9d
--- /dev/null
+++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/MayoKey.java
@@ -0,0 +1,16 @@
+package org.bouncycastle.pqc.jcajce.interfaces;
+
+import java.security.Key;
+
+import org.bouncycastle.pqc.jcajce.spec.MayoParameterSpec;
+
+public interface MayoKey
+ extends Key
+{
+ /**
+ * Return the parameters for this key.
+ *
+ * @return a MayoParameterSpec
+ */
+ MayoParameterSpec getParameterSpec();
+}
diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java
index b1ef6ccbed..b616736f5b 100644
--- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java
+++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java
@@ -40,7 +40,8 @@ public class BouncyCastlePQCProvider
//"Rainbow", "McEliece",
"SPHINCS", "LMS", "NH", "XMSS", "SPHINCSPlus",
"CMCE", "Frodo", "SABER", "Picnic", "NTRU", "Falcon", "Kyber",
- "Dilithium", "NTRUPrime", "BIKE", "HQC", "Rainbow"
+ "Dilithium", "NTRUPrime", "BIKE", "HQC", "Rainbow",
+ "Mayo"
};
/**
diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/Mayo.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/Mayo.java
new file mode 100644
index 0000000000..ae8669d748
--- /dev/null
+++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/Mayo.java
@@ -0,0 +1,44 @@
+package org.bouncycastle.pqc.jcajce.provider;
+
+import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+import org.bouncycastle.pqc.jcajce.provider.mayo.MayoKeyFactorySpi;
+
+public class Mayo
+{
+ private static final String PREFIX = "org.bouncycastle.pqc.jcajce.provider.mayo.";
+
+ public static class Mappings
+ extends AsymmetricAlgorithmProvider
+ {
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("KeyFactory.Mayo", PREFIX + "MayoKeyFactorySpi");
+
+ addKeyFactoryAlgorithm(provider, "MAYO_1", PREFIX + "MayoKeyFactorySpi$Mayo1", BCObjectIdentifiers.mayo1, new MayoKeyFactorySpi.Mayo1());
+ addKeyFactoryAlgorithm(provider, "MAYO_2", PREFIX + "MayoKeyFactorySpi$Mayo2", BCObjectIdentifiers.mayo2, new MayoKeyFactorySpi.Mayo2());
+ addKeyFactoryAlgorithm(provider, "MAYO_3", PREFIX + "MayoKeyFactorySpi$Mayo3", BCObjectIdentifiers.mayo3, new MayoKeyFactorySpi.Mayo3());
+ addKeyFactoryAlgorithm(provider, "MAYO_5", PREFIX + "MayoKeyFactorySpi$Mayo5", BCObjectIdentifiers.mayo5, new MayoKeyFactorySpi.Mayo5());
+
+ provider.addAlgorithm("KeyPairGenerator.Mayo", PREFIX + "MayoKeyPairGeneratorSpi");
+
+ addKeyPairGeneratorAlgorithm(provider, "MAYO_1", PREFIX + "MayoKeyPairGeneratorSpi$Mayo1", BCObjectIdentifiers.mayo1);
+ addKeyPairGeneratorAlgorithm(provider, "MAYO_2", PREFIX + "MayoKeyPairGeneratorSpi$Mayo2", BCObjectIdentifiers.mayo2);
+ addKeyPairGeneratorAlgorithm(provider, "MAYO_3", PREFIX + "MayoKeyPairGeneratorSpi$Mayo3", BCObjectIdentifiers.mayo3);
+ addKeyPairGeneratorAlgorithm(provider, "MAYO_5", PREFIX + "MayoKeyPairGeneratorSpi$Mayo5", BCObjectIdentifiers.mayo5);
+
+ addSignatureAlgorithm(provider, "Mayo", PREFIX + "SignatureSpi$Base", BCObjectIdentifiers.mayo);
+
+ addSignatureAlgorithm(provider, "MAYO_1", PREFIX + "SignatureSpi$Mayo1", BCObjectIdentifiers.mayo1);
+ addSignatureAlgorithm(provider, "MAYO_2", PREFIX + "SignatureSpi$Mayo2", BCObjectIdentifiers.mayo2);
+ addSignatureAlgorithm(provider, "MAYO_3", PREFIX + "SignatureSpi$Mayo3", BCObjectIdentifiers.mayo3);
+ addSignatureAlgorithm(provider, "MAYO_5", PREFIX + "SignatureSpi$Mayo5", BCObjectIdentifiers.mayo5);
+ }
+ }
+}
+
diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/cmce/BCCMCEPrivateKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/cmce/BCCMCEPrivateKey.java
index e810a83003..a5868d94ce 100644
--- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/cmce/BCCMCEPrivateKey.java
+++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/cmce/BCCMCEPrivateKey.java
@@ -43,7 +43,7 @@ private void init(PrivateKeyInfo keyInfo)
}
/**
- * Compare this SPHINCS-256 private key with another object.
+ * Compare this CMCE private key with another object.
*
* @param o the other object
* @return the result of the comparison
diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/cmce/BCCMCEPublicKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/cmce/BCCMCEPublicKey.java
index 386b92a975..0d17b3793d 100644
--- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/cmce/BCCMCEPublicKey.java
+++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/cmce/BCCMCEPublicKey.java
@@ -40,7 +40,7 @@ private void init(SubjectPublicKeyInfo keyInfo)
}
/**
- * Compare this SPHINCS-256 public key with another object.
+ * Compare this CMCE public key with another object.
*
* @param o the other object
* @return the result of the comparison
diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/falcon/FalconKeyFactorySpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/falcon/FalconKeyFactorySpi.java
index d4f36890a5..58adc178c5 100644
--- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/falcon/FalconKeyFactorySpi.java
+++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/falcon/FalconKeyFactorySpi.java
@@ -17,7 +17,6 @@
import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
-import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
import org.bouncycastle.pqc.jcajce.provider.util.BaseKeyFactorySpi;
public class FalconKeyFactorySpi
diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/BCMayoPrivateKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/BCMayoPrivateKey.java
new file mode 100644
index 0000000000..043fee5635
--- /dev/null
+++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/BCMayoPrivateKey.java
@@ -0,0 +1,131 @@
+package org.bouncycastle.pqc.jcajce.provider.mayo;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.security.PrivateKey;
+
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.pqc.crypto.mayo.MayoPrivateKeyParameters;
+import org.bouncycastle.pqc.crypto.util.PrivateKeyFactory;
+import org.bouncycastle.pqc.crypto.util.PrivateKeyInfoFactory;
+import org.bouncycastle.pqc.jcajce.interfaces.MayoKey;
+import org.bouncycastle.pqc.jcajce.spec.MayoParameterSpec;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+
+public class BCMayoPrivateKey
+ implements PrivateKey, MayoKey
+{
+ private static final long serialVersionUID = 1L;
+
+ private transient MayoPrivateKeyParameters params;
+ private transient ASN1Set attributes;
+
+ public BCMayoPrivateKey(
+ MayoPrivateKeyParameters params)
+ {
+ this.params = params;
+ }
+
+ public BCMayoPrivateKey(PrivateKeyInfo keyInfo)
+ throws IOException
+ {
+ init(keyInfo);
+ }
+
+ private void init(PrivateKeyInfo keyInfo)
+ throws IOException
+ {
+ this.attributes = keyInfo.getAttributes();
+ this.params = (MayoPrivateKeyParameters) PrivateKeyFactory.createKey(keyInfo);
+ }
+
+ /**
+ * Compare this private key with another object.
+ *
+ * @param o the other object
+ * @return the result of the comparison
+ */
+ public boolean equals(Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (o instanceof BCMayoPrivateKey)
+ {
+ BCMayoPrivateKey otherKey = (BCMayoPrivateKey)o;
+
+ return Arrays.areEqual(params.getEncoded(), otherKey.params.getEncoded());
+ }
+
+ return false;
+ }
+
+ public int hashCode()
+ {
+ return Arrays.hashCode(params.getEncoded());
+ }
+
+ /**
+ * @return name of the algorithm - "Mayo[1|2|3|5]"
+ */
+ public final String getAlgorithm()
+ {
+ return Strings.toUpperCase(params.getParameters().getName());
+ }
+
+ public byte[] getEncoded()
+ {
+
+ try
+ {
+ PrivateKeyInfo pki = PrivateKeyInfoFactory.createPrivateKeyInfo(params, attributes);
+
+ return pki.getEncoded();
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public MayoParameterSpec getParameterSpec()
+ {
+ return MayoParameterSpec.fromName(params.getParameters().getName());
+ }
+
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ MayoPrivateKeyParameters getKeyParams()
+ {
+ return params;
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ byte[] enc = (byte[])in.readObject();
+
+ init(PrivateKeyInfo.getInstance(enc));
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(this.getEncoded());
+ }
+}
+
diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/BCMayoPublicKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/BCMayoPublicKey.java
new file mode 100644
index 0000000000..30d861d3b2
--- /dev/null
+++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/BCMayoPublicKey.java
@@ -0,0 +1,127 @@
+package org.bouncycastle.pqc.jcajce.provider.mayo;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.security.PublicKey;
+
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.pqc.crypto.mayo.MayoPublicKeyParameters;
+import org.bouncycastle.pqc.crypto.util.PublicKeyFactory;
+import org.bouncycastle.pqc.crypto.util.SubjectPublicKeyInfoFactory;
+import org.bouncycastle.pqc.jcajce.interfaces.MayoKey;
+import org.bouncycastle.pqc.jcajce.spec.MayoParameterSpec;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+
+public class BCMayoPublicKey
+ implements PublicKey, MayoKey
+{
+ private static final long serialVersionUID = 1L;
+
+ private transient MayoPublicKeyParameters params;
+
+ public BCMayoPublicKey(
+ MayoPublicKeyParameters params)
+ {
+ this.params = params;
+ }
+
+ public BCMayoPublicKey(SubjectPublicKeyInfo keyInfo)
+ throws IOException
+ {
+ init(keyInfo);
+ }
+
+ private void init(SubjectPublicKeyInfo keyInfo)
+ throws IOException
+ {
+ this.params = (MayoPublicKeyParameters) PublicKeyFactory.createKey(keyInfo);
+ }
+
+ /**
+ * Compare this BIKE public key with another object.
+ *
+ * @param o the other object
+ * @return the result of the comparison
+ */
+ public boolean equals(Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (o instanceof BCMayoPublicKey)
+ {
+ BCMayoPublicKey otherKey = (BCMayoPublicKey)o;
+
+ return Arrays.areEqual(params.getEncoded(), otherKey.params.getEncoded());
+ }
+
+ return false;
+ }
+
+ public int hashCode()
+ {
+ return Arrays.hashCode(params.getEncoded());
+ }
+
+ /**
+ * @return name of the algorithm - "BIKE"
+ */
+ public final String getAlgorithm()
+ {
+ return Strings.toUpperCase(params.getParameters().getName());
+ }
+
+ public byte[] getEncoded()
+ {
+ try
+ {
+ SubjectPublicKeyInfo pki = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(params);
+
+ return pki.getEncoded();
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public MayoParameterSpec getParameterSpec()
+ {
+ return MayoParameterSpec.fromName(params.getParameters().getName());
+ }
+
+ MayoPublicKeyParameters getKeyParams()
+ {
+ return params;
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ byte[] enc = (byte[])in.readObject();
+
+ init(SubjectPublicKeyInfo.getInstance(enc));
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(this.getEncoded());
+ }
+}
+
diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/MayoKeyFactorySpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/MayoKeyFactorySpi.java
new file mode 100644
index 0000000000..f27d25e86d
--- /dev/null
+++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/MayoKeyFactorySpi.java
@@ -0,0 +1,130 @@
+package org.bouncycastle.pqc.jcajce.provider.mayo;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.pqc.jcajce.provider.util.BaseKeyFactorySpi;
+
+public class MayoKeyFactorySpi
+ extends BaseKeyFactorySpi
+{
+ private static final Set keyOids = new HashSet();
+
+ static
+ {
+ keyOids.add(BCObjectIdentifiers.mayo1);
+ keyOids.add(BCObjectIdentifiers.mayo2);
+ keyOids.add(BCObjectIdentifiers.mayo3);
+ keyOids.add(BCObjectIdentifiers.mayo5);
+ }
+
+ public MayoKeyFactorySpi()
+ {
+ super(keyOids);
+ }
+
+ public MayoKeyFactorySpi(ASN1ObjectIdentifier keyOid)
+ {
+ super(keyOid);
+ }
+
+ public final KeySpec engineGetKeySpec(Key key, Class keySpec)
+ throws InvalidKeySpecException
+ {
+ if (key instanceof BCMayoPrivateKey)
+ {
+ if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new PKCS8EncodedKeySpec(key.getEncoded());
+ }
+ }
+ else if (key instanceof BCMayoPublicKey)
+ {
+ if (X509EncodedKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new X509EncodedKeySpec(key.getEncoded());
+ }
+ }
+ else
+ {
+ throw new InvalidKeySpecException("Unsupported key type: "
+ + key.getClass() + ".");
+ }
+
+ throw new InvalidKeySpecException("Unknown key specification: "
+ + keySpec + ".");
+ }
+
+ public final Key engineTranslateKey(Key key)
+ throws InvalidKeyException
+ {
+ if (key instanceof BCMayoPrivateKey || key instanceof BCMayoPublicKey)
+ {
+ return key;
+ }
+
+ throw new InvalidKeyException("Unsupported key type");
+ }
+
+ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+ throws IOException
+ {
+ return new BCMayoPrivateKey(keyInfo);
+ }
+
+ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+ throws IOException
+ {
+ return new BCMayoPublicKey(keyInfo);
+ }
+
+ public static class Mayo1
+ extends MayoKeyFactorySpi
+ {
+ public Mayo1()
+ {
+ super(BCObjectIdentifiers.mayo1);
+ }
+ }
+
+ public static class Mayo2
+ extends MayoKeyFactorySpi
+ {
+ public Mayo2()
+ {
+ super(BCObjectIdentifiers.mayo2);
+ }
+ }
+
+ public static class Mayo3
+ extends MayoKeyFactorySpi
+ {
+ public Mayo3()
+ {
+ super(BCObjectIdentifiers.mayo3);
+ }
+ }
+
+ public static class Mayo5
+ extends MayoKeyFactorySpi
+ {
+ public Mayo5()
+ {
+ super(BCObjectIdentifiers.mayo5);
+ }
+ }
+}
+
diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/MayoKeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/MayoKeyPairGeneratorSpi.java
new file mode 100644
index 0000000000..9f0eded803
--- /dev/null
+++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/MayoKeyPairGeneratorSpi.java
@@ -0,0 +1,150 @@
+package org.bouncycastle.pqc.jcajce.provider.mayo;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.CryptoServicesRegistrar;
+import org.bouncycastle.pqc.crypto.falcon.FalconParameters;
+import org.bouncycastle.pqc.crypto.mayo.MayoKeyGenerationParameters;
+import org.bouncycastle.pqc.crypto.mayo.MayoKeyPairGenerator;
+import org.bouncycastle.pqc.crypto.mayo.MayoParameters;
+import org.bouncycastle.pqc.crypto.mayo.MayoPrivateKeyParameters;
+import org.bouncycastle.pqc.crypto.mayo.MayoPublicKeyParameters;
+import org.bouncycastle.pqc.jcajce.provider.falcon.FalconKeyPairGeneratorSpi;
+import org.bouncycastle.pqc.jcajce.provider.util.SpecUtil;
+import org.bouncycastle.pqc.jcajce.spec.MayoParameterSpec;
+import org.bouncycastle.util.Strings;
+
+public class MayoKeyPairGeneratorSpi
+ extends java.security.KeyPairGenerator
+{
+ private static Map parameters = new HashMap();
+
+ static
+ {
+ parameters.put("MAYO_1", MayoParameters.mayo1);
+ parameters.put("MAYO_2", MayoParameters.mayo2);
+ parameters.put("MAYO_3", MayoParameters.mayo3);
+ parameters.put("MAYO_5", MayoParameters.mayo5);
+ parameters.put(MayoParameterSpec.mayo1.getName(), MayoParameters.mayo1);
+ parameters.put(MayoParameterSpec.mayo2.getName(), MayoParameters.mayo2);
+ parameters.put(MayoParameterSpec.mayo3.getName(), MayoParameters.mayo3);
+ parameters.put(MayoParameterSpec.mayo5.getName(), MayoParameters.mayo5);
+ }
+
+ MayoKeyGenerationParameters param;
+ private MayoParameters mayoParameters;
+ MayoKeyPairGenerator engine = new MayoKeyPairGenerator();
+
+ SecureRandom random = CryptoServicesRegistrar.getSecureRandom();
+ boolean initialised = false;
+
+ public MayoKeyPairGeneratorSpi()
+ {
+ super("Mayo");
+ }
+
+ protected MayoKeyPairGeneratorSpi(MayoParameters mayoParameters)
+ {
+ super(mayoParameters.getName());
+ this.mayoParameters = mayoParameters;
+ }
+
+ public void initialize(
+ int strength,
+ SecureRandom random)
+ {
+ throw new IllegalArgumentException("use AlgorithmParameterSpec");
+ }
+
+ public void initialize(
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ String name = getNameFromParams(params);
+
+ if (name != null)
+ {
+ param = new MayoKeyGenerationParameters(random, (MayoParameters)parameters.get(name));
+
+ engine.init(param);
+ initialised = true;
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("invalid ParameterSpec: " + params);
+ }
+ }
+
+ private static String getNameFromParams(AlgorithmParameterSpec paramSpec)
+ {
+ if (paramSpec instanceof MayoParameterSpec)
+ {
+ MayoParameterSpec MayoParams = (MayoParameterSpec)paramSpec;
+ return MayoParams.getName();
+ }
+ else
+ {
+ return Strings.toLowerCase(SpecUtil.getNameFrom(paramSpec));
+ }
+ }
+
+ public KeyPair generateKeyPair()
+ {
+ if (!initialised)
+ {
+ param = new MayoKeyGenerationParameters(random, MayoParameters.mayo1);
+
+ engine.init(param);
+ initialised = true;
+ }
+
+ AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+ MayoPublicKeyParameters pub = (MayoPublicKeyParameters)pair.getPublic();
+ MayoPrivateKeyParameters priv = (MayoPrivateKeyParameters)pair.getPrivate();
+
+ return new KeyPair(new BCMayoPublicKey(pub), new BCMayoPrivateKey(priv));
+ }
+
+ public static class Mayo1
+ extends MayoKeyPairGeneratorSpi
+ {
+ public Mayo1()
+ {
+ super(MayoParameters.mayo1);
+ }
+ }
+
+ public static class Mayo2
+ extends MayoKeyPairGeneratorSpi
+ {
+ public Mayo2()
+ {
+ super(MayoParameters.mayo2);
+ }
+ }
+
+ public static class Mayo3
+ extends MayoKeyPairGeneratorSpi
+ {
+ public Mayo3()
+ {
+ super(MayoParameters.mayo3);
+ }
+ }
+
+ public static class Mayo5
+ extends MayoKeyPairGeneratorSpi
+ {
+ public Mayo5()
+ {
+ super(MayoParameters.mayo5);
+ }
+ }
+}
diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/SignatureSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/SignatureSpi.java
new file mode 100644
index 0000000000..dd791cba9a
--- /dev/null
+++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/SignatureSpi.java
@@ -0,0 +1,218 @@
+package org.bouncycastle.pqc.jcajce.provider.mayo;
+
+import java.io.ByteArrayOutputStream;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.pqc.crypto.mayo.MayoParameters;
+import org.bouncycastle.pqc.crypto.mayo.MayoSigner;
+import org.bouncycastle.util.Strings;
+
+public class SignatureSpi
+ extends java.security.Signature
+{
+ private final ByteArrayOutputStream bOut;
+ private final MayoSigner signer;
+ private SecureRandom random;
+ private final MayoParameters parameters;
+
+ protected SignatureSpi(MayoSigner signer)
+ {
+ super("Mayo");
+
+ this.bOut = new ByteArrayOutputStream();
+ this.signer = signer;
+ this.parameters = null;
+ }
+
+ protected SignatureSpi(MayoSigner signer, MayoParameters parameters)
+ {
+ super(Strings.toUpperCase(parameters.getName()));
+ this.parameters = parameters;
+
+ this.bOut = new ByteArrayOutputStream();
+ this.signer = signer;
+ }
+
+ protected void engineInitVerify(PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ if (!(publicKey instanceof BCMayoPublicKey))
+ {
+ try
+ {
+ publicKey = new BCMayoPublicKey(SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()));
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("unknown public key passed to Mayo: " + e.getMessage(), e);
+ }
+ }
+
+ BCMayoPublicKey key = (BCMayoPublicKey)publicKey;
+
+ if (parameters != null)
+ {
+ String canonicalAlg = Strings.toUpperCase(parameters.getName());
+ if (!canonicalAlg.equals(key.getAlgorithm()))
+ {
+ throw new InvalidKeyException("signature configured for " + canonicalAlg);
+ }
+ }
+
+ signer.init(false, key.getKeyParams());
+ }
+
+ protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
+ throws InvalidKeyException
+ {
+ this.random = random;
+ engineInitSign(privateKey);
+ }
+
+ protected void engineInitSign(PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ if (privateKey instanceof BCMayoPrivateKey)
+ {
+ BCMayoPrivateKey key = (BCMayoPrivateKey)privateKey;
+ CipherParameters param = key.getKeyParams();
+
+ if (parameters != null)
+ {
+ String canonicalAlg = Strings.toUpperCase(parameters.getName());
+ if (!canonicalAlg.equals(key.getAlgorithm()))
+ {
+ throw new InvalidKeyException("signature configured for " + canonicalAlg);
+ }
+ }
+
+ if (random != null)
+ {
+ signer.init(true, new ParametersWithRandom(param, random));
+ }
+ else
+ {
+ signer.init(true, param);
+ }
+ }
+ else
+ {
+ throw new InvalidKeyException("unknown private key passed to Mayo");
+ }
+ }
+
+ protected void engineUpdate(byte b)
+ throws SignatureException
+ {
+ bOut.write(b);
+ }
+
+ protected void engineUpdate(byte[] b, int off, int len)
+ throws SignatureException
+ {
+ bOut.write(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ try
+ {
+ byte[] message = bOut.toByteArray();
+
+ bOut.reset();
+
+ return signer.generateSignature(message);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.toString());
+ }
+ }
+
+ protected boolean engineVerify(byte[] sigBytes)
+ throws SignatureException
+ {
+ byte[] message = bOut.toByteArray();
+
+ bOut.reset();
+
+ return signer.verifySignature(message, sigBytes);
+ }
+
+ protected void engineSetParameter(AlgorithmParameterSpec params)
+ {
+ // TODO
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated replaced with #engineSetParameter(java.security.spec.AlgorithmParameterSpec)
+ */
+ protected void engineSetParameter(String param, Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated
+ */
+ protected Object engineGetParameter(String param)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ public static class Base
+ extends org.bouncycastle.pqc.jcajce.provider.mayo.SignatureSpi
+ {
+ public Base()
+ {
+ super(new MayoSigner());
+ }
+ }
+
+ public static class Mayo1
+ extends org.bouncycastle.pqc.jcajce.provider.mayo.SignatureSpi
+ {
+ public Mayo1()
+ {
+ super(new MayoSigner(), MayoParameters.mayo1);
+ }
+ }
+
+ public static class Mayo2
+ extends org.bouncycastle.pqc.jcajce.provider.mayo.SignatureSpi
+ {
+ public Mayo2()
+ {
+ super(new MayoSigner(), MayoParameters.mayo2);
+ }
+ }
+
+ public static class Mayo3
+ extends org.bouncycastle.pqc.jcajce.provider.mayo.SignatureSpi
+ {
+ public Mayo3()
+ {
+ super(new MayoSigner(), MayoParameters.mayo3);
+ }
+ }
+
+ public static class Mayo5
+ extends org.bouncycastle.pqc.jcajce.provider.mayo.SignatureSpi
+ {
+ public Mayo5()
+ {
+ super(new MayoSigner(), MayoParameters.mayo5);
+ }
+ }
+}
+
diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/MayoParameterSpec.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/MayoParameterSpec.java
new file mode 100644
index 0000000000..9f3ee3e061
--- /dev/null
+++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/MayoParameterSpec.java
@@ -0,0 +1,48 @@
+package org.bouncycastle.pqc.jcajce.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.bouncycastle.pqc.crypto.mayo.MayoParameters;
+import org.bouncycastle.util.Strings;
+
+public class MayoParameterSpec
+ implements AlgorithmParameterSpec
+{
+ public static final MayoParameterSpec mayo1 = new MayoParameterSpec(MayoParameters.mayo1);
+ public static final MayoParameterSpec mayo2 = new MayoParameterSpec(MayoParameters.mayo2);
+ public static final MayoParameterSpec mayo3 = new MayoParameterSpec(MayoParameters.mayo3);
+ public static final MayoParameterSpec mayo5 = new MayoParameterSpec(MayoParameters.mayo5);
+
+ private static Map parameters = new HashMap();
+
+ static
+ {
+// parameters.put("mayo1", mayo1);
+// parameters.put("mayo2", mayo2);
+// parameters.put("mayo3", mayo3);
+// parameters.put("mayo5", mayo5);
+ parameters.put("MAYO_1", mayo1);
+ parameters.put("MAYO_2", mayo2);
+ parameters.put("MAYO_3", mayo3);
+ parameters.put("MAYO_5", mayo5);
+ }
+
+ private final String name;
+
+ private MayoParameterSpec(MayoParameters parameters)
+ {
+ this.name = parameters.getName();
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public static MayoParameterSpec fromName(String name)
+ {
+ return (MayoParameterSpec)parameters.get(Strings.toLowerCase(name));
+ }
+}
diff --git a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/MayoKeyPairGeneratorTest.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/MayoKeyPairGeneratorTest.java
new file mode 100644
index 0000000000..454722219c
--- /dev/null
+++ b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/MayoKeyPairGeneratorTest.java
@@ -0,0 +1,63 @@
+package org.bouncycastle.pqc.jcajce.provider.test;
+
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.SecureRandom;
+import java.security.Security;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.pqc.jcajce.spec.MayoParameterSpec;
+
+public class MayoKeyPairGeneratorTest
+ extends KeyPairGeneratorTest
+{
+ public static void main(String[] args)
+ throws Exception
+ {
+ MayoKeyPairGeneratorTest test = new MayoKeyPairGeneratorTest();
+ test.setUp();
+ test.testKeyFactory();
+ test.testKeyPairEncoding();
+ }
+
+ protected void setUp()
+ {
+ super.setUp();
+ if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+ }
+
+ public void testKeyFactory()
+ throws Exception
+ {
+ kf = KeyFactory.getInstance("Mayo", "BCPQC");
+ KeyFactory kf1 = KeyFactory.getInstance("MAYO_1", "BCPQC");
+ KeyFactory kf2 = KeyFactory.getInstance("MAYO_2", "BCPQC");
+ KeyFactory kf3 = KeyFactory.getInstance("MAYO_3", "BCPQC");
+ KeyFactory kf5 = KeyFactory.getInstance("MAYO_5", "BCPQC");
+ }
+
+ public void testKeyPairEncoding()
+ throws Exception
+ {
+ MayoParameterSpec[] specs =
+ new MayoParameterSpec[]
+ {
+ MayoParameterSpec.mayo1,
+ MayoParameterSpec.mayo2,
+ MayoParameterSpec.mayo3,
+ MayoParameterSpec.mayo5
+ };
+ kf = KeyFactory.getInstance("Mayo", "BCPQC");
+
+ kpg = KeyPairGenerator.getInstance("Mayo", "BCPQC");
+
+ for (int i = 0; i != specs.length; i++)
+ {
+ kpg.initialize(specs[i], new SecureRandom());
+ performKeyPairEncodingTest(specs[i].getName(), kpg.generateKeyPair());
+ }
+ }
+}
diff --git a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/MayoTest.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/MayoTest.java
new file mode 100644
index 0000000000..58d433f0c3
--- /dev/null
+++ b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/MayoTest.java
@@ -0,0 +1,276 @@
+package org.bouncycastle.pqc.jcajce.provider.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.Signature;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import junit.framework.TestCase;
+import org.bouncycastle.pqc.jcajce.interfaces.MayoKey;
+import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
+import org.bouncycastle.pqc.jcajce.spec.MayoParameterSpec;
+import org.bouncycastle.util.Strings;
+
+public class MayoTest
+ extends TestCase
+{
+ public static void main(String[] args)
+ throws Exception
+ {
+ MayoTest test = new MayoTest();
+ test.setUp();
+ test.testMayo3();
+ test.testMayo5();
+ test.testMayoRandomSig();
+ test.testPrivateKeyRecovery();
+ test.testPublicKeyRecovery();
+ test.testRestrictedKeyPairGen();
+ }
+
+ byte[] msg = Strings.toByteArray("Hello World!");
+
+ public void setUp()
+ {
+ if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null)
+ {
+ Security.addProvider(new BouncyCastlePQCProvider());
+ }
+ }
+
+ public void testPrivateKeyRecovery()
+ throws Exception
+ {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("Mayo", "BCPQC");
+
+ kpg.initialize(MayoParameterSpec.mayo1, new RiggedRandom());
+
+ KeyPair kp = kpg.generateKeyPair();
+
+ KeyFactory kFact = KeyFactory.getInstance("Mayo", "BCPQC");
+
+ MayoKey privKey = (MayoKey)kFact.generatePrivate(new PKCS8EncodedKeySpec(kp.getPrivate().getEncoded()));
+
+ assertEquals(kp.getPrivate(), privKey);
+ assertEquals(kp.getPrivate().getAlgorithm(), privKey.getAlgorithm());
+ assertEquals(kp.getPrivate().hashCode(), privKey.hashCode());
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ObjectOutputStream oOut = new ObjectOutputStream(bOut);
+
+ oOut.writeObject(privKey);
+
+ oOut.close();
+
+ ObjectInputStream oIn = new ObjectInputStream(new ByteArrayInputStream(bOut.toByteArray()));
+
+ MayoKey privKey2 = (MayoKey)oIn.readObject();
+
+ assertEquals(privKey, privKey2);
+ assertEquals(privKey.getAlgorithm(), privKey2.getAlgorithm());
+ assertEquals(privKey.hashCode(), privKey2.hashCode());
+ }
+
+ public void testPublicKeyRecovery()
+ throws Exception
+ {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("Mayo", "BCPQC");
+
+ kpg.initialize(MayoParameterSpec.mayo2, new MayoTest.RiggedRandom());
+
+ KeyPair kp = kpg.generateKeyPair();
+
+ KeyFactory kFact = KeyFactory.getInstance("Mayo_2", "BCPQC");
+
+ MayoKey pubKey = (MayoKey)kFact.generatePublic(new X509EncodedKeySpec(kp.getPublic().getEncoded()));
+
+ assertEquals(kp.getPublic(), pubKey);
+ assertEquals(kp.getPublic().getAlgorithm(), pubKey.getAlgorithm());
+ assertEquals(kp.getPublic().hashCode(), pubKey.hashCode());
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ObjectOutputStream oOut = new ObjectOutputStream(bOut);
+
+ oOut.writeObject(pubKey);
+
+ oOut.close();
+
+ ObjectInputStream oIn = new ObjectInputStream(new ByteArrayInputStream(bOut.toByteArray()));
+
+ MayoKey pubKey2 = (MayoKey)oIn.readObject();
+
+ assertEquals(pubKey, pubKey2);
+ assertEquals(pubKey.getAlgorithm(), pubKey2.getAlgorithm());
+ assertEquals(pubKey.hashCode(), pubKey2.hashCode());
+ }
+
+ public void testMayo5()
+ throws Exception
+ {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("Mayo", "BCPQC");
+
+ kpg.initialize(MayoParameterSpec.mayo5, new SecureRandom());
+
+ KeyPair kp = kpg.generateKeyPair();
+
+ Signature sig = Signature.getInstance("MAYO_5", "BCPQC");
+
+ sig.initSign(kp.getPrivate(), new SecureRandom());
+
+ sig.update(msg, 0, msg.length);
+
+ byte[] s = sig.sign();
+
+ sig = Signature.getInstance("MAYO_5", "BCPQC");
+
+ assertEquals("MAYO_5", Strings.toUpperCase(sig.getAlgorithm()));
+
+ sig.initVerify(kp.getPublic());
+
+ sig.update(msg, 0, msg.length);
+
+ assertTrue(sig.verify(s));
+
+ kpg = KeyPairGenerator.getInstance("Mayo", "BCPQC");
+
+ kpg.initialize(MayoParameterSpec.mayo1, new SecureRandom());
+
+ kp = kpg.generateKeyPair();
+
+ try
+ {
+ sig.initVerify(kp.getPublic());
+ fail("no exception");
+ }
+ catch (InvalidKeyException e)
+ {
+ assertEquals("signature configured for MAYO_5", e.getMessage());
+ }
+ }
+
+ public void testMayo3()
+ throws Exception
+ {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("Mayo", "BCPQC");
+
+ kpg.initialize(MayoParameterSpec.mayo3, new SecureRandom());
+
+ KeyPair kp = kpg.generateKeyPair();
+
+ Signature sig = Signature.getInstance("MAYO_3", "BCPQC");
+
+ sig.initSign(kp.getPrivate(), new SecureRandom());
+
+ sig.update(msg, 0, msg.length);
+
+ byte[] s = sig.sign();
+
+ sig = Signature.getInstance("MAYO_3", "BCPQC");
+
+ assertEquals("MAYO_3", Strings.toUpperCase(sig.getAlgorithm()));
+
+ sig.initVerify(kp.getPublic());
+
+ sig.update(msg, 0, msg.length);
+
+ assertTrue(sig.verify(s));
+
+ kpg = KeyPairGenerator.getInstance("Mayo", "BCPQC");
+
+ kpg.initialize(MayoParameterSpec.mayo5, new SecureRandom());
+
+ kp = kpg.generateKeyPair();
+
+ try
+ {
+ sig.initVerify(kp.getPublic());
+ fail("no exception");
+ }
+ catch (InvalidKeyException e)
+ {
+ assertEquals("signature configured for MAYO_3", e.getMessage());
+ }
+ }
+
+ public void testRestrictedKeyPairGen()
+ throws Exception
+ {
+ doTestRestrictedKeyPairGen(MayoParameterSpec.mayo1);
+ doTestRestrictedKeyPairGen(MayoParameterSpec.mayo2);
+ doTestRestrictedKeyPairGen(MayoParameterSpec.mayo3);
+ doTestRestrictedKeyPairGen(MayoParameterSpec.mayo5);
+ }
+
+ private void doTestRestrictedKeyPairGen(MayoParameterSpec spec)
+ throws Exception
+ {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance(spec.getName(), "BCPQC");
+
+ kpg.initialize(spec, new SecureRandom());
+
+ KeyPair kp = kpg.generateKeyPair();
+
+ assertEquals(spec.getName(), kp.getPublic().getAlgorithm());
+ assertEquals(spec.getName(), kp.getPrivate().getAlgorithm());
+
+ //kpg = KeyPairGenerator.getInstance(spec.getName(), "BCPQC");
+
+// try
+// {
+// kpg.initialize(altSpec, new SecureRandom());
+// fail("no exception");
+// }
+// catch (InvalidAlgorithmParameterException e)
+// {
+// assertEquals("key pair generator locked to " + spec.getName(), e.getMessage());
+// }
+ }
+
+ public void testMayoRandomSig()
+ throws Exception
+ {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("Mayo", "BCPQC");
+
+ kpg.initialize(MayoParameterSpec.mayo2, new SecureRandom());
+
+ KeyPair kp = kpg.generateKeyPair();
+
+ Signature sig = Signature.getInstance("Mayo", "BCPQC");
+
+ sig.initSign(kp.getPrivate(), new SecureRandom());
+
+ sig.update(msg, 0, msg.length);
+
+ byte[] s = sig.sign();
+
+ sig = Signature.getInstance("Mayo", "BCPQC");
+
+ sig.initVerify(kp.getPublic());
+
+ sig.update(msg, 0, msg.length);
+
+ assertTrue(sig.verify(s));
+ }
+
+ private static class RiggedRandom
+ extends SecureRandom
+ {
+ public void nextBytes(byte[] bytes)
+ {
+ for (int i = 0; i != bytes.length; i++)
+ {
+ bytes[i] = (byte)(i & 0xff);
+ }
+ }
+ }
+
+}
+
From 76a597b2c768c6d6ba125fdc1fa41ad9e0762c82 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Tue, 4 Mar 2025 13:11:32 +1030
Subject: [PATCH 145/890] Add Mayo to PQC Provider
---
.../org/bouncycastle/pqc/jcajce/provider/test/AllTests.java | 2 ++
1 file changed, 2 insertions(+)
diff --git a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/AllTests.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/AllTests.java
index 693dae7730..a01a130495 100644
--- a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/AllTests.java
+++ b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/AllTests.java
@@ -77,6 +77,8 @@ public static Test suite()
suite.addTestSuite(HQCTest.class);
suite.addTestSuite(RainbowKeyPairGeneratorTest.class);
suite.addTestSuite(RainbowTest.class);
+ suite.addTestSuite(MayoKeyPairGeneratorTest.class);
+ suite.addTestSuite(MayoTest.class);
return new BCTestSetup(suite);
}
From 025f99d1ad942e895b98b5589073fafb1771b27d Mon Sep 17 00:00:00 2001
From: gefeili
Date: Tue, 4 Mar 2025 14:40:35 +1030
Subject: [PATCH 146/890] Refactor of Mayo
---
.../pqc/crypto/mayo/GF16Utils.java | 105 +++++-------
.../pqc/crypto/mayo/MayoKeyPairGenerator.java | 2 +-
.../pqc/crypto/mayo/MayoSigner.java | 149 +++++++++---------
.../java/org/bouncycastle/util/Bytes.java | 8 +
4 files changed, 119 insertions(+), 145 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java
index 6595d412eb..cc2db8ba1d 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java
@@ -1,6 +1,6 @@
package org.bouncycastle.pqc.crypto.mayo;
-public class GF16Utils
+class GF16Utils
{
static final long NIBBLE_MASK_MSB = 0x7777777777777777L;
static final long MASK_MSB = 0x8888888888888888L;
@@ -20,7 +20,7 @@ public class GF16Utils
* @param acc the accumulator long array; the target vector starts at index accOffset
* @param accOffset the starting index in 'acc'
*/
- public static void mVecMulAdd(int mVecLimbs, long[] in, int inOffset, int b, long[] acc, int accOffset)
+ static void mVecMulAdd(int mVecLimbs, long[] in, int inOffset, int b, long[] acc, int accOffset)
{
long a, r64, a_msb, a_msb3;
long b32 = b & 0x00000000FFFFFFFFL;
@@ -67,18 +67,17 @@ public static void mVecMulAdd(int mVecLimbs, long[] in, int inOffset, int b, lon
* @param acc the accumulator (as a flat long[] array) with dimensions (bsMatRows x matCols);
* each “entry” is an m‐vector (length mVecLimbs).
* @param bsMatRows number of rows in the bsMat (the “triangular” matrix’s row count).
- * @param bsMatCols number of columns in bsMat.
* @param matCols number of columns in the matrix “mat.”
*/
- public static void mulAddMUpperTriangularMatXMat(int mVecLimbs, long[] bsMat, byte[] mat, long[] acc, int accOff,
- int bsMatRows, int bsMatCols, int matCols)
+ static void mulAddMUpperTriangularMatXMat(int mVecLimbs, long[] bsMat, byte[] mat, long[] acc, int accOff,
+ int bsMatRows, int matCols)
{
int bsMatEntriesUsed = 0;
int matColsmVecLimbs = matCols * mVecLimbs;
for (int r = 0, rmatCols = 0, rmatColsmVecLimbs = 0; r < bsMatRows; r++, rmatCols += matCols, rmatColsmVecLimbs += matColsmVecLimbs)
{
// For each row r, the inner loop goes from column triangular*r to bsMatCols-1.
- for (int c = r, cmatCols = rmatCols; c < bsMatCols; c++, cmatCols += matCols)
+ for (int c = r, cmatCols = rmatCols; c < bsMatRows; c++, cmatCols += matCols)
{
for (int k = 0, kmVecLimbs = 0; k < matCols; k++, kmVecLimbs += mVecLimbs)
{
@@ -103,8 +102,8 @@ public static void mulAddMUpperTriangularMatXMat(int mVecLimbs, long[] bsMat, by
* @param matCols number of columns in “mat.”
* @param bsMatCols number of columns in the bsMat matrix.
*/
- public static void mulAddMatTransXMMat(int mVecLimbs, byte[] mat, long[] bsMat, int bsMatOff, long[] acc,
- int matRows, int matCols, int bsMatCols)
+ static void mulAddMatTransXMMat(int mVecLimbs, byte[] mat, long[] bsMat, int bsMatOff, long[] acc,
+ int matRows, int matCols, int bsMatCols)
{
// Loop over each column r of mat (which becomes row of mat^T)
for (int r = 0; r < matCols; r++)
@@ -141,8 +140,8 @@ public static void mulAddMatTransXMMat(int mVecLimbs, byte[] mat, long[] bsMat,
* @param matCols the number of columns in the matrix
* @param bsMatCols the number of columns in the bit‐sliced matrix (per block)
*/
- public static void mulAddMatXMMat(int mVecLimbs, byte[] mat, long[] bsMat, long[] acc,
- int matRows, int matCols, int bsMatCols)
+ static void mulAddMatXMMat(int mVecLimbs, byte[] mat, long[] bsMat, long[] acc,
+ int matRows, int matCols, int bsMatCols)
{
for (int r = 0; r < matRows; r++)
{
@@ -163,8 +162,8 @@ public static void mulAddMatXMMat(int mVecLimbs, byte[] mat, long[] bsMat, long[
}
}
- public static void mulAddMatXMMat(int mVecLimbs, byte[] mat, long[] bsMat, int bsMatOff, long[] acc,
- int matRows, int matCols, int bsMatCols)
+ static void mulAddMatXMMat(int mVecLimbs, byte[] mat, long[] bsMat, int bsMatOff, long[] acc,
+ int matRows, int matCols, int bsMatCols)
{
for (int r = 0; r < matRows; r++)
{
@@ -204,8 +203,8 @@ public static void mulAddMatXMMat(int mVecLimbs, byte[] mat, long[] bsMat, int b
* @param bsMatCols the number of columns in the bit‑sliced matrix.
* @param matRows the number of rows in the matrix.
*/
- public static void mulAddMUpperTriangularMatXMatTrans(int mVecLimbs, long[] bsMat, byte[] mat, long[] acc,
- int bsMatRows, int bsMatCols, int matRows)
+ static void mulAddMUpperTriangularMatXMatTrans(int mVecLimbs, long[] bsMat, byte[] mat, long[] acc,
+ int bsMatRows, int bsMatCols, int matRows)
{
int bsMatEntriesUsed = 0;
for (int r = 0; r < bsMatRows; r++)
@@ -236,23 +235,28 @@ public static void mulAddMUpperTriangularMatXMatTrans(int mVecLimbs, long[] bsMa
* @param b an element in GF(16) (only the lower 4 bits are used)
* @return the product a * b in GF(16)
*/
- public static int mulF(int a, int b)
+ static int mulF(int a, int b)
{
- // In C there is a conditional XOR with unsigned_char_blocker to work around
- // compiler-specific behavior. In Java we can omit it (or define it as needed).
- // a ^= unsignedCharBlocker; // Omitted in Java
-
- // Perform carryless multiplication:
- // Multiply b by each bit of a and XOR the results.
- int p = ((a & 1) * b) ^ ((a & 2) * b) ^ ((a & 4) * b) ^ ((a & 8) * b);
-
+ // Carryless multiply: multiply b by each bit of a and XOR.
+ int p = (-(a & 1) & b) ^ (-((a >> 1) & 1) & (b << 1)) ^ (-((a >> 2) & 1) & (b << 2)) ^ (-((a >> 3) & 1) & (b << 3));
// Reduce modulo f(X) = x^4 + x + 1.
- // Extract the upper nibble (bits 4 to 7).
int topP = p & 0xF0;
- // The reduction: XOR p with (topP shifted right by 4 and by 3) and mask to 4 bits.
return (p ^ (topP >> 4) ^ (topP >> 3)) & 0x0F;
}
+ /**
+ * Computes the multiplicative inverse in GF(16) for a GF(16) element.
+ */
+ static byte inverseF(int a)
+ {
+ // In GF(16), the inverse can be computed via exponentiation.
+ int a2 = mulF(a, a);
+ int a4 = mulF(a2, a2);
+ int a8 = mulF(a4, a4);
+ int a6 = mulF(a2, a4);
+ return (byte) mulF(a8, a6);
+ }
+
/**
* Performs a GF(16) carryless multiplication of a nibble (lower 4 bits of a)
* with a 64-bit word b, then reduces modulo the polynomial x⁴ + x + 1 on each byte.
@@ -261,64 +265,29 @@ public static int mulF(int a, int b)
* @param b a 64-bit word representing 16 GF(16) elements (packed 4 bits per element)
* @return the reduced 64-bit word after multiplication
*/
- public static long mulFx8(byte a, long b)
+ static long mulFx8(byte a, long b)
{
// Convert 'a' to an unsigned int so that bit operations work as expected.
int aa = a & 0xFF;
// Carryless multiplication: for each bit in 'aa' (considering only the lower 4 bits),
// if that bit is set, multiply 'b' (by 1, 2, 4, or 8) and XOR the result.
- long p = ((aa & 1) * b) ^ ((aa & 2) * b) ^ ((aa & 4) * b) ^ ((aa & 8) * b);
+ long p = (-(aa & 1) & b) ^ (-((aa >> 1) & 1) & (b << 1)) ^ (-((aa >> 2) & 1) & (b << 2)) ^ (-((aa >> 3) & 1) & (b << 3));
// Reduction mod (x^4 + x + 1): process each byte in parallel.
long topP = p & 0xf0f0f0f0f0f0f0f0L;
return (p ^ (topP >> 4) ^ (topP >> 3)) & 0x0f0f0f0f0f0f0f0fL;
}
- public static void matMul(byte[] a, byte[] b, byte[] c, int colrowAB, int rowA, int colB)
- {
- int cIndex = 0;
- for (int i = 0; i < rowA; i++)
- {
- int aRowStart = i * colrowAB;
- for (int j = 0; j < colB; j++)
- {
- c[cIndex++] = lincomb(a, aRowStart, b, j, colrowAB, colB);
- }
- }
- }
-
- public static void matMul(byte[] a, int aOff, byte[] b, int bOff, byte[] c, int cOff,
- int colrowAB, int rowA, int colB)
- {
- for (int i = 0, aRowStart = 0; i < rowA; i++, aRowStart += colrowAB)
- {
- for (int j = 0; j < colB; j++)
- {
- c[cOff++] = lincomb(a, aOff + aRowStart, b, bOff + j, colrowAB, colB);
- }
- }
- }
-
- private static byte lincomb(byte[] a, int aStart, byte[] b, int bStart,
- int colrowAB, int colB)
- {
- byte result = 0;
- for (int k = 0; k < colrowAB; k++)
- {
- result ^= mulF(a[aStart + k], b[bStart + k * colB]);
- }
- return result;
- }
-
- public static void matAdd(byte[] a, int aOff, byte[] b, int bOff, byte[] c, int cOff, int m, int n)
+ static void matMul(byte[] a, byte[] b, int bOff, byte[] c, int colrowAB, int rowA)
{
- for (int i = 0, in = 0; i < m; i++, in += n)
+ for (int i = 0, aRowStart = 0, cOff = 0; i < rowA; i++, aRowStart += colrowAB)
{
- for (int j = 0; j < n; j++)
+ byte result = 0;
+ for (int k = 0; k < colrowAB; k++)
{
- int idx = in + j;
- c[idx + cOff] = (byte)(a[idx + aOff] ^ b[idx + bOff]);
+ result ^= mulF(a[aRowStart + k], b[bOff + k]);
}
+ c[cOff++] = result;
}
}
}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
index ffad286ab3..af6e96100c 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
@@ -69,7 +69,7 @@ public AsymmetricCipherKeyPair generateKeyPair()
// Compute P1 * O + P2 and store the result in P2.
// GF16Utils.P1TimesO(p, P, O, P2);
// Here, bsMatRows and bsMatCols are both paramV, and matCols is paramO, triangular=1.
- GF16Utils.mulAddMUpperTriangularMatXMat(mVecLimbs, P, O, P, p1Limbs, v, v, o);
+ GF16Utils.mulAddMUpperTriangularMatXMat(mVecLimbs, P, O, P, p1Limbs, v, o);
// Compute P3 = O^T * (P1*O + P2).
// Here, treat P2 as the bsMat for the multiplication.
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
index 9d8656b26f..7a5cbcb109 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
@@ -8,6 +8,7 @@
import org.bouncycastle.pqc.crypto.MessageSigner;
import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Bytes;
import org.bouncycastle.util.Longs;
import org.bouncycastle.util.Pack;
@@ -204,8 +205,8 @@ public byte[] generateSignature(byte[] message)
byte[] Ox = new byte[v];
for (int i = 0; i < k; i++)
{
- GF16Utils.matMul(O, 0, x, i * o, Ox, 0, o, n - o, 1);
- GF16Utils.matAdd(Vdec, i * v, Ox, 0, s, i * n, v, 1);
+ GF16Utils.matMul(O, x, i * o, Ox, o, n - o);
+ Bytes.xor(v, Vdec, i * v, Ox, s, i * n);
System.arraycopy(x, i * o, s, i * n + n - o, o);
}
@@ -287,7 +288,7 @@ public boolean verifySignature(byte[] message, byte[] signature)
return Arrays.constantTimeAreEqual(m, y, 0, t, 0);
}
- public void computeRHS(long[] vPv, byte[] t, byte[] y)
+ void computeRHS(long[] vPv, byte[] t, byte[] y)
{
final int m = params.getM();
final int mVecLimbs = params.getMVecLimbs();
@@ -350,16 +351,16 @@ public void computeRHS(long[] vPv, byte[] t, byte[] y)
Pack.littleEndianToLong(tempBytes, 0, temp);
// Extract from vPv and add
- int matrixIndex = i * k + j;
- int symmetricIndex = j * k + i;
+ int matrixIndex = (i * k + j) * mVecLimbs;
+ int symmetricIndex = (j * k + i) * mVecLimbs;
boolean isDiagonal = (i == j);
for (int limb = 0; limb < mVecLimbs; limb++)
{
- long value = vPv[matrixIndex * mVecLimbs + limb];
+ long value = vPv[matrixIndex + limb];
if (!isDiagonal)
{
- value ^= vPv[symmetricIndex * mVecLimbs + limb];
+ value ^= vPv[symmetricIndex + limb];
}
temp[limb] ^= value;
}
@@ -379,7 +380,7 @@ public void computeRHS(long[] vPv, byte[] t, byte[] y)
private static final long EVEN_BYTES = 0x00FF00FF00FF00FFL;
private static final long EVEN_2BYTES = 0x0000FFFF0000FFFFL;
- public void computeA(long[] Mtmp, byte[] AOut)
+ void computeA(long[] Mtmp, byte[] AOut)
{
final int k = params.getK();
final int o = params.getO();
@@ -554,8 +555,8 @@ private static void transpose16x16Nibbles(long[] M, int offset)
}
}
- public boolean sampleSolution(MayoParameters params, byte[] A, byte[] y,
- byte[] r, byte[] x)
+ boolean sampleSolution(MayoParameters params, byte[] A, byte[] y,
+ byte[] r, byte[] x)
{
final int k = params.getK();
final int o = params.getO();
@@ -573,7 +574,7 @@ public boolean sampleSolution(MayoParameters params, byte[] A, byte[] y,
// {
// A[k * o + i * (k * o + 1)] = 0;
// }
- GF16Utils.matMul(A, r, Ar, k * o + 1, m, 1);
+ GF16Utils.matMul(A, r, 0, Ar, k * o + 1, m);
// Update last column of A with y - Ar
for (int i = 0; i < m; i++)
@@ -645,7 +646,7 @@ public boolean sampleSolution(MayoParameters params, byte[] A, byte[] y,
* @param nrows the number of rows
* @param ncols the number of columns (GF(16) elements per row)
*/
- public void ef(byte[] A, int nrows, int ncols)
+ void ef(byte[] A, int nrows, int ncols)
{
// Each 64-bit long can hold 16 nibbles (16 GF(16) elements).
int rowLen = (ncols + 15) / 16;
@@ -713,8 +714,7 @@ public void ef(byte[] A, int nrows, int ncols)
}
// Multiply the pivot row by the inverse of the pivot element.
- int inv = inverseF(pivot);
- vecMulAddU64(rowLen, pivotRow, (byte)inv, pivotRow2);
+ vecMulAddU64(rowLen, pivotRow, GF16Utils.inverseF(pivot), pivotRow2);
// Conditionally write the pivot row back into the correct row (if pivot is nonzero).
for (int row = lowerBound, rowRowLen = lowerBound * rowLen; row <= upperBound; row++, rowRowLen += rowLen)
@@ -769,33 +769,6 @@ private static long ctCompare64(int a, int b)
return (-(long)(a ^ b)) >> 63;
}
- /**
- * Computes the multiplicative inverse in GF(16) for a GF(16) element.
- */
- private static int inverseF(int a)
- {
- // In GF(16), the inverse can be computed via exponentiation.
- int a2 = mulF(a, a);
- int a4 = mulF(a2, a2);
- int a8 = mulF(a4, a4);
- int a6 = mulF(a2, a4);
- return mulF(a8, a6);
- }
-
- /**
- * GF(16) multiplication mod (x^4 + x + 1).
- *
- * Multiplies two GF(16) elements (only the lower 4 bits are used).
- */
- public static int mulF(int a, int b)
- {
- // Carryless multiply: multiply b by each bit of a and XOR.
- int p = (-(a & 1) & b) ^ (-((a >> 1) & 1) & (b << 1)) ^ (-((a >> 2) & 1) & (b << 2)) ^ (-((a >> 3) & 1) & (b << 3));
- // Reduce modulo f(X) = x^4 + x + 1.
- int topP = p & 0xF0;
- return (p ^ (topP >> 4) ^ (topP >> 3)) & 0x0F;
- }
-
/**
* Multiplies each word of the input vector (in) by a GF(16) scalar (a),
* then XORs the result into the accumulator vector (acc).
@@ -927,45 +900,69 @@ private static void mayoGenericMCalculateSPS(long[] PS, byte[] S, int mVecLimbs,
private static void mVecMultiplyBins(int mVecLimbs, int len, long[] bins, long[] ps)
{
+ long a, b, t;
+ int mVecLimbs2 = mVecLimbs + mVecLimbs,
+ mVecLimbs3 = mVecLimbs2 + mVecLimbs,
+ mVecLimbs4 = mVecLimbs3 + mVecLimbs,
+ mVecLimbs5 = mVecLimbs4 + mVecLimbs,
+ mVecLimbs6 = mVecLimbs5 + mVecLimbs,
+ mVecLimbs7 = mVecLimbs6 + mVecLimbs,
+ mVecLimbs8 = mVecLimbs7 + mVecLimbs,
+ mVecLimbs9 = mVecLimbs8 + mVecLimbs,
+ mVecLimbs10 = mVecLimbs9 + mVecLimbs,
+ mVecLimbs11 = mVecLimbs10 + mVecLimbs,
+ mVecLimbs12 = mVecLimbs11 + mVecLimbs,
+ mVecLimbs13 = mVecLimbs12 + mVecLimbs,
+ mVecLimbs14 = mVecLimbs13 + mVecLimbs,
+ mVecLimbs15 = mVecLimbs14 + mVecLimbs;
for (int i = 0, imVecLimbs4 = 0; i < len; i++, imVecLimbs4 += (mVecLimbs << 4))
{
- // Series of modular operations as per original C code
- mVecMulAddXInv(mVecLimbs, bins, imVecLimbs4 + 5 * mVecLimbs, bins, imVecLimbs4 + 10 * mVecLimbs);
- mVecMulAddX(mVecLimbs, bins, imVecLimbs4 + 11 * mVecLimbs, bins, imVecLimbs4 + 12 * mVecLimbs);
- mVecMulAddXInv(mVecLimbs, bins, imVecLimbs4 + 10 * mVecLimbs, bins, imVecLimbs4 + 7 * mVecLimbs);
- mVecMulAddX(mVecLimbs, bins, imVecLimbs4 + 12 * mVecLimbs, bins, imVecLimbs4 + 6 * mVecLimbs);
- mVecMulAddXInv(mVecLimbs, bins, imVecLimbs4 + 7 * mVecLimbs, bins, imVecLimbs4 + 14 * mVecLimbs);
- mVecMulAddX(mVecLimbs, bins, imVecLimbs4 + 6 * mVecLimbs, bins, imVecLimbs4 + 3 * mVecLimbs);
- mVecMulAddXInv(mVecLimbs, bins, imVecLimbs4 + 14 * mVecLimbs, bins, imVecLimbs4 + 15 * mVecLimbs);
- mVecMulAddX(mVecLimbs, bins, imVecLimbs4 + 3 * mVecLimbs, bins, imVecLimbs4 + 8 * mVecLimbs);
- mVecMulAddXInv(mVecLimbs, bins, imVecLimbs4 + 15 * mVecLimbs, bins, imVecLimbs4 + 13 * mVecLimbs);
- mVecMulAddX(mVecLimbs, bins, imVecLimbs4 + 8 * mVecLimbs, bins, imVecLimbs4 + 4 * mVecLimbs);
- mVecMulAddXInv(mVecLimbs, bins, imVecLimbs4 + 13 * mVecLimbs, bins, imVecLimbs4 + 9 * mVecLimbs);
- mVecMulAddX(mVecLimbs, bins, imVecLimbs4 + 4 * mVecLimbs, bins, imVecLimbs4 + 2 * mVecLimbs);
- mVecMulAddXInv(mVecLimbs, bins, imVecLimbs4 + 9 * mVecLimbs, bins, imVecLimbs4 + mVecLimbs);
- mVecMulAddX(mVecLimbs, bins, imVecLimbs4 + 2 * mVecLimbs, bins, imVecLimbs4 + mVecLimbs);
- System.arraycopy(bins, mVecLimbs + imVecLimbs4, ps, imVecLimbs4 >> 4, mVecLimbs);
- }
- }
+ for (int j = 0, off = imVecLimbs4; j < mVecLimbs; j++, off++)
+ {
+ b = bins[off + mVecLimbs5];
+ t = b & GF16Utils.MASK_LSB;
+ b = bins[off + mVecLimbs10] ^ ((b & GF16Utils.NIBBLE_MASK_LSB) >>> 1) ^ ((t << 3) + t);
- // Modular arithmetic operations
- private static void mVecMulAddXInv(int limbs, long[] in, int inOffset, long[] acc, int accOffset)
- {
- for (int i = 0; i < limbs; i++)
- {
- long input = in[inOffset + i];
- long t = input & GF16Utils.MASK_LSB;
- acc[accOffset + i] ^= ((input & GF16Utils.NIBBLE_MASK_LSB) >>> 1) ^ ((t << 3) + t);
- }
- }
+ a = bins[off + mVecLimbs11];
+ t = (a & GF16Utils.MASK_MSB) >>> 3;
+ a = bins[off + mVecLimbs12] ^ ((a & GF16Utils.NIBBLE_MASK_MSB) << 1) ^ ((t << 1) + t);
- private static void mVecMulAddX(int limbs, long[] in, int inOffset, long[] acc, int accOffset)
- {
- for (int i = 0; i < limbs; i++)
- {
- long input = in[inOffset + i];
- long t = (input & GF16Utils.MASK_MSB) >>> 3;
- acc[accOffset + i] ^= ((input & GF16Utils.NIBBLE_MASK_MSB) << 1) ^ ((t << 1) + t);
+ t = b & GF16Utils.MASK_LSB;
+ b = bins[off + mVecLimbs7] ^ ((b & GF16Utils.NIBBLE_MASK_LSB) >>> 1) ^ ((t << 3) + t);
+
+ t = (a & GF16Utils.MASK_MSB) >>> 3;
+ a = bins[off + mVecLimbs6] ^ ((a & GF16Utils.NIBBLE_MASK_MSB) << 1) ^ ((t << 1) + t);
+
+ t = b & GF16Utils.MASK_LSB;
+ b = bins[off + mVecLimbs14] ^ ((b & GF16Utils.NIBBLE_MASK_LSB) >>> 1) ^ ((t << 3) + t);
+
+ t = (a & GF16Utils.MASK_MSB) >>> 3;
+ a = bins[off + mVecLimbs3] ^ ((a & GF16Utils.NIBBLE_MASK_MSB) << 1) ^ ((t << 1) + t);
+
+ t = b & GF16Utils.MASK_LSB;
+ b = bins[off + mVecLimbs15] ^ ((b & GF16Utils.NIBBLE_MASK_LSB) >>> 1) ^ ((t << 3) + t);
+
+ t = (a & GF16Utils.MASK_MSB) >>> 3;
+ a = bins[off + mVecLimbs8] ^ ((a & GF16Utils.NIBBLE_MASK_MSB) << 1) ^ ((t << 1) + t);
+
+ t = b & GF16Utils.MASK_LSB;
+ b = bins[off + mVecLimbs13] ^ ((b & GF16Utils.NIBBLE_MASK_LSB) >>> 1) ^ ((t << 3) + t);
+
+ t = (a & GF16Utils.MASK_MSB) >>> 3;
+ a = bins[off + mVecLimbs4] ^ ((a & GF16Utils.NIBBLE_MASK_MSB) << 1) ^ ((t << 1) + t);
+
+ t = b & GF16Utils.MASK_LSB;
+ b = bins[off + mVecLimbs9] ^ ((b & GF16Utils.NIBBLE_MASK_LSB) >>> 1) ^ ((t << 3) + t);
+
+ t = (a & GF16Utils.MASK_MSB) >>> 3;
+ a = bins[off + mVecLimbs2] ^ ((a & GF16Utils.NIBBLE_MASK_MSB) << 1) ^ ((t << 1) + t);
+
+ t = b & GF16Utils.MASK_LSB;
+ b = bins[off + mVecLimbs] ^ ((b & GF16Utils.NIBBLE_MASK_LSB) >>> 1) ^ ((t << 3) + t);
+
+ t = (a & GF16Utils.MASK_MSB) >>> 3;
+ ps[(imVecLimbs4 >> 4) + j] = b ^ ((a & GF16Utils.NIBBLE_MASK_MSB) << 1) ^ ((t << 1) + t);
+ }
}
}
}
diff --git a/core/src/main/java/org/bouncycastle/util/Bytes.java b/core/src/main/java/org/bouncycastle/util/Bytes.java
index 4db85758a0..928cacd714 100644
--- a/core/src/main/java/org/bouncycastle/util/Bytes.java
+++ b/core/src/main/java/org/bouncycastle/util/Bytes.java
@@ -16,6 +16,14 @@ public static void xor(int len, byte[] x, byte[] y, byte[] z)
}
}
+ public static void xor(int len, byte[] x, int xOff, byte[] y, byte[] z, int zOff)
+ {
+ for (int i = 0; i < len; ++i)
+ {
+ z[zOff + i] = (byte)(x[xOff + i] ^ y[i]);
+ }
+ }
+
public static void xor(int len, byte[] x, int xOff, byte[] y, int yOff, byte[] z, int zOff)
{
for (int i = 0; i < len; ++i)
From 50f0914f65cf9f6567e1602c709078d992bffd5a Mon Sep 17 00:00:00 2001
From: gefeili
Date: Tue, 4 Mar 2025 15:53:34 +1030
Subject: [PATCH 147/890] Refactor of Mayo
---
.../pqc/crypto/mayo/GF16Utils.java | 77 ++++++----------
.../pqc/crypto/mayo/MayoKeyPairGenerator.java | 2 +-
.../pqc/crypto/mayo/MayoSigner.java | 90 +++++++++----------
.../bouncycastle/pqc/crypto/mayo/Utils.java | 25 +++---
4 files changed, 87 insertions(+), 107 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java
index cc2db8ba1d..d367c94109 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java
@@ -100,23 +100,19 @@ static void mulAddMUpperTriangularMatXMat(int mVecLimbs, long[] bsMat, byte[] ma
* each entry is an m-vector.
* @param matRows number of rows in the matrix “mat.”
* @param matCols number of columns in “mat.”
- * @param bsMatCols number of columns in the bsMat matrix.
*/
static void mulAddMatTransXMMat(int mVecLimbs, byte[] mat, long[] bsMat, int bsMatOff, long[] acc,
- int matRows, int matCols, int bsMatCols)
+ int matRows, int matCols)
{
- // Loop over each column r of mat (which becomes row of mat^T)
- for (int r = 0; r < matCols; r++)
+ int multiply = matCols * mVecLimbs;
+ for (int r = 0, rmultiply = 0; r < matCols; r++, rmultiply += multiply)
{
- for (int c = 0, cmatCols = 0; c < matRows; c++, cmatCols += matCols)
+ for (int c = 0, cmatCols = 0, cmultiply = 0; c < matRows; c++, cmatCols += matCols, cmultiply += multiply)
{
byte matVal = mat[cmatCols + r];
- for (int k = 0; k < bsMatCols; k++)
+ for (int k = 0, kmVecLimbs = 0; k < matCols; k++, kmVecLimbs += mVecLimbs)
{
- int bsMatOffset = bsMatOff + (c * bsMatCols + k) * mVecLimbs;
- // For acc: add into the m-vector at index (r * bsMatCols + k)
- int accOffset = (r * bsMatCols + k) * mVecLimbs;
- mVecMulAdd(mVecLimbs, bsMat, bsMatOffset, matVal, acc, accOffset);
+ mVecMulAdd(mVecLimbs, bsMat, bsMatOff + cmultiply + kmVecLimbs, matVal, acc, rmultiply + kmVecLimbs);
}
}
}
@@ -138,25 +134,19 @@ static void mulAddMatTransXMMat(int mVecLimbs, byte[] mat, long[] bsMat, int bsM
* @param acc the accumulator array (long[]) where results are accumulated
* @param matRows the number of rows in the matrix
* @param matCols the number of columns in the matrix
- * @param bsMatCols the number of columns in the bit‐sliced matrix (per block)
*/
- static void mulAddMatXMMat(int mVecLimbs, byte[] mat, long[] bsMat, long[] acc,
- int matRows, int matCols, int bsMatCols)
+ static void mulAddMatXMMat(int mVecLimbs, byte[] mat, long[] bsMat, long[] acc, int matRows, int matCols)
{
- for (int r = 0; r < matRows; r++)
+ int multiply = mVecLimbs * matRows;
+ for (int r = 0, rmatCols = 0, rmultiply = 0; r < matRows; r++, rmatCols += matCols, rmultiply += multiply)
{
- for (int c = 0; c < matCols; c++)
+ for (int c = 0, cmultiply = 0; c < matCols; c++, cmultiply += multiply)
{
// Retrieve the scalar from the matrix for row r and column c.
- byte matVal = mat[r * matCols + c];
- for (int k = 0; k < bsMatCols; k++)
+ byte matVal = mat[rmatCols + c];
+ for (int k = 0, kmVecLimbs = 0; k < matRows; k++, kmVecLimbs += mVecLimbs)
{
- // Compute the starting index for the vector in bsMat.
- int bsMatOffset = mVecLimbs * (c * bsMatCols + k);
- // Compute the starting index for the accumulator vector in acc.
- int accOffset = mVecLimbs * (r * bsMatCols + k);
- // Multiply the vector by the scalar and add the result to the accumulator.
- mVecMulAdd(mVecLimbs, bsMat, bsMatOffset, matVal, acc, accOffset);
+ mVecMulAdd(mVecLimbs, bsMat, cmultiply + kmVecLimbs, matVal, acc, rmultiply + kmVecLimbs);
}
}
}
@@ -165,20 +155,16 @@ static void mulAddMatXMMat(int mVecLimbs, byte[] mat, long[] bsMat, long[] acc,
static void mulAddMatXMMat(int mVecLimbs, byte[] mat, long[] bsMat, int bsMatOff, long[] acc,
int matRows, int matCols, int bsMatCols)
{
- for (int r = 0; r < matRows; r++)
+ int multiply = mVecLimbs * bsMatCols;
+ for (int r = 0, rmultiply = 0, rmatCols = 0; r < matRows; r++, rmultiply += multiply, rmatCols += matCols)
{
- for (int c = 0; c < matCols; c++)
+ for (int c = 0, cmultiply = 0; c < matCols; c++, cmultiply += multiply)
{
// Retrieve the scalar from the matrix for row r and column c.
- byte matVal = mat[r * matCols + c];
- for (int k = 0; k < bsMatCols; k++)
+ byte matVal = mat[rmatCols + c];
+ for (int k = 0, kmVecLimbs = 0; k < bsMatCols; k++, kmVecLimbs += mVecLimbs)
{
- // Compute the starting index for the vector in bsMat.
- int bsMatOffset = mVecLimbs * (c * bsMatCols + k) + bsMatOff;
- // Compute the starting index for the accumulator vector in acc.
- int accOffset = mVecLimbs * (r * bsMatCols + k);
- // Multiply the vector by the scalar and add the result to the accumulator.
- mVecMulAdd(mVecLimbs, bsMat, bsMatOffset, matVal, acc, accOffset);
+ mVecMulAdd(mVecLimbs, bsMat, cmultiply + kmVecLimbs + bsMatOff, matVal, acc, rmultiply + kmVecLimbs);
}
}
}
@@ -200,27 +186,22 @@ static void mulAddMatXMMat(int mVecLimbs, byte[] mat, long[] bsMat, int bsMatOff
* @param mat the matrix stored as a byte array.
* @param acc the accumulator array where the results are added.
* @param bsMatRows the number of rows in the bit‑sliced matrix.
- * @param bsMatCols the number of columns in the bit‑sliced matrix.
* @param matRows the number of rows in the matrix.
*/
- static void mulAddMUpperTriangularMatXMatTrans(int mVecLimbs, long[] bsMat, byte[] mat, long[] acc,
- int bsMatRows, int bsMatCols, int matRows)
+ static void mulAddMUpperTriangularMatXMatTrans(int mVecLimbs, long[] bsMat, byte[] mat, long[] acc, int bsMatRows, int matRows)
{
int bsMatEntriesUsed = 0;
- for (int r = 0; r < bsMatRows; r++)
+ int multiply = mVecLimbs * matRows;
+ for (int r = 0, rmultiply = 0; r < bsMatRows; r++, rmultiply += multiply)
{
// For upper triangular, start c at triangular * r; otherwise, triangular is zero.
- for (int c = r; c < bsMatCols; c++)
+ for (int c = r; c < bsMatRows; c++)
{
- for (int k = 0; k < matRows; k++)
+ for (int k = 0, kbsMatRows = 0, kmVecLimbs = 0; k < matRows; k++, kbsMatRows += bsMatRows, kmVecLimbs += mVecLimbs)
{
- int bsMatOffset = mVecLimbs * bsMatEntriesUsed;
- int accOffset = mVecLimbs * (r * matRows + k);
- // Get the matrix element at row k and column c
- byte matVal = mat[k * bsMatCols + c];
- mVecMulAdd(mVecLimbs, bsMat, bsMatOffset, matVal, acc, accOffset);
+ mVecMulAdd(mVecLimbs, bsMat, bsMatEntriesUsed, mat[kbsMatRows + c], acc, rmultiply + kmVecLimbs);
}
- bsMatEntriesUsed++;
+ bsMatEntriesUsed += mVecLimbs;
}
}
}
@@ -254,7 +235,7 @@ static byte inverseF(int a)
int a4 = mulF(a2, a2);
int a8 = mulF(a4, a4);
int a6 = mulF(a2, a4);
- return (byte) mulF(a8, a6);
+ return (byte)mulF(a8, a6);
}
/**
@@ -280,12 +261,12 @@ static long mulFx8(byte a, long b)
static void matMul(byte[] a, byte[] b, int bOff, byte[] c, int colrowAB, int rowA)
{
- for (int i = 0, aRowStart = 0, cOff = 0; i < rowA; i++, aRowStart += colrowAB)
+ for (int i = 0, aRowStart = 0, cOff = 0; i < rowA; i++)
{
byte result = 0;
for (int k = 0; k < colrowAB; k++)
{
- result ^= mulF(a[aRowStart + k], b[bOff + k]);
+ result ^= mulF(a[aRowStart++], b[bOff + k]);
}
c[cOff++] = result;
}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
index af6e96100c..56fdd1fa35 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
@@ -75,7 +75,7 @@ public AsymmetricCipherKeyPair generateKeyPair()
// Here, treat P2 as the bsMat for the multiplication.
// Dimensions: mat = O (size: paramV x paramO), bsMat = P2 (size: paramV x paramO),
// and acc (P3) will have dimensions: (paramO x paramO), each entry being an m-vector.
- GF16Utils.mulAddMatTransXMMat(mVecLimbs, O, P, p1Limbs, P3, v, o, o);
+ GF16Utils.mulAddMatTransXMMat(mVecLimbs, O, P, p1Limbs, P3, v, o);
// Store seed_pk into the public key cpk.
System.arraycopy(seed_pk, 0, cpk, 0, pkSeedBytes);
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
index 7a5cbcb109..2e6fd8c96d 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
@@ -71,15 +71,16 @@ public byte[] generateSignature(byte[] message)
byte[] salt = new byte[saltBytes];
byte[] V = new byte[k * vbytes + params.getRBytes()];
byte[] Vdec = new byte[v * k];
- byte[] A = new byte[((params.getM() + 7) / 8 * 8) * (k * o + 1)];
+ int ok = k * o;
+ byte[] A = new byte[((params.getM() + 7) / 8 * 8) * (ok + 1)];
byte[] x = new byte[k * n];
- byte[] r = new byte[k * o + 1];
+ byte[] r = new byte[ok + 1];
byte[] s = new byte[k * n];
byte[] tmp = new byte[digestBytes + saltBytes + skSeedBytes + 1];
byte[] sig = new byte[params.getSigBytes()];
long[] P = new long[p1Limbs + params.getP2Limbs()];
byte[] O = new byte[v * o];
- long[] Mtmp = new long[k * o * mVecLimbs];
+ long[] Mtmp = new long[ok * mVecLimbs];
long[] vPv = new long[k * k * mVecLimbs];
SHAKEDigest shake = new SHAKEDigest(256);
try
@@ -150,7 +151,8 @@ public byte[] generateSignature(byte[] message)
shake.update(tmp, 0, digestBytes + saltBytes);
shake.doFinal(tenc, 0, params.getMBytes());
Utils.decode(tenc, t, params.getM());
-
+ int size = v * k * mVecLimbs;
+ long[] Pv = new long[size];
for (int ctr = 0; ctr <= 255; ctr++)
{
tmp[tmp.length - 1] = (byte)ctr;
@@ -171,13 +173,10 @@ public byte[] generateSignature(byte[] message)
// Compute VP1V:
// Allocate temporary array for Pv. Its length is V_MAX * K_MAX * M_VEC_LIMBS_MAX.
- int size = v * k * mVecLimbs;
- long[] Pv = new long[size]; // automatically initialized to zero in Java
-
// Compute Pv = P1 * V^T (using upper triangular multiplication)
- GF16Utils.mulAddMUpperTriangularMatXMatTrans(mVecLimbs, P, Vdec, Pv, v, v, k);
+ GF16Utils.mulAddMUpperTriangularMatXMatTrans(mVecLimbs, P, Vdec, Pv, v, k);
// Compute VP1V = Vdec * Pv
- GF16Utils.mulAddMatXMMat(mVecLimbs, Vdec, Pv, vPv, k, v, k);
+ GF16Utils.mulAddMatXMMat(mVecLimbs, Vdec, Pv, vPv, k, v);
computeRHS(vPv, t, y);
computeA(Mtmp, A);
@@ -185,10 +184,10 @@ public byte[] generateSignature(byte[] message)
// Clear trailing bytes
// for (int i = 0; i < params.getM(); ++i)
// {
-// A[(i + 1) * (k * o + 1) - 1] = 0;
+// A[(i + 1) * (ok + 1) - 1] = 0;
// }
- Utils.decode(V, k * vbytes, r, 0, k * o);
+ Utils.decode(V, k * vbytes, r, 0, ok);
if (sampleSolution(params, A, y, r, x))
{
@@ -304,19 +303,21 @@ void computeRHS(long[] vPv, byte[] t, byte[] y)
mask -= 1;
final int kSquared = k * k;
- for (int i = 0; i < kSquared; i++)
+ for (int i = 0, index = mVecLimbs - 1; i < kSquared; i++, index += mVecLimbs)
{
- int index = i * mVecLimbs + mVecLimbs - 1;
vPv[index] &= mask;
}
}
long[] temp = new long[mVecLimbs];
byte[] tempBytes = new byte[mVecLimbs << 3];
+ int kmVecLimbs = k * mVecLimbs;
- for (int i = k - 1; i >= 0; i--)
+ for (int i = k - 1, imVecLimbs = i * mVecLimbs, ikmVecLimbs = imVecLimbs * k; i >= 0; i--,
+ imVecLimbs -= mVecLimbs, ikmVecLimbs -= kmVecLimbs)
{
- for (int j = i; j < k; j++)
+ for (int j = i, jmVecLimbs = imVecLimbs, jkmVecLimbs = ikmVecLimbs; j < k; j++,
+ jmVecLimbs += mVecLimbs, jkmVecLimbs += kmVecLimbs)
{
// Multiply by X (shift up 4 bits)
int top = (int)((temp[mVecLimbs - 1] >>> topPos) & 0xF);
@@ -351,8 +352,8 @@ void computeRHS(long[] vPv, byte[] t, byte[] y)
Pack.littleEndianToLong(tempBytes, 0, temp);
// Extract from vPv and add
- int matrixIndex = (i * k + j) * mVecLimbs;
- int symmetricIndex = (j * k + i) * mVecLimbs;
+ int matrixIndex = ikmVecLimbs + jmVecLimbs;
+ int symmetricIndex = jkmVecLimbs + imVecLimbs;
boolean isDiagonal = (i == j);
for (int limb = 0; limb < mVecLimbs; limb++)
@@ -393,6 +394,7 @@ void computeA(long[] Mtmp, byte[] AOut)
int wordsToShift = 0;
final int MAYO_M_OVER_8 = (m + 7) >>> 3;
int ok = o * k;
+ int omVecLimbs = o * mVecLimbs;
final int AWidth = ((ok + 15) >> 4) << 4;
long[] A = new long[(AWidth * MAYO_M_OVER_8) << 4];
@@ -407,20 +409,18 @@ void computeA(long[] Mtmp, byte[] AOut)
}
}
- for (int i = 0; i < k; i++)
+ for (int i = 0, io = 0; i < k; i++, io += o)
{
- for (int j = k - 1; j >= i; j--)
+ for (int j = k - 1, jomVecLimbs = j * omVecLimbs, jo = j * o; j >= i; j--, jomVecLimbs -= omVecLimbs, jo -= o)
{
// Process Mj
- int mjOffset = j * mVecLimbs * o;
- for (int c = 0; c < o; c++)
+ for (int c = 0, cmVecLimbs = 0; c < o; c++, cmVecLimbs += mVecLimbs)
{
- for (int limb = 0; limb < mVecLimbs; limb++)
+ for (int limb = 0, limbAWidhth = 0; limb < mVecLimbs; limb++, limbAWidhth += AWidth)
{
- int idx = mjOffset + limb + c * mVecLimbs;
- long value = Mtmp[idx];
+ long value = Mtmp[jomVecLimbs + limb + cmVecLimbs];
- int aIndex = o * i + c + (limb + wordsToShift) * AWidth;
+ int aIndex = io + c + wordsToShift + limbAWidhth;
A[aIndex] ^= value << bitsToShift;
if (bitsToShift > 0)
@@ -434,14 +434,13 @@ void computeA(long[] Mtmp, byte[] AOut)
{
// Process Mi
int miOffset = i * mVecLimbs * o;
- for (int c = 0; c < o; c++)
+ for (int c = 0, cmVecLimbs = 0; c < o; c++, cmVecLimbs += mVecLimbs)
{
- for (int limb = 0; limb < mVecLimbs; limb++)
+ for (int limb = 0, limbAWidhth = 0; limb < mVecLimbs; limb++, limbAWidhth += AWidth)
{
- int idx = miOffset + limb + c * mVecLimbs;
- long value = Mtmp[idx];
+ long value = Mtmp[miOffset + limb + cmVecLimbs];
- int aIndex = o * j + c + (limb + wordsToShift) * AWidth;
+ int aIndex = jo + c + wordsToShift + limbAWidhth;
A[aIndex] ^= value << bitsToShift;
if (bitsToShift > 0)
@@ -455,14 +454,14 @@ void computeA(long[] Mtmp, byte[] AOut)
bitsToShift += 4;
if (bitsToShift == 64)
{
- wordsToShift++;
+ wordsToShift += AWidth;
bitsToShift = 0;
}
}
}
// Transpose blocks
- for (int c = 0; c < AWidth * ((m + (k + 1) * k / 2 + 15) / 16); c += 16)
+ for (int c = 0; c < AWidth * ((m + (k + 1) * k / 2 + 15) >>> 4); c += 16)
{
transpose16x16Nibbles(A, c);
}
@@ -481,7 +480,7 @@ void computeA(long[] Mtmp, byte[] AOut)
// Final processing
for (int c = 0; c < AWidth; c += 16)
{
- for (int r = m; r < m + (k + 1) * k / 2; r++)
+ for (int r = m; r < m + (((k + 1) * k) >>> 1); r++)
{
int pos = (r >>> 4) * AWidth + c + (r & 15);
long t0 = A[pos] & GF16Utils.MASK_LSB;
@@ -562,9 +561,9 @@ boolean sampleSolution(MayoParameters params, byte[] A, byte[] y,
final int o = params.getO();
final int m = params.getM();
final int aCols = params.getACols();
-
+ int ok = k * o;
// Initialize x with r values
- System.arraycopy(r, 0, x, 0, k * o);
+ System.arraycopy(r, 0, x, 0, ok);
// Compute Ar matrix product
byte[] Ar = new byte[m];
@@ -572,14 +571,14 @@ boolean sampleSolution(MayoParameters params, byte[] A, byte[] y,
// Clear last column of A
// for (int i = 0; i < m; i++)
// {
-// A[k * o + i * (k * o + 1)] = 0;
+// A[ok + i * (ok + 1)] = 0;
// }
- GF16Utils.matMul(A, r, 0, Ar, k * o + 1, m);
+ GF16Utils.matMul(A, r, 0, Ar, ok + 1, m);
// Update last column of A with y - Ar
for (int i = 0; i < m; i++)
{
- A[k * o + i * (k * o + 1)] = (byte)(y[i] ^ Ar[i]);
+ A[ok + i * (ok + 1)] = (byte)(y[i] ^ Ar[i]);
}
// Perform row echelon form transformation
@@ -597,18 +596,17 @@ boolean sampleSolution(MayoParameters params, byte[] A, byte[] y,
}
// Constant-time back substitution
- for (int row = m - 1; row >= 0; row--)
+ for (int row = m - 1, rowAcols = row * aCols; row >= 0; row--, rowAcols -= aCols)
{
byte finished = 0;
- int colUpperBound = Math.min(row + (32 / (m - row)), k * o);
+ int colUpperBound = Math.min(row + (32 / (m - row)), ok);
for (int col = row; col <= colUpperBound; col++)
{
- byte correctCol = (byte)((-(A[row * aCols + col] & 0xFF)) >> 31);
+ byte correctCol = (byte)((-(A[rowAcols + col] & 0xFF)) >> 31);
// Update x[col] using constant-time mask
- byte u = (byte)(correctCol & ~finished & A[row * aCols + aCols - 1]);
- //System.out.println("x[col]: " + x[col] + ", u: " + u);
+ byte u = (byte)(correctCol & ~finished & A[rowAcols + aCols - 1]);
x[col] ^= u;
@@ -661,7 +659,7 @@ void ef(byte[] A, int nrows, int ncols)
int len_4 = len >> 4;
// Pack the matrix rows.
- for (int i = 0, incols = 0; i < nrows; i++, incols += ncols)
+ for (int i = 0, incols = 0, irowLen = 0; i < nrows; i++, incols += ncols, irowLen += rowLen)
{
//packRow(A, i, ncols);
// Process each 64-bit word (each holds 16 nibbles).
@@ -676,7 +674,7 @@ void ef(byte[] A, int nrows, int ncols)
wordVal |= ((long)A[incols + col] & 0xF) << (nibble << 2);
}
}
- packedA[word + i * rowLen] = wordVal;
+ packedA[word + irowLen] = wordVal;
}
}
@@ -710,7 +708,7 @@ void ef(byte[] A, int nrows, int ncols)
}
// Extract candidate pivot element from the packed row.
pivot = (int)((pivotRow[pivotCol >>> 4] >>> ((pivotCol & 15) << 2)) & 0xF);
- pivotIsZero = ~ctCompare64(pivot, 0);
+ pivotIsZero = ~((-(long)pivot) >> 63);
}
// Multiply the pivot row by the inverse of the pivot element.
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/Utils.java
index e48d019cda..8d9b1ef47b 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/Utils.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/Utils.java
@@ -24,13 +24,14 @@ public static void decode(byte[] m, byte[] mdec, int mdecLen)
{
int i;
int decIndex = 0;
+ int blocks = mdecLen >> 1;
// Process pairs of nibbles from each byte
- for (i = 0; i < mdecLen / 2; i++)
+ for (i = 0; i < blocks; i++)
{
// Extract the lower nibble
- mdec[decIndex++] = (byte)((m[i] & 0xFF) & 0x0F);
+ mdec[decIndex++] = (byte)(m[i] & 0x0F);
// Extract the upper nibble (shift right 4 bits)
- mdec[decIndex++] = (byte)(((m[i] & 0xFF) >> 4) & 0x0F);
+ mdec[decIndex++] = (byte)((m[i] >> 4) & 0x0F);
}
// If there is an extra nibble (odd number of nibbles), decode only the lower nibble
if (mdecLen % 2 == 1)
@@ -41,19 +42,19 @@ public static void decode(byte[] m, byte[] mdec, int mdecLen)
public static void decode(byte[] m, int mOff, byte[] mdec, int decIndex, int mdecLen)
{
- int i;
// Process pairs of nibbles from each byte
- for (i = 0; i < mdecLen / 2; i++)
+ int blocks = mdecLen >> 1;
+ for (int i = 0; i < blocks; i++)
{
// Extract the lower nibble
- mdec[decIndex++] = (byte)(m[i + mOff] & 0x0F);
+ mdec[decIndex++] = (byte)(m[mOff] & 0x0F);
// Extract the upper nibble (shift right 4 bits)
- mdec[decIndex++] = (byte)((m[i + mOff] >> 4) & 0x0F);
+ mdec[decIndex++] = (byte)((m[mOff++] >> 4) & 0x0F);
}
// If there is an extra nibble (odd number of nibbles), decode only the lower nibble
if (mdecLen % 2 == 1)
{
- mdec[decIndex] = (byte)(m[i + mOff] & 0x0F);
+ mdec[decIndex] = (byte)(m[mOff] & 0x0F);
}
}
@@ -68,15 +69,15 @@ public static void decode(byte[] m, int mOff, byte[] mdec, int decIndex, int mde
public static void decode(byte[] input, int inputOffset, byte[] output, int mdecLen)
{
int decIndex = 0;
- int blocks = mdecLen / 2;
+ int blocks = mdecLen >> 1;
for (int i = 0; i < blocks; i++)
{
- output[decIndex++] = (byte)(input[inputOffset + i] & 0x0F);
- output[decIndex++] = (byte)((input[inputOffset + i] >> 4) & 0x0F);
+ output[decIndex++] = (byte)(input[inputOffset] & 0x0F);
+ output[decIndex++] = (byte)((input[inputOffset++] >> 4) & 0x0F);
}
if (mdecLen % 2 == 1)
{
- output[decIndex] = (byte)(input[inputOffset + blocks] & 0x0F);
+ output[decIndex] = (byte)(input[inputOffset] & 0x0F);
}
}
From fa20a568aeb0318b180a24c0ad41b9b442bce908 Mon Sep 17 00:00:00 2001
From: Jill Kleiber
Date: Thu, 16 Jan 2025 11:58:44 +0100
Subject: [PATCH 148/890] added support for rfc9579 (PBMAC1 with PBKDF2) to
PKCS12KeyStoreSpi
---
.../keystore/pkcs12/PKCS12KeyStoreSpi.java | 56 +++
.../jce/provider/test/PKCS12StoreTest.java | 402 ++++++++++++++++++
2 files changed, 458 insertions(+)
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
index ebbd568a5c..219efb6d8d 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
@@ -76,6 +76,7 @@
import org.bouncycastle.asn1.pkcs.KeyDerivationFunc;
import org.bouncycastle.asn1.pkcs.MacData;
import org.bouncycastle.asn1.pkcs.PBES2Parameters;
+import org.bouncycastle.asn1.pkcs.PBMAC1Params;
import org.bouncycastle.asn1.pkcs.PBKDF2Params;
import org.bouncycastle.asn1.pkcs.PKCS12PBEParams;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
@@ -93,8 +94,14 @@
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x509.TBSCertificate;
import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.PBEParametersGenerator;
+import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.digests.SHA512Digest;
+import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator;
+import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.util.DigestFactory;
import org.bouncycastle.internal.asn1.cms.GCMParameters;
import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
@@ -2041,6 +2048,39 @@ private byte[] calculatePbeMac(
byte[] data)
throws Exception
{
+ if (PKCSObjectIdentifiers.id_PBMAC1.equals(oid))
+ {
+ PBMAC1Params pbmac1Params = PBMAC1Params.getInstance(macAlgorithm.getParameters());
+ if (pbmac1Params == null)
+ {
+ throw new IOException("If the DigestAlgorithmIdentifier is id-PBMAC1, then the parameters field must contain valid PBMAC1-params parameters.");
+ }
+ if (PKCSObjectIdentifiers.id_PBKDF2.equals(pbmac1Params.getKeyDerivationFunc().getAlgorithm()))
+ {
+ PBKDF2Params pbkdf2Params = PBKDF2Params.getInstance(pbmac1Params.getKeyDerivationFunc().getParameters());
+ if (pbkdf2Params.getKeyLength() == null)
+ {
+ throw new IOException("Key length must be present when using PBMAC1.");
+ }
+ final HMac hMac = new HMac(getPrf(pbmac1Params.getMessageAuthScheme().getAlgorithm()));
+
+ PBEParametersGenerator generator = new PKCS5S2ParametersGenerator(getPrf(pbkdf2Params.getPrf().getAlgorithm()));
+
+ generator.init(
+ Strings.toUTF8ByteArray(password),
+ pbkdf2Params.getSalt(),
+ BigIntegers.intValueExact(pbkdf2Params.getIterationCount()));
+
+ CipherParameters key = generator.generateDerivedParameters(BigIntegers.intValueExact(pbkdf2Params.getKeyLength()) * 8);
+
+ hMac.init(key);
+ hMac.update(data, 0, data.length);
+ byte[] res = new byte[hMac.getMacSize()];
+ hMac.doFinal(res, 0);
+ return res;
+ }
+ }
+
PBEParameterSpec defParams = new PBEParameterSpec(salt, itCount);
Mac mac = helper.createMac(oid.getId());
@@ -2050,6 +2090,22 @@ private byte[] calculatePbeMac(
return mac.doFinal();
}
+ private static Digest getPrf(ASN1ObjectIdentifier prfId)
+ {
+ if (PKCSObjectIdentifiers.id_hmacWithSHA256.equals(prfId))
+ {
+ return new SHA256Digest();
+ }
+ else if (PKCSObjectIdentifiers.id_hmacWithSHA512.equals(prfId))
+ {
+ return new SHA512Digest();
+ }
+ else
+ {
+ throw new IllegalArgumentException("unknown prf id " + prfId);
+ }
+ }
+
public static class BCPKCS12KeyStore
extends AdaptingKeyStoreSpi
{
diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/PKCS12StoreTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/PKCS12StoreTest.java
index 0ebbcdb104..9011fee6f7 100644
--- a/prov/src/test/java/org/bouncycastle/jce/provider/test/PKCS12StoreTest.java
+++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/PKCS12StoreTest.java
@@ -943,6 +943,361 @@ public class PKCS12StoreTest
private static byte[] rawKeyBagStore = Base64.decode("MIIFlgIBAzCCBY8GCSqGSIb3DQEHAaCCBYAEggV8MIIFeDCCAv4GCSqGSIb3DQEHAaCCAu8EggLrMIIC5zCCAuMGCyqGSIb3DQEMCgEBoIICejCCAnYCAQAwDQYJKoZIhvcNAQEBBQAEggJgMIICXAIBAAKBgQCF4Tw78b8eDuwY+FomQazkPFuAxDbWTs//AozC4MvzBatdJeDu+s9WyK3PdU+gI7wFish0r2FP8M5dj/rA0ieCJ9UDTGWVKm06DB0y7zmAO3SS/3TXGQRekMmOXBtVlZa4AYVy8Tr+Ls69gfo3sgqJU8uH0ebWuoQTKJz/mpst0wIDAQABAoGBAIJbpu/jWylkdEV4BSd9CWCO2LYP2CliQirXC8JxaoTuf0ZKrLNlqd+htYPsgSS3xstKsBbV8hYJrpbxq8J2npok973j0bm9sW9RL8XmAYJbaat27IzQQkGj2j4CNWPJzQC3NsDWQJPMJMFHvT1ZIj5ASwvOHwKpM6haLPxX24o5AkEA/zBVPpO6Ic9Yfd8Fk+BN/DykpPbLMUNZFl/I2MavoXTh5Ng7J4/S5ABxkvvQdqKf1Nhal5CznakU4BjFUGr+dwJBAIZOLwlfToFgekV4SmcPnq4aNGdetDfEettRGJLrKf+qrZrTzW3Rj6N2cjxKHsE5/xOpyjOtgVv3cTQm0x//VoUCQAdQBUFTzmOlo22H9Ir2RIXT3wvzHoN84JKpkAHWP7YquUZrg9ZwYqSx9o81tBWSN25L/NyXAu6jp7t8OjtBtaUCQCILB1k0001wCw4444MkLnCrK8VX+A56uzmEYNo8ybSIquCn91Zy3BnvGB24G/uWm9V8IEjhHf0Vx5gUj0d5DZECQGRs4BMYE+y2Tpn7/zbjhZh/iAdttDq5/b2BBMbSiosSKRIGkOyHTu0SJKoxoDnHA5ryLK8NoSwoGjID5qESjA8xVjAjBgkqhkiG9w0BCRUxFgQU3U3Taaj7rCAV2GyyVEnAUZvc4JkwLwYJKoZIhvcNAQkUMSIeIABPAE4AVgBJAEYAXwBUAGUAcwB0AF8AQQBsAGkAYQBzMIICcgYJKoZIhvcNAQcBoIICYwSCAl8wggJbMIICVwYLKoZIhvcNAQwKAQOgggHuMIIB6gYKKoZIhvcNAQkWAaCCAdoEggHWMIIB0jCCATugAwIBAgIICNurBKCCK6gwDQYJKoZIhvcNAQEFBQAwIDERMA8GA1UEAwwIT05WSUYgVFQxCzAJBgNVBAYTAlVTMCAXDTcwMDEwMTAwMDAwMFoYDzk5OTkxMjMxMjM1OTU5WjAgMREwDwYDVQQDDAhPTlZJRiBUVDELMAkGA1UEBhMCVVMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAIXhPDvxvx4O7Bj4WiZBrOQ8W4DENtZOz/8CjMLgy/MFq10l4O76z1bIrc91T6AjvAWKyHSvYU/wzl2P+sDSJ4In1QNMZZUqbToMHTLvOYA7dJL/dNcZBF6QyY5cG1WVlrgBhXLxOv4uzr2B+jeyColTy4fR5ta6hBMonP+amy3TAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEARmnQ9q/lUycK5P4shGFlwK0Uy3dHZs4VxOBSinejSTTy1FL4+SRzwA+YDMmfRrI0WHY/upUCYyugDj5kDg5K6/mSiIWGr0PDjl+8qw352fpUQgY4vnpGBaJoLQf/KRFilVhZJz0QDq5iHo16UkibDDHYQqdt6la5SHKx4U6AJwYxVjAjBgkqhkiG9w0BCRUxFgQU3U3Taaj7rCAV2GyyVEnAUZvc4JkwLwYJKoZIhvcNAQkUMSIeIABPAE4AVgBJAEYAXwBUAGUAcwB0AF8AQQBsAGkAYQBz");
+ // Valid PKCS #12 File with SHA-256 HMAC and PRF
+ private static final byte[] pkcs12WithPBMac1PBKdf2_a1 = Base64.decode(
+ "MIIKigIBAzCCCgUGCSqGSIb3DQEHAaCCCfYEggnyMIIJ7jCCBGIGCSqGSIb3DQEH\n" +
+ "BqCCBFMwggRPAgEAMIIESAYJKoZIhvcNAQcBMFcGCSqGSIb3DQEFDTBKMCkGCSqG\n" +
+ "SIb3DQEFDDAcBAg9pxXxY2yscwICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQME\n" +
+ "ASoEEK7yYaFQDi1pYwWzm9F/fs+AggPgFIT2XapyaFgDppdvLkdvaF3HXw+zjzKb\n" +
+ "7xFC76DtVPhVTWVHD+kIss+jsj+XyvMwY0aCuAhAG/Dig+vzWomnsqB5ssw5/kTb\n" +
+ "+TMQ5PXLkNeoBmB6ArKeGc/QmCBQvQG/a6b+nXSWmxNpP+71772dmWmB8gcSJ0kF\n" +
+ "Fj75NrIbmNiDMCb71Q8gOzBMFf6BpXf/3xWAJtxyic+tSNETfOJa8zTZb0+lV0w9\n" +
+ "5eUmDrPUpuxEVbb0KJtIc63gRkcfrPtDd6Ii4Zzbzj2Evr4/S4hnrQBsiryVzJWy\n" +
+ "IEjaD0y6+DmG0JwMgRuGi1wBoGowi37GMrDCOyOZWC4n5wHLtYyhR6JaElxbrhxP\n" +
+ "H46z2USLKmZoF+YgEQgYcSBXMgP0t36+XQocFWYi2N5niy02TnctwF430FYsQlhJ\n" +
+ "Suma4I33E808dJuMv8T/soF66HsD4Zj46hOf4nWmas7IaoSAbGKXgIa7KhGRJvij\n" +
+ "xM3WOX0aqNi/8bhnxSA7fCmIy/7opyx5UYJFWGBSmHP1pBHBVmx7Ad8SAsB9MSsh\n" +
+ "nbGjGiUk4h0QcOi29/M9WwFlo4urePyI8PK2qtVAmpD3rTLlsmgzguZ69L0Q/CFU\n" +
+ "fbtqsMF0bgEuh8cfivd1DYFABEt1gypuwCUtCqQ7AXK2nQqOjsQCxVz9i9K8NDeD\n" +
+ "aau98VAl0To2sk3/VR/QUq0PRwU1jPN5BzUevhE7SOy/ImuJKwpGqqFljYdrQmj5\n" +
+ "jDe+LmYH9QGVRlfN8zuU+48FY8CAoeBeHn5AAPml0PYPVUnt3/jQN1+v+CahNVI+\n" +
+ "La8q1Nen+j1R44aa2I3y/pUgtzXRwK+tPrxTQbG030EU51LYJn8amPWmn3w75ZIA\n" +
+ "MJrXWeKj44de7u4zdUsEBVC2uM44rIHM8MFjyYAwYsey0rcp0emsaxzar+7ZA67r\n" +
+ "lDoXvvS3NqsnTXHcn3T9tkPRoee6L7Dh3x4Od96lcRwgdYT5BwyH7e34ld4VTUmJ\n" +
+ "bDEq7Ijvn4JKrwQJh1RCC+Z/ObfkC42xAm7G010u3g08xB0Qujpdg4a7VcuWrywF\n" +
+ "c7hLNquuaF4qoDaVwYXHH3iuX6YlJ/3siTKbYCVXPEZOAMBP9lF/OU76UMJBQNfU\n" +
+ "0xjDx+3AhUVgnGuCsmYlK6ETDp8qOZKGyV0KrNSGtqLx3uMhd7PETeW+ML3tDQ/0\n" +
+ "X9fMkcZHi4C2fXnoHV/qa2dGhBj4jjQ0Xh1poU6mxGn2Mebe2hDsBZkkBpnn7pK4\n" +
+ "wP/VqXdQTwqEuvzGHLVFsCuADe40ZFBmtBrf70wG7ZkO8SUZ8Zz1IX3+S024g7yj\n" +
+ "QRev/6x6TtkwggWEBgkqhkiG9w0BBwGgggV1BIIFcTCCBW0wggVpBgsqhkiG9w0B\n" +
+ "DAoBAqCCBTEwggUtMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAhTxzw+\n" +
+ "VptrYAICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEK9nSqc1I2t4tMVG\n" +
+ "bWHpdtQEggTQzCwI7j34gCTvfj6nuOSndAjShGv7mN2j7WMV0pslTpq2b9Bn3vn1\n" +
+ "Y0JMvL4E7sLrUzNU02pdOcfCnEpMFccNv2sQrLp1mOCKxu8OjSqHZLoKVL0ROVsZ\n" +
+ "8dMECLLigDlPKRiSyLErl14tErX4/zbkUaWMROO28kFbTbubQ8YoHlRUwsKW1xLg\n" +
+ "vfi0gRkG/zHXRfQHjX/8NStv7hXlehn7/Gy2EKPsRFhadm/iUHAfmCMkMgHTU248\n" +
+ "JER9+nsXltd59H+IeDpj/kbxZ+YvHow9XUZKu828d3MQnUpLZ1BfJGhMBPVwbVUD\n" +
+ "A40CiQBVdCoGtPJyalL28xoS3H0ILFCnwQOr6u0HwleNJPGHq78HUyH6Hwxnh0b0\n" +
+ "5o163r6wTFZn5cMOxpbs/Ttd+3TrxmrYpd2XnuRme3cnaYJ0ILvpc/8eLLR7SKjD\n" +
+ "T4JhZ0h/CfcV2WWvhpQugkY0pWrZ+EIMneB1dZB96mJVLxOi148OeSgi0PsxZMNi\n" +
+ "YM33rTpwQT5WqOsEyDwUQpne5b8Kkt/s7EN0LJNnPyJJRL1LcqOdr6j+6YqRtPa7\n" +
+ "a9oWJqMcuTP+bqzGRJh+3HDlFBw2Yzp9iadv4KmB2MzhStLUoi2MSjvnnkkd5Led\n" +
+ "sshAd6WbKfF7kLAHQHT4Ai6dMEO4EKkEVF9JBtxCR4JEn6C98Lpg+Lk+rfY7gHOf\n" +
+ "ZxtgGURwgXRY3aLUrdT55ZKgk3ExVKPzi5EhdpAau7JKhpOwyKozAp/OKWMNrz6h\n" +
+ "obu2Mbn1B+IA60psYHHxynBgsJHv7WQmbYh8HyGfHgVvaA8pZCYqxxjpLjSJrR8B\n" +
+ "Bu9H9xkTh7KlhxgreXYv19uAYbUd95kcox9izad6VPnovgFSb+Omdy6PJACPj6hF\n" +
+ "W6PJbucP0YPpO0VtWtQdZZ3df1P0hZ7qvKwOPFA+gKZSckgqASfygiP9V3Zc8jIi\n" +
+ "wjNzoDM2QT+UUJKiiGYXJUEOO9hxzFHlGj759DcNRhpgl5AgR57ofISD9yBuCAJY\n" +
+ "PQ/aZHPFuRTrcVG3RaIbCAS73nEznKyFaLOXfzyfyaSmyhsH253tnyL1MejC+2bR\n" +
+ "Eko/yldgFUxvU5JI+Q3KJ6Awj+PnduHXx71E4UwSuu2xXYMpxnQwI6rroQpZBX82\n" +
+ "HhqgcLV83P8lpzQwPdHjH5zkoxmWdC0+jU/tcQfNXYpJdyoaX7tDmVclLhwl9ps/\n" +
+ "O841pIsNLJWXwvxG6B+3LN/kw4QjwN194PopiOD7+oDm5mhttO78CrBrRxHMD/0Q\n" +
+ "qniZjKzSZepxlZq+J792u8vtMnuzzChxu0Bf3PhIXcJNcVhwUtr0yKe/N+NvC0tm\n" +
+ "p8wyik/BlndxN9eKbdTOi2wIi64h2QG8nOk66wQ/PSIJYwZl6eDNEQSzH/1mGCfU\n" +
+ "QnUT17UC/p+Qgenf6Auap2GWlvsJrB7u/pytz65rtjt/ouo6Ih6EwWqwVVpGXZD0\n" +
+ "7gVWH0Ke/Vr6aPGNvkLcmftPuDZsn9jiig3guhdeyRVf10Ox369kKWcG75q77hxE\n" +
+ "IzSzDyUlBNbnom9SIjut3r+qVYmWONatC6q/4D0I42Lnjd3dEyZx7jmH3g/S2ASM\n" +
+ "FzWr9pvXc61dsYOkdZ4PYa9XPUZxXFagZsoS3F1sU799+IJVU0tC0MExJTAjBgkq\n" +
+ "hkiG9w0BCRUxFgQUwWO5DorvVWYF3BWUmAw0rUEajScwfDBtMEkGCSqGSIb3DQEF\n" +
+ "DjA8MCwGCSqGSIb3DQEFDDAfBAhvRzw4sC4xcwICCAACASAwDAYIKoZIhvcNAgkF\n" +
+ "ADAMBggqhkiG9w0CCQUABCB6pW2FOdcCNj87zS64NUXG36K5aXDnFHctIk5Bf4kG\n" +
+ "3QQITk9UIFVTRUQCAQE=\n");
+
+ // Valid PKCS #12 File with SHA-256 HMAC and SHA-512 PRF
+ private static final byte[] pkcs12WithPBMac1PBKdf2_a2 = Base64.decode("MIIKigIBAzCCCgUGCSqGSIb3DQEHAaCCCfYEggnyMIIJ7jCCBGIGCSqGSIb3DQEH\n" +
+ "BqCCBFMwggRPAgEAMIIESAYJKoZIhvcNAQcBMFcGCSqGSIb3DQEFDTBKMCkGCSqG\n" +
+ "SIb3DQEFDDAcBAi4j6UBBY2iOgICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQME\n" +
+ "ASoEEFpHSS5zrk/9pkDo1JRbtE6AggPgtbMLGoFd5KLpVXMdcxLrT129L7/vCr0B\n" +
+ "0I2tnhPPA7aFtRjjuGbwooCMQwxw9qzuCX1eH4xK2LUw6Gbd2H47WimSOWJMaiUb\n" +
+ "wy4alIWELYufe74kXPmKPCyH92lN1hqu8s0EGhIl7nBhWbFzow1+qpIc9/lpujJo\n" +
+ "wodSY+pNBD8oBeoU1m6DgOjgc62apL7m0nwavDUqEt7HAqtTBxKxu/3lpb1q8nbl\n" +
+ "XLTqROax5feXErf+GQAqs24hUJIPg3O1eCMDVzH0h5pgZyRN9ZSIP0HC1i+d1lnb\n" +
+ "JwHyrAhZv8GMdAVKaXHETbq8zTpxT3UE/LmH1gyZGOG2B21D2dvNDKa712sHOS/t\n" +
+ "3XkFngHDLx+a9pVftt6p7Nh6jqI581tb7fyc7HBV9VUc/+xGgPgHZouaZw+I3PUz\n" +
+ "fjHboyLQer22ndBz+l1/S2GhhZ4xLXg4l0ozkgn7DX92S/UlbmcZam1apjGwkGY/\n" +
+ "7ktA8BarNW211mJF+Z+hci+BeDiM7eyEguLCYRdH+/UBiUuYjG1hi5Ki3+42pRZD\n" +
+ "FZkTHGOrcG6qE2KJDsENj+RkGiylG98v7flm4iWFVAB78AlAogT38Bod40evR7Ok\n" +
+ "c48sOIW05eCH/GLSO0MHKcttYUQNMqIDiG1TLzP1czFghhG97AxiTzYkKLx2cYfs\n" +
+ "pgg5PE9drq1fNzBZMUmC2bSwRhGRb5PDu6meD8uqvjxoIIZQAEV53xmD63umlUH1\n" +
+ "jhVXfcWSmhU/+vV/IWStZgQbwhF7DmH2q6S8itCkz7J7Byp5xcDiUOZ5Gpf9RJnk\n" +
+ "DTZoOYM5iA8kte6KCwA+jnmCgstI5EbRbnsNcjNvAT3q/X776VdmnehW0VeL+6k4\n" +
+ "z+GvQkr+D2sxPpldIb5hrb+1rcp9nOQgtpBnbXaT16Lc1HdTNe5kx4ScujXOWwfd\n" +
+ "Iy6bR6H0QFq2SLKAAC0qw4E8h1j3WPxll9e0FXNtoRKdsRuX3jzyqDBrQ6oGskkL\n" +
+ "wnyMtVjSX+3c9xbFc4vyJPFMPwb3Ng3syjUDrOpU5RxaMEAWt4josadWKEeyIC2F\n" +
+ "wrS1dzFn/5wv1g7E7xWq+nLq4zdppsyYOljzNUbhOEtJ2lhme3NJ45fxnxXmrPku\n" +
+ "gBda1lLf29inVuzuTjwtLjQwGk+usHJm9R/K0hTaSNRgepXnjY0cIgS+0gEY1/BW\n" +
+ "k3+Y4GE2JXds2cQToe5rCSYH3QG0QTyUAGvwX6hAlhrRRgUG3vxtYSixQ3UUuwzs\n" +
+ "eQW2SUFLl1611lJ7cQwFSPyr0sL0p81vdxWiigwjkfPtgljZ2QpmzR5rX2xiqItH\n" +
+ "Dy4E+iVigIYwggWEBgkqhkiG9w0BBwGgggV1BIIFcTCCBW0wggVpBgsqhkiG9w0B\n" +
+ "DAoBAqCCBTEwggUtMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAhDiwsh\n" +
+ "4wt3aAICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEELNFnEpJT65wsXwd\n" +
+ "fZ1g56cEggTQRo04bP/fWfPPZrTEczq1qO1HHV86j76Sgxau2WQ9OQAG998HFtNq\n" +
+ "NxO8R66en6QFhqpWCI73tSJD+oA29qOsT+Xt2bR2z5+K7D4QoiXuLa3gXv62VkjB\n" +
+ "0DLCHAS7Mu+hkp5OKCpXCS7fo0OnAiQjM4EluAsiwwLrHu7z1E16UwpmlgKQnaC1\n" +
+ "S44fV9znS9TxofRTnuCq1lupdn2qQjSydOU6inQeKLBflKRiLrJHOobaFmjWwp1U\n" +
+ "OQAMuZrALhHyIbOFXMPYk3mmU/1UPuRGcbcV5v2Ut2UME+WYExXSCOYR3/R4UfVk\n" +
+ "IfEzeRPFs2slJMIDS2fmMyFkEEElBckhKO9IzhQV3koeKUBdM066ufyax/uIyXPm\n" +
+ "MiB9fAqbQQ4jkQTT80bKkBAP1Bvyg2L8BssstR5iCoZgWnfA9Uz4RI5GbRqbCz7H\n" +
+ "iSkuOIowEqOox3IWbXty5VdWBXNjZBHpbE0CyMLSH/4QdGVw8R0DiCAC0mmaMaZq\n" +
+ "32yrBR32E472N+2KaicvX31MwB/LkZN46c34TGanL5LJZx0DR6ITjdNgP8TlSSrp\n" +
+ "7y2mqi7VbKp/C/28Cj5r+m++Gk6EOUpLHsZ2d2hthrr7xqoPzUAEkkyYWedHJaoQ\n" +
+ "TkoIisZb0MGlXb9thjQ8Ee429ekfjv7CQfSDS6KTE/+mhuJ33mPz1ZcIacHjdHhE\n" +
+ "6rbrKhjSrLbgmrGa8i7ezd89T4EONu0wkG9KW0wM2cn5Gb12PF6rxjTfzypG7a50\n" +
+ "yc1IJ2Wrm0B7gGuYpVoCeIohr7IlxPYdeQGRO/SlzTd0xYaJVm9FzJaMNK0ZqnZo\n" +
+ "QMEPaeq8PC3kMjpa8eAiHXk9K3DWdOWYviGVCPVYIZK6Cpwe+EwfXs+2hZgZlYzc\n" +
+ "vpUWg60md1PD4UsyLQagaj37ubR6K4C4mzlhFx5NovV/C/KD+LgekMbjCtwEQeWy\n" +
+ "agev2l9KUEz73/BT4TgQFM5K2qZpVamwmsOmldPpekGPiUCu5YxYg/y4jUKvAqj1\n" +
+ "S9t4wUAScCJx8OvXUfgpmS2+mhFPBiFps0M4O3nWG91Q6mKMqbNHPUcFDn9P7cUh\n" +
+ "s1xu3NRLyJ+QIfVfba3YBTV8A6WBYEmL9lxf1uL1WS2Bx6+Crh0keyNUPo9cRjpx\n" +
+ "1oj/xkInoc2HQODEkvuK9DD7VrLr7sDhfmJvr1mUfJMQ5/THk7Z+E+NAuMdMtkM2\n" +
+ "yKXxghZAbBrQkU3mIW150i7PsjlUw0o0/LJvQwJIsh6yeJDHY8mby9mIdeP3LQAF\n" +
+ "clYKzNwmgwbdtmVAXmQxLuhmEpXfstIzkBrNJzChzb2onNSfa+r5L6XEHNHl7wCw\n" +
+ "TuuV/JWldNuYXLfVfuv3msfSjSWkv6aRtRWIvmOv0Qba2o05LlwFMd1PzKM5uN4D\n" +
+ "DYtsS9A6yQOXEsvUkWcLOJnCs8SkJRdXhJTxdmzeBqM1JttKwLbgGMbpjbxlg3ns\n" +
+ "N+Z+sEFox+2ZWOglgnBHj0mCZOiAC8wqUu+sxsLT4WndaPWKVqoRQChvDaZaNOaN\n" +
+ "qHciF9HPUcfZow+fH8TnSHneiQcDe6XcMhSaQ2MtpY8/jrgNKguZt22yH9gw/VpT\n" +
+ "3/QOB7FBgKFIEbvUaf3nVjFIlryIheg+LeiBd2isoMNNXaBwcg2YXukxJTAjBgkq\n" +
+ "hkiG9w0BCRUxFgQUwWO5DorvVWYF3BWUmAw0rUEajScwfDBtMEkGCSqGSIb3DQEF\n" +
+ "DjA8MCwGCSqGSIb3DQEFDDAfBAgUr2yP+/DBrgICCAACASAwDAYIKoZIhvcNAgsF\n" +
+ "ADAMBggqhkiG9w0CCQUABCA5zFL93jw8ItGlcbHKhqkNwbgpp6layuOuxSju4/Vd\n" +
+ "6QQITk9UIFVTRUQCAQE=");
+
+ // Valid PKCS #12 File with SHA-512 HMAC and PRF
+ private static final byte[] pkcs12WithPBMac1PBKdf2_a3 = Base64.decode("MIIKrAIBAzCCCgUGCSqGSIb3DQEHAaCCCfYEggnyMIIJ7jCCBGIGCSqGSIb3DQEH\n" +
+ "BqCCBFMwggRPAgEAMIIESAYJKoZIhvcNAQcBMFcGCSqGSIb3DQEFDTBKMCkGCSqG\n" +
+ "SIb3DQEFDDAcBAisrqL8obSBaQICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQME\n" +
+ "ASoEECjXYYca0pwsgn1Imb9WqFGAggPgT7RcF5YzEJANZU9G3tSdpCHnyWatTlhm\n" +
+ "iCEcBGgwI5gz0+GoX+JCojgYY4g+KxeqznyCu+6GeD00T4Em7SWme9nzAfBFzng0\n" +
+ "3lYCSnahSEKfgHerbzAtq9kgXkclPVk0Liy92/buf0Mqotjjs/5o78AqP86Pwbj8\n" +
+ "xYNuXOU1ivO0JiW2c2HefKYvUvMYlOh99LCoZPLHPkaaZ4scAwDjFeTICU8oowVk\n" +
+ "LKvslrg1pHbfmXHMFJ4yqub37hRtj2CoJNy4+UA2hBYlBi9WnuAJIsjv0qS3kpLe\n" +
+ "4+J2DGe31GNG8pD01XD0l69OlailK1ykh4ap2u0KeD2z357+trCFbpWMMXQcSUCO\n" +
+ "OcVjxYqgv/l1++9huOHoPSt224x4wZfJ7cO2zbAAx/K2CPhdvi4CBaDHADsRq/c8\n" +
+ "SAi+LX5SCocGT51zL5KQD6pnr2ExaVum+U8a3nMPPMv9R2MfFUksYNGgFvS+lcZf\n" +
+ "R3qk/G9iXtSgray0mwRA8pWzoXl43vc9HJuuCU+ryOc/h36NChhQ9ltivUNaiUc2\n" +
+ "b9AAQSrZD8Z7KtxjbH3noS+gjDtimDB0Uh199zaCwQ95y463zdYsNCESm1OT979o\n" +
+ "Y+81BWFMFM/Hog5s7Ynhoi2E9+ZlyLK2UeKwvWjGzvcdPvxHR+5l/h6PyWROlpaZ\n" +
+ "zmzZBm+NKmbXtMD2AEa5+Q32ZqJQhijXZyIji3NS65y81j/a1ZrvU0lOVKA+MSPN\n" +
+ "KU27/eKZuF1LEL6qaazTUmpznLLdaVQy5aZ1qz5dyCziKcuHIclhh+RCblHU6XdE\n" +
+ "6pUTZSRQQiGUIkPUTnU9SFlZc7VwvxgeynLyXPCSzOKNWYGajy1LxDvv28uhMgNd\n" +
+ "WF51bNkl1QYl0fNunGO7YFt4wk+g7CQ/Yu2w4P7S3ZLMw0g4eYclcvyIMt4vxXfp\n" +
+ "VTKIPyzMqLr+0dp1eCPm8fIdaBZUhMUC/OVqLwgnPNY9cXCrn2R1cGKo5LtvtjbH\n" +
+ "2skz/D5DIOErfZSBJ8LE3De4j8MAjOeC8ia8LaM4PNfW/noQP1LBsZtTDTqEy01N\n" +
+ "Z5uliIocyQzlyWChErJv/Wxh+zBpbk1iXc2Owmh2GKjx0VSe7XbiqdoKkONUNUIE\n" +
+ "siseASiU/oXdJYUnBYVEUDJ1HPz7qnKiFhSgxNJZnoPfzbbx1hEzV+wxQqNnWIqQ\n" +
+ "U0s7Jt22wDBzPBHGao2tnGRLuBZWVePJGbsxThGKwrf3vYsNJTxme5KJiaxcPMwE\n" +
+ "r+ln2AqVOzzXHXgIxv/dvK0Qa7pH3AvGzcFjQChTRipgqiRrLor0//8580h+Ly2l\n" +
+ "IFo7bCuztmcwggWEBgkqhkiG9w0BBwGgggV1BIIFcTCCBW0wggVpBgsqhkiG9w0B\n" +
+ "DAoBAqCCBTEwggUtMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAi1c7S5\n" +
+ "IEG77wICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEN6rzRtIdYxqOnY+\n" +
+ "aDS3AFYEggTQNdwUoZDXCryOFBUI/z71vfoyAxlnwJLRHNXQUlI7w0KkH22aNnSm\n" +
+ "xiaXHoCP1HgcmsYORS7p/ITi/9atCHqnGR4zHmePNhoMpNHFehdjlUUWgt004vUJ\n" +
+ "5ZwTdXweM+K4We6CfWA/tyvsyGNAsuunel+8243Zsv0mGLKpjA+ZyALt51s0knmX\n" +
+ "OD2DW49FckImUVnNC5LmvEIAmVC/ZNycryZQI+2EBkJKe+BC3834GexJnSwtUBg3\n" +
+ "Xg33ZV7X66kw8tK1Ws5zND5GQAJyIu47mnjZkIWQBY+XbWowrBZ8uXIQuxMZC0p8\n" +
+ "u62oIAtZaVQoVTR1LyR/7PISFW6ApwtbTn6uQxsb16qF8lEM0S1+x0AfJY6Zm11t\n" +
+ "yCqbb2tYZF+X34MoUkR/IYC/KCq/KJdpnd8Yqgfrwjg8dR2WGIxbp2GBHq6BK/DI\n" +
+ "ehOLMcLcsOuP0DEXppfcelMOGNIs+4h4KsjWiHVDMPsqLdozBdm6FLGcno3lY5FO\n" +
+ "+avVrlElAOB+9evgaBbD2lSrEMoOjAoD090tgXXwYBEnWnIpdk+56cf5IpshrLBA\n" +
+ "/+H13LBLes+X1o5dd0Mu+3abp5RtAv7zLPRRtXkDYJPzgNcTvJ2Wxw2C+zrAclzZ\n" +
+ "7IRdcLESUa4CsN01aEvQgOtkCNVjSCtkJGP0FstsWM4hP7lfSB7P2tDL+ugy6GvB\n" +
+ "X1sz9fMC7QMAFL98nDm/yqcnejG1BcQXZho8n0svSfbcVByGlPZGMuI9t25+0B2M\n" +
+ "TAx0f6zoD8+fFmhcVgS6MQPybGKFawckYl0zulsePqs+G4voIW17owGKsRiv06Jm\n" +
+ "ZSwd3KoGmjM49ADzuG9yrQ5PSa0nhVk1tybNape4HNYHrAmmN0ILlN+E0Bs/Edz4\n" +
+ "ntYZuoc/Z35tCgm79dV4/Vl6HUZ1JrLsLrEWCByVytwVFyf3/MwTWdf+Ac+XzBuC\n" +
+ "yEMqPlvnPWswdnaid35pxios79fPl1Hr0/Q6+DoA5GyYq8SFdP7EYLrGMGa5GJ+x\n" +
+ "5nS7z6U4UmZ2sXuKYHnuhB0zi6Y04a+fhT71x02eTeC7aPlEB319UqysujJVJnso\n" +
+ "bkcwOu/Jj0Is9YeFd693dB44xeZuYyvlwoD19lqcim0TSa2Tw7D1W/yu47dKrVP2\n" +
+ "VKxRqomuAQOpoZiuSfq1/7ysrV8U4hIlIU2vnrSVJ8EtPQKsoBW5l70dQGwXyxBk\n" +
+ "BUTHqfJ4LG/kPGRMOtUzgqFw2DjJtbym1q1MZgp2ycMon4vp7DeQLGs2XfEANB+Y\n" +
+ "nRwtjpevqAnIuK6K3Y02LY4FXTNQpC37Xb04bmdIQAcE0MaoP4/hY87aS82PQ68g\n" +
+ "3bI79uKo4we2g+WaEJlEzQ7147ZzV2wbDq89W69x1MWTfaDwlEtd4UaacYchAv7B\n" +
+ "TVaaVFiRAUywWaHGePpZG2WV1feH/zd+temxWR9qMFgBZySg1jipBPVciwl0LqlW\n" +
+ "s/raIBYmLmAaMMgM3759UkNVznDoFHrY4z2EADXp0RHHVzJS1x+yYvp/9I+AcW55\n" +
+ "oN0UP/3uQ6eyz/ix22sovQwhMJ8rmgR6CfyRPKmXu1RPK3puNv7mbFTfTXpYN2vX\n" +
+ "vhEZReXY8hJF/9o4G3UrJ1F0MgUHMCG86cw1z0bhPSaXVoufOnx/fRoxJTAjBgkq\n" +
+ "hkiG9w0BCRUxFgQUwWO5DorvVWYF3BWUmAw0rUEajScwgZ0wgY0wSQYJKoZIhvcN\n" +
+ "AQUOMDwwLAYJKoZIhvcNAQUMMB8ECFDaXOUaOcUPAgIIAAIBQDAMBggqhkiG9w0C\n" +
+ "CwUAMAwGCCqGSIb3DQILBQAEQHIAM8C9OAsHUCj9CmOJioqf7YwD4O/b3UiZ3Wqo\n" +
+ "F6OmQIRDc68SdkZJ6024l4nWlnhTE7a4lb2Tru4k3NOTa1oECE5PVCBVU0VEAgEB");
+
+ // Invalid PKCS #12 File with Incorrect Iteration Count
+ private static final byte[] pkcs12WithPBMac1PBKdf2_a4 = Base64.decode("MIIKiwIBAzCCCgUGCSqGSIb3DQEHAaCCCfYEggnyMIIJ7jCCBGIGCSqGSIb3DQEH\n" +
+ "BqCCBFMwggRPAgEAMIIESAYJKoZIhvcNAQcBMFcGCSqGSIb3DQEFDTBKMCkGCSqG\n" +
+ "SIb3DQEFDDAcBAg9pxXxY2yscwICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQME\n" +
+ "ASoEEK7yYaFQDi1pYwWzm9F/fs+AggPgFIT2XapyaFgDppdvLkdvaF3HXw+zjzKb\n" +
+ "7xFC76DtVPhVTWVHD+kIss+jsj+XyvMwY0aCuAhAG/Dig+vzWomnsqB5ssw5/kTb\n" +
+ "+TMQ5PXLkNeoBmB6ArKeGc/QmCBQvQG/a6b+nXSWmxNpP+71772dmWmB8gcSJ0kF\n" +
+ "Fj75NrIbmNiDMCb71Q8gOzBMFf6BpXf/3xWAJtxyic+tSNETfOJa8zTZb0+lV0w9\n" +
+ "5eUmDrPUpuxEVbb0KJtIc63gRkcfrPtDd6Ii4Zzbzj2Evr4/S4hnrQBsiryVzJWy\n" +
+ "IEjaD0y6+DmG0JwMgRuGi1wBoGowi37GMrDCOyOZWC4n5wHLtYyhR6JaElxbrhxP\n" +
+ "H46z2USLKmZoF+YgEQgYcSBXMgP0t36+XQocFWYi2N5niy02TnctwF430FYsQlhJ\n" +
+ "Suma4I33E808dJuMv8T/soF66HsD4Zj46hOf4nWmas7IaoSAbGKXgIa7KhGRJvij\n" +
+ "xM3WOX0aqNi/8bhnxSA7fCmIy/7opyx5UYJFWGBSmHP1pBHBVmx7Ad8SAsB9MSsh\n" +
+ "nbGjGiUk4h0QcOi29/M9WwFlo4urePyI8PK2qtVAmpD3rTLlsmgzguZ69L0Q/CFU\n" +
+ "fbtqsMF0bgEuh8cfivd1DYFABEt1gypuwCUtCqQ7AXK2nQqOjsQCxVz9i9K8NDeD\n" +
+ "aau98VAl0To2sk3/VR/QUq0PRwU1jPN5BzUevhE7SOy/ImuJKwpGqqFljYdrQmj5\n" +
+ "jDe+LmYH9QGVRlfN8zuU+48FY8CAoeBeHn5AAPml0PYPVUnt3/jQN1+v+CahNVI+\n" +
+ "La8q1Nen+j1R44aa2I3y/pUgtzXRwK+tPrxTQbG030EU51LYJn8amPWmn3w75ZIA\n" +
+ "MJrXWeKj44de7u4zdUsEBVC2uM44rIHM8MFjyYAwYsey0rcp0emsaxzar+7ZA67r\n" +
+ "lDoXvvS3NqsnTXHcn3T9tkPRoee6L7Dh3x4Od96lcRwgdYT5BwyH7e34ld4VTUmJ\n" +
+ "bDEq7Ijvn4JKrwQJh1RCC+Z/ObfkC42xAm7G010u3g08xB0Qujpdg4a7VcuWrywF\n" +
+ "c7hLNquuaF4qoDaVwYXHH3iuX6YlJ/3siTKbYCVXPEZOAMBP9lF/OU76UMJBQNfU\n" +
+ "0xjDx+3AhUVgnGuCsmYlK6ETDp8qOZKGyV0KrNSGtqLx3uMhd7PETeW+ML3tDQ/0\n" +
+ "X9fMkcZHi4C2fXnoHV/qa2dGhBj4jjQ0Xh1poU6mxGn2Mebe2hDsBZkkBpnn7pK4\n" +
+ "wP/VqXdQTwqEuvzGHLVFsCuADe40ZFBmtBrf70wG7ZkO8SUZ8Zz1IX3+S024g7yj\n" +
+ "QRev/6x6TtkwggWEBgkqhkiG9w0BBwGgggV1BIIFcTCCBW0wggVpBgsqhkiG9w0B\n" +
+ "DAoBAqCCBTEwggUtMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAhTxzw+\n" +
+ "VptrYAICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEK9nSqc1I2t4tMVG\n" +
+ "bWHpdtQEggTQzCwI7j34gCTvfj6nuOSndAjShGv7mN2j7WMV0pslTpq2b9Bn3vn1\n" +
+ "Y0JMvL4E7sLrUzNU02pdOcfCnEpMFccNv2sQrLp1mOCKxu8OjSqHZLoKVL0ROVsZ\n" +
+ "8dMECLLigDlPKRiSyLErl14tErX4/zbkUaWMROO28kFbTbubQ8YoHlRUwsKW1xLg\n" +
+ "vfi0gRkG/zHXRfQHjX/8NStv7hXlehn7/Gy2EKPsRFhadm/iUHAfmCMkMgHTU248\n" +
+ "JER9+nsXltd59H+IeDpj/kbxZ+YvHow9XUZKu828d3MQnUpLZ1BfJGhMBPVwbVUD\n" +
+ "A40CiQBVdCoGtPJyalL28xoS3H0ILFCnwQOr6u0HwleNJPGHq78HUyH6Hwxnh0b0\n" +
+ "5o163r6wTFZn5cMOxpbs/Ttd+3TrxmrYpd2XnuRme3cnaYJ0ILvpc/8eLLR7SKjD\n" +
+ "T4JhZ0h/CfcV2WWvhpQugkY0pWrZ+EIMneB1dZB96mJVLxOi148OeSgi0PsxZMNi\n" +
+ "YM33rTpwQT5WqOsEyDwUQpne5b8Kkt/s7EN0LJNnPyJJRL1LcqOdr6j+6YqRtPa7\n" +
+ "a9oWJqMcuTP+bqzGRJh+3HDlFBw2Yzp9iadv4KmB2MzhStLUoi2MSjvnnkkd5Led\n" +
+ "sshAd6WbKfF7kLAHQHT4Ai6dMEO4EKkEVF9JBtxCR4JEn6C98Lpg+Lk+rfY7gHOf\n" +
+ "ZxtgGURwgXRY3aLUrdT55ZKgk3ExVKPzi5EhdpAau7JKhpOwyKozAp/OKWMNrz6h\n" +
+ "obu2Mbn1B+IA60psYHHxynBgsJHv7WQmbYh8HyGfHgVvaA8pZCYqxxjpLjSJrR8B\n" +
+ "Bu9H9xkTh7KlhxgreXYv19uAYbUd95kcox9izad6VPnovgFSb+Omdy6PJACPj6hF\n" +
+ "W6PJbucP0YPpO0VtWtQdZZ3df1P0hZ7qvKwOPFA+gKZSckgqASfygiP9V3Zc8jIi\n" +
+ "wjNzoDM2QT+UUJKiiGYXJUEOO9hxzFHlGj759DcNRhpgl5AgR57ofISD9yBuCAJY\n" +
+ "PQ/aZHPFuRTrcVG3RaIbCAS73nEznKyFaLOXfzyfyaSmyhsH253tnyL1MejC+2bR\n" +
+ "Eko/yldgFUxvU5JI+Q3KJ6Awj+PnduHXx71E4UwSuu2xXYMpxnQwI6rroQpZBX82\n" +
+ "HhqgcLV83P8lpzQwPdHjH5zkoxmWdC0+jU/tcQfNXYpJdyoaX7tDmVclLhwl9ps/\n" +
+ "O841pIsNLJWXwvxG6B+3LN/kw4QjwN194PopiOD7+oDm5mhttO78CrBrRxHMD/0Q\n" +
+ "qniZjKzSZepxlZq+J792u8vtMnuzzChxu0Bf3PhIXcJNcVhwUtr0yKe/N+NvC0tm\n" +
+ "p8wyik/BlndxN9eKbdTOi2wIi64h2QG8nOk66wQ/PSIJYwZl6eDNEQSzH/1mGCfU\n" +
+ "QnUT17UC/p+Qgenf6Auap2GWlvsJrB7u/pytz65rtjt/ouo6Ih6EwWqwVVpGXZD0\n" +
+ "7gVWH0Ke/Vr6aPGNvkLcmftPuDZsn9jiig3guhdeyRVf10Ox369kKWcG75q77hxE\n" +
+ "IzSzDyUlBNbnom9SIjut3r+qVYmWONatC6q/4D0I42Lnjd3dEyZx7jmH3g/S2ASM\n" +
+ "FzWr9pvXc61dsYOkdZ4PYa9XPUZxXFagZsoS3F1sU799+IJVU0tC0MExJTAjBgkq\n" +
+ "hkiG9w0BCRUxFgQUwWO5DorvVWYF3BWUmAw0rUEajScwfTBtMEkGCSqGSIb3DQEF\n" +
+ "DjA8MCwGCSqGSIb3DQEFDDAfBAhvRzw4sC4xcwICCAECASAwDAYIKoZIhvcNAgkF\n" +
+ "ADAMBggqhkiG9w0CCQUABCB6pW2FOdcCNj87zS64NUXG36K5aXDnFHctIk5Bf4kG\n" +
+ "3QQITk9UIFVTRUQCAggA");
+
+ // Invalid PKCS #12 File with Incorrect Salt
+ private static final byte[] pkcs12WithPBMac1PBKdf2_a5 = Base64.decode("MIIKigIBAzCCCgUGCSqGSIb3DQEHAaCCCfYEggnyMIIJ7jCCBGIGCSqGSIb3DQEH\n" +
+ "BqCCBFMwggRPAgEAMIIESAYJKoZIhvcNAQcBMFcGCSqGSIb3DQEFDTBKMCkGCSqG\n" +
+ "SIb3DQEFDDAcBAg9pxXxY2yscwICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQME\n" +
+ "ASoEEK7yYaFQDi1pYwWzm9F/fs+AggPgFIT2XapyaFgDppdvLkdvaF3HXw+zjzKb\n" +
+ "7xFC76DtVPhVTWVHD+kIss+jsj+XyvMwY0aCuAhAG/Dig+vzWomnsqB5ssw5/kTb\n" +
+ "+TMQ5PXLkNeoBmB6ArKeGc/QmCBQvQG/a6b+nXSWmxNpP+71772dmWmB8gcSJ0kF\n" +
+ "Fj75NrIbmNiDMCb71Q8gOzBMFf6BpXf/3xWAJtxyic+tSNETfOJa8zTZb0+lV0w9\n" +
+ "5eUmDrPUpuxEVbb0KJtIc63gRkcfrPtDd6Ii4Zzbzj2Evr4/S4hnrQBsiryVzJWy\n" +
+ "IEjaD0y6+DmG0JwMgRuGi1wBoGowi37GMrDCOyOZWC4n5wHLtYyhR6JaElxbrhxP\n" +
+ "H46z2USLKmZoF+YgEQgYcSBXMgP0t36+XQocFWYi2N5niy02TnctwF430FYsQlhJ\n" +
+ "Suma4I33E808dJuMv8T/soF66HsD4Zj46hOf4nWmas7IaoSAbGKXgIa7KhGRJvij\n" +
+ "xM3WOX0aqNi/8bhnxSA7fCmIy/7opyx5UYJFWGBSmHP1pBHBVmx7Ad8SAsB9MSsh\n" +
+ "nbGjGiUk4h0QcOi29/M9WwFlo4urePyI8PK2qtVAmpD3rTLlsmgzguZ69L0Q/CFU\n" +
+ "fbtqsMF0bgEuh8cfivd1DYFABEt1gypuwCUtCqQ7AXK2nQqOjsQCxVz9i9K8NDeD\n" +
+ "aau98VAl0To2sk3/VR/QUq0PRwU1jPN5BzUevhE7SOy/ImuJKwpGqqFljYdrQmj5\n" +
+ "jDe+LmYH9QGVRlfN8zuU+48FY8CAoeBeHn5AAPml0PYPVUnt3/jQN1+v+CahNVI+\n" +
+ "La8q1Nen+j1R44aa2I3y/pUgtzXRwK+tPrxTQbG030EU51LYJn8amPWmn3w75ZIA\n" +
+ "MJrXWeKj44de7u4zdUsEBVC2uM44rIHM8MFjyYAwYsey0rcp0emsaxzar+7ZA67r\n" +
+ "lDoXvvS3NqsnTXHcn3T9tkPRoee6L7Dh3x4Od96lcRwgdYT5BwyH7e34ld4VTUmJ\n" +
+ "bDEq7Ijvn4JKrwQJh1RCC+Z/ObfkC42xAm7G010u3g08xB0Qujpdg4a7VcuWrywF\n" +
+ "c7hLNquuaF4qoDaVwYXHH3iuX6YlJ/3siTKbYCVXPEZOAMBP9lF/OU76UMJBQNfU\n" +
+ "0xjDx+3AhUVgnGuCsmYlK6ETDp8qOZKGyV0KrNSGtqLx3uMhd7PETeW+ML3tDQ/0\n" +
+ "X9fMkcZHi4C2fXnoHV/qa2dGhBj4jjQ0Xh1poU6mxGn2Mebe2hDsBZkkBpnn7pK4\n" +
+ "wP/VqXdQTwqEuvzGHLVFsCuADe40ZFBmtBrf70wG7ZkO8SUZ8Zz1IX3+S024g7yj\n" +
+ "QRev/6x6TtkwggWEBgkqhkiG9w0BBwGgggV1BIIFcTCCBW0wggVpBgsqhkiG9w0B\n" +
+ "DAoBAqCCBTEwggUtMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAhTxzw+\n" +
+ "VptrYAICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEK9nSqc1I2t4tMVG\n" +
+ "bWHpdtQEggTQzCwI7j34gCTvfj6nuOSndAjShGv7mN2j7WMV0pslTpq2b9Bn3vn1\n" +
+ "Y0JMvL4E7sLrUzNU02pdOcfCnEpMFccNv2sQrLp1mOCKxu8OjSqHZLoKVL0ROVsZ\n" +
+ "8dMECLLigDlPKRiSyLErl14tErX4/zbkUaWMROO28kFbTbubQ8YoHlRUwsKW1xLg\n" +
+ "vfi0gRkG/zHXRfQHjX/8NStv7hXlehn7/Gy2EKPsRFhadm/iUHAfmCMkMgHTU248\n" +
+ "JER9+nsXltd59H+IeDpj/kbxZ+YvHow9XUZKu828d3MQnUpLZ1BfJGhMBPVwbVUD\n" +
+ "A40CiQBVdCoGtPJyalL28xoS3H0ILFCnwQOr6u0HwleNJPGHq78HUyH6Hwxnh0b0\n" +
+ "5o163r6wTFZn5cMOxpbs/Ttd+3TrxmrYpd2XnuRme3cnaYJ0ILvpc/8eLLR7SKjD\n" +
+ "T4JhZ0h/CfcV2WWvhpQugkY0pWrZ+EIMneB1dZB96mJVLxOi148OeSgi0PsxZMNi\n" +
+ "YM33rTpwQT5WqOsEyDwUQpne5b8Kkt/s7EN0LJNnPyJJRL1LcqOdr6j+6YqRtPa7\n" +
+ "a9oWJqMcuTP+bqzGRJh+3HDlFBw2Yzp9iadv4KmB2MzhStLUoi2MSjvnnkkd5Led\n" +
+ "sshAd6WbKfF7kLAHQHT4Ai6dMEO4EKkEVF9JBtxCR4JEn6C98Lpg+Lk+rfY7gHOf\n" +
+ "ZxtgGURwgXRY3aLUrdT55ZKgk3ExVKPzi5EhdpAau7JKhpOwyKozAp/OKWMNrz6h\n" +
+ "obu2Mbn1B+IA60psYHHxynBgsJHv7WQmbYh8HyGfHgVvaA8pZCYqxxjpLjSJrR8B\n" +
+ "Bu9H9xkTh7KlhxgreXYv19uAYbUd95kcox9izad6VPnovgFSb+Omdy6PJACPj6hF\n" +
+ "W6PJbucP0YPpO0VtWtQdZZ3df1P0hZ7qvKwOPFA+gKZSckgqASfygiP9V3Zc8jIi\n" +
+ "wjNzoDM2QT+UUJKiiGYXJUEOO9hxzFHlGj759DcNRhpgl5AgR57ofISD9yBuCAJY\n" +
+ "PQ/aZHPFuRTrcVG3RaIbCAS73nEznKyFaLOXfzyfyaSmyhsH253tnyL1MejC+2bR\n" +
+ "Eko/yldgFUxvU5JI+Q3KJ6Awj+PnduHXx71E4UwSuu2xXYMpxnQwI6rroQpZBX82\n" +
+ "HhqgcLV83P8lpzQwPdHjH5zkoxmWdC0+jU/tcQfNXYpJdyoaX7tDmVclLhwl9ps/\n" +
+ "O841pIsNLJWXwvxG6B+3LN/kw4QjwN194PopiOD7+oDm5mhttO78CrBrRxHMD/0Q\n" +
+ "qniZjKzSZepxlZq+J792u8vtMnuzzChxu0Bf3PhIXcJNcVhwUtr0yKe/N+NvC0tm\n" +
+ "p8wyik/BlndxN9eKbdTOi2wIi64h2QG8nOk66wQ/PSIJYwZl6eDNEQSzH/1mGCfU\n" +
+ "QnUT17UC/p+Qgenf6Auap2GWlvsJrB7u/pytz65rtjt/ouo6Ih6EwWqwVVpGXZD0\n" +
+ "7gVWH0Ke/Vr6aPGNvkLcmftPuDZsn9jiig3guhdeyRVf10Ox369kKWcG75q77hxE\n" +
+ "IzSzDyUlBNbnom9SIjut3r+qVYmWONatC6q/4D0I42Lnjd3dEyZx7jmH3g/S2ASM\n" +
+ "FzWr9pvXc61dsYOkdZ4PYa9XPUZxXFagZsoS3F1sU799+IJVU0tC0MExJTAjBgkq\n" +
+ "hkiG9w0BCRUxFgQUwWO5DorvVWYF3BWUmAw0rUEajScwfDBtMEkGCSqGSIb3DQEF\n" +
+ "DjA8MCwGCSqGSIb3DQEFDDAfBAhOT1QgVVNFRAICCAACASAwDAYIKoZIhvcNAgkF\n" +
+ "ADAMBggqhkiG9w0CCQUABCB6pW2FOdcCNj87zS64NUXG36K5aXDnFHctIk5Bf4kG\n" +
+ "3QQIb0c8OLAuMXMCAQE=");
+
+ // Invalid PKCS #12 File with Missing Key Length
+ private static final byte[] pkcs12WithPBMac1PBKdf2_a6 = Base64.decode("MIIKiAIBAzCCCgUGCSqGSIb3DQEHAaCCCfYEggnyMIIJ7jCCBGIGCSqGSIb3DQEH\n" +
+ "BqCCBFMwggRPAgEAMIIESAYJKoZIhvcNAQcBMFcGCSqGSIb3DQEFDTBKMCkGCSqG\n" +
+ "SIb3DQEFDDAcBAg9pxXxY2yscwICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQME\n" +
+ "ASoEEK7yYaFQDi1pYwWzm9F/fs+AggPgFIT2XapyaFgDppdvLkdvaF3HXw+zjzKb\n" +
+ "7xFC76DtVPhVTWVHD+kIss+jsj+XyvMwY0aCuAhAG/Dig+vzWomnsqB5ssw5/kTb\n" +
+ "+TMQ5PXLkNeoBmB6ArKeGc/QmCBQvQG/a6b+nXSWmxNpP+71772dmWmB8gcSJ0kF\n" +
+ "Fj75NrIbmNiDMCb71Q8gOzBMFf6BpXf/3xWAJtxyic+tSNETfOJa8zTZb0+lV0w9\n" +
+ "5eUmDrPUpuxEVbb0KJtIc63gRkcfrPtDd6Ii4Zzbzj2Evr4/S4hnrQBsiryVzJWy\n" +
+ "IEjaD0y6+DmG0JwMgRuGi1wBoGowi37GMrDCOyOZWC4n5wHLtYyhR6JaElxbrhxP\n" +
+ "H46z2USLKmZoF+YgEQgYcSBXMgP0t36+XQocFWYi2N5niy02TnctwF430FYsQlhJ\n" +
+ "Suma4I33E808dJuMv8T/soF66HsD4Zj46hOf4nWmas7IaoSAbGKXgIa7KhGRJvij\n" +
+ "xM3WOX0aqNi/8bhnxSA7fCmIy/7opyx5UYJFWGBSmHP1pBHBVmx7Ad8SAsB9MSsh\n" +
+ "nbGjGiUk4h0QcOi29/M9WwFlo4urePyI8PK2qtVAmpD3rTLlsmgzguZ69L0Q/CFU\n" +
+ "fbtqsMF0bgEuh8cfivd1DYFABEt1gypuwCUtCqQ7AXK2nQqOjsQCxVz9i9K8NDeD\n" +
+ "aau98VAl0To2sk3/VR/QUq0PRwU1jPN5BzUevhE7SOy/ImuJKwpGqqFljYdrQmj5\n" +
+ "jDe+LmYH9QGVRlfN8zuU+48FY8CAoeBeHn5AAPml0PYPVUnt3/jQN1+v+CahNVI+\n" +
+ "La8q1Nen+j1R44aa2I3y/pUgtzXRwK+tPrxTQbG030EU51LYJn8amPWmn3w75ZIA\n" +
+ "MJrXWeKj44de7u4zdUsEBVC2uM44rIHM8MFjyYAwYsey0rcp0emsaxzar+7ZA67r\n" +
+ "lDoXvvS3NqsnTXHcn3T9tkPRoee6L7Dh3x4Od96lcRwgdYT5BwyH7e34ld4VTUmJ\n" +
+ "bDEq7Ijvn4JKrwQJh1RCC+Z/ObfkC42xAm7G010u3g08xB0Qujpdg4a7VcuWrywF\n" +
+ "c7hLNquuaF4qoDaVwYXHH3iuX6YlJ/3siTKbYCVXPEZOAMBP9lF/OU76UMJBQNfU\n" +
+ "0xjDx+3AhUVgnGuCsmYlK6ETDp8qOZKGyV0KrNSGtqLx3uMhd7PETeW+ML3tDQ/0\n" +
+ "X9fMkcZHi4C2fXnoHV/qa2dGhBj4jjQ0Xh1poU6mxGn2Mebe2hDsBZkkBpnn7pK4\n" +
+ "wP/VqXdQTwqEuvzGHLVFsCuADe40ZFBmtBrf70wG7ZkO8SUZ8Zz1IX3+S024g7yj\n" +
+ "QRev/6x6TtkwggWEBgkqhkiG9w0BBwGgggV1BIIFcTCCBW0wggVpBgsqhkiG9w0B\n" +
+ "DAoBAqCCBTEwggUtMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAhTxzw+\n" +
+ "VptrYAICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEK9nSqc1I2t4tMVG\n" +
+ "bWHpdtQEggTQzCwI7j34gCTvfj6nuOSndAjShGv7mN2j7WMV0pslTpq2b9Bn3vn1\n" +
+ "Y0JMvL4E7sLrUzNU02pdOcfCnEpMFccNv2sQrLp1mOCKxu8OjSqHZLoKVL0ROVsZ\n" +
+ "8dMECLLigDlPKRiSyLErl14tErX4/zbkUaWMROO28kFbTbubQ8YoHlRUwsKW1xLg\n" +
+ "vfi0gRkG/zHXRfQHjX/8NStv7hXlehn7/Gy2EKPsRFhadm/iUHAfmCMkMgHTU248\n" +
+ "JER9+nsXltd59H+IeDpj/kbxZ+YvHow9XUZKu828d3MQnUpLZ1BfJGhMBPVwbVUD\n" +
+ "A40CiQBVdCoGtPJyalL28xoS3H0ILFCnwQOr6u0HwleNJPGHq78HUyH6Hwxnh0b0\n" +
+ "5o163r6wTFZn5cMOxpbs/Ttd+3TrxmrYpd2XnuRme3cnaYJ0ILvpc/8eLLR7SKjD\n" +
+ "T4JhZ0h/CfcV2WWvhpQugkY0pWrZ+EIMneB1dZB96mJVLxOi148OeSgi0PsxZMNi\n" +
+ "YM33rTpwQT5WqOsEyDwUQpne5b8Kkt/s7EN0LJNnPyJJRL1LcqOdr6j+6YqRtPa7\n" +
+ "a9oWJqMcuTP+bqzGRJh+3HDlFBw2Yzp9iadv4KmB2MzhStLUoi2MSjvnnkkd5Led\n" +
+ "sshAd6WbKfF7kLAHQHT4Ai6dMEO4EKkEVF9JBtxCR4JEn6C98Lpg+Lk+rfY7gHOf\n" +
+ "ZxtgGURwgXRY3aLUrdT55ZKgk3ExVKPzi5EhdpAau7JKhpOwyKozAp/OKWMNrz6h\n" +
+ "obu2Mbn1B+IA60psYHHxynBgsJHv7WQmbYh8HyGfHgVvaA8pZCYqxxjpLjSJrR8B\n" +
+ "Bu9H9xkTh7KlhxgreXYv19uAYbUd95kcox9izad6VPnovgFSb+Omdy6PJACPj6hF\n" +
+ "W6PJbucP0YPpO0VtWtQdZZ3df1P0hZ7qvKwOPFA+gKZSckgqASfygiP9V3Zc8jIi\n" +
+ "wjNzoDM2QT+UUJKiiGYXJUEOO9hxzFHlGj759DcNRhpgl5AgR57ofISD9yBuCAJY\n" +
+ "PQ/aZHPFuRTrcVG3RaIbCAS73nEznKyFaLOXfzyfyaSmyhsH253tnyL1MejC+2bR\n" +
+ "Eko/yldgFUxvU5JI+Q3KJ6Awj+PnduHXx71E4UwSuu2xXYMpxnQwI6rroQpZBX82\n" +
+ "HhqgcLV83P8lpzQwPdHjH5zkoxmWdC0+jU/tcQfNXYpJdyoaX7tDmVclLhwl9ps/\n" +
+ "O841pIsNLJWXwvxG6B+3LN/kw4QjwN194PopiOD7+oDm5mhttO78CrBrRxHMD/0Q\n" +
+ "qniZjKzSZepxlZq+J792u8vtMnuzzChxu0Bf3PhIXcJNcVhwUtr0yKe/N+NvC0tm\n" +
+ "p8wyik/BlndxN9eKbdTOi2wIi64h2QG8nOk66wQ/PSIJYwZl6eDNEQSzH/1mGCfU\n" +
+ "QnUT17UC/p+Qgenf6Auap2GWlvsJrB7u/pytz65rtjt/ouo6Ih6EwWqwVVpGXZD0\n" +
+ "7gVWH0Ke/Vr6aPGNvkLcmftPuDZsn9jiig3guhdeyRVf10Ox369kKWcG75q77hxE\n" +
+ "IzSzDyUlBNbnom9SIjut3r+qVYmWONatC6q/4D0I42Lnjd3dEyZx7jmH3g/S2ASM\n" +
+ "FzWr9pvXc61dsYOkdZ4PYa9XPUZxXFagZsoS3F1sU799+IJVU0tC0MExJTAjBgkq\n" +
+ "hkiG9w0BCRUxFgQUwWO5DorvVWYF3BWUmAw0rUEajScwejBqMEYGCSqGSIb3DQEF\n" +
+ "DjA5MCkGCSqGSIb3DQEFDDAcBAhvRzw4sC4xcwICCAAwDAYIKoZIhvcNAgkFADAM\n" +
+ "BggqhkiG9w0CCQUABCB6pW2FOdcCNj87zS64NUXG36K5aXDnFHctIk5Bf4kG3QQI\n" +
+ "b0c8OLAuMXMCAggA");
+
/**
* we generate a self signed certificate for the sake of testing - RSA
*/
@@ -2145,6 +2500,52 @@ private void testIterationCount()
System.clearProperty("org.bouncycastle.pkcs12.max_it_count");
}
+ private void testPBMac1PBKdf2()
+ throws Exception
+ {
+ KeyStore store = KeyStore.getInstance("PKCS12", BC);
+ final char[] password = "1234".toCharArray();
+ ByteArrayInputStream stream;
+ // valid test vectors
+ for (byte[] test_vector : new byte[][]{pkcs12WithPBMac1PBKdf2_a1, pkcs12WithPBMac1PBKdf2_a2, pkcs12WithPBMac1PBKdf2_a3})
+ {
+ stream = new ByteArrayInputStream(test_vector);
+ store.load(stream, password);
+
+ try
+ {
+ store.load(stream, "not right".toCharArray());
+ fail("no exception");
+ }
+ catch (IOException ignored) {}
+ }
+ // invalid test vectors
+ for (byte[] test_vector : new byte[][]{pkcs12WithPBMac1PBKdf2_a4, pkcs12WithPBMac1PBKdf2_a5})
+ {
+ stream = new ByteArrayInputStream(test_vector);
+ try
+ {
+ store.load(stream, password);
+ fail("no exception");
+ }
+ catch (IOException e)
+ {
+ isTrue(e.getMessage().contains("PKCS12 key store mac invalid - wrong password or corrupted file."));
+ }
+ }
+ // invalid test vector that throws exception
+ stream = new ByteArrayInputStream(pkcs12WithPBMac1PBKdf2_a6);
+ try
+ {
+ store.load(stream, password);
+ fail("no exception");
+ }
+ catch (IOException e)
+ {
+ isTrue(e.getMessage().contains("Key length must be present when using PBMAC1."));
+ }
+ }
+
private void testBCFKSLoad()
throws Exception
{
@@ -2327,6 +2728,7 @@ public void performTest()
{
testPKCS12StoreFriendlyName();
testIterationCount();
+ testPBMac1PBKdf2();
testPKCS12Store();
testGOSTStore();
testChainCycle();
From d1183b3e8e70f461749fac0df2dc66daa1fb61fd Mon Sep 17 00:00:00 2001
From: Jill Kleiber
Date: Tue, 21 Jan 2025 13:20:14 +0100
Subject: [PATCH 149/890] added save tests to testPBMac1PBKdf2 test
---
.../jce/provider/test/PKCS12StoreTest.java | 21 +++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/PKCS12StoreTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/PKCS12StoreTest.java
index 9011fee6f7..3bfc031ef6 100644
--- a/prov/src/test/java/org/bouncycastle/jce/provider/test/PKCS12StoreTest.java
+++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/PKCS12StoreTest.java
@@ -2509,6 +2509,9 @@ private void testPBMac1PBKdf2()
// valid test vectors
for (byte[] test_vector : new byte[][]{pkcs12WithPBMac1PBKdf2_a1, pkcs12WithPBMac1PBKdf2_a2, pkcs12WithPBMac1PBKdf2_a3})
{
+ //
+ // load test
+ //
stream = new ByteArrayInputStream(test_vector);
store.load(stream, password);
@@ -2518,6 +2521,24 @@ private void testPBMac1PBKdf2()
fail("no exception");
}
catch (IOException ignored) {}
+
+ //
+ // save test
+ //
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ store.store(bOut, passwd);
+ stream = new ByteArrayInputStream(bOut.toByteArray());
+ store.load(stream, passwd);
+
+ //
+ // save test using LoadStoreParameter
+ //
+ bOut = new ByteArrayOutputStream();
+ PKCS12StoreParameter storeParam = new PKCS12StoreParameter(bOut, passwd, true);
+ store.store(storeParam);
+ byte[] data = bOut.toByteArray();
+ stream = new ByteArrayInputStream(data);
+ store.load(stream, passwd);
}
// invalid test vectors
for (byte[] test_vector : new byte[][]{pkcs12WithPBMac1PBKdf2_a4, pkcs12WithPBMac1PBKdf2_a5})
From 9ef9e788329bf2fe1f1cfa4ba861c8b4277e2791 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Tue, 4 Mar 2025 16:55:37 +1030
Subject: [PATCH 150/890] Refactor of Mayo
---
.../pqc/crypto/mayo/GF16Utils.java | 4 +-
.../pqc/crypto/mayo/MayoSigner.java | 71 +++++++--------
.../bouncycastle/pqc/crypto/mayo/Utils.java | 86 ++++++-------------
.../java/org/bouncycastle/util/Bytes.java | 2 +-
4 files changed, 60 insertions(+), 103 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java
index d367c94109..c12f35b289 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java
@@ -82,7 +82,7 @@ static void mulAddMUpperTriangularMatXMat(int mVecLimbs, long[] bsMat, byte[] ma
for (int k = 0, kmVecLimbs = 0; k < matCols; k++, kmVecLimbs += mVecLimbs)
{
// For acc: add into the m-vector at row r, column k.
- mVecMulAdd(mVecLimbs, bsMat, bsMatEntriesUsed, mat[cmatCols + k] & 0xFF, acc, accOff + rmatColsmVecLimbs + kmVecLimbs);
+ mVecMulAdd(mVecLimbs, bsMat, bsMatEntriesUsed, mat[cmatCols + k], acc, accOff + rmatColsmVecLimbs + kmVecLimbs);
}
bsMatEntriesUsed += mVecLimbs;
}
@@ -256,7 +256,7 @@ static long mulFx8(byte a, long b)
// Reduction mod (x^4 + x + 1): process each byte in parallel.
long topP = p & 0xf0f0f0f0f0f0f0f0L;
- return (p ^ (topP >> 4) ^ (topP >> 3)) & 0x0f0f0f0f0f0f0f0fL;
+ return (p ^ (topP >>> 4) ^ (topP >>> 3)) & 0x0f0f0f0f0f0f0f0fL;
}
static void matMul(byte[] a, byte[] b, int bOff, byte[] c, int colrowAB, int rowA)
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
index 2e6fd8c96d..c5242b00bd 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
@@ -16,7 +16,7 @@ public class MayoSigner
implements MessageSigner
{
private SecureRandom random;
- MayoParameters params;
+ private MayoParameters params;
private MayoPublicKeyParameters pubKey;
private MayoPrivateKeyParameters privKey;
@@ -57,6 +57,7 @@ public byte[] generateSignature(byte[] message)
int v = params.getV();
int o = params.getO();
int n = params.getN();
+ int m = params.getM();
int vbytes = params.getVBytes();
int oBytes = params.getOBytes();
int saltBytes = params.getSaltBytes();
@@ -66,16 +67,17 @@ public byte[] generateSignature(byte[] message)
int digestBytes = params.getDigestBytes();
int skSeedBytes = params.getSkSeedBytes();
byte[] tenc = new byte[params.getMBytes()];
- byte[] t = new byte[params.getM()];
- byte[] y = new byte[params.getM()];
+ byte[] t = new byte[m];
+ byte[] y = new byte[m];
byte[] salt = new byte[saltBytes];
byte[] V = new byte[k * vbytes + params.getRBytes()];
byte[] Vdec = new byte[v * k];
int ok = k * o;
- byte[] A = new byte[((params.getM() + 7) / 8 * 8) * (ok + 1)];
- byte[] x = new byte[k * n];
+ int nk = k * n;
+ byte[] A = new byte[((m + 7) / 8 * 8) * (ok + 1)];
+ byte[] x = new byte[nk];
byte[] r = new byte[ok + 1];
- byte[] s = new byte[k * n];
+ byte[] s = new byte[nk];
byte[] tmp = new byte[digestBytes + saltBytes + skSeedBytes + 1];
byte[] sig = new byte[params.getSigBytes()];
long[] P = new long[p1Limbs + params.getP2Limbs()];
@@ -121,9 +123,9 @@ public byte[] generateSignature(byte[] message)
{
// Multiply the m-vector at P1 for the current matrix entry,
// and accumulate into acc for row r.
- GF16Utils.mVecMulAdd(mVecLimbs, P, bsMatEntriesUsed, O[co + j] & 0xFF, P, iomVecLimbs + jmVecLimbs);
+ GF16Utils.mVecMulAdd(mVecLimbs, P, bsMatEntriesUsed, O[co + j], P, iomVecLimbs + jmVecLimbs);
// Similarly, accumulate into acc for row c.
- GF16Utils.mVecMulAdd(mVecLimbs, P, bsMatEntriesUsed, O[io + j] & 0xFF, P, comVecLimbs + jmVecLimbs);
+ GF16Utils.mVecMulAdd(mVecLimbs, P, bsMatEntriesUsed, O[io + j], P, comVecLimbs + jmVecLimbs);
}
bsMatEntriesUsed += mVecLimbs;
}
@@ -150,9 +152,10 @@ public byte[] generateSignature(byte[] message)
System.arraycopy(salt, 0, tmp, digestBytes, saltBytes);
shake.update(tmp, 0, digestBytes + saltBytes);
shake.doFinal(tenc, 0, params.getMBytes());
- Utils.decode(tenc, t, params.getM());
+ Utils.decode(tenc, t, m);
int size = v * k * mVecLimbs;
long[] Pv = new long[size];
+ byte[] Ox = new byte[v];
for (int ctr = 0; ctr <= 255; ctr++)
{
tmp[tmp.length - 1] = (byte)ctr;
@@ -182,12 +185,12 @@ public byte[] generateSignature(byte[] message)
computeA(Mtmp, A);
// Clear trailing bytes
-// for (int i = 0; i < params.getM(); ++i)
+// for (int i = 0; i < m; ++i)
// {
// A[(i + 1) * (ok + 1) - 1] = 0;
// }
- Utils.decode(V, k * vbytes, r, 0, ok);
+ Utils.decode(V, k * vbytes, r, ok);
if (sampleSolution(params, A, y, r, x))
{
@@ -201,16 +204,16 @@ public byte[] generateSignature(byte[] message)
}
// Compute final signature components
- byte[] Ox = new byte[v];
- for (int i = 0; i < k; i++)
+
+ for (int i = 0, io = 0, in = 0, iv = 0; i < k; i++, io += o, in+= n, iv += v)
{
- GF16Utils.matMul(O, x, i * o, Ox, o, n - o);
- Bytes.xor(v, Vdec, i * v, Ox, s, i * n);
- System.arraycopy(x, i * o, s, i * n + n - o, o);
+ GF16Utils.matMul(O, x, io, Ox, o, v);
+ Bytes.xor(v, Vdec, iv, Ox, s, in);
+ System.arraycopy(x, io, s, in + v, o);
}
// Encode and add salt
- Utils.encode(s, sig, n * k);
+ Utils.encode(s, sig, nk);
System.arraycopy(salt, 0, sig, sig.length - saltBytes, saltBytes);
return Arrays.concatenate(sig, message);
@@ -294,13 +297,12 @@ void computeRHS(long[] vPv, byte[] t, byte[] y)
final int k = params.getK();
final int[] fTail = params.getFTail();
- final int topPos = ((m - 1) & 15) * 4;
+ final int topPos = ((m - 1) & 15) << 2;
// Zero out tails of m_vecs if necessary
if ((m & 15) != 0)
{
- long mask = 1L << ((m & 15) << 2);
- mask -= 1;
+ long mask = (1L << ((m & 15) << 2)) - 1;
final int kSquared = k * k;
for (int i = 0, index = mVecLimbs - 1; i < kSquared; i++, index += mVecLimbs)
@@ -409,7 +411,7 @@ void computeA(long[] Mtmp, byte[] AOut)
}
}
- for (int i = 0, io = 0; i < k; i++, io += o)
+ for (int i = 0, io = 0, iomVecLimbs = 0; i < k; i++, io += o, iomVecLimbs += omVecLimbs)
{
for (int j = k - 1, jomVecLimbs = j * omVecLimbs, jo = j * o; j >= i; j--, jomVecLimbs -= omVecLimbs, jo -= o)
{
@@ -433,13 +435,11 @@ void computeA(long[] Mtmp, byte[] AOut)
if (i != j)
{
// Process Mi
- int miOffset = i * mVecLimbs * o;
for (int c = 0, cmVecLimbs = 0; c < o; c++, cmVecLimbs += mVecLimbs)
{
for (int limb = 0, limbAWidhth = 0; limb < mVecLimbs; limb++, limbAWidhth += AWidth)
{
- long value = Mtmp[miOffset + limb + cmVecLimbs];
-
+ long value = Mtmp[iomVecLimbs + limb + cmVecLimbs];
int aIndex = jo + c + wordsToShift + limbAWidhth;
A[aIndex] ^= value << bitsToShift;
@@ -461,7 +461,7 @@ void computeA(long[] Mtmp, byte[] AOut)
}
// Transpose blocks
- for (int c = 0; c < AWidth * ((m + (k + 1) * k / 2 + 15) >>> 4); c += 16)
+ for (int c = 0; c < AWidth * ((m + (((k + 1) * k) >> 1) + 15) >>> 4); c += 16)
{
transpose16x16Nibbles(A, c);
}
@@ -554,8 +554,7 @@ private static void transpose16x16Nibbles(long[] M, int offset)
}
}
- boolean sampleSolution(MayoParameters params, byte[] A, byte[] y,
- byte[] r, byte[] x)
+ boolean sampleSolution(MayoParameters params, byte[] A, byte[] y, byte[] r, byte[] x)
{
final int k = params.getK();
final int o = params.getO();
@@ -576,9 +575,9 @@ boolean sampleSolution(MayoParameters params, byte[] A, byte[] y,
GF16Utils.matMul(A, r, 0, Ar, ok + 1, m);
// Update last column of A with y - Ar
- for (int i = 0; i < m; i++)
+ for (int i = 0, idx = ok; i < m; i++, idx += ok + 1)
{
- A[ok + i * (ok + 1)] = (byte)(y[i] ^ Ar[i]);
+ A[idx] = (byte)(y[i] ^ Ar[i]);
}
// Perform row echelon form transformation
@@ -586,9 +585,9 @@ boolean sampleSolution(MayoParameters params, byte[] A, byte[] y,
// Check matrix rank
boolean fullRank = false;
- for (int i = 0; i < aCols - 1; i++)
+ for (int i = 0, idx = (m - 1) * aCols; i < aCols - 1; i++, idx++)
{
- fullRank |= (A[(m - 1) * aCols + i] != 0);
+ fullRank |= (A[idx] != 0);
}
if (!fullRank)
{
@@ -609,7 +608,6 @@ boolean sampleSolution(MayoParameters params, byte[] A, byte[] y,
byte u = (byte)(correctCol & ~finished & A[rowAcols + aCols - 1]);
x[col] ^= u;
-
// Update matrix entries
for (int i = 0, iaCols_col = col, iaCols_aCols1 = aCols - 1; i < row; i += 8,
iaCols_col += aCols << 3, iaCols_aCols1 += aCols << 3)
@@ -647,7 +645,7 @@ boolean sampleSolution(MayoParameters params, byte[] A, byte[] y,
void ef(byte[] A, int nrows, int ncols)
{
// Each 64-bit long can hold 16 nibbles (16 GF(16) elements).
- int rowLen = (ncols + 15) / 16;
+ int rowLen = (ncols + 15) >> 4;
// Allocate temporary arrays.
long[] pivotRow = new long[rowLen];
@@ -686,11 +684,8 @@ void ef(byte[] A, int nrows, int ncols)
int upperBound = Math.min(nrows - 1, pivotCol);
// Zero out pivot row buffers.
- for (int i = 0; i < rowLen; i++)
- {
- pivotRow[i] = 0;
- pivotRow2[i] = 0;
- }
+ Arrays.clear(pivotRow);
+ Arrays.clear(pivotRow2);
// Try to select a pivot row in constant time.
int pivot = 0;
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/Utils.java
index 8d9b1ef47b..16b4922278 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/Utils.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/Utils.java
@@ -22,9 +22,7 @@ public class Utils
*/
public static void decode(byte[] m, byte[] mdec, int mdecLen)
{
- int i;
- int decIndex = 0;
- int blocks = mdecLen >> 1;
+ int i, decIndex = 0, blocks = mdecLen >> 1;
// Process pairs of nibbles from each byte
for (i = 0; i < blocks; i++)
{
@@ -34,7 +32,7 @@ public static void decode(byte[] m, byte[] mdec, int mdecLen)
mdec[decIndex++] = (byte)((m[i] >> 4) & 0x0F);
}
// If there is an extra nibble (odd number of nibbles), decode only the lower nibble
- if (mdecLen % 2 == 1)
+ if ((mdecLen & 1) == 1)
{
mdec[decIndex] = (byte)((m[i] & 0xFF) & 0x0F);
}
@@ -52,7 +50,7 @@ public static void decode(byte[] m, int mOff, byte[] mdec, int decIndex, int mde
mdec[decIndex++] = (byte)((m[mOff++] >> 4) & 0x0F);
}
// If there is an extra nibble (odd number of nibbles), decode only the lower nibble
- if (mdecLen % 2 == 1)
+ if ((mdecLen & 1) == 1)
{
mdec[decIndex] = (byte)(m[mOff] & 0x0F);
}
@@ -68,14 +66,13 @@ public static void decode(byte[] m, int mOff, byte[] mdec, int decIndex, int mde
*/
public static void decode(byte[] input, int inputOffset, byte[] output, int mdecLen)
{
- int decIndex = 0;
- int blocks = mdecLen >> 1;
+ int decIndex = 0, blocks = mdecLen >> 1;
for (int i = 0; i < blocks; i++)
{
output[decIndex++] = (byte)(input[inputOffset] & 0x0F);
output[decIndex++] = (byte)((input[inputOffset++] >> 4) & 0x0F);
}
- if (mdecLen % 2 == 1)
+ if ((mdecLen & 1) == 1)
{
output[decIndex] = (byte)(input[inputOffset] & 0x0F);
}
@@ -92,8 +89,7 @@ public static void decode(byte[] input, int inputOffset, byte[] output, int mdec
*/
public static void encode(byte[] m, byte[] menc, int mlen)
{
- int i;
- int srcIndex = 0;
+ int i, srcIndex = 0;
// Process pairs of 4-bit values
for (i = 0; i < mlen / 2; i++)
{
@@ -103,58 +99,28 @@ public static void encode(byte[] m, byte[] menc, int mlen)
srcIndex += 2;
}
// If there is an extra nibble (odd number of nibbles), store it directly in lower 4 bits.
- if (mlen % 2 == 1)
+ if ((mlen & 1) == 1)
{
menc[i] = (byte)(m[srcIndex] & 0x0F);
}
}
- /**
- * Unpacks m-vectors from a packed byte array into an array of 64-bit limbs.
- *
- * @param in the input byte array containing packed data
- * @param out the output long array where unpacked limbs are stored
- * @param vecs the number of vectors
- * @param m the m parameter (used to compute m_vec_limbs and copy lengths)
- */
- public static void unpackMVecs(byte[] in, long[] out, int vecs, int m)
- {
- int mVecLimbs = (m + 15) / 16;
- int bytesToCopy = m / 2; // Number of bytes to copy per vector
- // Temporary buffer to hold mVecLimbs longs (each long is 8 bytes)
- byte[] tmp = new byte[mVecLimbs << 3];
-
- // Process vectors in reverse order
- for (int i = vecs - 1; i >= 0; i--)
- {
- // Copy m/2 bytes from the input into tmp. The rest remains zero.
- System.arraycopy(in, i * bytesToCopy, tmp, 0, bytesToCopy);
-
- // Convert each 8-byte block in tmp into a long using Pack
- for (int j = 0; j < mVecLimbs; j++)
- {
- out[i * mVecLimbs + j] = Pack.littleEndianToLong(tmp, j << 3);
- }
- }
- }
-
public static void unpackMVecs(byte[] in, int inOff, long[] out, int outOff, int vecs, int m)
{
- int mVecLimbs = (m + 15) / 16;
- int bytesToCopy = m / 2; // Number of bytes to copy per vector
+ int mVecLimbs = (m + 15) >> 4;
+ int bytesToCopy = m >> 1; // Number of bytes to copy per vector
// Temporary buffer to hold mVecLimbs longs (each long is 8 bytes)
- byte[] tmp = new byte[mVecLimbs << 3];
+ int lastblockLen = 8 - (mVecLimbs << 3) + bytesToCopy;
+ int i, j;
// Process vectors in reverse order
- for (int i = vecs - 1; i >= 0; i--)
+ for (i = vecs - 1, outOff += i * mVecLimbs, inOff += i * bytesToCopy; i >= 0; i--, outOff -= mVecLimbs, inOff -= bytesToCopy)
{
- // Copy m/2 bytes from the input into tmp. The rest remains zero.
- System.arraycopy(in, inOff + i * bytesToCopy, tmp, 0, bytesToCopy);
-
// Convert each 8-byte block in tmp into a long using Pack
- for (int j = 0; j < mVecLimbs; j++)
+ for (j = 0; j < mVecLimbs - 1; j++)
{
- out[outOff + i * mVecLimbs + j] = Pack.littleEndianToLong(tmp, j * 8);
+ out[outOff + j] = Pack.littleEndianToLong(in, inOff + (j << 3));
}
+ out[outOff + j] = Pack.littleEndianToLong(in, inOff + (j << 3), lastblockLen);
}
}
@@ -168,23 +134,19 @@ public static void unpackMVecs(byte[] in, int inOff, long[] out, int outOff, int
*/
public static void packMVecs(long[] in, byte[] out, int outOff, int vecs, int m)
{
- int mVecLimbs = (m + 15) / 16;
- int bytesToCopy = m / 2; // Number of bytes per vector to write
-
+ int mVecLimbs = (m + 15) >> 4;
+ int bytesToCopy = m >> 1; // Number of bytes per vector to write
+ int lastBlockLen = 8 - (mVecLimbs << 3) + bytesToCopy;
+ int j;
// Process each vector in order
- for (int i = 0; i < vecs; i++)
+ for (int i = 0, inOff = 0; i < vecs; i++, outOff += bytesToCopy, inOff += mVecLimbs)
{
- // Temporary buffer to hold the bytes for this vector
- byte[] tmp = new byte[mVecLimbs * 8];
-
// Convert each long into 8 bytes using Pack
- for (int j = 0; j < mVecLimbs; j++)
+ for (j = 0; j < mVecLimbs - 1; j++)
{
- Pack.longToLittleEndian(in[i * mVecLimbs + j], tmp, j * 8);
+ Pack.longToLittleEndian(in[inOff + j], out, outOff + (j << 3));
}
-
- // Copy the first m/2 bytes from tmp to the output array
- System.arraycopy(tmp, 0, out, i * bytesToCopy + outOff, bytesToCopy);
+ Pack.longToLittleEndian(in[inOff + j], out, outOff + (j << 3), lastBlockLen);
}
}
@@ -242,6 +204,6 @@ public static void expandP1P2(MayoParameters p, long[] P, byte[] seed_pk)
// Unpack the byte array 'temp' into the long array 'P'
// using our previously defined unpackMVecs method.
- unpackMVecs(temp, P, numVectors, p.getM());
+ unpackMVecs(temp, 0, P, 0, numVectors, p.getM());
}
}
diff --git a/core/src/main/java/org/bouncycastle/util/Bytes.java b/core/src/main/java/org/bouncycastle/util/Bytes.java
index 928cacd714..70dc29d13a 100644
--- a/core/src/main/java/org/bouncycastle/util/Bytes.java
+++ b/core/src/main/java/org/bouncycastle/util/Bytes.java
@@ -20,7 +20,7 @@ public static void xor(int len, byte[] x, int xOff, byte[] y, byte[] z, int zOff
{
for (int i = 0; i < len; ++i)
{
- z[zOff + i] = (byte)(x[xOff + i] ^ y[i]);
+ z[zOff++] = (byte)(x[xOff++] ^ y[i]);
}
}
From 8b7bf520191713efc0dfb72e01d440462b71e480 Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Tue, 4 Mar 2025 13:31:35 +0700
Subject: [PATCH 151/890] Use Arrays.areEqual
---
.../bouncycastle/crypto/test/PKCS12Test.java | 27 +++----------------
1 file changed, 4 insertions(+), 23 deletions(-)
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/PKCS12Test.java b/core/src/test/java/org/bouncycastle/crypto/test/PKCS12Test.java
index a5402aeae0..e158379013 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/PKCS12Test.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/PKCS12Test.java
@@ -6,6 +6,7 @@
import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTestResult;
import org.bouncycastle.util.test.Test;
@@ -22,26 +23,6 @@ public class PKCS12Test
char[] password1 = { 's', 'm', 'e', 'g' };
char[] password2 = { 'q', 'u', 'e', 'e', 'g' };
- private boolean isEqual(
- byte[] a,
- byte[] b)
- {
- if (a.length != b.length)
- {
- return false;
- }
-
- for (int i = 0; i != a.length; i++)
- {
- if (a[i] != b[i])
- {
- return false;
- }
- }
-
- return true;
- }
-
private TestResult run1(
int id,
char[] password,
@@ -59,7 +40,7 @@ private TestResult run1(
CipherParameters key = generator.generateDerivedParameters(24 * 8);
- if (isEqual(result, ((KeyParameter)key).getKey()))
+ if (Arrays.areEqual(result, ((KeyParameter)key).getKey()))
{
return new SimpleTestResult(true, "PKCS12Test: Okay");
}
@@ -87,7 +68,7 @@ private TestResult run2(
ParametersWithIV params = (ParametersWithIV)generator.generateDerivedParameters(64, 64);
- if (isEqual(result, params.getIV()))
+ if (Arrays.areEqual(result, params.getIV()))
{
return new SimpleTestResult(true, "PKCS12Test: Okay");
}
@@ -115,7 +96,7 @@ private TestResult run3(
CipherParameters key = generator.generateDerivedMacParameters(160);
- if (isEqual(result, ((KeyParameter)key).getKey()))
+ if (Arrays.areEqual(result, ((KeyParameter)key).getKey()))
{
return new SimpleTestResult(true, "PKCS12Test: Okay");
}
From e78fa256be85f5f255215ab6132c914b29fdcea3 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Tue, 4 Mar 2025 17:33:25 +1030
Subject: [PATCH 152/890] Refactor of MayoParameters
---
.../pqc/crypto/mayo/MayoParameters.java | 31 +++++++------------
1 file changed, 12 insertions(+), 19 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoParameters.java
index 86e99704a7..ebaa54cbe0 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoParameters.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoParameters.java
@@ -11,7 +11,7 @@ public class MayoParameters
86 - 8, // v = n - o = 78
10 * 8 + 1, // A_cols = k * o + 1 = 10 * 8 + 1 = 81
10, // k
- 16, // q
+ // q
39, // m_bytes
312, // O_bytes
39, // v_bytes
@@ -26,7 +26,7 @@ public class MayoParameters
new byte[]{8, 1, 1, 0}, // f_tail_arr
24, // salt_bytes
32, // digest_bytes
- 16, // pk_seed_bytes
+ // pk_seed_bytes
24 // sk_seed_bytes
);
@@ -39,7 +39,7 @@ public class MayoParameters
81 - 17, // v = 64
4 * 17 + 1, // A_cols = 4 * 17 + 1 = 69
4, // k
- 16, // q
+ // q
32, // m_bytes
544, // O_bytes
32, // v_bytes
@@ -54,7 +54,7 @@ public class MayoParameters
new byte[]{8, 0, 2, 8}, // f_tail_arr
24, // salt_bytes
32, // digest_bytes
- 16, // pk_seed_bytes
+ // pk_seed_bytes
24 // sk_seed_bytes
);
@@ -67,7 +67,7 @@ public class MayoParameters
118 - 10, // v = 108
11 * 10 + 1, // A_cols = 11 * 10 + 1 = 111
11, // k
- 16, // q
+ // q
54, // m_bytes
540, // O_bytes
54, // v_bytes
@@ -82,7 +82,7 @@ public class MayoParameters
new byte[]{8, 0, 1, 7}, // f_tail_arr
32, // salt_bytes
48, // digest_bytes
- 16, // pk_seed_bytes
+ // pk_seed_bytes
32 // sk_seed_bytes
);
@@ -95,7 +95,7 @@ public class MayoParameters
154 - 12, // v = 142
12 * 12 + 1, // A_cols = 12 * 12 + 1 = 145
12, // k
- 16, // q
+ // q
71, // m_bytes
852, // O_bytes
71, // v_bytes
@@ -110,7 +110,7 @@ public class MayoParameters
new byte[]{4, 0, 8, 1}, // f_tail_arr
40, // salt_bytes
64, // digest_bytes
- 16, // pk_seed_bytes
+ // pk_seed_bytes
40 // sk_seed_bytes
);
@@ -122,7 +122,7 @@ public class MayoParameters
private final int v;
private final int ACols;
private final int k;
- private final int q;
+ //private final int q; q = 16
private final int mBytes;
private final int OBytes;
private final int vBytes;
@@ -136,13 +136,13 @@ public class MayoParameters
private final byte[] fTailArr;
private final int saltBytes;
private final int digestBytes;
- private final int pkSeedBytes;
+ private static final int pkSeedBytes = 16;
private final int skSeedBytes;
- private MayoParameters(String name, int n, int m, int mVecLimbs, int o, int v, int ACols, int k, int q,
+ private MayoParameters(String name, int n, int m, int mVecLimbs, int o, int v, int ACols, int k,
int mBytes, int OBytes, int vBytes, int rBytes, int P1Bytes, int P2Bytes,
int cskBytes, int cpkBytes, int sigBytes, int[] fTail, byte[] fTailArr,
- int saltBytes, int digestBytes, int pkSeedBytes, int skSeedBytes)
+ int saltBytes, int digestBytes, int skSeedBytes)
{
this.name = name;
this.n = n;
@@ -152,7 +152,6 @@ private MayoParameters(String name, int n, int m, int mVecLimbs, int o, int v, i
this.v = v;
this.ACols = ACols;
this.k = k;
- this.q = q;
this.mBytes = mBytes;
this.OBytes = OBytes;
this.vBytes = vBytes;
@@ -166,7 +165,6 @@ private MayoParameters(String name, int n, int m, int mVecLimbs, int o, int v, i
this.fTailArr = fTailArr;
this.saltBytes = saltBytes;
this.digestBytes = digestBytes;
- this.pkSeedBytes = pkSeedBytes;
this.skSeedBytes = skSeedBytes;
}
@@ -210,11 +208,6 @@ public int getK()
return k;
}
- public int getQ()
- {
- return q;
- }
-
public int getMBytes()
{
return mBytes;
From d54df598d84ea1c70220d0da7be58ad6edf4baf1 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Wed, 5 Mar 2025 12:17:17 +1030
Subject: [PATCH 153/890] Add java doc for the two main classes of Mayo
---
.../pqc/crypto/mayo/MayoKeyPairGenerator.java | 33 ++++++++++
.../pqc/crypto/mayo/MayoSigner.java | 61 ++++++++++++++++++-
2 files changed, 91 insertions(+), 3 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
index 56fdd1fa35..d123c7d8f8 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
@@ -9,6 +9,22 @@
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Longs;
+/**
+ * Implementation of the MAYO asymmetric key pair generator following the MAYO signature scheme specifications.
+ *
+ * This generator produces {@link MayoPublicKeyParameters} and {@link MayoPrivateKeyParameters} based on the
+ * MAYO algorithm parameters. The implementation follows the specification defined in the official MAYO
+ * documentation and reference implementation.
+ *
+ *
+ * References:
+ *
+ *
+ */
public class MayoKeyPairGenerator
implements AsymmetricCipherKeyPairGenerator
{
@@ -21,6 +37,23 @@ public void init(KeyGenerationParameters param)
this.random = param.getRandom();
}
+ /**
+ * Generates a new asymmetric key pair following the MAYO algorithm specifications.
+ *
+ * The key generation process follows these steps:
+ *
+ *
+ * - Initializes parameter dimensions from {@link MayoParameters}
+ * - Generates secret key seed using a secure random generator
+ * - Derives public key seed using SHAKE-256
+ * - Expands matrix parameters P1 and P2
+ * - Performs GF(16) matrix operations for key material generation
+ * - Assembles and packages the public key components
+ * - Securely clears temporary buffers containing sensitive data
+ *
+ *
+ * @return A valid MAYO key pair containing public and private key parameters
+ */
@Override
public AsymmetricCipherKeyPair generateKeyPair()
{
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
index c5242b00bd..560068bb34 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
@@ -3,6 +3,7 @@
import java.security.SecureRandom;
import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.crypto.digests.SHAKEDigest;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.pqc.crypto.MessageSigner;
@@ -12,6 +13,21 @@
import org.bouncycastle.util.Longs;
import org.bouncycastle.util.Pack;
+/**
+ * Implementation of the MAYO digital signature scheme as specified in the MAYO documentation.
+ * This class provides functionality for both signature generation and verification.
+ *
+ * MAYO is a candidate in the NIST Post-Quantum Cryptography: Additional Digital Signature Schemes project,
+ * currently in Round 2 of evaluations. For more details about the NIST standardization process, see:
+ * NIST PQC Additional Digital Signatures.
+ *
+ * References:
+ *
+ */
public class MayoSigner
implements MessageSigner
{
@@ -20,6 +36,17 @@ public class MayoSigner
private MayoPublicKeyParameters pubKey;
private MayoPrivateKeyParameters privKey;
+ /**
+ * Initializes the signer for either signature generation or verification.
+ *
+ * @param forSigning {@code true} for signing mode, {@code false} for verification
+ * @param param CipherParameters containing:
+ *
+ * - {@link ParametersWithRandom} with {@link MayoPrivateKeyParameters} (for signing)
+ * - {@link MayoPublicKeyParameters} (for verification)
+ *
+ * @throws IllegalArgumentException if invalid parameters are provided
+ */
@Override
public void init(boolean forSigning, CipherParameters param)
{
@@ -37,7 +64,7 @@ public void init(boolean forSigning, CipherParameters param)
else
{
privKey = (MayoPrivateKeyParameters)param;
- random = null;
+ random = CryptoServicesRegistrar.getSecureRandom();
}
params = privKey.getParameters();
}
@@ -50,6 +77,14 @@ public void init(boolean forSigning, CipherParameters param)
}
}
+ /**
+ * Generates a MAYO signature for the given message using the initialized private key.
+ * Follows the signature generation process outlined in the MAYO specification document.
+ *
+ * @param message The message to be signed
+ * @return The signature bytes concatenated with the original message
+ * @see MAYO Spec Algorithm 8 and 10
+ */
@Override
public byte[] generateSignature(byte[] message)
{
@@ -192,7 +227,7 @@ public byte[] generateSignature(byte[] message)
Utils.decode(V, k * vbytes, r, ok);
- if (sampleSolution(params, A, y, r, x))
+ if (sampleSolution(A, y, r, x))
{
break;
}
@@ -235,6 +270,15 @@ public byte[] generateSignature(byte[] message)
}
}
+ /**
+ * Verifies a MAYO signature against the initialized public key and message.
+ * Implements the verification process specified in the MAYO documentation.
+ *
+ * @param message The original message
+ * @param signature The signature to verify
+ * @return {@code true} if the signature is valid, {@code false} otherwise
+ * @see MAYO Spec Algorithm 9 and 11
+ */
@Override
public boolean verifySignature(byte[] message, byte[] signature)
{
@@ -554,7 +598,17 @@ private static void transpose16x16Nibbles(long[] M, int offset)
}
}
- boolean sampleSolution(MayoParameters params, byte[] A, byte[] y, byte[] r, byte[] x)
+ /**
+ * Samples a solution for the MAYO signature equation using the provided parameters.
+ *
+ * @param A Coefficient matrix
+ * @param y Target vector
+ * @param r Randomness vector
+ * @param x Output solution vector
+ * @return {@code true} if a valid solution was found, {@code false} otherwise
+ * @see MAYO Spec Algorithm 2
+ */
+ boolean sampleSolution(byte[] A, byte[] y, byte[] r, byte[] x)
{
final int k = params.getK();
final int o = params.getO();
@@ -641,6 +695,7 @@ boolean sampleSolution(MayoParameters params, byte[] A, byte[] y, byte[] r, byte
* @param A the input matrix, stored rowwise; each element is in [0,15]
* @param nrows the number of rows
* @param ncols the number of columns (GF(16) elements per row)
+ * @see MAYO Spec Algorithm 1
*/
void ef(byte[] A, int nrows, int ncols)
{
From 6c5020715ee785a0223a6923993ca6f6304b3902 Mon Sep 17 00:00:00 2001
From: Paul Schaub
Date: Wed, 5 Mar 2025 12:02:49 +0100
Subject: [PATCH 154/890] PGPSignatureSubpacketGenerator: setXYZ() now removes
duplicates.
Prior to this chance, calling e.g. setKeyFlags() on a subpacket generator that already
contained key flags would introduce a duplicate key flag subpacket.
I fixed this behavior by changing all setXYZ() methods to first remove any packet
occurrences of the same type.
NOTE: This breaks the current behavior of setRevocable() and setExportable(),
as these method previously did a check to see if another packet of the same type was present
and threw an IllegalStateException. Now, no such exception is thrown and instead the later
method invocation takes precedence.
NOTE: If you rely on duplicate packets (e.g. in your tests), you can still introduce
duplicates by adding the duplicate packet via addCustomSubpacket(YourPacket).
---
.../PGPSignatureSubpacketGenerator.java | 44 ++++++++++++++----
.../openpgp/test/PGPGeneralTest.java | 45 +++++++++----------
2 files changed, 55 insertions(+), 34 deletions(-)
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPSignatureSubpacketGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPSignatureSubpacketGenerator.java
index 4330035bc1..2d008bd7d3 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/PGPSignatureSubpacketGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPSignatureSubpacketGenerator.java
@@ -69,10 +69,7 @@ public PGPSignatureSubpacketGenerator(PGPSignatureSubpacketVector sigSubV)
*/
public void setRevocable(boolean isCritical, boolean isRevocable)
{
- if (contains(SignatureSubpacketTags.REVOCABLE))
- {
- throw new IllegalStateException("Revocable exists in the Signature Subpacket Generator");
- }
+ removePacketsOfType(SignatureSubpacketTags.REVOCABLE);
packets.add(new Revocable(isCritical, isRevocable));
}
@@ -97,10 +94,7 @@ public void setExportable(boolean isExportable)
*/
public void setExportable(boolean isCritical, boolean isExportable)
{
- if (contains(SignatureSubpacketTags.EXPORTABLE))
- {
- throw new IllegalStateException("Exportable Certification exists in the Signature Subpacket Generator");
- }
+ removePacketsOfType(SignatureSubpacketTags.EXPORTABLE);
packets.add(new Exportable(isCritical, isExportable));
}
@@ -108,10 +102,11 @@ public void setExportable(boolean isCritical, boolean isExportable)
* Specify the set of features of the key.
*
* @param isCritical true if should be treated as critical, false otherwise.
- * @param feature features
+ * @param feature features bitmap
*/
public void setFeature(boolean isCritical, byte feature)
{
+ removePacketsOfType(SignatureSubpacketTags.FEATURES);
packets.add(new Features(isCritical, feature));
}
@@ -126,6 +121,7 @@ public void setFeature(boolean isCritical, byte feature)
*/
public void setTrust(boolean isCritical, int depth, int trustAmount)
{
+ removePacketsOfType(SignatureSubpacketTags.TRUST_SIG);
packets.add(new TrustSignature(isCritical, depth, trustAmount));
}
@@ -150,6 +146,7 @@ public void setKeyExpirationTime(long seconds)
*/
public void setKeyExpirationTime(boolean isCritical, long seconds)
{
+ removePacketsOfType(SignatureSubpacketTags.KEY_EXPIRE_TIME);
packets.add(new KeyExpirationTime(isCritical, seconds));
}
@@ -175,6 +172,7 @@ public void setSignatureExpirationTime(long seconds)
*/
public void setSignatureExpirationTime(boolean isCritical, long seconds)
{
+ removePacketsOfType(SignatureSubpacketTags.EXPIRE_TIME);
packets.add(new SignatureExpirationTime(isCritical, seconds));
}
@@ -200,6 +198,7 @@ public void setSignatureCreationTime(Date date)
*/
public void setSignatureCreationTime(boolean isCritical, Date date)
{
+ removePacketsOfType(SignatureSubpacketTags.CREATION_TIME);
packets.add(new SignatureCreationTime(isCritical, date));
}
@@ -212,6 +211,7 @@ public void setSignatureCreationTime(boolean isCritical, Date date)
*/
public void setPreferredHashAlgorithms(boolean isCritical, int[] algorithms)
{
+ removePacketsOfType(SignatureSubpacketTags.PREFERRED_HASH_ALGS);
packets.add(new PreferredAlgorithms(SignatureSubpacketTags.PREFERRED_HASH_ALGS, isCritical,
algorithms));
}
@@ -225,6 +225,7 @@ public void setPreferredHashAlgorithms(boolean isCritical, int[] algorithms)
*/
public void setPreferredSymmetricAlgorithms(boolean isCritical, int[] algorithms)
{
+ removePacketsOfType(SignatureSubpacketTags.PREFERRED_SYM_ALGS);
packets.add(new PreferredAlgorithms(SignatureSubpacketTags.PREFERRED_SYM_ALGS, isCritical,
algorithms));
}
@@ -238,6 +239,7 @@ public void setPreferredSymmetricAlgorithms(boolean isCritical, int[] algorithms
*/
public void setPreferredCompressionAlgorithms(boolean isCritical, int[] algorithms)
{
+ removePacketsOfType(SignatureSubpacketTags.PREFERRED_COMP_ALGS);
packets.add(new PreferredAlgorithms(SignatureSubpacketTags.PREFERRED_COMP_ALGS, isCritical,
algorithms));
}
@@ -254,6 +256,7 @@ public void setPreferredCompressionAlgorithms(boolean isCritical, int[] algorith
@Deprecated
public void setPreferredAEADAlgorithms(boolean isCritical, int[] algorithms)
{
+ removePacketsOfType(SignatureSubpacketTags.PREFERRED_AEAD_ALGORITHMS);
packets.add(new PreferredAlgorithms(SignatureSubpacketTags.PREFERRED_AEAD_ALGORITHMS, isCritical,
algorithms));
}
@@ -268,6 +271,7 @@ public void setPreferredAEADAlgorithms(boolean isCritical, int[] algorithms)
*/
public void setPreferredAEADCiphersuites(boolean isCritical, PreferredAEADCiphersuites.Combination[] algorithms)
{
+ removePacketsOfType(SignatureSubpacketTags.PREFERRED_AEAD_ALGORITHMS);
packets.add(new PreferredAEADCiphersuites(isCritical, algorithms));
}
@@ -280,6 +284,7 @@ public void setPreferredAEADCiphersuites(boolean isCritical, PreferredAEADCipher
*/
public void setPreferredAEADCiphersuites(PreferredAEADCiphersuites.Builder builder)
{
+ removePacketsOfType(SignatureSubpacketTags.PREFERRED_AEAD_ALGORITHMS);
packets.add(builder.build());
}
@@ -300,6 +305,7 @@ public void setPreferredAEADCiphersuites(PreferredAEADCiphersuites.Builder build
@Deprecated
public void setPreferredLibrePgpEncryptionModes(boolean isCritical, int[] algorithms)
{
+ removePacketsOfType(SignatureSubpacketTags.LIBREPGP_PREFERRED_ENCRYPTION_MODES);
packets.add(new LibrePGPPreferredEncryptionModes(isCritical, algorithms));
}
@@ -309,8 +315,22 @@ public void setPreferredLibrePgpEncryptionModes(boolean isCritical, int[] algori
*
* @param isCritical true if the subpacket should be treated as critical
* @param uri key server URI
+ * @deprecated use {@link #addPreferredKeyServer(boolean, String)} instead.
*/
+ @Deprecated
public void setPreferredKeyServer(boolean isCritical, String uri)
+ {
+ addPreferredKeyServer(isCritical, uri);
+ }
+
+ /**
+ * Specify a preferred key server for the signed user-id / key.
+ * Note, that the key server might also be a http/ftp etc. URI pointing to the key itself.
+ *
+ * @param isCritical true if the subpacket should be treated as critical
+ * @param uri key server URI
+ */
+ public void addPreferredKeyServer(boolean isCritical, String uri)
{
packets.add(new PreferredKeyServer(isCritical, uri));
}
@@ -341,6 +361,7 @@ public void setKeyFlags(int flags)
*/
public void setKeyFlags(boolean isCritical, int flags)
{
+ removePacketsOfType(SignatureSubpacketTags.KEY_FLAGS);
packets.add(new KeyFlags(isCritical, flags));
}
@@ -443,6 +464,7 @@ public void addEmbeddedSignature(boolean isCritical, PGPSignature pgpSignature)
public void setPrimaryUserID(boolean isCritical, boolean isPrimaryUserID)
{
+ removePacketsOfType(SignatureSubpacketTags.PRIMARY_USER_ID);
packets.add(new PrimaryUserID(isCritical, isPrimaryUserID));
}
@@ -485,6 +507,7 @@ public void addNotationData(boolean isCritical, boolean isHumanReadable, String
*/
public void setRevocationReason(boolean isCritical, byte reason, String description)
{
+ removePacketsOfType(SignatureSubpacketTags.REVOCATION_REASON);
packets.add(new RevocationReason(isCritical, reason, description));
}
@@ -523,6 +546,7 @@ public void addRevocationKey(boolean isCritical, int keyAlgorithm, byte[] finger
*/
public void setIssuerKeyID(boolean isCritical, long keyID)
{
+ removePacketsOfType(SignatureSubpacketTags.ISSUER_KEY_ID);
packets.add(new IssuerKeyID(isCritical, keyID));
}
@@ -536,6 +560,7 @@ public void setIssuerKeyID(boolean isCritical, long keyID)
*/
public void setSignatureTarget(boolean isCritical, int publicKeyAlgorithm, int hashAlgorithm, byte[] hashData)
{
+ removePacketsOfType(SignatureSubpacketTags.SIGNATURE_TARGET);
packets.add(new SignatureTarget(isCritical, publicKeyAlgorithm, hashAlgorithm, hashData));
}
@@ -558,6 +583,7 @@ public void setIssuerFingerprint(boolean isCritical, PGPSecretKey secretKey)
*/
public void setIssuerFingerprint(boolean isCritical, PGPPublicKey publicKey)
{
+ removePacketsOfType(SignatureSubpacketTags.ISSUER_FINGERPRINT);
packets.add(new IssuerFingerprint(isCritical, publicKey.getVersion(), publicKey.getFingerprint()));
}
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/PGPGeneralTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/PGPGeneralTest.java
index bc03498760..afd421d860 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/PGPGeneralTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/PGPGeneralTest.java
@@ -30,6 +30,7 @@
import org.bouncycastle.bcpg.SignatureSubpacketTags;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.bouncycastle.bcpg.attr.ImageAttribute;
+import org.bouncycastle.bcpg.sig.Exportable;
import org.bouncycastle.bcpg.sig.Features;
import org.bouncycastle.bcpg.sig.IntendedRecipientFingerprint;
import org.bouncycastle.bcpg.sig.KeyFlags;
@@ -37,6 +38,7 @@
import org.bouncycastle.bcpg.sig.PolicyURI;
import org.bouncycastle.bcpg.sig.PreferredAEADCiphersuites;
import org.bouncycastle.bcpg.sig.RegularExpression;
+import org.bouncycastle.bcpg.sig.Revocable;
import org.bouncycastle.bcpg.sig.RevocationKey;
import org.bouncycastle.bcpg.sig.RevocationKeyTags;
import org.bouncycastle.bcpg.sig.RevocationReason;
@@ -2169,7 +2171,7 @@ public void testPGPSignatureSubpacketVector()
isTrue("Trust should be null", trustSignature != null);
isTrue("Trust level depth should be " + depth, trustSignature.getDepth() == depth);
isTrue("Trust amount should be " + trustAmount, trustSignature.getTrustAmount() == trustAmount);
- isTrue("Exporable should be false", !hashedPcks.isExportable());
+ isTrue("Exportable should be false", !hashedPcks.isExportable());
isTrue(hashedPcks.getIssuerFingerprint().getKeyVersion() == publicKey.getVersion());
isTrue("isPrimaryUserID should be true", hashedPcks.isPrimaryUserID());
@@ -2195,7 +2197,7 @@ public void testPGPSignatureSubpacketVector()
isTrue("Trust should be null", trustSignature != null);
isTrue("Trust level depth should be " + depth, trustSignature.getDepth() == depth);
isTrue("Trust amount should be " + trustAmount, trustSignature.getTrustAmount() == trustAmount);
- isTrue("Exporable should be false", !hashedPcks.isExportable());
+ isTrue("Exportable should be false", !hashedPcks.isExportable());
isTrue(hashedPcks.getIssuerFingerprint().getKeyVersion() == publicKey.getVersion());
isTrue("isPrimaryUserID should be true", hashedPcks.isPrimaryUserID());
@@ -2207,27 +2209,20 @@ public void testPGPSignatureSubpacketVector()
hashedGen = new PGPSignatureSubpacketGenerator();
hashedGen.setExportable(false, true);
- try
- {
- hashedGen.setExportable(false, false);
- fail("Duplicated settings for Exportable");
- }
- catch (IllegalStateException e)
- {
- isTrue("Exportable Certification exists in the Signature Subpacket Generator",
- messageIs(e.getMessage(), "Exportable Certification exists in the Signature Subpacket Generator"));
- }
+ hashedGen.setExportable(false, false);
+ isEquals("Calling setExportable multiple times MUST NOT introduce duplicates",
+ 1, hashedGen.getSubpackets(SignatureSubpacketTags.EXPORTABLE).length);
+ Exportable exportable = (Exportable) hashedGen.getSubpackets(SignatureSubpacketTags.EXPORTABLE)[0];
+ isTrue("Last invocation of setExportable MUST take precedence.",
+ !exportable.isExportable());
+
hashedGen.setRevocable(false, true);
- try
- {
- hashedGen.setRevocable(false, false);
- fail("Duplicated settings for Revocable");
- }
- catch (IllegalStateException e)
- {
- isTrue("Revocable exists in the Signature Subpacket Generator",
- messageIs(e.getMessage(), "Revocable exists in the Signature Subpacket Generator"));
- }
+ hashedGen.setRevocable(false, false);
+ isEquals("Calling setRevocable multiple times MUST NOT introduce duplicates.",
+ 1, hashedGen.getSubpackets(SignatureSubpacketTags.REVOCABLE).length);
+ Revocable revocable = (Revocable) hashedGen.getSubpackets(SignatureSubpacketTags.REVOCABLE)[0];
+ isTrue("Last invocation of setRevocable MUST take precedence.",
+ !revocable.isRevocable());
try
{
@@ -2273,13 +2268,13 @@ public void testPGPSignatureSubpacketVector()
hashedPcks = sig.getHashedSubPackets();
isTrue("URL should be " + url, hashedPcks.getPolicyURI().getURI().equals(url));
isTrue(areEqual(hashedPcks.getPolicyURI().getRawURI(), Strings.toUTF8ByteArray(url)));
- isTrue("Exporable should be true", hashedPcks.isExportable());
- isTrue("Test Singner User ID", hashedPcks.getSignerUserID().equals(""));
+ isTrue("Exportable should be false", !hashedPcks.isExportable());
+ isTrue("Test Signer User ID", hashedPcks.getSignerUserID().equals(""));
isTrue("Test for empty description", hashedPcks.getRevocationReason().getRevocationDescription().equals(""));
Features features = hashedPcks.getFeatures();
isTrue(features.supportsSEIPDv2());
isTrue(features.getFeatures() == Features.FEATURE_SEIPD_V2);
- isTrue(hashedPcks.getRevocable().isRevocable());
+ isTrue("Revocable should be false", !hashedPcks.getRevocable().isRevocable());
}
public void testECNistCurves()
From 08c9a09a0d456b75ca2d42bcf90d802420d0bdbe Mon Sep 17 00:00:00 2001
From: gefeili
Date: Fri, 7 Mar 2025 12:28:20 +1030
Subject: [PATCH 155/890] TODO: gen_a_FqS_ct function in line 192 of
SnovaKeyPairGenerator
---
.../pqc/crypto/snova/GF16Matrix.java | 105 +++++++
.../pqc/crypto/snova/GF16Utils.java | 149 +++++++++
.../pqc/crypto/snova/MapGroup1.java | 29 ++
.../pqc/crypto/snova/MapGroup2.java | 20 ++
.../pqc/crypto/snova/PublicKey.java | 14 +
.../pqc/crypto/snova/PublicKeyExpanded.java | 19 ++
.../crypto/snova/PublicKeyExpandedPack.java | 19 ++
.../bouncycastle/pqc/crypto/snova/SKGF16.java | 36 +++
.../pqc/crypto/snova/SnovaEngine.java | 69 +++++
.../pqc/crypto/snova/SnovaKeyElements.java | 17 ++
.../snova/SnovaKeyGenerationParameters.java | 22 ++
.../crypto/snova/SnovaKeyPairGenerator.java | 283 ++++++++++++++++++
.../pqc/crypto/snova/SnovaParameters.java | 167 +++++++++++
.../snova/SnovaPrivateKeyParameters.java | 26 ++
.../snova/SnovaPublicKeyParameters.java | 26 ++
.../pqc/crypto/test/SnovaTest.java | 88 ++++++
.../pqc/crypto/test/TestUtils.java | 146 +++++++++
17 files changed, 1235 insertions(+)
create mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/snova/GF16Matrix.java
create mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/snova/GF16Utils.java
create mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup1.java
create mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup2.java
create mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/snova/PublicKey.java
create mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/snova/PublicKeyExpanded.java
create mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/snova/PublicKeyExpandedPack.java
create mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/snova/SKGF16.java
create mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java
create mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyElements.java
create mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyGenerationParameters.java
create mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyPairGenerator.java
create mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaParameters.java
create mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaPrivateKeyParameters.java
create mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaPublicKeyParameters.java
create mode 100644 core/src/test/java/org/bouncycastle/pqc/crypto/test/SnovaTest.java
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/GF16Matrix.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/GF16Matrix.java
new file mode 100644
index 0000000000..c929e33f5e
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/GF16Matrix.java
@@ -0,0 +1,105 @@
+package org.bouncycastle.pqc.crypto.snova;
+
+class GF16Matrix
+{
+ private final byte[][] data;
+ private final int rank;
+
+ public GF16Matrix(int rank)
+ {
+ this.rank = rank;
+ this.data = new byte[rank][rank];
+ }
+
+ public void set(int x, int y, byte value)
+ {
+ data[x][y] = (byte)(value & 0xF);
+ }
+
+ public byte get(int x, int y)
+ {
+ return data[x][y];
+ }
+
+ public void add(GF16Matrix other)
+ {
+// for (int i = 0; i < size; i++)
+// {
+// for (int j = 0; j < size; j++)
+// {
+// data[i][j] = add(data[i][j], other.data[i][j]);
+// }
+// }
+ }
+
+ public void mul(GF16Matrix a, GF16Matrix b)
+ {
+ byte[][] temp = new byte[rank][rank];
+ for (int i = 0; i < rank; i++)
+ {
+ for (int j = 0; j < rank; j++)
+ {
+ byte sum = 0;
+// for (int k = 0; k < size; k++)
+// {
+// sum = add(sum, mul(a.data[i][k], b.data[k][j]));
+// }
+ temp[i][j] = sum;
+ }
+ }
+ System.arraycopy(temp, 0, data, 0, temp.length);
+ }
+
+ public void scale(byte scalar)
+ {
+// for (int i = 0; i < size; i++)
+// {
+// for (int j = 0; j < size; j++)
+// {
+// data[i][j] = mul(data[i][j], scalar);
+// }
+// }
+ }
+
+ public void transpose()
+ {
+ byte[][] temp = new byte[rank][rank];
+ for (int i = 0; i < rank; i++)
+ {
+ for (int j = 0; j < rank; j++)
+ {
+ temp[j][i] = data[i][j];
+ }
+ }
+ System.arraycopy(temp, 0, data, 0, temp.length);
+ }
+
+ public void makeInvertible()
+ {
+ // Implementation of be_invertible_by_add_aS
+ GF16Matrix temp = new GF16Matrix(rank);
+ if (determinant() == 0)
+ {
+ for (byte a = 1; a < 16; a++)
+ {
+ temp.scale(a);
+ add(temp);
+ if (determinant() != 0)
+ {
+ return;
+ }
+ }
+ }
+ }
+
+ private byte determinant()
+ {
+ // Simplified determinant calculation for small matrices
+// if (rank == 2)
+// {
+// return add(mul(data[0][0], data[1][1]), mul(data[0][1], data[1][0]));
+// }
+ // Add implementations for larger matrices as needed
+ throw new UnsupportedOperationException("Determinant for size " + rank + " not implemented");
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/GF16Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/GF16Utils.java
new file mode 100644
index 0000000000..40549bbe5d
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/GF16Utils.java
@@ -0,0 +1,149 @@
+package org.bouncycastle.pqc.crypto.snova;
+
+
+public class GF16Utils
+{
+ private static final byte[] F_STAR = {1, 2, 4, 8, 3, 6, 12, 11, 5, 10, 7, 14, 15, 13, 9};
+ private static final byte[] MT4B = new byte[256];
+ private static final byte[] INV4B = new byte[16];
+
+ static byte mt(int p, int q)
+ {
+ return MT4B[((p) << 4) ^ (q)];
+ }
+
+ static
+ {
+
+ // Initialize multiplication table
+ for (int i = 0; i < 15; i++)
+ {
+ for (int j = 0; j < 15; j++)
+ {
+ MT4B[(F_STAR[i]<<4) ^ F_STAR[j]] = F_STAR[(i + j) % 15];
+ }
+ }
+
+ int g = F_STAR[1], g_inv = F_STAR[14], gn = 1, gn_inv = 1;
+ // Initialize inversion table
+ INV4B[0] = 0;
+ INV4B[1] = 1;
+ for (int i = 0; i < 14; i++)
+ {
+ gn = mt(gn, g);
+ gn_inv = mt(gn_inv, g_inv);
+ INV4B[gn] = (byte)gn_inv;
+ }
+ }
+
+ public static void gf16mMul(byte[] a, byte[] b, byte[] c, int rank)
+ {
+
+ for (int i = 0; i < rank; i++)
+ {
+ for (int j = 0; j < rank; j++)
+ {
+ int cIndex = i * rank + j;
+ c[cIndex] = mt(getGf16m(a, i, 0, rank), getGf16m(b, 0, j, rank));
+ for (int k = 1; k < rank; ++k)
+ {
+ c[cIndex] ^= mt(getGf16m(a, i, k, rank), getGf16m(b, k, j, rank));
+ }
+ }
+ }
+ }
+
+ static byte getGf16m(byte[] gf16m, int x, int y, int rank)
+ {
+ return gf16m[x * rank + y];
+ }
+
+ /**
+ * Conversion 4 bit -> 32 bit representation
+ */
+ public static int gf16FromNibble(int idx)
+ {
+ int middle = idx | (idx << 4);
+ return ((middle & 0x41) | ((middle << 2) & 0x208));
+ }
+
+ public static void gf16mAdd(byte[] a, byte[] b, byte[] c, int rank)
+ {
+
+ for (int i = 0; i < rank; ++i)
+ {
+ for (int j = 0; j < rank; ++j)
+ {
+ int index = i * rank + j;
+ // GF16 addition is XOR operation (equivalent to GF(2^4) addition)
+ // Mask with 0x0F to ensure we only keep 4-bit values
+ c[index] = (byte)((a[index] ^ b[index]) & 0x0F);
+ }
+ }
+ }
+
+ public static byte mul(byte a, byte b)
+ {
+ return MT4B[(a & 0xF) << 4 | (b & 0xF)];
+ }
+
+ public static byte add(byte a, byte b)
+ {
+ return (byte)((a ^ b) & 0xF);
+ }
+
+ public static byte inv(byte a)
+ {
+ return INV4B[a & 0xF];
+ }
+
+ public static void convertBytesToGF16s(byte[] input, byte[] output, int gf16Count)
+ {
+ int pairs = gf16Count / 2;
+ for (int i = 0; i < pairs; i++)
+ {
+ output[i * 2] = (byte)(input[i] & 0x0F);
+ output[i * 2 + 1] = (byte)((input[i] >> 4) & 0x0F);
+ }
+ if (gf16Count % 2 == 1)
+ {
+ output[gf16Count - 1] = (byte)(input[pairs] & 0x0F);
+ }
+ }
+
+ public static void convertGF16sToBytes(byte[] output, byte[] gf16s, int gf16Count)
+ {
+ int pairs = gf16Count / 2;
+ for (int i = 0; i < pairs; i++)
+ {
+ output[i] = (byte)((gf16s[i * 2 + 1] << 4) | gf16s[i * 2]);
+ }
+ if (gf16Count % 2 == 1)
+ {
+ output[pairs] = gf16s[gf16Count - 1];
+ }
+ }
+
+ static GF16Matrix[][][] create3DArray(int d1, int d2, int d3, int rank) {
+ GF16Matrix[][][] arr = new GF16Matrix[d1][d2][d3];
+ for (int i = 0; i < d1; i++) {
+ for (int j = 0; j < d2; j++) {
+ for (int k = 0; k < d3; k++) {
+ arr[i][j][k] = new GF16Matrix(rank);
+ }
+ }
+ }
+ return arr;
+ }
+
+ static GF16Matrix[][] create2DArray(int d1, int d2, int rank) {
+ GF16Matrix[][] arr = new GF16Matrix[d1][d2];
+ for (int i = 0; i < d1; i++) {
+ for (int j = 0; j < d2; j++) {
+ arr[i][j] = new GF16Matrix(rank);
+ }
+ }
+ return arr;
+ }
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup1.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup1.java
new file mode 100644
index 0000000000..57a8a51c83
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup1.java
@@ -0,0 +1,29 @@
+package org.bouncycastle.pqc.crypto.snova;
+
+class MapGroup1
+{
+ public final GF16Matrix[][][] P11; // [m][v][v]
+ public final GF16Matrix[][][] P12; // [m][v][o]
+ public final GF16Matrix[][][] P21; // [m][o][v]
+ public final GF16Matrix[][] Aalpha; // [m][alpha]
+ public final GF16Matrix[][] Balpha; // [m][alpha]
+ public final GF16Matrix[][] Qalpha1;// [m][alpha]
+ public final GF16Matrix[][] Qalpha2;// [m][alpha]
+
+ public MapGroup1(SnovaParameters params)
+ {
+ int m = params.getM();
+ int v = params.getV();
+ int o = params.getO();
+ int alpha = params.getAlpha();
+ int rank = params.getL();
+
+ P11 = GF16Utils.create3DArray(m, v, v, rank);
+ P12 = GF16Utils.create3DArray(m, v, o, rank);
+ P21 = GF16Utils.create3DArray(m, o, v, rank);
+ Aalpha = GF16Utils.create2DArray(m, alpha, rank);
+ Balpha = GF16Utils.create2DArray(m, alpha, rank);
+ Qalpha1 = GF16Utils.create2DArray(m, alpha, rank);
+ Qalpha2 = GF16Utils.create2DArray(m, alpha, rank);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup2.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup2.java
new file mode 100644
index 0000000000..a78141e370
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup2.java
@@ -0,0 +1,20 @@
+package org.bouncycastle.pqc.crypto.snova;
+
+public class MapGroup2
+{
+ public final GF16Matrix[][][] F11; // [m][v][v]
+ public final GF16Matrix[][][] F12; // [m][v][o]
+ public final GF16Matrix[][][] F21; // [m][o][v]
+
+ public MapGroup2(SnovaParameters params)
+ {
+ int m = params.getM();
+ int v = params.getV();
+ int o = params.getO();
+ int rank = params.getL();
+
+ F11 = GF16Utils.create3DArray(m, v, v, rank);
+ F12 = GF16Utils.create3DArray(m, v, o, rank);
+ F21 = GF16Utils.create3DArray(m, o, v, rank);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/PublicKey.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/PublicKey.java
new file mode 100644
index 0000000000..a83b48f391
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/PublicKey.java
@@ -0,0 +1,14 @@
+package org.bouncycastle.pqc.crypto.snova;
+
+class PublicKey
+{
+ public final byte[] publicKeySeed;
+ public final byte[] P22;
+
+ public PublicKey(SnovaParameters params)
+ {
+ publicKeySeed = new byte[SnovaKeyPairGenerator.publicSeedLength];
+ P22 = new byte[(params.getM() * params.getO() * params.getO() * params.getL() * params.getL()) >> 1];
+ }
+}
+
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/PublicKeyExpanded.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/PublicKeyExpanded.java
new file mode 100644
index 0000000000..90ab90ecca
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/PublicKeyExpanded.java
@@ -0,0 +1,19 @@
+package org.bouncycastle.pqc.crypto.snova;
+
+class PublicKeyExpanded
+{
+ public final byte[] publicKeySeed;
+ public final GF16Matrix[][][] P22; // [m][o][o]
+ public final MapGroup1 map1;
+
+ public PublicKeyExpanded(SnovaParameters params)
+ {
+ int m = params.getM();
+ int o = params.getO();
+ int rank = params.getL();
+
+ publicKeySeed = new byte[SnovaKeyPairGenerator.publicSeedLength];
+ P22 = GF16Utils.create3DArray(m, o, o, rank);
+ map1 = new MapGroup1(params);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/PublicKeyExpandedPack.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/PublicKeyExpandedPack.java
new file mode 100644
index 0000000000..fc73b52dec
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/PublicKeyExpandedPack.java
@@ -0,0 +1,19 @@
+package org.bouncycastle.pqc.crypto.snova;
+
+class PublicKeyExpandedPack
+{
+ public final byte[] publicKeySeed;
+ public final byte[] packedData;
+
+ public PublicKeyExpandedPack(SnovaParameters params)
+ {
+ publicKeySeed = new byte[SnovaKeyPairGenerator.publicSeedLength];
+ int m = params.getM();
+ int o = params.getO();
+ int v = params.getV();
+ int alpha = params.getAlpha();
+ packedData = new byte[(((m * o * o) << 4) + // P22_t
+ (m * v * v * 16 + m * v * o * 16 + m * o * v * 16 + m * alpha * 16 * 4) // map_group1
+ + 1) >> 1];
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SKGF16.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SKGF16.java
new file mode 100644
index 0000000000..fe25ffefb6
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SKGF16.java
@@ -0,0 +1,36 @@
+package org.bouncycastle.pqc.crypto.snova;
+
+class SKGF16
+{
+ public final GF16Matrix[][] Aalpha; // [m][alpha]
+ public final GF16Matrix[][] Balpha; // [m][alpha]
+ public final GF16Matrix[][] Qalpha1; // [m][alpha]
+ public final GF16Matrix[][] Qalpha2; // [m][alpha]
+ public final GF16Matrix[][] T12; // [v][o]
+ public final GF16Matrix[][][] F11; // [m][v][v]
+ public final GF16Matrix[][][] F12; // [m][v][o]
+ public final GF16Matrix[][][] F21; // [m][o][v]
+ public final byte[] publicKeySeed;
+ public final byte[] privateKeySeed;
+
+ public SKGF16(SnovaParameters params)
+ {
+ int m = params.getM();
+ int v = params.getV();
+ int o = params.getO();
+ int alpha = params.getAlpha();
+ int rank = params.getL();
+
+ Aalpha = GF16Utils.create2DArray(m, alpha, rank);
+ Balpha = GF16Utils.create2DArray(m, alpha, rank);
+ Qalpha1 = GF16Utils.create2DArray(m, alpha, rank);
+ Qalpha2 = GF16Utils.create2DArray(m, alpha, rank);
+ T12 = GF16Utils.create2DArray(v, o, rank);
+ F11 = GF16Utils.create3DArray(m, v, v, rank);
+ F12 = GF16Utils.create3DArray(m, v, o, rank);
+ F21 = GF16Utils.create3DArray(m, o, v, rank);
+
+ publicKeySeed = new byte[SnovaKeyPairGenerator.publicSeedLength];
+ privateKeySeed = new byte[SnovaKeyPairGenerator.privateSeedLength];
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java
new file mode 100644
index 0000000000..60bfe3f4c7
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java
@@ -0,0 +1,69 @@
+package org.bouncycastle.pqc.crypto.snova;
+
+public class SnovaEngine
+{
+ private final SnovaParameters params;
+ private final int l;
+ private final int lsq;
+ final byte[][] S;
+ final int[][] xS;
+
+ public SnovaEngine(SnovaParameters params)
+ {
+ this.params = params;
+ this.l = params.getL();
+ this.lsq = l * l;
+ S = new byte[l][lsq];
+ xS = new int[l][lsq];
+ be_aI(S[0], (byte)1);
+ beTheS(S[1]);
+ for (int index = 2; index < l; ++index)
+ {
+ GF16Utils.gf16mMul(S[index - 1], S[1], S[index], l);
+ }
+
+ for (int index = 0; index < l; ++index)
+ {
+ for (int ij = 0; ij < lsq; ++ij)
+ {
+ xS[index][ij] = GF16Utils.gf16FromNibble(S[index][ij]);
+ }
+ }
+ }
+
+ public void be_aI(byte[] target, byte a)
+ {
+ // Mask 'a' to ensure it's a valid 4-bit GF16 element
+ a = (byte)(a & 0x0F);
+
+ for (int i = 0; i < l; ++i)
+ {
+ for (int j = 0; j < l; ++j)
+ {
+ int index = i * l + j;
+ target[index] = (i == j) ? a : (byte)0;
+ }
+ }
+ }
+
+ private void beTheS(byte[] target)
+ {
+ // Set all elements to 8 - (i + j) in GF16 (4-bit values)
+ for (int i = 0; i < l; ++i)
+ {
+ for (int j = 0; j < l; ++j)
+ {
+ int value = 8 - (i + j);
+ target[i * l + j] = (byte)(value & 0x0F); // Mask to 4 bits
+ }
+ }
+
+ // Special case for rank 5
+ if (l == 5)
+ {
+ target[4 * 5 + 4] = (byte)(9 & 0x0F); // Set (4,4) to 9
+ }
+ }
+
+
+}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyElements.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyElements.java
new file mode 100644
index 0000000000..e9f44db7d9
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyElements.java
@@ -0,0 +1,17 @@
+package org.bouncycastle.pqc.crypto.snova;
+
+class SnovaKeyElements
+{
+ public final MapGroup1 map1;
+ public final GF16Matrix[][] T12; // [v][o]
+ public final MapGroup2 map2;
+ public final PublicKey publicKey;
+
+ public SnovaKeyElements(SnovaParameters params)
+ {
+ map1 = new MapGroup1(params);
+ T12 = GF16Utils.create2DArray(params.getV(), params.getO(), params.getL());
+ map2 = new MapGroup2(params);
+ publicKey = new PublicKey(params);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyGenerationParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyGenerationParameters.java
new file mode 100644
index 0000000000..ef25e9605d
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyGenerationParameters.java
@@ -0,0 +1,22 @@
+package org.bouncycastle.pqc.crypto.snova;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.KeyGenerationParameters;
+
+public class SnovaKeyGenerationParameters
+ extends KeyGenerationParameters
+{
+ private final SnovaParameters params;
+
+ public SnovaKeyGenerationParameters(SecureRandom random, SnovaParameters params)
+ {
+ super(random, -1); // Security parameter not used directly
+ this.params = params;
+ }
+
+ public SnovaParameters getParameters()
+ {
+ return params;
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyPairGenerator.java
new file mode 100644
index 0000000000..23bc7c90db
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyPairGenerator.java
@@ -0,0 +1,283 @@
+package org.bouncycastle.pqc.crypto.snova;
+
+import java.io.ByteArrayOutputStream;
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bouncycastle.crypto.KeyGenerationParameters;
+import org.bouncycastle.crypto.digests.SHAKEDigest;
+import org.bouncycastle.util.Arrays;
+
+public class SnovaKeyPairGenerator
+ implements AsymmetricCipherKeyPairGenerator
+{
+ private SnovaEngine engine;
+ private static final int seedLength = 48;
+ static final int publicSeedLength = 16;
+ static final int privateSeedLength = 32;
+ private SnovaParameters params;
+ private SecureRandom random;
+ private boolean initialized;
+
+ @Override
+ public void init(KeyGenerationParameters param)
+ {
+ SnovaKeyGenerationParameters snovaParams = (SnovaKeyGenerationParameters)param;
+ this.params = snovaParams.getParameters();
+ this.random = snovaParams.getRandom();
+ this.initialized = true;
+ this.engine = new SnovaEngine(params);
+ }
+
+ @Override
+ public AsymmetricCipherKeyPair generateKeyPair()
+ {
+ if (!initialized)
+ {
+ throw new IllegalStateException("SNOVA key pair generator not initialized");
+ }
+
+ // Generate seed pair according to SNOVA specifications
+ byte[] seedPair = new byte[seedLength];
+ random.nextBytes(seedPair);
+
+ byte[] pk = new byte[publicSeedLength];
+ byte[] sk = new byte[privateSeedLength];
+
+ byte[] ptPublicKeySeed = Arrays.copyOfRange(seedPair, 0, publicSeedLength);
+ byte[] ptPrivateKeySeed = Arrays.copyOfRange(seedPair, publicSeedLength, seedPair.length);
+
+ if (params.isSkIsSeed())
+ {
+ generateKeysSSK(pk, sk, ptPublicKeySeed, ptPrivateKeySeed);
+ }
+ else
+ {
+ generateKeysESK(pk, sk, ptPublicKeySeed, ptPrivateKeySeed);
+ }
+
+ return new AsymmetricCipherKeyPair(
+ new SnovaPublicKeyParameters(pk),
+ new SnovaPrivateKeyParameters(sk)
+ );
+ }
+
+ private void generateKeysSSK(byte[] pk, byte[] sk, byte[] ptPublicKeySeed, byte[] ptPrivateKeySeed)
+ {
+ // Implementation based on C's generate_keys_ssk
+ System.arraycopy(ptPublicKeySeed, 0, sk, 0, ptPublicKeySeed.length);
+ System.arraycopy(ptPrivateKeySeed, 0, sk, ptPublicKeySeed.length, ptPrivateKeySeed.length);
+
+ // Actual key generation would go here using BC's SHAKE/AES implementations
+ // This would include the matrix operations from the C code
+ generatePublicKey(pk, ptPublicKeySeed, ptPrivateKeySeed);
+ }
+
+ private void generateKeysESK(byte[] pk, byte[] esk, byte[] ptPublicKeySeed, byte[] ptPrivateKeySeed)
+ {
+ // Implementation based on C's generate_keys_esk
+ // Actual expanded key generation would go here
+ generatePublicKey(pk, ptPublicKeySeed, ptPrivateKeySeed);
+ packPrivateKey(esk, ptPublicKeySeed, ptPrivateKeySeed);
+ }
+
+ private void packPrivateKey(byte[] esk, byte[] ptPublicKeySeed, byte[] ptPrivateKeySeed)
+ {
+ SnovaKeyElements keyElements = new SnovaKeyElements(params);
+ generateKeysCore(keyElements, ptPublicKeySeed, ptPrivateKeySeed);
+
+ // Serialize all components
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+ // Serialize map components
+// serializeMatrixGroup(bos, keyElements.map1.Aalpha);
+// serializeMatrixGroup(bos, keyElements.map1.Balpha);
+// serializeMatrixGroup(bos, keyElements.map1.Qalpha1);
+// serializeMatrixGroup(bos, keyElements.map1.Qalpha2);
+
+ // Serialize T12
+ for (GF16Matrix[] row : keyElements.T12)
+ {
+ for (GF16Matrix matrix : row)
+ {
+ serializeMatrix(bos, matrix);
+ }
+ }
+
+ // Add public and private seeds
+ bos.write(ptPublicKeySeed, 0, ptPublicKeySeed.length);
+ bos.write(ptPrivateKeySeed, 0, ptPrivateKeySeed.length);
+
+ System.arraycopy(bos.toByteArray(), 0, esk, 0, esk.length);
+ }
+
+ private void serializeMatrixGroup(ByteArrayOutputStream bos, GF16Matrix[][][] group)
+ {
+ for (GF16Matrix[][] dim1 : group)
+ {
+ for (GF16Matrix[] dim2 : dim1)
+ {
+ for (GF16Matrix matrix : dim2)
+ {
+ serializeMatrix(bos, matrix);
+ }
+ }
+ }
+ }
+
+ private void serializeMatrix(ByteArrayOutputStream bos, GF16Matrix matrix)
+ {
+// byte[] temp = new byte[(matrix.size * matrix.size + 1) / 2];
+// byte[] gf16s = new byte[matrix.size * matrix.size];
+//
+// int idx = 0;
+// for (int i = 0; i < matrix.size; i++) {
+// for (int j = 0; j < matrix.size; j++) {
+// gf16s[idx++] = matrix.get(i, j);
+// }
+// }
+//
+// GF16Utils.convertGF16sToBytes(temp, gf16s, gf16s.length);
+// bos.write(temp, 0, temp.length);
+ }
+
+ private void generatePublicKey(byte[] pk, byte[] ptPublicKeySeed, byte[] ptPrivateKeySeed)
+ {
+
+ // Generate key elements
+ SnovaKeyElements keyElements = new SnovaKeyElements(params);
+ generateKeysCore(keyElements, ptPublicKeySeed, ptPrivateKeySeed);
+
+ // Pack public key components
+ //packPublicKey(pk, keyElements);
+ }
+
+ private void generateKeysCore(SnovaKeyElements keyElements, byte[] pkSeed, byte[] skSeed)
+ {
+ // Generate T12 matrix
+ genSeedsAndT12(keyElements.T12, skSeed);
+
+ // Generate map components
+// genABQP(keyElements.map1, pkSeed);
+//
+// // Generate F matrices
+// genF(keyElements.map2, keyElements.map1, keyElements.T12);
+
+ // Generate P22 matrix
+// genP22(keyElements.pk.P22, keyElements.T12, keyElements.map1.P21, keyElements.map2.F12);
+ }
+
+ private void genSeedsAndT12(GF16Matrix[][] T12, byte[] skSeed)
+ {
+ int bytesPrngPrivate = (params.getV() * params.getO() * params.getL() + 1) >>> 1;
+ int gf16sPrngPrivate = params.getV() * params.getO() * params.getL();
+ byte[] prngOutput = new byte[bytesPrngPrivate];
+
+ // Generate PRNG output using SHAKE-256
+ SHAKEDigest shake = new SHAKEDigest(256);
+ shake.update(skSeed, 0, skSeed.length);
+ shake.doFinal(prngOutput, 0, prngOutput.length);
+
+ // Convert bytes to GF16 array
+ byte[] gf16PrngOutput = new byte[gf16sPrngPrivate];
+ GF16Utils.convertBytesToGF16s(prngOutput, gf16PrngOutput, gf16sPrngPrivate);
+
+ // Generate T12 matrices
+ int ptr = 0;
+ for (int j = 0; j < params.getV(); j++)
+ {
+ for (int k = 0; k < params.getO(); k++)
+ {
+ //gen_a_FqS_ct
+ GF16Matrix matrix = new GF16Matrix(params.getL());
+ for (int i = 0; i < params.getL(); i++)
+ {
+ for (int m = 0; m < params.getL(); m++)
+ {
+ matrix.set(i, m, gf16PrngOutput[ptr++]);
+ }
+ }
+ matrix.makeInvertible();
+ T12[j][k] = matrix;
+ }
+ }
+ }
+//
+// private void genABQP(MapGroup1 map1, byte[] pkSeed)
+// {
+// byte[] prngOutput = new byte[params.getBytesPrngPublic()];
+//
+// if (params.isPkExpandShake()) {
+// // SHAKE-based expansion
+// SHAKEDigest shake = new SHAKEDigest(256);
+// shake.update(pkSeed, 0, pkSeed.length);
+// shake.doFinal(prngOutput, 0, prngOutput.length);
+// } else {
+// // AES-CTR-based expansion
+// AESEngine aes = new AESEngine();
+// aes.init(true, new KeyParameter(pkSeed));
+// for (int i = 0; i < prngOutput.length; i += 16) {
+// byte[] block = new byte[16];
+// aes.processBlock(block, 0, block, 0);
+// System.arraycopy(block, 0, prngOutput, i, Math.min(16, prngOutput.length - i));
+// }
+// }
+//
+// // Convert bytes to GF16 structures
+// GF16Utils.convertBytesToGF16s(prngOutput, map1);
+//
+// // Post-processing for invertible matrices
+// for (GF16Matrix matrix : map1.Aalpha) {
+// GF16Utils.makeInvertible(matrix);
+// }
+// for (GF16Matrix matrix : map1.Balpha) {
+// GF16Utils.makeInvertible(matrix);
+// }
+// }
+
+// private void genF(MapGroup2 map2, MapGroup1 map1, GF16Matrix[][] T12)
+// {
+// // Matrix operations from C code's gen_F_ref
+// // Clone initial matrices
+// System.arraycopy(map1.P11, 0, map2.F11, 0, map1.P11.length);
+// System.arraycopy(map1.P12, 0, map2.F12, 0, map1.P12.length);
+// System.arraycopy(map1.P21, 0, map2.F21, 0, map1.P21.length);
+//
+// // Perform matrix multiplications and additions
+// GF16Matrix temp = new GF16Matrix(params.getL());
+// for (int i = 0; i < params.getM(); i++) {
+// for (int j = 0; j < params.getV(); j++) {
+// for (int k = 0; k < params.getO(); k++) {
+// for (int idx = 0; idx < params.getV(); idx++) {
+// GF16Matrix.mul(map1.P11[i][j][idx], T12[idx][k], temp);
+// GF16Matrix.add(map2.F12[i][j][k], temp, map2.F12[i][j][k]);
+// }
+// }
+// }
+// }
+// }
+
+ private void genP22(byte[] outP22, GF16Matrix[][] T12, GF16Matrix[][][] P21, GF16Matrix[][][] F12)
+ {
+// GF16Matrix[][][] P22 = new GF16Matrix[params.getM()][params.getO()][params.getO()];
+// GF16Matrix temp1 = new GF16Matrix(params.getL());
+// GF16Matrix temp2 = new GF16Matrix(params.getL());
+//
+// for (int i = 0; i < params.getM(); i++) {
+// for (int j = 0; j < params.getO(); j++) {
+// for (int k = 0; k < params.getO(); k++) {
+// for (int idx = 0; idx < params.getV(); idx++) {
+// GF16Matrix.mul(T12[idx][j], F12[i][idx][k], temp1);
+// GF16Matrix.mul(P21[i][j][idx], T12[idx][k], temp2);
+// GF16Matrix.add(temp1, temp2, temp1);
+// GF16Matrix.add(P22[i][j][k], temp1, P22[i][j][k]);
+// }
+// }
+// }
+// }
+//
+// // Convert GF16 matrices to bytes
+// GF16Utils.convertGF16sToBytes(P22, outP22);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaParameters.java
new file mode 100644
index 0000000000..90436bab3c
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaParameters.java
@@ -0,0 +1,167 @@
+package org.bouncycastle.pqc.crypto.snova;
+
+public class SnovaParameters
+{
+ public static final SnovaParameters SNOVA_24_5_16_4_SSK =
+ new SnovaParameters("SNOVA_24_5_16_4_SSK", 24, 5, 4, true, false);
+ public static final SnovaParameters SNOVA_24_5_16_4_ESK =
+ new SnovaParameters("SNOVA_24_5_16_4_ESK", 24, 5, 4, false, false);
+ public static final SnovaParameters SNOVA_24_5_16_4_SHAKE_SSK =
+ new SnovaParameters("SNOVA_24_5_16_4_SHAKE_SSK", 24, 5, 4, true, true);
+ public static final SnovaParameters SNOVA_24_5_16_4_SHAKE_ESK =
+ new SnovaParameters("SNOVA_24_5_16_4_SHAKE_ESK", 24, 5, 4, false, true);
+
+ public static final SnovaParameters SNOVA_24_5_16_5_SSK =
+ new SnovaParameters("SNOVA_24_5_16_5_SSK", 24, 5, 5, true, false);
+ public static final SnovaParameters SNOVA_24_5_16_5_ESK =
+ new SnovaParameters("SNOVA_24_5_16_5_ESK", 24, 5, 5, false, false);
+ public static final SnovaParameters SNOVA_24_5_16_5_SHAKE_SSK =
+ new SnovaParameters("SNOVA_24_5_16_5_SHAKE_SSK", 24, 5, 5, true, true);
+ public static final SnovaParameters SNOVA_24_5_16_5_SHAKE_ESK =
+ new SnovaParameters("SNOVA_24_5_16_5_SHAKE_ESK", 24, 5, 5, false, true);
+
+ public static final SnovaParameters SNOVA_25_8_16_3_SSK =
+ new SnovaParameters("SNOVA_25_8_16_3_SSK", 25, 8, 3, true, false);
+ public static final SnovaParameters SNOVA_25_8_16_3_ESK =
+ new SnovaParameters("SNOVA_25_8_16_3_ESK", 25, 8, 3, false, false);
+ public static final SnovaParameters SNOVA_25_8_16_3_SHAKE_SSK =
+ new SnovaParameters("SNOVA_25_8_16_3_SHAKE_SSK", 25, 8, 3, true, true);
+ public static final SnovaParameters SNOVA_25_8_16_3_SHAKE_ESK =
+ new SnovaParameters("SNOVA_25_8_16_3_SHAKE_ESK", 25, 8, 3, false, true);
+
+ public static final SnovaParameters SNOVA_29_6_16_5_SSK =
+ new SnovaParameters("SNOVA_29_6_16_5_SSK", 29, 6, 5, true, false);
+ public static final SnovaParameters SNOVA_29_6_16_5_ESK =
+ new SnovaParameters("SNOVA_29_6_16_5_ESK", 29, 6, 5, false, false);
+ public static final SnovaParameters SNOVA_29_6_16_5_SHAKE_SSK =
+ new SnovaParameters("SNOVA_29_6_16_5_SHAKE_SSK", 29, 6, 5, true, true);
+ public static final SnovaParameters SNOVA_29_6_16_5_SHAKE_ESK =
+ new SnovaParameters("SNOVA_29_6_16_5_SHAKE_ESK", 29, 6, 5, false, true);
+
+ public static final SnovaParameters SNOVA_37_8_16_4_SSK =
+ new SnovaParameters("SNOVA_37_8_16_4_SSK", 37, 8, 4, true, false);
+ public static final SnovaParameters SNOVA_37_8_16_4_ESK =
+ new SnovaParameters("SNOVA_37_8_16_4_ESK", 37, 8, 4, false, false);
+ public static final SnovaParameters SNOVA_37_8_16_4_SHAKE_SSK =
+ new SnovaParameters("SNOVA_37_8_16_4_SHAKE_SSK", 37, 8, 4, true, true);
+ public static final SnovaParameters SNOVA_37_8_16_4_SHAKE_ESK =
+ new SnovaParameters("SNOVA_37_8_16_4_SHAKE_ESK", 37, 8, 4, false, true);
+
+ // SNOVA_37_17_16_2 variants
+ public static final SnovaParameters SNOVA_37_17_16_2_SSK =
+ new SnovaParameters("SNOVA_37_17_16_2_SSK", 37, 17, 2, true, false);
+ public static final SnovaParameters SNOVA_37_17_16_2_ESK =
+ new SnovaParameters("SNOVA_37_17_16_2_ESK", 37, 17, 2, false, false);
+ public static final SnovaParameters SNOVA_37_17_16_2_SHAKE_SSK =
+ new SnovaParameters("SNOVA_37_17_16_2_SHAKE_SSK", 37, 17, 2, true, true);
+ public static final SnovaParameters SNOVA_37_17_16_2_SHAKE_ESK =
+ new SnovaParameters("SNOVA_37_17_16_2_SHAKE_ESK", 37, 17, 2, false, true);
+
+ // SNOVA_49_11_16_3 variants
+ public static final SnovaParameters SNOVA_49_11_16_3_SSK =
+ new SnovaParameters("SNOVA_49_11_16_3_SSK", 49, 11, 3, true, false);
+ public static final SnovaParameters SNOVA_49_11_16_3_ESK =
+ new SnovaParameters("SNOVA_49_11_16_3_ESK", 49, 11, 3, false, false);
+ public static final SnovaParameters SNOVA_49_11_16_3_SHAKE_SSK =
+ new SnovaParameters("SNOVA_49_11_16_3_SHAKE_SSK", 49, 11, 3, true, true);
+ public static final SnovaParameters SNOVA_49_11_16_3_SHAKE_ESK =
+ new SnovaParameters("SNOVA_49_11_16_3_SHAKE_ESK", 49, 11, 3, false, true);
+
+ // SNOVA_56_25_16_2 variants
+ public static final SnovaParameters SNOVA_56_25_16_2_SSK =
+ new SnovaParameters("SNOVA_56_25_16_2_SSK", 56, 25, 2, true, false);
+ public static final SnovaParameters SNOVA_56_25_16_2_ESK =
+ new SnovaParameters("SNOVA_56_25_16_2_ESK", 56, 25, 2, false, false);
+ public static final SnovaParameters SNOVA_56_25_16_2_SHAKE_SSK =
+ new SnovaParameters("SNOVA_56_25_16_2_SHAKE_SSK", 56, 25, 2, true, true);
+ public static final SnovaParameters SNOVA_56_25_16_2_SHAKE_ESK =
+ new SnovaParameters("SNOVA_56_25_16_2_SHAKE_ESK", 56, 25, 2, false, true);
+
+ // SNOVA_60_10_16_4 variants
+ public static final SnovaParameters SNOVA_60_10_16_4_SSK =
+ new SnovaParameters("SNOVA_60_10_16_4_SSK", 60, 10, 4, true, false);
+ public static final SnovaParameters SNOVA_60_10_16_4_ESK =
+ new SnovaParameters("SNOVA_60_10_16_4_ESK", 60, 10, 4, false, false);
+ public static final SnovaParameters SNOVA_60_10_16_4_SHAKE_SSK =
+ new SnovaParameters("SNOVA_60_10_16_4_SHAKE_SSK", 60, 10, 4, true, true);
+ public static final SnovaParameters SNOVA_60_10_16_4_SHAKE_ESK =
+ new SnovaParameters("SNOVA_60_10_16_4_SHAKE_ESK", 60, 10, 4, false, true);
+
+ // SNOVA_66_15_16_4 variants
+ public static final SnovaParameters SNOVA_66_15_16_4_SSK =
+ new SnovaParameters("SNOVA_66_15_16_4_SSK", 66, 15, 4, true, false);
+ public static final SnovaParameters SNOVA_66_15_16_4_ESK =
+ new SnovaParameters("SNOVA_66_15_16_4_ESK", 66, 15, 4, false, false);
+ public static final SnovaParameters SNOVA_66_15_16_4_SHAKE_SSK =
+ new SnovaParameters("SNOVA_66_15_16_4_SHAKE_SSK", 66, 15, 4, true, true);
+ public static final SnovaParameters SNOVA_66_15_16_4_SHAKE_ESK =
+ new SnovaParameters("SNOVA_66_15_16_4_SHAKE_ESK", 66, 15, 4, false, true);
+
+ // SNOVA_75_33_16_2 variants
+ public static final SnovaParameters SNOVA_75_33_16_2_SSK =
+ new SnovaParameters("SNOVA_75_33_16_2_SSK", 75, 33, 2, true, false);
+ public static final SnovaParameters SNOVA_75_33_16_2_ESK =
+ new SnovaParameters("SNOVA_75_33_16_2_ESK", 75, 33, 2, false, false);
+ public static final SnovaParameters SNOVA_75_33_16_2_SHAKE_SSK =
+ new SnovaParameters("SNOVA_75_33_16_2_SHAKE_SSK", 75, 33, 2, true, true);
+ public static final SnovaParameters SNOVA_75_33_16_2_SHAKE_ESK =
+ new SnovaParameters("SNOVA_75_33_16_2_SHAKE_ESK", 75, 33, 2, false, true);
+
+ private final String name;
+ private final int v;
+ private final int o;
+ private final int l;
+ private final boolean skIsSeed;
+ private final boolean pkExpandShake;
+
+ public SnovaParameters(String name, int v, int o, int l, boolean skIsSeed, boolean pkExpandShake)
+ {
+ this.name = name;
+ this.v = v;
+ this.o = o;
+ this.l = l;
+ this.skIsSeed = skIsSeed;
+ this.pkExpandShake = pkExpandShake;
+ }
+
+ // Getter methods
+ public String getName()
+ {
+ return name;
+ }
+
+ public int getV()
+ {
+ return v;
+ }
+
+ public int getO()
+ {
+ return o;
+ }
+
+ public int getL()
+ {
+ return l;
+ }
+
+ public boolean isSkIsSeed()
+ {
+ return skIsSeed;
+ }
+
+ public boolean isPkExpandShake()
+ {
+ return pkExpandShake;
+ }
+
+ public int getM()
+ {
+ return o;
+ }
+
+ public int getAlpha()
+ {
+ return l * l + l;
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaPrivateKeyParameters.java
new file mode 100644
index 0000000000..bcd35f51cf
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaPrivateKeyParameters.java
@@ -0,0 +1,26 @@
+package org.bouncycastle.pqc.crypto.snova;
+
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.util.Arrays;
+
+public class SnovaPrivateKeyParameters
+ extends AsymmetricKeyParameter
+{
+ private final byte[] privateKey;
+
+ public SnovaPrivateKeyParameters(byte[] privateKey)
+ {
+ super(true);
+ this.privateKey = Arrays.clone(privateKey);
+ }
+
+ public byte[] getPrivateKey()
+ {
+ return Arrays.clone(privateKey);
+ }
+
+ public byte[] getEncoded()
+ {
+ return Arrays.clone(privateKey);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaPublicKeyParameters.java
new file mode 100644
index 0000000000..99f9c9a8d8
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaPublicKeyParameters.java
@@ -0,0 +1,26 @@
+package org.bouncycastle.pqc.crypto.snova;
+
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.util.Arrays;
+
+public class SnovaPublicKeyParameters
+ extends AsymmetricKeyParameter
+{
+ private final byte[] publicKey;
+
+ public SnovaPublicKeyParameters(byte[] publicKey)
+ {
+ super(false);
+ this.publicKey = Arrays.clone(publicKey);
+ }
+
+ public byte[] getPublicKey()
+ {
+ return Arrays.clone(publicKey);
+ }
+
+ public byte[] getEncoded()
+ {
+ return Arrays.clone(publicKey);
+ }
+}
diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/SnovaTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/SnovaTest.java
new file mode 100644
index 0000000000..b02b1ab703
--- /dev/null
+++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/SnovaTest.java
@@ -0,0 +1,88 @@
+package org.bouncycastle.pqc.crypto.test;
+
+import java.security.SecureRandom;
+
+import junit.framework.TestCase;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Signer;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.pqc.crypto.MessageSigner;
+import org.bouncycastle.pqc.crypto.snova.SnovaKeyGenerationParameters;
+import org.bouncycastle.pqc.crypto.snova.SnovaKeyPairGenerator;
+import org.bouncycastle.pqc.crypto.snova.SnovaParameters;
+import org.bouncycastle.pqc.crypto.snova.SnovaPrivateKeyParameters;
+import org.bouncycastle.pqc.crypto.snova.SnovaPublicKeyParameters;
+
+
+public class SnovaTest
+ extends TestCase
+{
+ public static void main(String[] args)
+ throws Exception
+ {
+ SnovaTest test = new SnovaTest();
+ test.testTestVectors();
+ }
+
+ private static final SnovaParameters[] PARAMETER_SETS = new SnovaParameters[]
+ {
+ SnovaParameters.SNOVA_24_5_16_4_ESK,
+ };
+
+ private static final String[] files = new String[]{
+ "PQCsignKAT_SNOVA_24_5_4_ESK.rsp",
+ };
+
+
+ public void testTestVectors()
+ throws Exception
+ {
+ long start = System.currentTimeMillis();
+ TestUtils.testTestVector(false, false, "pqc/crypto/snova", files, new TestUtils.KeyGenerationOperation()
+ {
+ @Override
+ public SecureRandom getSecureRanom(byte[] seed)
+ {
+ return new NISTSecureRandom(seed, null);
+ }
+
+ @Override
+ public AsymmetricCipherKeyPairGenerator getAsymmetricCipherKeyPairGenerator(int fileIndex, SecureRandom random)
+ {
+ SnovaParameters parameters = PARAMETER_SETS[fileIndex];
+
+ SnovaKeyPairGenerator kpGen = new SnovaKeyPairGenerator();
+ kpGen.init(new SnovaKeyGenerationParameters(random, parameters));
+ return kpGen;
+ }
+
+ @Override
+ public byte[] getPublicKeyEncoded(AsymmetricKeyParameter pubParams)
+ {
+ return ((SnovaPublicKeyParameters)pubParams).getEncoded();
+ }
+
+ @Override
+ public byte[] getPrivateKeyEncoded(CipherParameters privParams)
+ {
+ return ((SnovaPrivateKeyParameters)privParams).getEncoded();
+ }
+
+ @Override
+ public Signer getSigner()
+ {
+ return null;
+ }
+
+ @Override
+ public MessageSigner getMessageSigner()
+ {
+ return null;//new SnovaSigner();
+ }
+ });
+ long end = System.currentTimeMillis();
+ System.out.println("time cost: " + (end - start) + "\n");
+ }
+}
+
diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/TestUtils.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/TestUtils.java
index 743f936caf..986de28ed2 100644
--- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/TestUtils.java
+++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/TestUtils.java
@@ -1,9 +1,155 @@
package org.bouncycastle.pqc.crypto.test;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.security.SecureRandom;
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.Assert;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Signer;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.pqc.crypto.MessageSigner;
+import org.bouncycastle.pqc.crypto.util.PrivateKeyFactory;
+import org.bouncycastle.pqc.crypto.util.PrivateKeyInfoFactory;
+import org.bouncycastle.pqc.crypto.util.PublicKeyFactory;
+import org.bouncycastle.pqc.crypto.util.SubjectPublicKeyInfoFactory;
+import org.bouncycastle.test.TestResourceFinder;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.encoders.Hex;
+
class TestUtils
{
static boolean parseBoolean(String value)
{
return "true".equalsIgnoreCase(value);
}
+
+ public interface KeyGenerationOperation
+ {
+ SecureRandom getSecureRanom(byte[] seed);
+
+ AsymmetricCipherKeyPairGenerator getAsymmetricCipherKeyPairGenerator(int fileIndex, SecureRandom random);
+
+ byte[] getPublicKeyEncoded(AsymmetricKeyParameter pubParams);
+
+ byte[] getPrivateKeyEncoded(CipherParameters privParams);
+
+ Signer getSigner();
+
+ MessageSigner getMessageSigner();
+ }
+
+ public static void testTestVector(boolean enableFactory, boolean isSigner, String homeDir, String[] files, KeyGenerationOperation operation)
+ throws Exception
+ {
+ for (int fileIndex = 0; fileIndex != files.length; fileIndex++)
+ {
+ String name = files[fileIndex];
+ InputStream src = TestResourceFinder.findTestResource(homeDir, name);
+ BufferedReader bin = new BufferedReader(new InputStreamReader(src));
+
+ String line;
+ HashMap buf = new HashMap();
+ while ((line = bin.readLine()) != null)
+ {
+ line = line.trim();
+
+ if (line.startsWith("#"))
+ {
+ continue;
+ }
+ if (line.length() == 0)
+ {
+ if (buf.size() > 0)
+ {
+// int count = Integer.parseInt(buf.get("count"));
+// if (count == 99)
+// {
+// System.out.println("break");
+// }
+ byte[] seed = Hex.decode((String)buf.get("seed"));
+ byte[] pk = Hex.decode((String)buf.get("pk"));
+ byte[] sk = Hex.decode((String)buf.get("sk"));
+ byte[] message = Hex.decode((String)buf.get("msg"));
+ byte[] signature = Hex.decode((String)buf.get("sm"));
+
+ SecureRandom random = operation.getSecureRanom(seed);
+
+ AsymmetricCipherKeyPairGenerator kpGen = operation.getAsymmetricCipherKeyPairGenerator(fileIndex, random);
+
+ //
+ // Generate keys and test.
+ //
+ AsymmetricCipherKeyPair kp = kpGen.generateKeyPair();
+ AsymmetricKeyParameter pubParams;
+ CipherParameters privParams;
+ if (enableFactory)
+ {
+ pubParams = PublicKeyFactory.createKey(
+ SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(kp.getPublic()));
+ privParams = PrivateKeyFactory.createKey(
+ PrivateKeyInfoFactory.createPrivateKeyInfo(kp.getPrivate()));
+ }
+ else
+ {
+ pubParams = kp.getPublic();
+ privParams = kp.getPrivate();
+ }
+
+ Assert.assertTrue(name + ": public key", Arrays.areEqual(pk, operation.getPublicKeyEncoded(pubParams)));
+ Assert.assertTrue(name + ": secret key", Arrays.areEqual(sk, operation.getPrivateKeyEncoded(privParams)));
+
+ byte[] sigGenerated;
+ privParams = new ParametersWithRandom(privParams, random);
+ if (isSigner)
+ {
+ Signer signer = operation.getSigner();
+ signer.init(true, privParams);
+ signer.update(message, 0, message.length);
+ sigGenerated = signer.generateSignature();
+ }
+ else
+ {
+ MessageSigner signer = operation.getMessageSigner();
+ signer.init(true, privParams);
+ sigGenerated = signer.generateSignature(message);
+ }
+
+ Assert.assertTrue(Arrays.areEqual(sigGenerated, signature));
+
+ if (isSigner)
+ {
+ Signer signer = operation.getSigner();
+ signer.init(false, pubParams);
+ signer.update(message, 0, message.length);
+ Assert.assertTrue(signer.verifySignature(sigGenerated));
+ }
+ else
+ {
+ MessageSigner signer = operation.getMessageSigner();
+ signer.init(false, pubParams);
+ Assert.assertTrue(signer.verifySignature(message, sigGenerated));
+ }
+ //System.out.println("Count " + count + " pass");
+ }
+ buf.clear();
+ continue;
+ }
+
+ int a = line.indexOf("=");
+ if (a > -1)
+ {
+ buf.put(line.substring(0, a).trim(), line.substring(a + 1).trim());
+ }
+ }
+ }
+ }
}
From cf05a00a259408921295135ed6b141738401e5bf Mon Sep 17 00:00:00 2001
From: David Hook
Date: Fri, 7 Mar 2025 13:10:36 +1100
Subject: [PATCH 156/890] added PKCS#10 PQC tests.
---
.../org/bouncycastle/cert/test/AllTests.java | 1 +
.../bouncycastle/cert/test/PQCPKCS10Test.java | 147 ++++++++++++++++++
2 files changed, 148 insertions(+)
create mode 100644 pkix/src/test/java/org/bouncycastle/cert/test/PQCPKCS10Test.java
diff --git a/pkix/src/test/java/org/bouncycastle/cert/test/AllTests.java b/pkix/src/test/java/org/bouncycastle/cert/test/AllTests.java
index 4034d9d018..39b7bdaeb5 100644
--- a/pkix/src/test/java/org/bouncycastle/cert/test/AllTests.java
+++ b/pkix/src/test/java/org/bouncycastle/cert/test/AllTests.java
@@ -61,6 +61,7 @@ public static Test suite()
suite.addTestSuite(BcAttrCertTest.class);
suite.addTestSuite(BcCertTest.class);
suite.addTestSuite(BcPKCS10Test.class);
+ suite.addTestSuite(PQCPKCS10Test.class);
suite.addTest(ConverterTest.suite());
return new BCTestSetup(suite);
diff --git a/pkix/src/test/java/org/bouncycastle/cert/test/PQCPKCS10Test.java b/pkix/src/test/java/org/bouncycastle/cert/test/PQCPKCS10Test.java
new file mode 100644
index 0000000000..c81c84123b
--- /dev/null
+++ b/pkix/src/test/java/org/bouncycastle/cert/test/PQCPKCS10Test.java
@@ -0,0 +1,147 @@
+package org.bouncycastle.cert.test;
+
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.Security;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+
+import javax.security.auth.x500.X500Principal;
+
+import junit.framework.TestCase;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x500.X500NameBuilder;
+import org.bouncycastle.asn1.x500.style.BCStyle;
+import org.bouncycastle.asn1.x509.BasicConstraints;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.cert.X509v3CertificateBuilder;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
+import org.bouncycastle.jcajce.spec.MLDSAParameterSpec;
+import org.bouncycastle.jcajce.spec.MLKEMParameterSpec;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
+import org.bouncycastle.pkcs.PKCS10CertificationRequest;
+import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder;
+import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest;
+import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
+import org.bouncycastle.util.Arrays;
+
+/**
+ **/
+public class PQCPKCS10Test
+ extends TestCase
+{
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+
+ public String getName()
+ {
+ return "PKCS10CertRequest";
+ }
+
+ public void setUp()
+ {
+ if (Security.getProvider("BC") == null)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+ }
+
+ public void testMLDsa()
+ throws Exception
+ {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("ML-DSA", "BC");
+
+ kpg.initialize(MLDSAParameterSpec.ml_dsa_65);
+
+ KeyPair kp = kpg.genKeyPair();
+
+ X500Name subject = getSubjectName();
+
+ PKCS10CertificationRequestBuilder requestBuilder = new JcaPKCS10CertificationRequestBuilder(subject, kp.getPublic());
+
+ PKCS10CertificationRequest req1 = requestBuilder.build(new JcaContentSignerBuilder("ML-DSA").setProvider(BC).build(kp.getPrivate()));
+
+ JcaPKCS10CertificationRequest req2 = new JcaPKCS10CertificationRequest(req1.getEncoded()).setProvider(BC);
+
+ if (!req2.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(kp.getPublic())))
+ {
+ fail("ML-DSA: Failed verify check.");
+ }
+
+ if (!Arrays.areEqual(req2.getPublicKey().getEncoded(), req1.getSubjectPublicKeyInfo().getEncoded()))
+ {
+ fail("ML-DSA: Failed public key check.");
+ }
+ }
+
+ /**
+ * ML-KEM basesd PKCS#10 request using ML-DSA signing key.
+ */
+ public void testMLKem()
+ throws Exception
+ {
+ KeyPairGenerator signKpg = KeyPairGenerator.getInstance("ML-DSA", "BC");
+
+ signKpg.initialize(MLDSAParameterSpec.ml_dsa_65);
+
+ KeyPair signKp = signKpg.genKeyPair();
+ X509Certificate signCert = getMLDSACertificate(signKp);
+
+ KeyPairGenerator kemKpg = KeyPairGenerator.getInstance("ML-KEM", "BC");
+
+ kemKpg.initialize(MLKEMParameterSpec.ml_kem_768);
+
+ KeyPair kemKp = kemKpg.genKeyPair();
+
+ X500Principal subject = signCert.getSubjectX500Principal();
+
+ PKCS10CertificationRequestBuilder requestBuilder = new JcaPKCS10CertificationRequestBuilder(subject, kemKp.getPublic());
+
+ PKCS10CertificationRequest req1 = requestBuilder.build(new JcaContentSignerBuilder("ML-DSA").setProvider(BC).build(signKp.getPrivate()));
+
+ JcaPKCS10CertificationRequest req2 = new JcaPKCS10CertificationRequest(req1.getEncoded()).setProvider(BC);
+
+ if (!req2.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(signCert.getPublicKey())))
+ {
+ fail("ML-KEM: Failed verify check.");
+ }
+
+ if (!Arrays.areEqual(req2.getPublicKey().getEncoded(), req1.getSubjectPublicKeyInfo().getEncoded()))
+ {
+ fail("ML-KEM: Failed public key check.");
+ }
+ }
+
+ private X500Name getSubjectName()
+ {
+ X500NameBuilder x500NameBld = new X500NameBuilder(BCStyle.INSTANCE);
+
+ x500NameBld.addRDN(BCStyle.C, "AU");
+ x500NameBld.addRDN(BCStyle.O, "The Legion of the Bouncy Castle");
+ x500NameBld.addRDN(BCStyle.L, "Melbourne");
+ x500NameBld.addRDN(BCStyle.ST, "Victoria");
+ x500NameBld.addRDN(BCStyle.EmailAddress, "feedback-crypto@bouncycastle.org");
+
+ X500Name subject = x500NameBld.build();
+ return subject;
+ }
+
+ private X509Certificate getMLDSACertificate(KeyPair kp)
+ throws Exception
+ {
+ X500Name issuer = getSubjectName(); // self signed
+ X509v3CertificateBuilder v3certBldr = new JcaX509v3CertificateBuilder(issuer,
+ BigInteger.valueOf(System.currentTimeMillis()),
+ new Date(System.currentTimeMillis() - 5000L),
+ new Date(System.currentTimeMillis() + 15000L),
+ issuer, kp.getPublic()).addExtension(Extension.basicConstraints, true, new BasicConstraints(false));
+
+ ContentSigner signer = new JcaContentSignerBuilder("ML-DSA").setProvider(BC).build(kp.getPrivate());
+
+ return new JcaX509CertificateConverter().setProvider(BC).getCertificate(v3certBldr.build(signer));
+ }
+}
From 0db98d9cc2a24b46d6fc03fbbbe5a3fae065a050 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Fri, 7 Mar 2025 13:00:41 +1030
Subject: [PATCH 157/890] Fix the bug of ParallelHash that block size is set to
0.
---
.../bouncycastle/crypto/digests/ParallelHash.java | 14 ++++++++++----
.../crypto/test/ParallelHashTest.java | 15 +++++++++++++++
2 files changed, 25 insertions(+), 4 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/ParallelHash.java b/core/src/main/java/org/bouncycastle/crypto/digests/ParallelHash.java
index 5ac7f120d0..7b05eb52ca 100644
--- a/core/src/main/java/org/bouncycastle/crypto/digests/ParallelHash.java
+++ b/core/src/main/java/org/bouncycastle/crypto/digests/ParallelHash.java
@@ -38,8 +38,8 @@ public class ParallelHash
* Base constructor.
*
* @param bitLength security strength (bits) of the underlying SHAKE function, 128 or 256.
- * @param S the customization string - available for local use.
- * @param B the blocksize (in bytes) for hashing.
+ * @param S the customization string - available for local use.
+ * @param B the blocksize (in bytes) for hashing.
*/
public ParallelHash(int bitLength, byte[] S, int B)
{
@@ -50,12 +50,18 @@ public ParallelHash(int bitLength, byte[] S, int B, int outputSize)
{
this(bitLength, S, B, outputSize, CryptoServicePurpose.ANY);
}
+
public ParallelHash(int bitLength, byte[] S, int B, int outputSize, CryptoServicePurpose purpose)
{
+ if (B <= 0)
+ {
+ throw new IllegalArgumentException("block size should be greater than 0");
+ }
this.cshake = new CSHAKEDigest(bitLength, N_PARALLEL_HASH, S);
this.compressor = new CSHAKEDigest(bitLength, new byte[0], new byte[0]);
this.bitLength = bitLength;
this.B = B;
+
this.outputLength = (outputSize + 7) / 8;
this.buffer = new byte[B];
this.compressorBuffer = new byte[bitLength * 2 / 8];
@@ -112,7 +118,7 @@ public void update(byte in)
public void update(byte[] in, int inOff, int len)
throws DataLengthException, IllegalStateException
{
- len = Math.max(0, len);
+ len = Math.max(0, len);
//
// fill the current word
@@ -198,7 +204,7 @@ public int doFinal(byte[] out, int outOff, int outLen)
{
wrapUp(outputLength);
}
-
+
int rv = cshake.doFinal(out, outOff, outLen);
reset();
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/ParallelHashTest.java b/core/src/test/java/org/bouncycastle/crypto/test/ParallelHashTest.java
index 05080caf2d..5d825cf705 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/ParallelHashTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/ParallelHashTest.java
@@ -1,5 +1,6 @@
package org.bouncycastle.crypto.test;
+
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.ParallelHash;
import org.bouncycastle.util.Arrays;
@@ -23,6 +24,7 @@ public String getName()
public void performTest()
throws Exception
{
+ testException();
ParallelHash pHash = new ParallelHash(128, new byte[0], 8);
byte[] data = Hex.decode("00 01 02 03 04 05 06 07 10 11 12 13 14 15 16 17 20 21 22 23 24 25 26 27");
@@ -164,6 +166,19 @@ private void testClone()
}
}
+ private void testException()
+ {
+ testException("block size should be greater than 0", "IllegalArgumentException", new TestExceptionOperation()
+ {
+ @Override
+ public void operation()
+ throws Exception
+ {
+ Digest digest = new ParallelHash(128, null, 0);
+ }
+ });
+ }
+
public static void main(
String[] args)
{
From ad11e9b7b185536519bc10d8871c9864bbdfc184 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Fri, 7 Mar 2025 16:30:38 +1030
Subject: [PATCH 158/890] Refactor of decode (which can be re-used in Snova).
---
.../pqc/crypto/mayo/MayoKeyPairGenerator.java | 2 +-
.../pqc/crypto/mayo/MayoSigner.java | 18 ++++++-------
.../bouncycastle/pqc/crypto/mayo/Utils.java | 26 ++-----------------
3 files changed, 12 insertions(+), 34 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
index d123c7d8f8..95797cbf62 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java
@@ -94,7 +94,7 @@ public AsymmetricCipherKeyPair generateKeyPair()
// o ← Decode_o(S[ param_pk_seed_bytes : param_pk_seed_bytes + O_bytes ])
// Decode nibbles from S starting at offset param_pk_seed_bytes into O,
// with expected output length = param_v * param_o.
- Utils.decode(seed_pk, pkSeedBytes, O, O.length);
+ Utils.decode(seed_pk, pkSeedBytes, O, 0, O.length);
// Expand P1 and P2 into the array P using seed_pk.
Utils.expandP1P2(p, P, seed_pk);
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
index 560068bb34..65d148b896 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
@@ -135,7 +135,7 @@ public byte[] generateSignature(byte[] message)
// Decode the portion of S after the first param_pk_seed_bytes into O.
// (In C, this is: decode(S + param_pk_seed_bytes, O, param_v * param_o))
- Utils.decode(seed_pk, pk_seed_bytes, O, v * o);
+ Utils.decode(seed_pk, pk_seed_bytes, O, 0, v * o);
// Expand P1 and P2 into the long array P using seed_pk.
Utils.expandP1P2(params, P, seed_pk);
@@ -225,7 +225,7 @@ public byte[] generateSignature(byte[] message)
// A[(i + 1) * (ok + 1) - 1] = 0;
// }
- Utils.decode(V, k * vbytes, r, ok);
+ Utils.decode(V, k * vbytes, r, 0, ok);
if (sampleSolution(A, y, r, x))
{
@@ -240,7 +240,7 @@ public byte[] generateSignature(byte[] message)
// Compute final signature components
- for (int i = 0, io = 0, in = 0, iv = 0; i < k; i++, io += o, in+= n, iv += v)
+ for (int i = 0, io = 0, in = 0, iv = 0; i < k; i++, io += o, in += n, iv += v)
{
GF16Utils.matMul(O, x, io, Ox, o, v);
Bytes.xor(v, Vdec, iv, Ox, s, in);
@@ -274,8 +274,8 @@ public byte[] generateSignature(byte[] message)
* Verifies a MAYO signature against the initialized public key and message.
* Implements the verification process specified in the MAYO documentation.
*
- * @param message The original message
- * @param signature The signature to verify
+ * @param message The original message
+ * @param signature The signature to verify
* @return {@code true} if the signature is valid, {@code false} otherwise
* @see MAYO Spec Algorithm 9 and 11
*/
@@ -601,10 +601,10 @@ private static void transpose16x16Nibbles(long[] M, int offset)
/**
* Samples a solution for the MAYO signature equation using the provided parameters.
*
- * @param A Coefficient matrix
- * @param y Target vector
- * @param r Randomness vector
- * @param x Output solution vector
+ * @param A Coefficient matrix
+ * @param y Target vector
+ * @param r Randomness vector
+ * @param x Output solution vector
* @return {@code true} if a valid solution was found, {@code false} otherwise
* @see MAYO Spec Algorithm 2
*/
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/Utils.java
index 16b4922278..f1205c3843 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/Utils.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/Utils.java
@@ -9,7 +9,7 @@
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Pack;
-public class Utils
+class Utils
{
/**
* Decodes an encoded byte array.
@@ -34,7 +34,7 @@ public static void decode(byte[] m, byte[] mdec, int mdecLen)
// If there is an extra nibble (odd number of nibbles), decode only the lower nibble
if ((mdecLen & 1) == 1)
{
- mdec[decIndex] = (byte)((m[i] & 0xFF) & 0x0F);
+ mdec[decIndex] = (byte)(m[i] & 0x0F);
}
}
@@ -56,28 +56,6 @@ public static void decode(byte[] m, int mOff, byte[] mdec, int decIndex, int mde
}
}
- /**
- * Decodes a nibble-packed byte array into an output array.
- *
- * @param input the input byte array.
- * @param inputOffset the offset in input from which to start decoding.
- * @param output the output byte array to hold the decoded nibbles.
- * @param mdecLen the total number of nibbles to decode.
- */
- public static void decode(byte[] input, int inputOffset, byte[] output, int mdecLen)
- {
- int decIndex = 0, blocks = mdecLen >> 1;
- for (int i = 0; i < blocks; i++)
- {
- output[decIndex++] = (byte)(input[inputOffset] & 0x0F);
- output[decIndex++] = (byte)((input[inputOffset++] >> 4) & 0x0F);
- }
- if ((mdecLen & 1) == 1)
- {
- output[decIndex] = (byte)(input[inputOffset] & 0x0F);
- }
- }
-
/**
* Encodes an array of 4-bit values into a byte array.
* Two 4-bit values are packed into one byte, with the first nibble stored in the lower 4 bits
From 46e112bf79bdefdca02bf4e33a54a4cad54b4dcf Mon Sep 17 00:00:00 2001
From: gefeili
Date: Fri, 7 Mar 2025 17:08:55 +1030
Subject: [PATCH 159/890] TODO: genABQP
---
.../pqc/crypto/snova/GF16Utils.java | 133 +++++++++++++++---
.../pqc/crypto/snova/MapGroup1.java | 64 +++++++--
.../pqc/crypto/snova/SnovaEngine.java | 41 ++++++
.../pqc/crypto/snova/SnovaKeyElements.java | 4 +-
.../crypto/snova/SnovaKeyPairGenerator.java | 102 ++++++++------
5 files changed, 259 insertions(+), 85 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/GF16Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/GF16Utils.java
index 40549bbe5d..9deda36297 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/GF16Utils.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/GF16Utils.java
@@ -20,7 +20,7 @@ static byte mt(int p, int q)
{
for (int j = 0; j < 15; j++)
{
- MT4B[(F_STAR[i]<<4) ^ F_STAR[j]] = F_STAR[(i + j) % 15];
+ MT4B[(F_STAR[i] << 4) ^ F_STAR[j]] = F_STAR[(i + j) % 15];
}
}
@@ -36,6 +36,73 @@ static byte mt(int p, int q)
}
}
+ /**
+ * Convert one byte of data to GF16 representation (using only half of the
+ * byte). Example: ->
+ *
+ * @param m the input byte array (each byte holds two 4-bit values)
+ * @param mdec the output array that will hold the decoded nibbles (one per byte)
+ * @param mdecLen the total number of nibbles to decode
+ */
+ public static void decode(byte[] m, byte[] mdec, int mdecLen)
+ {
+ int i, decIndex = 0, blocks = mdecLen >> 1;
+ // Process pairs of nibbles from each byte
+ for (i = 0; i < blocks; i++)
+ {
+ // Extract the lower nibble
+ mdec[decIndex++] = (byte)(m[i] & 0x0F);
+ // Extract the upper nibble (shift right 4 bits)
+ mdec[decIndex++] = (byte)((m[i] >> 4) & 0x0F);
+ }
+ // If there is an extra nibble (odd number of nibbles), decode only the lower nibble
+ if ((mdecLen & 1) == 1)
+ {
+ mdec[decIndex] = (byte)((m[i] & 0xFF) & 0x0F);
+ }
+ }
+
+ public static void decode(byte[] m, int mOff, byte[] mdec, int decIndex, int mdecLen)
+ {
+ // Process pairs of nibbles from each byte
+ int blocks = mdecLen >> 1;
+ for (int i = 0; i < blocks; i++)
+ {
+ // Extract the lower nibble
+ mdec[decIndex++] = (byte)(m[mOff] & 0x0F);
+ // Extract the upper nibble (shift right 4 bits)
+ mdec[decIndex++] = (byte)((m[mOff++] >> 4) & 0x0F);
+ }
+ // If there is an extra nibble (odd number of nibbles), decode only the lower nibble
+ if ((mdecLen & 1) == 1)
+ {
+ mdec[decIndex] = (byte)(m[mOff] & 0x0F);
+ }
+ }
+
+ /**
+ * Decodes a nibble-packed byte array into an output array.
+ *
+ * @param input the input byte array.
+ * @param inputOffset the offset in input from which to start decoding.
+ * @param output the output byte array to hold the decoded nibbles.
+ * @param mdecLen the total number of nibbles to decode.
+ */
+ public static void decode(byte[] input, int inputOffset, byte[] output, int mdecLen)
+ {
+ int decIndex = 0, blocks = mdecLen >> 1;
+ for (int i = 0; i < blocks; i++)
+ {
+ output[decIndex++] = (byte)(input[inputOffset] & 0x0F);
+ output[decIndex++] = (byte)((input[inputOffset++] >> 4) & 0x0F);
+ }
+ if ((mdecLen & 1) == 1)
+ {
+ output[decIndex] = (byte)(input[inputOffset] & 0x0F);
+ }
+ }
+
public static void gf16mMul(byte[] a, byte[] b, byte[] c, int rank)
{
@@ -97,20 +164,6 @@ public static byte inv(byte a)
return INV4B[a & 0xF];
}
- public static void convertBytesToGF16s(byte[] input, byte[] output, int gf16Count)
- {
- int pairs = gf16Count / 2;
- for (int i = 0; i < pairs; i++)
- {
- output[i * 2] = (byte)(input[i] & 0x0F);
- output[i * 2 + 1] = (byte)((input[i] >> 4) & 0x0F);
- }
- if (gf16Count % 2 == 1)
- {
- output[gf16Count - 1] = (byte)(input[pairs] & 0x0F);
- }
- }
-
public static void convertGF16sToBytes(byte[] output, byte[] gf16s, int gf16Count)
{
int pairs = gf16Count / 2;
@@ -124,11 +177,15 @@ public static void convertGF16sToBytes(byte[] output, byte[] gf16s, int gf16Coun
}
}
- static GF16Matrix[][][] create3DArray(int d1, int d2, int d3, int rank) {
+ static GF16Matrix[][][] create3DArray(int d1, int d2, int d3, int rank)
+ {
GF16Matrix[][][] arr = new GF16Matrix[d1][d2][d3];
- for (int i = 0; i < d1; i++) {
- for (int j = 0; j < d2; j++) {
- for (int k = 0; k < d3; k++) {
+ for (int i = 0; i < d1; i++)
+ {
+ for (int j = 0; j < d2; j++)
+ {
+ for (int k = 0; k < d3; k++)
+ {
arr[i][j][k] = new GF16Matrix(rank);
}
}
@@ -136,14 +193,46 @@ static GF16Matrix[][][] create3DArray(int d1, int d2, int d3, int rank) {
return arr;
}
- static GF16Matrix[][] create2DArray(int d1, int d2, int rank) {
+ static GF16Matrix[][] create2DArray(int d1, int d2, int rank)
+ {
GF16Matrix[][] arr = new GF16Matrix[d1][d2];
- for (int i = 0; i < d1; i++) {
- for (int j = 0; j < d2; j++) {
+ for (int i = 0; i < d1; i++)
+ {
+ for (int j = 0; j < d2; j++)
+ {
arr[i][j] = new GF16Matrix(rank);
}
}
return arr;
}
+ private static final int GF16_MASK = 0x249; // Mask for GF(2^4) reduction
+
+ // Constant-time GF16 != 0 check
+ static int ctGF16IsNotZero(byte val)
+ {
+ int v = val & 0xFF;
+ return (v | (v >>> 1) | (v >>> 2) | (v >>> 3)) & 1;
+ }
+
+ // GF16 reduction modulo x^4 + x + 1
+ private static int gf16Reduce(int idx)
+ {
+ int res = idx & 0x49249249;
+ int upper = idx >>> 12;
+ res ^= upper ^ (upper << 3);
+ upper = res >>> 12;
+ res ^= upper ^ (upper << 3);
+ upper = res >>> 12;
+ res ^= upper ^ (upper << 3);
+ return res & GF16_MASK;
+ }
+
+ // Convert 32-bit reduced value to 4-bit nibble
+ static byte gf16ToNibble(int val)
+ {
+ int res = gf16Reduce(val);
+ res |= res >>> 4;
+ return (byte)((res & 0x5) | ((res >>> 2) & 0xA));
+ }
}
\ No newline at end of file
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup1.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup1.java
index 57a8a51c83..0f0caea2a4 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup1.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup1.java
@@ -2,13 +2,13 @@
class MapGroup1
{
- public final GF16Matrix[][][] P11; // [m][v][v]
- public final GF16Matrix[][][] P12; // [m][v][o]
- public final GF16Matrix[][][] P21; // [m][o][v]
- public final GF16Matrix[][] Aalpha; // [m][alpha]
- public final GF16Matrix[][] Balpha; // [m][alpha]
- public final GF16Matrix[][] Qalpha1;// [m][alpha]
- public final GF16Matrix[][] Qalpha2;// [m][alpha]
+ public final byte[][][][] p11; // [m][v][v]
+ public final byte[][][][] p12; // [m][v][o]
+ public final byte[][][][] p21; // [m][o][v]
+ public final byte[][][] aAlpha; // [m][alpha]
+ public final byte[][][] bAlpha; // [m][alpha]
+ public final byte[][][] qAlpha1;// [m][alpha]
+ public final byte[][][] qAlpha2;// [m][alpha]
public MapGroup1(SnovaParameters params)
{
@@ -16,14 +16,48 @@ public MapGroup1(SnovaParameters params)
int v = params.getV();
int o = params.getO();
int alpha = params.getAlpha();
- int rank = params.getL();
- P11 = GF16Utils.create3DArray(m, v, v, rank);
- P12 = GF16Utils.create3DArray(m, v, o, rank);
- P21 = GF16Utils.create3DArray(m, o, v, rank);
- Aalpha = GF16Utils.create2DArray(m, alpha, rank);
- Balpha = GF16Utils.create2DArray(m, alpha, rank);
- Qalpha1 = GF16Utils.create2DArray(m, alpha, rank);
- Qalpha2 = GF16Utils.create2DArray(m, alpha, rank);
+ p11 = new byte[m][v][v][16];
+ p12 = new byte[m][v][o][16];
+ p21 = new byte[m][o][v][16];
+ aAlpha = new byte[m][alpha][16];
+ bAlpha = new byte[m][alpha][16];
+ qAlpha1 = new byte[m][alpha][16];
+ qAlpha2 = new byte[m][alpha][16];
}
+
+ public int decode(byte[] input)
+ {
+ int inOff = decodeP(input, 0, p11);
+ inOff = decodeP(input, inOff, p12);
+ inOff = decodeP(input, inOff, p21);
+ inOff = decodeAlpha(input, inOff, aAlpha);
+ inOff = decodeAlpha(input, inOff, bAlpha);
+ inOff = decodeAlpha(input, inOff, qAlpha1);
+ inOff = decodeAlpha(input, inOff, qAlpha2);
+ return inOff;
+ }
+
+ private int decodeP(byte[] input, int inOff, byte[][][][] p)
+ {
+ for (int i = 0; i < p.length; ++i)
+ {
+ inOff = decodeAlpha(input, inOff, p[i]);
+ }
+ return inOff;
+ }
+
+ private int decodeAlpha(byte[] input, int inOff, byte[][][] alpha)
+ {
+ for (int i = 0; i < alpha.length; ++i)
+ {
+ for (int j = 0; j < alpha[i].length; ++j)
+ {
+ GF16Utils.decode(input, inOff, alpha[i][j], 0, alpha[i][j].length);
+ inOff += (alpha[i][j].length + 1) >> 1;
+ }
+ }
+ return inOff;
+ }
+
}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java
index 60bfe3f4c7..30c5087c7b 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java
@@ -1,5 +1,7 @@
package org.bouncycastle.pqc.crypto.snova;
+import org.bouncycastle.util.Arrays;
+
public class SnovaEngine
{
private final SnovaParameters params;
@@ -65,5 +67,44 @@ private void beTheS(byte[] target)
}
}
+ // Constant-time GF16 matrix generation
+ public void genAFqSCT(byte[] c, int cOff, byte[] ptMatrix)
+ {
+ int lsq = l * l;
+ int[] xTemp = new int[lsq];
+
+ // Initialize diagonal with c[0]
+ int cX = GF16Utils.gf16FromNibble(c[cOff]);
+ for (int ij = 0; ij < l; ij++)
+ {
+ xTemp[ij * l + ij] = cX;
+ }
+ // Process middle coefficients
+ for (int i1 = 1; i1 < l - 1; i1++)
+ {
+ cX = GF16Utils.gf16FromNibble(c[cOff + i1]);
+ for (int ij = 0; ij < lsq; ij++)
+ {
+ xTemp[ij] ^= cX * xS[i1][ij];
+ }
+ }
+
+ // Handle last coefficient with constant-time selection
+ int zero = GF16Utils.ctGF16IsNotZero(c[cOff + l - 1]);
+ int val = zero * c[cOff +l - 1] + (1 - zero) * (15 + GF16Utils.ctGF16IsNotZero(c[cOff]) - c[cOff]);
+ cX = GF16Utils.gf16FromNibble((byte)val);
+
+ for (int ij = 0; ij < lsq; ij++)
+ {
+ xTemp[ij] ^= cX * xS[l - 1][ij];
+ }
+
+ // Convert to nibbles and clear temp
+ for (int ij = 0; ij < lsq; ij++)
+ {
+ ptMatrix[ij] = GF16Utils.gf16ToNibble(xTemp[ij]);
+ }
+ Arrays.fill(xTemp, 0); // Secure clear
+ }
}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyElements.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyElements.java
index e9f44db7d9..1c1d7ea3ea 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyElements.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyElements.java
@@ -3,14 +3,14 @@
class SnovaKeyElements
{
public final MapGroup1 map1;
- public final GF16Matrix[][] T12; // [v][o]
+ public final byte[][][] T12; // [v][o]
public final MapGroup2 map2;
public final PublicKey publicKey;
public SnovaKeyElements(SnovaParameters params)
{
map1 = new MapGroup1(params);
- T12 = GF16Utils.create2DArray(params.getV(), params.getO(), params.getL());
+ T12 = new byte[params.getV()][params.getO()][16];
map2 = new MapGroup2(params);
publicKey = new PublicKey(params);
}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyPairGenerator.java
index 23bc7c90db..81d814ad0f 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyPairGenerator.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyPairGenerator.java
@@ -7,6 +7,8 @@
import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
import org.bouncycastle.crypto.KeyGenerationParameters;
import org.bouncycastle.crypto.digests.SHAKEDigest;
+import org.bouncycastle.crypto.engines.AESEngine;
+import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.util.Arrays;
public class SnovaKeyPairGenerator
@@ -97,13 +99,13 @@ private void packPrivateKey(byte[] esk, byte[] ptPublicKeySeed, byte[] ptPrivate
// serializeMatrixGroup(bos, keyElements.map1.Qalpha2);
// Serialize T12
- for (GF16Matrix[] row : keyElements.T12)
- {
- for (GF16Matrix matrix : row)
- {
- serializeMatrix(bos, matrix);
- }
- }
+// for (GF16Matrix[] row : keyElements.T12)
+// {
+// for (GF16Matrix matrix : row)
+// {
+// serializeMatrix(bos, matrix);
+// }
+// }
// Add public and private seeds
bos.write(ptPublicKeySeed, 0, ptPublicKeySeed.length);
@@ -168,7 +170,7 @@ private void generateKeysCore(SnovaKeyElements keyElements, byte[] pkSeed, byte[
// genP22(keyElements.pk.P22, keyElements.T12, keyElements.map1.P21, keyElements.map2.F12);
}
- private void genSeedsAndT12(GF16Matrix[][] T12, byte[] skSeed)
+ private void genSeedsAndT12(byte[][][] T12, byte[] skSeed)
{
int bytesPrngPrivate = (params.getV() * params.getO() * params.getL() + 1) >>> 1;
int gf16sPrngPrivate = params.getV() * params.getO() * params.getL();
@@ -181,60 +183,68 @@ private void genSeedsAndT12(GF16Matrix[][] T12, byte[] skSeed)
// Convert bytes to GF16 array
byte[] gf16PrngOutput = new byte[gf16sPrngPrivate];
- GF16Utils.convertBytesToGF16s(prngOutput, gf16PrngOutput, gf16sPrngPrivate);
+ GF16Utils.decode(prngOutput, gf16PrngOutput, gf16sPrngPrivate);
// Generate T12 matrices
- int ptr = 0;
+ int ptArray = 0;
+ int l = params.getL();
for (int j = 0; j < params.getV(); j++)
{
for (int k = 0; k < params.getO(); k++)
{
//gen_a_FqS_ct
- GF16Matrix matrix = new GF16Matrix(params.getL());
- for (int i = 0; i < params.getL(); i++)
- {
- for (int m = 0; m < params.getL(); m++)
- {
- matrix.set(i, m, gf16PrngOutput[ptr++]);
- }
- }
- matrix.makeInvertible();
- T12[j][k] = matrix;
+ engine.genAFqSCT(gf16PrngOutput, ptArray, T12[j][k]);
+ ptArray += l;
}
}
}
-//
-// private void genABQP(MapGroup1 map1, byte[] pkSeed)
-// {
-// byte[] prngOutput = new byte[params.getBytesPrngPublic()];
-//
-// if (params.isPkExpandShake()) {
-// // SHAKE-based expansion
-// SHAKEDigest shake = new SHAKEDigest(256);
-// shake.update(pkSeed, 0, pkSeed.length);
-// shake.doFinal(prngOutput, 0, prngOutput.length);
-// } else {
-// // AES-CTR-based expansion
-// AESEngine aes = new AESEngine();
-// aes.init(true, new KeyParameter(pkSeed));
-// for (int i = 0; i < prngOutput.length; i += 16) {
-// byte[] block = new byte[16];
-// aes.processBlock(block, 0, block, 0);
-// System.arraycopy(block, 0, prngOutput, i, Math.min(16, prngOutput.length - i));
-// }
-// }
-//
-// // Convert bytes to GF16 structures
-// GF16Utils.convertBytesToGF16s(prngOutput, map1);
+
+ private void genABQP(MapGroup1 map1, byte[] pkSeed)
+ {
+ int l = params.getL();
+ int lsq = l * l;
+ int m = params.getM();
+ int alpha = params.getAlpha();
+ int v = params.getV();
+ int o = params.getO();
+ int n = v + o;
+
+ int gf16sPrngPublic = lsq * (2 * m * alpha + m * (n * n - m * m)) + l * 2 * m * alpha;
+ byte[] prngOutput = new byte[gf16sPrngPublic];
+
+ if (params.isPkExpandShake())
+ {
+ // SHAKE-based expansion
+ SHAKEDigest shake = new SHAKEDigest(256);
+ shake.update(pkSeed, 0, pkSeed.length);
+ shake.doFinal(prngOutput, 0, prngOutput.length);
+ }
+ else
+ {
+ // AES-CTR-based expansion
+ AESEngine aes = new AESEngine();
+ aes.init(true, new KeyParameter(pkSeed));
+ for (int i = 0; i < prngOutput.length; i += 16)
+ {
+ byte[] block = new byte[16];
+ aes.processBlock(block, 0, block, 0);
+ System.arraycopy(block, 0, prngOutput, i, Math.min(16, prngOutput.length - i));
+ }
+ }
+
+ // Convert bytes to GF16 structures
+// int inOff = map1.decode(prngOutput);
//
// // Post-processing for invertible matrices
-// for (GF16Matrix matrix : map1.Aalpha) {
+// for (GF16Matrix matrix : map1.Aalpha)
+// {
// GF16Utils.makeInvertible(matrix);
// }
-// for (GF16Matrix matrix : map1.Balpha) {
+// for (GF16Matrix matrix : map1.Balpha)
+// {
// GF16Utils.makeInvertible(matrix);
// }
-// }
+ }
// private void genF(MapGroup2 map2, MapGroup1 map1, GF16Matrix[][] T12)
// {
From d42abdebd824426561a9ac46d9cae960600e763b Mon Sep 17 00:00:00 2001
From: David Hook
Date: Fri, 7 Mar 2025 20:05:49 +1100
Subject: [PATCH 160/890] updated for tls change
---
ant/jdk18+.xml | 1 -
1 file changed, 1 deletion(-)
diff --git a/ant/jdk18+.xml b/ant/jdk18+.xml
index 4a37034a93..f099672565 100644
--- a/ant/jdk18+.xml
+++ b/ant/jdk18+.xml
@@ -43,7 +43,6 @@
-
From 3a2c2d782ecf701fad1529728d154935fe8cc8c5 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Fri, 7 Mar 2025 20:07:25 +1100
Subject: [PATCH 161/890] updated for tls change
---
ant/jdk15+.xml | 1 -
1 file changed, 1 deletion(-)
diff --git a/ant/jdk15+.xml b/ant/jdk15+.xml
index 80412884fc..35a23c11d4 100644
--- a/ant/jdk15+.xml
+++ b/ant/jdk15+.xml
@@ -43,7 +43,6 @@
-
From 81b4930b06448c76bd4131498c21494bb3d47ca8 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Fri, 7 Mar 2025 20:09:18 +1100
Subject: [PATCH 162/890] updated for tls change
---
ant/jdk14.xml | 2 --
1 file changed, 2 deletions(-)
diff --git a/ant/jdk14.xml b/ant/jdk14.xml
index 5fe4ae4802..d6769e5cbd 100644
--- a/ant/jdk14.xml
+++ b/ant/jdk14.xml
@@ -196,8 +196,6 @@
-
-
From 9d39e6f82f6ed44998fecce5db26073f78d3e679 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Sun, 9 Mar 2025 18:30:35 +1030
Subject: [PATCH 163/890] Array clone of Mayo Key parameters. Remove Mayo from
BouncyCastleProvider
---
.../pqc/crypto/mayo/MayoPrivateKeyParameters.java | 2 +-
.../pqc/crypto/mayo/MayoPublicKeyParameters.java | 4 ++--
.../org/bouncycastle/jce/provider/BouncyCastleProvider.java | 6 ------
3 files changed, 3 insertions(+), 9 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPrivateKeyParameters.java
index f325f96dc4..1dcc6324dd 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPrivateKeyParameters.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPrivateKeyParameters.java
@@ -10,7 +10,7 @@ public class MayoPrivateKeyParameters
public MayoPrivateKeyParameters(MayoParameters params, byte[] seed_sk)
{
super(true, params);
- this.seed_sk = seed_sk;
+ this.seed_sk = Arrays.clone(seed_sk);
}
public byte[] getEncoded()
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPublicKeyParameters.java
index 086660edfd..f7df56fb69 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPublicKeyParameters.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPublicKeyParameters.java
@@ -10,12 +10,12 @@ public class MayoPublicKeyParameters
public MayoPublicKeyParameters(MayoParameters params, byte[] p)
{
super(false, params);
- this.p = p;
+ this.p = Arrays.clone(p);
}
public byte[] getP()
{
- return p;
+ return Arrays.clone(p);
}
public byte[] getEncoded()
diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java b/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
index 6af5a7297a..f26c929495 100644
--- a/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
+++ b/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
@@ -38,7 +38,6 @@
import org.bouncycastle.pqc.jcajce.provider.hqc.HQCKeyFactorySpi;
import org.bouncycastle.pqc.jcajce.provider.kyber.KyberKeyFactorySpi;
import org.bouncycastle.pqc.jcajce.provider.lms.LMSKeyFactorySpi;
-import org.bouncycastle.pqc.jcajce.provider.mayo.MayoKeyFactorySpi;
import org.bouncycastle.pqc.jcajce.provider.newhope.NHKeyFactorySpi;
import org.bouncycastle.pqc.jcajce.provider.ntru.NTRUKeyFactorySpi;
import org.bouncycastle.pqc.jcajce.provider.picnic.PicnicKeyFactorySpi;
@@ -438,11 +437,6 @@ private void loadPQCKeys()
addKeyInfoConverter(BCObjectIdentifiers.ntruhps2048677, new NTRUKeyFactorySpi());
addKeyInfoConverter(BCObjectIdentifiers.ntruhps4096821, new NTRUKeyFactorySpi());
addKeyInfoConverter(BCObjectIdentifiers.ntruhrss701, new NTRUKeyFactorySpi());
-
- addKeyInfoConverter(BCObjectIdentifiers.mayo1, new MayoKeyFactorySpi());
- addKeyInfoConverter(BCObjectIdentifiers.mayo2, new MayoKeyFactorySpi());
- addKeyInfoConverter(BCObjectIdentifiers.mayo3, new MayoKeyFactorySpi());
- addKeyInfoConverter(BCObjectIdentifiers.mayo5, new MayoKeyFactorySpi());
}
public void setParameter(String parameterName, Object parameter)
From 0e88a50bcd72dece84f98ee6d1754aef88ad4071 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Sun, 9 Mar 2025 18:38:46 +1030
Subject: [PATCH 164/890] Add Mayo to BouncyCastleProvider
---
.../jce/provider/BouncyCastleProvider.java | 80 ++++++++++---------
1 file changed, 43 insertions(+), 37 deletions(-)
diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java b/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
index f26c929495..f59524555f 100644
--- a/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
+++ b/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
@@ -38,6 +38,7 @@
import org.bouncycastle.pqc.jcajce.provider.hqc.HQCKeyFactorySpi;
import org.bouncycastle.pqc.jcajce.provider.kyber.KyberKeyFactorySpi;
import org.bouncycastle.pqc.jcajce.provider.lms.LMSKeyFactorySpi;
+import org.bouncycastle.pqc.jcajce.provider.mayo.MayoKeyFactorySpi;
import org.bouncycastle.pqc.jcajce.provider.newhope.NHKeyFactorySpi;
import org.bouncycastle.pqc.jcajce.provider.ntru.NTRUKeyFactorySpi;
import org.bouncycastle.pqc.jcajce.provider.picnic.PicnicKeyFactorySpi;
@@ -92,29 +93,29 @@ public final class BouncyCastleProvider extends Provider
private static final String SYMMETRIC_PACKAGE = "org.bouncycastle.jcajce.provider.symmetric.";
private static final String[] SYMMETRIC_GENERIC =
- {
- "PBEPBKDF1", "PBEPBKDF2", "PBEPKCS12", "TLSKDF", "SCRYPT"
- };
+ {
+ "PBEPBKDF1", "PBEPBKDF2", "PBEPKCS12", "TLSKDF", "SCRYPT"
+ };
private static final String[] SYMMETRIC_MACS =
- {
- "SipHash", "SipHash128", "Poly1305"
- };
+ {
+ "SipHash", "SipHash128", "Poly1305"
+ };
private static final CryptoServiceProperties[] SYMMETRIC_CIPHERS =
- {
- // TODO: these numbers need a bit more work, we cap at 256 bits.
- service("AES", 256), service("ARC4", 20), service("ARIA", 256), service("Blowfish", 128), service("Camellia", 256),
- service("CAST5", 128), service("CAST6", 256), service("ChaCha", 128), service("DES", 56), service("DESede", 112),
- service("GOST28147", 128), service("Grainv1", 128), service("Grain128", 128), service("HC128", 128), service("HC256", 256),
- service("IDEA", 128), service("Noekeon", 128), service("RC2", 128), service("RC5", 128), service("RC6", 256),
- service("Rijndael", 256), service("Salsa20", 128), service("SEED", 128), service("Serpent", 256), service("Shacal2", 128),
- service("Skipjack", 80), service("SM4", 128), service("TEA", 128), service("Twofish", 256), service("Threefish", 128),
- service("VMPC", 128), service("VMPCKSA3", 128), service("XTEA", 128), service("XSalsa20", 128), service("OpenSSLPBKDF", 128),
- service("DSTU7624", 256), service("GOST3412_2015", 256), service("Zuc", 128)
- };
-
- /*
+ {
+ // TODO: these numbers need a bit more work, we cap at 256 bits.
+ service("AES", 256), service("ARC4", 20), service("ARIA", 256), service("Blowfish", 128), service("Camellia", 256),
+ service("CAST5", 128), service("CAST6", 256), service("ChaCha", 128), service("DES", 56), service("DESede", 112),
+ service("GOST28147", 128), service("Grainv1", 128), service("Grain128", 128), service("HC128", 128), service("HC256", 256),
+ service("IDEA", 128), service("Noekeon", 128), service("RC2", 128), service("RC5", 128), service("RC6", 256),
+ service("Rijndael", 256), service("Salsa20", 128), service("SEED", 128), service("Serpent", 256), service("Shacal2", 128),
+ service("Skipjack", 80), service("SM4", 128), service("TEA", 128), service("Twofish", 256), service("Threefish", 128),
+ service("VMPC", 128), service("VMPCKSA3", 128), service("XTEA", 128), service("XSalsa20", 128), service("OpenSSLPBKDF", 128),
+ service("DSTU7624", 256), service("GOST3412_2015", 256), service("Zuc", 128)
+ };
+
+ /*
* Configurable asymmetric ciphers
*/
private static final String ASYMMETRIC_PACKAGE = "org.bouncycastle.jcajce.provider.asymmetric.";
@@ -122,43 +123,43 @@ public final class BouncyCastleProvider extends Provider
// this one is required for GNU class path - it needs to be loaded first as the
// later ones configure it.
private static final String[] ASYMMETRIC_GENERIC =
- {
- "X509", "IES", "COMPOSITE", "EXTERNAL", "CompositeSignatures", "NoSig"
- };
+ {
+ "X509", "IES", "COMPOSITE", "EXTERNAL", "CompositeSignatures", "NoSig"
+ };
private static final String[] ASYMMETRIC_CIPHERS =
- {
- "DSA", "DH", "EC", "RSA", "GOST", "ECGOST", "ElGamal", "DSTU4145", "GM", "EdEC", "LMS", "SPHINCSPlus", "Dilithium", "Falcon", "NTRU", "CONTEXT", "SLHDSA", "MLDSA", "MLKEM"
- };
+ {
+ "DSA", "DH", "EC", "RSA", "GOST", "ECGOST", "ElGamal", "DSTU4145", "GM", "EdEC", "LMS", "SPHINCSPlus", "Dilithium", "Falcon", "NTRU", "CONTEXT", "SLHDSA", "MLDSA", "MLKEM"
+ };
/*
* Configurable digests
*/
private static final String DIGEST_PACKAGE = "org.bouncycastle.jcajce.provider.digest.";
private static final String[] DIGESTS =
- {
- "GOST3411", "Keccak", "MD2", "MD4", "MD5", "SHA1", "RIPEMD128", "RIPEMD160", "RIPEMD256", "RIPEMD320", "SHA224",
- "SHA256", "SHA384", "SHA512", "SHA3", "Skein", "SM3", "Tiger", "Whirlpool", "Blake2b", "Blake2s", "DSTU7564",
- "Haraka", "Blake3"
- };
+ {
+ "GOST3411", "Keccak", "MD2", "MD4", "MD5", "SHA1", "RIPEMD128", "RIPEMD160", "RIPEMD256", "RIPEMD320", "SHA224",
+ "SHA256", "SHA384", "SHA512", "SHA3", "Skein", "SM3", "Tiger", "Whirlpool", "Blake2b", "Blake2s", "DSTU7564",
+ "Haraka", "Blake3"
+ };
/*
* Configurable keystores
*/
private static final String KEYSTORE_PACKAGE = "org.bouncycastle.jcajce.provider.keystore.";
private static final String[] KEYSTORES =
- {
- "BC", "BCFKS", "PKCS12"
- };
+ {
+ "BC", "BCFKS", "PKCS12"
+ };
/*
* Configurable secure random
*/
private static final String SECURE_RANDOM_PACKAGE = "org.bouncycastle.jcajce.provider.drbg.";
private static final String[] SECURE_RANDOMS =
- {
- "DRBG"
- };
+ {
+ "DRBG"
+ };
private Map serviceMap = new ConcurrentHashMap();
@@ -437,6 +438,11 @@ private void loadPQCKeys()
addKeyInfoConverter(BCObjectIdentifiers.ntruhps2048677, new NTRUKeyFactorySpi());
addKeyInfoConverter(BCObjectIdentifiers.ntruhps4096821, new NTRUKeyFactorySpi());
addKeyInfoConverter(BCObjectIdentifiers.ntruhrss701, new NTRUKeyFactorySpi());
+
+ addKeyInfoConverter(BCObjectIdentifiers.mayo1, new MayoKeyFactorySpi());
+ addKeyInfoConverter(BCObjectIdentifiers.mayo2, new MayoKeyFactorySpi());
+ addKeyInfoConverter(BCObjectIdentifiers.mayo3, new MayoKeyFactorySpi());
+ addKeyInfoConverter(BCObjectIdentifiers.mayo5, new MayoKeyFactorySpi());
}
public void setParameter(String parameterName, Object parameter)
@@ -480,7 +486,7 @@ public void addAlgorithm(String type, ASN1ObjectIdentifier oid, String className
addAttributes(type + "." + oid, attributes);
addAttributes(type + ".OID." + oid, attributes);
}
-
+
public void addKeyInfoConverter(ASN1ObjectIdentifier oid, AsymmetricKeyInfoConverter keyInfoConverter)
{
synchronized (keyInfoConverters)
From f4a2618924873095915b8292f50276630ceeec79 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Thu, 30 Jan 2025 17:38:07 +1030
Subject: [PATCH 165/890] TODO: try to get the correct q
---
.../crypto/kems/SAKKEKEMSGenerator.java | 150 ++++++++++++++++++
.../bouncycastle/crypto/kems/SAKKEUtils.java | 66 ++++++++
.../crypto/params/SAKKEPrivateKey.java | 37 +++++
.../crypto/params/SAKKEPublicKey.java | 52 ++++++
.../crypto/kems/test/SAKKEKEMSTest.java | 81 ++++++++++
5 files changed, 386 insertions(+)
create mode 100644 core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
create mode 100644 core/src/main/java/org/bouncycastle/crypto/kems/SAKKEUtils.java
create mode 100644 core/src/main/java/org/bouncycastle/crypto/params/SAKKEPrivateKey.java
create mode 100644 core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKey.java
create mode 100644 core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
diff --git a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
new file mode 100644
index 0000000000..e44d681f12
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
@@ -0,0 +1,150 @@
+package org.bouncycastle.crypto.kems;
+
+import org.bouncycastle.crypto.EncapsulatedSecretGenerator;
+import org.bouncycastle.crypto.SecretWithEncapsulation;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.SAKKEPublicKey;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECFieldElement;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.BigIntegers;
+
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.security.SecureRandom;
+
+public class SAKKEKEMSGenerator
+ implements EncapsulatedSecretGenerator
+{
+ private final SAKKEPublicKey publicParams;
+ private final SecureRandom random;
+
+ public SAKKEKEMSGenerator(SAKKEPublicKey params, SecureRandom random)
+ {
+ this.publicParams = params;
+ this.random = random;
+ }
+
+ @Override
+ public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recipientKey)
+ {
+ // 1. Generate random SSV in range [0, 2^n - 1]
+ BigInteger ssv = new BigInteger(publicParams.getN(), random);
+
+ // 2. Compute r = HashToIntegerRange(SSV || b, q)
+ BigInteger b = getRecipientId((SAKKEPublicKey)recipientKey);
+ BigInteger r = SAKKEUtils.hashToIntegerRange(Arrays.concatenate(ssv.toByteArray(), b.toByteArray()), publicParams.getQ());
+
+ // 3. Compute R_(b,S) = [r]([b]P + Z_S)
+ ECPoint bP = publicParams.getP().multiply(b); // [b]P
+ ECPoint Z_S = publicParams.getZ(); // Z_S
+ ECPoint R_bS = bP.add(Z_S).multiply(r); // [r]([b]P + Z_S)
+
+ // 4. Compute H = SSV XOR HashToIntegerRange( g^r, 2^n )
+ BigInteger g_r = pairing(R_bS, publicParams.getP(), publicParams.getQ(), publicParams.getP().getCurve().getField().getCharacteristic());
+ BigInteger mask = SAKKEUtils.hashToIntegerRange(g_r.toByteArray(), BigInteger.ONE.shiftLeft(publicParams.getN())); // 2^n
+
+ BigInteger H = ssv.xor(mask);
+
+ // 5. Encode encapsulated data (R_bS, H)
+ byte[] encapsulated = encodeData(R_bS, H);
+
+ return new SecretWithEncapsulationImpl(
+ BigIntegers.asUnsignedByteArray(publicParams.getN() / 8, ssv), // Output SSV as key material
+ encapsulated
+ );
+ }
+
+ private BigInteger getRecipientId(SAKKEPublicKey pubKey)
+ {
+ byte[] hashedId = SAKKEUtils.hash(pubKey.getZ().getEncoded(false)); // Hash Z_S
+ return new BigInteger(1, hashedId).mod(pubKey.getQ().subtract(BigInteger.ONE)).add(BigIntegers.TWO);
+ }
+
+ /**
+ * Computes the Tate-Lichtenbaum pairing ⟨P, Q⟩ as per RFC 6508.
+ *
+ * //* @param P First point (on E(F_p)).
+ *
+ * @param Q Second point (on E(F_p)).
+ * @return Result of the pairing in the field F_p^2.
+ */
+ public static BigInteger pairing(ECPoint R, ECPoint Q, BigInteger p, BigInteger q)
+ {
+ ECCurve curve = R.getCurve();
+ ECFieldElement i = curve.fromBigInteger(BigInteger.ONE.negate()); // i = -1 in F_p^2
+
+ ECPoint C = R;
+ BigInteger c = p.add(BigInteger.ONE).divide(q);
+ ECFieldElement v = curve.fromBigInteger(BigInteger.ONE); // v = 1 in F_p
+
+ String qBits = q.subtract(BigInteger.ONE).toString(2); // Binary representation of q-1
+
+ for (int j = 1; j < qBits.length(); j++)
+ { // Skip MSB
+ // l = (3 * (C_x^2 - 1)) / (2 * C_y)
+ ECFieldElement Cx = C.getAffineXCoord();
+ ECFieldElement Cy = C.getAffineYCoord();
+ ECFieldElement l = Cx.square().multiply(curve.fromBigInteger(ECFieldElement.THREE)).subtract(curve.fromBigInteger(BigInteger.ONE))
+ .divide(Cy.multiply(curve.fromBigInteger(BigIntegers.TWO)));
+
+ // v = v^2 * (l * (Q_x + C_x) + (i * Q_y - C_y))
+ ECFieldElement Qx = Q.getAffineXCoord();
+ ECFieldElement Qy = Q.getAffineYCoord();
+ v = v.square().multiply(l.multiply(Qx.add(Cx)).add(i.multiply(Qy).subtract(Cy)));
+
+ // Double the point
+ C = C.twice();
+
+ // If the bit is 1, perform additional step
+ if (qBits.charAt(j) == '1')
+ {
+ // l = (C_y - R_y) / (C_x - R_x)
+ ECFieldElement Rx = R.getAffineXCoord();
+ ECFieldElement Ry = R.getAffineYCoord();
+ l = Cy.subtract(Ry).divide(Cx.subtract(Rx));
+
+ // v = v * (l * (Q_x + C_x) + (i * Q_y - C_y))
+ v = v.multiply(l.multiply(Qx.add(Cx)).add(i.multiply(Qy).subtract(Cy)));
+
+ // C = C + R
+ C = C.add(R);
+ }
+ }
+
+ // Compute v^c
+ v = curve.fromBigInteger(v.toBigInteger().pow(c.intValue()));
+
+ // Convert to F_p representative
+ return computeFpRepresentative(v, curve);
+ }
+
+ private static BigInteger computeFpRepresentative(ECFieldElement t, ECCurve curve)
+ {
+ // Characteristic of F_p
+ BigInteger p = ((ECCurve.Fp) curve).getQ();
+
+ // Assume t = a + i * b in F_p² → extract a, b
+ ECFieldElement a = t; // In F_p², a is the real part
+ ECFieldElement b = t.multiply(curve.fromBigInteger(BigInteger.ONE.negate())); // Imaginary part
+
+ // Compute b/a mod p
+ return b.toBigInteger().multiply(a.toBigInteger().modInverse(p)).mod(p);
+ }
+
+ public static byte[] encodeData(ECPoint R_bS, BigInteger H) {
+ // 1. Serialize EC Point (use compressed format for efficiency)
+ byte[] R_bS_bytes = R_bS.getEncoded(true);
+
+ // 2. Serialize H (convert to a fixed-length byte array)
+ byte[] H_bytes = H.toByteArray();
+
+ // 3. Combine both into a single byte array
+ ByteBuffer buffer = ByteBuffer.allocate(R_bS_bytes.length + H_bytes.length);
+ buffer.put(R_bS_bytes);
+ buffer.put(H_bytes);
+
+ return buffer.array();
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEUtils.java b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEUtils.java
new file mode 100644
index 0000000000..bc3a9a90f2
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEUtils.java
@@ -0,0 +1,66 @@
+package org.bouncycastle.crypto.kems;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.util.Strings;
+import org.bouncycastle.util.encoders.Hex;
+
+public class SAKKEUtils
+{
+ public static BigInteger hashToIntegerRange(byte[] input, BigInteger q)
+ {
+ // RFC 6508 Section 5.1: Hashing to an Integer Range
+ SHA256Digest digest = new SHA256Digest();
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ // Step 1: Compute A = hashfn(s)
+ digest.update(input, 0, input.length);
+ digest.doFinal(hash, 0);
+ byte[] A = hash.clone();
+
+ // Step 2: Initialize h_0 to all-zero bytes of hashlen size
+ byte[] h = new byte[digest.getDigestSize()];
+
+ // Step 3: Compute l = Ceiling(lg(n)/hashlen)
+ int l = q.bitLength() >> 8;
+
+ BigInteger v = BigInteger.ZERO;
+
+ // Step 4: Compute h_i and v_i
+ for (int i = 1; i <= l; i++)
+ {
+ // h_i = hashfn(h_{i-1})
+ digest.update(h, 0, h.length);
+ digest.doFinal(h, 0);
+ System.out.println("h_"+i+":" +new String(Hex.encode(h)));
+ // v_i = hashfn(h_i || A)
+ digest.update(h, 0, h.length);
+ digest.update(A, 0, A.length);
+ byte[] v_i = new byte[digest.getDigestSize()];
+ digest.doFinal(v_i, 0);
+ System.out.println("v_"+i+":" +new String(Hex.encode(v_i)));
+ // Append v_i to v'
+ v = v.shiftLeft(v_i.length * 8).add(new BigInteger(1, v_i));
+ }
+ System.out.println("v:" +new String(Hex.encode(v.toByteArray())));
+ // Step 6: v = v' mod n
+ return v.mod(q);
+ }
+
+ public static byte[] hash(byte[] data)
+ {
+ Digest digest = new SHA256Digest();
+ byte[] rlt = new byte[digest.getDigestSize()];
+ digest.update(data, 0, data.length);
+ digest.doFinal(rlt, 0);
+ return rlt;
+ }
+
+ public static byte[] hash(ECPoint point)
+ {
+ return hash(point.getEncoded(false)); // Use uncompressed encoding
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPrivateKey.java b/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPrivateKey.java
new file mode 100644
index 0000000000..02e6d7c54b
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPrivateKey.java
@@ -0,0 +1,37 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.math.ec.ECPoint;
+
+public class SAKKEPrivateKey
+ extends AsymmetricKeyParameter
+{
+ private final BigInteger b; // User's identity
+ private final ECPoint K; // Private key K_a
+ private final SAKKEPublicKey publicParams;
+
+ public SAKKEPrivateKey(BigInteger b, ECPoint K, SAKKEPublicKey publicParams)
+ {
+ super(true);
+ this.b = b;
+ this.K = K;
+ this.publicParams = publicParams;
+ }
+
+ // Getters
+ public ECPoint getK()
+ {
+ return K;
+ }
+
+ public BigInteger getB()
+ {
+ return b;
+ }
+
+ public SAKKEPublicKey getPublicParams()
+ {
+ return publicParams;
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKey.java b/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKey.java
new file mode 100644
index 0000000000..81829f9caf
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKey.java
@@ -0,0 +1,52 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+
+public class SAKKEPublicKey
+ extends AsymmetricKeyParameter
+{
+ private final ECCurve curve;
+ private final ECPoint P; // Base point
+ private final ECPoint Z; // KMS Public Key: Z = [z]P
+ private final BigInteger q; // Subgroup order
+ private final int n; // SSV bit length
+
+ public SAKKEPublicKey(ECCurve curve, ECPoint P, ECPoint Z, BigInteger q, int n)
+ {
+ super(false);
+ this.curve = curve;
+ this.P = P;
+ this.Z = Z;
+ this.q = q;
+ this.n = n;
+ }
+
+ // Getters
+ public ECCurve getCurve()
+ {
+ return curve;
+ }
+
+ public ECPoint getP()
+ {
+ return P;
+ }
+
+ public ECPoint getZ()
+ {
+ return Z;
+ }
+
+ public BigInteger getQ()
+ {
+ return q;
+ }
+
+ public int getN()
+ {
+ return n;
+ }
+}
diff --git a/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java b/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
new file mode 100644
index 0000000000..61ba76350d
--- /dev/null
+++ b/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
@@ -0,0 +1,81 @@
+package org.bouncycastle.crypto.kems.test;
+
+import java.math.BigInteger;
+
+
+import org.bouncycastle.crypto.kems.SAKKEKEMSGenerator;
+import org.bouncycastle.crypto.kems.SAKKEUtils;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+import org.bouncycastle.util.encoders.Hex;
+import org.bouncycastle.util.test.SimpleTest;
+import org.junit.Assert;
+
+public class SAKKEKEMSTest
+ extends SimpleTest
+{
+ public static void main(String[] args)
+ throws Exception
+ {
+ SAKKEKEMSTest test = new SAKKEKEMSTest();
+ test.performTest();
+ // Expected Rb values
+// BigInteger expectedRbx = new BigInteger("44E8AD44AB8592A6A5A3DDCA5CF896C718043606A01D650DEF37A01F37C228C332FC317354E2C274D4DAF8AD001054C7...
+// BigInteger expectedRby = new BigInteger("557E134AD85BB1D4B9CE4F8BE4B08A12BABF55B1D6F1D7A638019EA28E15AB1C9F76375FDD1210D4F4351B9A009486B7...
+//
+// // Instantiate SAKKE KEM Generator
+// SAKKEKEMSGenerator kem = new SAKKEKEMSGenerator();
+// EncapsulatedData encapsulatedData = kem.encapsulate(SSV);
+//
+// // Validate results
+// boolean testPassed = expectedRbx.equals(encapsulatedData.getRbx()) && expectedRby.equals(encapsulatedData.getRby());
+
+ //System.out.println("SAKKE KEM Test " + (testPassed ? "PASSED" : "FAILED"));
+ }
+
+ private static byte[] hexStringToByteArray(String s)
+ {
+ int len = s.length();
+ byte[] data = new byte[len / 2];
+ for (int i = 0; i < len; i += 2)
+ {
+ data[i / 2] = (byte)((Character.digit(s.charAt(i), 16) << 4)
+ + Character.digit(s.charAt(i + 1), 16));
+ }
+ return data;
+ }
+
+ @Override
+ public String getName()
+ {
+ return null;
+ }
+
+ @Override
+ public void performTest()
+ throws Exception
+ {
+// BigInteger z = new BigInteger("AFF429D35F84B110D094803B3595A6E2998BC99F");
+// BigInteger Zx = new BigInteger("5958EF1B1679BF099B3A030DF255AA6A23C1D8F143D4D23F753E69BD27A832F38CB4AD53DDEF"
+// + "4260B0FE8BB45C4C1FF510EFFE300367A37B61F701D914AEF09724825FA0707D61A6DFF4FBD7273566CDDE352A0B04B7C16A78309BE"
+// + "640697DE747613A5FC195E8B9F328852A579DB8F99B1D0034479EA9C5595F47C4B2F54FF2");
+// BigInteger Zy = new BigInteger("1508D37514DCF7A8E143A6058C09A6BF2C9858CA37C258065AE6BF7532BC8B5B63383866E075"
+// + "3C5AC0E72709F8445F2E6178E065857E0EDA10F68206B63505ED87E534FB2831FF957FB7DC619DAE61301EEACC2FDA3680EA499925" +
+// "8A833CEA8FC67C6D19487FB449059F26CC8AAB655AB58B7CC796E24E9A394095754F5F8BAE");
+//
+ byte[] b = Hex.decode("323031312D30320074656C3A2B34343737303039303031323300");
+
+ byte[] SSV = Hex.decode("123456789ABCDEF0123456789ABCDEF0");
+ byte[] expectedR = Hex.decode("13EE3E1B8DAC5DB168B1CEB32F0566A4C273693F78BAFFA2A2EE6A686E6BD90F8206CCAB84E7F"
+ + "42ED39BD4FB131012ECCA2ECD2119414560C17CAB46B956A80F58A3302EB3E2C9A228FBA7ED34D8ACA2392DA1FFB0B17B2320AE09AAEDF"
+ + "D0235F6FE0EB65337A63F9CC97728B8E5AD0460FADE144369AA5B2166213247712096");
+
+ BigInteger r = SAKKEUtils.hashToIntegerRange(Arrays.concatenate(SSV, b), BigInteger.valueOf(1024));
+
+ System.out.println("r:" +new String(Hex.encode(r.toByteArray())));
+
+ System.out.println("r:" +new String(Hex.encode(expectedR)));
+
+ Assert.assertTrue(Arrays.areEqual(r.toByteArray(), expectedR));
+ }
+}
From b69dd7362348e9b285d7d3be34ee48f31b9c47a9 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Fri, 31 Jan 2025 16:59:02 +1030
Subject: [PATCH 166/890] hashToIntegerRange is correct. TODO: fix the curve
definition and pairing function
---
.../crypto/kems/SAKKEKEMSGenerator.java | 140 ++++++++++++++++--
.../bouncycastle/crypto/kems/SAKKEUtils.java | 9 +-
.../crypto/params/SAKKEPublicKey.java | 6 +-
.../crypto/kems/test/SAKKEKEMSTest.java | 105 +++++++++++--
4 files changed, 228 insertions(+), 32 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
index e44d681f12..1024ed7428 100644
--- a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
+++ b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
@@ -7,8 +7,10 @@
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECFieldElement;
import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.math.ec.custom.sec.SecP256R1Curve;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
+import org.bouncycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.nio.ByteBuffer;
@@ -17,12 +19,74 @@
public class SAKKEKEMSGenerator
implements EncapsulatedSecretGenerator
{
- private final SAKKEPublicKey publicParams;
+
+ // private static final BigInteger p = new BigInteger(Hex.decode("997ABB1F 0A563FDA 65C61198 DAD0657A\n" +
+// " 416C0CE1 9CB48261 BE9AE358 B3E01A2E\n" +
+// " F40AAB27 E2FC0F1B 228730D5 31A59CB0\n" +
+// " E791B39F F7C88A19 356D27F4 A666A6D0\n" +
+// " E26C6487 326B4CD4 512AC5CD 65681CE1\n" +
+// " B6AFF4A8 31852A82 A7CF3C52 1C3C09AA\n" +
+// " 9F94D6AF 56971F1F FCE3E823 89857DB0\n" +
+// " 80C5DF10 AC7ACE87 666D807A FEA85FEB"));
+ private static final BigInteger p = new BigInteger(
+ "997ABB1F0A563FDA65C61198DAD0657A416C0CE19CB48261BE9AE358B3E01A2E" +
+ "F40AAB27E2FC0F1B228730D531A59CB0E791B39FF7C88A19356D27F4A666A6D0" +
+ "E26C6487326B4CD4512AC5CD65681CE1B6AFF4A831852A82A7CF3C521C3C09AA" +
+ "9F94D6AF56971F1FFCE3E82389857DB080C5DF10AC7ACE87666D807AFEA85FEB", 16
+ );
+ // private static final BigInteger q = new BigInteger(Hex.decode("265EAEC7 C2958FF6 99718466 36B4195E\n" +
+// " 905B0338 672D2098 6FA6B8D6 2CF8068B\n" +
+// " BD02AAC9 F8BF03C6 C8A1CC35 4C69672C\n" +
+// " 39E46CE7 FDF22286 4D5B49FD 2999A9B4\n" +
+// " 389B1921 CC9AD335 144AB173 595A0738\n" +
+// " 6DABFD2A 0C614AA0 A9F3CF14 870F026A\n" +
+// " A7E535AB D5A5C7C7 FF38FA08 E2615F6C\n" +
+// " 203177C4 2B1EB3A1 D99B601E BFAA17FB"));
+ private static final BigInteger q = new BigInteger(
+ "265EAEC7C2958FF69971846636B4195E905B0338672D20986FA6B8D62CF8068B" +
+ "BD02AAC9F8BF03C6C8A1CC354C69672C39E46CE7FDF222864D5B49FD2999A9B4" +
+ "389B1921CC9AD335144AB173595A07386DABFD2A0C614AA0A9F3CF14870F026A" +
+ "A7E535ABD5A5C7C7FF38FA08E2615F6C203177C42B1EB3A1D99B601EBFAA17FB", 16
+ );
+// private static final BigInteger a = BigInteger.valueOf(-3).mod(p); // y² = x³ - 3x
+// private static final BigInteger b = BigInteger.ZERO;
+// private static final ECCurve.Fp curve = new ECCurve.Fp(
+// p, // Prime p
+// BigInteger.valueOf(-3).mod(p), // a = -3
+// BigInteger.ZERO, // b = 0
+// q, // Order of the subgroup (from RFC 6509)
+// BigInteger.ONE // Cofactor = 1
+// );
+
+ // Base point P = (Px, Py)
+ private static final BigInteger Px = new BigInteger(
+ "53FC09EE332C29AD0A7990053ED9B52A2B1A2FD60AEC69C698B2F204B6FF7CBF" +
+ "B5EDB6C0F6CE2308AB10DB9030B09E1043D5F22CDB9DFA55718BD9E7406CE890" +
+ "9760AF765DD5BCCB337C86548B72F2E1A702C3397A60DE74A7C1514DBA66910D" +
+ "D5CFB4CC80728D87EE9163A5B63F73EC80EC46C4967E0979880DC8ABEAE63895", 16
+ );
+
+ private static final BigInteger Py = new BigInteger(
+ "0A8249063F6009F1F9F1F0533634A135D3E82016029906963D778D821E141178" +
+ "F5EA69F4654EC2B9E7F7F5E5F0DE55F66B598CCF9A140B2E416CFF0CA9E032B9" +
+ "70DAE117AD547C6CCAD696B5B7652FE0AC6F1E80164AA989492D979FC5A4D5F2" +
+ "13515AD7E9CB99A980BDAD5AD5BB4636ADB9B5706A67DCDE75573FD71BEF16D7", 16
+ );
+
+
+ BigInteger g = new BigInteger(Hex.decode("66FC2A43 2B6EA392 148F1586 7D623068\n" +
+ " C6A87BD1 FB94C41E 27FABE65 8E015A87\n" +
+ " 371E9474 4C96FEDA 449AE956 3F8BC446\n" +
+ " CBFDA85D 5D00EF57 7072DA8F 541721BE\n" +
+ " EE0FAED1 828EAB90 B99DFB01 38C78433\n" +
+ " 55DF0460 B4A9FD74 B4F1A32B CAFA1FFA\n" +
+ " D682C033 A7942BCC E3720F20 B9B7B040\n" +
+ " 3C8CAE87 B7A0042A CDE0FAB3 6461EA46"));
+ private final int n = 128;
private final SecureRandom random;
- public SAKKEKEMSGenerator(SAKKEPublicKey params, SecureRandom random)
+ public SAKKEKEMSGenerator(SecureRandom random)
{
- this.publicParams = params;
this.random = random;
}
@@ -30,20 +94,67 @@ public SAKKEKEMSGenerator(SAKKEPublicKey params, SecureRandom random)
public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recipientKey)
{
// 1. Generate random SSV in range [0, 2^n - 1]
- BigInteger ssv = new BigInteger(publicParams.getN(), random);
+ BigInteger ssv = new BigInteger("123456789ABCDEF0123456789ABCDEF0", 16);//new BigInteger(n, random);
// 2. Compute r = HashToIntegerRange(SSV || b, q)
- BigInteger b = getRecipientId((SAKKEPublicKey)recipientKey);
- BigInteger r = SAKKEUtils.hashToIntegerRange(Arrays.concatenate(ssv.toByteArray(), b.toByteArray()), publicParams.getQ());
-
+ BigInteger b = new BigInteger("323031312D30320074656C3A2B34343737303039303031323300", 16); //getRecipientId((SAKKEPublicKey)recipientKey);
+ BigInteger r = SAKKEUtils.hashToIntegerRange(Arrays.concatenate(ssv.toByteArray(), b.toByteArray()), q);
+ System.out.println(new String(Hex.encode(r.toByteArray())));
+ ECCurve.Fp curve = new ECCurve.Fp(
+ p, // Prime p
+ BigInteger.valueOf(-3).mod(p), // a = -3
+ BigInteger.ZERO, // ,
+ g, // Order of the subgroup (from RFC 6509)
+ BigInteger.ONE // Cofactor = 1
+ );
+ ECPoint P = curve.createPoint(Px, Py);
+ ECPoint G = curve.createPoint(
+ new BigInteger(Hex.decode("53FC09EE 332C29AD 0A799005 3ED9B52A\n" +
+ " 2B1A2FD6 0AEC69C6 98B2F204 B6FF7CBF\n" +
+ " B5EDB6C0 F6CE2308 AB10DB90 30B09E10\n" +
+ " 43D5F22C DB9DFA55 718BD9E7 406CE890\n" +
+ " 9760AF76 5DD5BCCB 337C8654 8B72F2E1\n" +
+ " A702C339 7A60DE74 A7C1514D BA66910D\n" +
+ " D5CFB4CC 80728D87 EE9163A5 B63F73EC\n" +
+ " 80EC46C4 967E0979 880DC8AB EAE63895")), // Px
+ new BigInteger(Hex.decode("0A824906 3F6009F1 F9F1F053 3634A135\n" +
+ " D3E82016 02990696 3D778D82 1E141178\n" +
+ " F5EA69F4 654EC2B9 E7F7F5E5 F0DE55F6\n" +
+ " 6B598CCF 9A140B2E 416CFF0C A9E032B9\n" +
+ " 70DAE117 AD547C6C CAD696B5 B7652FE0\n" +
+ " AC6F1E80 164AA989 492D979F C5A4D5F2\n" +
+ " 13515AD7 E9CB99A9 80BDAD5A D5BB4636\n" +
+ " ADB9B570 6A67DCDE 75573FD7 1BEF16D7")) // Py
+ );
+ ECPoint Z = curve.createPoint(
+ new BigInteger("5958EF1B1679BF099B3A030DF255AA6A" +
+ "23C1D8F143D4D23F753E69BD27A832F3" +
+ "8CB4AD53DDEF4260B0FE8BB45C4C1FF5" +
+ "10EFFE300367A37B61F701D914AEF097" +
+ "24825FA0707D61A6DFF4FBD7273566CD" +
+ "DE352A0B04B7C16A78309BE640697DE7" +
+ "47613A5FC195E8B9F328852A579DB8F9" +
+ "9B1D0034479EA9C5595F47C4B2F54FF2", 16), // Px
+ new BigInteger("1508D37514DCF7A8E143A6058C09A6BF" +
+ "2C9858CA37C258065AE6BF7532BC8B5B" +
+ "63383866E0753C5AC0E72709F8445F2E" +
+ "6178E065857E0EDA10F68206B63505ED" +
+ "87E534FB2831FF957FB7DC619DAE6130" +
+ "1EEACC2FDA3680EA4999258A833CEA8F" +
+ "C67C6D19487FB449059F26CC8AAB655A" +
+ "B58B7CC796E24E9A394095754F5F8BAE", 16) // Py
+ );
// 3. Compute R_(b,S) = [r]([b]P + Z_S)
- ECPoint bP = publicParams.getP().multiply(b); // [b]P
- ECPoint Z_S = publicParams.getZ(); // Z_S
+ ECPoint bP = P.multiply(b).normalize();
+ ECPoint Z_S = Z;// P.multiply(ssv).normalize();;//.multiply(new BigInteger("AFF429D35F84B110D094803B3595A6E2998BC99F", 16)); // Z_S
ECPoint R_bS = bP.add(Z_S).multiply(r); // [r]([b]P + Z_S)
+ System.out.println("R_Bs x:" + new String(Hex.encode(R_bS.getXCoord().toBigInteger().toByteArray())));
+ System.out.println("R_Bs y:" + new String(Hex.encode(R_bS.getYCoord().toBigInteger().toByteArray())));
+
// 4. Compute H = SSV XOR HashToIntegerRange( g^r, 2^n )
- BigInteger g_r = pairing(R_bS, publicParams.getP(), publicParams.getQ(), publicParams.getP().getCurve().getField().getCharacteristic());
- BigInteger mask = SAKKEUtils.hashToIntegerRange(g_r.toByteArray(), BigInteger.ONE.shiftLeft(publicParams.getN())); // 2^n
+ BigInteger g_r = pairing(R_bS, G, p, q);
+ BigInteger mask = SAKKEUtils.hashToIntegerRange(g_r.toByteArray(), BigInteger.ONE.shiftLeft(n)); // 2^n
BigInteger H = ssv.xor(mask);
@@ -51,7 +162,7 @@ public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recip
byte[] encapsulated = encodeData(R_bS, H);
return new SecretWithEncapsulationImpl(
- BigIntegers.asUnsignedByteArray(publicParams.getN() / 8, ssv), // Output SSV as key material
+ BigIntegers.asUnsignedByteArray(n / 8, ssv), // Output SSV as key material
encapsulated
);
}
@@ -123,7 +234,7 @@ public static BigInteger pairing(ECPoint R, ECPoint Q, BigInteger p, BigInteger
private static BigInteger computeFpRepresentative(ECFieldElement t, ECCurve curve)
{
// Characteristic of F_p
- BigInteger p = ((ECCurve.Fp) curve).getQ();
+ BigInteger p = ((ECCurve.Fp)curve).getQ();
// Assume t = a + i * b in F_p² → extract a, b
ECFieldElement a = t; // In F_p², a is the real part
@@ -133,7 +244,8 @@ private static BigInteger computeFpRepresentative(ECFieldElement t, ECCurve curv
return b.toBigInteger().multiply(a.toBigInteger().modInverse(p)).mod(p);
}
- public static byte[] encodeData(ECPoint R_bS, BigInteger H) {
+ public static byte[] encodeData(ECPoint R_bS, BigInteger H)
+ {
// 1. Serialize EC Point (use compressed format for efficiency)
byte[] R_bS_bytes = R_bS.getEncoded(true);
diff --git a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEUtils.java b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEUtils.java
index bc3a9a90f2..05938e2ac5 100644
--- a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEUtils.java
+++ b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEUtils.java
@@ -5,7 +5,6 @@
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.math.ec.ECPoint;
-import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
public class SAKKEUtils
@@ -30,22 +29,22 @@ public static BigInteger hashToIntegerRange(byte[] input, BigInteger q)
BigInteger v = BigInteger.ZERO;
// Step 4: Compute h_i and v_i
- for (int i = 1; i <= l; i++)
+ for (int i = 0; i <= l; i++)
{
// h_i = hashfn(h_{i-1})
digest.update(h, 0, h.length);
digest.doFinal(h, 0);
- System.out.println("h_"+i+":" +new String(Hex.encode(h)));
+ //System.out.println("h_"+i+":" +new String(Hex.encode(h)));
// v_i = hashfn(h_i || A)
digest.update(h, 0, h.length);
digest.update(A, 0, A.length);
byte[] v_i = new byte[digest.getDigestSize()];
digest.doFinal(v_i, 0);
- System.out.println("v_"+i+":" +new String(Hex.encode(v_i)));
+ //System.out.println("v_"+i+":" +new String(Hex.encode(v_i)));
// Append v_i to v'
v = v.shiftLeft(v_i.length * 8).add(new BigInteger(1, v_i));
}
- System.out.println("v:" +new String(Hex.encode(v.toByteArray())));
+ //System.out.println("v:" +new String(Hex.encode(v.toByteArray())));
// Step 6: v = v' mod n
return v.mod(q);
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKey.java b/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKey.java
index 81829f9caf..c992dbb70b 100644
--- a/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKey.java
+++ b/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKey.java
@@ -4,20 +4,20 @@
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.math.ec.custom.sec.SecP256R1Curve;
public class SAKKEPublicKey
extends AsymmetricKeyParameter
{
- private final ECCurve curve;
+ private final ECCurve curve = new SecP256R1Curve();
private final ECPoint P; // Base point
private final ECPoint Z; // KMS Public Key: Z = [z]P
private final BigInteger q; // Subgroup order
private final int n; // SSV bit length
- public SAKKEPublicKey(ECCurve curve, ECPoint P, ECPoint Z, BigInteger q, int n)
+ public SAKKEPublicKey(ECPoint P, ECPoint Z, BigInteger q, int n)
{
super(false);
- this.curve = curve;
this.P = P;
this.Z = Z;
this.q = q;
diff --git a/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java b/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
index 61ba76350d..4a40e99c5c 100644
--- a/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
@@ -1,13 +1,17 @@
package org.bouncycastle.crypto.kems.test;
import java.math.BigInteger;
+import java.security.SecureRandom;
import org.bouncycastle.crypto.kems.SAKKEKEMSGenerator;
import org.bouncycastle.crypto.kems.SAKKEUtils;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
+import org.bouncycastle.util.test.FixedSecureRandom;
import org.bouncycastle.util.test.SimpleTest;
import org.junit.Assert;
@@ -55,13 +59,29 @@ public String getName()
public void performTest()
throws Exception
{
-// BigInteger z = new BigInteger("AFF429D35F84B110D094803B3595A6E2998BC99F");
-// BigInteger Zx = new BigInteger("5958EF1B1679BF099B3A030DF255AA6A23C1D8F143D4D23F753E69BD27A832F38CB4AD53DDEF"
-// + "4260B0FE8BB45C4C1FF510EFFE300367A37B61F701D914AEF09724825FA0707D61A6DFF4FBD7273566CDDE352A0B04B7C16A78309BE"
-// + "640697DE747613A5FC195E8B9F328852A579DB8F99B1D0034479EA9C5595F47C4B2F54FF2");
-// BigInteger Zy = new BigInteger("1508D37514DCF7A8E143A6058C09A6BF2C9858CA37C258065AE6BF7532BC8B5B63383866E075"
-// + "3C5AC0E72709F8445F2E6178E065857E0EDA10F68206B63505ED87E534FB2831FF957FB7DC619DAE61301EEACC2FDA3680EA499925" +
-// "8A833CEA8FC67C6D19487FB449059F26CC8AAB655AB58B7CC796E24E9A394095754F5F8BAE");
+ BigInteger g = new BigInteger(Hex.decode("66FC2A43 2B6EA392 148F1586 7D623068" +
+ " C6A87BD1 FB94C41E 27FABE65 8E015A87" +
+ " 371E9474 4C96FEDA 449AE956 3F8BC446" +
+ " CBFDA85D 5D00EF57 7072DA8F 541721BE" +
+ " EE0FAED1 828EAB90 B99DFB01 38C78433" +
+ " 55DF0460 B4A9FD74 B4F1A32B CAFA1FFA" +
+ " D682C033 A7942BCC E3720F20 B9B7B040" +
+ " 3C8CAE87 B7A0042A CDE0FAB3 6461EA46"));
+ BigInteger z = new BigInteger(Hex.decode("AFF429D35F84B110D094803B3595A6E2998BC99F"));
+ BigInteger Zx = new BigInteger(Hex.decode("5958EF1B1679BF099B3A030DF255AA6A23C1D8F143D4D23F753E69BD27A832F38CB4AD53DDEF"
+ + "4260B0FE8BB45C4C1FF510EFFE300367A37B61F701D914AEF09724825FA0707D61A6DFF4FBD7273566CDDE352A0B04B7C16A78309BE"
+ + "640697DE747613A5FC195E8B9F328852A579DB8F99B1D0034479EA9C5595F47C4B2F54FF2"));
+ BigInteger Zy = new BigInteger(Hex.decode("1508D37514DCF7A8E143A6058C09A6BF2C9858CA37C258065AE6BF7532BC8B5B63383866E075"
+ + "3C5AC0E72709F8445F2E6178E065857E0EDA10F68206B63505ED87E534FB2831FF957FB7DC619DAE61301EEACC2FDA3680EA499925" +
+ "8A833CEA8FC67C6D19487FB449059F26CC8AAB655AB58B7CC796E24E9A394095754F5F8BAE"));
+ BigInteger q = new BigInteger(Hex.decode("265EAEC7 C2958FF6 99718466 36B4195E" +
+ " 905B0338 672D2098 6FA6B8D6 2CF8068B" +
+ " BD02AAC9 F8BF03C6 C8A1CC35 4C69672C" +
+ " 39E46CE7 FDF22286 4D5B49FD 2999A9B4" +
+ " 389B1921 CC9AD335 144AB173 595A0738" +
+ " 6DABFD2A 0C614AA0 A9F3CF14 870F026A" +
+ " A7E535AB D5A5C7C7 FF38FA08 E2615F6C" +
+ " 203177C4 2B1EB3A1 D99B601E BFAA17FB"));
//
byte[] b = Hex.decode("323031312D30320074656C3A2B34343737303039303031323300");
@@ -70,12 +90,77 @@ public void performTest()
+ "42ED39BD4FB131012ECCA2ECD2119414560C17CAB46B956A80F58A3302EB3E2C9A228FBA7ED34D8ACA2392DA1FFB0B17B2320AE09AAEDF"
+ "D0235F6FE0EB65337A63F9CC97728B8E5AD0460FADE144369AA5B2166213247712096");
- BigInteger r = SAKKEUtils.hashToIntegerRange(Arrays.concatenate(SSV, b), BigInteger.valueOf(1024));
+ BigInteger kbx = new BigInteger("93AF67E5007BA6E6A80DA793DA300FA4" +
+ "B52D0A74E25E6E7B2B3D6EE9D18A9B5C" +
+ "5023597BD82D8062D34019563BA1D25C" +
+ "0DC56B7B979D74AA50F29FBF11CC2C93" +
+ "F5DFCA615E609279F6175CEADB00B58C" +
+ "6BEE1E7A2A47C4F0C456F05259A6FA94" +
+ "A634A40DAE1DF593D4FECF688D5FC678" +
+ "BE7EFC6DF3D6835325B83B2C6E69036B", 16);
- System.out.println("r:" +new String(Hex.encode(r.toByteArray())));
+ BigInteger kby = new BigInteger("155F0A27241094B04BFB0BDFAC6C670A" +
+ "65C325D39A069F03659D44CA27D3BE8D" +
+ "F311172B554160181CBE94A2A783320C" +
+ "ED590BC42644702CF371271E496BF20F" +
+ "588B78A1BC01ECBB6559934BDD2FB65D" +
+ "2884318A33D1A42ADF5E33CC5800280B" +
+ "28356497F87135BAB9612A1726042440" +
+ "9AC15FEE996B744C332151235DECB0F5", 16);
+ BigInteger w = new BigInteger(Hex.decode("7D2A8438 E6291C64 9B6579EB 3B79EAE9" +
+ "48B1DE9E 5F7D1F40 70A08F8D B6B3C515" +
+ "6F2201AF FBB5CB9D 82AA3EC0 D0398B89" +
+ "ABC78A13 A760C0BF 3F77E63D 0DF3F1A3" +
+ "41A41B88 11DF197F D6CD0F00 3125606F" +
+ "4F109F40 0F7292A1 0D255E3C 0EBCCB42" +
+ "53FB182C 68F09CF6 CD9C4A53 DA6C74AD" +
+ "007AF36B 8BCA979D 5895E282 F483FCD6"));
+ BigInteger Rbx = new BigInteger(Hex.decode("44E8AD44 AB8592A6 A5A3DDCA 5CF896C7" +
+ "18043606 A01D650D EF37A01F 37C228C3" +
+ "32FC3173 54E2C274 D4DAF8AD 001054C7" +
+ "6CE57971 C6F4486D 57230432 61C506EB" +
+ "F5BE438F 53DE04F0 67C776E0 DD3B71A6" +
+ "29013328 3725A532 F21AF145 126DC1D7" +
+ "77ECC27B E50835BD 28098B8A 73D9F801" +
+ "D893793A 41FF5C49 B87E79F2 BE4D56CE"));
+ BigInteger Rby = new BigInteger(Hex.decode("557E134A D85BB1D4 B9CE4F8B E4B08A12" +
+ "BABF55B1 D6F1D7A6 38019EA2 8E15AB1C" +
+ "9F76375F DD1210D4 F4351B9A 009486B7" +
+ "F3ED46C9 65DED2D8 0DADE4F3 8C6721D5" +
+ "2C3AD103 A10EBD29 59248B4E F006836B" +
+ "F097448E 6107C9ED EE9FB704 823DF199" +
+ "F832C905 AE45F8A2 47A072D8 EF729EAB" +
+ "C5E27574 B07739B3 4BE74A53 2F747B86"));
+ BigInteger p = new BigInteger(
+ "997ABB1F0A563FDA65C61198DAD0657A416C0CE19CB48261BE9AE358B3E01A2E" +
+ "F40AAB27E2FC0F1B228730D531A59CB0E791B39FF7C88A19356D27F4A666A6D0" +
+ "E26C6487326B4CD4512AC5CD65681CE1B6AFF4A831852A82A7CF3C521C3C09AA" +
+ "9F94D6AF56971F1FFCE3E82389857DB080C5DF10AC7ACE87666D807AFEA85FEB", 16
+ );
- System.out.println("r:" +new String(Hex.encode(expectedR)));
+ ECCurve.Fp curve = new ECCurve.Fp(
+ p, // Prime p
+ BigInteger.valueOf(-3).mod(p), // a = -3
+ BigInteger.ZERO, // ,
+ q,// Order of the subgroup (from RFC 6509)
+ BigInteger.ONE // Cofactor = 1
+ );
+
+ ECPoint K_bS = curve.createPoint(kbx, kby);
+ System.out.println("K_bS x:" + new String(Hex.encode(K_bS.getXCoord().toBigInteger().toByteArray())));
+ System.out.println("K_bS y:" + new String(Hex.encode(K_bS.getYCoord().toBigInteger().toByteArray())));
+ ECPoint R_bs = curve.createPoint(Rbx, Rby);
+ SAKKEKEMSGenerator.pairing(K_bS, R_bs, p, q);
+
+ BigInteger r = SAKKEUtils.hashToIntegerRange(Arrays.concatenate(SSV, b), q);
+
+ System.out.println("r:" + new String(Hex.encode(r.toByteArray())));
+
+ System.out.println("r:" + new String(Hex.encode(expectedR)));
Assert.assertTrue(Arrays.areEqual(r.toByteArray(), expectedR));
+ SAKKEKEMSGenerator generator = new SAKKEKEMSGenerator(new SecureRandom());
+ generator.generateEncapsulated(null);
+
}
}
From d53e3ab82d908e46acb4d1c7a7972ece07ae0d37 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Fri, 31 Jan 2025 21:49:58 +1030
Subject: [PATCH 167/890] Fix step 3.
---
.../org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java | 4 ++--
.../org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java | 9 +++++----
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
index 1024ed7428..e8f53b2cd7 100644
--- a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
+++ b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
@@ -144,10 +144,10 @@ public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recip
"C67C6D19487FB449059F26CC8AAB655A" +
"B58B7CC796E24E9A394095754F5F8BAE", 16) // Py
);
+ BigInteger z = new BigInteger("AFF429D35F84B110D094803B3595A6E2998BC99F", 16);
// 3. Compute R_(b,S) = [r]([b]P + Z_S)
ECPoint bP = P.multiply(b).normalize();
- ECPoint Z_S = Z;// P.multiply(ssv).normalize();;//.multiply(new BigInteger("AFF429D35F84B110D094803B3595A6E2998BC99F", 16)); // Z_S
- ECPoint R_bS = bP.add(Z_S).multiply(r); // [r]([b]P + Z_S)
+ ECPoint R_bS = bP.add(Z).multiply(r).normalize(); // [r]([b]P + Z_S)
System.out.println("R_Bs x:" + new String(Hex.encode(R_bS.getXCoord().toBigInteger().toByteArray())));
System.out.println("R_Bs y:" + new String(Hex.encode(R_bS.getYCoord().toBigInteger().toByteArray())));
diff --git a/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java b/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
index 4a40e99c5c..cbe940a064 100644
--- a/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
@@ -142,10 +142,11 @@ public void performTest()
p, // Prime p
BigInteger.valueOf(-3).mod(p), // a = -3
BigInteger.ZERO, // ,
- q,// Order of the subgroup (from RFC 6509)
+ g,// Order of the subgroup (from RFC 6509)
BigInteger.ONE // Cofactor = 1
);
-
+ SAKKEKEMSGenerator generator = new SAKKEKEMSGenerator(new SecureRandom());
+ generator.generateEncapsulated(null);
ECPoint K_bS = curve.createPoint(kbx, kby);
System.out.println("K_bS x:" + new String(Hex.encode(K_bS.getXCoord().toBigInteger().toByteArray())));
System.out.println("K_bS y:" + new String(Hex.encode(K_bS.getYCoord().toBigInteger().toByteArray())));
@@ -159,8 +160,8 @@ public void performTest()
System.out.println("r:" + new String(Hex.encode(expectedR)));
Assert.assertTrue(Arrays.areEqual(r.toByteArray(), expectedR));
- SAKKEKEMSGenerator generator = new SAKKEKEMSGenerator(new SecureRandom());
- generator.generateEncapsulated(null);
+// SAKKEKEMSGenerator generator = new SAKKEKEMSGenerator(new SecureRandom());
+// generator.generateEncapsulated(null);
}
}
From 2434c1c56c1df052bfbe877470b9467325dced78 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Mon, 3 Feb 2025 18:07:28 +1030
Subject: [PATCH 168/890] TODO fix the bugs in SAKKEKEMExtractor
---
.../crypto/kems/SAKKEKEMExtractor.java | 128 +++++++
.../crypto/kems/SAKKEKEMSGenerator.java | 351 ++++++++++++++++--
.../bouncycastle/crypto/kems/SAKKEUtils.java | 32 ++
...ey.java => SAKKEPrivateKeyParameters.java} | 19 +-
.../crypto/params/SAKKEPublicKey.java | 52 ---
.../params/SAKKEPublicKeyParameters.java | 100 +++++
.../crypto/kems/test/SAKKEKEMSTest.java | 13 +-
7 files changed, 597 insertions(+), 98 deletions(-)
create mode 100644 core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java
rename core/src/main/java/org/bouncycastle/crypto/params/{SAKKEPrivateKey.java => SAKKEPrivateKeyParameters.java} (63%)
delete mode 100644 core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKey.java
create mode 100644 core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKeyParameters.java
diff --git a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java
new file mode 100644
index 0000000000..caff3dffa5
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java
@@ -0,0 +1,128 @@
+package org.bouncycastle.crypto.kems;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.EncapsulatedSecretExtractor;
+import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.params.SAKKEPrivateKeyParameters;
+import org.bouncycastle.crypto.params.SAKKEPublicKeyParameters;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.BigIntegers;
+
+import static org.bouncycastle.crypto.kems.SAKKEKEMSGenerator.pairing;
+
+public class SAKKEKEMExtractor implements EncapsulatedSecretExtractor
+{
+ private final ECCurve curve;
+ private final BigInteger p;
+ private final BigInteger q;
+ private final ECPoint P;
+ private final ECPoint Z_S;
+ private final ECPoint K_bS; // Receiver's RSK
+ private final int n; // Security parameter
+ private final SAKKEPrivateKeyParameters privateKey;
+
+ public SAKKEKEMExtractor(SAKKEPrivateKeyParameters privateKey) {
+ this.privateKey = privateKey;
+ SAKKEPublicKeyParameters publicKey = privateKey.getPublicParams();
+ this.curve = publicKey.getCurve();
+ this.q = publicKey.getQ();
+ this.P = publicKey.getP();
+ this.p = publicKey.getp();
+ this.Z_S = publicKey.getZ();
+ this.K_bS = privateKey.getPrivatePoint();
+ this.n = publicKey.getN();
+ }
+
+ @Override
+ public byte[] extractSecret(byte[] encapsulation) {
+ try {
+ // Step 1: Parse Encapsulated Data (R_bS, H)
+ ECPoint R_bS = parseECPoint(encapsulation);
+ BigInteger H = parseH(encapsulation);
+
+ // Step 2: Compute w = using pairing
+ BigInteger w = computePairing(R_bS, K_bS);
+
+ // Step 3: Compute SSV = H XOR HashToIntegerRange(w, 2^n)
+ BigInteger ssv = computeSSV(H, w);
+
+ // Step 4: Compute r = HashToIntegerRange(SSV || b)
+// BigInteger r = computeR(ssv, privateKey.getPrivatePoint());
+//
+// // Step 5: Validate R_bS
+// if (!validateR_bS(r, privateKey.getPrivatePoint(), R_bS)) {
+// throw new IllegalStateException("Validation of R_bS failed");
+// }
+
+ return BigIntegers.asUnsignedByteArray(n/8, ssv);
+ } catch (Exception e) {
+ throw new IllegalStateException("SAKKE extraction failed: " + e.getMessage());
+ }
+ }
+
+ @Override
+ public int getEncapsulationLength()
+ {
+ return 0;
+ }
+
+ private ECPoint parseECPoint(byte[] encapsulation) {
+ int coordLen = (p.bitLength() + 7) / 8;
+ byte[] xBytes = Arrays.copyOfRange(encapsulation, 0, coordLen);
+ byte[] yBytes = Arrays.copyOfRange(encapsulation, coordLen, 2*coordLen);
+
+ BigInteger x = new BigInteger(1, xBytes);
+ BigInteger y = new BigInteger(1, yBytes);
+
+ return curve.createPoint(x, y).normalize();
+ }
+
+ private BigInteger parseH(byte[] encapsulation) {
+ int coordLen = (p.bitLength() + 7) / 8;
+ byte[] hBytes = Arrays.copyOfRange(encapsulation, 2*coordLen, encapsulation.length);
+ return new BigInteger(1, hBytes);
+ }
+
+ private BigInteger computePairing(ECPoint R, ECPoint K) {
+ // Use your existing pairing implementation
+ return pairing(R, K, p, q);
+ }
+
+ private BigInteger computeSSV(BigInteger H, BigInteger w) {
+ BigInteger twoToN = BigInteger.ONE.shiftLeft(n);
+ BigInteger mask = SAKKEUtils.hashToIntegerRange(w.toByteArray(), twoToN);
+ return H.xor(mask);
+ }
+
+ private BigInteger computeR(BigInteger ssv, byte[] userId) {
+ byte[] ssvBytes = BigIntegers.asUnsignedByteArray(ssv);
+ byte[] ssvConcatB = Arrays.concatenate(ssvBytes, userId);
+ return SAKKEUtils.hashToIntegerRange(ssvConcatB, q);
+ }
+
+ private boolean validateR_bS(BigInteger r, byte[] b, ECPoint receivedR) {
+ try {
+ // Compute [b]P
+ ECPoint bP = P.multiply(new BigInteger(1, b)).normalize();
+
+ // Compute [b]P + Z_S
+ ECPoint bP_plus_Z = bP.add(Z_S).normalize();
+
+ // Compute [r]([b]P + Z_S)
+ ECPoint computedR = bP_plus_Z.multiply(r).normalize();
+
+ return pointsEqual(computedR, receivedR);
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ private boolean pointsEqual(ECPoint p1, ECPoint p2) {
+ return p1.normalize().getXCoord().equals(p2.normalize().getXCoord())
+ && p1.normalize().getYCoord().equals(p2.normalize().getYCoord());
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
index e8f53b2cd7..df94f031ae 100644
--- a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
+++ b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
@@ -3,11 +3,10 @@
import org.bouncycastle.crypto.EncapsulatedSecretGenerator;
import org.bouncycastle.crypto.SecretWithEncapsulation;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
-import org.bouncycastle.crypto.params.SAKKEPublicKey;
+import org.bouncycastle.crypto.params.SAKKEPublicKeyParameters;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECFieldElement;
import org.bouncycastle.math.ec.ECPoint;
-import org.bouncycastle.math.ec.custom.sec.SecP256R1Curve;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
import org.bouncycastle.util.encoders.Hex;
@@ -153,8 +152,21 @@ public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recip
// 4. Compute H = SSV XOR HashToIntegerRange( g^r, 2^n )
- BigInteger g_r = pairing(R_bS, G, p, q);
+ BigInteger[] result = fp2Exponentiate(p, BigInteger.ONE, g, r);
+ BigInteger g_r = result[0].mod(p);
+ g_r = g_r.modInverse(p);
+ g_r = g_r.multiply(result[1]).mod(p);
+ System.out.println("g_r " + new String(Hex.encode(g_r.toByteArray())));
+ byte[] expected_g_r = Hex.decode("7D2A8438 E6291C64 9B6579EB 3B79EAE9\n" +
+ " 48B1DE9E 5F7D1F40 70A08F8D B6B3C515\n" +
+ " 6F2201AF FBB5CB9D 82AA3EC0 D0398B89\n" +
+ " ABC78A13 A760C0BF 3F77E63D 0DF3F1A3\n" +
+ " 41A41B88 11DF197F D6CD0F00 3125606F\n" +
+ " 4F109F40 0F7292A1 0D255E3C 0EBCCB42\n" +
+ " 53FB182C 68F09CF6 CD9C4A53 DA6C74AD\n" +
+ " 007AF36B 8BCA979D 5895E282 F483FCD6");
BigInteger mask = SAKKEUtils.hashToIntegerRange(g_r.toByteArray(), BigInteger.ONE.shiftLeft(n)); // 2^n
+ System.out.println(new String(Hex.encode(mask.toByteArray())));
BigInteger H = ssv.xor(mask);
@@ -162,17 +174,158 @@ public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recip
byte[] encapsulated = encodeData(R_bS, H);
return new SecretWithEncapsulationImpl(
- BigIntegers.asUnsignedByteArray(n / 8, ssv), // Output SSV as key material
- encapsulated
+ encapsulated,
+ BigIntegers.asUnsignedByteArray(n / 8, ssv) // Output SSV as key material
);
}
- private BigInteger getRecipientId(SAKKEPublicKey pubKey)
+
+ // Helper method for F_p² exponentiation
+ public static BigInteger[] fp2Exponentiate(
+ BigInteger p,
+ BigInteger x,
+ BigInteger y,
+ BigInteger exponent
+ )
+ {
+ BigInteger[] result = new BigInteger[2];
+ sakkePointExponent(p, result, x, y, exponent);
+ return result;
+ }
+
+ public static boolean sakkePointExponent(
+ BigInteger p,
+ BigInteger[] result,
+ BigInteger pointX,
+ BigInteger pointY,
+ BigInteger n
+ )
+ {
+ if (n.equals(BigInteger.ZERO))
+ {
+ return false;
+ }
+
+ // Initialize result with the original point
+ BigInteger currentX = pointX;
+ BigInteger currentY = pointY;
+
+ int numBits = n.bitLength();
+
+ // Process bits from MSB-1 down to 0
+ for (int i = numBits - 2; i >= 0; i--)
+ {
+ // Square the current point
+ //sakkePointSquare(p, new BigInteger[]{currentX, currentY});
+ // Compute newX = (x + y)(x - y) mod p
+ BigInteger xPlusY = currentX.add(currentY).mod(p);
+ BigInteger xMinusY = currentX.subtract(currentY).mod(p);
+ BigInteger newX = xPlusY.multiply(xMinusY).mod(p);
+
+ // Compute newY = 2xy mod p
+ BigInteger newY = currentX.multiply(currentY).multiply(BigInteger.valueOf(2)).mod(p);
+ currentX = newX;
+ currentY = newY;
+ // Multiply if bit is set
+ if (n.testBit(i))
+ {
+ //sakkePointsMultiply(p, currentX, currentY, pointX, pointY);
+ BigInteger real = currentX.multiply(pointX)
+ .subtract(currentY.multiply(pointY))
+ .mod(p);
+
+ // Compute imaginary part = x1*y2 + x2*y1 mod p
+ BigInteger imag = currentX.multiply(pointY)
+ .add(pointX.multiply(currentY))
+ .mod(p);
+
+ currentX = real;
+ currentY = imag;
+ }
+ }
+
+ result[0] = currentX;
+ result[1] = currentY;
+ return true;
+ }
+
+
+ private BigInteger getRecipientId(SAKKEPublicKeyParameters pubKey)
{
byte[] hashedId = SAKKEUtils.hash(pubKey.getZ().getEncoded(false)); // Hash Z_S
return new BigInteger(1, hashedId).mod(pubKey.getQ().subtract(BigInteger.ONE)).add(BigIntegers.TWO);
}
+ public static class FP2Element
+ {
+ private final BigInteger a; // Real part
+ private final BigInteger b; // Imaginary part
+ private final BigInteger p; // Prime modulus
+
+ public FP2Element(BigInteger a, BigInteger b, BigInteger p)
+ {
+ this.a = a.mod(p);
+ this.b = b.mod(p);
+ this.p = p;
+ }
+
+ public FP2Element add(FP2Element other)
+ {
+ return new FP2Element(a.add(other.a), b.add(other.b), p);
+ }
+
+ public FP2Element subtract(FP2Element other)
+ {
+ return new FP2Element(a.subtract(other.a), b.subtract(other.b), p);
+ }
+
+ public FP2Element multiply(FP2Element other)
+ {
+ BigInteger real = a.multiply(other.a).subtract(b.multiply(other.b)).mod(p);
+ BigInteger imag = a.multiply(other.b).add(b.multiply(other.a)).mod(p);
+ return new FP2Element(real, imag, p);
+ }
+
+ public FP2Element inverse()
+ {
+ BigInteger denom = a.pow(2).add(b.pow(2)).mod(p);
+ BigInteger invDenom = denom.modInverse(p);
+ return new FP2Element(a.multiply(invDenom), b.negate().multiply(invDenom), p);
+ }
+
+ public FP2Element square()
+ {
+ return this.multiply(this);
+ }
+
+ public FP2Element pow(BigInteger exponent)
+ {
+ // Implement exponentiation using square-and-multiply
+ FP2Element result = new FP2Element(BigInteger.ONE, BigInteger.ZERO, p);
+ FP2Element base = this;
+ for (int i = exponent.bitLength() - 1; i >= 0; i--)
+ {
+ result = result.square();
+ if (exponent.testBit(i))
+ {
+ result = result.multiply(base);
+ }
+ }
+ return result;
+ }
+
+ // Getters
+ public BigInteger getA()
+ {
+ return a;
+ }
+
+ public BigInteger getB()
+ {
+ return b;
+ }
+ }
+
/**
* Computes the Tate-Lichtenbaum pairing ⟨P, Q⟩ as per RFC 6508.
*
@@ -184,53 +337,181 @@ private BigInteger getRecipientId(SAKKEPublicKey pubKey)
public static BigInteger pairing(ECPoint R, ECPoint Q, BigInteger p, BigInteger q)
{
ECCurve curve = R.getCurve();
- ECFieldElement i = curve.fromBigInteger(BigInteger.ONE.negate()); // i = -1 in F_p^2
+ FP2Element v = new FP2Element(BigInteger.ONE, BigInteger.ZERO, p); // Initialize to 1+0i
- ECPoint C = R;
- BigInteger c = p.add(BigInteger.ONE).divide(q);
- ECFieldElement v = curve.fromBigInteger(BigInteger.ONE); // v = 1 in F_p
+ // Use correct exponent from RFC 6508: (p² - 1)/q
+ BigInteger exponent = p.pow(2).subtract(BigInteger.ONE).divide(q);
- String qBits = q.subtract(BigInteger.ONE).toString(2); // Binary representation of q-1
+ String qBits = q.subtract(BigInteger.ONE).toString(2);
+ ECPoint C = R.normalize();
for (int j = 1; j < qBits.length(); j++)
- { // Skip MSB
- // l = (3 * (C_x^2 - 1)) / (2 * C_y)
+ {
+ C = C.normalize();
ECFieldElement Cx = C.getAffineXCoord();
ECFieldElement Cy = C.getAffineYCoord();
- ECFieldElement l = Cx.square().multiply(curve.fromBigInteger(ECFieldElement.THREE)).subtract(curve.fromBigInteger(BigInteger.ONE))
- .divide(Cy.multiply(curve.fromBigInteger(BigIntegers.TWO)));
- // v = v^2 * (l * (Q_x + C_x) + (i * Q_y - C_y))
+ // Line function for doubling
+ ECFieldElement lNum = Cx.square().multiply(curve.fromBigInteger(BigInteger.valueOf(3))).add(curve.getA());
+ ECFieldElement lDen = Cy.multiply(curve.fromBigInteger(BigInteger.valueOf(2)));
+ BigInteger l = lNum.divide(lDen).toBigInteger();
+
+ // Evaluate line at Q using F_p² arithmetic
ECFieldElement Qx = Q.getAffineXCoord();
ECFieldElement Qy = Q.getAffineYCoord();
- v = v.square().multiply(l.multiply(Qx.add(Cx)).add(i.multiply(Qy).subtract(Cy)));
+ FP2Element lineVal = new FP2Element(
+ l.multiply(Qx.add(Cx).toBigInteger()),
+ l.multiply(Qy.toBigInteger()),
+ p
+ );
- // Double the point
- C = C.twice();
+ v = v.multiply(lineVal).pow(BigInteger.valueOf(2));
+ C = C.twice().normalize();
- // If the bit is 1, perform additional step
if (qBits.charAt(j) == '1')
{
- // l = (C_y - R_y) / (C_x - R_x)
- ECFieldElement Rx = R.getAffineXCoord();
- ECFieldElement Ry = R.getAffineYCoord();
- l = Cy.subtract(Ry).divide(Cx.subtract(Rx));
-
- // v = v * (l * (Q_x + C_x) + (i * Q_y - C_y))
- v = v.multiply(l.multiply(Qx.add(Cx)).add(i.multiply(Qy).subtract(Cy)));
-
- // C = C + R
- C = C.add(R);
+ ECPoint Rnorm = R.normalize();
+ ECFieldElement Rx = Rnorm.getAffineXCoord();
+ ECFieldElement Ry = Rnorm.getAffineYCoord();
+
+ // Line function for addition
+ ECFieldElement lAddNum = Cy.subtract(Ry);
+ ECFieldElement lAddDen = Cx.subtract(Rx);
+ BigInteger lAdd = lAddNum.divide(lAddDen).toBigInteger();
+
+ FP2Element lineAddVal = new FP2Element(
+ lAdd.multiply(Qx.add(Cx).toBigInteger()),
+ lAdd.multiply(Qy.toBigInteger()),
+ p
+ );
+
+ v = v.multiply(lineAddVal);
+ C = C.add(Rnorm).normalize();
}
}
- // Compute v^c
- v = curve.fromBigInteger(v.toBigInteger().pow(c.intValue()));
+ // Final exponentiation
+ FP2Element t = v.pow(exponent);
- // Convert to F_p representative
- return computeFpRepresentative(v, curve);
+ // Convert to F_p representative: b/a mod p
+ BigInteger a = t.getA();
+ BigInteger b = t.getB();
+ return b.multiply(a.modInverse(p)).mod(p);
}
+// public static BigInteger pairing(ECPoint R, ECPoint Q, BigInteger p, BigInteger q)
+// {
+// ECCurve curve = R.getCurve();
+// FP2Element i = new FP2Element(BigInteger.ZERO, BigInteger.ONE, p); // i = -1 in F_p^2
+//
+// ECPoint C = R.normalize();
+// BigInteger c = p.add(BigInteger.ONE).divide(q);
+// //ECFieldElement v = curve.fromBigInteger(BigInteger.ONE); // v = 1 in F_p
+// FP2Element v = new FP2Element(BigInteger.ONE, BigInteger.ZERO, p);
+//
+// String qBits = q.subtract(BigInteger.ONE).toString(2); // Binary representation of q-1
+//
+// for (int j = 1; j < qBits.length(); j++)
+// { // Skip MSB
+// // l = (3 * (C_x^2 - 1)) / (2 * C_y)
+// C = C.normalize(); // Add this line to ensure normalization
+// ECFieldElement Cx = C.getAffineXCoord();
+// ECFieldElement Cy = C.getAffineXCoord();
+// BigInteger CxVal = Cx.toBigInteger();
+// BigInteger CyVal = Cy.toBigInteger();
+//// ECFieldElement l = Cx.square().multiply(curve.fromBigInteger(ECFieldElement.THREE)).subtract(curve.fromBigInteger(BigInteger.ONE))
+//// .divide(Cy.multiply(curve.fromBigInteger(BigIntegers.TWO)));
+//
+// // l = 3*(Cx² - 1) / (2*Cy) in F_p
+// ECFieldElement lNum = Cx.square().subtract(curve.fromBigInteger(BigInteger.ONE)).multiply(curve.fromBigInteger(BigInteger.valueOf(3)));
+// ECFieldElement lDen = Cy.multiply(curve.fromBigInteger(BigInteger.valueOf(2)));
+// ECFieldElement l = lNum.divide(lDen);
+// BigInteger lVal = l.toBigInteger();
+//
+// // Evaluate line at [i]Q: (Qx, i*Qy)
+// ECFieldElement Qx = Q.getAffineXCoord();
+// ECFieldElement Qy = Q.getAffineYCoord();
+// BigInteger QxVal = Qx.toBigInteger();
+// BigInteger QyVal = Qy.toBigInteger();
+//
+// // Convert l*(Qx + Cx) to F_p²
+// FP2Element term1 = new FP2Element(lVal.multiply(QxVal.add(CxVal)).mod(p), BigInteger.ZERO, p);
+//
+// // (i*Qy - Cy) in F_p²: (-Cy, Qy)
+// FP2Element term2 = new FP2Element(QyVal.negate().mod(p), QyVal, p); // Wait, original term is i*Qy - Cy: i*Qy is (0, Qy), subtract Cy (Cy,0) gives (-Cy, Qy)
+// FP2Element lineVal = new FP2Element(lVal, BigInteger.ZERO, p) // l is in F_p
+// .multiply(new FP2Element(QxVal.add(CxVal).mod(p), BigInteger.ZERO, p)) // (Qx + Cx) in F_p
+// .add(term2); // i*Qy - Cy
+//
+// v = v.square().multiply(lineVal);
+//
+// C = C.twice().normalize();;
+//
+// // v = v^2 * (l * (Q_x + C_x) + (i * Q_y - C_y))
+//// ECFieldElement Qx = Q.getAffineXCoord();
+//// ECFieldElement Qy = Q.getAffineYCoord();
+//// v = v.square().multiply(l.multiply(Qx.add(Cx)).add(i.multiply(Qy).subtract(Cy)));
+//
+// // Double the point
+//// C = C.twice();
+// if (qBits.charAt(j) == '1')
+// {
+// // Compute line function for addition
+// ECFieldElement Rx = R.getAffineXCoord();
+// ECFieldElement Ry = R.getAffineYCoord();
+// BigInteger RxVal = Rx.toBigInteger();
+// BigInteger RyVal = Ry.toBigInteger();
+//
+// ECFieldElement lAddNum = Cy.subtract(Ry);
+// ECFieldElement lAddDen = Cx.subtract(Rx);
+// ECFieldElement lAdd = lAddNum.divide(lAddDen);
+// BigInteger lAddVal = lAdd.toBigInteger();
+//
+// // Evaluate line at [i]Q
+// FP2Element lineAddTerm1 = new FP2Element(lAddVal.multiply(QxVal.add(CxVal)).mod(p), BigInteger.ZERO, p);
+// FP2Element lineAddTerm2 = new FP2Element(QyVal.negate().mod(p), QyVal, p); // i*Qy - Cy (Cy is current C's y)
+// FP2Element lineAddVal = lineAddTerm1.add(lineAddTerm2);
+//
+// v = v.multiply(lineAddVal);
+//
+// C = C.add(R);
+// }
+//
+//// // If the bit is 1, perform additional step
+//// if (qBits.charAt(j) == '1')
+//// {
+//// // l = (C_y - R_y) / (C_x - R_x)
+//// ECFieldElement Rx = R.getAffineXCoord();
+//// ECFieldElement Ry = R.getAffineYCoord();
+//// l = Cy.subtract(Ry).divide(Cx.subtract(Rx));
+////
+//// // v = v * (l * (Q_x + C_x) + (i * Q_y - C_y))
+//// v = v.multiply(l.multiply(Qx.add(Cx)).add(i.multiply(Qy).subtract(Cy)));
+////
+//// // C = C + R
+//// C = C.add(R);
+//// }
+// }
+//
+//// // Compute v^c
+//// v = curve.fromBigInteger(v.toBigInteger().modPow(c, p));
+////
+//// // Convert to F_p representative
+//// return computeFpRepresentative(v, curve);
+// FP2Element t = v.pow(c);
+//
+// // Compute representative: b/a mod p
+// BigInteger a = t.getA();
+// BigInteger bVal = t.getB();
+// if (a.equals(BigInteger.ZERO)) {
+// throw new ArithmeticException("Division by zero in F_p representative");
+// }
+// BigInteger aInv = a.modInverse(p);
+// BigInteger representative = bVal.multiply(aInv).mod(p);
+//
+// return representative;
+// }
+
private static BigInteger computeFpRepresentative(ECFieldElement t, ECCurve curve)
{
// Characteristic of F_p
@@ -238,7 +519,7 @@ private static BigInteger computeFpRepresentative(ECFieldElement t, ECCurve curv
// Assume t = a + i * b in F_p² → extract a, b
ECFieldElement a = t; // In F_p², a is the real part
- ECFieldElement b = t.multiply(curve.fromBigInteger(BigInteger.ONE.negate())); // Imaginary part
+ ECFieldElement b = t.multiply(curve.fromBigInteger(BigInteger.ONE.negate().add(p))); // Imaginary part
// Compute b/a mod p
return b.toBigInteger().multiply(a.toBigInteger().modInverse(p)).mod(p);
diff --git a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEUtils.java b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEUtils.java
index 05938e2ac5..45fbbb38b5 100644
--- a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEUtils.java
+++ b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEUtils.java
@@ -9,6 +9,38 @@
public class SAKKEUtils
{
+ public static ECPoint sakkePointExponent(ECPoint point, BigInteger n) {
+ if (n.equals(BigInteger.ZERO)) {
+ throw new IllegalArgumentException("Exponent cannot be zero.");
+ }
+
+ ECPoint result = point;
+ int N = n.bitLength() - 1;
+
+ for (; N != 0; --N) {
+ result = sakkePointSquare(result);
+ if (n.testBit(N - 1)) {
+ result = sakkePointsMultiply(result, point);
+ }
+ }
+ return result;
+ }
+
+ public static ECPoint sakkePointSquare(ECPoint point) {
+ BigInteger x = point.getAffineXCoord().toBigInteger();
+ BigInteger y = point.getAffineYCoord().toBigInteger();
+
+ BigInteger bx1 = x.add(y);
+ BigInteger bx2 = x.subtract(y);
+ BigInteger newX = bx1.multiply(bx2).mod(point.getCurve().getField().getCharacteristic());
+ BigInteger newY = x.multiply(y).multiply(BigInteger.valueOf(2)).mod(point.getCurve().getField().getCharacteristic());
+
+ return point.getCurve().createPoint(newX, newY);
+ }
+
+ public static ECPoint sakkePointsMultiply(ECPoint p1, ECPoint p2) {
+ return p1.add(p2).normalize();
+ }
public static BigInteger hashToIntegerRange(byte[] input, BigInteger q)
{
// RFC 6508 Section 5.1: Hashing to an Integer Range
diff --git a/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPrivateKey.java b/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPrivateKeyParameters.java
similarity index 63%
rename from core/src/main/java/org/bouncycastle/crypto/params/SAKKEPrivateKey.java
rename to core/src/main/java/org/bouncycastle/crypto/params/SAKKEPrivateKeyParameters.java
index 02e6d7c54b..2c83f35ba3 100644
--- a/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPrivateKey.java
+++ b/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPrivateKeyParameters.java
@@ -4,14 +4,14 @@
import org.bouncycastle.math.ec.ECPoint;
-public class SAKKEPrivateKey
+public class SAKKEPrivateKeyParameters
extends AsymmetricKeyParameter
{
private final BigInteger b; // User's identity
private final ECPoint K; // Private key K_a
- private final SAKKEPublicKey publicParams;
+ private final SAKKEPublicKeyParameters publicParams;
- public SAKKEPrivateKey(BigInteger b, ECPoint K, SAKKEPublicKey publicParams)
+ public SAKKEPrivateKeyParameters(BigInteger b, ECPoint K, SAKKEPublicKeyParameters publicParams)
{
super(true);
this.b = b;
@@ -19,19 +19,18 @@ public SAKKEPrivateKey(BigInteger b, ECPoint K, SAKKEPublicKey publicParams)
this.publicParams = publicParams;
}
- // Getters
- public ECPoint getK()
- {
- return K;
- }
-
public BigInteger getB()
{
return b;
}
- public SAKKEPublicKey getPublicParams()
+ public SAKKEPublicKeyParameters getPublicParams()
{
return publicParams;
}
+
+ public ECPoint getPrivatePoint()
+ {
+ return K;
+ }
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKey.java b/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKey.java
deleted file mode 100644
index c992dbb70b..0000000000
--- a/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKey.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package org.bouncycastle.crypto.params;
-
-import java.math.BigInteger;
-
-import org.bouncycastle.math.ec.ECCurve;
-import org.bouncycastle.math.ec.ECPoint;
-import org.bouncycastle.math.ec.custom.sec.SecP256R1Curve;
-
-public class SAKKEPublicKey
- extends AsymmetricKeyParameter
-{
- private final ECCurve curve = new SecP256R1Curve();
- private final ECPoint P; // Base point
- private final ECPoint Z; // KMS Public Key: Z = [z]P
- private final BigInteger q; // Subgroup order
- private final int n; // SSV bit length
-
- public SAKKEPublicKey(ECPoint P, ECPoint Z, BigInteger q, int n)
- {
- super(false);
- this.P = P;
- this.Z = Z;
- this.q = q;
- this.n = n;
- }
-
- // Getters
- public ECCurve getCurve()
- {
- return curve;
- }
-
- public ECPoint getP()
- {
- return P;
- }
-
- public ECPoint getZ()
- {
- return Z;
- }
-
- public BigInteger getQ()
- {
- return q;
- }
-
- public int getN()
- {
- return n;
- }
-}
diff --git a/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKeyParameters.java
new file mode 100644
index 0000000000..66ce4e81ef
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKeyParameters.java
@@ -0,0 +1,100 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.util.encoders.Hex;
+
+public class SAKKEPublicKeyParameters
+ extends AsymmetricKeyParameter
+{
+ // Base point
+ private static final BigInteger p = new BigInteger(
+ "997ABB1F0A563FDA65C61198DAD0657A416C0CE19CB48261BE9AE358B3E01A2E" +
+ "F40AAB27E2FC0F1B228730D531A59CB0E791B39FF7C88A19356D27F4A666A6D0" +
+ "E26C6487326B4CD4512AC5CD65681CE1B6AFF4A831852A82A7CF3C521C3C09AA" +
+ "9F94D6AF56971F1FFCE3E82389857DB080C5DF10AC7ACE87666D807AFEA85FEB", 16
+ );
+
+ private static final BigInteger Px = new BigInteger(
+ "53FC09EE332C29AD0A7990053ED9B52A2B1A2FD60AEC69C698B2F204B6FF7CBF" +
+ "B5EDB6C0F6CE2308AB10DB9030B09E1043D5F22CDB9DFA55718BD9E7406CE890" +
+ "9760AF765DD5BCCB337C86548B72F2E1A702C3397A60DE74A7C1514DBA66910D" +
+ "D5CFB4CC80728D87EE9163A5B63F73EC80EC46C4967E0979880DC8ABEAE63895", 16
+ );
+
+ private static final BigInteger Py = new BigInteger(
+ "0A8249063F6009F1F9F1F0533634A135D3E82016029906963D778D821E141178" +
+ "F5EA69F4654EC2B9E7F7F5E5F0DE55F66B598CCF9A140B2E416CFF0CA9E032B9" +
+ "70DAE117AD547C6CCAD696B5B7652FE0AC6F1E80164AA989492D979FC5A4D5F2" +
+ "13515AD7E9CB99A980BDAD5AD5BB4636ADB9B5706A67DCDE75573FD71BEF16D7", 16
+ );
+
+
+ private static final BigInteger g = new BigInteger(Hex.decode("66FC2A43 2B6EA392 148F1586 7D623068\n" +
+ " C6A87BD1 FB94C41E 27FABE65 8E015A87\n" +
+ " 371E9474 4C96FEDA 449AE956 3F8BC446\n" +
+ " CBFDA85D 5D00EF57 7072DA8F 541721BE\n" +
+ " EE0FAED1 828EAB90 B99DFB01 38C78433\n" +
+ " 55DF0460 B4A9FD74 B4F1A32B CAFA1FFA\n" +
+ " D682C033 A7942BCC E3720F20 B9B7B040\n" +
+ " 3C8CAE87 B7A0042A CDE0FAB3 6461EA46"));
+
+ private static final BigInteger q = new BigInteger(
+ "265EAEC7C2958FF69971846636B4195E905B0338672D20986FA6B8D62CF8068B" +
+ "BD02AAC9F8BF03C6C8A1CC354C69672C39E46CE7FDF222864D5B49FD2999A9B4" +
+ "389B1921CC9AD335144AB173595A07386DABFD2A0C614AA0A9F3CF14870F026A" +
+ "A7E535ABD5A5C7C7FF38FA08E2615F6C203177C42B1EB3A1D99B601EBFAA17FB", 16
+ );
+
+ private static final ECCurve.Fp curve = new ECCurve.Fp(
+ p, // Prime p
+ BigInteger.valueOf(-3).mod(p), // a = -3
+ BigInteger.ZERO, // ,
+ g, // Order of the subgroup (from RFC 6509)
+ BigInteger.ONE // Cofactor = 1
+ );
+
+ private static final ECPoint P = curve.createPoint(Px, Py);
+ private final ECPoint Z; // KMS Public Key: Z = [z]P
+
+ private static final int n = 128; // SSV bit length
+
+ public SAKKEPublicKeyParameters(ECPoint Z)
+ {
+ super(false);
+ this.Z = Z;
+ }
+
+ // Getters
+ public ECCurve getCurve()
+ {
+ return curve;
+ }
+
+ public ECPoint getP()
+ {
+ return P;
+ }
+
+ public ECPoint getZ()
+ {
+ return Z;
+ }
+
+ public BigInteger getp()
+ {
+ return p;
+ }
+
+ public BigInteger getQ()
+ {
+ return q;
+ }
+
+ public int getN()
+ {
+ return n;
+ }
+}
diff --git a/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java b/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
index cbe940a064..485965ad59 100644
--- a/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
@@ -4,8 +4,12 @@
import java.security.SecureRandom;
+import org.bouncycastle.crypto.SecretWithEncapsulation;
+import org.bouncycastle.crypto.kems.SAKKEKEMExtractor;
import org.bouncycastle.crypto.kems.SAKKEKEMSGenerator;
import org.bouncycastle.crypto.kems.SAKKEUtils;
+import org.bouncycastle.crypto.params.SAKKEPrivateKeyParameters;
+import org.bouncycastle.crypto.params.SAKKEPublicKeyParameters;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.Arrays;
@@ -146,8 +150,15 @@ public void performTest()
BigInteger.ONE // Cofactor = 1
);
SAKKEKEMSGenerator generator = new SAKKEKEMSGenerator(new SecureRandom());
- generator.generateEncapsulated(null);
+ SecretWithEncapsulation rlt = generator.generateEncapsulated(null);
+
ECPoint K_bS = curve.createPoint(kbx, kby);
+
+
+ SAKKEKEMExtractor extractor = new SAKKEKEMExtractor(new SAKKEPrivateKeyParameters(new BigInteger(b), K_bS, new SAKKEPublicKeyParameters(null)));
+ byte[] test = extractor.extractSecret(rlt.getSecret());
+
+
System.out.println("K_bS x:" + new String(Hex.encode(K_bS.getXCoord().toBigInteger().toByteArray())));
System.out.println("K_bS y:" + new String(Hex.encode(K_bS.getYCoord().toBigInteger().toByteArray())));
ECPoint R_bs = curve.createPoint(Rbx, Rby);
From a9c71796ff4c2580da47250f9e288367c1bdac91 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Tue, 4 Feb 2025 18:32:08 +1030
Subject: [PATCH 169/890] TODO pairing
---
.../crypto/kems/SAKKEKEMExtractor.java | 300 +++++++++++--
.../crypto/kems/SAKKEKEMSGenerator.java | 396 +++++++++++-------
2 files changed, 490 insertions(+), 206 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java
index caff3dffa5..0e23ab22cb 100644
--- a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java
+++ b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java
@@ -14,7 +14,8 @@
import static org.bouncycastle.crypto.kems.SAKKEKEMSGenerator.pairing;
-public class SAKKEKEMExtractor implements EncapsulatedSecretExtractor
+public class SAKKEKEMExtractor
+ implements EncapsulatedSecretExtractor
{
private final ECCurve curve;
private final BigInteger p;
@@ -25,7 +26,8 @@ public class SAKKEKEMExtractor implements EncapsulatedSecretExtractor
private final int n; // Security parameter
private final SAKKEPrivateKeyParameters privateKey;
- public SAKKEKEMExtractor(SAKKEPrivateKeyParameters privateKey) {
+ public SAKKEKEMExtractor(SAKKEPrivateKeyParameters privateKey)
+ {
this.privateKey = privateKey;
SAKKEPublicKeyParameters publicKey = privateKey.getPublicParams();
this.curve = publicKey.getCurve();
@@ -38,14 +40,18 @@ public SAKKEKEMExtractor(SAKKEPrivateKeyParameters privateKey) {
}
@Override
- public byte[] extractSecret(byte[] encapsulation) {
- try {
+ public byte[] extractSecret(byte[] encapsulation)
+ {
+ try
+ {
// Step 1: Parse Encapsulated Data (R_bS, H)
- ECPoint R_bS = parseECPoint(encapsulation);
- BigInteger H = parseH(encapsulation);
+ ECPoint R_bS = curve.decodePoint(Arrays.copyOfRange(encapsulation, 0, 257));
+ BigInteger H = new BigInteger(Arrays.copyOfRange(encapsulation, 257, 274));
// Step 2: Compute w = using pairing
- BigInteger w = computePairing(R_bS, K_bS);
+// BigInteger w = computeTLPairing(new BigInteger[] {R_bS.getXCoord().toBigInteger(), R_bS.getYCoord().toBigInteger()},
+// new BigInteger[] {K_bS.getXCoord().toBigInteger(), K_bS.getYCoord().toBigInteger()}, this.p, this.q);
+ BigInteger w = computePairing(R_bS, K_bS, p, q);
// Step 3: Compute SSV = H XOR HashToIntegerRange(w, 2^n)
BigInteger ssv = computeSSV(H, w);
@@ -58,8 +64,10 @@ public byte[] extractSecret(byte[] encapsulation) {
// throw new IllegalStateException("Validation of R_bS failed");
// }
- return BigIntegers.asUnsignedByteArray(n/8, ssv);
- } catch (Exception e) {
+ return BigIntegers.asUnsignedByteArray(n / 8, ssv);
+ }
+ catch (Exception e)
+ {
throw new IllegalStateException("SAKKE extraction failed: " + e.getMessage());
}
}
@@ -70,59 +78,263 @@ public int getEncapsulationLength()
return 0;
}
- private ECPoint parseECPoint(byte[] encapsulation) {
- int coordLen = (p.bitLength() + 7) / 8;
- byte[] xBytes = Arrays.copyOfRange(encapsulation, 0, coordLen);
- byte[] yBytes = Arrays.copyOfRange(encapsulation, coordLen, 2*coordLen);
+ private BigInteger computePairing(ECPoint R, ECPoint K)
+ {
+ // Use your existing pairing implementation
+ return pairing(R, K, p, q);
+ }
+
+ private BigInteger computeSSV(BigInteger H, BigInteger w)
+ {
+ BigInteger twoToN = BigInteger.ONE.shiftLeft(n);
+ BigInteger mask = SAKKEUtils.hashToIntegerRange(w.toByteArray(), twoToN);
+ return H.xor(mask);
+ }
+
+ public static BigInteger computeTLPairing(
+ BigInteger[] R, // C = (Rx, Ry)
+ BigInteger[] Q, // Q = (Qx, Qy)
+ BigInteger p,
+ BigInteger q
+ )
+ {
+ BigInteger qMinus1 = q.subtract(BigInteger.ONE);
+ int N = qMinus1.bitLength() - 1;
+
+ // Initialize V = (1, 0)
+ BigInteger[] V = {BigInteger.ONE, BigInteger.ZERO};
+ // Initialize C = R
+ BigInteger[] C = {R[0], R[1]};
+
+ for (; N > 0; N--)
+ {
+ // V = V^2
+ pointSquare(V, p);
+
+ // Compute line function T
+ BigInteger[] T = computeLineFunctionT(C, Q, p);
+
+ // V = V * T
+ pointMultiply(V, T, p);
+
+ // C = 2*C (point doubling)
+ pointDouble(C, p);
- BigInteger x = new BigInteger(1, xBytes);
- BigInteger y = new BigInteger(1, yBytes);
+ if (qMinus1.testBit(N - 1))
+ {
+ // Compute addition line function
+ BigInteger[] TAdd = computeLineFunctionAdd(C, R, Q, p);
- return curve.createPoint(x, y).normalize();
+ // V = V * TAdd
+ pointMultiply(V, TAdd, p);
+
+ // C = C + R (point addition)
+ pointAdd(C, R, p);
+ }
+ }
+
+ // Final squaring
+ pointSquare(V, p);
+ pointSquare(V, p);
+
+ // Compute w = (Vy * Vx^{-1}) mod p
+ BigInteger VxInv = V[0].modInverse(p);
+ return V[1].multiply(VxInv).mod(p);
}
- private BigInteger parseH(byte[] encapsulation) {
- int coordLen = (p.bitLength() + 7) / 8;
- byte[] hBytes = Arrays.copyOfRange(encapsulation, 2*coordLen, encapsulation.length);
- return new BigInteger(1, hBytes);
+ private static void pointSquare(BigInteger[] point, BigInteger p)
+ {
+ BigInteger x = point[0];
+ BigInteger y = point[1];
+
+ // x = (x + y)(x - y) mod p
+ BigInteger xPlusY = x.add(y).mod(p);
+ BigInteger xMinusY = x.subtract(y).mod(p);
+ BigInteger newX = xPlusY.multiply(xMinusY).mod(p);
+
+ // y = 2xy mod p
+ BigInteger newY = x.multiply(y).multiply(BigInteger.valueOf(2)).mod(p);
+
+ point[0] = newX;
+ point[1] = newY;
}
- private BigInteger computePairing(ECPoint R, ECPoint K) {
- // Use your existing pairing implementation
- return pairing(R, K, p, q);
+ private static void pointMultiply(BigInteger[] a, BigInteger[] b, BigInteger p)
+ {
+ // Complex multiplication (a + bi)*(c + di) = (ac - bd) + (ad + bc)i
+ BigInteger real = a[0].multiply(b[0]).subtract(a[1].multiply(b[1])).mod(p);
+ BigInteger imag = a[0].multiply(b[1]).add(a[1].multiply(b[0])).mod(p);
+
+ a[0] = real;
+ a[1] = imag;
}
- private BigInteger computeSSV(BigInteger H, BigInteger w) {
- BigInteger twoToN = BigInteger.ONE.shiftLeft(n);
- BigInteger mask = SAKKEUtils.hashToIntegerRange(w.toByteArray(), twoToN);
- return H.xor(mask);
+ private static void pointDouble(BigInteger[] point, BigInteger p)
+ {
+ // Elliptic curve point doubling formulas
+ BigInteger x = point[0];
+ BigInteger y = point[1];
+
+ BigInteger slope = x.pow(2).multiply(BigInteger.valueOf(3))
+ .mod(p)
+ .multiply(y.multiply(BigInteger.valueOf(2)).modInverse(p))
+ .mod(p);
+
+ BigInteger newX = slope.pow(2).subtract(x.multiply(BigInteger.valueOf(2))).mod(p);
+ BigInteger newY = slope.multiply(x.subtract(newX)).subtract(y).mod(p);
+
+ point[0] = newX;
+ point[1] = newY;
}
- private BigInteger computeR(BigInteger ssv, byte[] userId) {
- byte[] ssvBytes = BigIntegers.asUnsignedByteArray(ssv);
- byte[] ssvConcatB = Arrays.concatenate(ssvBytes, userId);
- return SAKKEUtils.hashToIntegerRange(ssvConcatB, q);
+ private static void pointAdd(BigInteger[] a, BigInteger[] b, BigInteger p)
+ {
+ // Elliptic curve point addition
+ BigInteger x1 = a[0], y1 = a[1];
+ BigInteger x2 = b[0], y2 = b[1];
+
+ BigInteger slope = y2.subtract(y1)
+ .multiply(x2.subtract(x1).modInverse(p))
+ .mod(p);
+
+ BigInteger newX = slope.pow(2).subtract(x1).subtract(x2).mod(p);
+ BigInteger newY = slope.multiply(x1.subtract(newX)).subtract(y1).mod(p);
+
+ a[0] = newX;
+ a[1] = newY;
}
- private boolean validateR_bS(BigInteger r, byte[] b, ECPoint receivedR) {
- try {
- // Compute [b]P
- ECPoint bP = P.multiply(new BigInteger(1, b)).normalize();
+ private static BigInteger[] computeLineFunctionT(
+ BigInteger[] C,
+ BigInteger[] Q,
+ BigInteger p
+ )
+ {
+ // Line function evaluation for doubling
+ BigInteger Cx = C[0], Cy = C[1];
+ BigInteger Qx = Q[0], Qy = Q[1];
- // Compute [b]P + Z_S
- ECPoint bP_plus_Z = bP.add(Z_S).normalize();
+ // l = (3Cx² + a)/(2Cy) but a=0 for many curves
+ BigInteger numerator = Cx.pow(2).multiply(BigInteger.valueOf(3)).mod(p);
+ BigInteger denominator = Cy.multiply(BigInteger.valueOf(2)).mod(p);
+ BigInteger l = numerator.multiply(denominator.modInverse(p)).mod(p);
- // Compute [r]([b]P + Z_S)
- ECPoint computedR = bP_plus_Z.multiply(r).normalize();
+ // T = l*(Qx + Cx) - 2Qy
+ BigInteger tReal = l.multiply(Qx.add(Cx).mod(p)).mod(p);
+ BigInteger tImag = l.multiply(Qy).negate().mod(p);
- return pointsEqual(computedR, receivedR);
- } catch (Exception e) {
- return false;
- }
+ return new BigInteger[]{tReal, tImag};
}
- private boolean pointsEqual(ECPoint p1, ECPoint p2) {
+ private static BigInteger[] computeLineFunctionAdd(
+ BigInteger[] C,
+ BigInteger[] R,
+ BigInteger[] Q,
+ BigInteger p
+ )
+ {
+ // Line function evaluation for addition
+ BigInteger Cx = C[0], Cy = C[1];
+ BigInteger Rx = R[0], Ry = R[1];
+ BigInteger Qx = Q[0], Qy = Q[1];
+
+ // l = (Cy - Ry)/(Cx - Rx)
+ BigInteger numerator = Cy.subtract(Ry).mod(p);
+ BigInteger denominator = Cx.subtract(Rx).mod(p);
+ BigInteger l = numerator.multiply(denominator.modInverse(p)).mod(p);
+
+ // T = l*(Qx + Cx) - Qy
+ BigInteger tReal = l.multiply(Qx.add(Cx).mod(p)).mod(p);
+ BigInteger tImag = l.multiply(Qy).negate().mod(p);
+
+ return new BigInteger[]{tReal, tImag};
+ }
+
+ private boolean pointsEqual(ECPoint p1, ECPoint p2)
+ {
return p1.normalize().getXCoord().equals(p2.normalize().getXCoord())
&& p1.normalize().getYCoord().equals(p2.normalize().getYCoord());
}
+
+ public static BigInteger computePairing(ECPoint R, ECPoint Q, BigInteger p, BigInteger q)
+ {
+ BigInteger c = p.add(BigInteger.ONE).divide(q); // Compute c = (p+1)/q
+ BigInteger[] v = new BigInteger[]{BigInteger.ONE, BigInteger.ZERO}; // v = (1,0) in F_p^2
+ ECPoint C = R;
+
+ BigInteger qMinusOne = q.subtract(BigInteger.ONE);
+ int numBits = qMinusOne.bitLength();
+
+ // Miller loop
+ for (int i = numBits - 2; i >= 0; i--)
+ {
+ v = fp2SquareAndAccumulate(v, C, Q, p);
+ C = C.twice().normalize(); // C = [2]C
+
+ if (qMinusOne.testBit(i))
+ {
+ v = fp2MultiplyAndAccumulate(v, C, R, Q, p);
+ C = C.add(R).normalize();
+ }
+ }
+
+ // Final exponentiation: t = v^c
+ return fp2FinalExponentiation(v, p, c);
+ }
+
+ private static BigInteger[] fp2SquareAndAccumulate(BigInteger[] v, ECPoint C, ECPoint Q, BigInteger p)
+ {
+ BigInteger Cx = C.getAffineXCoord().toBigInteger();
+ BigInteger Cy = C.getAffineYCoord().toBigInteger();
+ BigInteger Qx = Q.getAffineXCoord().toBigInteger();
+ BigInteger Qy = Q.getAffineYCoord().toBigInteger();
+
+ // Compute l = (3 * (Cx^2 - 1)) / (2 * Cy) mod p
+ BigInteger l = Cx.multiply(Cx).mod(p).subtract(BigInteger.ONE).multiply(BigInteger.valueOf(3)).mod(p)
+ .multiply(Cy.multiply(BigInteger.valueOf(2)).modInverse(p))
+ .mod(p);
+
+ // Compute v = v^2 * ( l*( Q_x + C_x ) + ( i*Q_y - C_y ) )
+ v = fp2Multiply(v[0], v[1], v[0], v[1], p);
+ return fp2Multiply(v[0], v[1], l.multiply(Qx.add(Cx)), (Qy.subtract(Cy)), p);
+ }
+
+ private static BigInteger[] fp2MultiplyAndAccumulate(BigInteger[] v, ECPoint C, ECPoint R, ECPoint Q, BigInteger p)
+ {
+ BigInteger Cx = C.getAffineXCoord().toBigInteger();
+ BigInteger Cy = C.getAffineYCoord().toBigInteger();
+ BigInteger Rx = R.getAffineXCoord().toBigInteger();
+ BigInteger Ry = R.getAffineYCoord().toBigInteger();
+ BigInteger Qx = Q.getAffineXCoord().toBigInteger();
+ BigInteger Qy = Q.getAffineYCoord().toBigInteger();
+
+ // Compute l = (Cy - Ry) / (Cx - Rx) mod p
+ BigInteger l = Cy.subtract(Ry)
+ .multiply(Cx.subtract(Rx).modInverse(p))
+ .mod(p);
+
+ // Compute v = v * ( l*( Q_x + C_x ) + ( i*Q_y - C_y ) )
+ return fp2Multiply(v[0], v[1], l.multiply(Qx.add(Cx)), Qy.subtract(Cy), p);
+ }
+
+
+ private static BigInteger[] fp2Multiply(BigInteger x_real, BigInteger x_imag, BigInteger y_real, BigInteger y_imag, BigInteger p)
+ {
+ // Multiply v = (a + i*b) * scalar
+ return new BigInteger[]{
+ x_real.multiply(y_real).subtract(x_imag.multiply(y_imag)).mod(p),
+ x_real.multiply(y_imag).add(x_imag.multiply(y_real)).mod(p)
+ };
+ }
+
+ private static BigInteger fp2FinalExponentiation(BigInteger[] v, BigInteger p, BigInteger c)
+ {
+ // Compute representative in F_p: return b/a (mod p)
+// BigInteger v0 = v[0].modPow(c, p);
+// BigInteger v1 = v[1].modPow(c, p);
+// return v1.multiply(v0.modInverse(p)).mod(p);
+ v = fp2Multiply(v[0], v[1], v[0], v[1], p);
+ v = fp2Multiply(v[0], v[1], v[0], v[1], p);
+ return v[1].multiply(v[0].modInverse(p)).mod(p);
+ }
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
index df94f031ae..59895f5738 100644
--- a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
+++ b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
@@ -171,7 +171,7 @@ public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recip
BigInteger H = ssv.xor(mask);
// 5. Encode encapsulated data (R_bS, H)
- byte[] encapsulated = encodeData(R_bS, H);
+ byte[] encapsulated = Arrays.concatenate(R_bS.getEncoded(false), H.toByteArray());
return new SecretWithEncapsulationImpl(
encapsulated,
@@ -337,207 +337,279 @@ public BigInteger getB()
public static BigInteger pairing(ECPoint R, ECPoint Q, BigInteger p, BigInteger q)
{
ECCurve curve = R.getCurve();
- FP2Element v = new FP2Element(BigInteger.ONE, BigInteger.ZERO, p); // Initialize to 1+0i
+ //FP2Element v = new FP2Element(BigInteger.ONE, BigInteger.ZERO, p); // Initialize to 1+0i
- // Use correct exponent from RFC 6508: (p² - 1)/q
- BigInteger exponent = p.pow(2).subtract(BigInteger.ONE).divide(q);
+ // Use correct exponent from RFC 6508: (p+1)/q
+ BigInteger exponent = p.add(BigInteger.ONE).divide(q);
String qBits = q.subtract(BigInteger.ONE).toString(2);
ECPoint C = R.normalize();
-
- for (int j = 1; j < qBits.length(); j++)
+ BigInteger vx = BigInteger.ONE;
+ BigInteger vy = BigInteger.ZERO;
+
+ // Evaluate line at Q using F_p² arithmetic
+ BigInteger Qx = Q.getAffineXCoord().toBigInteger();
+ BigInteger Qy = Q.getAffineYCoord().toBigInteger();
+
+ ECPoint Rnorm = R.normalize();
+ BigInteger Rx = Rnorm.getAffineXCoord().toBigInteger();
+ BigInteger Ry = Rnorm.getAffineYCoord().toBigInteger();
+ int n = q.subtract(BigInteger.ONE).bitLength() - 1;
+ for (int j = n; j > 0; j--)
{
+ /*
+ * BigInteger xPlusY = currentX.add(currentY).mod(p);
+ BigInteger xMinusY = currentX.subtract(currentY).mod(p);
+ BigInteger newX = xPlusY.multiply(xMinusY).mod(p);
+
+ // Compute newY = 2xy mod p
+ BigInteger newY = currentX.multiply(currentY).multiply(BigInteger.valueOf(2)).mod(p);
+ * */
+ BigInteger xPlusY = vx.add(vy).mod(p);
+ BigInteger xMinusY = vx.subtract(vy).mod(p);
+ BigInteger newX = xPlusY.multiply(xMinusY).mod(p);
+
+ // Compute newY = 2xy mod p
+ BigInteger newY = vx.multiply(vy).multiply(BigInteger.valueOf(2)).mod(p);
+ vx = newX;
+ vy = newY;
+
C = C.normalize();
- ECFieldElement Cx = C.getAffineXCoord();
- ECFieldElement Cy = C.getAffineYCoord();
+ BigInteger Cx = C.getAffineXCoord().toBigInteger();
+ BigInteger Cy = C.getAffineYCoord().toBigInteger();
+
// Line function for doubling
- ECFieldElement lNum = Cx.square().multiply(curve.fromBigInteger(BigInteger.valueOf(3))).add(curve.getA());
- ECFieldElement lDen = Cy.multiply(curve.fromBigInteger(BigInteger.valueOf(2)));
- BigInteger l = lNum.divide(lDen).toBigInteger();
-
- // Evaluate line at Q using F_p² arithmetic
- ECFieldElement Qx = Q.getAffineXCoord();
- ECFieldElement Qy = Q.getAffineYCoord();
- FP2Element lineVal = new FP2Element(
- l.multiply(Qx.add(Cx).toBigInteger()),
- l.multiply(Qy.toBigInteger()),
- p
- );
-
- v = v.multiply(lineVal).pow(BigInteger.valueOf(2));
+ //3*(C_x^2 - 1)
+ BigInteger t_x1_bn = (Cx.multiply(Cx).mod(p).subtract(BigInteger.ONE)).multiply(BigInteger.valueOf(3));
+ //Qx + Cx
+ BigInteger t_bn = Qx.add(Cx);
+ //3*(C_x^2 - 1)(Qx+Cx)
+ t_x1_bn = t_x1_bn.multiply(t_bn).mod(p);
+ //Cy^2*2
+ t_bn = Cy.multiply(Cy).mod(p).multiply(BigInteger.valueOf(2));
+ //3*(C_x^2 - 1)(Qx+Cx) - Cy^2*2
+ t_x1_bn = t_x1_bn.subtract(t_bn).mod(p);
+ // Cy*2*Qy
+ BigInteger t_x2_bn = Cy.multiply(BigInteger.valueOf(2)).multiply(Qy).mod(p);
+
+ /*
+ * BigInteger real = currentX.multiply(pointX)
+ .subtract(currentY.multiply(pointY))
+ .mod(p);
+
+ // Compute imaginary part = x1*y2 + x2*y1 mod p
+ BigInteger imag = currentX.multiply(pointY)
+ .add(pointX.multiply(currentY))
+ .mod(p);*/
+ BigInteger real = vx.multiply(t_x1_bn)
+ .subtract(vy.multiply(t_x2_bn))
+ .mod(p);
+
+ // Compute imaginary part = x1*y2 + x2*y1 mod p
+ BigInteger imag = vx.multiply(t_x2_bn)
+ .add(t_x1_bn.multiply(vy))
+ .mod(p);
+
+ vx = real;
+ vy = imag;
+
C = C.twice().normalize();
if (qBits.charAt(j) == '1')
{
- ECPoint Rnorm = R.normalize();
- ECFieldElement Rx = Rnorm.getAffineXCoord();
- ECFieldElement Ry = Rnorm.getAffineYCoord();
-
- // Line function for addition
- ECFieldElement lAddNum = Cy.subtract(Ry);
- ECFieldElement lAddDen = Cx.subtract(Rx);
- BigInteger lAdd = lAddNum.divide(lAddDen).toBigInteger();
-
- FP2Element lineAddVal = new FP2Element(
- lAdd.multiply(Qx.add(Cx).toBigInteger()),
- lAdd.multiply(Qy.toBigInteger()),
- p
- );
-
- v = v.multiply(lineAddVal);
+ t_x1_bn = Qx.add(Rx).multiply(Cy).mod(p);
+ BigInteger tmp_t_bn = Qx.add(Cx).multiply(Ry);
+ t_x1_bn = t_x1_bn.subtract(tmp_t_bn).mod(p);
+ t_x2_bn = Cx.subtract(Rx).multiply(Qy).mod(p);
+ real = vx.multiply(t_x1_bn)
+ .subtract(vy.multiply(t_x2_bn))
+ .mod(p);
+
+ // Compute imaginary part = x1*y2 + x2*y1 mod p
+ imag = vx.multiply(t_x2_bn)
+ .add(t_x1_bn.multiply(vy))
+ .mod(p);
+
+ vx = real;
+ vy = imag;
C = C.add(Rnorm).normalize();
}
}
+ BigInteger xPlusY = vx.add(vy).mod(p);
+ BigInteger xMinusY = vx.subtract(vy).mod(p);
+ BigInteger newX = xPlusY.multiply(xMinusY).mod(p);
- // Final exponentiation
- FP2Element t = v.pow(exponent);
+ // Compute newY = 2xy mod p
+ BigInteger newY = vx.multiply(vy).multiply(BigInteger.valueOf(2)).mod(p);
+ vx = newX;
+ vy = newY;
- // Convert to F_p representative: b/a mod p
- BigInteger a = t.getA();
- BigInteger b = t.getB();
- return b.multiply(a.modInverse(p)).mod(p);
- }
+ xPlusY = vx.add(vy).mod(p);
+ xMinusY = vx.subtract(vy).mod(p);
+ newX = xPlusY.multiply(xMinusY).mod(p);
+
+ // Compute newY = 2xy mod p
+ newY = vx.multiply(vy).multiply(BigInteger.valueOf(2)).mod(p);
+
+ vx = newX;
+ vy = newY;
-// public static BigInteger pairing(ECPoint R, ECPoint Q, BigInteger p, BigInteger q)
-// {
+ BigInteger w = vx.modInverse(p).multiply(vy).mod(p);
+
+ return w;
+// // Final exponentiation
+// FP2Element t = v.pow(exponent);
+//
+// // Convert to F_p representative: b/a mod p
+// BigInteger a = t.getA();
+// BigInteger b = t.getB();
+// return b.multiply(a.modInverse(p)).mod(p);
+ }
+// public static BigInteger pairing(ECPoint R, ECPoint Q, BigInteger p, BigInteger q) {
// ECCurve curve = R.getCurve();
-// FP2Element i = new FP2Element(BigInteger.ZERO, BigInteger.ONE, p); // i = -1 in F_p^2
+// BigInteger qMinus1 = q.subtract(BigInteger.ONE);
+// int N = qMinus1.bitLength() - 1;
//
+// // Initialize V = (1, 0) in Fp²
+// BigInteger vx = BigInteger.ONE;
+// BigInteger vy = BigInteger.ZERO;
+//
+// // Initialize C = R
// ECPoint C = R.normalize();
-// BigInteger c = p.add(BigInteger.ONE).divide(q);
-// //ECFieldElement v = curve.fromBigInteger(BigInteger.ONE); // v = 1 in F_p
-// FP2Element v = new FP2Element(BigInteger.ONE, BigInteger.ZERO, p);
+// BigInteger Cx = C.getAffineXCoord().toBigInteger();
+// BigInteger Cy = C.getAffineYCoord().toBigInteger();
//
-// String qBits = q.subtract(BigInteger.ONE).toString(2); // Binary representation of q-1
+// // Precompute Q coordinates
+// ECPoint Qnorm = Q.normalize();
+// BigInteger Qx = Qnorm.getAffineXCoord().toBigInteger();
+// BigInteger Qy = Qnorm.getAffineYCoord().toBigInteger();
//
-// for (int j = 1; j < qBits.length(); j++)
-// { // Skip MSB
-// // l = (3 * (C_x^2 - 1)) / (2 * C_y)
-// C = C.normalize(); // Add this line to ensure normalization
-// ECFieldElement Cx = C.getAffineXCoord();
-// ECFieldElement Cy = C.getAffineXCoord();
-// BigInteger CxVal = Cx.toBigInteger();
-// BigInteger CyVal = Cy.toBigInteger();
-//// ECFieldElement l = Cx.square().multiply(curve.fromBigInteger(ECFieldElement.THREE)).subtract(curve.fromBigInteger(BigInteger.ONE))
-//// .divide(Cy.multiply(curve.fromBigInteger(BigIntegers.TWO)));
+// // Precompute R coordinates for addition steps
+// ECPoint Rnorm = R.normalize();
+// BigInteger Rx = Rnorm.getAffineXCoord().toBigInteger();
+// BigInteger Ry = Rnorm.getAffineYCoord().toBigInteger();
//
-// // l = 3*(Cx² - 1) / (2*Cy) in F_p
-// ECFieldElement lNum = Cx.square().subtract(curve.fromBigInteger(BigInteger.ONE)).multiply(curve.fromBigInteger(BigInteger.valueOf(3)));
-// ECFieldElement lDen = Cy.multiply(curve.fromBigInteger(BigInteger.valueOf(2)));
-// ECFieldElement l = lNum.divide(lDen);
-// BigInteger lVal = l.toBigInteger();
+// for (; N > 0; N--) {
+// // V = V² (complex squaring)
+// BigInteger[] squared = pointSquare(vx, vy, p);
+// vx = squared[0];
+// vy = squared[1];
//
-// // Evaluate line at [i]Q: (Qx, i*Qy)
-// ECFieldElement Qx = Q.getAffineXCoord();
-// ECFieldElement Qy = Q.getAffineYCoord();
-// BigInteger QxVal = Qx.toBigInteger();
-// BigInteger QyVal = Qy.toBigInteger();
+// // Calculate line function for doubling
+// BigInteger[] T = computeLineFunction(Cx, Cy, Qx, Qy, p);
//
-// // Convert l*(Qx + Cx) to F_p²
-// FP2Element term1 = new FP2Element(lVal.multiply(QxVal.add(CxVal)).mod(p), BigInteger.ZERO, p);
+// // V = V * T (complex multiplication)
+// BigInteger[] multiplied = pointMultiply(vx, vy, T[0], T[1], p);
+// vx = multiplied[0];
+// vy = multiplied[1];
//
-// // (i*Qy - Cy) in F_p²: (-Cy, Qy)
-// FP2Element term2 = new FP2Element(QyVal.negate().mod(p), QyVal, p); // Wait, original term is i*Qy - Cy: i*Qy is (0, Qy), subtract Cy (Cy,0) gives (-Cy, Qy)
-// FP2Element lineVal = new FP2Element(lVal, BigInteger.ZERO, p) // l is in F_p
-// .multiply(new FP2Element(QxVal.add(CxVal).mod(p), BigInteger.ZERO, p)) // (Qx + Cx) in F_p
-// .add(term2); // i*Qy - Cy
+// // Double point C
+// BigInteger[] doubled = pointDouble(Cx, Cy, p);
+// Cx = doubled[0];
+// Cy = doubled[1];
//
-// v = v.square().multiply(lineVal);
+// if (qMinus1.testBit(N-1)) {
+// // Calculate line function for addition
+// BigInteger[] TAdd = computeLineFunctionAdd(Cx, Cy, Rx, Ry, Qx, Qy, p);
//
-// C = C.twice().normalize();;
+// // V = V * TAdd
+// multiplied = pointMultiply(vx, vy, TAdd[0], TAdd[1], p);
+// vx = multiplied[0];
+// vy = multiplied[1];
//
-// // v = v^2 * (l * (Q_x + C_x) + (i * Q_y - C_y))
-//// ECFieldElement Qx = Q.getAffineXCoord();
-//// ECFieldElement Qy = Q.getAffineYCoord();
-//// v = v.square().multiply(l.multiply(Qx.add(Cx)).add(i.multiply(Qy).subtract(Cy)));
+// // Add points C = C + R
+// BigInteger[] added = pointAdd(Cx, Cy, Rx, Ry, p);
+// Cx = added[0];
+// Cy = added[1];
+// }
+// }
//
-// // Double the point
-//// C = C.twice();
-// if (qBits.charAt(j) == '1')
-// {
-// // Compute line function for addition
-// ECFieldElement Rx = R.getAffineXCoord();
-// ECFieldElement Ry = R.getAffineYCoord();
-// BigInteger RxVal = Rx.toBigInteger();
-// BigInteger RyVal = Ry.toBigInteger();
+// // Final squaring V = V²
+// BigInteger[] squared = pointSquare(vx, vy, p);
+// vx = squared[0];
+// vy = squared[1];
+// squared = pointSquare(vx, vy, p);
+// vx = squared[0];
+// vy = squared[1];
//
-// ECFieldElement lAddNum = Cy.subtract(Ry);
-// ECFieldElement lAddDen = Cx.subtract(Rx);
-// ECFieldElement lAdd = lAddNum.divide(lAddDen);
-// BigInteger lAddVal = lAdd.toBigInteger();
+// // Compute w = (Vy * Vx⁻¹) mod p
+// BigInteger vxInv = vx.modInverse(p);
+// return vy.multiply(vxInv).mod(p);
+// }
//
-// // Evaluate line at [i]Q
-// FP2Element lineAddTerm1 = new FP2Element(lAddVal.multiply(QxVal.add(CxVal)).mod(p), BigInteger.ZERO, p);
-// FP2Element lineAddTerm2 = new FP2Element(QyVal.negate().mod(p), QyVal, p); // i*Qy - Cy (Cy is current C's y)
-// FP2Element lineAddVal = lineAddTerm1.add(lineAddTerm2);
+// // Helper methods implementing exact C code operations
+// private static BigInteger[] pointSquare(BigInteger x, BigInteger y, BigInteger p) {
+// BigInteger xPlusY = x.add(y).mod(p);
+// BigInteger xMinusY = x.subtract(y).mod(p);
+// return new BigInteger[] {
+// xPlusY.multiply(xMinusY).mod(p),
+// x.multiply(y).multiply(BigInteger.valueOf(2)).mod(p)
+// };
+// }
//
-// v = v.multiply(lineAddVal);
+// private static BigInteger[] pointMultiply(BigInteger a, BigInteger b, BigInteger c, BigInteger d, BigInteger p) {
+// return new BigInteger[] {
+// a.multiply(d).add(b.multiply(c)).mod(p),
+// a.multiply(c).subtract(b.multiply(d)).mod(p),
//
-// C = C.add(R);
-// }
+// };
+// }
//
-//// // If the bit is 1, perform additional step
-//// if (qBits.charAt(j) == '1')
-//// {
-//// // l = (C_y - R_y) / (C_x - R_x)
-//// ECFieldElement Rx = R.getAffineXCoord();
-//// ECFieldElement Ry = R.getAffineYCoord();
-//// l = Cy.subtract(Ry).divide(Cx.subtract(Rx));
-////
-//// // v = v * (l * (Q_x + C_x) + (i * Q_y - C_y))
-//// v = v.multiply(l.multiply(Qx.add(Cx)).add(i.multiply(Qy).subtract(Cy)));
-////
-//// // C = C + R
-//// C = C.add(R);
-//// }
-// }
+// private static BigInteger[] pointDouble(BigInteger x, BigInteger y, BigInteger p) {
+// BigInteger slope = x.pow(2).multiply(BigInteger.valueOf(3))
+// .mod(p)
+// .multiply(y.multiply(BigInteger.valueOf(2)).modInverse(p))
+// .mod(p);
+// return new BigInteger[] {
+// slope.pow(2).subtract(x.multiply(BigInteger.valueOf(2))).mod(p),
+// slope.multiply(x.subtract(slope.pow(2).mod(p)))
+// .subtract(y).mod(p)
+// };
+// }
//
-//// // Compute v^c
-//// v = curve.fromBigInteger(v.toBigInteger().modPow(c, p));
-////
-//// // Convert to F_p representative
-//// return computeFpRepresentative(v, curve);
-// FP2Element t = v.pow(c);
+// private static BigInteger[] pointAdd(BigInteger x1, BigInteger y1, BigInteger x2, BigInteger y2, BigInteger p) {
+// BigInteger slope = y2.subtract(y1)
+// .multiply(x2.subtract(x1).modInverse(p))
+// .mod(p);
+// return new BigInteger[] {
+// slope.pow(2).subtract(x1).subtract(x2).mod(p),
+// slope.multiply(x1.subtract(slope.pow(2).subtract(x1).subtract(x2).mod(p)))
+// .subtract(y1).mod(p)
+// };
+// }
//
-// // Compute representative: b/a mod p
-// BigInteger a = t.getA();
-// BigInteger bVal = t.getB();
-// if (a.equals(BigInteger.ZERO)) {
-// throw new ArithmeticException("Division by zero in F_p representative");
-// }
-// BigInteger aInv = a.modInverse(p);
-// BigInteger representative = bVal.multiply(aInv).mod(p);
+// private static BigInteger[] computeLineFunction(BigInteger Cx, BigInteger Cy,
+// BigInteger Qx, BigInteger Qy,
+// BigInteger p) {
+// // Calculate 3*(Cx² - 1)
+// BigInteger t_x1 = Cx.pow(2).subtract(BigInteger.ONE).multiply(BigInteger.valueOf(3)).mod(p);
+// // Calculate Qx + Cx
+// BigInteger t = Qx.add(Cx).mod(p);
+// // Multiply components
+// t_x1 = t_x1.multiply(t).mod(p);
+// // Subtract 2*Cy²
+// t_x1 = t_x1.subtract(Cy.pow(2).multiply(BigInteger.valueOf(2))).mod(p);
+// // Calculate 2*Cy*Qy
+// BigInteger t_x2 = Cy.multiply(BigInteger.valueOf(2)).multiply(Qy).mod(p);
+// return new BigInteger[] {t_x1, t_x2};
+// }
+//
+// private static BigInteger[] computeLineFunctionAdd(BigInteger Cx, BigInteger Cy,
+// BigInteger Rx, BigInteger Ry,
+// BigInteger Qx, BigInteger Qy,
+// BigInteger p) {
+// // Calculate (Cy - Ry)
+// BigInteger numerator = Cy.subtract(Ry).mod(p);
+// // Calculate (Cx - Rx)⁻¹
+// BigInteger denominator = Cx.subtract(Rx).modInverse(p);
+// BigInteger slope = numerator.multiply(denominator).mod(p);
//
-// return representative;
+// // Calculate line function components
+// BigInteger t_x1 = slope.multiply(Qx.add(Cx).mod(p)).mod(p);
+// BigInteger t_x2 = slope.multiply(Qy).negate().mod(p);
+// return new BigInteger[] {t_x1, t_x2};
// }
- private static BigInteger computeFpRepresentative(ECFieldElement t, ECCurve curve)
- {
- // Characteristic of F_p
- BigInteger p = ((ECCurve.Fp)curve).getQ();
-
- // Assume t = a + i * b in F_p² → extract a, b
- ECFieldElement a = t; // In F_p², a is the real part
- ECFieldElement b = t.multiply(curve.fromBigInteger(BigInteger.ONE.negate().add(p))); // Imaginary part
- // Compute b/a mod p
- return b.toBigInteger().multiply(a.toBigInteger().modInverse(p)).mod(p);
- }
-
- public static byte[] encodeData(ECPoint R_bS, BigInteger H)
- {
- // 1. Serialize EC Point (use compressed format for efficiency)
- byte[] R_bS_bytes = R_bS.getEncoded(true);
-
- // 2. Serialize H (convert to a fixed-length byte array)
- byte[] H_bytes = H.toByteArray();
-
- // 3. Combine both into a single byte array
- ByteBuffer buffer = ByteBuffer.allocate(R_bS_bytes.length + H_bytes.length);
- buffer.put(R_bS_bytes);
- buffer.put(H_bytes);
-
- return buffer.array();
- }
}
From cc77eaf2b97e786569223c337712f60e5fd31f30 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Wed, 5 Feb 2025 14:23:30 +1030
Subject: [PATCH 170/890] Pass the test vector of SAKKE
---
.../crypto/kems/SAKKEKEMExtractor.java | 216 +++---------------
.../crypto/kems/SAKKEKEMSGenerator.java | 16 +-
.../crypto/kems/test/SAKKEKEMSTest.java | 3 +-
3 files changed, 42 insertions(+), 193 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java
index 0e23ab22cb..551f83cd01 100644
--- a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java
+++ b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java
@@ -1,6 +1,7 @@
package org.bouncycastle.crypto.kems;
import java.math.BigInteger;
+import java.security.SecureRandom;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.EncapsulatedSecretExtractor;
@@ -8,9 +9,11 @@
import org.bouncycastle.crypto.params.SAKKEPrivateKeyParameters;
import org.bouncycastle.crypto.params.SAKKEPublicKeyParameters;
import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECFieldElement;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
+import org.bouncycastle.util.encoders.Hex;
import static org.bouncycastle.crypto.kems.SAKKEKEMSGenerator.pairing;
@@ -48,18 +51,28 @@ public byte[] extractSecret(byte[] encapsulation)
ECPoint R_bS = curve.decodePoint(Arrays.copyOfRange(encapsulation, 0, 257));
BigInteger H = new BigInteger(Arrays.copyOfRange(encapsulation, 257, 274));
+ //ECCurveWithTatePairing pairing = new ECCurveWithTatePairing(q, BigInteger.ONE, BigInteger.ZERO, p);
+ //BigInteger w = pairing.TatePairing(R_bS, K_bS).toBigInteger();
// Step 2: Compute w = using pairing
// BigInteger w = computeTLPairing(new BigInteger[] {R_bS.getXCoord().toBigInteger(), R_bS.getYCoord().toBigInteger()},
// new BigInteger[] {K_bS.getXCoord().toBigInteger(), K_bS.getYCoord().toBigInteger()}, this.p, this.q);
BigInteger w = computePairing(R_bS, K_bS, p, q);
-
+ System.out.println(new String(Hex.encode(w.toByteArray())));
+ //BigInteger w = tatePairing(R_bS.getXCoord().toBigInteger(), R_bS.getYCoord().toBigInteger(), K_bS.getXCoord().toBigInteger(), K_bS.getYCoord().toBigInteger(), q, p);
// Step 3: Compute SSV = H XOR HashToIntegerRange(w, 2^n)
BigInteger ssv = computeSSV(H, w);
// Step 4: Compute r = HashToIntegerRange(SSV || b)
-// BigInteger r = computeR(ssv, privateKey.getPrivatePoint());
+ BigInteger b = privateKey.getB();
+ BigInteger r = SAKKEUtils.hashToIntegerRange(Arrays.concatenate(ssv.toByteArray(), b.toByteArray()), q);
//
// // Step 5: Validate R_bS
+ ECPoint bP = P.multiply(b).normalize();
+ ECPoint Test = bP.add(Z_S).multiply(r).normalize();
+ if(!R_bS.equals(Test))
+ {
+ throw new IllegalStateException("Validation of R_bS failed");
+ }
// if (!validateR_bS(r, privateKey.getPrivatePoint(), R_bS)) {
// throw new IllegalStateException("Validation of R_bS failed");
// }
@@ -78,11 +91,6 @@ public int getEncapsulationLength()
return 0;
}
- private BigInteger computePairing(ECPoint R, ECPoint K)
- {
- // Use your existing pairing implementation
- return pairing(R, K, p, q);
- }
private BigInteger computeSSV(BigInteger H, BigInteger w)
{
@@ -91,175 +99,11 @@ private BigInteger computeSSV(BigInteger H, BigInteger w)
return H.xor(mask);
}
- public static BigInteger computeTLPairing(
- BigInteger[] R, // C = (Rx, Ry)
- BigInteger[] Q, // Q = (Qx, Qy)
- BigInteger p,
- BigInteger q
- )
- {
- BigInteger qMinus1 = q.subtract(BigInteger.ONE);
- int N = qMinus1.bitLength() - 1;
-
- // Initialize V = (1, 0)
- BigInteger[] V = {BigInteger.ONE, BigInteger.ZERO};
- // Initialize C = R
- BigInteger[] C = {R[0], R[1]};
-
- for (; N > 0; N--)
- {
- // V = V^2
- pointSquare(V, p);
-
- // Compute line function T
- BigInteger[] T = computeLineFunctionT(C, Q, p);
-
- // V = V * T
- pointMultiply(V, T, p);
-
- // C = 2*C (point doubling)
- pointDouble(C, p);
-
- if (qMinus1.testBit(N - 1))
- {
- // Compute addition line function
- BigInteger[] TAdd = computeLineFunctionAdd(C, R, Q, p);
-
- // V = V * TAdd
- pointMultiply(V, TAdd, p);
-
- // C = C + R (point addition)
- pointAdd(C, R, p);
- }
- }
-
- // Final squaring
- pointSquare(V, p);
- pointSquare(V, p);
-
- // Compute w = (Vy * Vx^{-1}) mod p
- BigInteger VxInv = V[0].modInverse(p);
- return V[1].multiply(VxInv).mod(p);
- }
-
- private static void pointSquare(BigInteger[] point, BigInteger p)
- {
- BigInteger x = point[0];
- BigInteger y = point[1];
-
- // x = (x + y)(x - y) mod p
- BigInteger xPlusY = x.add(y).mod(p);
- BigInteger xMinusY = x.subtract(y).mod(p);
- BigInteger newX = xPlusY.multiply(xMinusY).mod(p);
-
- // y = 2xy mod p
- BigInteger newY = x.multiply(y).multiply(BigInteger.valueOf(2)).mod(p);
-
- point[0] = newX;
- point[1] = newY;
- }
-
- private static void pointMultiply(BigInteger[] a, BigInteger[] b, BigInteger p)
- {
- // Complex multiplication (a + bi)*(c + di) = (ac - bd) + (ad + bc)i
- BigInteger real = a[0].multiply(b[0]).subtract(a[1].multiply(b[1])).mod(p);
- BigInteger imag = a[0].multiply(b[1]).add(a[1].multiply(b[0])).mod(p);
-
- a[0] = real;
- a[1] = imag;
- }
-
- private static void pointDouble(BigInteger[] point, BigInteger p)
- {
- // Elliptic curve point doubling formulas
- BigInteger x = point[0];
- BigInteger y = point[1];
-
- BigInteger slope = x.pow(2).multiply(BigInteger.valueOf(3))
- .mod(p)
- .multiply(y.multiply(BigInteger.valueOf(2)).modInverse(p))
- .mod(p);
-
- BigInteger newX = slope.pow(2).subtract(x.multiply(BigInteger.valueOf(2))).mod(p);
- BigInteger newY = slope.multiply(x.subtract(newX)).subtract(y).mod(p);
-
- point[0] = newX;
- point[1] = newY;
- }
-
- private static void pointAdd(BigInteger[] a, BigInteger[] b, BigInteger p)
- {
- // Elliptic curve point addition
- BigInteger x1 = a[0], y1 = a[1];
- BigInteger x2 = b[0], y2 = b[1];
-
- BigInteger slope = y2.subtract(y1)
- .multiply(x2.subtract(x1).modInverse(p))
- .mod(p);
-
- BigInteger newX = slope.pow(2).subtract(x1).subtract(x2).mod(p);
- BigInteger newY = slope.multiply(x1.subtract(newX)).subtract(y1).mod(p);
-
- a[0] = newX;
- a[1] = newY;
- }
-
- private static BigInteger[] computeLineFunctionT(
- BigInteger[] C,
- BigInteger[] Q,
- BigInteger p
- )
- {
- // Line function evaluation for doubling
- BigInteger Cx = C[0], Cy = C[1];
- BigInteger Qx = Q[0], Qy = Q[1];
-
- // l = (3Cx² + a)/(2Cy) but a=0 for many curves
- BigInteger numerator = Cx.pow(2).multiply(BigInteger.valueOf(3)).mod(p);
- BigInteger denominator = Cy.multiply(BigInteger.valueOf(2)).mod(p);
- BigInteger l = numerator.multiply(denominator.modInverse(p)).mod(p);
-
- // T = l*(Qx + Cx) - 2Qy
- BigInteger tReal = l.multiply(Qx.add(Cx).mod(p)).mod(p);
- BigInteger tImag = l.multiply(Qy).negate().mod(p);
-
- return new BigInteger[]{tReal, tImag};
- }
-
- private static BigInteger[] computeLineFunctionAdd(
- BigInteger[] C,
- BigInteger[] R,
- BigInteger[] Q,
- BigInteger p
- )
- {
- // Line function evaluation for addition
- BigInteger Cx = C[0], Cy = C[1];
- BigInteger Rx = R[0], Ry = R[1];
- BigInteger Qx = Q[0], Qy = Q[1];
-
- // l = (Cy - Ry)/(Cx - Rx)
- BigInteger numerator = Cy.subtract(Ry).mod(p);
- BigInteger denominator = Cx.subtract(Rx).mod(p);
- BigInteger l = numerator.multiply(denominator.modInverse(p)).mod(p);
-
- // T = l*(Qx + Cx) - Qy
- BigInteger tReal = l.multiply(Qx.add(Cx).mod(p)).mod(p);
- BigInteger tImag = l.multiply(Qy).negate().mod(p);
-
- return new BigInteger[]{tReal, tImag};
- }
-
- private boolean pointsEqual(ECPoint p1, ECPoint p2)
- {
- return p1.normalize().getXCoord().equals(p2.normalize().getXCoord())
- && p1.normalize().getYCoord().equals(p2.normalize().getYCoord());
- }
-
public static BigInteger computePairing(ECPoint R, ECPoint Q, BigInteger p, BigInteger q)
{
BigInteger c = p.add(BigInteger.ONE).divide(q); // Compute c = (p+1)/q
BigInteger[] v = new BigInteger[]{BigInteger.ONE, BigInteger.ZERO}; // v = (1,0) in F_p^2
+ //BigInteger v = BigInteger.ONE;
ECPoint C = R;
BigInteger qMinusOne = q.subtract(BigInteger.ONE);
@@ -269,6 +113,7 @@ public static BigInteger computePairing(ECPoint R, ECPoint Q, BigInteger p, BigI
for (int i = numBits - 2; i >= 0; i--)
{
v = fp2SquareAndAccumulate(v, C, Q, p);
+
C = C.twice().normalize(); // C = [2]C
if (qMinusOne.testBit(i))
@@ -290,13 +135,24 @@ private static BigInteger[] fp2SquareAndAccumulate(BigInteger[] v, ECPoint C, EC
BigInteger Qy = Q.getAffineYCoord().toBigInteger();
// Compute l = (3 * (Cx^2 - 1)) / (2 * Cy) mod p
- BigInteger l = Cx.multiply(Cx).mod(p).subtract(BigInteger.ONE).multiply(BigInteger.valueOf(3)).mod(p)
- .multiply(Cy.multiply(BigInteger.valueOf(2)).modInverse(p))
- .mod(p);
+ BigInteger l = BigInteger.valueOf(3).multiply(Cx.multiply(Cx).subtract(BigInteger.ONE))
+ .multiply(Cy.multiply(BigInteger.valueOf(2)).modInverse(p)).mod(p);
// Compute v = v^2 * ( l*( Q_x + C_x ) + ( i*Q_y - C_y ) )
v = fp2Multiply(v[0], v[1], v[0], v[1], p);
- return fp2Multiply(v[0], v[1], l.multiply(Qx.add(Cx)), (Qy.subtract(Cy)), p);
+// v[0] = v[0].multiply(v[0]);
+// v[1] = v[1].multiply(v[1]);
+ return accumulateLine(v[0], v[1], Cx, Cy, Qx, Qy, l, p);
+// BigInteger t_x1_bn = Cx.multiply(Cx).subtract(BigInteger.ONE).multiply(BigInteger.valueOf(3)).multiply(Qx.add(Cx)).mod(p)
+// .subtract(Cy.multiply(Cy).multiply(BigInteger.valueOf(2))).mod(p);
+// BigInteger t_x2_bn = Cy.multiply(Qy).multiply(BigInteger.valueOf(2)).mod(p);
+// v = fp2Multiply(v[0], v[1], v[0], v[1], p);
+// return fp2Multiply(v[0], v[1], t_x1_bn, t_x2_bn, p);
+ }
+
+ private static BigInteger[] accumulateLine(BigInteger v0, BigInteger v1, BigInteger Cx, BigInteger Cy, BigInteger Qx, BigInteger Qy, BigInteger l, BigInteger p)
+ {
+ return fp2Multiply(v0, v1, l.multiply(Qx.add(Cx)).subtract(Cy), Qy, p);
}
private static BigInteger[] fp2MultiplyAndAccumulate(BigInteger[] v, ECPoint C, ECPoint R, ECPoint Q, BigInteger p)
@@ -314,11 +170,15 @@ private static BigInteger[] fp2MultiplyAndAccumulate(BigInteger[] v, ECPoint C,
.mod(p);
// Compute v = v * ( l*( Q_x + C_x ) + ( i*Q_y - C_y ) )
- return fp2Multiply(v[0], v[1], l.multiply(Qx.add(Cx)), Qy.subtract(Cy), p);
+ return accumulateLine(v[0], v[1], Cx, Cy, Qx, Qy, l, p);
+// BigInteger t_x1_bn = Qx.add(Rx).multiply(Cy).subtract(Qx.add(Cx).multiply(Ry)).mod(p);
+// BigInteger t_x2_bn = Cx.subtract(Rx).multiply(Qy).mod(p);
+// return fp2Multiply(v[0], v[1], t_x1_bn, t_x2_bn, p);
+
}
- private static BigInteger[] fp2Multiply(BigInteger x_real, BigInteger x_imag, BigInteger y_real, BigInteger y_imag, BigInteger p)
+ static BigInteger[] fp2Multiply(BigInteger x_real, BigInteger x_imag, BigInteger y_real, BigInteger y_imag, BigInteger p)
{
// Multiply v = (a + i*b) * scalar
return new BigInteger[]{
diff --git a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
index 59895f5738..1d5128e7d3 100644
--- a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
+++ b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
@@ -156,20 +156,12 @@ public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recip
BigInteger g_r = result[0].mod(p);
g_r = g_r.modInverse(p);
g_r = g_r.multiply(result[1]).mod(p);
- System.out.println("g_r " + new String(Hex.encode(g_r.toByteArray())));
- byte[] expected_g_r = Hex.decode("7D2A8438 E6291C64 9B6579EB 3B79EAE9\n" +
- " 48B1DE9E 5F7D1F40 70A08F8D B6B3C515\n" +
- " 6F2201AF FBB5CB9D 82AA3EC0 D0398B89\n" +
- " ABC78A13 A760C0BF 3F77E63D 0DF3F1A3\n" +
- " 41A41B88 11DF197F D6CD0F00 3125606F\n" +
- " 4F109F40 0F7292A1 0D255E3C 0EBCCB42\n" +
- " 53FB182C 68F09CF6 CD9C4A53 DA6C74AD\n" +
- " 007AF36B 8BCA979D 5895E282 F483FCD6");
+
BigInteger mask = SAKKEUtils.hashToIntegerRange(g_r.toByteArray(), BigInteger.ONE.shiftLeft(n)); // 2^n
System.out.println(new String(Hex.encode(mask.toByteArray())));
BigInteger H = ssv.xor(mask);
-
+ System.out.println(new String(Hex.encode(H.toByteArray())));
// 5. Encode encapsulated data (R_bS, H)
byte[] encapsulated = Arrays.concatenate(R_bS.getEncoded(false), H.toByteArray());
@@ -201,10 +193,6 @@ public static boolean sakkePointExponent(
BigInteger n
)
{
- if (n.equals(BigInteger.ZERO))
- {
- return false;
- }
// Initialize result with the original point
BigInteger currentX = pointX;
diff --git a/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java b/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
index 485965ad59..d40a78abfb 100644
--- a/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
@@ -155,7 +155,8 @@ public void performTest()
ECPoint K_bS = curve.createPoint(kbx, kby);
- SAKKEKEMExtractor extractor = new SAKKEKEMExtractor(new SAKKEPrivateKeyParameters(new BigInteger(b), K_bS, new SAKKEPublicKeyParameters(null)));
+ SAKKEKEMExtractor extractor = new SAKKEKEMExtractor(new SAKKEPrivateKeyParameters(new BigInteger(b), K_bS,
+ new SAKKEPublicKeyParameters(curve.createPoint(Zx, Zy))));
byte[] test = extractor.extractSecret(rlt.getSecret());
From 50c84da8e52143b318d67e5ba26d23bd5f31eb22 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Wed, 5 Feb 2025 16:25:43 +1030
Subject: [PATCH 171/890] TODO: SAKKEKEMSGenerator and parameter settings
---
.../crypto/kems/SAKKEKEMExtractor.java | 133 ++---
.../crypto/kems/SAKKEKEMSGenerator.java | 478 +-----------------
.../crypto/kems/test/SAKKEKEMSTest.java | 32 +-
3 files changed, 75 insertions(+), 568 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java
index 551f83cd01..8551f74680 100644
--- a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java
+++ b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java
@@ -1,11 +1,8 @@
package org.bouncycastle.crypto.kems;
import java.math.BigInteger;
-import java.security.SecureRandom;
-import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.EncapsulatedSecretExtractor;
-import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.params.SAKKEPrivateKeyParameters;
import org.bouncycastle.crypto.params.SAKKEPublicKeyParameters;
import org.bouncycastle.math.ec.ECCurve;
@@ -15,7 +12,6 @@
import org.bouncycastle.util.BigIntegers;
import org.bouncycastle.util.encoders.Hex;
-import static org.bouncycastle.crypto.kems.SAKKEKEMSGenerator.pairing;
public class SAKKEKEMExtractor
implements EncapsulatedSecretExtractor
@@ -51,31 +47,26 @@ public byte[] extractSecret(byte[] encapsulation)
ECPoint R_bS = curve.decodePoint(Arrays.copyOfRange(encapsulation, 0, 257));
BigInteger H = new BigInteger(Arrays.copyOfRange(encapsulation, 257, 274));
- //ECCurveWithTatePairing pairing = new ECCurveWithTatePairing(q, BigInteger.ONE, BigInteger.ZERO, p);
- //BigInteger w = pairing.TatePairing(R_bS, K_bS).toBigInteger();
// Step 2: Compute w = using pairing
-// BigInteger w = computeTLPairing(new BigInteger[] {R_bS.getXCoord().toBigInteger(), R_bS.getYCoord().toBigInteger()},
-// new BigInteger[] {K_bS.getXCoord().toBigInteger(), K_bS.getYCoord().toBigInteger()}, this.p, this.q);
BigInteger w = computePairing(R_bS, K_bS, p, q);
System.out.println(new String(Hex.encode(w.toByteArray())));
//BigInteger w = tatePairing(R_bS.getXCoord().toBigInteger(), R_bS.getYCoord().toBigInteger(), K_bS.getXCoord().toBigInteger(), K_bS.getYCoord().toBigInteger(), q, p);
// Step 3: Compute SSV = H XOR HashToIntegerRange(w, 2^n)
- BigInteger ssv = computeSSV(H, w);
+ BigInteger twoToN = BigInteger.ONE.shiftLeft(n);
+ BigInteger mask = SAKKEUtils.hashToIntegerRange(w.toByteArray(), twoToN);
+ BigInteger ssv = H.xor(mask);
// Step 4: Compute r = HashToIntegerRange(SSV || b)
BigInteger b = privateKey.getB();
BigInteger r = SAKKEUtils.hashToIntegerRange(Arrays.concatenate(ssv.toByteArray(), b.toByteArray()), q);
-//
-// // Step 5: Validate R_bS
+
+ // Step 5: Validate R_bS
ECPoint bP = P.multiply(b).normalize();
ECPoint Test = bP.add(Z_S).multiply(r).normalize();
- if(!R_bS.equals(Test))
+ if (!R_bS.equals(Test))
{
throw new IllegalStateException("Validation of R_bS failed");
}
-// if (!validateR_bS(r, privateKey.getPrivatePoint(), R_bS)) {
-// throw new IllegalStateException("Validation of R_bS failed");
-// }
return BigIntegers.asUnsignedByteArray(n / 8, ssv);
}
@@ -92,109 +83,75 @@ public int getEncapsulationLength()
}
- private BigInteger computeSSV(BigInteger H, BigInteger w)
- {
- BigInteger twoToN = BigInteger.ONE.shiftLeft(n);
- BigInteger mask = SAKKEUtils.hashToIntegerRange(w.toByteArray(), twoToN);
- return H.xor(mask);
- }
-
public static BigInteger computePairing(ECPoint R, ECPoint Q, BigInteger p, BigInteger q)
{
- BigInteger c = p.add(BigInteger.ONE).divide(q); // Compute c = (p+1)/q
- BigInteger[] v = new BigInteger[]{BigInteger.ONE, BigInteger.ZERO}; // v = (1,0) in F_p^2
- //BigInteger v = BigInteger.ONE;
+ // v = (1,0) in F_p^2
+ BigInteger[] v = new BigInteger[]{BigInteger.ONE, BigInteger.ZERO};
ECPoint C = R;
BigInteger qMinusOne = q.subtract(BigInteger.ONE);
int numBits = qMinusOne.bitLength();
+ BigInteger Qx = Q.getAffineXCoord().toBigInteger();
+ BigInteger Qy = Q.getAffineYCoord().toBigInteger();
+ BigInteger Rx = R.getAffineXCoord().toBigInteger();
+ BigInteger Ry = R.getAffineYCoord().toBigInteger();
+ BigInteger l, Cx, Cy;
+ final BigInteger three = BigInteger.valueOf(3);
+ final BigInteger two = BigInteger.valueOf(2);
// Miller loop
for (int i = numBits - 2; i >= 0; i--)
{
- v = fp2SquareAndAccumulate(v, C, Q, p);
+ Cx = C.getAffineXCoord().toBigInteger();
+ Cy = C.getAffineYCoord().toBigInteger();
+
+ // Compute l = (3 * (Cx^2 - 1)) / (2 * Cy) mod p
+ l = three.multiply(Cx.multiply(Cx).subtract(BigInteger.ONE))
+ .multiply(Cy.multiply(two).modInverse(p)).mod(p);
+
+ // Compute v = v^2 * ( l*( Q_x + C_x ) + ( i*Q_y - C_y ) )
+ v = fp2PointSquare(v[0], v[1], p);
+ v = fp2Multiply(v[0], v[1], l.multiply(Qx.add(Cx)).subtract(Cy), Qy, p);
C = C.twice().normalize(); // C = [2]C
if (qMinusOne.testBit(i))
{
- v = fp2MultiplyAndAccumulate(v, C, R, Q, p);
+ Cx = C.getAffineXCoord().toBigInteger();
+ Cy = C.getAffineYCoord().toBigInteger();
+
+ // Compute l = (Cy - Ry) / (Cx - Rx) mod p
+ l = Cy.subtract(Ry).multiply(Cx.subtract(Rx).modInverse(p)).mod(p);
+
+ // Compute v = v * ( l*( Q_x + C_x ) + ( i*Q_y - C_y ) )
+ v = fp2Multiply(v[0], v[1], l.multiply(Qx.add(Cx)).subtract(Cy), Qy, p);
+
C = C.add(R).normalize();
}
}
// Final exponentiation: t = v^c
- return fp2FinalExponentiation(v, p, c);
- }
-
- private static BigInteger[] fp2SquareAndAccumulate(BigInteger[] v, ECPoint C, ECPoint Q, BigInteger p)
- {
- BigInteger Cx = C.getAffineXCoord().toBigInteger();
- BigInteger Cy = C.getAffineYCoord().toBigInteger();
- BigInteger Qx = Q.getAffineXCoord().toBigInteger();
- BigInteger Qy = Q.getAffineYCoord().toBigInteger();
-
- // Compute l = (3 * (Cx^2 - 1)) / (2 * Cy) mod p
- BigInteger l = BigInteger.valueOf(3).multiply(Cx.multiply(Cx).subtract(BigInteger.ONE))
- .multiply(Cy.multiply(BigInteger.valueOf(2)).modInverse(p)).mod(p);
-
- // Compute v = v^2 * ( l*( Q_x + C_x ) + ( i*Q_y - C_y ) )
- v = fp2Multiply(v[0], v[1], v[0], v[1], p);
-// v[0] = v[0].multiply(v[0]);
-// v[1] = v[1].multiply(v[1]);
- return accumulateLine(v[0], v[1], Cx, Cy, Qx, Qy, l, p);
-// BigInteger t_x1_bn = Cx.multiply(Cx).subtract(BigInteger.ONE).multiply(BigInteger.valueOf(3)).multiply(Qx.add(Cx)).mod(p)
-// .subtract(Cy.multiply(Cy).multiply(BigInteger.valueOf(2))).mod(p);
-// BigInteger t_x2_bn = Cy.multiply(Qy).multiply(BigInteger.valueOf(2)).mod(p);
-// v = fp2Multiply(v[0], v[1], v[0], v[1], p);
-// return fp2Multiply(v[0], v[1], t_x1_bn, t_x2_bn, p);
- }
-
- private static BigInteger[] accumulateLine(BigInteger v0, BigInteger v1, BigInteger Cx, BigInteger Cy, BigInteger Qx, BigInteger Qy, BigInteger l, BigInteger p)
- {
- return fp2Multiply(v0, v1, l.multiply(Qx.add(Cx)).subtract(Cy), Qy, p);
- }
-
- private static BigInteger[] fp2MultiplyAndAccumulate(BigInteger[] v, ECPoint C, ECPoint R, ECPoint Q, BigInteger p)
- {
- BigInteger Cx = C.getAffineXCoord().toBigInteger();
- BigInteger Cy = C.getAffineYCoord().toBigInteger();
- BigInteger Rx = R.getAffineXCoord().toBigInteger();
- BigInteger Ry = R.getAffineYCoord().toBigInteger();
- BigInteger Qx = Q.getAffineXCoord().toBigInteger();
- BigInteger Qy = Q.getAffineYCoord().toBigInteger();
-
- // Compute l = (Cy - Ry) / (Cx - Rx) mod p
- BigInteger l = Cy.subtract(Ry)
- .multiply(Cx.subtract(Rx).modInverse(p))
- .mod(p);
-
- // Compute v = v * ( l*( Q_x + C_x ) + ( i*Q_y - C_y ) )
- return accumulateLine(v[0], v[1], Cx, Cy, Qx, Qy, l, p);
-// BigInteger t_x1_bn = Qx.add(Rx).multiply(Cy).subtract(Qx.add(Cx).multiply(Ry)).mod(p);
-// BigInteger t_x2_bn = Cx.subtract(Rx).multiply(Qy).mod(p);
-// return fp2Multiply(v[0], v[1], t_x1_bn, t_x2_bn, p);
-
+ v = fp2PointSquare(v[0], v[1], p);
+ v = fp2PointSquare(v[0], v[1], p);
+ return v[1].multiply(v[0].modInverse(p)).mod(p);
}
-
static BigInteger[] fp2Multiply(BigInteger x_real, BigInteger x_imag, BigInteger y_real, BigInteger y_imag, BigInteger p)
{
- // Multiply v = (a + i*b) * scalar
return new BigInteger[]{
x_real.multiply(y_real).subtract(x_imag.multiply(y_imag)).mod(p),
x_real.multiply(y_imag).add(x_imag.multiply(y_real)).mod(p)
};
}
- private static BigInteger fp2FinalExponentiation(BigInteger[] v, BigInteger p, BigInteger c)
+ static BigInteger[] fp2PointSquare(BigInteger currentX, BigInteger currentY, BigInteger p)
{
- // Compute representative in F_p: return b/a (mod p)
-// BigInteger v0 = v[0].modPow(c, p);
-// BigInteger v1 = v[1].modPow(c, p);
-// return v1.multiply(v0.modInverse(p)).mod(p);
- v = fp2Multiply(v[0], v[1], v[0], v[1], p);
- v = fp2Multiply(v[0], v[1], v[0], v[1], p);
- return v[1].multiply(v[0].modInverse(p)).mod(p);
+ BigInteger xPlusY = currentX.add(currentY).mod(p);
+ BigInteger xMinusY = currentX.subtract(currentY).mod(p);
+ BigInteger newX = xPlusY.multiply(xMinusY).mod(p);
+
+ // Compute newY = 2xy mod p
+ BigInteger newY = currentX.multiply(currentY).multiply(BigInteger.valueOf(2)).mod(p);
+ return new BigInteger[]{newX, newY};
}
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
index 1d5128e7d3..d2f81af17b 100644
--- a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
+++ b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
@@ -3,61 +3,33 @@
import org.bouncycastle.crypto.EncapsulatedSecretGenerator;
import org.bouncycastle.crypto.SecretWithEncapsulation;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
-import org.bouncycastle.crypto.params.SAKKEPublicKeyParameters;
import org.bouncycastle.math.ec.ECCurve;
-import org.bouncycastle.math.ec.ECFieldElement;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
import org.bouncycastle.util.encoders.Hex;
import java.math.BigInteger;
-import java.nio.ByteBuffer;
import java.security.SecureRandom;
public class SAKKEKEMSGenerator
implements EncapsulatedSecretGenerator
{
- // private static final BigInteger p = new BigInteger(Hex.decode("997ABB1F 0A563FDA 65C61198 DAD0657A\n" +
-// " 416C0CE1 9CB48261 BE9AE358 B3E01A2E\n" +
-// " F40AAB27 E2FC0F1B 228730D5 31A59CB0\n" +
-// " E791B39F F7C88A19 356D27F4 A666A6D0\n" +
-// " E26C6487 326B4CD4 512AC5CD 65681CE1\n" +
-// " B6AFF4A8 31852A82 A7CF3C52 1C3C09AA\n" +
-// " 9F94D6AF 56971F1F FCE3E823 89857DB0\n" +
-// " 80C5DF10 AC7ACE87 666D807A FEA85FEB"));
private static final BigInteger p = new BigInteger(
"997ABB1F0A563FDA65C61198DAD0657A416C0CE19CB48261BE9AE358B3E01A2E" +
"F40AAB27E2FC0F1B228730D531A59CB0E791B39FF7C88A19356D27F4A666A6D0" +
"E26C6487326B4CD4512AC5CD65681CE1B6AFF4A831852A82A7CF3C521C3C09AA" +
"9F94D6AF56971F1FFCE3E82389857DB080C5DF10AC7ACE87666D807AFEA85FEB", 16
);
- // private static final BigInteger q = new BigInteger(Hex.decode("265EAEC7 C2958FF6 99718466 36B4195E\n" +
-// " 905B0338 672D2098 6FA6B8D6 2CF8068B\n" +
-// " BD02AAC9 F8BF03C6 C8A1CC35 4C69672C\n" +
-// " 39E46CE7 FDF22286 4D5B49FD 2999A9B4\n" +
-// " 389B1921 CC9AD335 144AB173 595A0738\n" +
-// " 6DABFD2A 0C614AA0 A9F3CF14 870F026A\n" +
-// " A7E535AB D5A5C7C7 FF38FA08 E2615F6C\n" +
-// " 203177C4 2B1EB3A1 D99B601E BFAA17FB"));
+
private static final BigInteger q = new BigInteger(
"265EAEC7C2958FF69971846636B4195E905B0338672D20986FA6B8D62CF8068B" +
"BD02AAC9F8BF03C6C8A1CC354C69672C39E46CE7FDF222864D5B49FD2999A9B4" +
"389B1921CC9AD335144AB173595A07386DABFD2A0C614AA0A9F3CF14870F026A" +
"A7E535ABD5A5C7C7FF38FA08E2615F6C203177C42B1EB3A1D99B601EBFAA17FB", 16
);
-// private static final BigInteger a = BigInteger.valueOf(-3).mod(p); // y² = x³ - 3x
-// private static final BigInteger b = BigInteger.ZERO;
-// private static final ECCurve.Fp curve = new ECCurve.Fp(
-// p, // Prime p
-// BigInteger.valueOf(-3).mod(p), // a = -3
-// BigInteger.ZERO, // b = 0
-// q, // Order of the subgroup (from RFC 6509)
-// BigInteger.ONE // Cofactor = 1
-// );
- // Base point P = (Px, Py)
private static final BigInteger Px = new BigInteger(
"53FC09EE332C29AD0A7990053ED9B52A2B1A2FD60AEC69C698B2F204B6FF7CBF" +
"B5EDB6C0F6CE2308AB10DB9030B09E1043D5F22CDB9DFA55718BD9E7406CE890" +
@@ -72,7 +44,6 @@ public class SAKKEKEMSGenerator
"13515AD7E9CB99A980BDAD5AD5BB4636ADB9B5706A67DCDE75573FD71BEF16D7", 16
);
-
BigInteger g = new BigInteger(Hex.decode("66FC2A43 2B6EA392 148F1586 7D623068\n" +
" C6A87BD1 FB94C41E 27FABE65 8E015A87\n" +
" 371E9474 4C96FEDA 449AE956 3F8BC446\n" +
@@ -81,7 +52,7 @@ public class SAKKEKEMSGenerator
" 55DF0460 B4A9FD74 B4F1A32B CAFA1FFA\n" +
" D682C033 A7942BCC E3720F20 B9B7B040\n" +
" 3C8CAE87 B7A0042A CDE0FAB3 6461EA46"));
- private final int n = 128;
+ private static final int n = 128;
private final SecureRandom random;
public SAKKEKEMSGenerator(SecureRandom random)
@@ -98,7 +69,7 @@ public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recip
// 2. Compute r = HashToIntegerRange(SSV || b, q)
BigInteger b = new BigInteger("323031312D30320074656C3A2B34343737303039303031323300", 16); //getRecipientId((SAKKEPublicKey)recipientKey);
BigInteger r = SAKKEUtils.hashToIntegerRange(Arrays.concatenate(ssv.toByteArray(), b.toByteArray()), q);
- System.out.println(new String(Hex.encode(r.toByteArray())));
+ //System.out.println(new String(Hex.encode(r.toByteArray())));
ECCurve.Fp curve = new ECCurve.Fp(
p, // Prime p
BigInteger.valueOf(-3).mod(p), // a = -3
@@ -107,24 +78,7 @@ public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recip
BigInteger.ONE // Cofactor = 1
);
ECPoint P = curve.createPoint(Px, Py);
- ECPoint G = curve.createPoint(
- new BigInteger(Hex.decode("53FC09EE 332C29AD 0A799005 3ED9B52A\n" +
- " 2B1A2FD6 0AEC69C6 98B2F204 B6FF7CBF\n" +
- " B5EDB6C0 F6CE2308 AB10DB90 30B09E10\n" +
- " 43D5F22C DB9DFA55 718BD9E7 406CE890\n" +
- " 9760AF76 5DD5BCCB 337C8654 8B72F2E1\n" +
- " A702C339 7A60DE74 A7C1514D BA66910D\n" +
- " D5CFB4CC 80728D87 EE9163A5 B63F73EC\n" +
- " 80EC46C4 967E0979 880DC8AB EAE63895")), // Px
- new BigInteger(Hex.decode("0A824906 3F6009F1 F9F1F053 3634A135\n" +
- " D3E82016 02990696 3D778D82 1E141178\n" +
- " F5EA69F4 654EC2B9 E7F7F5E5 F0DE55F6\n" +
- " 6B598CCF 9A140B2E 416CFF0C A9E032B9\n" +
- " 70DAE117 AD547C6C CAD696B5 B7652FE0\n" +
- " AC6F1E80 164AA989 492D979F C5A4D5F2\n" +
- " 13515AD7 E9CB99A9 80BDAD5A D5BB4636\n" +
- " ADB9B570 6A67DCDE 75573FD7 1BEF16D7")) // Py
- );
+
ECPoint Z = curve.createPoint(
new BigInteger("5958EF1B1679BF099B3A030DF255AA6A" +
"23C1D8F143D4D23F753E69BD27A832F3" +
@@ -143,31 +97,29 @@ public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recip
"C67C6D19487FB449059F26CC8AAB655A" +
"B58B7CC796E24E9A394095754F5F8BAE", 16) // Py
);
- BigInteger z = new BigInteger("AFF429D35F84B110D094803B3595A6E2998BC99F", 16);
+
// 3. Compute R_(b,S) = [r]([b]P + Z_S)
ECPoint bP = P.multiply(b).normalize();
ECPoint R_bS = bP.add(Z).multiply(r).normalize(); // [r]([b]P + Z_S)
- System.out.println("R_Bs x:" + new String(Hex.encode(R_bS.getXCoord().toBigInteger().toByteArray())));
- System.out.println("R_Bs y:" + new String(Hex.encode(R_bS.getYCoord().toBigInteger().toByteArray())));
+// System.out.println("R_Bs x:" + new String(Hex.encode(R_bS.getXCoord().toBigInteger().toByteArray())));
+// System.out.println("R_Bs y:" + new String(Hex.encode(R_bS.getYCoord().toBigInteger().toByteArray())));
// 4. Compute H = SSV XOR HashToIntegerRange( g^r, 2^n )
- BigInteger[] result = fp2Exponentiate(p, BigInteger.ONE, g, r);
- BigInteger g_r = result[0].mod(p);
- g_r = g_r.modInverse(p);
- g_r = g_r.multiply(result[1]).mod(p);
+ BigInteger[] v = fp2Exponentiate(p, BigInteger.ONE, g, r, curve);
+ BigInteger g_r = v[1].multiply(v[0].modInverse(p)).mod(p);
BigInteger mask = SAKKEUtils.hashToIntegerRange(g_r.toByteArray(), BigInteger.ONE.shiftLeft(n)); // 2^n
- System.out.println(new String(Hex.encode(mask.toByteArray())));
+ //System.out.println(new String(Hex.encode(mask.toByteArray())));
BigInteger H = ssv.xor(mask);
- System.out.println(new String(Hex.encode(H.toByteArray())));
+ //System.out.println(new String(Hex.encode(H.toByteArray())));
// 5. Encode encapsulated data (R_bS, H)
byte[] encapsulated = Arrays.concatenate(R_bS.getEncoded(false), H.toByteArray());
return new SecretWithEncapsulationImpl(
- encapsulated,
- BigIntegers.asUnsignedByteArray(n / 8, ssv) // Output SSV as key material
+ BigIntegers.asUnsignedByteArray(n / 8, ssv), // Output SSV as key material
+ encapsulated
);
}
@@ -177,11 +129,12 @@ public static BigInteger[] fp2Exponentiate(
BigInteger p,
BigInteger x,
BigInteger y,
- BigInteger exponent
+ BigInteger exponent,
+ ECCurve.Fp curve
)
{
BigInteger[] result = new BigInteger[2];
- sakkePointExponent(p, result, x, y, exponent);
+ sakkePointExponent(p, result, x, y, exponent, curve);
return result;
}
@@ -190,45 +143,32 @@ public static boolean sakkePointExponent(
BigInteger[] result,
BigInteger pointX,
BigInteger pointY,
- BigInteger n
- )
+ BigInteger n,
+ ECCurve.Fp curve)
{
// Initialize result with the original point
BigInteger currentX = pointX;
BigInteger currentY = pointY;
+ ECPoint current = curve.createPoint(currentX, currentY);
int numBits = n.bitLength();
-
+ BigInteger[] rlt;
// Process bits from MSB-1 down to 0
for (int i = numBits - 2; i >= 0; i--)
{
// Square the current point
- //sakkePointSquare(p, new BigInteger[]{currentX, currentY});
- // Compute newX = (x + y)(x - y) mod p
- BigInteger xPlusY = currentX.add(currentY).mod(p);
- BigInteger xMinusY = currentX.subtract(currentY).mod(p);
- BigInteger newX = xPlusY.multiply(xMinusY).mod(p);
-
- // Compute newY = 2xy mod p
- BigInteger newY = currentX.multiply(currentY).multiply(BigInteger.valueOf(2)).mod(p);
- currentX = newX;
- currentY = newY;
+ rlt = SAKKEKEMExtractor.fp2PointSquare(currentX, currentY, p);
+ current = current.timesPow2(2);
+ currentX = rlt[0];
+ currentY = rlt[1];
// Multiply if bit is set
if (n.testBit(i))
{
- //sakkePointsMultiply(p, currentX, currentY, pointX, pointY);
- BigInteger real = currentX.multiply(pointX)
- .subtract(currentY.multiply(pointY))
- .mod(p);
+ rlt = SAKKEKEMExtractor.fp2Multiply(currentX, currentY, pointX, pointY, p);
- // Compute imaginary part = x1*y2 + x2*y1 mod p
- BigInteger imag = currentX.multiply(pointY)
- .add(pointX.multiply(currentY))
- .mod(p);
-
- currentX = real;
- currentY = imag;
+ currentX = rlt[0];
+ currentY = rlt[1];
}
}
@@ -236,368 +176,4 @@ public static boolean sakkePointExponent(
result[1] = currentY;
return true;
}
-
-
- private BigInteger getRecipientId(SAKKEPublicKeyParameters pubKey)
- {
- byte[] hashedId = SAKKEUtils.hash(pubKey.getZ().getEncoded(false)); // Hash Z_S
- return new BigInteger(1, hashedId).mod(pubKey.getQ().subtract(BigInteger.ONE)).add(BigIntegers.TWO);
- }
-
- public static class FP2Element
- {
- private final BigInteger a; // Real part
- private final BigInteger b; // Imaginary part
- private final BigInteger p; // Prime modulus
-
- public FP2Element(BigInteger a, BigInteger b, BigInteger p)
- {
- this.a = a.mod(p);
- this.b = b.mod(p);
- this.p = p;
- }
-
- public FP2Element add(FP2Element other)
- {
- return new FP2Element(a.add(other.a), b.add(other.b), p);
- }
-
- public FP2Element subtract(FP2Element other)
- {
- return new FP2Element(a.subtract(other.a), b.subtract(other.b), p);
- }
-
- public FP2Element multiply(FP2Element other)
- {
- BigInteger real = a.multiply(other.a).subtract(b.multiply(other.b)).mod(p);
- BigInteger imag = a.multiply(other.b).add(b.multiply(other.a)).mod(p);
- return new FP2Element(real, imag, p);
- }
-
- public FP2Element inverse()
- {
- BigInteger denom = a.pow(2).add(b.pow(2)).mod(p);
- BigInteger invDenom = denom.modInverse(p);
- return new FP2Element(a.multiply(invDenom), b.negate().multiply(invDenom), p);
- }
-
- public FP2Element square()
- {
- return this.multiply(this);
- }
-
- public FP2Element pow(BigInteger exponent)
- {
- // Implement exponentiation using square-and-multiply
- FP2Element result = new FP2Element(BigInteger.ONE, BigInteger.ZERO, p);
- FP2Element base = this;
- for (int i = exponent.bitLength() - 1; i >= 0; i--)
- {
- result = result.square();
- if (exponent.testBit(i))
- {
- result = result.multiply(base);
- }
- }
- return result;
- }
-
- // Getters
- public BigInteger getA()
- {
- return a;
- }
-
- public BigInteger getB()
- {
- return b;
- }
- }
-
- /**
- * Computes the Tate-Lichtenbaum pairing ⟨P, Q⟩ as per RFC 6508.
- *
- * //* @param P First point (on E(F_p)).
- *
- * @param Q Second point (on E(F_p)).
- * @return Result of the pairing in the field F_p^2.
- */
- public static BigInteger pairing(ECPoint R, ECPoint Q, BigInteger p, BigInteger q)
- {
- ECCurve curve = R.getCurve();
- //FP2Element v = new FP2Element(BigInteger.ONE, BigInteger.ZERO, p); // Initialize to 1+0i
-
- // Use correct exponent from RFC 6508: (p+1)/q
- BigInteger exponent = p.add(BigInteger.ONE).divide(q);
-
- String qBits = q.subtract(BigInteger.ONE).toString(2);
- ECPoint C = R.normalize();
- BigInteger vx = BigInteger.ONE;
- BigInteger vy = BigInteger.ZERO;
-
- // Evaluate line at Q using F_p² arithmetic
- BigInteger Qx = Q.getAffineXCoord().toBigInteger();
- BigInteger Qy = Q.getAffineYCoord().toBigInteger();
-
- ECPoint Rnorm = R.normalize();
- BigInteger Rx = Rnorm.getAffineXCoord().toBigInteger();
- BigInteger Ry = Rnorm.getAffineYCoord().toBigInteger();
- int n = q.subtract(BigInteger.ONE).bitLength() - 1;
- for (int j = n; j > 0; j--)
- {
- /*
- * BigInteger xPlusY = currentX.add(currentY).mod(p);
- BigInteger xMinusY = currentX.subtract(currentY).mod(p);
- BigInteger newX = xPlusY.multiply(xMinusY).mod(p);
-
- // Compute newY = 2xy mod p
- BigInteger newY = currentX.multiply(currentY).multiply(BigInteger.valueOf(2)).mod(p);
- * */
- BigInteger xPlusY = vx.add(vy).mod(p);
- BigInteger xMinusY = vx.subtract(vy).mod(p);
- BigInteger newX = xPlusY.multiply(xMinusY).mod(p);
-
- // Compute newY = 2xy mod p
- BigInteger newY = vx.multiply(vy).multiply(BigInteger.valueOf(2)).mod(p);
- vx = newX;
- vy = newY;
-
- C = C.normalize();
- BigInteger Cx = C.getAffineXCoord().toBigInteger();
- BigInteger Cy = C.getAffineYCoord().toBigInteger();
-
-
- // Line function for doubling
- //3*(C_x^2 - 1)
- BigInteger t_x1_bn = (Cx.multiply(Cx).mod(p).subtract(BigInteger.ONE)).multiply(BigInteger.valueOf(3));
- //Qx + Cx
- BigInteger t_bn = Qx.add(Cx);
- //3*(C_x^2 - 1)(Qx+Cx)
- t_x1_bn = t_x1_bn.multiply(t_bn).mod(p);
- //Cy^2*2
- t_bn = Cy.multiply(Cy).mod(p).multiply(BigInteger.valueOf(2));
- //3*(C_x^2 - 1)(Qx+Cx) - Cy^2*2
- t_x1_bn = t_x1_bn.subtract(t_bn).mod(p);
- // Cy*2*Qy
- BigInteger t_x2_bn = Cy.multiply(BigInteger.valueOf(2)).multiply(Qy).mod(p);
-
- /*
- * BigInteger real = currentX.multiply(pointX)
- .subtract(currentY.multiply(pointY))
- .mod(p);
-
- // Compute imaginary part = x1*y2 + x2*y1 mod p
- BigInteger imag = currentX.multiply(pointY)
- .add(pointX.multiply(currentY))
- .mod(p);*/
- BigInteger real = vx.multiply(t_x1_bn)
- .subtract(vy.multiply(t_x2_bn))
- .mod(p);
-
- // Compute imaginary part = x1*y2 + x2*y1 mod p
- BigInteger imag = vx.multiply(t_x2_bn)
- .add(t_x1_bn.multiply(vy))
- .mod(p);
-
- vx = real;
- vy = imag;
-
- C = C.twice().normalize();
-
- if (qBits.charAt(j) == '1')
- {
- t_x1_bn = Qx.add(Rx).multiply(Cy).mod(p);
- BigInteger tmp_t_bn = Qx.add(Cx).multiply(Ry);
- t_x1_bn = t_x1_bn.subtract(tmp_t_bn).mod(p);
- t_x2_bn = Cx.subtract(Rx).multiply(Qy).mod(p);
- real = vx.multiply(t_x1_bn)
- .subtract(vy.multiply(t_x2_bn))
- .mod(p);
-
- // Compute imaginary part = x1*y2 + x2*y1 mod p
- imag = vx.multiply(t_x2_bn)
- .add(t_x1_bn.multiply(vy))
- .mod(p);
-
- vx = real;
- vy = imag;
- C = C.add(Rnorm).normalize();
- }
- }
- BigInteger xPlusY = vx.add(vy).mod(p);
- BigInteger xMinusY = vx.subtract(vy).mod(p);
- BigInteger newX = xPlusY.multiply(xMinusY).mod(p);
-
- // Compute newY = 2xy mod p
- BigInteger newY = vx.multiply(vy).multiply(BigInteger.valueOf(2)).mod(p);
- vx = newX;
- vy = newY;
-
- xPlusY = vx.add(vy).mod(p);
- xMinusY = vx.subtract(vy).mod(p);
- newX = xPlusY.multiply(xMinusY).mod(p);
-
- // Compute newY = 2xy mod p
- newY = vx.multiply(vy).multiply(BigInteger.valueOf(2)).mod(p);
-
- vx = newX;
- vy = newY;
-
- BigInteger w = vx.modInverse(p).multiply(vy).mod(p);
-
- return w;
-// // Final exponentiation
-// FP2Element t = v.pow(exponent);
-//
-// // Convert to F_p representative: b/a mod p
-// BigInteger a = t.getA();
-// BigInteger b = t.getB();
-// return b.multiply(a.modInverse(p)).mod(p);
- }
-// public static BigInteger pairing(ECPoint R, ECPoint Q, BigInteger p, BigInteger q) {
-// ECCurve curve = R.getCurve();
-// BigInteger qMinus1 = q.subtract(BigInteger.ONE);
-// int N = qMinus1.bitLength() - 1;
-//
-// // Initialize V = (1, 0) in Fp²
-// BigInteger vx = BigInteger.ONE;
-// BigInteger vy = BigInteger.ZERO;
-//
-// // Initialize C = R
-// ECPoint C = R.normalize();
-// BigInteger Cx = C.getAffineXCoord().toBigInteger();
-// BigInteger Cy = C.getAffineYCoord().toBigInteger();
-//
-// // Precompute Q coordinates
-// ECPoint Qnorm = Q.normalize();
-// BigInteger Qx = Qnorm.getAffineXCoord().toBigInteger();
-// BigInteger Qy = Qnorm.getAffineYCoord().toBigInteger();
-//
-// // Precompute R coordinates for addition steps
-// ECPoint Rnorm = R.normalize();
-// BigInteger Rx = Rnorm.getAffineXCoord().toBigInteger();
-// BigInteger Ry = Rnorm.getAffineYCoord().toBigInteger();
-//
-// for (; N > 0; N--) {
-// // V = V² (complex squaring)
-// BigInteger[] squared = pointSquare(vx, vy, p);
-// vx = squared[0];
-// vy = squared[1];
-//
-// // Calculate line function for doubling
-// BigInteger[] T = computeLineFunction(Cx, Cy, Qx, Qy, p);
-//
-// // V = V * T (complex multiplication)
-// BigInteger[] multiplied = pointMultiply(vx, vy, T[0], T[1], p);
-// vx = multiplied[0];
-// vy = multiplied[1];
-//
-// // Double point C
-// BigInteger[] doubled = pointDouble(Cx, Cy, p);
-// Cx = doubled[0];
-// Cy = doubled[1];
-//
-// if (qMinus1.testBit(N-1)) {
-// // Calculate line function for addition
-// BigInteger[] TAdd = computeLineFunctionAdd(Cx, Cy, Rx, Ry, Qx, Qy, p);
-//
-// // V = V * TAdd
-// multiplied = pointMultiply(vx, vy, TAdd[0], TAdd[1], p);
-// vx = multiplied[0];
-// vy = multiplied[1];
-//
-// // Add points C = C + R
-// BigInteger[] added = pointAdd(Cx, Cy, Rx, Ry, p);
-// Cx = added[0];
-// Cy = added[1];
-// }
-// }
-//
-// // Final squaring V = V²
-// BigInteger[] squared = pointSquare(vx, vy, p);
-// vx = squared[0];
-// vy = squared[1];
-// squared = pointSquare(vx, vy, p);
-// vx = squared[0];
-// vy = squared[1];
-//
-// // Compute w = (Vy * Vx⁻¹) mod p
-// BigInteger vxInv = vx.modInverse(p);
-// return vy.multiply(vxInv).mod(p);
-// }
-//
-// // Helper methods implementing exact C code operations
-// private static BigInteger[] pointSquare(BigInteger x, BigInteger y, BigInteger p) {
-// BigInteger xPlusY = x.add(y).mod(p);
-// BigInteger xMinusY = x.subtract(y).mod(p);
-// return new BigInteger[] {
-// xPlusY.multiply(xMinusY).mod(p),
-// x.multiply(y).multiply(BigInteger.valueOf(2)).mod(p)
-// };
-// }
-//
-// private static BigInteger[] pointMultiply(BigInteger a, BigInteger b, BigInteger c, BigInteger d, BigInteger p) {
-// return new BigInteger[] {
-// a.multiply(d).add(b.multiply(c)).mod(p),
-// a.multiply(c).subtract(b.multiply(d)).mod(p),
-//
-// };
-// }
-//
-// private static BigInteger[] pointDouble(BigInteger x, BigInteger y, BigInteger p) {
-// BigInteger slope = x.pow(2).multiply(BigInteger.valueOf(3))
-// .mod(p)
-// .multiply(y.multiply(BigInteger.valueOf(2)).modInverse(p))
-// .mod(p);
-// return new BigInteger[] {
-// slope.pow(2).subtract(x.multiply(BigInteger.valueOf(2))).mod(p),
-// slope.multiply(x.subtract(slope.pow(2).mod(p)))
-// .subtract(y).mod(p)
-// };
-// }
-//
-// private static BigInteger[] pointAdd(BigInteger x1, BigInteger y1, BigInteger x2, BigInteger y2, BigInteger p) {
-// BigInteger slope = y2.subtract(y1)
-// .multiply(x2.subtract(x1).modInverse(p))
-// .mod(p);
-// return new BigInteger[] {
-// slope.pow(2).subtract(x1).subtract(x2).mod(p),
-// slope.multiply(x1.subtract(slope.pow(2).subtract(x1).subtract(x2).mod(p)))
-// .subtract(y1).mod(p)
-// };
-// }
-//
-// private static BigInteger[] computeLineFunction(BigInteger Cx, BigInteger Cy,
-// BigInteger Qx, BigInteger Qy,
-// BigInteger p) {
-// // Calculate 3*(Cx² - 1)
-// BigInteger t_x1 = Cx.pow(2).subtract(BigInteger.ONE).multiply(BigInteger.valueOf(3)).mod(p);
-// // Calculate Qx + Cx
-// BigInteger t = Qx.add(Cx).mod(p);
-// // Multiply components
-// t_x1 = t_x1.multiply(t).mod(p);
-// // Subtract 2*Cy²
-// t_x1 = t_x1.subtract(Cy.pow(2).multiply(BigInteger.valueOf(2))).mod(p);
-// // Calculate 2*Cy*Qy
-// BigInteger t_x2 = Cy.multiply(BigInteger.valueOf(2)).multiply(Qy).mod(p);
-// return new BigInteger[] {t_x1, t_x2};
-// }
-//
-// private static BigInteger[] computeLineFunctionAdd(BigInteger Cx, BigInteger Cy,
-// BigInteger Rx, BigInteger Ry,
-// BigInteger Qx, BigInteger Qy,
-// BigInteger p) {
-// // Calculate (Cy - Ry)
-// BigInteger numerator = Cy.subtract(Ry).mod(p);
-// // Calculate (Cx - Rx)⁻¹
-// BigInteger denominator = Cx.subtract(Rx).modInverse(p);
-// BigInteger slope = numerator.multiply(denominator).mod(p);
-//
-// // Calculate line function components
-// BigInteger t_x1 = slope.multiply(Qx.add(Cx).mod(p)).mod(p);
-// BigInteger t_x2 = slope.multiply(Qy).negate().mod(p);
-// return new BigInteger[] {t_x1, t_x2};
-// }
-
-
}
diff --git a/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java b/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
index d40a78abfb..187adf0d09 100644
--- a/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
@@ -41,17 +41,6 @@ public static void main(String[] args)
//System.out.println("SAKKE KEM Test " + (testPassed ? "PASSED" : "FAILED"));
}
- private static byte[] hexStringToByteArray(String s)
- {
- int len = s.length();
- byte[] data = new byte[len / 2];
- for (int i = 0; i < len; i += 2)
- {
- data[i / 2] = (byte)((Character.digit(s.charAt(i), 16) << 4)
- + Character.digit(s.charAt(i + 1), 16));
- }
- return data;
- }
@Override
public String getName()
@@ -141,7 +130,6 @@ public void performTest()
"E26C6487326B4CD4512AC5CD65681CE1B6AFF4A831852A82A7CF3C521C3C09AA" +
"9F94D6AF56971F1FFCE3E82389857DB080C5DF10AC7ACE87666D807AFEA85FEB", 16
);
-
ECCurve.Fp curve = new ECCurve.Fp(
p, // Prime p
BigInteger.valueOf(-3).mod(p), // a = -3
@@ -152,28 +140,14 @@ public void performTest()
SAKKEKEMSGenerator generator = new SAKKEKEMSGenerator(new SecureRandom());
SecretWithEncapsulation rlt = generator.generateEncapsulated(null);
+
ECPoint K_bS = curve.createPoint(kbx, kby);
SAKKEKEMExtractor extractor = new SAKKEKEMExtractor(new SAKKEPrivateKeyParameters(new BigInteger(b), K_bS,
new SAKKEPublicKeyParameters(curve.createPoint(Zx, Zy))));
- byte[] test = extractor.extractSecret(rlt.getSecret());
-
-
- System.out.println("K_bS x:" + new String(Hex.encode(K_bS.getXCoord().toBigInteger().toByteArray())));
- System.out.println("K_bS y:" + new String(Hex.encode(K_bS.getYCoord().toBigInteger().toByteArray())));
- ECPoint R_bs = curve.createPoint(Rbx, Rby);
- SAKKEKEMSGenerator.pairing(K_bS, R_bs, p, q);
-
- BigInteger r = SAKKEUtils.hashToIntegerRange(Arrays.concatenate(SSV, b), q);
-
- System.out.println("r:" + new String(Hex.encode(r.toByteArray())));
-
- System.out.println("r:" + new String(Hex.encode(expectedR)));
-
- Assert.assertTrue(Arrays.areEqual(r.toByteArray(), expectedR));
-// SAKKEKEMSGenerator generator = new SAKKEKEMSGenerator(new SecureRandom());
-// generator.generateEncapsulated(null);
+ byte[] test = extractor.extractSecret(rlt.getEncapsulation());
+ Assert.assertTrue(Arrays.areEqual(test, SSV));
}
}
From 1fdc823db8eb1feaa4914d12f5ff162334193f72 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Wed, 5 Feb 2025 18:26:05 +1030
Subject: [PATCH 172/890] Remove unused functions. Format the code
---
.../crypto/kems/SAKKEKEMExtractor.java | 4 +-
.../crypto/kems/SAKKEKEMSGenerator.java | 22 ++------
.../bouncycastle/crypto/kems/SAKKEUtils.java | 51 -------------------
.../crypto/kems/test/SAKKEKEMSTest.java | 25 +++------
.../crypto/test/RegressionTest.java | 2 +
5 files changed, 14 insertions(+), 90 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java
index 8551f74680..469cd1aa92 100644
--- a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java
+++ b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java
@@ -6,11 +6,9 @@
import org.bouncycastle.crypto.params.SAKKEPrivateKeyParameters;
import org.bouncycastle.crypto.params.SAKKEPublicKeyParameters;
import org.bouncycastle.math.ec.ECCurve;
-import org.bouncycastle.math.ec.ECFieldElement;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
-import org.bouncycastle.util.encoders.Hex;
public class SAKKEKEMExtractor
@@ -49,7 +47,7 @@ public byte[] extractSecret(byte[] encapsulation)
// Step 2: Compute w = using pairing
BigInteger w = computePairing(R_bS, K_bS, p, q);
- System.out.println(new String(Hex.encode(w.toByteArray())));
+ //System.out.println(new String(Hex.encode(w.toByteArray())));
//BigInteger w = tatePairing(R_bS.getXCoord().toBigInteger(), R_bS.getYCoord().toBigInteger(), K_bS.getXCoord().toBigInteger(), K_bS.getYCoord().toBigInteger(), q, p);
// Step 3: Compute SSV = H XOR HashToIntegerRange(w, 2^n)
BigInteger twoToN = BigInteger.ONE.shiftLeft(n);
diff --git a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
index d2f81af17b..0d53ce0281 100644
--- a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
+++ b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
@@ -64,7 +64,7 @@ public SAKKEKEMSGenerator(SecureRandom random)
public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recipientKey)
{
// 1. Generate random SSV in range [0, 2^n - 1]
- BigInteger ssv = new BigInteger("123456789ABCDEF0123456789ABCDEF0", 16);//new BigInteger(n, random);
+ BigInteger ssv = new BigInteger(n, random);
// 2. Compute r = HashToIntegerRange(SSV || b, q)
BigInteger b = new BigInteger("323031312D30320074656C3A2B34343737303039303031323300", 16); //getRecipientId((SAKKEPublicKey)recipientKey);
@@ -127,25 +127,13 @@ public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recip
// Helper method for F_p² exponentiation
public static BigInteger[] fp2Exponentiate(
BigInteger p,
- BigInteger x,
- BigInteger y,
- BigInteger exponent,
- ECCurve.Fp curve
- )
- {
- BigInteger[] result = new BigInteger[2];
- sakkePointExponent(p, result, x, y, exponent, curve);
- return result;
- }
-
- public static boolean sakkePointExponent(
- BigInteger p,
- BigInteger[] result,
BigInteger pointX,
BigInteger pointY,
BigInteger n,
- ECCurve.Fp curve)
+ ECCurve.Fp curve
+ )
{
+ BigInteger[] result = new BigInteger[2];
// Initialize result with the original point
BigInteger currentX = pointX;
@@ -174,6 +162,6 @@ public static boolean sakkePointExponent(
result[0] = currentX;
result[1] = currentY;
- return true;
+ return result;
}
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEUtils.java b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEUtils.java
index 45fbbb38b5..891f2ae878 100644
--- a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEUtils.java
+++ b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEUtils.java
@@ -2,45 +2,11 @@
import java.math.BigInteger;
-import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;
-import org.bouncycastle.math.ec.ECPoint;
-import org.bouncycastle.util.encoders.Hex;
public class SAKKEUtils
{
- public static ECPoint sakkePointExponent(ECPoint point, BigInteger n) {
- if (n.equals(BigInteger.ZERO)) {
- throw new IllegalArgumentException("Exponent cannot be zero.");
- }
-
- ECPoint result = point;
- int N = n.bitLength() - 1;
-
- for (; N != 0; --N) {
- result = sakkePointSquare(result);
- if (n.testBit(N - 1)) {
- result = sakkePointsMultiply(result, point);
- }
- }
- return result;
- }
-
- public static ECPoint sakkePointSquare(ECPoint point) {
- BigInteger x = point.getAffineXCoord().toBigInteger();
- BigInteger y = point.getAffineYCoord().toBigInteger();
-
- BigInteger bx1 = x.add(y);
- BigInteger bx2 = x.subtract(y);
- BigInteger newX = bx1.multiply(bx2).mod(point.getCurve().getField().getCharacteristic());
- BigInteger newY = x.multiply(y).multiply(BigInteger.valueOf(2)).mod(point.getCurve().getField().getCharacteristic());
-
- return point.getCurve().createPoint(newX, newY);
- }
- public static ECPoint sakkePointsMultiply(ECPoint p1, ECPoint p2) {
- return p1.add(p2).normalize();
- }
public static BigInteger hashToIntegerRange(byte[] input, BigInteger q)
{
// RFC 6508 Section 5.1: Hashing to an Integer Range
@@ -66,32 +32,15 @@ public static BigInteger hashToIntegerRange(byte[] input, BigInteger q)
// h_i = hashfn(h_{i-1})
digest.update(h, 0, h.length);
digest.doFinal(h, 0);
- //System.out.println("h_"+i+":" +new String(Hex.encode(h)));
// v_i = hashfn(h_i || A)
digest.update(h, 0, h.length);
digest.update(A, 0, A.length);
byte[] v_i = new byte[digest.getDigestSize()];
digest.doFinal(v_i, 0);
- //System.out.println("v_"+i+":" +new String(Hex.encode(v_i)));
// Append v_i to v'
v = v.shiftLeft(v_i.length * 8).add(new BigInteger(1, v_i));
}
- //System.out.println("v:" +new String(Hex.encode(v.toByteArray())));
// Step 6: v = v' mod n
return v.mod(q);
}
-
- public static byte[] hash(byte[] data)
- {
- Digest digest = new SHA256Digest();
- byte[] rlt = new byte[digest.getDigestSize()];
- digest.update(data, 0, data.length);
- digest.doFinal(rlt, 0);
- return rlt;
- }
-
- public static byte[] hash(ECPoint point)
- {
- return hash(point.getEncoded(false)); // Use uncompressed encoding
- }
}
diff --git a/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java b/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
index 187adf0d09..7a2b0d5b64 100644
--- a/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
@@ -7,13 +7,11 @@
import org.bouncycastle.crypto.SecretWithEncapsulation;
import org.bouncycastle.crypto.kems.SAKKEKEMExtractor;
import org.bouncycastle.crypto.kems.SAKKEKEMSGenerator;
-import org.bouncycastle.crypto.kems.SAKKEUtils;
import org.bouncycastle.crypto.params.SAKKEPrivateKeyParameters;
import org.bouncycastle.crypto.params.SAKKEPublicKeyParameters;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.Arrays;
-import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.FixedSecureRandom;
import org.bouncycastle.util.test.SimpleTest;
@@ -27,18 +25,6 @@ public static void main(String[] args)
{
SAKKEKEMSTest test = new SAKKEKEMSTest();
test.performTest();
- // Expected Rb values
-// BigInteger expectedRbx = new BigInteger("44E8AD44AB8592A6A5A3DDCA5CF896C718043606A01D650DEF37A01F37C228C332FC317354E2C274D4DAF8AD001054C7...
-// BigInteger expectedRby = new BigInteger("557E134AD85BB1D4B9CE4F8BE4B08A12BABF55B1D6F1D7A638019EA28E15AB1C9F76375FDD1210D4F4351B9A009486B7...
-//
-// // Instantiate SAKKE KEM Generator
-// SAKKEKEMSGenerator kem = new SAKKEKEMSGenerator();
-// EncapsulatedData encapsulatedData = kem.encapsulate(SSV);
-//
-// // Validate results
-// boolean testPassed = expectedRbx.equals(encapsulatedData.getRbx()) && expectedRby.equals(encapsulatedData.getRby());
-
- //System.out.println("SAKKE KEM Test " + (testPassed ? "PASSED" : "FAILED"));
}
@@ -78,7 +64,7 @@ public void performTest()
//
byte[] b = Hex.decode("323031312D30320074656C3A2B34343737303039303031323300");
- byte[] SSV = Hex.decode("123456789ABCDEF0123456789ABCDEF0");
+ byte[] ssv = Hex.decode("123456789ABCDEF0123456789ABCDEF0");
byte[] expectedR = Hex.decode("13EE3E1B8DAC5DB168B1CEB32F0566A4C273693F78BAFFA2A2EE6A686E6BD90F8206CCAB84E7F"
+ "42ED39BD4FB131012ECCA2ECD2119414560C17CAB46B956A80F58A3302EB3E2C9A228FBA7ED34D8ACA2392DA1FFB0B17B2320AE09AAEDF"
+ "D0235F6FE0EB65337A63F9CC97728B8E5AD0460FADE144369AA5B2166213247712096");
@@ -137,17 +123,18 @@ public void performTest()
g,// Order of the subgroup (from RFC 6509)
BigInteger.ONE // Cofactor = 1
);
- SAKKEKEMSGenerator generator = new SAKKEKEMSGenerator(new SecureRandom());
- SecretWithEncapsulation rlt = generator.generateEncapsulated(null);
+ SecureRandom random = new FixedSecureRandom(new FixedSecureRandom.Source[]{new FixedSecureRandom.Data(ssv),
+ new FixedSecureRandom.Data(b)});
+ SAKKEKEMSGenerator generator = new SAKKEKEMSGenerator(random);
+ SecretWithEncapsulation rlt = generator.generateEncapsulated(null);
ECPoint K_bS = curve.createPoint(kbx, kby);
-
SAKKEKEMExtractor extractor = new SAKKEKEMExtractor(new SAKKEPrivateKeyParameters(new BigInteger(b), K_bS,
new SAKKEPublicKeyParameters(curve.createPoint(Zx, Zy))));
byte[] test = extractor.extractSecret(rlt.getEncapsulation());
- Assert.assertTrue(Arrays.areEqual(test, SSV));
+ Assert.assertTrue(Arrays.areEqual(test, ssv));
}
}
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java b/core/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java
index c945e3154a..1025007493 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java
@@ -1,5 +1,6 @@
package org.bouncycastle.crypto.test;
+import org.bouncycastle.crypto.kems.test.SAKKEKEMSTest;
import org.bouncycastle.util.test.SimpleTest;
import org.bouncycastle.util.test.Test;
@@ -195,6 +196,7 @@ public class RegressionTest
new SparkleTest(),
new ISAPTest(),
new ConcatenationKDFTest(),
+ new SAKKEKEMSTest(),
};
public static void main(String[] args)
From 26136939d1269327228ee92dfcf7f35d62c75b3c Mon Sep 17 00:00:00 2001
From: gefeili
Date: Thu, 6 Feb 2025 17:20:19 +1030
Subject: [PATCH 173/890] Set teh parameter settings of SAKKE
---
.../crypto/kems/SAKKEKEMExtractor.java | 17 ++--
.../crypto/kems/SAKKEKEMSGenerator.java | 90 ++++---------------
.../params/SAKKEPrivateKeyParameters.java | 23 ++---
.../params/SAKKEPublicKeyParameters.java | 56 ++++++++----
.../crypto/kems/test/SAKKEKEMSTest.java | 26 +++++-
5 files changed, 97 insertions(+), 115 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java
index 469cd1aa92..418ec767dd 100644
--- a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java
+++ b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java
@@ -19,21 +19,21 @@ public class SAKKEKEMExtractor
private final BigInteger q;
private final ECPoint P;
private final ECPoint Z_S;
- private final ECPoint K_bS; // Receiver's RSK
+ private final ECPoint K_bs;
private final int n; // Security parameter
- private final SAKKEPrivateKeyParameters privateKey;
+ private final BigInteger identifier;
public SAKKEKEMExtractor(SAKKEPrivateKeyParameters privateKey)
{
- this.privateKey = privateKey;
SAKKEPublicKeyParameters publicKey = privateKey.getPublicParams();
this.curve = publicKey.getCurve();
this.q = publicKey.getQ();
this.P = publicKey.getP();
- this.p = publicKey.getp();
+ this.p = publicKey.getPrime();
this.Z_S = publicKey.getZ();
- this.K_bS = privateKey.getPrivatePoint();
+ this.K_bs = privateKey.getRSK();
this.n = publicKey.getN();
+ this.identifier = publicKey.getIdentifier();
}
@Override
@@ -46,16 +46,15 @@ public byte[] extractSecret(byte[] encapsulation)
BigInteger H = new BigInteger(Arrays.copyOfRange(encapsulation, 257, 274));
// Step 2: Compute w = using pairing
- BigInteger w = computePairing(R_bS, K_bS, p, q);
- //System.out.println(new String(Hex.encode(w.toByteArray())));
- //BigInteger w = tatePairing(R_bS.getXCoord().toBigInteger(), R_bS.getYCoord().toBigInteger(), K_bS.getXCoord().toBigInteger(), K_bS.getYCoord().toBigInteger(), q, p);
+ BigInteger w = computePairing(R_bS, K_bs, p, q);
+
// Step 3: Compute SSV = H XOR HashToIntegerRange(w, 2^n)
BigInteger twoToN = BigInteger.ONE.shiftLeft(n);
BigInteger mask = SAKKEUtils.hashToIntegerRange(w.toByteArray(), twoToN);
BigInteger ssv = H.xor(mask);
// Step 4: Compute r = HashToIntegerRange(SSV || b)
- BigInteger b = privateKey.getB();
+ BigInteger b = identifier;
BigInteger r = SAKKEUtils.hashToIntegerRange(Arrays.concatenate(ssv.toByteArray(), b.toByteArray()), q);
// Step 5: Validate R_bS
diff --git a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
index 0d53ce0281..fe48251968 100644
--- a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
+++ b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
@@ -3,11 +3,11 @@
import org.bouncycastle.crypto.EncapsulatedSecretGenerator;
import org.bouncycastle.crypto.SecretWithEncapsulation;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.SAKKEPublicKeyParameters;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
-import org.bouncycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.security.SecureRandom;
@@ -15,44 +15,6 @@
public class SAKKEKEMSGenerator
implements EncapsulatedSecretGenerator
{
-
- private static final BigInteger p = new BigInteger(
- "997ABB1F0A563FDA65C61198DAD0657A416C0CE19CB48261BE9AE358B3E01A2E" +
- "F40AAB27E2FC0F1B228730D531A59CB0E791B39FF7C88A19356D27F4A666A6D0" +
- "E26C6487326B4CD4512AC5CD65681CE1B6AFF4A831852A82A7CF3C521C3C09AA" +
- "9F94D6AF56971F1FFCE3E82389857DB080C5DF10AC7ACE87666D807AFEA85FEB", 16
- );
-
- private static final BigInteger q = new BigInteger(
- "265EAEC7C2958FF69971846636B4195E905B0338672D20986FA6B8D62CF8068B" +
- "BD02AAC9F8BF03C6C8A1CC354C69672C39E46CE7FDF222864D5B49FD2999A9B4" +
- "389B1921CC9AD335144AB173595A07386DABFD2A0C614AA0A9F3CF14870F026A" +
- "A7E535ABD5A5C7C7FF38FA08E2615F6C203177C42B1EB3A1D99B601EBFAA17FB", 16
- );
-
- private static final BigInteger Px = new BigInteger(
- "53FC09EE332C29AD0A7990053ED9B52A2B1A2FD60AEC69C698B2F204B6FF7CBF" +
- "B5EDB6C0F6CE2308AB10DB9030B09E1043D5F22CDB9DFA55718BD9E7406CE890" +
- "9760AF765DD5BCCB337C86548B72F2E1A702C3397A60DE74A7C1514DBA66910D" +
- "D5CFB4CC80728D87EE9163A5B63F73EC80EC46C4967E0979880DC8ABEAE63895", 16
- );
-
- private static final BigInteger Py = new BigInteger(
- "0A8249063F6009F1F9F1F0533634A135D3E82016029906963D778D821E141178" +
- "F5EA69F4654EC2B9E7F7F5E5F0DE55F66B598CCF9A140B2E416CFF0CA9E032B9" +
- "70DAE117AD547C6CCAD696B5B7652FE0AC6F1E80164AA989492D979FC5A4D5F2" +
- "13515AD7E9CB99A980BDAD5AD5BB4636ADB9B5706A67DCDE75573FD71BEF16D7", 16
- );
-
- BigInteger g = new BigInteger(Hex.decode("66FC2A43 2B6EA392 148F1586 7D623068\n" +
- " C6A87BD1 FB94C41E 27FABE65 8E015A87\n" +
- " 371E9474 4C96FEDA 449AE956 3F8BC446\n" +
- " CBFDA85D 5D00EF57 7072DA8F 541721BE\n" +
- " EE0FAED1 828EAB90 B99DFB01 38C78433\n" +
- " 55DF0460 B4A9FD74 B4F1A32B CAFA1FFA\n" +
- " D682C033 A7942BCC E3720F20 B9B7B040\n" +
- " 3C8CAE87 B7A0042A CDE0FAB3 6461EA46"));
- private static final int n = 128;
private final SecureRandom random;
public SAKKEKEMSGenerator(SecureRandom random)
@@ -63,54 +25,34 @@ public SAKKEKEMSGenerator(SecureRandom random)
@Override
public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recipientKey)
{
+ SAKKEPublicKeyParameters keyParameters = (SAKKEPublicKeyParameters)recipientKey;
+ ECPoint Z = keyParameters.getZ();
+ BigInteger b = keyParameters.getIdentifier();
+ BigInteger p = keyParameters.getPrime();
+ BigInteger q = keyParameters.getQ();
+ BigInteger g = keyParameters.getG();
+ int n = keyParameters.getN();
+ ECCurve curve = keyParameters.getCurve();
+ ECPoint P = keyParameters.getP();
+
// 1. Generate random SSV in range [0, 2^n - 1]
BigInteger ssv = new BigInteger(n, random);
+
// 2. Compute r = HashToIntegerRange(SSV || b, q)
- BigInteger b = new BigInteger("323031312D30320074656C3A2B34343737303039303031323300", 16); //getRecipientId((SAKKEPublicKey)recipientKey);
+
BigInteger r = SAKKEUtils.hashToIntegerRange(Arrays.concatenate(ssv.toByteArray(), b.toByteArray()), q);
- //System.out.println(new String(Hex.encode(r.toByteArray())));
- ECCurve.Fp curve = new ECCurve.Fp(
- p, // Prime p
- BigInteger.valueOf(-3).mod(p), // a = -3
- BigInteger.ZERO, // ,
- g, // Order of the subgroup (from RFC 6509)
- BigInteger.ONE // Cofactor = 1
- );
- ECPoint P = curve.createPoint(Px, Py);
-
- ECPoint Z = curve.createPoint(
- new BigInteger("5958EF1B1679BF099B3A030DF255AA6A" +
- "23C1D8F143D4D23F753E69BD27A832F3" +
- "8CB4AD53DDEF4260B0FE8BB45C4C1FF5" +
- "10EFFE300367A37B61F701D914AEF097" +
- "24825FA0707D61A6DFF4FBD7273566CD" +
- "DE352A0B04B7C16A78309BE640697DE7" +
- "47613A5FC195E8B9F328852A579DB8F9" +
- "9B1D0034479EA9C5595F47C4B2F54FF2", 16), // Px
- new BigInteger("1508D37514DCF7A8E143A6058C09A6BF" +
- "2C9858CA37C258065AE6BF7532BC8B5B" +
- "63383866E0753C5AC0E72709F8445F2E" +
- "6178E065857E0EDA10F68206B63505ED" +
- "87E534FB2831FF957FB7DC619DAE6130" +
- "1EEACC2FDA3680EA4999258A833CEA8F" +
- "C67C6D19487FB449059F26CC8AAB655A" +
- "B58B7CC796E24E9A394095754F5F8BAE", 16) // Py
- );
+
// 3. Compute R_(b,S) = [r]([b]P + Z_S)
ECPoint bP = P.multiply(b).normalize();
ECPoint R_bS = bP.add(Z).multiply(r).normalize(); // [r]([b]P + Z_S)
-// System.out.println("R_Bs x:" + new String(Hex.encode(R_bS.getXCoord().toBigInteger().toByteArray())));
-// System.out.println("R_Bs y:" + new String(Hex.encode(R_bS.getYCoord().toBigInteger().toByteArray())));
-
// 4. Compute H = SSV XOR HashToIntegerRange( g^r, 2^n )
BigInteger[] v = fp2Exponentiate(p, BigInteger.ONE, g, r, curve);
BigInteger g_r = v[1].multiply(v[0].modInverse(p)).mod(p);
BigInteger mask = SAKKEUtils.hashToIntegerRange(g_r.toByteArray(), BigInteger.ONE.shiftLeft(n)); // 2^n
- //System.out.println(new String(Hex.encode(mask.toByteArray())));
BigInteger H = ssv.xor(mask);
//System.out.println(new String(Hex.encode(H.toByteArray())));
@@ -124,14 +66,12 @@ public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recip
}
- // Helper method for F_p² exponentiation
public static BigInteger[] fp2Exponentiate(
BigInteger p,
BigInteger pointX,
BigInteger pointY,
BigInteger n,
- ECCurve.Fp curve
- )
+ ECCurve curve)
{
BigInteger[] result = new BigInteger[2];
diff --git a/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPrivateKeyParameters.java
index 2c83f35ba3..c90a373cf0 100644
--- a/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPrivateKeyParameters.java
+++ b/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPrivateKeyParameters.java
@@ -7,30 +7,31 @@
public class SAKKEPrivateKeyParameters
extends AsymmetricKeyParameter
{
- private final BigInteger b; // User's identity
- private final ECPoint K; // Private key K_a
private final SAKKEPublicKeyParameters publicParams;
+ private final BigInteger z; // KMS Public Key: Z = [z]P
+ private final ECPoint rsk;
- public SAKKEPrivateKeyParameters(BigInteger b, ECPoint K, SAKKEPublicKeyParameters publicParams)
+ public SAKKEPrivateKeyParameters(BigInteger z, ECPoint rsk, SAKKEPublicKeyParameters publicParams)
{
super(true);
- this.b = b;
- this.K = K;
+ this.z = z;
+ this.rsk = rsk;
this.publicParams = publicParams;
}
- public BigInteger getB()
+ public SAKKEPublicKeyParameters getPublicParams()
{
- return b;
+ return publicParams;
}
- public SAKKEPublicKeyParameters getPublicParams()
+
+ public BigInteger getMasterSecret()
{
- return publicParams;
+ return z;
}
- public ECPoint getPrivatePoint()
+ public ECPoint getRSK()
{
- return K;
+ return rsk;
}
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKeyParameters.java
index 66ce4e81ef..a062d766fc 100644
--- a/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKeyParameters.java
+++ b/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKeyParameters.java
@@ -2,6 +2,8 @@
import java.math.BigInteger;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;
@@ -17,6 +19,13 @@ public class SAKKEPublicKeyParameters
"9F94D6AF56971F1FFCE3E82389857DB080C5DF10AC7ACE87666D807AFEA85FEB", 16
);
+ private static final BigInteger q = new BigInteger(
+ "265EAEC7C2958FF69971846636B4195E905B0338672D20986FA6B8D62CF8068B" +
+ "BD02AAC9F8BF03C6C8A1CC354C69672C39E46CE7FDF222864D5B49FD2999A9B4" +
+ "389B1921CC9AD335144AB173595A07386DABFD2A0C614AA0A9F3CF14870F026A" +
+ "A7E535ABD5A5C7C7FF38FA08E2615F6C203177C42B1EB3A1D99B601EBFAA17FB", 16
+ );
+
private static final BigInteger Px = new BigInteger(
"53FC09EE332C29AD0A7990053ED9B52A2B1A2FD60AEC69C698B2F204B6FF7CBF" +
"B5EDB6C0F6CE2308AB10DB9030B09E1043D5F22CDB9DFA55718BD9E7406CE890" +
@@ -31,7 +40,8 @@ public class SAKKEPublicKeyParameters
"13515AD7E9CB99A980BDAD5AD5BB4636ADB9B5706A67DCDE75573FD71BEF16D7", 16
);
-
+ // g =
+ // < , > is Tate-Lichtenbaum Pairing
private static final BigInteger g = new BigInteger(Hex.decode("66FC2A43 2B6EA392 148F1586 7D623068\n" +
" C6A87BD1 FB94C41E 27FABE65 8E015A87\n" +
" 371E9474 4C96FEDA 449AE956 3F8BC446\n" +
@@ -41,13 +51,6 @@ public class SAKKEPublicKeyParameters
" D682C033 A7942BCC E3720F20 B9B7B040\n" +
" 3C8CAE87 B7A0042A CDE0FAB3 6461EA46"));
- private static final BigInteger q = new BigInteger(
- "265EAEC7C2958FF69971846636B4195E905B0338672D20986FA6B8D62CF8068B" +
- "BD02AAC9F8BF03C6C8A1CC354C69672C39E46CE7FDF222864D5B49FD2999A9B4" +
- "389B1921CC9AD335144AB173595A07386DABFD2A0C614AA0A9F3CF14870F026A" +
- "A7E535ABD5A5C7C7FF38FA08E2615F6C203177C42B1EB3A1D99B601EBFAA17FB", 16
- );
-
private static final ECCurve.Fp curve = new ECCurve.Fp(
p, // Prime p
BigInteger.valueOf(-3).mod(p), // a = -3
@@ -56,18 +59,34 @@ public class SAKKEPublicKeyParameters
BigInteger.ONE // Cofactor = 1
);
+
private static final ECPoint P = curve.createPoint(Px, Py);
- private final ECPoint Z; // KMS Public Key: Z = [z]P
+ private final ECPoint Z;
+
+ private final BigInteger identifier; // User's identity
private static final int n = 128; // SSV bit length
- public SAKKEPublicKeyParameters(ECPoint Z)
+ private final Digest digest = new SHA256Digest();
+
+ public SAKKEPublicKeyParameters(BigInteger identifier, ECPoint Z)
{
super(false);
+ this.identifier = identifier;
this.Z = Z;
}
// Getters
+ public BigInteger getIdentifier()
+ {
+ return identifier;
+ }
+
+ public ECPoint getZ()
+ {
+ return Z;
+ }
+
public ECCurve getCurve()
{
return curve;
@@ -78,12 +97,7 @@ public ECPoint getP()
return P;
}
- public ECPoint getZ()
- {
- return Z;
- }
-
- public BigInteger getp()
+ public BigInteger getPrime()
{
return p;
}
@@ -97,4 +111,14 @@ public int getN()
{
return n;
}
+
+ public Digest getDigest()
+ {
+ return digest;
+ }
+
+ public BigInteger getG()
+ {
+ return g;
+ }
}
diff --git a/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java b/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
index 7a2b0d5b64..8dd350c673 100644
--- a/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
@@ -38,6 +38,20 @@ public String getName()
public void performTest()
throws Exception
{
+
+ final BigInteger Px = new BigInteger(
+ "53FC09EE332C29AD0A7990053ED9B52A2B1A2FD60AEC69C698B2F204B6FF7CBF" +
+ "B5EDB6C0F6CE2308AB10DB9030B09E1043D5F22CDB9DFA55718BD9E7406CE890" +
+ "9760AF765DD5BCCB337C86548B72F2E1A702C3397A60DE74A7C1514DBA66910D" +
+ "D5CFB4CC80728D87EE9163A5B63F73EC80EC46C4967E0979880DC8ABEAE63895", 16
+ );
+
+ final BigInteger Py = new BigInteger(
+ "0A8249063F6009F1F9F1F0533634A135D3E82016029906963D778D821E141178" +
+ "F5EA69F4654EC2B9E7F7F5E5F0DE55F66B598CCF9A140B2E416CFF0CA9E032B9" +
+ "70DAE117AD547C6CCAD696B5B7652FE0AC6F1E80164AA989492D979FC5A4D5F2" +
+ "13515AD7E9CB99A980BDAD5AD5BB4636ADB9B5706A67DCDE75573FD71BEF16D7", 16
+ );
BigInteger g = new BigInteger(Hex.decode("66FC2A43 2B6EA392 148F1586 7D623068" +
" C6A87BD1 FB94C41E 27FABE65 8E015A87" +
" 371E9474 4C96FEDA 449AE956 3F8BC446" +
@@ -127,14 +141,18 @@ public void performTest()
SecureRandom random = new FixedSecureRandom(new FixedSecureRandom.Source[]{new FixedSecureRandom.Data(ssv),
new FixedSecureRandom.Data(b)});
SAKKEKEMSGenerator generator = new SAKKEKEMSGenerator(random);
- SecretWithEncapsulation rlt = generator.generateEncapsulated(null);
+ SecretWithEncapsulation rlt = generator.generateEncapsulated(new SAKKEPublicKeyParameters(new BigInteger(b), curve.createPoint(Zx, Zy)));
+ ECPoint P = curve.createPoint(Px, Py);
+
+ BigInteger computed_g2 = SAKKEKEMExtractor.computePairing(P, P, p, q);
+ Assert.assertTrue(computed_g2.equals(g));
ECPoint K_bS = curve.createPoint(kbx, kby);
- SAKKEKEMExtractor extractor = new SAKKEKEMExtractor(new SAKKEPrivateKeyParameters(new BigInteger(b), K_bS,
- new SAKKEPublicKeyParameters(curve.createPoint(Zx, Zy))));
+
+ SAKKEKEMExtractor extractor = new SAKKEKEMExtractor(new SAKKEPrivateKeyParameters(z, K_bS,
+ new SAKKEPublicKeyParameters(new BigInteger(b), curve.createPoint(Zx, Zy))));
byte[] test = extractor.extractSecret(rlt.getEncapsulation());
Assert.assertTrue(Arrays.areEqual(test, ssv));
-
}
}
From 68c38165d2b0ced84a80fe4f87bbf28942847fcc Mon Sep 17 00:00:00 2001
From: gefeili
Date: Fri, 7 Feb 2025 14:10:33 +1030
Subject: [PATCH 174/890] Add javadoc and add random tests.
---
.../crypto/kems/SAKKEKEMExtractor.java | 133 +++++++++++-----
.../crypto/kems/SAKKEKEMSGenerator.java | 143 +++++++++++++-----
.../bouncycastle/crypto/kems/SAKKEUtils.java | 46 ------
.../params/SAKKEPrivateKeyParameters.java | 64 ++++++--
.../params/SAKKEPublicKeyParameters.java | 102 +++++++++++--
.../crypto/kems/test/SAKKEKEMSTest.java | 89 ++++++-----
6 files changed, 398 insertions(+), 179 deletions(-)
delete mode 100644 core/src/main/java/org/bouncycastle/crypto/kems/SAKKEUtils.java
diff --git a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java
index 418ec767dd..8e2307e153 100644
--- a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java
+++ b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java
@@ -2,6 +2,7 @@
import java.math.BigInteger;
+import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.EncapsulatedSecretExtractor;
import org.bouncycastle.crypto.params.SAKKEPrivateKeyParameters;
import org.bouncycastle.crypto.params.SAKKEPublicKeyParameters;
@@ -10,7 +11,22 @@
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
-
+/**
+ * Implements the receiver side of the SAKKE (Sakai-Kasahara Key Encryption) protocol
+ * as defined in RFC 6508. This class extracts the shared secret value (SSV) from
+ * encapsulated data using the receiver's private key.
+ *
+ * The extraction process follows these steps (RFC 6508, Section 6.2.2):
+ *
+ * - Parse encapsulated data into R_(b,S) and H
+ * - Compute pairing result w = <R_(b,S), K_(b,S)>
+ * - Recover SSV via SSV = H XOR HashToIntegerRange(w, 2^n)
+ * - Validate R_(b,S) by recomputing it with derived parameters
+ *
+ *
+ *
+ * @see Sakai-Kasahara Key Encryption (SAKKE)
+ */
public class SAKKEKEMExtractor
implements EncapsulatedSecretExtractor
{
@@ -22,65 +38,88 @@ public class SAKKEKEMExtractor
private final ECPoint K_bs;
private final int n; // Security parameter
private final BigInteger identifier;
-
+ private final Digest digest;
+
+ /**
+ * Initializes the extractor with cryptographic parameters from the receiver's private key.
+ *
+ * @param privateKey The receiver's private key containing public parameters
+ * (curve, prime, generator, etc.) and the Receiver Secret Key (RSK).
+ * Must not be {@code null}.
+ */
public SAKKEKEMExtractor(SAKKEPrivateKeyParameters privateKey)
{
SAKKEPublicKeyParameters publicKey = privateKey.getPublicParams();
this.curve = publicKey.getCurve();
this.q = publicKey.getQ();
- this.P = publicKey.getP();
+ this.P = publicKey.getPoint();
this.p = publicKey.getPrime();
this.Z_S = publicKey.getZ();
- this.K_bs = privateKey.getRSK();
- this.n = publicKey.getN();
this.identifier = publicKey.getIdentifier();
+ this.K_bs = P.multiply(this.identifier.add(privateKey.getMasterSecret()).modInverse(q)).normalize();
+ this.n = publicKey.getN();
+
+ this.digest = publicKey.getDigest();
}
+ /**
+ * Extracts the shared secret value (SSV) from encapsulated data as per RFC 6508.
+ *
+ * @param encapsulation The encapsulated data containing:
+ *
+ * - R_(b,S): Elliptic curve point (uncompressed format, 257 bytes)
+ * - H: Integer value (n/8 bytes)
+ *
+ * @return The extracted SSV as a byte array.
+ * @throws IllegalStateException If: Validation of R_(b,S) fails
+ */
@Override
public byte[] extractSecret(byte[] encapsulation)
{
- try
- {
- // Step 1: Parse Encapsulated Data (R_bS, H)
- ECPoint R_bS = curve.decodePoint(Arrays.copyOfRange(encapsulation, 0, 257));
- BigInteger H = new BigInteger(Arrays.copyOfRange(encapsulation, 257, 274));
-
- // Step 2: Compute w = using pairing
- BigInteger w = computePairing(R_bS, K_bs, p, q);
-
- // Step 3: Compute SSV = H XOR HashToIntegerRange(w, 2^n)
- BigInteger twoToN = BigInteger.ONE.shiftLeft(n);
- BigInteger mask = SAKKEUtils.hashToIntegerRange(w.toByteArray(), twoToN);
- BigInteger ssv = H.xor(mask);
-
- // Step 4: Compute r = HashToIntegerRange(SSV || b)
- BigInteger b = identifier;
- BigInteger r = SAKKEUtils.hashToIntegerRange(Arrays.concatenate(ssv.toByteArray(), b.toByteArray()), q);
-
- // Step 5: Validate R_bS
- ECPoint bP = P.multiply(b).normalize();
- ECPoint Test = bP.add(Z_S).multiply(r).normalize();
- if (!R_bS.equals(Test))
- {
- throw new IllegalStateException("Validation of R_bS failed");
- }
-
- return BigIntegers.asUnsignedByteArray(n / 8, ssv);
- }
- catch (Exception e)
+ // Step 1: Parse Encapsulated Data (R_bS, H)
+ ECPoint R_bS = curve.decodePoint(Arrays.copyOfRange(encapsulation, 0, 257));
+ BigInteger H = BigIntegers.fromUnsignedByteArray(encapsulation, 257, 16);
+
+ // Step 2: Compute w = using pairing
+ BigInteger w = computePairing(R_bS, K_bs, p, q);
+
+ // Step 3: Compute SSV = H XOR HashToIntegerRange(w, 2^n)
+ BigInteger twoToN = BigInteger.ONE.shiftLeft(n);
+ BigInteger mask = SAKKEKEMSGenerator.hashToIntegerRange(w.toByteArray(), twoToN, digest);
+ BigInteger ssv = H.xor(mask).mod(p);
+
+ // Step 4: Compute r = HashToIntegerRange(SSV || b)
+ BigInteger b = identifier;
+ BigInteger r = SAKKEKEMSGenerator.hashToIntegerRange(Arrays.concatenate(ssv.toByteArray(), b.toByteArray()), q, digest);
+
+ // Step 5: Validate R_bS
+ ECPoint bP = P.multiply(b).normalize();
+ ECPoint Test = bP.add(Z_S).multiply(r).normalize();
+ if (!R_bS.equals(Test))
{
- throw new IllegalStateException("SAKKE extraction failed: " + e.getMessage());
+ throw new IllegalStateException("Validation of R_bS failed");
}
+
+ return BigIntegers.asUnsignedByteArray(n / 8, ssv);
}
@Override
public int getEncapsulationLength()
{
- return 0;
+ return 273; //257 (length of ECPoint) + 16 (length of Hash)
}
-
- public static BigInteger computePairing(ECPoint R, ECPoint Q, BigInteger p, BigInteger q)
+ /**
+ * Computes the Tate-Lichtenbaum pairing <R, Q> for SAKKE validation.
+ * Follows the pairing algorithm described in RFC 6508, Section 3.2.
+ *
+ * @param R First pairing input (elliptic curve point)
+ * @param Q Second pairing input (elliptic curve point)
+ * @param p Prime field characteristic
+ * @param q Subgroup order
+ * @return Pairing result in PF_p[q], represented as a field element
+ */
+ static BigInteger computePairing(ECPoint R, ECPoint Q, BigInteger p, BigInteger q)
{
// v = (1,0) in F_p^2
BigInteger[] v = new BigInteger[]{BigInteger.ONE, BigInteger.ZERO};
@@ -133,6 +172,16 @@ public static BigInteger computePairing(ECPoint R, ECPoint Q, BigInteger p, BigI
return v[1].multiply(v[0].modInverse(p)).mod(p);
}
+ /**
+ * Performs multiplication in F_p^2 field.
+ *
+ * @param x_real Real component of first operand
+ * @param x_imag Imaginary component of first operand
+ * @param y_real Real component of second operand
+ * @param y_imag Imaginary component of second operand
+ * @param p Prime field characteristic
+ * @return Result of multiplication in F_p^2 as [real, imaginary] array
+ */
static BigInteger[] fp2Multiply(BigInteger x_real, BigInteger x_imag, BigInteger y_real, BigInteger y_imag, BigInteger p)
{
return new BigInteger[]{
@@ -141,6 +190,14 @@ static BigInteger[] fp2Multiply(BigInteger x_real, BigInteger x_imag, BigInteger
};
}
+ /**
+ * Computes squaring operation in F_p^2 field.
+ *
+ * @param currentX Real component of input
+ * @param currentY Imaginary component of input
+ * @param p Prime field characteristic
+ * @return Squared result in F_p^2 as [newX, newY] array
+ */
static BigInteger[] fp2PointSquare(BigInteger currentX, BigInteger currentY, BigInteger p)
{
BigInteger xPlusY = currentX.add(currentY).mod(p);
diff --git a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
index fe48251968..9bb956d4c1 100644
--- a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
+++ b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
@@ -1,5 +1,6 @@
package org.bouncycastle.crypto.kems;
+import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.EncapsulatedSecretGenerator;
import org.bouncycastle.crypto.SecretWithEncapsulation;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
@@ -12,19 +13,59 @@
import java.math.BigInteger;
import java.security.SecureRandom;
+/**
+ * This class implements the SAKKE (Sakai-Kasahara Key Encryption) Key Encapsulation Mechanism
+ * as defined in RFC 6508. It generates an encapsulated shared secret value (SSV) using
+ * Identity-Based Encryption (IBE) for secure transmission from a Sender to a Receiver.
+ *
+ * The algorithm follows these steps (as per RFC 6508, Section 6.2.1):
+ *
+ * - Generate a random SSV in the range [0, 2^n - 1].
+ * - Compute r = HashToIntegerRange(SSV || b, q).
+ * - Compute R_(b,S) = [r]([b]P + Z_S) on the elliptic curve.
+ * - Compute H = SSV XOR HashToIntegerRange(g^r, 2^n).
+ * - Encode the encapsulated data (R_(b,S), H).
+ *
+ *
+ *
+ * @see RFC 6508: Sakai-Kasahara Key Encryption (SAKKE)
+ */
public class SAKKEKEMSGenerator
implements EncapsulatedSecretGenerator
{
private final SecureRandom random;
+ /**
+ * Constructs a SAKKEKEMSGenerator with the specified source of randomness.
+ *
+ * @param random a {@link SecureRandom} instance for generating cryptographically secure random values.
+ * Must not be {@code null}.
+ */
public SAKKEKEMSGenerator(SecureRandom random)
{
this.random = random;
}
+ /**
+ * Generates an encapsulated shared secret value (SSV) using the recipient's public key parameters
+ * as specified in RFC 6508, Section 6.2.1.
+ *
+ * This method performs the following operations:
+ *
+ * - Derives cryptographic parameters from the recipient's public key.
+ * - Generates a random SSV and computes the encapsulation components (R_(b,S), H).
+ * - Encodes the encapsulated data as specified in RFC 6508, Section 4.
+ *
+ *
+ *
+ * @param recipientKey the recipient's public key parameters. Must be an instance of
+ * {@link SAKKEPublicKeyParameters}. Must not be {@code null}.
+ * @return a {@link SecretWithEncapsulation} containing the SSV and the encapsulated data.
+ */
@Override
public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recipientKey)
{
+ // Extract public parameters from the recipient's key
SAKKEPublicKeyParameters keyParameters = (SAKKEPublicKeyParameters)recipientKey;
ECPoint Z = keyParameters.getZ();
BigInteger b = keyParameters.getIdentifier();
@@ -33,54 +74,31 @@ public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recip
BigInteger g = keyParameters.getG();
int n = keyParameters.getN();
ECCurve curve = keyParameters.getCurve();
- ECPoint P = keyParameters.getP();
+ ECPoint P = keyParameters.getPoint();
+ Digest digest = keyParameters.getDigest();
// 1. Generate random SSV in range [0, 2^n - 1]
BigInteger ssv = new BigInteger(n, random);
-
// 2. Compute r = HashToIntegerRange(SSV || b, q)
-
- BigInteger r = SAKKEUtils.hashToIntegerRange(Arrays.concatenate(ssv.toByteArray(), b.toByteArray()), q);
+ BigInteger r = hashToIntegerRange(Arrays.concatenate(ssv.toByteArray(), b.toByteArray()), q, digest);
// 3. Compute R_(b,S) = [r]([b]P + Z_S)
ECPoint bP = P.multiply(b).normalize();
- ECPoint R_bS = bP.add(Z).multiply(r).normalize(); // [r]([b]P + Z_S)
+ ECPoint R_bS = bP.add(Z).multiply(r).normalize();
// 4. Compute H = SSV XOR HashToIntegerRange( g^r, 2^n )
- BigInteger[] v = fp2Exponentiate(p, BigInteger.ONE, g, r, curve);
- BigInteger g_r = v[1].multiply(v[0].modInverse(p)).mod(p);
-
- BigInteger mask = SAKKEUtils.hashToIntegerRange(g_r.toByteArray(), BigInteger.ONE.shiftLeft(n)); // 2^n
-
- BigInteger H = ssv.xor(mask);
- //System.out.println(new String(Hex.encode(H.toByteArray())));
- // 5. Encode encapsulated data (R_bS, H)
- byte[] encapsulated = Arrays.concatenate(R_bS.getEncoded(false), H.toByteArray());
-
- return new SecretWithEncapsulationImpl(
- BigIntegers.asUnsignedByteArray(n / 8, ssv), // Output SSV as key material
- encapsulated
- );
- }
-
-
- public static BigInteger[] fp2Exponentiate(
- BigInteger p,
- BigInteger pointX,
- BigInteger pointY,
- BigInteger n,
- ECCurve curve)
- {
- BigInteger[] result = new BigInteger[2];
+ BigInteger pointX = BigInteger.ONE;
+ BigInteger pointY = g;
+ BigInteger[] v = new BigInteger[2];
// Initialize result with the original point
- BigInteger currentX = pointX;
- BigInteger currentY = pointY;
+ BigInteger currentX = BigInteger.ONE;
+ BigInteger currentY = g;
ECPoint current = curve.createPoint(currentX, currentY);
- int numBits = n.bitLength();
+ int numBits = r.bitLength();
BigInteger[] rlt;
// Process bits from MSB-1 down to 0
for (int i = numBits - 2; i >= 0; i--)
@@ -91,7 +109,7 @@ public static BigInteger[] fp2Exponentiate(
currentX = rlt[0];
currentY = rlt[1];
// Multiply if bit is set
- if (n.testBit(i))
+ if (r.testBit(i))
{
rlt = SAKKEKEMExtractor.fp2Multiply(currentX, currentY, pointX, pointY, p);
@@ -100,8 +118,59 @@ public static BigInteger[] fp2Exponentiate(
}
}
- result[0] = currentX;
- result[1] = currentY;
- return result;
+ v[0] = currentX;
+ v[1] = currentY;
+ BigInteger g_r = v[1].multiply(v[0].modInverse(p)).mod(p);
+
+ BigInteger mask = hashToIntegerRange(g_r.toByteArray(), BigInteger.ONE.shiftLeft(n), digest); // 2^n
+
+ BigInteger H = ssv.xor(mask);
+ // 5. Encode encapsulated data (R_bS, H)
+// byte[] encapsulated = Arrays.concatenate(new byte[]{(byte)0x04},
+// BigIntegers.asUnsignedByteArray(n, R_bS.getXCoord().toBigInteger()),
+// BigIntegers.asUnsignedByteArray(n, R_bS.getYCoord().toBigInteger()),
+// BigIntegers.asUnsignedByteArray(16, H));
+ byte[] encapsulated = Arrays.concatenate(R_bS.getEncoded(false), BigIntegers.asUnsignedByteArray(16, H));
+
+ return new SecretWithEncapsulationImpl(
+ BigIntegers.asUnsignedByteArray(n / 8, ssv), // Output SSV as key material
+ encapsulated
+ );
+ }
+
+ static BigInteger hashToIntegerRange(byte[] input, BigInteger q, Digest digest)
+ {
+ // RFC 6508 Section 5.1: Hashing to an Integer Range
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ // Step 1: Compute A = hashfn(s)
+ digest.update(input, 0, input.length);
+ digest.doFinal(hash, 0);
+ byte[] A = hash.clone();
+
+ // Step 2: Initialize h_0 to all-zero bytes of hashlen size
+ byte[] h = new byte[digest.getDigestSize()];
+
+ // Step 3: Compute l = Ceiling(lg(n)/hashlen)
+ int l = q.bitLength() >> 8;
+
+ BigInteger v = BigInteger.ZERO;
+
+ // Step 4: Compute h_i and v_i
+ for (int i = 0; i <= l; i++)
+ {
+ // h_i = hashfn(h_{i-1})
+ digest.update(h, 0, h.length);
+ digest.doFinal(h, 0);
+ // v_i = hashfn(h_i || A)
+ digest.update(h, 0, h.length);
+ digest.update(A, 0, A.length);
+ byte[] v_i = new byte[digest.getDigestSize()];
+ digest.doFinal(v_i, 0);
+ // Append v_i to v'
+ v = v.shiftLeft(v_i.length * 8).add(new BigInteger(1, v_i));
+ }
+ // Step 6: v = v' mod n
+ return v.mod(q);
}
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEUtils.java b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEUtils.java
deleted file mode 100644
index 891f2ae878..0000000000
--- a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEUtils.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package org.bouncycastle.crypto.kems;
-
-import java.math.BigInteger;
-
-import org.bouncycastle.crypto.digests.SHA256Digest;
-
-public class SAKKEUtils
-{
-
- public static BigInteger hashToIntegerRange(byte[] input, BigInteger q)
- {
- // RFC 6508 Section 5.1: Hashing to an Integer Range
- SHA256Digest digest = new SHA256Digest();
- byte[] hash = new byte[digest.getDigestSize()];
-
- // Step 1: Compute A = hashfn(s)
- digest.update(input, 0, input.length);
- digest.doFinal(hash, 0);
- byte[] A = hash.clone();
-
- // Step 2: Initialize h_0 to all-zero bytes of hashlen size
- byte[] h = new byte[digest.getDigestSize()];
-
- // Step 3: Compute l = Ceiling(lg(n)/hashlen)
- int l = q.bitLength() >> 8;
-
- BigInteger v = BigInteger.ZERO;
-
- // Step 4: Compute h_i and v_i
- for (int i = 0; i <= l; i++)
- {
- // h_i = hashfn(h_{i-1})
- digest.update(h, 0, h.length);
- digest.doFinal(h, 0);
- // v_i = hashfn(h_i || A)
- digest.update(h, 0, h.length);
- digest.update(A, 0, A.length);
- byte[] v_i = new byte[digest.getDigestSize()];
- digest.doFinal(v_i, 0);
- // Append v_i to v'
- v = v.shiftLeft(v_i.length * 8).add(new BigInteger(1, v_i));
- }
- // Step 6: v = v' mod n
- return v.mod(q);
- }
-}
diff --git a/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPrivateKeyParameters.java
index c90a373cf0..d5a7539045 100644
--- a/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPrivateKeyParameters.java
+++ b/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPrivateKeyParameters.java
@@ -1,37 +1,81 @@
package org.bouncycastle.crypto.params;
import java.math.BigInteger;
+import java.security.SecureRandom;
-import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.util.BigIntegers;
+/**
+ * Represents a private key for the Sakai-Kasahara Key Encryption (SAKKE) scheme, as defined in RFC 6508.
+ *
+ * SAKKE is an identity-based public key encryption scheme designed for one-pass key establishment.
+ * It is used in MIKEY-SAKKE for secure communication key distribution.
+ *
+ * This class generates and manages a SAKKE private key, which consists of a randomly generated
+ * scalar {@code z}. The corresponding public key is computed as {@code Z = [z]P}, where {@code P}
+ * is a publicly known generator point on the elliptic curve.
+ *
+ * The private key is used to derive the master secret in the key exchange process.
+ *
+ * @see RFC 6508: Sakai-Kasahara Key Encryption (SAKKE)
+ */
public class SAKKEPrivateKeyParameters
extends AsymmetricKeyParameter
{
+ private static final BigInteger qMinOne = SAKKEPublicKeyParameters.q.subtract(BigInteger.ONE);
+ /** The associated public key parameters. */
private final SAKKEPublicKeyParameters publicParams;
+ /** The private key scalar (master secret). */
private final BigInteger z; // KMS Public Key: Z = [z]P
- private final ECPoint rsk;
- public SAKKEPrivateKeyParameters(BigInteger z, ECPoint rsk, SAKKEPublicKeyParameters publicParams)
+ /**
+ * Constructs a SAKKE private key with a given private value and associated public parameters.
+ *
+ * @param z The private key scalar.
+ * @param publicParams The associated public key parameters.
+ */
+ public SAKKEPrivateKeyParameters(BigInteger z, SAKKEPublicKeyParameters publicParams)
{
super(true);
this.z = z;
- this.rsk = rsk;
this.publicParams = publicParams;
}
+ /**
+ * Generates a random SAKKE private key and its corresponding public key.
+ *
+ * The private key scalar {@code z} is chosen randomly in the range [2, q-1],
+ * where {@code q} is the order of the subgroup. The public key is computed as
+ * {@code Z = [z]P}, where {@code P} is the public generator.
+ *
+ * @param random A cryptographic random number generator.
+ */
+ public SAKKEPrivateKeyParameters(SecureRandom random)
+ {
+ super(true);
+ this.z = BigIntegers.createRandomInRange(BigIntegers.TWO, qMinOne, random);
+ BigInteger identifier = BigIntegers.createRandomInRange(BigIntegers.TWO, qMinOne, random);
+ this.publicParams = new SAKKEPublicKeyParameters(identifier,
+ SAKKEPublicKeyParameters.P.multiply(z).normalize());
+ }
+
+ /**
+ * Retrieves the public key parameters associated with this private key.
+ *
+ * @return The corresponding SAKKE public key parameters.
+ */
public SAKKEPublicKeyParameters getPublicParams()
{
return publicParams;
}
-
+ /**
+ * Retrieves the private key scalar (master secret).
+ *
+ * @return The private key scalar {@code z}.
+ */
public BigInteger getMasterSecret()
{
return z;
}
-
- public ECPoint getRSK()
- {
- return rsk;
- }
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKeyParameters.java
index a062d766fc..2380efe143 100644
--- a/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKeyParameters.java
+++ b/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKeyParameters.java
@@ -8,18 +8,50 @@
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;
+/**
+ * Represents the public parameters for the SAKKE (Sakai-Kasahara Key Encryption) scheme
+ * as defined in RFC 6508. This class encapsulates the cryptographic domain parameters
+ * and public key components required for SAKKE operations.
+ *
+ * Contains the following public parameters (RFC 6508, Section 2.3):
+ *
+ * - Prime modulus {@code p} defining the field F_p
+ * - Subgroup order {@code q} (divides p+1)
+ * - Base point {@code P} on the elliptic curve E(F_p)
+ * - Pairing result {@code g =
}
+ * - KMS Public Key {@code Z_S = [z_S]P}
+ * - Security parameter {@code n} (SSV bit length)
+ * - User Identifier
+ * - Elliptic curve parameters (a = -3, b = 0)
+ *
+ *
+ *
+ * The predefined parameters in this implementation correspond to the 128-bit security
+ * level example from RFC 6509 Appendix A.
+ *
+ *
+ * @see RFC 6508: Sakai-Kasahara Key Encryption
+ * @see RFC 6509: MIKEY-SAKKE
+ */
public class SAKKEPublicKeyParameters
extends AsymmetricKeyParameter
{
- // Base point
- private static final BigInteger p = new BigInteger(
+ /**
+ * Prime modulus p defining the finite field F_p (RFC 6508, Section 2.1).
+ * Value from RFC 6509 Appendix A.
+ */
+ static final BigInteger p = new BigInteger(
"997ABB1F0A563FDA65C61198DAD0657A416C0CE19CB48261BE9AE358B3E01A2E" +
"F40AAB27E2FC0F1B228730D531A59CB0E791B39FF7C88A19356D27F4A666A6D0" +
"E26C6487326B4CD4512AC5CD65681CE1B6AFF4A831852A82A7CF3C521C3C09AA" +
"9F94D6AF56971F1FFCE3E82389857DB080C5DF10AC7ACE87666D807AFEA85FEB", 16
);
- private static final BigInteger q = new BigInteger(
+ /**
+ * Subgroup order q (divides p+1) (RFC 6508, Section 2.1).
+ * Value from RFC 6509 Appendix A.
+ */
+ static final BigInteger q = new BigInteger(
"265EAEC7C2958FF69971846636B4195E905B0338672D20986FA6B8D62CF8068B" +
"BD02AAC9F8BF03C6C8A1CC354C69672C39E46CE7FDF222864D5B49FD2999A9B4" +
"389B1921CC9AD335144AB173595A07386DABFD2A0C614AA0A9F3CF14870F026A" +
@@ -33,6 +65,7 @@ public class SAKKEPublicKeyParameters
"D5CFB4CC80728D87EE9163A5B63F73EC80EC46C4967E0979880DC8ABEAE63895", 16
);
+
private static final BigInteger Py = new BigInteger(
"0A8249063F6009F1F9F1F0533634A135D3E82016029906963D778D821E141178" +
"F5EA69F4654EC2B9E7F7F5E5F0DE55F66B598CCF9A140B2E416CFF0CA9E032B9" +
@@ -40,8 +73,10 @@ public class SAKKEPublicKeyParameters
"13515AD7E9CB99A980BDAD5AD5BB4636ADB9B5706A67DCDE75573FD71BEF16D7", 16
);
- // g =
- // < , > is Tate-Lichtenbaum Pairing
+ /**
+ * Pairing result g =
computed using the Tate-Lichtenbaum pairing
+ * (RFC 6508, Section 3.2). Value from RFC 6509 Appendix A.
+ */
private static final BigInteger g = new BigInteger(Hex.decode("66FC2A43 2B6EA392 148F1586 7D623068\n" +
" C6A87BD1 FB94C41E 27FABE65 8E015A87\n" +
" 371E9474 4C96FEDA 449AE956 3F8BC446\n" +
@@ -51,6 +86,10 @@ public class SAKKEPublicKeyParameters
" D682C033 A7942BCC E3720F20 B9B7B040\n" +
" 3C8CAE87 B7A0042A CDE0FAB3 6461EA46"));
+ /**
+ * The elliptic curve E: y² = x³ - 3x over F_p (RFC 6508, Section 3.1).
+ * Uses parameters from RFC 6509 Appendix A.
+ */
private static final ECCurve.Fp curve = new ECCurve.Fp(
p, // Prime p
BigInteger.valueOf(-3).mod(p), // a = -3
@@ -59,16 +98,27 @@ public class SAKKEPublicKeyParameters
BigInteger.ONE // Cofactor = 1
);
-
- private static final ECPoint P = curve.createPoint(Px, Py);
+ /**
+ * Base point P on the elliptic curve E(F_p) (RFC 6508, Section 3.1).
+ * Coordinates from RFC 6509 Appendix A.
+ */
+ static final ECPoint P = curve.createPoint(Px, Py);
+ /** KMS Public Key Z_S = [z_S]P (RFC 6508, Section 2.2) */
private final ECPoint Z;
-
+ /** User's Identifier (RFC 6508, Section 2.2) */
private final BigInteger identifier; // User's identity
-
+ /** Security parameter: SSV bit length (n = 128 bits) */
private static final int n = 128; // SSV bit length
-
+ /** Hash function (SHA-256) used in SAKKE operations */
private final Digest digest = new SHA256Digest();
-
+ /**
+ * Constructs SAKKE public key parameters with the specified identifier and KMS Public Key.
+ *
+ * @param identifier The user's identifier as defined in RFC 6508, Section 2.2.
+ * Must be a valid integer in [2, q-1].
+ * @param Z The KMS Public Key Z_S = [z_S]P (RFC 6508, Section 2.2).
+ * Must be a valid point on the curve E(F_p).
+ */
public SAKKEPublicKeyParameters(BigInteger identifier, ECPoint Z)
{
super(false);
@@ -76,47 +126,73 @@ public SAKKEPublicKeyParameters(BigInteger identifier, ECPoint Z)
this.Z = Z;
}
- // Getters
+ /**
+ * @return The user's identifier (RFC 6508, Section 2.2)
+ */
public BigInteger getIdentifier()
{
return identifier;
}
+ /**
+ * @return The KMS Public Key Z_S = [z_S]P (RFC 6508, Section 2.2)
+ */
public ECPoint getZ()
{
return Z;
}
+ /**
+ * @return The elliptic curve E(F_p) with parameters from RFC 6509 Appendix A
+ */
public ECCurve getCurve()
{
return curve;
}
- public ECPoint getP()
+ /**
+ * @return The base point P on E(F_p) (RFC 6508, Section 3.1)
+ */
+ public ECPoint getPoint()
{
return P;
}
+ /**
+ * @return Prime modulus p defining the field F_p (RFC 6508, Section 2.1)
+ */
public BigInteger getPrime()
{
return p;
}
+ /**
+ * @return Subgroup order q (divides p+1) (RFC 6508, Section 2.1)
+ */
public BigInteger getQ()
{
return q;
}
+ /**
+ * @return Security parameter n (SSV bit length = 128 bits)
+ */
public int getN()
{
return n;
}
+ /**
+ * @return The hash function (SHA-256) used in SAKKE operations
+ */
public Digest getDigest()
{
return digest;
}
+ /**
+ * @return The pairing result g =
(RFC 6508, Section 3.2)
+ */
public BigInteger getG()
{
return g;
diff --git a/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java b/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
index 8dd350c673..492c8d1e4c 100644
--- a/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
@@ -38,7 +38,15 @@ public String getName()
public void performTest()
throws Exception
{
+ testTestVector();
+ for (int i = 0; i < 100; ++i)
+ {
+ testRandom();
+ }
+ }
+ private void testTestVector()
+ {
final BigInteger Px = new BigInteger(
"53FC09EE332C29AD0A7990053ED9B52A2B1A2FD60AEC69C698B2F204B6FF7CBF" +
"B5EDB6C0F6CE2308AB10DB9030B09E1043D5F22CDB9DFA55718BD9E7406CE890" +
@@ -60,7 +68,7 @@ public void performTest()
" 55DF0460 B4A9FD74 B4F1A32B CAFA1FFA" +
" D682C033 A7942BCC E3720F20 B9B7B040" +
" 3C8CAE87 B7A0042A CDE0FAB3 6461EA46"));
- BigInteger z = new BigInteger(Hex.decode("AFF429D35F84B110D094803B3595A6E2998BC99F"));
+ BigInteger z = new BigInteger("AFF429D35F84B110D094803B3595A6E2998BC99F", 16);
BigInteger Zx = new BigInteger(Hex.decode("5958EF1B1679BF099B3A030DF255AA6A23C1D8F143D4D23F753E69BD27A832F38CB4AD53DDEF"
+ "4260B0FE8BB45C4C1FF510EFFE300367A37B61F701D914AEF09724825FA0707D61A6DFF4FBD7273566CDDE352A0B04B7C16A78309BE"
+ "640697DE747613A5FC195E8B9F328852A579DB8F99B1D0034479EA9C5595F47C4B2F54FF2"));
@@ -100,30 +108,30 @@ public void performTest()
"2884318A33D1A42ADF5E33CC5800280B" +
"28356497F87135BAB9612A1726042440" +
"9AC15FEE996B744C332151235DECB0F5", 16);
- BigInteger w = new BigInteger(Hex.decode("7D2A8438 E6291C64 9B6579EB 3B79EAE9" +
- "48B1DE9E 5F7D1F40 70A08F8D B6B3C515" +
- "6F2201AF FBB5CB9D 82AA3EC0 D0398B89" +
- "ABC78A13 A760C0BF 3F77E63D 0DF3F1A3" +
- "41A41B88 11DF197F D6CD0F00 3125606F" +
- "4F109F40 0F7292A1 0D255E3C 0EBCCB42" +
- "53FB182C 68F09CF6 CD9C4A53 DA6C74AD" +
- "007AF36B 8BCA979D 5895E282 F483FCD6"));
- BigInteger Rbx = new BigInteger(Hex.decode("44E8AD44 AB8592A6 A5A3DDCA 5CF896C7" +
- "18043606 A01D650D EF37A01F 37C228C3" +
- "32FC3173 54E2C274 D4DAF8AD 001054C7" +
- "6CE57971 C6F4486D 57230432 61C506EB" +
- "F5BE438F 53DE04F0 67C776E0 DD3B71A6" +
- "29013328 3725A532 F21AF145 126DC1D7" +
- "77ECC27B E50835BD 28098B8A 73D9F801" +
- "D893793A 41FF5C49 B87E79F2 BE4D56CE"));
- BigInteger Rby = new BigInteger(Hex.decode("557E134A D85BB1D4 B9CE4F8B E4B08A12" +
- "BABF55B1 D6F1D7A6 38019EA2 8E15AB1C" +
- "9F76375F DD1210D4 F4351B9A 009486B7" +
- "F3ED46C9 65DED2D8 0DADE4F3 8C6721D5" +
- "2C3AD103 A10EBD29 59248B4E F006836B" +
- "F097448E 6107C9ED EE9FB704 823DF199" +
- "F832C905 AE45F8A2 47A072D8 EF729EAB" +
- "C5E27574 B07739B3 4BE74A53 2F747B86"));
+// BigInteger w = new BigInteger(Hex.decode("7D2A8438 E6291C64 9B6579EB 3B79EAE9" +
+// "48B1DE9E 5F7D1F40 70A08F8D B6B3C515" +
+// "6F2201AF FBB5CB9D 82AA3EC0 D0398B89" +
+// "ABC78A13 A760C0BF 3F77E63D 0DF3F1A3" +
+// "41A41B88 11DF197F D6CD0F00 3125606F" +
+// "4F109F40 0F7292A1 0D255E3C 0EBCCB42" +
+// "53FB182C 68F09CF6 CD9C4A53 DA6C74AD" +
+// "007AF36B 8BCA979D 5895E282 F483FCD6"));
+// BigInteger Rbx = new BigInteger(Hex.decode("44E8AD44 AB8592A6 A5A3DDCA 5CF896C7" +
+// "18043606 A01D650D EF37A01F 37C228C3" +
+// "32FC3173 54E2C274 D4DAF8AD 001054C7" +
+// "6CE57971 C6F4486D 57230432 61C506EB" +
+// "F5BE438F 53DE04F0 67C776E0 DD3B71A6" +
+// "29013328 3725A532 F21AF145 126DC1D7" +
+// "77ECC27B E50835BD 28098B8A 73D9F801" +
+// "D893793A 41FF5C49 B87E79F2 BE4D56CE"));
+// BigInteger Rby = new BigInteger(Hex.decode("557E134A D85BB1D4 B9CE4F8B E4B08A12" +
+// "BABF55B1 D6F1D7A6 38019EA2 8E15AB1C" +
+// "9F76375F DD1210D4 F4351B9A 009486B7" +
+// "F3ED46C9 65DED2D8 0DADE4F3 8C6721D5" +
+// "2C3AD103 A10EBD29 59248B4E F006836B" +
+// "F097448E 6107C9ED EE9FB704 823DF199" +
+// "F832C905 AE45F8A2 47A072D8 EF729EAB" +
+// "C5E27574 B07739B3 4BE74A53 2F747B86"));
BigInteger p = new BigInteger(
"997ABB1F0A563FDA65C61198DAD0657A416C0CE19CB48261BE9AE358B3E01A2E" +
"F40AAB27E2FC0F1B228730D531A59CB0E791B39FF7C88A19356D27F4A666A6D0" +
@@ -137,21 +145,32 @@ public void performTest()
g,// Order of the subgroup (from RFC 6509)
BigInteger.ONE // Cofactor = 1
);
+ ECPoint P = curve.createPoint(Px, Py);
- SecureRandom random = new FixedSecureRandom(new FixedSecureRandom.Source[]{new FixedSecureRandom.Data(ssv),
- new FixedSecureRandom.Data(b)});
- SAKKEKEMSGenerator generator = new SAKKEKEMSGenerator(random);
- SecretWithEncapsulation rlt = generator.generateEncapsulated(new SAKKEPublicKeyParameters(new BigInteger(b), curve.createPoint(Zx, Zy)));
+ ECPoint computed_Z = P.multiply(z).normalize();
+ Assert.assertTrue(computed_Z.equals(curve.createPoint(Zx, Zy)));
- ECPoint P = curve.createPoint(Px, Py);
+ SecureRandom random = new FixedSecureRandom(new FixedSecureRandom.Source[]{new FixedSecureRandom.Data(ssv)});
+ SAKKEPublicKeyParameters b_publicKey = new SAKKEPublicKeyParameters(new BigInteger(b), curve.createPoint(Zx, Zy));
+ SAKKEKEMSGenerator generator = new SAKKEKEMSGenerator(random);
+ SecretWithEncapsulation rlt = generator.generateEncapsulated(b_publicKey);
- BigInteger computed_g2 = SAKKEKEMExtractor.computePairing(P, P, p, q);
- Assert.assertTrue(computed_g2.equals(g));
- ECPoint K_bS = curve.createPoint(kbx, kby);
+ SAKKEKEMExtractor extractor = new SAKKEKEMExtractor(new SAKKEPrivateKeyParameters(z, b_publicKey));
+ byte[] test = extractor.extractSecret(rlt.getEncapsulation());
+ Assert.assertTrue(Arrays.areEqual(test, ssv));
+ }
- SAKKEKEMExtractor extractor = new SAKKEKEMExtractor(new SAKKEPrivateKeyParameters(z, K_bS,
- new SAKKEPublicKeyParameters(new BigInteger(b), curve.createPoint(Zx, Zy))));
+ private void testRandom()
+ {
+ SecureRandom random = new SecureRandom();
+ byte[] ssv = new byte[16];
+ random.nextBytes(ssv);
+ SAKKEPrivateKeyParameters b_priv = new SAKKEPrivateKeyParameters(random);
+ SAKKEPublicKeyParameters b_pub = b_priv.getPublicParams();
+ SAKKEKEMSGenerator generator = new SAKKEKEMSGenerator(new FixedSecureRandom(new FixedSecureRandom.Source[]{new FixedSecureRandom.Data(ssv)}));
+ SecretWithEncapsulation rlt = generator.generateEncapsulated(b_pub);
+ SAKKEKEMExtractor extractor = new SAKKEKEMExtractor(b_priv);
byte[] test = extractor.extractSecret(rlt.getEncapsulation());
Assert.assertTrue(Arrays.areEqual(test, ssv));
}
From 3b6cab061dd1ff1ea8c698835c31283b7696f4b0 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Fri, 7 Feb 2025 14:42:34 +1030
Subject: [PATCH 175/890] Add key pair check in SAKKEPrivateKeyParameters.
---
.../crypto/params/SAKKEPrivateKeyParameters.java | 16 +++++++++++++---
.../crypto/kems/test/SAKKEKEMSTest.java | 2 +-
2 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPrivateKeyParameters.java
index d5a7539045..9e3be92c3f 100644
--- a/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPrivateKeyParameters.java
+++ b/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPrivateKeyParameters.java
@@ -3,6 +3,7 @@
import java.math.BigInteger;
import java.security.SecureRandom;
+import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.BigIntegers;
/**
@@ -23,15 +24,19 @@ public class SAKKEPrivateKeyParameters
extends AsymmetricKeyParameter
{
private static final BigInteger qMinOne = SAKKEPublicKeyParameters.q.subtract(BigInteger.ONE);
- /** The associated public key parameters. */
+ /**
+ * The associated public key parameters.
+ */
private final SAKKEPublicKeyParameters publicParams;
- /** The private key scalar (master secret). */
+ /**
+ * The private key scalar (master secret).
+ */
private final BigInteger z; // KMS Public Key: Z = [z]P
/**
* Constructs a SAKKE private key with a given private value and associated public parameters.
*
- * @param z The private key scalar.
+ * @param z The private key scalar.
* @param publicParams The associated public key parameters.
*/
public SAKKEPrivateKeyParameters(BigInteger z, SAKKEPublicKeyParameters publicParams)
@@ -39,6 +44,11 @@ public SAKKEPrivateKeyParameters(BigInteger z, SAKKEPublicKeyParameters publicPa
super(true);
this.z = z;
this.publicParams = publicParams;
+ ECPoint computed_Z = publicParams.getPoint().multiply(z).normalize();
+ if (!computed_Z.equals(publicParams.getZ()))
+ {
+ throw new IllegalStateException("public key and private key of SAKKE do not match");
+ }
}
/**
diff --git a/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java b/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
index 492c8d1e4c..0ef2797037 100644
--- a/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
@@ -39,7 +39,7 @@ public void performTest()
throws Exception
{
testTestVector();
- for (int i = 0; i < 100; ++i)
+ for (int i = 0; i < 1; ++i)
{
testRandom();
}
From b05a7b508d22919948ba60f0463b8a6729de62ba Mon Sep 17 00:00:00 2001
From: gefeili
Date: Tue, 18 Feb 2025 19:14:04 +1030
Subject: [PATCH 176/890] Add ECCSI key generator process
---
.../generators/ECCSIKeyPairGenerator.java | 78 +++++++++++++
.../params/ECCSIKeyGenerationParameters.java | 60 ++++++++++
.../params/ECCSIPrivateKeyParameters.java | 14 +++
.../params/ECCSIPublicKeyParameters.java | 14 +++
.../crypto/signers/ECCSISigner.java | 108 ++++++++++++++++++
5 files changed, 274 insertions(+)
create mode 100644 core/src/main/java/org/bouncycastle/crypto/generators/ECCSIKeyPairGenerator.java
create mode 100644 core/src/main/java/org/bouncycastle/crypto/params/ECCSIKeyGenerationParameters.java
create mode 100644 core/src/main/java/org/bouncycastle/crypto/params/ECCSIPrivateKeyParameters.java
create mode 100644 core/src/main/java/org/bouncycastle/crypto/params/ECCSIPublicKeyParameters.java
create mode 100644 core/src/main/java/org/bouncycastle/crypto/signers/ECCSISigner.java
diff --git a/core/src/main/java/org/bouncycastle/crypto/generators/ECCSIKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/crypto/generators/ECCSIKeyPairGenerator.java
new file mode 100644
index 0000000000..fac222e103
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/crypto/generators/ECCSIKeyPairGenerator.java
@@ -0,0 +1,78 @@
+package org.bouncycastle.crypto.generators;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bouncycastle.crypto.CryptoServicePurpose;
+import org.bouncycastle.crypto.CryptoServicesRegistrar;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.KeyGenerationParameters;
+import org.bouncycastle.crypto.constraints.DefaultServiceProperties;
+import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.ec.CustomNamedCurves;
+import org.bouncycastle.crypto.params.ECCSIKeyGenerationParameters;
+import org.bouncycastle.crypto.params.ECCSIPrivateKeyParameters;
+import org.bouncycastle.crypto.params.ECCSIPublicKeyParameters;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+
+public class ECCSIKeyPairGenerator
+ implements AsymmetricCipherKeyPairGenerator
+{
+ // Initialize NIST P-256 curve
+ private static final X9ECParameters params = CustomNamedCurves.getByName("secP256r1");
+ private static final ECCurve curve = params.getCurve();
+
+ private static final BigInteger q = ((ECCurve.Fp)curve).getQ();
+
+ //BigInteger p = ((ECCurve.Fp)curve).getOrder();
+
+ // The subgroup order is available as:
+ //BigInteger n = params.getN();
+
+ // And the base point (generator) is:
+ private static final ECPoint G = params.getG();
+ //int N = 32; // 256 bits
+
+ private ECCSIKeyGenerationParameters parameters;
+
+ @Override
+ public void init(KeyGenerationParameters parameters)
+ {
+ this.parameters = (ECCSIKeyGenerationParameters)parameters;
+
+ CryptoServicesRegistrar.checkConstraints(new DefaultServiceProperties("ECCSI", 256, null, CryptoServicePurpose.KEYGEN));
+ }
+
+ @Override
+ public AsymmetricCipherKeyPair generateKeyPair()
+ {
+ SecureRandom random = parameters.getRandom();
+ byte[] id = parameters.getId();
+ ECPoint kpak = parameters.getKPAK();
+ // 1) Choose v, a random (ephemeral) non-zero element of F_q;
+ BigInteger v = new BigInteger(256, random).mod(q);
+ // 2) Compute PVT = [v]G
+ ECPoint pvt = G.multiply(v).normalize();
+
+ // 3) Compute a hash value HS = hash( G || KPAK || ID || PVT ), an N-octet integer;
+ Digest digest = new SHA256Digest();
+ byte[] tmp = G.getEncoded(false);
+ digest.update(tmp, 0, tmp.length);
+ tmp = kpak.getEncoded(false);
+ digest.update(tmp, 0, tmp.length);
+ digest.update(id, 0, id.length);
+ tmp = pvt.getEncoded(false);
+ digest.update(tmp, 0, tmp.length);
+ tmp = new byte[digest.getDigestSize()];
+ digest.doFinal(tmp, 0);
+ BigInteger HS = new BigInteger(1, tmp).mod(q);
+
+ // 4) Compute SSK = ( KSAK + HS * v ) modulo q;
+ BigInteger ssk = parameters.computeSSK(HS.multiply(v));
+ return new AsymmetricCipherKeyPair(new ECCSIPublicKeyParameters(pvt), new ECCSIPrivateKeyParameters(ssk));
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/crypto/params/ECCSIKeyGenerationParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIKeyGenerationParameters.java
new file mode 100644
index 0000000000..f21a8df432
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIKeyGenerationParameters.java
@@ -0,0 +1,60 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.crypto.KeyGenerationParameters;
+import org.bouncycastle.crypto.ec.CustomNamedCurves;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.util.Arrays;
+
+public class ECCSIKeyGenerationParameters
+ extends KeyGenerationParameters
+{
+ private static final X9ECParameters params = CustomNamedCurves.getByName("secP256r1");
+ private static final ECCurve curve = params.getCurve();
+
+ private static final BigInteger q = ((ECCurve.Fp)curve).getQ();
+
+ //BigInteger p = ((ECCurve.Fp)curve).getOrder();
+
+ // The subgroup order is available as:
+ //BigInteger n = params.getN();
+
+ // And the base point (generator) is:
+ private static final ECPoint G = params.getG();
+ private final byte[] id;
+ private final BigInteger ksak;
+ private final ECPoint kpak;
+
+ /**
+ * initialise the generator with a source of randomness
+ * and a strength (in bits).
+ *
+ * @param random the random byte source.
+ */
+ public ECCSIKeyGenerationParameters(SecureRandom random, byte[] id)
+ {
+ super(random, 256);
+ this.id = Arrays.clone(id);
+ this.ksak = new BigInteger(256, random).mod(q);
+ this.kpak = G.multiply(ksak).normalize();
+ }
+
+ public byte[] getId()
+ {
+ return id;
+ }
+
+ public ECPoint getKPAK()
+ {
+ return kpak;
+ }
+
+ public BigInteger computeSSK(BigInteger hs_v)
+ {
+ return ksak.add(hs_v).mod(q);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPrivateKeyParameters.java
new file mode 100644
index 0000000000..e98a947257
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPrivateKeyParameters.java
@@ -0,0 +1,14 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+public class ECCSIPrivateKeyParameters
+ extends AsymmetricKeyParameter
+{
+ private final BigInteger ssk;
+ public ECCSIPrivateKeyParameters(BigInteger ssk)
+ {
+ super(true);
+ this.ssk = ssk;
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPublicKeyParameters.java
new file mode 100644
index 0000000000..aa41c352f0
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPublicKeyParameters.java
@@ -0,0 +1,14 @@
+package org.bouncycastle.crypto.params;
+
+import org.bouncycastle.math.ec.ECPoint;
+
+public class ECCSIPublicKeyParameters
+ extends AsymmetricKeyParameter
+{
+ private final ECPoint pvt;
+ public ECCSIPublicKeyParameters(ECPoint pvt)
+ {
+ super(false);
+ this.pvt = pvt;
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/crypto/signers/ECCSISigner.java b/core/src/main/java/org/bouncycastle/crypto/signers/ECCSISigner.java
new file mode 100644
index 0000000000..b5dd0c2d1b
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/crypto/signers/ECCSISigner.java
@@ -0,0 +1,108 @@
+package org.bouncycastle.crypto.signers;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.CryptoException;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.Signer;
+import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.ec.CustomNamedCurves;
+import org.bouncycastle.crypto.params.ECCSIPrivateKeyParameters;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.util.BigIntegers;
+
+public class ECCSISigner
+ implements Signer
+{
+ private static final X9ECParameters params = CustomNamedCurves.getByName("secP256r1");
+ private static final ECCurve curve = params.getCurve();
+
+ private static final BigInteger q = ((ECCurve.Fp)curve).getQ();
+
+ //BigInteger p = ((ECCurve.Fp)curve).getOrder();
+
+ // The subgroup order is available as:
+ //BigInteger n = params.getN();
+
+ // And the base point (generator) is:
+ private static final ECPoint G = params.getG();
+ private final Digest digest = new SHA256Digest();
+ BigInteger j;
+ ECPoint J;
+ BigInteger r;
+
+ public ECCSISigner()
+ {
+
+ }
+
+ @Override
+ public void init(boolean forSigning, CipherParameters param)
+ {
+ SecureRandom random = null;
+ if (param instanceof ParametersWithRandom)
+ {
+ random = ((ParametersWithRandom)param).getRandom();
+ param = ((ParametersWithRandom)param).getParameters();
+ }
+
+ if (forSigning)
+ {
+ ECCSIPrivateKeyParameters parameters = (ECCSIPrivateKeyParameters)param;
+
+ j = new BigInteger(256, random).mod(q);
+ J = G.multiply(j).normalize();
+ r = J.getAffineXCoord().toBigInteger();
+ byte[] rBytes = BigIntegers.asUnsignedByteArray(256, r);
+// BigInteger kpak = parameters
+ byte[] tmp = G.getEncoded(false);
+ digest.update(tmp, 0, tmp.length);
+// tmp = kpak.getEncoded(false);
+// digest.update(tmp, 0, tmp.length);
+// digest.update(id, 0, id.length);
+// tmp = pvt.getEncoded(false);
+// digest.update(tmp, 0, tmp.length);
+ tmp = new byte[digest.getDigestSize()];
+ digest.doFinal(tmp, 0);
+ BigInteger HS = new BigInteger(1, tmp).mod(q);
+ }
+
+ }
+
+ @Override
+ public void update(byte b)
+ {
+
+ }
+
+ @Override
+ public void update(byte[] in, int off, int len)
+ {
+
+ }
+
+ @Override
+ public byte[] generateSignature()
+ throws CryptoException, DataLengthException
+ {
+ return new byte[0];
+ }
+
+ @Override
+ public boolean verifySignature(byte[] signature)
+ {
+ return false;
+ }
+
+ @Override
+ public void reset()
+ {
+
+ }
+}
From 9cb941fbff8c2c3e99a296f0c469d1b3289678ae Mon Sep 17 00:00:00 2001
From: gefeili
Date: Wed, 19 Feb 2025 17:00:58 +1030
Subject: [PATCH 177/890] Pass the test vector of ECCSISigner
---
.../generators/ECCSIKeyPairGenerator.java | 13 +-
.../params/ECCSIKeyGenerationParameters.java | 19 +--
.../params/ECCSIPrivateKeyParameters.java | 15 +-
.../params/ECCSIPublicKeyParameters.java | 6 +
.../params/SAKKEPublicKeyParameters.java | 2 +-
.../crypto/signers/ECCSISigner.java | 152 ++++++++++++++----
.../crypto/test/ECCSISignerTest.java | 72 +++++++++
.../crypto/test/RegressionTest.java | 1 -
.../crypto/{kems => }/test/SAKKEKEMSTest.java | 4 +-
9 files changed, 223 insertions(+), 61 deletions(-)
create mode 100644 core/src/test/java/org/bouncycastle/crypto/test/ECCSISignerTest.java
rename core/src/test/java/org/bouncycastle/crypto/{kems => }/test/SAKKEKEMSTest.java (99%)
diff --git a/core/src/main/java/org/bouncycastle/crypto/generators/ECCSIKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/crypto/generators/ECCSIKeyPairGenerator.java
index fac222e103..25cf523d64 100644
--- a/core/src/main/java/org/bouncycastle/crypto/generators/ECCSIKeyPairGenerator.java
+++ b/core/src/main/java/org/bouncycastle/crypto/generators/ECCSIKeyPairGenerator.java
@@ -16,7 +16,6 @@
import org.bouncycastle.crypto.params.ECCSIKeyGenerationParameters;
import org.bouncycastle.crypto.params.ECCSIPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECCSIPublicKeyParameters;
-import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
public class ECCSIKeyPairGenerator
@@ -24,14 +23,7 @@ public class ECCSIKeyPairGenerator
{
// Initialize NIST P-256 curve
private static final X9ECParameters params = CustomNamedCurves.getByName("secP256r1");
- private static final ECCurve curve = params.getCurve();
-
- private static final BigInteger q = ((ECCurve.Fp)curve).getQ();
-
- //BigInteger p = ((ECCurve.Fp)curve).getOrder();
-
- // The subgroup order is available as:
- //BigInteger n = params.getN();
+ private static final BigInteger q = params.getCurve().getOrder();
// And the base point (generator) is:
private static final ECPoint G = params.getG();
@@ -73,6 +65,7 @@ public AsymmetricCipherKeyPair generateKeyPair()
// 4) Compute SSK = ( KSAK + HS * v ) modulo q;
BigInteger ssk = parameters.computeSSK(HS.multiply(v));
- return new AsymmetricCipherKeyPair(new ECCSIPublicKeyParameters(pvt), new ECCSIPrivateKeyParameters(ssk));
+ ECCSIPublicKeyParameters pub = new ECCSIPublicKeyParameters(pvt);
+ return new AsymmetricCipherKeyPair(new ECCSIPublicKeyParameters(pvt), new ECCSIPrivateKeyParameters(ssk, pub));
}
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/params/ECCSIKeyGenerationParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIKeyGenerationParameters.java
index f21a8df432..0e773b17ec 100644
--- a/core/src/main/java/org/bouncycastle/crypto/params/ECCSIKeyGenerationParameters.java
+++ b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIKeyGenerationParameters.java
@@ -6,25 +6,22 @@
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.KeyGenerationParameters;
import org.bouncycastle.crypto.ec.CustomNamedCurves;
-import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.Arrays;
public class ECCSIKeyGenerationParameters
extends KeyGenerationParameters
{
- private static final X9ECParameters params = CustomNamedCurves.getByName("secP256r1");
- private static final ECCurve curve = params.getCurve();
+ private static final BigInteger q;
+ private static final ECPoint G;
- private static final BigInteger q = ((ECCurve.Fp)curve).getQ();
-
- //BigInteger p = ((ECCurve.Fp)curve).getOrder();
-
- // The subgroup order is available as:
- //BigInteger n = params.getN();
+ static
+ {
+ X9ECParameters params = CustomNamedCurves.getByName("secP256r1");
+ q = params.getCurve().getOrder();
+ G = params.getG();
+ }
- // And the base point (generator) is:
- private static final ECPoint G = params.getG();
private final byte[] id;
private final BigInteger ksak;
private final ECPoint kpak;
diff --git a/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPrivateKeyParameters.java
index e98a947257..17ee88614a 100644
--- a/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPrivateKeyParameters.java
+++ b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPrivateKeyParameters.java
@@ -6,9 +6,22 @@ public class ECCSIPrivateKeyParameters
extends AsymmetricKeyParameter
{
private final BigInteger ssk;
- public ECCSIPrivateKeyParameters(BigInteger ssk)
+ private final ECCSIPublicKeyParameters pub;
+
+ public ECCSIPrivateKeyParameters(BigInteger ssk, ECCSIPublicKeyParameters pub)
{
super(true);
this.ssk = ssk;
+ this.pub = pub;
+ }
+
+ public ECCSIPublicKeyParameters getPublicKeyParameters()
+ {
+ return pub;
+ }
+
+ public BigInteger getSSK()
+ {
+ return ssk;
}
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPublicKeyParameters.java
index aa41c352f0..19bfc43b8f 100644
--- a/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPublicKeyParameters.java
+++ b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPublicKeyParameters.java
@@ -6,9 +6,15 @@ public class ECCSIPublicKeyParameters
extends AsymmetricKeyParameter
{
private final ECPoint pvt;
+
public ECCSIPublicKeyParameters(ECPoint pvt)
{
super(false);
this.pvt = pvt;
}
+
+ public final ECPoint getPVT()
+ {
+ return pvt;
+ }
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKeyParameters.java
index 2380efe143..5dc57b95d1 100644
--- a/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKeyParameters.java
+++ b/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKeyParameters.java
@@ -77,7 +77,7 @@ public class SAKKEPublicKeyParameters
* Pairing result g = computed using the Tate-Lichtenbaum pairing
* (RFC 6508, Section 3.2). Value from RFC 6509 Appendix A.
*/
- private static final BigInteger g = new BigInteger(Hex.decode("66FC2A43 2B6EA392 148F1586 7D623068\n" +
+ private static final BigInteger g = new BigInteger(1, Hex.decode("66FC2A43 2B6EA392 148F1586 7D623068\n" +
" C6A87BD1 FB94C41E 27FABE65 8E015A87\n" +
" 371E9474 4C96FEDA 449AE956 3F8BC446\n" +
" CBFDA85D 5D00EF57 7072DA8F 541721BE\n" +
diff --git a/core/src/main/java/org/bouncycastle/crypto/signers/ECCSISigner.java b/core/src/main/java/org/bouncycastle/crypto/signers/ECCSISigner.java
index b5dd0c2d1b..550f6e9996 100644
--- a/core/src/main/java/org/bouncycastle/crypto/signers/ECCSISigner.java
+++ b/core/src/main/java/org/bouncycastle/crypto/signers/ECCSISigner.java
@@ -1,5 +1,6 @@
package org.bouncycastle.crypto.signers;
+import java.io.ByteArrayOutputStream;
import java.math.BigInteger;
import java.security.SecureRandom;
@@ -12,92 +13,173 @@
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.ec.CustomNamedCurves;
import org.bouncycastle.crypto.params.ECCSIPrivateKeyParameters;
+import org.bouncycastle.crypto.params.ECCSIPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
-import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
public class ECCSISigner
implements Signer
{
- private static final X9ECParameters params = CustomNamedCurves.getByName("secP256r1");
- private static final ECCurve curve = params.getCurve();
+ private static final BigInteger q;
+ private static final ECPoint G;
- private static final BigInteger q = ((ECCurve.Fp)curve).getQ();
-
- //BigInteger p = ((ECCurve.Fp)curve).getOrder();
-
- // The subgroup order is available as:
- //BigInteger n = params.getN();
+ static
+ {
+ X9ECParameters params = CustomNamedCurves.getByName("secP256r1");
+ q = params.getCurve().getOrder();
+ G = params.getG();
+ }
- // And the base point (generator) is:
- private static final ECPoint G = params.getG();
private final Digest digest = new SHA256Digest();
- BigInteger j;
- ECPoint J;
- BigInteger r;
-
- public ECCSISigner()
+ private BigInteger j;
+ private BigInteger r;
+ private ECPoint Y;
+ private final ECPoint kpak;
+ private final byte[] id;
+ private CipherParameters param;
+ private ByteArrayOutputStream stream;
+ private boolean forSigning;
+
+ public ECCSISigner(ECPoint kpak, byte[] id)
{
-
+ this.kpak = kpak;
+ this.id = id;
}
@Override
public void init(boolean forSigning, CipherParameters param)
{
+ this.forSigning = forSigning;
+ this.param = param;
SecureRandom random = null;
if (param instanceof ParametersWithRandom)
{
random = ((ParametersWithRandom)param).getRandom();
param = ((ParametersWithRandom)param).getParameters();
}
-
+ ECPoint kpak_computed = null;
+ ECPoint pvt;
if (forSigning)
{
ECCSIPrivateKeyParameters parameters = (ECCSIPrivateKeyParameters)param;
j = new BigInteger(256, random).mod(q);
- J = G.multiply(j).normalize();
+ ECPoint J = G.multiply(j).normalize();
r = J.getAffineXCoord().toBigInteger();
- byte[] rBytes = BigIntegers.asUnsignedByteArray(256, r);
-// BigInteger kpak = parameters
- byte[] tmp = G.getEncoded(false);
- digest.update(tmp, 0, tmp.length);
-// tmp = kpak.getEncoded(false);
-// digest.update(tmp, 0, tmp.length);
-// digest.update(id, 0, id.length);
-// tmp = pvt.getEncoded(false);
-// digest.update(tmp, 0, tmp.length);
- tmp = new byte[digest.getDigestSize()];
- digest.doFinal(tmp, 0);
- BigInteger HS = new BigInteger(1, tmp).mod(q);
+ pvt = parameters.getPublicKeyParameters().getPVT();
+ kpak_computed = G.multiply(parameters.getSSK());
+ }
+ else
+ {
+ ECCSIPublicKeyParameters parameters = (ECCSIPublicKeyParameters)param;
+ pvt = parameters.getPVT();
+ stream = new ByteArrayOutputStream();
}
+ // compute HS
+ byte[] tmp = G.getEncoded(false);
+ digest.update(tmp, 0, tmp.length);
+ tmp = kpak.getEncoded(false);
+ digest.update(tmp, 0, tmp.length);
+ digest.update(id, 0, id.length);
+ tmp = pvt.getEncoded(false);
+ digest.update(tmp, 0, tmp.length);
+ tmp = new byte[digest.getDigestSize()];
+ digest.doFinal(tmp, 0);
+ BigInteger HS = new BigInteger(1, tmp).mod(q);
+
+ //HE = hash( HS || r || M );
+ digest.update(tmp, 0, tmp.length);
+ if (forSigning)
+ {
+ kpak_computed = kpak_computed.subtract(pvt.multiply(HS)).normalize();
+ if (!kpak_computed.equals(kpak))
+ {
+ throw new IllegalArgumentException("Invalid KPAK");
+ }
+ byte[] rBytes = BigIntegers.asUnsignedByteArray(32, r);
+ digest.update(rBytes, 0, rBytes.length);
+ }
+ else
+ {
+ // Compute Y = HS*PVT + KPAK
+ Y = pvt.multiply(HS).add(kpak).normalize();
+ }
}
@Override
public void update(byte b)
{
-
+ if (forSigning)
+ {
+ digest.update(b);
+ }
+ else
+ {
+ stream.write(b);
+ }
}
@Override
public void update(byte[] in, int off, int len)
{
-
+ if (forSigning)
+ {
+ digest.update(in, off, len);
+ }
+ else
+ {
+ stream.write(in, off, len);
+ }
}
@Override
public byte[] generateSignature()
throws CryptoException, DataLengthException
{
- return new byte[0];
+ byte[] heBytes = new byte[digest.getDigestSize()];
+ digest.doFinal(heBytes, 0);
+
+ //Compute s' = ( (( HE + r * SSK )^-1) * j ) modulo q
+ ECCSIPrivateKeyParameters params = (ECCSIPrivateKeyParameters)(((ParametersWithRandom)param).getParameters());
+ BigInteger ssk = params.getSSK();
+ BigInteger denominator = new BigInteger(1, heBytes).add(r.multiply(ssk)).mod(q);
+ if (denominator.equals(BigInteger.ZERO))
+ {
+ throw new IllegalArgumentException("Invalid j, retry");
+ }
+
+ BigInteger sPrime = denominator.modInverse(q).multiply(j).mod(q);
+
+ return Arrays.concatenate(BigIntegers.asUnsignedByteArray(32, r), BigIntegers.asUnsignedByteArray(32, sPrime),
+ params.getPublicKeyParameters().getPVT().getEncoded(false));
}
@Override
public boolean verifySignature(byte[] signature)
{
- return false;
+ byte[] bytes = Arrays.copyOf(signature, 32);
+ BigInteger s = new BigInteger(1, Arrays.copyOfRange(signature, 32, 64));
+ r = new BigInteger(1, bytes).mod(q);
+ digest.update(bytes, 0, 32);
+ bytes = stream.toByteArray();
+ digest.update(bytes, 0, bytes.length);
+ bytes = new byte[digest.getDigestSize()];
+ digest.doFinal(bytes, 0);
+
+ BigInteger HE = new BigInteger(1, bytes).mod(q);
+
+ // Compute J = s*(HE*G + r*Y)
+ ECPoint HE_G = G.multiply(HE).normalize();
+ ECPoint rY = Y.multiply(r).normalize();
+ ECPoint sum = HE_G.add(rY).normalize();
+ ECPoint J = sum.multiply(s).normalize();
+
+ BigInteger rComputed = J.getAffineXCoord().toBigInteger();
+
+ return rComputed.mod(q).equals(r.mod(q));
}
@Override
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/ECCSISignerTest.java b/core/src/test/java/org/bouncycastle/crypto/test/ECCSISignerTest.java
new file mode 100644
index 0000000000..ba959a929c
--- /dev/null
+++ b/core/src/test/java/org/bouncycastle/crypto/test/ECCSISignerTest.java
@@ -0,0 +1,72 @@
+package org.bouncycastle.crypto.test;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.generators.ECCSIKeyPairGenerator;
+import org.bouncycastle.crypto.params.ECCSIKeyGenerationParameters;
+import org.bouncycastle.crypto.params.ECCSIPrivateKeyParameters;
+import org.bouncycastle.crypto.params.ECCSIPublicKeyParameters;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.crypto.signers.ECCSISigner;
+import org.bouncycastle.util.BigIntegers;
+import org.bouncycastle.util.encoders.Hex;
+import org.bouncycastle.util.test.FixedSecureRandom;
+import org.bouncycastle.util.test.SimpleTest;
+
+public class ECCSISignerTest
+ extends SimpleTest
+{
+ public static void main(String[] args)
+ throws Exception
+ {
+ ECCSISignerTest test = new ECCSISignerTest();
+ test.performTest();
+ }
+
+ @Override
+ public String getName()
+ {
+ return "ECCSISigner Test";
+ }
+
+ @Override
+ public void performTest()
+ throws Exception
+ {
+ testTestVector();
+ }
+
+ private void testTestVector()
+ throws Exception
+ {
+ BigInteger ksak = BigInteger.valueOf(0x12345);
+ BigInteger v = BigInteger.valueOf(0x23456);
+ BigInteger j = BigInteger.valueOf(0x34567);
+ ECCSIKeyPairGenerator generator = new ECCSIKeyPairGenerator();
+ SecureRandom random = new FixedSecureRandom(new FixedSecureRandom.Source[]{new FixedSecureRandom.Data(BigIntegers.asUnsignedByteArray(32, ksak)),
+ new FixedSecureRandom.Data(BigIntegers.asUnsignedByteArray(32, v)),
+ new FixedSecureRandom.Data(BigIntegers.asUnsignedByteArray(32, j))});
+ ECCSIKeyGenerationParameters keyGenerationParameters = new ECCSIKeyGenerationParameters(random, "2011-02\0tel:+447700900123\0".getBytes());
+ generator.init(keyGenerationParameters);
+ AsymmetricCipherKeyPair keyPair = generator.generateKeyPair();
+ ECCSIPublicKeyParameters pub = (ECCSIPublicKeyParameters)keyPair.getPublic();
+ ECCSIPrivateKeyParameters priv = (ECCSIPrivateKeyParameters)keyPair.getPrivate();
+ System.out.println(new String(Hex.encode(pub.getPVT().getXCoord().toBigInteger().toByteArray())));
+ System.out.println(new String(Hex.encode(pub.getPVT().getYCoord().toBigInteger().toByteArray())));
+ System.out.println(new String(Hex.encode(priv.getSSK().toByteArray())));
+
+ byte[] M = "message\0".getBytes();
+
+ ECCSISigner signer = new ECCSISigner(keyGenerationParameters.getKPAK(), keyGenerationParameters.getId());
+ signer.init(true, new ParametersWithRandom(priv, random));
+ signer.update(M, 0, M.length);
+ byte[] sig = signer.generateSignature();
+ System.out.println("sig: " + new String(Hex.encode(sig)));
+
+ signer.init(false, pub);
+ signer.update(M, 0, M.length);
+ isTrue(signer.verifySignature(sig));
+ }
+}
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java b/core/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java
index 1025007493..4349b06ec0 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java
@@ -1,6 +1,5 @@
package org.bouncycastle.crypto.test;
-import org.bouncycastle.crypto.kems.test.SAKKEKEMSTest;
import org.bouncycastle.util.test.SimpleTest;
import org.bouncycastle.util.test.Test;
diff --git a/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java b/core/src/test/java/org/bouncycastle/crypto/test/SAKKEKEMSTest.java
similarity index 99%
rename from core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
rename to core/src/test/java/org/bouncycastle/crypto/test/SAKKEKEMSTest.java
index 0ef2797037..fa9d73f1e4 100644
--- a/core/src/test/java/org/bouncycastle/crypto/kems/test/SAKKEKEMSTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/SAKKEKEMSTest.java
@@ -1,4 +1,4 @@
-package org.bouncycastle.crypto.kems.test;
+package org.bouncycastle.crypto.test;
import java.math.BigInteger;
import java.security.SecureRandom;
@@ -31,7 +31,7 @@ public static void main(String[] args)
@Override
public String getName()
{
- return null;
+ return "SAKKE-KEMS Test";
}
@Override
From 3d3ca2d6109e84d6d9c36da0faafbf113e45a359 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Thu, 20 Feb 2025 12:36:13 +1030
Subject: [PATCH 178/890] Add support for different curves
---
.../generators/ECCSIKeyPairGenerator.java | 21 +--
.../params/ECCSIKeyGenerationParameters.java | 46 +++--
.../crypto/signers/ECCSISigner.java | 158 ++++++++++--------
.../crypto/test/ECCSISignerTest.java | 103 +++++++++++-
4 files changed, 223 insertions(+), 105 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/generators/ECCSIKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/crypto/generators/ECCSIKeyPairGenerator.java
index 25cf523d64..bfe73a514f 100644
--- a/core/src/main/java/org/bouncycastle/crypto/generators/ECCSIKeyPairGenerator.java
+++ b/core/src/main/java/org/bouncycastle/crypto/generators/ECCSIKeyPairGenerator.java
@@ -3,7 +3,6 @@
import java.math.BigInteger;
import java.security.SecureRandom;
-import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
import org.bouncycastle.crypto.CryptoServicePurpose;
@@ -11,8 +10,6 @@
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.KeyGenerationParameters;
import org.bouncycastle.crypto.constraints.DefaultServiceProperties;
-import org.bouncycastle.crypto.digests.SHA256Digest;
-import org.bouncycastle.crypto.ec.CustomNamedCurves;
import org.bouncycastle.crypto.params.ECCSIKeyGenerationParameters;
import org.bouncycastle.crypto.params.ECCSIPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECCSIPublicKeyParameters;
@@ -21,28 +18,27 @@
public class ECCSIKeyPairGenerator
implements AsymmetricCipherKeyPairGenerator
{
- // Initialize NIST P-256 curve
- private static final X9ECParameters params = CustomNamedCurves.getByName("secP256r1");
- private static final BigInteger q = params.getCurve().getOrder();
-
- // And the base point (generator) is:
- private static final ECPoint G = params.getG();
- //int N = 32; // 256 bits
-
+ private BigInteger q;
+ private ECPoint G;
+ private Digest digest;
private ECCSIKeyGenerationParameters parameters;
@Override
public void init(KeyGenerationParameters parameters)
{
this.parameters = (ECCSIKeyGenerationParameters)parameters;
+ this.q = this.parameters.getQ();
+ this.G = this.parameters.getG();
+ this.digest = this.parameters.getDigest();
- CryptoServicesRegistrar.checkConstraints(new DefaultServiceProperties("ECCSI", 256, null, CryptoServicePurpose.KEYGEN));
+ CryptoServicesRegistrar.checkConstraints(new DefaultServiceProperties("ECCSI", this.parameters.getN(), null, CryptoServicePurpose.KEYGEN));
}
@Override
public AsymmetricCipherKeyPair generateKeyPair()
{
SecureRandom random = parameters.getRandom();
+ this.digest.reset();
byte[] id = parameters.getId();
ECPoint kpak = parameters.getKPAK();
// 1) Choose v, a random (ephemeral) non-zero element of F_q;
@@ -51,7 +47,6 @@ public AsymmetricCipherKeyPair generateKeyPair()
ECPoint pvt = G.multiply(v).normalize();
// 3) Compute a hash value HS = hash( G || KPAK || ID || PVT ), an N-octet integer;
- Digest digest = new SHA256Digest();
byte[] tmp = G.getEncoded(false);
digest.update(tmp, 0, tmp.length);
tmp = kpak.getEncoded(false);
diff --git a/core/src/main/java/org/bouncycastle/crypto/params/ECCSIKeyGenerationParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIKeyGenerationParameters.java
index 0e773b17ec..22df66c639 100644
--- a/core/src/main/java/org/bouncycastle/crypto/params/ECCSIKeyGenerationParameters.java
+++ b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIKeyGenerationParameters.java
@@ -4,27 +4,21 @@
import java.security.SecureRandom;
import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.KeyGenerationParameters;
-import org.bouncycastle.crypto.ec.CustomNamedCurves;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.Arrays;
public class ECCSIKeyGenerationParameters
extends KeyGenerationParameters
{
- private static final BigInteger q;
- private static final ECPoint G;
-
- static
- {
- X9ECParameters params = CustomNamedCurves.getByName("secP256r1");
- q = params.getCurve().getOrder();
- G = params.getG();
- }
-
+ private final BigInteger q;
+ private final ECPoint G;
+ private final Digest digest;
private final byte[] id;
private final BigInteger ksak;
private final ECPoint kpak;
+ private final int n;
/**
* initialise the generator with a source of randomness
@@ -32,11 +26,15 @@ public class ECCSIKeyGenerationParameters
*
* @param random the random byte source.
*/
- public ECCSIKeyGenerationParameters(SecureRandom random, byte[] id)
+ public ECCSIKeyGenerationParameters(SecureRandom random, X9ECParameters params, Digest digest, byte[] id)
{
- super(random, 256);
+ super(random, params.getCurve().getA().bitLength());
+ this.q = params.getCurve().getOrder();
+ this.G = params.getG();
+ this.digest = digest;
this.id = Arrays.clone(id);
- this.ksak = new BigInteger(256, random).mod(q);
+ this.n = params.getCurve().getA().bitLength();
+ this.ksak = new BigInteger(n, random).mod(q);
this.kpak = G.multiply(ksak).normalize();
}
@@ -54,4 +52,24 @@ public BigInteger computeSSK(BigInteger hs_v)
{
return ksak.add(hs_v).mod(q);
}
+
+ public BigInteger getQ()
+ {
+ return q;
+ }
+
+ public ECPoint getG()
+ {
+ return G;
+ }
+
+ public Digest getDigest()
+ {
+ return digest;
+ }
+
+ public int getN()
+ {
+ return n;
+ }
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/signers/ECCSISigner.java b/core/src/main/java/org/bouncycastle/crypto/signers/ECCSISigner.java
index 550f6e9996..c825971f04 100644
--- a/core/src/main/java/org/bouncycastle/crypto/signers/ECCSISigner.java
+++ b/core/src/main/java/org/bouncycastle/crypto/signers/ECCSISigner.java
@@ -10,8 +10,6 @@
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.Signer;
-import org.bouncycastle.crypto.digests.SHA256Digest;
-import org.bouncycastle.crypto.ec.CustomNamedCurves;
import org.bouncycastle.crypto.params.ECCSIPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECCSIPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
@@ -19,20 +17,27 @@
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
+/**
+ * Implementation of Elliptic Curve-based Certificateless Signatures for Identity-Based Encryption (ECCSI)
+ * as defined in RFC 6507.
+ *
+ * This class handles both signature generation and verification using the ECCSI scheme. It supports:
+ *
+ * - NIST P-256 (secp256r1) elliptic curve parameters
+ * - SHA-256 hash function
+ * - Certificateless signatures using KMS Public Authentication Key (KPAK)
+ * - Identity-based signatures with Secret Signing Key (SSK)
+ *
+ *
+ * @see RFC 6507: Elliptic Curve-Based Certificateless
+ * Signatures for Identity-Based Encryption (ECCSI)
+ */
public class ECCSISigner
implements Signer
{
- private static final BigInteger q;
- private static final ECPoint G;
-
- static
- {
- X9ECParameters params = CustomNamedCurves.getByName("secP256r1");
- q = params.getCurve().getOrder();
- G = params.getG();
- }
-
- private final Digest digest = new SHA256Digest();
+ private final BigInteger q;
+ private final ECPoint G;
+ private final Digest digest;
private BigInteger j;
private BigInteger r;
private ECPoint Y;
@@ -41,11 +46,18 @@ public class ECCSISigner
private CipherParameters param;
private ByteArrayOutputStream stream;
private boolean forSigning;
+ private final int N;
- public ECCSISigner(ECPoint kpak, byte[] id)
+
+ public ECCSISigner(ECPoint kpak, X9ECParameters params, Digest digest, byte[] id)
{
this.kpak = kpak;
this.id = id;
+ this.q = params.getCurve().getOrder();
+ this.G = params.getG();
+ this.digest = digest;
+ this.digest.reset();
+ this.N = (params.getCurve().getOrder().bitLength() + 7) >> 3;
}
@Override
@@ -53,60 +65,7 @@ public void init(boolean forSigning, CipherParameters param)
{
this.forSigning = forSigning;
this.param = param;
- SecureRandom random = null;
- if (param instanceof ParametersWithRandom)
- {
- random = ((ParametersWithRandom)param).getRandom();
- param = ((ParametersWithRandom)param).getParameters();
- }
- ECPoint kpak_computed = null;
- ECPoint pvt;
- if (forSigning)
- {
- ECCSIPrivateKeyParameters parameters = (ECCSIPrivateKeyParameters)param;
-
- j = new BigInteger(256, random).mod(q);
- ECPoint J = G.multiply(j).normalize();
- r = J.getAffineXCoord().toBigInteger();
- pvt = parameters.getPublicKeyParameters().getPVT();
- kpak_computed = G.multiply(parameters.getSSK());
- }
- else
- {
- ECCSIPublicKeyParameters parameters = (ECCSIPublicKeyParameters)param;
- pvt = parameters.getPVT();
- stream = new ByteArrayOutputStream();
- }
-
- // compute HS
- byte[] tmp = G.getEncoded(false);
- digest.update(tmp, 0, tmp.length);
- tmp = kpak.getEncoded(false);
- digest.update(tmp, 0, tmp.length);
- digest.update(id, 0, id.length);
- tmp = pvt.getEncoded(false);
- digest.update(tmp, 0, tmp.length);
- tmp = new byte[digest.getDigestSize()];
- digest.doFinal(tmp, 0);
- BigInteger HS = new BigInteger(1, tmp).mod(q);
-
- //HE = hash( HS || r || M );
- digest.update(tmp, 0, tmp.length);
- if (forSigning)
- {
- kpak_computed = kpak_computed.subtract(pvt.multiply(HS)).normalize();
- if (!kpak_computed.equals(kpak))
- {
- throw new IllegalArgumentException("Invalid KPAK");
- }
- byte[] rBytes = BigIntegers.asUnsignedByteArray(32, r);
- digest.update(rBytes, 0, rBytes.length);
- }
- else
- {
- // Compute Y = HS*PVT + KPAK
- Y = pvt.multiply(HS).add(kpak).normalize();
- }
+ reset();
}
@Override
@@ -153,17 +112,17 @@ public byte[] generateSignature()
BigInteger sPrime = denominator.modInverse(q).multiply(j).mod(q);
- return Arrays.concatenate(BigIntegers.asUnsignedByteArray(32, r), BigIntegers.asUnsignedByteArray(32, sPrime),
+ return Arrays.concatenate(BigIntegers.asUnsignedByteArray(this.N, r), BigIntegers.asUnsignedByteArray(this.N, sPrime),
params.getPublicKeyParameters().getPVT().getEncoded(false));
}
@Override
public boolean verifySignature(byte[] signature)
{
- byte[] bytes = Arrays.copyOf(signature, 32);
- BigInteger s = new BigInteger(1, Arrays.copyOfRange(signature, 32, 64));
+ byte[] bytes = Arrays.copyOf(signature, this.N);
+ BigInteger s = new BigInteger(1, Arrays.copyOfRange(signature, this.N, this.N << 1));
r = new BigInteger(1, bytes).mod(q);
- digest.update(bytes, 0, 32);
+ digest.update(bytes, 0, this.N);
bytes = stream.toByteArray();
digest.update(bytes, 0, bytes.length);
bytes = new byte[digest.getDigestSize()];
@@ -185,6 +144,61 @@ public boolean verifySignature(byte[] signature)
@Override
public void reset()
{
+ digest.reset();
+ CipherParameters param = this.param;
+ SecureRandom random = null;
+ if (param instanceof ParametersWithRandom)
+ {
+ random = ((ParametersWithRandom)param).getRandom();
+ param = ((ParametersWithRandom)param).getParameters();
+ }
+ ECPoint kpak_computed = null;
+ ECPoint pvt;
+ if (forSigning)
+ {
+ ECCSIPrivateKeyParameters parameters = (ECCSIPrivateKeyParameters)param;
+ pvt = parameters.getPublicKeyParameters().getPVT();
+ j = new BigInteger(q.bitLength(), random);
+ ECPoint J = G.multiply(j).normalize();
+ r = J.getAffineXCoord().toBigInteger().mod(q);
+ kpak_computed = G.multiply(parameters.getSSK());
+ }
+ else
+ {
+ ECCSIPublicKeyParameters parameters = (ECCSIPublicKeyParameters)param;
+ pvt = parameters.getPVT();
+ stream = new ByteArrayOutputStream();
+ }
+
+ // compute HS
+ byte[] tmp = G.getEncoded(false);
+ digest.update(tmp, 0, tmp.length);
+ tmp = kpak.getEncoded(false);
+ digest.update(tmp, 0, tmp.length);
+ digest.update(id, 0, id.length);
+ tmp = pvt.getEncoded(false);
+ digest.update(tmp, 0, tmp.length);
+ tmp = new byte[digest.getDigestSize()];
+ digest.doFinal(tmp, 0);
+ BigInteger HS = new BigInteger(1, tmp).mod(q);
+
+ //HE = hash( HS || r || M );
+ digest.update(tmp, 0, tmp.length);
+ if (forSigning)
+ {
+ kpak_computed = kpak_computed.subtract(pvt.multiply(HS)).normalize();
+ if (!kpak_computed.equals(kpak))
+ {
+ throw new IllegalArgumentException("Invalid KPAK");
+ }
+ byte[] rBytes = BigIntegers.asUnsignedByteArray(this.N, r);
+ digest.update(rBytes, 0, rBytes.length);
+ }
+ else
+ {
+ // Compute Y = HS*PVT + KPAK
+ Y = pvt.multiply(HS).add(kpak).normalize();
+ }
}
}
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/ECCSISignerTest.java b/core/src/test/java/org/bouncycastle/crypto/test/ECCSISignerTest.java
index ba959a929c..dc6018444f 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/ECCSISignerTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/ECCSISignerTest.java
@@ -3,13 +3,19 @@
import java.math.BigInteger;
import java.security.SecureRandom;
+import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.digests.SHA512Digest;
+import org.bouncycastle.crypto.ec.CustomNamedCurves;
import org.bouncycastle.crypto.generators.ECCSIKeyPairGenerator;
import org.bouncycastle.crypto.params.ECCSIKeyGenerationParameters;
import org.bouncycastle.crypto.params.ECCSIPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECCSIPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.signers.ECCSISigner;
+import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.FixedSecureRandom;
@@ -18,6 +24,42 @@
public class ECCSISignerTest
extends SimpleTest
{
+ String[] curveNames = {
+ "curve25519",
+ "secp128r1",
+ "secp160k1",
+ "secp160r1",
+ "secp160r2",
+ "secp192k1",
+ "secp192r1",
+ "secp224k1",
+ "secp224r1",
+ "secp256k1",
+ "secp256r1",
+ "secp384r1",
+ "secp521r1",
+ "sect113r1",
+ "sect113r2",
+ "sect131r1",
+ "sect131r2",
+ "sect163k1",
+ "sect163r1",
+ "sect163r2",
+ "sect193r1",
+ "sect193r2",
+ "sect233k1",
+ "sect233r1",
+ "sect239k1",
+ "sect283k1",
+ "sect283r1",
+ "sect409k1",
+ "sect409r1",
+ "sect571k1",
+ "sect571r1",
+ "sm2p256v1"
+ };
+
+
public static void main(String[] args)
throws Exception
{
@@ -36,6 +78,11 @@ public void performTest()
throws Exception
{
testTestVector();
+ for (int i = 0; i < curveNames.length; ++i)
+ {
+ //System.out.println(curveNames[i]);
+ testRandom(curveNames[i]);
+ }
}
private void testTestVector()
@@ -48,25 +95,69 @@ private void testTestVector()
SecureRandom random = new FixedSecureRandom(new FixedSecureRandom.Source[]{new FixedSecureRandom.Data(BigIntegers.asUnsignedByteArray(32, ksak)),
new FixedSecureRandom.Data(BigIntegers.asUnsignedByteArray(32, v)),
new FixedSecureRandom.Data(BigIntegers.asUnsignedByteArray(32, j))});
- ECCSIKeyGenerationParameters keyGenerationParameters = new ECCSIKeyGenerationParameters(random, "2011-02\0tel:+447700900123\0".getBytes());
+ ECCSIKeyGenerationParameters keyGenerationParameters = new ECCSIKeyGenerationParameters(random,
+ CustomNamedCurves.getByName("secP256r1"), new SHA256Digest(), "2011-02\0tel:+447700900123\0".getBytes());
generator.init(keyGenerationParameters);
AsymmetricCipherKeyPair keyPair = generator.generateKeyPair();
ECCSIPublicKeyParameters pub = (ECCSIPublicKeyParameters)keyPair.getPublic();
ECCSIPrivateKeyParameters priv = (ECCSIPrivateKeyParameters)keyPair.getPrivate();
- System.out.println(new String(Hex.encode(pub.getPVT().getXCoord().toBigInteger().toByteArray())));
- System.out.println(new String(Hex.encode(pub.getPVT().getYCoord().toBigInteger().toByteArray())));
- System.out.println(new String(Hex.encode(priv.getSSK().toByteArray())));
+// System.out.println(new String(Hex.encode(pub.getPVT().getXCoord().toBigInteger().toByteArray())));
+// System.out.println(new String(Hex.encode(pub.getPVT().getYCoord().toBigInteger().toByteArray())));
+// System.out.println(new String(Hex.encode(priv.getSSK().toByteArray())));
byte[] M = "message\0".getBytes();
- ECCSISigner signer = new ECCSISigner(keyGenerationParameters.getKPAK(), keyGenerationParameters.getId());
+ ECCSISigner signer = new ECCSISigner(keyGenerationParameters.getKPAK(), CustomNamedCurves.getByName("secP256r1"), new SHA256Digest(), keyGenerationParameters.getId());
signer.init(true, new ParametersWithRandom(priv, random));
signer.update(M, 0, M.length);
byte[] sig = signer.generateSignature();
- System.out.println("sig: " + new String(Hex.encode(sig)));
+ isTrue(Arrays.areEqual(sig, Hex.decode("269D4C8F DEB66A74 E4EF8C0D 5DCC597D\n" +
+ " DFE6029C 2AFFC493 6008CD2C C1045D81\n" +
+ " E09B528D 0EF8D6DF 1AA3ECBF 80110CFC\n" +
+ " EC9FC682 52CEBB67 9F413484 6940CCFD\n" +
+ " 04\n" +
+ "\n" +
+ " 758A1427 79BE89E8 29E71984 CB40EF75\n" +
+ " 8CC4AD77 5FC5B9A3 E1C8ED52 F6FA36D9\n" +
+ " A79D2476 92F4EDA3 A6BDAB77 D6AA6474\n" +
+ " A464AE49 34663C52 65BA7018 BA091F79")));
+// System.out.println("sig: " + new String(Hex.encode(sig)));
signer.init(false, pub);
signer.update(M, 0, M.length);
isTrue(signer.verifySignature(sig));
}
+
+ private void testRandom(String curveName)
+ throws Exception
+ {
+ SecureRandom random = new SecureRandom();
+ ECCSIKeyPairGenerator generator = new ECCSIKeyPairGenerator();
+ byte[] id = new byte[16];
+ random.nextBytes(id);
+ Digest digest = new SHA512Digest();
+ X9ECParameters params = CustomNamedCurves.getByName(curveName);
+ ECCSIKeyGenerationParameters keyGenerationParameters = new ECCSIKeyGenerationParameters(random,
+ params, digest, id);
+ generator.init(keyGenerationParameters);
+ AsymmetricCipherKeyPair keyPair = generator.generateKeyPair();
+ ECCSIPublicKeyParameters pub = (ECCSIPublicKeyParameters)keyPair.getPublic();
+ ECCSIPrivateKeyParameters priv = (ECCSIPrivateKeyParameters)keyPair.getPrivate();
+
+ byte[] M = "message\0".getBytes();
+
+ ECCSISigner signer = new ECCSISigner(keyGenerationParameters.getKPAK(), params, digest, keyGenerationParameters.getId());
+ signer.init(true, new ParametersWithRandom(priv, random));
+ signer.update(M, 0, M.length);
+ signer.reset();
+ signer.update(M, 0, M.length);
+ byte[] sig = signer.generateSignature();
+ signer = new ECCSISigner(keyGenerationParameters.getKPAK(), params, digest, keyGenerationParameters.getId());
+ signer.init(false, pub);
+ signer.update(M, 0, M.length);
+ signer.reset();
+ signer.update(M, 0, M.length);
+ isTrue(signer.verifySignature(sig));
+ }
+
}
From 3e093511f9e9aebaee56652fcd7bde51529918c4 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Thu, 20 Feb 2025 13:51:18 +1030
Subject: [PATCH 179/890] Add java doc and more tests with different digests
---
.../params/ECCSIKeyGenerationParameters.java | 91 ++++++++++++++++++-
.../params/ECCSIPrivateKeyParameters.java | 45 +++++++++
.../params/ECCSIPublicKeyParameters.java | 30 ++++++
.../crypto/signers/ECCSISigner.java | 49 ++++++++--
.../crypto/test/ECCSISignerTest.java | 26 +++++-
5 files changed, 224 insertions(+), 17 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/params/ECCSIKeyGenerationParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIKeyGenerationParameters.java
index 22df66c639..3b62709c19 100644
--- a/core/src/main/java/org/bouncycastle/crypto/params/ECCSIKeyGenerationParameters.java
+++ b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIKeyGenerationParameters.java
@@ -9,22 +9,68 @@
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.Arrays;
+/**
+ * Parameters for ECCSI key generation.
+ *
+ *
+ * This class encapsulates the parameters required for ECCSI (Elliptic Curve
+ * Certificateless Signatures for Identity-based encryption) key generation.
+ * It holds the elliptic curve domain parameters and computes the key pair
+ * components used in ECCSI.
+ *
+ *
+ *
+ * The secret component {@code ksak} is generated randomly and reduced modulo
+ * {@code q}, while {@code kpak} is derived from {@code ksak} by multiplying the
+ * generator point.
+ *
+ */
public class ECCSIKeyGenerationParameters
extends KeyGenerationParameters
{
+ /**
+ * The order of the elliptic curve.
+ */
private final BigInteger q;
+
+ /**
+ * The generator (base point) of the elliptic curve.
+ */
private final ECPoint G;
+
+ /**
+ * The digest algorithm used in key generation.
+ */
private final Digest digest;
+
+ /**
+ * The identifier (e.g. user identity) used in key generation.
+ */
private final byte[] id;
+
+ /**
+ * The secret key component (ksak) used in ECCSI, generated randomly.
+ */
private final BigInteger ksak;
+
+ /**
+ * The public key component (kpak), computed as G * ksak.
+ */
private final ECPoint kpak;
+
+ /**
+ * The bit length used for key generation (typically the bit length of the curve's parameter A).
+ */
private final int n;
/**
- * initialise the generator with a source of randomness
- * and a strength (in bits).
+ * Constructs an instance of {@code ECCSIKeyGenerationParameters} with the specified
+ * source of randomness, elliptic curve parameters, digest algorithm, and identifier.
*
- * @param random the random byte source.
+ * @param random the source of randomness.
+ * @param params the elliptic curve parameters (in X9.62 format) providing the curve, order, and generator.
+ * @param digest the digest algorithm to be used.
+ * @param id the identifier associated with the key generation (e.g. a user or device ID).
*/
public ECCSIKeyGenerationParameters(SecureRandom random, X9ECParameters params, Digest digest, byte[] id)
{
@@ -38,36 +84,73 @@ public ECCSIKeyGenerationParameters(SecureRandom random, X9ECParameters params,
this.kpak = G.multiply(ksak).normalize();
}
+ /**
+ * Returns a copy of the identifier used in these parameters.
+ *
+ * @return a byte array containing the identifier.
+ */
public byte[] getId()
{
- return id;
+ return Arrays.clone(id);
}
+ /**
+ * Returns the public key component (kpak) corresponding to the secret key.
+ *
+ * @return the public key point.
+ */
public ECPoint getKPAK()
{
return kpak;
}
+ /**
+ * Computes the session secret key (SSK) by adding the provided value to the secret key component
+ * and reducing modulo the curve order.
+ *
+ * @param hs_v a BigInteger value (typically derived from a hash) to be added to the secret.
+ * @return the computed session secret key.
+ */
public BigInteger computeSSK(BigInteger hs_v)
{
return ksak.add(hs_v).mod(q);
}
+ /**
+ * Returns the order of the elliptic curve.
+ *
+ * @return the curve order.
+ */
public BigInteger getQ()
{
return q;
}
+ /**
+ * Returns the generator (base point) of the elliptic curve.
+ *
+ * @return the generator point.
+ */
public ECPoint getG()
{
return G;
}
+ /**
+ * Returns the digest algorithm used for key generation.
+ *
+ * @return the digest.
+ */
public Digest getDigest()
{
return digest;
}
+ /**
+ * Returns the bit length used in key generation.
+ *
+ * @return the bit length.
+ */
public int getN()
{
return n;
diff --git a/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPrivateKeyParameters.java
index 17ee88614a..bc37f5f839 100644
--- a/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPrivateKeyParameters.java
+++ b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPrivateKeyParameters.java
@@ -2,12 +2,47 @@
import java.math.BigInteger;
+/**
+ * Represents the private key parameters for the Elliptic Curve-based Certificateless
+ * Signature Infrastructure (ECCSI) scheme as defined in RFC 6507.
+ *
+ *
+ * This class encapsulates the secret signing key (SSK) used in ECCSI. The SSK is generated by
+ * the Key Management Service (KMS) and is a random integer modulo the order of the elliptic curve.
+ * It is paired with the corresponding public key parameters, represented by an instance of
+ * {@link ECCSIPublicKeyParameters}, to form the complete key material required for generating
+ * and verifying ECCSI signatures without the use of traditional certificates.
+ *
+ *
+ *
+ * Per RFC 6507 Section 5.1:
+ *
+ * - The SSK is generated as a random value in the appropriate range.
+ * - It is used in conjunction with the public validation token (PVT) to perform signature
+ * operations.
+ * - The combination of the SSK and the public key parameters enables certificateless
+ * signature generation and verification.
+ *
+ *
+ *
+ * @see ECCSIPublicKeyParameters
+ * @see
+ * RFC 6507: Elliptic Curve-Based Certificateless Signatures for Identity-Based Encryption (ECCSI)
+ *
+ */
public class ECCSIPrivateKeyParameters
extends AsymmetricKeyParameter
{
private final BigInteger ssk;
private final ECCSIPublicKeyParameters pub;
+ /**
+ * Constructs {@code ECCSIPrivateKeyParameters} with the specified secret signing key
+ * and associated public key parameters.
+ *
+ * @param ssk the secret signing key (SSK) as a BigInteger.
+ * @param pub the corresponding public key parameters, which encapsulate the public validation token.
+ */
public ECCSIPrivateKeyParameters(BigInteger ssk, ECCSIPublicKeyParameters pub)
{
super(true);
@@ -15,11 +50,21 @@ public ECCSIPrivateKeyParameters(BigInteger ssk, ECCSIPublicKeyParameters pub)
this.pub = pub;
}
+ /**
+ * Returns the public key parameters associated with this private key.
+ *
+ * @return the {@link ECCSIPublicKeyParameters} containing the public validation token (PVT).
+ */
public ECCSIPublicKeyParameters getPublicKeyParameters()
{
return pub;
}
+ /**
+ * Returns the secret signing key (SSK) used in ECCSI.
+ *
+ * @return the SSK as a BigInteger.
+ */
public BigInteger getSSK()
{
return ssk;
diff --git a/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPublicKeyParameters.java
index 19bfc43b8f..15269a0b46 100644
--- a/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPublicKeyParameters.java
+++ b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPublicKeyParameters.java
@@ -2,17 +2,47 @@
import org.bouncycastle.math.ec.ECPoint;
+/**
+ * Represents the public key parameters for the Elliptic Curve-based Certificateless
+ * Signature Infrastructure (ECCSI) scheme as defined in RFC 6507.
+ *
+ * This class encapsulates the Public Validation Token (PVT) required for verifying
+ * ECCSI signatures. The PVT is cryptographically bound to a user's identity and
+ * generated by the Key Management Service (KMS) as part of the key material.
+ *
+ *
Per RFC 6507 Section 5.1:
+ *
+ * - The PVT is derived from the user's identity and KMS secret material
+ * - Used during signature verification to validate the signer's identity
+ * - Does not require certificates for authentication
+ *
+ *
+ * @see RFC 6507: Elliptic Curve-Based Certificateless
+ * * Signatures for Identity-Based Encryption (ECCSI)
+ */
+
public class ECCSIPublicKeyParameters
extends AsymmetricKeyParameter
{
private final ECPoint pvt;
+ /**
+ * Constructs {@code ECCSIPublicKeyParameters} with the provided Public Validation Token (PVT).
+ */
public ECCSIPublicKeyParameters(ECPoint pvt)
{
super(false);
this.pvt = pvt;
}
+ /**
+ * Returns the Public Validation Token (PVT) for signature verification.
+ *
+ * The PVT is used in conjunction with the KMS Public Authentication Key (KPAK)
+ * to verify signatures per RFC 6507 Section 5.2.2.
+ *
+ * @return The PVT as an elliptic curve point in uncompressed format
+ */
public final ECPoint getPVT()
{
return pvt;
diff --git a/core/src/main/java/org/bouncycastle/crypto/signers/ECCSISigner.java b/core/src/main/java/org/bouncycastle/crypto/signers/ECCSISigner.java
index c825971f04..98df43fc99 100644
--- a/core/src/main/java/org/bouncycastle/crypto/signers/ECCSISigner.java
+++ b/core/src/main/java/org/bouncycastle/crypto/signers/ECCSISigner.java
@@ -20,14 +20,6 @@
/**
* Implementation of Elliptic Curve-based Certificateless Signatures for Identity-Based Encryption (ECCSI)
* as defined in RFC 6507.
- *
- * This class handles both signature generation and verification using the ECCSI scheme. It supports:
- *
- * - NIST P-256 (secp256r1) elliptic curve parameters
- * - SHA-256 hash function
- * - Certificateless signatures using KMS Public Authentication Key (KPAK)
- * - Identity-based signatures with Secret Signing Key (SSK)
- *
*
* @see RFC 6507: Elliptic Curve-Based Certificateless
* Signatures for Identity-Based Encryption (ECCSI)
@@ -48,7 +40,12 @@ public class ECCSISigner
private boolean forSigning;
private final int N;
-
+ /**
+ * Constructs an ECCSI signer/verifier with KMS Public Authentication Key and user identity.
+ *
+ * @param kpak KMS Public Authentication Key (KPAK) from RFC 6507 Section 2
+ * @param id User identity byte array formatted
+ */
public ECCSISigner(ECPoint kpak, X9ECParameters params, Digest digest, byte[] id)
{
this.kpak = kpak;
@@ -60,6 +57,15 @@ public ECCSISigner(ECPoint kpak, X9ECParameters params, Digest digest, byte[] id
this.N = (params.getCurve().getOrder().bitLength() + 7) >> 3;
}
+ /**
+ * Initializes the signer for either signature generation or verification.
+ *
+ * @param forSigning true for signing, false for verification
+ * @param param Key parameters:
+ * - For signing: {@code ParametersWithRandom} containing {@code ECCSIPrivateKeyParameters}
+ * - For verification: {@code ECCSIPublicKeyParameters}
+ * @throws IllegalArgumentException if invalid parameters are provided
+ */
@Override
public void init(boolean forSigning, CipherParameters param)
{
@@ -94,6 +100,17 @@ public void update(byte[] in, int off, int len)
}
}
+ /**
+ * Generates an ECCSI signature according to RFC 6507 Section 5.2.1.
+ *
+ * @return Signature structure containing:
+ * - r (N bytes)
+ * - s (N bytes)
+ * - PVT (Public Validation Token)
+ * @throws CryptoException if cryptographic operations fail
+ * @throws DataLengthException if input data is invalid
+ * @throws IllegalArgumentException if invalid SSK or j parameter is detected
+ */
@Override
public byte[] generateSignature()
throws CryptoException, DataLengthException
@@ -116,6 +133,13 @@ public byte[] generateSignature()
params.getPublicKeyParameters().getPVT().getEncoded(false));
}
+ /**
+ * Verifies an ECCSI signature according to RFC 6507 Section 5.2.2.
+ *
+ * @param signature Signature to verify (r || s || PVT)
+ * @return true if signature is valid, false otherwise
+ * @throws IllegalArgumentException if signature format is invalid
+ */
@Override
public boolean verifySignature(byte[] signature)
{
@@ -141,6 +165,13 @@ public boolean verifySignature(byte[] signature)
return rComputed.mod(q).equals(r.mod(q));
}
+ /**
+ * Resets the signer/verifier state and performs initial computations:
+ * - For signing: Validates KPAK consistency (RFC 6507 Section 5.1.2)
+ * - For verification: Computes Y = HS·PVT + KPAK
+ *
+ * Also computes HS = hash(G || KPAK || ID || PVT) as per RFC 6507 Section 5.1.1
+ */
@Override
public void reset()
{
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/ECCSISignerTest.java b/core/src/test/java/org/bouncycastle/crypto/test/ECCSISignerTest.java
index dc6018444f..7559cf2a90 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/ECCSISignerTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/ECCSISignerTest.java
@@ -6,8 +6,13 @@
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.AsconHash256;
+import org.bouncycastle.crypto.digests.MD5Digest;
+import org.bouncycastle.crypto.digests.SHA224Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.digests.SHA3Digest;
import org.bouncycastle.crypto.digests.SHA512Digest;
+import org.bouncycastle.crypto.digests.SHAKEDigest;
import org.bouncycastle.crypto.ec.CustomNamedCurves;
import org.bouncycastle.crypto.generators.ECCSIKeyPairGenerator;
import org.bouncycastle.crypto.params.ECCSIKeyGenerationParameters;
@@ -59,6 +64,18 @@ public class ECCSISignerTest
"sm2p256v1"
};
+ Digest[] digests = new Digest[]{
+ new SHA256Digest(),
+ new SHA3Digest(),
+ new SHA3Digest(512),
+ new SHA224Digest(),
+ new SHA512Digest(),
+ new AsconHash256(),
+ new SHAKEDigest(256),
+ new SHAKEDigest(128),
+ new MD5Digest()
+ };
+
public static void main(String[] args)
throws Exception
@@ -80,8 +97,10 @@ public void performTest()
testTestVector();
for (int i = 0; i < curveNames.length; ++i)
{
- //System.out.println(curveNames[i]);
- testRandom(curveNames[i]);
+ for (int j = 0; j < digests.length; ++j)
+ {
+ testRandom(curveNames[i], digests[j]);
+ }
}
}
@@ -128,14 +147,13 @@ private void testTestVector()
isTrue(signer.verifySignature(sig));
}
- private void testRandom(String curveName)
+ private void testRandom(String curveName, Digest digest)
throws Exception
{
SecureRandom random = new SecureRandom();
ECCSIKeyPairGenerator generator = new ECCSIKeyPairGenerator();
byte[] id = new byte[16];
random.nextBytes(id);
- Digest digest = new SHA512Digest();
X9ECParameters params = CustomNamedCurves.getByName(curveName);
ECCSIKeyGenerationParameters keyGenerationParameters = new ECCSIKeyGenerationParameters(random,
params, digest, id);
From cd39549e5e06e087fd2059f2c537d73355486534 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Thu, 20 Feb 2025 13:58:11 +1030
Subject: [PATCH 180/890] Add java doc
---
.../crypto/generators/ECCSIKeyPairGenerator.java | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/core/src/main/java/org/bouncycastle/crypto/generators/ECCSIKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/crypto/generators/ECCSIKeyPairGenerator.java
index bfe73a514f..49b5c2f4a3 100644
--- a/core/src/main/java/org/bouncycastle/crypto/generators/ECCSIKeyPairGenerator.java
+++ b/core/src/main/java/org/bouncycastle/crypto/generators/ECCSIKeyPairGenerator.java
@@ -15,6 +15,15 @@
import org.bouncycastle.crypto.params.ECCSIPublicKeyParameters;
import org.bouncycastle.math.ec.ECPoint;
+/**
+ * A key pair generator for the ECCSI scheme (Elliptic Curve-based Certificateless Signatures
+ * for Identity-based Encryption) as defined in RFC 6507.
+ *
+ * @see
+ * RFC 6507: Elliptic Curve-Based Certificateless Signatures for Identity-based Encryption (ECCSI)
+ *
+ */
+
public class ECCSIKeyPairGenerator
implements AsymmetricCipherKeyPairGenerator
{
@@ -23,6 +32,12 @@ public class ECCSIKeyPairGenerator
private Digest digest;
private ECCSIKeyGenerationParameters parameters;
+ /**
+ * Initializes the key pair generator with the specified parameters.
+ *
+ * @param parameters an instance of {@link ECCSIKeyGenerationParameters} which encapsulates the elliptic
+ * curve domain parameters, the digest algorithm, and an associated identifier.
+ */
@Override
public void init(KeyGenerationParameters parameters)
{
From 4bfc1d72d1e482ca623418d2976f21dfe6472f3a Mon Sep 17 00:00:00 2001
From: gefeili
Date: Sun, 9 Mar 2025 18:57:37 +1030
Subject: [PATCH 181/890] change new BigInteger(n, random) to
BigIntegers.createRandomBigInteger
---
.../bouncycastle/crypto/generators/ECCSIKeyPairGenerator.java | 3 ++-
.../java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java | 2 +-
.../crypto/params/ECCSIKeyGenerationParameters.java | 3 ++-
.../main/java/org/bouncycastle/crypto/signers/ECCSISigner.java | 2 +-
4 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/generators/ECCSIKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/crypto/generators/ECCSIKeyPairGenerator.java
index 49b5c2f4a3..321c020abd 100644
--- a/core/src/main/java/org/bouncycastle/crypto/generators/ECCSIKeyPairGenerator.java
+++ b/core/src/main/java/org/bouncycastle/crypto/generators/ECCSIKeyPairGenerator.java
@@ -14,6 +14,7 @@
import org.bouncycastle.crypto.params.ECCSIPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECCSIPublicKeyParameters;
import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.util.BigIntegers;
/**
* A key pair generator for the ECCSI scheme (Elliptic Curve-based Certificateless Signatures
@@ -57,7 +58,7 @@ public AsymmetricCipherKeyPair generateKeyPair()
byte[] id = parameters.getId();
ECPoint kpak = parameters.getKPAK();
// 1) Choose v, a random (ephemeral) non-zero element of F_q;
- BigInteger v = new BigInteger(256, random).mod(q);
+ BigInteger v = BigIntegers.createRandomBigInteger(256, random).mod(q);
// 2) Compute PVT = [v]G
ECPoint pvt = G.multiply(v).normalize();
diff --git a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
index 9bb956d4c1..eb14f47b04 100644
--- a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
+++ b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java
@@ -78,7 +78,7 @@ public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recip
Digest digest = keyParameters.getDigest();
// 1. Generate random SSV in range [0, 2^n - 1]
- BigInteger ssv = new BigInteger(n, random);
+ BigInteger ssv = BigIntegers.createRandomBigInteger(n, random);
// 2. Compute r = HashToIntegerRange(SSV || b, q)
BigInteger r = hashToIntegerRange(Arrays.concatenate(ssv.toByteArray(), b.toByteArray()), q, digest);
diff --git a/core/src/main/java/org/bouncycastle/crypto/params/ECCSIKeyGenerationParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIKeyGenerationParameters.java
index 3b62709c19..4df70d28bd 100644
--- a/core/src/main/java/org/bouncycastle/crypto/params/ECCSIKeyGenerationParameters.java
+++ b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIKeyGenerationParameters.java
@@ -8,6 +8,7 @@
import org.bouncycastle.crypto.KeyGenerationParameters;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.BigIntegers;
/**
* Parameters for ECCSI key generation.
@@ -80,7 +81,7 @@ public ECCSIKeyGenerationParameters(SecureRandom random, X9ECParameters params,
this.digest = digest;
this.id = Arrays.clone(id);
this.n = params.getCurve().getA().bitLength();
- this.ksak = new BigInteger(n, random).mod(q);
+ this.ksak = BigIntegers.createRandomBigInteger(n, random).mod(q);
this.kpak = G.multiply(ksak).normalize();
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/signers/ECCSISigner.java b/core/src/main/java/org/bouncycastle/crypto/signers/ECCSISigner.java
index 98df43fc99..bec1461a8a 100644
--- a/core/src/main/java/org/bouncycastle/crypto/signers/ECCSISigner.java
+++ b/core/src/main/java/org/bouncycastle/crypto/signers/ECCSISigner.java
@@ -189,7 +189,7 @@ public void reset()
{
ECCSIPrivateKeyParameters parameters = (ECCSIPrivateKeyParameters)param;
pvt = parameters.getPublicKeyParameters().getPVT();
- j = new BigInteger(q.bitLength(), random);
+ j = BigIntegers.createRandomBigInteger(q.bitLength(), random);
ECPoint J = G.multiply(j).normalize();
r = J.getAffineXCoord().toBigInteger().mod(q);
From f088322676edc0af646490b7b578957b9508b0d1 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Mon, 10 Mar 2025 10:08:59 +1030
Subject: [PATCH 182/890] TODO: AES CTR issue
---
.../pqc/crypto/snova/MapGroup1.java | 34 ++++++++-------
.../crypto/snova/SnovaKeyPairGenerator.java | 43 ++++++++++++++++---
2 files changed, 56 insertions(+), 21 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup1.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup1.java
index 0f0caea2a4..cab068f328 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup1.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup1.java
@@ -26,38 +26,42 @@ public MapGroup1(SnovaParameters params)
qAlpha2 = new byte[m][alpha][16];
}
- public int decode(byte[] input)
+ public int decode(byte[] input, int len)
{
- int inOff = decodeP(input, 0, p11);
- inOff = decodeP(input, inOff, p12);
- inOff = decodeP(input, inOff, p21);
- inOff = decodeAlpha(input, inOff, aAlpha);
- inOff = decodeAlpha(input, inOff, bAlpha);
- inOff = decodeAlpha(input, inOff, qAlpha1);
- inOff = decodeAlpha(input, inOff, qAlpha2);
+ int inOff = decodeP(input, 0, p11, len);
+ inOff += decodeP(input, inOff, p12, len - inOff);
+ inOff += decodeP(input, inOff, p21, len - inOff);
+ inOff += decodeAlpha(input, inOff, aAlpha, len - inOff);
+ inOff += decodeAlpha(input, inOff, bAlpha, len - inOff);
+ inOff += decodeAlpha(input, inOff, qAlpha1, len - inOff);
+ inOff += decodeAlpha(input, inOff, qAlpha2, len - inOff);
return inOff;
}
- private int decodeP(byte[] input, int inOff, byte[][][][] p)
+ private int decodeP(byte[] input, int inOff, byte[][][][] p, int len)
{
+ int rlt = 0;
for (int i = 0; i < p.length; ++i)
{
- inOff = decodeAlpha(input, inOff, p[i]);
+ rlt += decodeAlpha(input, inOff + rlt, p[i], len);
}
- return inOff;
+ return rlt;
}
- private int decodeAlpha(byte[] input, int inOff, byte[][][] alpha)
+ private int decodeAlpha(byte[] input, int inOff, byte[][][] alpha, int len)
{
+ int rlt = 0;
for (int i = 0; i < alpha.length; ++i)
{
for (int j = 0; j < alpha[i].length; ++j)
{
- GF16Utils.decode(input, inOff, alpha[i][j], 0, alpha[i][j].length);
- inOff += (alpha[i][j].length + 1) >> 1;
+ int tmp = Math.min(alpha[i][j].length, len << 1);
+ GF16Utils.decode(input, inOff + rlt, alpha[i][j], 0, tmp);
+ rlt += (tmp + 1) >> 1;
+ len -= (tmp + 1) >> 1;
}
}
- return inOff;
+ return rlt;
}
}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyPairGenerator.java
index 81d814ad0f..a2c2a51a62 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyPairGenerator.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyPairGenerator.java
@@ -5,10 +5,14 @@
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.KeyGenerationParameters;
import org.bouncycastle.crypto.digests.SHAKEDigest;
import org.bouncycastle.crypto.engines.AESEngine;
+import org.bouncycastle.crypto.modes.CTRModeCipher;
+import org.bouncycastle.crypto.modes.SICBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.util.Arrays;
public class SnovaKeyPairGenerator
@@ -161,7 +165,7 @@ private void generateKeysCore(SnovaKeyElements keyElements, byte[] pkSeed, byte[
genSeedsAndT12(keyElements.T12, skSeed);
// Generate map components
-// genABQP(keyElements.map1, pkSeed);
+ genABQP(keyElements.map1, pkSeed);
//
// // Generate F matrices
// genF(keyElements.map2, keyElements.map1, keyElements.T12);
@@ -210,7 +214,8 @@ private void genABQP(MapGroup1 map1, byte[] pkSeed)
int n = v + o;
int gf16sPrngPublic = lsq * (2 * m * alpha + m * (n * n - m * m)) + l * 2 * m * alpha;
- byte[] prngOutput = new byte[gf16sPrngPublic];
+ byte[] qTemp = new byte[(m * alpha * 16 + m * alpha * 16) / l];
+ byte[] prngOutput = new byte[(gf16sPrngPublic + 1) >> 1];
if (params.isPkExpandShake())
{
@@ -221,19 +226,45 @@ private void genABQP(MapGroup1 map1, byte[] pkSeed)
}
else
{
+ // Create a 16-byte IV (all zeros)
+ byte[] iv = new byte[16]; // automatically zero-initialized
// AES-CTR-based expansion
- AESEngine aes = new AESEngine();
- aes.init(true, new KeyParameter(pkSeed));
+ // Set up AES engine in CTR (SIC) mode.
+ BlockCipher aesEngine = AESEngine.newInstance();
+ // SICBlockCipher implements CTR mode for AES.
+ CTRModeCipher ctrCipher = SICBlockCipher.newInstance(aesEngine);
+ ParametersWithIV params = new ParametersWithIV(new KeyParameter(pkSeed), iv);
+ ctrCipher.init(true, params);
+ int blockSize = ctrCipher.getBlockSize(); // typically 16 bytes
+ byte[] zeroBlock = new byte[blockSize]; // block of zeros
+ byte[] blockOut = new byte[blockSize];
+
+ int offset = 0;
+ // Process full blocks
+ while (offset + blockSize <= prngOutput.length)
+ {
+ ctrCipher.processBlock(zeroBlock, 0, blockOut, 0);
+ System.arraycopy(blockOut, 0, prngOutput, offset, blockSize);
+ offset += blockSize;
+ }
+ // Process any remaining partial block.
+ if (offset < prngOutput.length)
+ {
+ ctrCipher.processBlock(zeroBlock, 0, blockOut, 0);
+ int remaining = prngOutput.length - offset;
+ System.arraycopy(blockOut, 0, prngOutput, offset, remaining);
+ }
+
for (int i = 0; i < prngOutput.length; i += 16)
{
byte[] block = new byte[16];
- aes.processBlock(block, 0, block, 0);
+ ctrCipher.processBlock(block, 0, block, 0);
System.arraycopy(block, 0, prngOutput, i, Math.min(16, prngOutput.length - i));
}
}
// Convert bytes to GF16 structures
-// int inOff = map1.decode(prngOutput);
+ int inOff = map1.decode(prngOutput, (gf16sPrngPublic - qTemp.length) >> 1);
//
// // Post-processing for invertible matrices
// for (GF16Matrix matrix : map1.Aalpha)
From 7dadecd49cf1fe82a3ae1263e760e6e94dba196f Mon Sep 17 00:00:00 2001
From: David Hook
Date: Mon, 10 Mar 2025 16:03:52 +1100
Subject: [PATCH 183/890] removed use of JUnit from simple test.
---
.../java/org/bouncycastle/crypto/test/SAKKEKEMSTest.java | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/SAKKEKEMSTest.java b/core/src/test/java/org/bouncycastle/crypto/test/SAKKEKEMSTest.java
index fa9d73f1e4..d21555274d 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/SAKKEKEMSTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/SAKKEKEMSTest.java
@@ -3,7 +3,6 @@
import java.math.BigInteger;
import java.security.SecureRandom;
-
import org.bouncycastle.crypto.SecretWithEncapsulation;
import org.bouncycastle.crypto.kems.SAKKEKEMExtractor;
import org.bouncycastle.crypto.kems.SAKKEKEMSGenerator;
@@ -15,7 +14,6 @@
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.FixedSecureRandom;
import org.bouncycastle.util.test.SimpleTest;
-import org.junit.Assert;
public class SAKKEKEMSTest
extends SimpleTest
@@ -148,7 +146,7 @@ private void testTestVector()
ECPoint P = curve.createPoint(Px, Py);
ECPoint computed_Z = P.multiply(z).normalize();
- Assert.assertTrue(computed_Z.equals(curve.createPoint(Zx, Zy)));
+ isTrue(computed_Z.equals(curve.createPoint(Zx, Zy)));
SecureRandom random = new FixedSecureRandom(new FixedSecureRandom.Source[]{new FixedSecureRandom.Data(ssv)});
SAKKEPublicKeyParameters b_publicKey = new SAKKEPublicKeyParameters(new BigInteger(b), curve.createPoint(Zx, Zy));
@@ -158,7 +156,7 @@ private void testTestVector()
SAKKEKEMExtractor extractor = new SAKKEKEMExtractor(new SAKKEPrivateKeyParameters(z, b_publicKey));
byte[] test = extractor.extractSecret(rlt.getEncapsulation());
- Assert.assertTrue(Arrays.areEqual(test, ssv));
+ isTrue(Arrays.areEqual(test, ssv));
}
private void testRandom()
@@ -172,6 +170,6 @@ private void testRandom()
SecretWithEncapsulation rlt = generator.generateEncapsulated(b_pub);
SAKKEKEMExtractor extractor = new SAKKEKEMExtractor(b_priv);
byte[] test = extractor.extractSecret(rlt.getEncapsulation());
- Assert.assertTrue(Arrays.areEqual(test, ssv));
+ isTrue(Arrays.areEqual(test, ssv));
}
}
From a5c27a408d0bffe81cd39640b710a0cc17a8c5e6 Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Mon, 10 Mar 2025 12:59:35 +0700
Subject: [PATCH 184/890] Cleanup array comparisons in tests
- see https://github.com/bcgit/bc-java/pull/2012
---
.../jce/provider/test/DESedeTest.java | 59 ++++---------------
.../jce/provider/test/FIPSDESTest.java | 28 ++-------
.../jce/provider/test/PSSTest.java | 29 ++-------
.../jce/provider/test/RSATest.java | 34 +++--------
.../jce/provider/test/PSSTest.java | 26 +-------
.../jce/provider/test/DHTest.java | 24 +-------
.../jce/provider/test/PSSTest.java | 30 ++--------
7 files changed, 36 insertions(+), 194 deletions(-)
diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/DESedeTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/DESedeTest.java
index 684fb17335..416e0cb55b 100644
--- a/prov/src/test/java/org/bouncycastle/jce/provider/test/DESedeTest.java
+++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/DESedeTest.java
@@ -19,6 +19,7 @@
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
@@ -79,50 +80,11 @@ public String getName()
return "DESEDE";
}
- private boolean equalArray(
- byte[] a,
- byte[] b)
+ private static boolean equalPrefix(byte[] a, byte[] b, int length)
{
- if (a.length != b.length)
- {
- return false;
- }
-
- for (int i = 0; i != a.length; i++)
- {
- if (a[i] != b[i])
- {
- return false;
- }
- }
-
- return true;
- }
-
- private boolean equalArray(
- byte[] a,
- byte[] b,
- int length)
- {
- if (a.length < length)
- {
- return false;
- }
-
- if (b.length < length)
- {
- return false;
- }
-
- for (int i = 0; i != length; i++)
- {
- if (a[i] != b[i])
- {
- return false;
- }
- }
-
- return true;
+ return a.length >= length
+ && b.length >= length
+ && Arrays.areEqual(a, 0, length, b, 0, length);
}
private void wrapTest(
@@ -142,7 +104,7 @@ private void wrapTest(
try
{
byte[] cText = wrapper.wrap(new SecretKeySpec(in, alg));
- if (!equalArray(cText, out))
+ if (!Arrays.areEqual(cText, out))
{
fail("failed wrap test " + id + " expected " + new String(Hex.encode(out)) + " got " + new String(Hex.encode(cText)));
}
@@ -157,7 +119,7 @@ private void wrapTest(
try
{
Key pText = wrapper.unwrap(out, alg, Cipher.SECRET_KEY);
- if (!equalArray(pText.getEncoded(), in))
+ if (!Arrays.areEqual(pText.getEncoded(), in))
{
fail("failed unwrap test " + id + " expected " + new String(Hex.encode(in)) + " got " + new String(Hex.encode(pText.getEncoded())));
}
@@ -242,7 +204,7 @@ public void test(
bytes = bOut.toByteArray();
- if (!equalArray(bytes, output))
+ if (!Arrays.areEqual(bytes, output))
{
fail(alg + " failed encryption - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(bytes)));
}
@@ -265,13 +227,14 @@ public void test(
bytes[i] = (byte)dIn.read();
}
dIn.readFully(bytes, input.length / 2, bytes.length - input.length / 2);
+ dIn.close();
}
catch (Exception e)
{
fail(alg + " failed encryption - " + e.toString());
}
- if (!equalArray(bytes, input))
+ if (!Arrays.areEqual(bytes, input))
{
fail(alg + " failed decryption - expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(bytes)));
}
@@ -284,7 +247,7 @@ public void test(
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(alg, "BC");
DESedeKeySpec keySpec = (DESedeKeySpec)keyFactory.getKeySpec((SecretKey)key, DESedeKeySpec.class);
- if (!equalArray(key.getEncoded(), keySpec.getKey(), 16))
+ if (!equalPrefix(key.getEncoded(), keySpec.getKey(), 16))
{
fail(alg + " KeySpec does not match key.");
}
diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/FIPSDESTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/FIPSDESTest.java
index 80024d458a..f9af706d6c 100644
--- a/prov/src/test/java/org/bouncycastle/jce/provider/test/FIPSDESTest.java
+++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/FIPSDESTest.java
@@ -16,6 +16,7 @@
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTestResult;
import org.bouncycastle.util.test.Test;
@@ -54,26 +55,6 @@ public String getName()
return "FIPSDESTest";
}
- private boolean equalArray(
- byte[] a,
- byte[] b)
- {
- if (a.length != b.length)
- {
- return false;
- }
-
- for (int i = 0; i != a.length; i++)
- {
- if (a[i] != b[i])
- {
- return false;
- }
- }
-
- return true;
- }
-
public TestResult test(
String algorithm,
byte[] input,
@@ -89,8 +70,6 @@ public TestResult test(
try
{
- String baseAlgorithm;
-
key = new SecretKeySpec(Hex.decode("0123456789abcdef"), "DES");
in = Cipher.getInstance(algorithm, "BC");
@@ -151,7 +130,7 @@ public TestResult test(
bytes = bOut.toByteArray();
- if (!equalArray(bytes, output))
+ if (!Arrays.areEqual(bytes, output))
{
return new SimpleTestResult(false, getName() + ": " + algorithm + " failed encryption - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(bytes)));
}
@@ -174,13 +153,14 @@ public TestResult test(
bytes[i] = (byte)dIn.read();
}
dIn.readFully(bytes, input.length / 2, bytes.length - input.length / 2);
+ dIn.close();
}
catch (Exception e)
{
return new SimpleTestResult(false, getName() + ": " + algorithm + " failed encryption - " + e.toString());
}
- if (!equalArray(bytes, input))
+ if (!Arrays.areEqual(bytes, input))
{
return new SimpleTestResult(false, getName() + ": " + algorithm + " failed decryption - expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(bytes)));
}
diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/PSSTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/PSSTest.java
index 75931bf195..462c06d5d7 100644
--- a/prov/src/test/java/org/bouncycastle/jce/provider/test/PSSTest.java
+++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/PSSTest.java
@@ -47,27 +47,6 @@ public void nextBytes(
}
}
- private boolean arrayEquals(
- byte[] a,
- byte[] b)
- {
- if (a.length != b.length)
- {
- return false;
- }
-
- for (int i = 0; i != a.length; i++)
- {
- if (a[i] != b[i])
- {
- return false;
- }
- }
-
- return true;
- }
-
-
private RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
new BigInteger("010001",16));
@@ -109,7 +88,7 @@ public void performTest() throws Exception
s.update(msg1a);
byte[] sig = s.sign();
- if (!arrayEquals(sig1a, sig))
+ if (!Arrays.areEqual(sig1a, sig))
{
fail("PSS Sign test expected " + new String(Hex.encode(sig1a)) + " got " + new String(Hex.encode(sig)));
}
@@ -135,7 +114,7 @@ public void performTest() throws Exception
}
AlgorithmParameters pss = s.getParameters();
- if (!arrayEquals(pss.getEncoded(), new byte[] { 0x30, 0x00 }))
+ if (!Arrays.areEqual(pss.getEncoded(), new byte[]{ 0x30, 0x00 }))
{
fail("failed default encoding test.");
}
@@ -148,7 +127,7 @@ public void performTest() throws Exception
pss = s.getParameters();
- if (!arrayEquals(sig1b, sig))
+ if (!Arrays.areEqual(sig1b, sig))
{
fail("PSS Sign test expected " + new String(Hex.encode(sig1b)) + " got " + new String(Hex.encode(sig)));
}
@@ -251,7 +230,7 @@ public void performTest() throws Exception
pss = s.getParameters();
- if (!arrayEquals(sig1c, sig))
+ if (!Arrays.areEqual(sig1c, sig))
{
fail("PSS Sign test expected " + new String(Hex.encode(sig1c)) + " got " + new String(Hex.encode(sig)));
}
diff --git a/prov/src/test/jdk1.1/org/bouncycastle/jce/provider/test/RSATest.java b/prov/src/test/jdk1.1/org/bouncycastle/jce/provider/test/RSATest.java
index e756f401a5..16e36be2d9 100644
--- a/prov/src/test/jdk1.1/org/bouncycastle/jce/provider/test/RSATest.java
+++ b/prov/src/test/jdk1.1/org/bouncycastle/jce/provider/test/RSATest.java
@@ -12,6 +12,7 @@
import javax.crypto.Cipher;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTestResult;
import org.bouncycastle.util.test.Test;
@@ -50,27 +51,6 @@ public void nextBytes(
}
}
- private boolean arrayEquals(
- byte[] a,
- byte[] b)
- {
- if (a.length != b.length)
- {
- return false;
- }
-
- for (int i = 0; i != a.length; i++)
- {
- if (a[i] != b[i])
- {
- return false;
- }
- }
-
- return true;
- }
-
-
private RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
new BigInteger("11", 16));
@@ -115,7 +95,7 @@ public TestResult perform()
byte[] out = c.doFinal(input);
- if (!arrayEquals(out, output[0]))
+ if (!Arrays.areEqual(out, output[0]))
{
return new SimpleTestResult(false, "NoPadding test failed on encrypt expected " + new String(Hex.encode(output[0])) + " got " + new String(Hex.encode(out)));
}
@@ -124,7 +104,7 @@ public TestResult perform()
out = c.doFinal(out);
- if (!arrayEquals(out, input))
+ if (!Arrays.areEqual(out, input))
{
return new SimpleTestResult(false, "NoPadding test failed on decrypt expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(out)));
}
@@ -138,7 +118,7 @@ public TestResult perform()
out = c.doFinal(input);
- if (!arrayEquals(out, output[1]))
+ if (!Arrays.areEqual(out, output[1]))
{
return new SimpleTestResult(false, "PKCS1 test failed on encrypt expected " + new String(Hex.encode(output[1])) + " got " + new String(Hex.encode(out)));
}
@@ -147,7 +127,7 @@ public TestResult perform()
out = c.doFinal(out);
- if (!arrayEquals(out, input))
+ if (!Arrays.areEqual(out, input))
{
return new SimpleTestResult(false, "PKCS1 test failed on decrypt expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(out)));
}
@@ -161,7 +141,7 @@ public TestResult perform()
out = c.doFinal(input);
- if (!arrayEquals(out, output[2]))
+ if (!Arrays.areEqual(out, output[2]))
{
return new SimpleTestResult(false, "OAEP test failed on encrypt expected " + new String(Hex.encode(output[2])) + " got " + new String(Hex.encode(out)));
}
@@ -170,7 +150,7 @@ public TestResult perform()
out = c.doFinal(out);
- if (!arrayEquals(out, input))
+ if (!Arrays.areEqual(out, input))
{
return new SimpleTestResult(false, "OAEP test failed on decrypt expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(out)));
}
diff --git a/prov/src/test/jdk1.3/org/bouncycastle/jce/provider/test/PSSTest.java b/prov/src/test/jdk1.3/org/bouncycastle/jce/provider/test/PSSTest.java
index bd1dc32f35..f0d567501a 100644
--- a/prov/src/test/jdk1.3/org/bouncycastle/jce/provider/test/PSSTest.java
+++ b/prov/src/test/jdk1.3/org/bouncycastle/jce/provider/test/PSSTest.java
@@ -11,6 +11,7 @@
import java.security.spec.RSAPublicKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTestResult;
import org.bouncycastle.util.test.Test;
@@ -38,27 +39,6 @@ public void nextBytes(
}
}
- private boolean arrayEquals(
- byte[] a,
- byte[] b)
- {
- if (a.length != b.length)
- {
- return false;
- }
-
- for (int i = 0; i != a.length; i++)
- {
- if (a[i] != b[i])
- {
- return false;
- }
- }
-
- return true;
- }
-
-
private RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
new BigInteger("010001",16));
@@ -98,7 +78,7 @@ public TestResult perform()
s.update(msg1a);
byte[] sig = s.sign();
- if (!arrayEquals(sig1a, sig))
+ if (!Arrays.areEqual(sig1a, sig))
{
return new SimpleTestResult(false, "PSS Sign test expected " + new String(Hex.encode(sig1a)) + " got " + new String(Hex.encode(sig)));
}
@@ -118,7 +98,7 @@ public TestResult perform()
s.update(msg1a);
sig = s.sign();
- if (!arrayEquals(sig1b, sig))
+ if (!Arrays.areEqual(sig1b, sig))
{
return new SimpleTestResult(false, "PSS Sign test expected " + new String(Hex.encode(sig1b)) + " got " + new String(Hex.encode(sig)));
}
diff --git a/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/DHTest.java b/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/DHTest.java
index 19c30d6cef..b394a1572a 100644
--- a/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/DHTest.java
+++ b/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/DHTest.java
@@ -26,6 +26,7 @@
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTestResult;
import org.bouncycastle.util.test.Test;
@@ -252,7 +253,7 @@ private TestResult testRandom(
// a and a2 should be equivalent!
byte[] encodeParams_2 = a2.getEncoded();
- if (!arrayEquals(encodeParams, encodeParams_2))
+ if (!Arrays.areEqual(encodeParams, encodeParams_2))
{
return new SimpleTestResult(false, this.getName() + ": encode/decode parameters failed");
}
@@ -474,27 +475,6 @@ private TestResult testExceptions()
return new SimpleTestResult(true, this.getName() + ": Okay");
}
-
- private boolean arrayEquals(
- byte[] a,
- byte[] b)
- {
- if (a.length != b.length)
- {
- return false;
- }
-
- for (int i = 0; i != a.length; i++)
- {
- if (a[i] != b[i])
- {
- return false;
- }
- }
-
- return true;
- }
-
public TestResult perform()
{
diff --git a/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/PSSTest.java b/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/PSSTest.java
index 3cba08eb79..672a6b9760 100644
--- a/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/PSSTest.java
+++ b/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/PSSTest.java
@@ -15,6 +15,7 @@
import java.security.spec.RSAPublicKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTestResult;
import org.bouncycastle.util.test.Test;
@@ -41,27 +42,6 @@ public void nextBytes(
}
}
- private boolean arrayEquals(
- byte[] a,
- byte[] b)
- {
- if (a.length != b.length)
- {
- return false;
- }
-
- for (int i = 0; i != a.length; i++)
- {
- if (a[i] != b[i])
- {
- return false;
- }
- }
-
- return true;
- }
-
-
private RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
new BigInteger("010001",16));
@@ -103,7 +83,7 @@ public TestResult perform()
s.update(msg1a);
byte[] sig = s.sign();
- if (!arrayEquals(sig1a, sig))
+ if (!Arrays.areEqual(sig1a, sig))
{
return new SimpleTestResult(false, "PSS Sign test expected " + new String(Hex.encode(sig1a)) + " got " + new String(Hex.encode(sig)));
}
@@ -129,7 +109,7 @@ public TestResult perform()
}
AlgorithmParameters pss = s.getParameters();
- if (!arrayEquals(pss.getEncoded(), new byte[] { 0x30, 0x00 }))
+ if (!Arrays.areEqual(pss.getEncoded(), new byte[] { 0x30, 0x00 }))
{
return new SimpleTestResult(false, "failed default encoding test.");
}
@@ -142,7 +122,7 @@ public TestResult perform()
pss = s.getParameters();
- if (!arrayEquals(sig1b, sig))
+ if (!Arrays.areEqual(sig1b, sig))
{
return new SimpleTestResult(false, "PSS Sign test expected " + new String(Hex.encode(sig1b)) + " got " + new String(Hex.encode(sig)));
}
@@ -171,7 +151,7 @@ public TestResult perform()
pss = s.getParameters();
- if (!arrayEquals(sig1c, sig))
+ if (!Arrays.areEqual(sig1c, sig))
{
return new SimpleTestResult(false, "PSS Sign test expected " + new String(Hex.encode(sig1c)) + " got " + new String(Hex.encode(sig)));
}
From bffd6a7e90aedd40653146557d0b527eef2ac9d7 Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Mon, 10 Mar 2025 13:27:03 +0700
Subject: [PATCH 185/890] TLS: Update ML-KEM codepoints
- draft-connolly-tls-mlkem-key-agreement-05
---
tls/src/main/java/org/bouncycastle/tls/NamedGroup.java | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/tls/src/main/java/org/bouncycastle/tls/NamedGroup.java b/tls/src/main/java/org/bouncycastle/tls/NamedGroup.java
index b8fc46d1c5..a69ecd1bc9 100644
--- a/tls/src/main/java/org/bouncycastle/tls/NamedGroup.java
+++ b/tls/src/main/java/org/bouncycastle/tls/NamedGroup.java
@@ -110,11 +110,11 @@ public class NamedGroup
public static final int OQS_mlkem1024 = 0x0249;
/*
- * draft-connolly-tls-mlkem-key-agreement-03
+ * draft-connolly-tls-mlkem-key-agreement-05
*/
- public static final int MLKEM512 = 0x0512;
- public static final int MLKEM768 = 0x0768;
- public static final int MLKEM1024 = 0x1024;
+ public static final int MLKEM512 = 0x0200;
+ public static final int MLKEM768 = 0x0201;
+ public static final int MLKEM1024 = 0x0202;
/* Names of the actual underlying elliptic curves (not necessarily matching the NamedGroup names). */
private static final String[] CURVE_NAMES = new String[]{ "sect163k1", "sect163r1", "sect163r2", "sect193r1",
From 0f08ecdd242eb13c63a52521ca9fb4957fbae3b4 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Mon, 10 Mar 2025 21:26:27 +1100
Subject: [PATCH 186/890] added PKCS12 example using PBMac1 additional PQC
tests added support for AES_WRAP_PAD to CMS.
---
.../asn1/x509/PrivateKeyStatement.java | 91 +++++++++++++++++
.../asn1/x509/X509AttributeIdentifiers.java | 28 +++---
.../crmf/CertificateRepMessageBuilder.java | 1 +
.../org/bouncycastle/cms/CMSAlgorithm.java | 3 +
.../org/bouncycastle/cms/jcajce/CMSUtils.java | 9 +-
.../bc/BcPKCS12PBMac1CalculatorBuilder.java | 10 +-
.../bouncycastle/pkcs/test/PQCPKCS10Test.java | 97 +++++++++++++++++++
.../bouncycastle/pkcs/test/PfxPduTest.java | 67 +++++++++++++
.../pqc/jcajce/provider/util/WrapUtil.java | 4 +-
.../jce/provider/test/PQCDHTest.java | 89 +++++++++++++++++
10 files changed, 378 insertions(+), 21 deletions(-)
create mode 100644 core/src/main/java/org/bouncycastle/asn1/x509/PrivateKeyStatement.java
create mode 100644 pkix/src/test/java/org/bouncycastle/pkcs/test/PQCPKCS10Test.java
create mode 100644 prov/src/test/java/org/bouncycastle/jce/provider/test/PQCDHTest.java
diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/PrivateKeyStatement.java b/core/src/main/java/org/bouncycastle/asn1/x509/PrivateKeyStatement.java
new file mode 100644
index 0000000000..f03c66886b
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/asn1/x509/PrivateKeyStatement.java
@@ -0,0 +1,91 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.pkcs.IssuerAndSerialNumber;
+
+/**
+ *
+ * PrivateKeyStatement ::= SEQUENCE {
+ * signer IssuerAndSerialNumber,
+ * cert Certificate OPTIONAL }
+ *
+ */
+public class PrivateKeyStatement
+ extends ASN1Object
+{
+ private final IssuerAndSerialNumber signer;
+ private final Certificate cert;
+
+ public static PrivateKeyStatement getInstance(Object obj)
+ {
+ if (obj instanceof PrivateKeyStatement)
+ {
+ return (PrivateKeyStatement)obj;
+ }
+
+ if (obj != null)
+ {
+ return new PrivateKeyStatement(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ private PrivateKeyStatement(ASN1Sequence seq)
+ {
+ if (seq.size() == 1)
+ {
+ this.signer = IssuerAndSerialNumber.getInstance(seq.getObjectAt(0));
+ this.cert = null;
+ }
+ else if (seq.size() == 2)
+ {
+ this.signer = IssuerAndSerialNumber.getInstance(seq.getObjectAt(0));
+ this.cert = Certificate.getInstance(seq.getObjectAt(1));
+ }
+ else
+ {
+ throw new IllegalArgumentException("unknown sequence in PrivateKeyStatement");
+ }
+ }
+
+ public PrivateKeyStatement(IssuerAndSerialNumber signer)
+ {
+ this.signer = signer;
+ this.cert = null;
+ }
+
+ public PrivateKeyStatement(Certificate cert)
+ {
+ this.signer = new IssuerAndSerialNumber(cert.getIssuer(), cert.getSerialNumber().getValue());
+ this.cert = cert;
+ }
+
+ public IssuerAndSerialNumber getSigner()
+ {
+ return signer;
+ }
+
+ public Certificate getCert()
+ {
+ return cert;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector(2);
+
+ v.add(signer);
+
+ if (cert != null)
+ {
+ v.add(cert);
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/X509AttributeIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/x509/X509AttributeIdentifiers.java
index 0ed12f7eb6..a64f721dc8 100644
--- a/core/src/main/java/org/bouncycastle/asn1/x509/X509AttributeIdentifiers.java
+++ b/core/src/main/java/org/bouncycastle/asn1/x509/X509AttributeIdentifiers.java
@@ -7,23 +7,25 @@ public interface X509AttributeIdentifiers
/**
* @deprecated use id_at_role
*/
- static final ASN1ObjectIdentifier RoleSyntax = new ASN1ObjectIdentifier("2.5.4.72");
+ ASN1ObjectIdentifier RoleSyntax = new ASN1ObjectIdentifier("2.5.4.72");
- static final ASN1ObjectIdentifier id_pe_ac_auditIdentity = X509ObjectIdentifiers.id_pe.branch("4");
- static final ASN1ObjectIdentifier id_pe_aaControls = X509ObjectIdentifiers.id_pe.branch("6");
- static final ASN1ObjectIdentifier id_pe_ac_proxying = X509ObjectIdentifiers.id_pe.branch("10");
+ ASN1ObjectIdentifier id_pe_ac_auditIdentity = X509ObjectIdentifiers.id_pe.branch("4");
+ ASN1ObjectIdentifier id_pe_aaControls = X509ObjectIdentifiers.id_pe.branch("6");
+ ASN1ObjectIdentifier id_pe_ac_proxying = X509ObjectIdentifiers.id_pe.branch("10");
- static final ASN1ObjectIdentifier id_ce_targetInformation= X509ObjectIdentifiers.id_ce.branch("55");
+ ASN1ObjectIdentifier id_ce_targetInformation = X509ObjectIdentifiers.id_ce.branch("55");
- static final ASN1ObjectIdentifier id_aca = X509ObjectIdentifiers.id_pkix.branch("10");
+ ASN1ObjectIdentifier id_aca = X509ObjectIdentifiers.id_pkix.branch("10");
- static final ASN1ObjectIdentifier id_aca_authenticationInfo = id_aca.branch("1");
- static final ASN1ObjectIdentifier id_aca_accessIdentity = id_aca.branch("2");
- static final ASN1ObjectIdentifier id_aca_chargingIdentity = id_aca.branch("3");
- static final ASN1ObjectIdentifier id_aca_group = id_aca.branch("4");
+ ASN1ObjectIdentifier id_aca_authenticationInfo = id_aca.branch("1");
+ ASN1ObjectIdentifier id_aca_accessIdentity = id_aca.branch("2");
+ ASN1ObjectIdentifier id_aca_chargingIdentity = id_aca.branch("3");
+ ASN1ObjectIdentifier id_aca_group = id_aca.branch("4");
// { id-aca 5 } is reserved
- static final ASN1ObjectIdentifier id_aca_encAttrs = id_aca.branch("6");
+ ASN1ObjectIdentifier id_aca_encAttrs = id_aca.branch("6");
- static final ASN1ObjectIdentifier id_at_role = new ASN1ObjectIdentifier("2.5.4.72");
- static final ASN1ObjectIdentifier id_at_clearance = new ASN1ObjectIdentifier("2.5.1.5.55");
+ ASN1ObjectIdentifier id_at_role = new ASN1ObjectIdentifier("2.5.4.72");
+ ASN1ObjectIdentifier id_at_clearance = new ASN1ObjectIdentifier("2.5.1.5.55");
+
+ ASN1ObjectIdentifier id_at_privateKeyStatement = new ASN1ObjectIdentifier("1.3.6.1.4.1.22112.2.1");
}
diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/CertificateRepMessageBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/CertificateRepMessageBuilder.java
index e6eabf140e..0b913218e5 100644
--- a/pkix/src/main/java/org/bouncycastle/cert/crmf/CertificateRepMessageBuilder.java
+++ b/pkix/src/main/java/org/bouncycastle/cert/crmf/CertificateRepMessageBuilder.java
@@ -30,6 +30,7 @@ public CertificateRepMessageBuilder(X509CertificateHolder... caCerts)
this.caCerts[i] = new CMPCertificate(caCerts[i].toASN1Structure());
}
}
+
public CertificateRepMessageBuilder addCertificateResponse(CertificateResponse response)
{
responses.add(response.toASN1Structure());
diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSAlgorithm.java b/pkix/src/main/java/org/bouncycastle/cms/CMSAlgorithm.java
index 103659c424..0418b5ac6f 100644
--- a/pkix/src/main/java/org/bouncycastle/cms/CMSAlgorithm.java
+++ b/pkix/src/main/java/org/bouncycastle/cms/CMSAlgorithm.java
@@ -46,6 +46,9 @@ public class CMSAlgorithm
public static final ASN1ObjectIdentifier AES128_WRAP = NISTObjectIdentifiers.id_aes128_wrap.intern();
public static final ASN1ObjectIdentifier AES192_WRAP = NISTObjectIdentifiers.id_aes192_wrap.intern();
public static final ASN1ObjectIdentifier AES256_WRAP = NISTObjectIdentifiers.id_aes256_wrap.intern();
+ public static final ASN1ObjectIdentifier AES128_WRAP_PAD = NISTObjectIdentifiers.id_aes128_wrap_pad.intern();
+ public static final ASN1ObjectIdentifier AES192_WRAP_PAD = NISTObjectIdentifiers.id_aes192_wrap_pad.intern();
+ public static final ASN1ObjectIdentifier AES256_WRAP_PAD = NISTObjectIdentifiers.id_aes256_wrap_pad.intern();
public static final ASN1ObjectIdentifier CAMELLIA128_WRAP = NTTObjectIdentifiers.id_camellia128_wrap.intern();
public static final ASN1ObjectIdentifier CAMELLIA192_WRAP = NTTObjectIdentifiers.id_camellia192_wrap.intern();
public static final ASN1ObjectIdentifier CAMELLIA256_WRAP = NTTObjectIdentifiers.id_camellia256_wrap.intern();
diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/CMSUtils.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/CMSUtils.java
index 9d9584f0bd..4d79bec90b 100644
--- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/CMSUtils.java
+++ b/pkix/src/main/java/org/bouncycastle/cms/jcajce/CMSUtils.java
@@ -52,6 +52,9 @@ class CMSUtils
wrapAlgNames.put(CMSAlgorithm.AES128_WRAP, "AESWRAP");
wrapAlgNames.put(CMSAlgorithm.AES192_WRAP, "AESWRAP");
wrapAlgNames.put(CMSAlgorithm.AES256_WRAP, "AESWRAP");
+ wrapAlgNames.put(CMSAlgorithm.AES128_WRAP_PAD, "AES-KWP");
+ wrapAlgNames.put(CMSAlgorithm.AES192_WRAP_PAD, "AES-KWP");
+ wrapAlgNames.put(CMSAlgorithm.AES256_WRAP_PAD, "AES-KWP");
}
static
@@ -264,15 +267,15 @@ static Cipher createAsymmetricWrapper(JcaJceHelper helper, ASN1ObjectIdentifier
public static int getKekSize(ASN1ObjectIdentifier symWrapAlg)
{
// TODO: add table
- if (symWrapAlg.equals(CMSAlgorithm.AES256_WRAP))
+ if (symWrapAlg.equals(CMSAlgorithm.AES256_WRAP) || symWrapAlg.equals(CMSAlgorithm.AES256_WRAP_PAD))
{
return 32;
}
- else if (symWrapAlg.equals(CMSAlgorithm.AES128_WRAP))
+ else if (symWrapAlg.equals(CMSAlgorithm.AES128_WRAP) || symWrapAlg.equals(CMSAlgorithm.AES128_WRAP_PAD))
{
return 16;
}
- else if (symWrapAlg.equals(CMSAlgorithm.AES192_WRAP))
+ else if (symWrapAlg.equals(CMSAlgorithm.AES192_WRAP) || symWrapAlg.equals(CMSAlgorithm.AES192_WRAP_PAD))
{
return 24;
}
diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/bc/BcPKCS12PBMac1CalculatorBuilder.java b/pkix/src/main/java/org/bouncycastle/pkcs/bc/BcPKCS12PBMac1CalculatorBuilder.java
index d1deb1445b..bc3480cf46 100644
--- a/pkix/src/main/java/org/bouncycastle/pkcs/bc/BcPKCS12PBMac1CalculatorBuilder.java
+++ b/pkix/src/main/java/org/bouncycastle/pkcs/bc/BcPKCS12PBMac1CalculatorBuilder.java
@@ -1,5 +1,7 @@
package org.bouncycastle.pkcs.bc;
+import java.io.IOException;
+
import org.bouncycastle.asn1.pkcs.PBKDF2Params;
import org.bouncycastle.asn1.pkcs.PBMAC1Params;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
@@ -8,8 +10,6 @@
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.pkcs.PKCS12MacCalculatorBuilder;
-import java.io.IOException;
-
public class BcPKCS12PBMac1CalculatorBuilder
implements PKCS12MacCalculatorBuilder
{
@@ -27,7 +27,11 @@ public BcPKCS12PBMac1CalculatorBuilder(PBMAC1Params pbeMacParams) throws IOExcep
throw new IOException("Key length must be present when using PBMAC1.");
}
}
- // TODO handle other cases
+ else
+ {
+ // TODO: add scrypt support.
+ throw new IllegalArgumentException("unrecognised PBKDF");
+ }
}
@Override
diff --git a/pkix/src/test/java/org/bouncycastle/pkcs/test/PQCPKCS10Test.java b/pkix/src/test/java/org/bouncycastle/pkcs/test/PQCPKCS10Test.java
new file mode 100644
index 0000000000..fd4de9cbf5
--- /dev/null
+++ b/pkix/src/test/java/org/bouncycastle/pkcs/test/PQCPKCS10Test.java
@@ -0,0 +1,97 @@
+package org.bouncycastle.pkcs.test;
+
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Security;
+import java.util.Date;
+
+import junit.framework.TestCase;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x509.BasicConstraints;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.asn1.x509.PrivateKeyStatement;
+import org.bouncycastle.asn1.x509.X509AttributeIdentifiers;
+import org.bouncycastle.cert.CertException;
+import org.bouncycastle.cert.CertIOException;
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cert.X509v3CertificateBuilder;
+import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
+import org.bouncycastle.jcajce.spec.MLDSAParameterSpec;
+import org.bouncycastle.jcajce.spec.MLKEMParameterSpec;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.ContentVerifierProvider;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
+import org.bouncycastle.pkcs.PKCS10CertificationRequest;
+import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder;
+import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
+
+public class PQCPKCS10Test
+ extends TestCase
+{
+ public void setUp()
+ {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+
+ public void testKEMPKCS10()
+ throws Exception
+ {
+ KeyPairGenerator dilKpGen = KeyPairGenerator.getInstance("ML-DSA", "BC");
+
+ dilKpGen.initialize(MLDSAParameterSpec.ml_dsa_65);
+
+ KeyPair dilKp = dilKpGen.generateKeyPair();
+
+ X509CertificateHolder sigCert = makeV3Certificate("CN=ML-KEM Client", dilKp);
+
+ KeyPairGenerator kemKpGen = KeyPairGenerator.getInstance("ML-KEM", "BC");
+
+ kemKpGen.initialize(MLKEMParameterSpec.ml_kem_768);
+
+ KeyPair kemKp = kemKpGen.generateKeyPair();
+
+ PKCS10CertificationRequestBuilder pkcs10Builder = new JcaPKCS10CertificationRequestBuilder(
+ new X500Name("CN=ML-KEM Client"), kemKp.getPublic());
+
+ pkcs10Builder.addAttribute(X509AttributeIdentifiers.id_at_privateKeyStatement,
+ new PrivateKeyStatement(sigCert.toASN1Structure()));
+
+ PKCS10CertificationRequest request = pkcs10Builder.build(
+ new JcaContentSignerBuilder("ML-DSA").setProvider("BC").build(dilKp.getPrivate()));
+
+ assertTrue(request.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider("BC").build(sigCert.getSubjectPublicKeyInfo())));
+ }
+
+ private static X509CertificateHolder makeV3Certificate(String _subDN, KeyPair issKP)
+ throws OperatorCreationException, CertException, CertIOException
+ {
+ PrivateKey issPriv = issKP.getPrivate();
+ PublicKey issPub = issKP.getPublic();
+
+ X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(
+ new X500Name(_subDN),
+ BigInteger.valueOf(System.currentTimeMillis()),
+ new Date(System.currentTimeMillis() - 5000L),
+ new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 100)),
+ new X500Name(_subDN),
+ issKP.getPublic());
+
+ certGen.addExtension(Extension.basicConstraints, true, new BasicConstraints(0));
+
+ ContentSigner signer = new JcaContentSignerBuilder("ML-DSA").build(issPriv);
+
+ X509CertificateHolder certHolder = certGen.build(signer);
+
+ ContentVerifierProvider verifier = new JcaContentVerifierProviderBuilder().build(issPub);
+
+ assertTrue(certHolder.isSignatureValid(verifier));
+
+ return certHolder;
+ }
+}
diff --git a/pkix/src/test/java/org/bouncycastle/pkcs/test/PfxPduTest.java b/pkix/src/test/java/org/bouncycastle/pkcs/test/PfxPduTest.java
index 7486ef6df6..3336fccb2e 100644
--- a/pkix/src/test/java/org/bouncycastle/pkcs/test/PfxPduTest.java
+++ b/pkix/src/test/java/org/bouncycastle/pkcs/test/PfxPduTest.java
@@ -35,11 +35,14 @@
import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.Attribute;
import org.bouncycastle.asn1.pkcs.ContentInfo;
+import org.bouncycastle.asn1.pkcs.PBKDF2Params;
+import org.bouncycastle.asn1.pkcs.PBMAC1Params;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
@@ -71,6 +74,7 @@
import org.bouncycastle.pkcs.bc.BcPKCS12MacCalculatorBuilderProvider;
import org.bouncycastle.pkcs.bc.BcPKCS12PBEInputDecryptorProviderBuilder;
import org.bouncycastle.pkcs.bc.BcPKCS12PBEOutputEncryptorBuilder;
+import org.bouncycastle.pkcs.bc.BcPKCS12PBMac1CalculatorBuilder;
import org.bouncycastle.pkcs.bc.BcPKCS12PBMac1CalculatorBuilderProvider;
import org.bouncycastle.pkcs.jcajce.JcaPKCS12SafeBagBuilder;
import org.bouncycastle.pkcs.jcajce.JcaPKCS8EncryptedPrivateKeyInfoBuilder;
@@ -79,6 +83,7 @@
import org.bouncycastle.pkcs.jcajce.JcePKCSPBEInputDecryptorProviderBuilder;
import org.bouncycastle.pkcs.jcajce.JcePKCSPBEOutputEncryptorBuilder;
import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Base64;
import org.junit.function.ThrowingRunnable;
@@ -1136,6 +1141,25 @@ public void testPfxPduMac()
assertFalse(pfx.isMacValid(new BcPKCS12MacCalculatorBuilderProvider(BcDefaultDigestProvider.INSTANCE), "not right".toCharArray()));
}
+ public void testPfxPduMac1()
+ throws Exception
+ {
+ //
+ // set up the keys
+ //
+ KeyFactory fact = KeyFactory.getInstance("RSA", BC);
+ PrivateKey privKey = fact.generatePrivate(privKeySpec);
+ PublicKey pubKey = fact.generatePublic(pubKeySpec);
+
+ X509Certificate[] chain = createCertChain(fact, pubKey);
+
+ PKCS12PfxPdu pfx = createPfxMac1(privKey, pubKey, chain);
+
+ assertTrue(pfx.hasMac());
+ assertTrue(pfx.isMacValid(new BcPKCS12PBMac1CalculatorBuilderProvider(), passwd));
+ assertFalse(pfx.isMacValid(new BcPKCS12PBMac1CalculatorBuilderProvider(), "not right".toCharArray()));
+ }
+
public void testPfxPduPBMac1PBKdf2()
throws Exception
{
@@ -1750,4 +1774,47 @@ private PKCS12PfxPdu createPfx(PrivateKey privKey, PublicKey pubKey, X509Certifi
return pfxPduBuilder.build(new BcPKCS12MacCalculatorBuilder(), passwd);
}
+
+ private PKCS12PfxPdu createPfxMac1(PrivateKey privKey, PublicKey pubKey, X509Certificate[] chain)
+ throws NoSuchAlgorithmException, IOException, PKCSException
+ {
+ JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();
+
+ PKCS12SafeBagBuilder taCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[2]);
+
+ taCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Bouncy Primary Certificate"));
+
+ PKCS12SafeBagBuilder caCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[1]);
+
+ caCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Bouncy Intermediate Certificate"));
+
+ PKCS12SafeBagBuilder eeCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[0]);
+
+ eeCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Eric's Key"));
+ eeCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, extUtils.createSubjectKeyIdentifier(pubKey));
+
+ PKCS12SafeBagBuilder keyBagBuilder = new JcaPKCS12SafeBagBuilder(privKey, new BcPKCS12PBEOutputEncryptorBuilder(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, new CBCBlockCipher(new DESedeEngine())).build(passwd));
+
+ keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Eric's Key"));
+ keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, extUtils.createSubjectKeyIdentifier(pubKey));
+
+ //
+ // construct the actual key store
+ //
+ PKCS12PfxPduBuilder pfxPduBuilder = new PKCS12PfxPduBuilder();
+
+ PKCS12SafeBag[] certs = new PKCS12SafeBag[3];
+
+ certs[0] = eeCertBagBuilder.build();
+ certs[1] = caCertBagBuilder.build();
+ certs[2] = taCertBagBuilder.build();
+
+ pfxPduBuilder.addEncryptedData(new BcPKCS12PBEOutputEncryptorBuilder(PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC, new CBCBlockCipher(new RC2Engine())).build(passwd), certs);
+
+ pfxPduBuilder.addData(keyBagBuilder.build());
+
+ return pfxPduBuilder.build(new BcPKCS12PBMac1CalculatorBuilder(new PBMAC1Params(
+ new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBKDF2, new PBKDF2Params(Strings.toByteArray("saltsalt"), 1024, 256, new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA256))),
+ new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA512))), passwd);
+ }
}
diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/util/WrapUtil.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/util/WrapUtil.java
index 7d1f11900b..41ff97e787 100644
--- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/util/WrapUtil.java
+++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/util/WrapUtil.java
@@ -55,10 +55,10 @@ public static Wrapper getKeyUnwrapper(KTSParameterSpec ktsParameterSpec, byte[]
public static Wrapper getWrapper(String keyAlgorithmName)
{
Wrapper kWrap;
-
+
if (keyAlgorithmName.equalsIgnoreCase("AESWRAP") || keyAlgorithmName.equalsIgnoreCase("AES"))
{
- kWrap = new RFC3394WrapEngine(new AESEngine());
+ kWrap = new RFC3394WrapEngine(AESEngine.newInstance());
}
else if (keyAlgorithmName.equalsIgnoreCase("ARIA"))
{
diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/PQCDHTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/PQCDHTest.java
new file mode 100644
index 0000000000..7c9f299cad
--- /dev/null
+++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/PQCDHTest.java
@@ -0,0 +1,89 @@
+package org.bouncycastle.jce.provider.test;
+
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.Security;
+import java.security.spec.ECGenParameterSpec;
+
+import javax.crypto.KeyAgreement;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+import org.bouncycastle.jcajce.SecretKeyWithEncapsulation;
+import org.bouncycastle.jcajce.spec.HybridValueParameterSpec;
+import org.bouncycastle.jcajce.spec.KEMExtractSpec;
+import org.bouncycastle.jcajce.spec.KEMGenerateSpec;
+import org.bouncycastle.jcajce.spec.MLKEMParameterSpec;
+import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.encoders.Hex;
+import org.bouncycastle.util.test.SimpleTest;
+
+public class PQCDHTest
+ extends SimpleTest
+{
+ public String getName()
+ {
+ return "PQCDHTest";
+ }
+
+ private void testMLKemECDH()
+ throws Exception
+ {
+
+ KeyPairGenerator kemKeyGen = KeyPairGenerator.getInstance("ML-KEM", "BC");
+
+ kemKeyGen.initialize(MLKEMParameterSpec.ml_kem_768);
+
+ KeyPair kemKp = kemKeyGen.generateKeyPair();
+
+ KeyPairGenerator ecKeyGen = KeyPairGenerator.getInstance("EC", "BC");
+
+ ecKeyGen.initialize(new ECGenParameterSpec("P-256"));
+
+ KeyPair ecKp = ecKeyGen.generateKeyPair();
+
+ byte[] ukm = Hex.decode("030f136fa7fef90d185655ed1c6d46bacdb820");
+
+ KeyGenerator keyGen = KeyGenerator.getInstance("ML-KEM", "BC");
+
+ keyGen.init(new KEMGenerateSpec.Builder(kemKp.getPublic(), "DEF", 256).withNoKdf().build());
+
+ SecretKeyWithEncapsulation secEnc1 = (SecretKeyWithEncapsulation)keyGen.generateKey();
+
+ KeyAgreement agreement = KeyAgreement.getInstance("ECCDHwithSHA256CKDF", "BC");
+
+ agreement.init(ecKp.getPrivate(), new HybridValueParameterSpec(secEnc1.getEncoded(), new UserKeyingMaterialSpec(ukm)));
+
+ agreement.doPhase(ecKp.getPublic(), true);
+
+ SecretKey k1 = agreement.generateSecret("AES[256]");
+
+ keyGen.init(new KEMExtractSpec.Builder(kemKp.getPrivate(), secEnc1.getEncapsulation(), "DEF", 256).withNoKdf().build());
+
+ SecretKeyWithEncapsulation secEnc2 = (SecretKeyWithEncapsulation)keyGen.generateKey();
+
+ agreement.init(ecKp.getPrivate(), new HybridValueParameterSpec(secEnc2.getEncoded(), new UserKeyingMaterialSpec(ukm)));
+
+ agreement.doPhase(ecKp.getPublic(), true);
+
+ SecretKey k2 = agreement.generateSecret("AES[256]");
+
+ isTrue(Arrays.areEqual(k1.getEncoded(), k2.getEncoded()));
+ }
+
+ @Override
+ public void performTest()
+ throws Exception
+ {
+ testMLKemECDH();
+ }
+
+ public static void main(String[] args)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ runTest(new PQCDHTest());
+ }
+}
From b5126f406dc0ff6bc71a4811553160e97876237d Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Mon, 10 Mar 2025 19:30:51 +0700
Subject: [PATCH 187/890] Add TlsProtocolKemTest to AllTests
---
tls/src/test/java/org/bouncycastle/tls/test/AllTests.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/tls/src/test/java/org/bouncycastle/tls/test/AllTests.java b/tls/src/test/java/org/bouncycastle/tls/test/AllTests.java
index 64b985fe45..b2ecab6091 100644
--- a/tls/src/test/java/org/bouncycastle/tls/test/AllTests.java
+++ b/tls/src/test/java/org/bouncycastle/tls/test/AllTests.java
@@ -31,6 +31,7 @@ public static Test suite()
suite.addTestSuite(OCSPTest.class);
suite.addTestSuite(PRFTest.class);
suite.addTestSuite(Tls13PSKProtocolTest.class);
+ suite.addTestSuite(TlsProtocolKemTest.class);
suite.addTestSuite(TlsProtocolNonBlockingTest.class);
suite.addTestSuite(TlsProtocolTest.class);
suite.addTestSuite(TlsPSKProtocolTest.class);
From d709e2f3c954f97ad42d99f17087369d86ee0ae0 Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Mon, 10 Mar 2025 19:31:39 +0700
Subject: [PATCH 188/890] Factor out testDHExplicit
---
.../bouncycastle/tls/crypto/test/TlsCryptoTest.java | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/tls/src/test/java/org/bouncycastle/tls/crypto/test/TlsCryptoTest.java b/tls/src/test/java/org/bouncycastle/tls/crypto/test/TlsCryptoTest.java
index 58c66a6a4b..a5ffbc4c30 100644
--- a/tls/src/test/java/org/bouncycastle/tls/crypto/test/TlsCryptoTest.java
+++ b/tls/src/test/java/org/bouncycastle/tls/crypto/test/TlsCryptoTest.java
@@ -221,6 +221,14 @@ public void testDHDomain() throws Exception
implTestDHDomain(new TlsDHConfig(namedGroup, false));
implTestDHDomain(new TlsDHConfig(namedGroup, true));
}
+ }
+
+ public void testDHExplicit() throws Exception
+ {
+ if (!crypto.hasDHAgreement())
+ {
+ return;
+ }
new DefaultTlsDHGroupVerifier()
{{
@@ -236,9 +244,10 @@ public void testDHDomain() throws Exception
assertSame(dhGroup, TlsDHUtils.getStandardGroupForDHParameters(p, g));
int namedGroup = TlsDHUtils.getNamedGroupForDHParameters(p, g);
+
+ // Named groups tested elsewhere
if (NamedGroup.refersToASpecificFiniteField(namedGroup))
{
- // Already tested the named groups
continue;
}
From 3512785c31e9d38e859846e18c07acf9e7277c8b Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Mon, 10 Mar 2025 19:41:15 +0700
Subject: [PATCH 189/890] Change ports for EdDSACredentialsTest
---
.../jsse/provider/test/EdDSACredentialsTest.java | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/tls/src/test/java/org/bouncycastle/jsse/provider/test/EdDSACredentialsTest.java b/tls/src/test/java/org/bouncycastle/jsse/provider/test/EdDSACredentialsTest.java
index a5bb4a4281..8e4c265257 100644
--- a/tls/src/test/java/org/bouncycastle/jsse/provider/test/EdDSACredentialsTest.java
+++ b/tls/src/test/java/org/bouncycastle/jsse/provider/test/EdDSACredentialsTest.java
@@ -28,10 +28,10 @@ protected void setUp()
}
private static final String HOST = "localhost";
- private static final int PORT_NO_12_ED25519 = 9020;
- private static final int PORT_NO_12_ED448 = 9021;
- private static final int PORT_NO_13_ED25519 = 9022;
- private static final int PORT_NO_13_ED448 = 9023;
+ private static final int PORT_NO_12_ED25519 = 9050;
+ private static final int PORT_NO_12_ED448 = 9051;
+ private static final int PORT_NO_13_ED25519 = 9052;
+ private static final int PORT_NO_13_ED448 = 9053;
static class EdDSAClient
implements TestProtocolUtil.BlockingCallable
From 223afeab117be228b12cfd36eb0f11f3b8c97702 Mon Sep 17 00:00:00 2001
From: mwcw
Date: Tue, 11 Mar 2025 10:43:31 +1100
Subject: [PATCH 190/890] Fixed, relates to GitHub #2107
---
.../oer/its/template/ieee1609dot2/IEEE1609dot2.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/util/src/main/java/org/bouncycastle/oer/its/template/ieee1609dot2/IEEE1609dot2.java b/util/src/main/java/org/bouncycastle/oer/its/template/ieee1609dot2/IEEE1609dot2.java
index fc36d74429..37bf6add62 100644
--- a/util/src/main/java/org/bouncycastle/oer/its/template/ieee1609dot2/IEEE1609dot2.java
+++ b/util/src/main/java/org/bouncycastle/oer/its/template/ieee1609dot2/IEEE1609dot2.java
@@ -259,7 +259,8 @@ public Element result(SwitchIndexer indexer)
* EndEntityType ::= BIT STRING {app (0), enrol (1) } (SIZE (8))
*/
public static final OERDefinition.Builder EndEntityType =
- OERDefinition.bitString(8).defaultValue(new DERBitString(new byte[]{0}, 0))
+ OERDefinition.bitString(8)
+ .defaultValue(new DERBitString(org.bouncycastle.oer.its.ieee1609dot2.EndEntityType.app))
.typeName("EndEntityType");
/**
From 9228be2d49dbddb62282b39bec2d45a9745825f7 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Tue, 11 Mar 2025 11:06:48 +1100
Subject: [PATCH 191/890] cleaned up TODOs.
---
.../java/org/bouncycastle/cms/KEMRecipientInformation.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pkix/src/main/java/org/bouncycastle/cms/KEMRecipientInformation.java b/pkix/src/main/java/org/bouncycastle/cms/KEMRecipientInformation.java
index e61ba4cbab..bf9984386c 100644
--- a/pkix/src/main/java/org/bouncycastle/cms/KEMRecipientInformation.java
+++ b/pkix/src/main/java/org/bouncycastle/cms/KEMRecipientInformation.java
@@ -27,13 +27,13 @@ public class KEMRecipientInformation
{
ASN1OctetString octs = ASN1OctetString.getInstance(r.getId());
- rid = new KEMRecipientId(octs.getOctets()); // TODO: should be KEM
+ rid = new KEMRecipientId(octs.getOctets());
}
else
{
IssuerAndSerialNumber iAnds = IssuerAndSerialNumber.getInstance(r.getId());
- rid = new KEMRecipientId(iAnds.getName(), iAnds.getSerialNumber().getValue()); // TODO:
+ rid = new KEMRecipientId(iAnds.getName(), iAnds.getSerialNumber().getValue());
}
}
From b7e747aa1ef5a06f4ce33945b820595426385be6 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Tue, 11 Mar 2025 12:13:00 +1030
Subject: [PATCH 192/890] Remove duplicated parameters in MayoParameters
---
.../pqc/crypto/mayo/MayoParameters.java | 28 ++-----------------
.../pqc/crypto/mayo/MayoSigner.java | 13 +++------
2 files changed, 7 insertions(+), 34 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoParameters.java
index ebaa54cbe0..28c01ad0c4 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoParameters.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoParameters.java
@@ -18,15 +18,12 @@ public class MayoParameters
40, // r_bytes
120159, // P1_bytes
24336, // P2_bytes
- // P3_bytes
24, // csk_bytes
1420, // cpk_bytes
454, // sig_bytes
new int[]{8, 1, 1, 0}, // F_TAIL_78
- new byte[]{8, 1, 1, 0}, // f_tail_arr
24, // salt_bytes
32, // digest_bytes
- // pk_seed_bytes
24 // sk_seed_bytes
);
@@ -39,22 +36,18 @@ public class MayoParameters
81 - 17, // v = 64
4 * 17 + 1, // A_cols = 4 * 17 + 1 = 69
4, // k
- // q
32, // m_bytes
544, // O_bytes
32, // v_bytes
34, // r_bytes
66560, // P1_bytes
34816, // P2_bytes
- // P3_bytes
24, // csk_bytes
4912, // cpk_bytes
186, // sig_bytes
new int[]{8, 0, 2, 8}, //F_TAIL_64
- new byte[]{8, 0, 2, 8}, // f_tail_arr
24, // salt_bytes
32, // digest_bytes
- // pk_seed_bytes
24 // sk_seed_bytes
);
@@ -67,22 +60,18 @@ public class MayoParameters
118 - 10, // v = 108
11 * 10 + 1, // A_cols = 11 * 10 + 1 = 111
11, // k
- // q
54, // m_bytes
540, // O_bytes
54, // v_bytes
55, // r_bytes
317844, // P1_bytes
58320, // P2_bytes
- // P3_bytes
32, // csk_bytes
2986, // cpk_bytes
681, // sig_bytes
new int[]{8, 0, 1, 7}, //F_TAIL_108
- new byte[]{8, 0, 1, 7}, // f_tail_arr
32, // salt_bytes
48, // digest_bytes
- // pk_seed_bytes
32 // sk_seed_bytes
);
@@ -95,22 +84,18 @@ public class MayoParameters
154 - 12, // v = 142
12 * 12 + 1, // A_cols = 12 * 12 + 1 = 145
12, // k
- // q
71, // m_bytes
852, // O_bytes
71, // v_bytes
72, // r_bytes
720863, // P1_bytes
120984, // P2_bytes
- // P3_bytes
40, // csk_bytes
5554, // cpk_bytes
964, // sig_bytes
new int[]{4, 0, 8, 1}, //F_TAIL_142
- new byte[]{4, 0, 8, 1}, // f_tail_arr
40, // salt_bytes
64, // digest_bytes
- // pk_seed_bytes
40 // sk_seed_bytes
);
@@ -133,7 +118,6 @@ public class MayoParameters
private final int cpkBytes;
private final int sigBytes;
private final int[] fTail;
- private final byte[] fTailArr;
private final int saltBytes;
private final int digestBytes;
private static final int pkSeedBytes = 16;
@@ -141,7 +125,7 @@ public class MayoParameters
private MayoParameters(String name, int n, int m, int mVecLimbs, int o, int v, int ACols, int k,
int mBytes, int OBytes, int vBytes, int rBytes, int P1Bytes, int P2Bytes,
- int cskBytes, int cpkBytes, int sigBytes, int[] fTail, byte[] fTailArr,
+ int cskBytes, int cpkBytes, int sigBytes, int[] fTail,
int saltBytes, int digestBytes, int skSeedBytes)
{
this.name = name;
@@ -162,7 +146,6 @@ private MayoParameters(String name, int n, int m, int mVecLimbs, int o, int v, i
this.cpkBytes = cpkBytes;
this.sigBytes = sigBytes;
this.fTail = fTail;
- this.fTailArr = fTailArr;
this.saltBytes = saltBytes;
this.digestBytes = digestBytes;
this.skSeedBytes = skSeedBytes;
@@ -258,11 +241,6 @@ public int[] getFTail()
return fTail;
}
- public byte[] getFTailArr()
- {
- return fTailArr;
- }
-
public int getSaltBytes()
{
return saltBytes;
@@ -288,7 +266,7 @@ public int getSkSeedBytes()
*/
public int getP1Limbs()
{
- return ((v * (v + 1)) / 2) * mVecLimbs;
+ return ((v * (v + 1)) >> 1) * mVecLimbs;
}
/**
@@ -304,7 +282,7 @@ public int getP2Limbs()
*/
public int getP3Limbs()
{
- return ((o * (o + 1)) / 2) * mVecLimbs;
+ return ((o * (o + 1)) >> 1) * mVecLimbs;
}
}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
index 65d148b896..254099dd90 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
@@ -434,7 +434,7 @@ void computeA(long[] Mtmp, byte[] AOut)
final int m = params.getM();
final int mVecLimbs = params.getMVecLimbs();
final int ACols = params.getACols();
- final byte[] fTailArr = params.getFTailArr();
+ final int[] fTailArr = params.getFTail();
int bitsToShift = 0;
int wordsToShift = 0;
@@ -514,7 +514,7 @@ void computeA(long[] Mtmp, byte[] AOut)
byte[] tab = new byte[F_TAIL_LEN << 2];
for (int i = 0, idx = 0; i < F_TAIL_LEN; i++)
{
- byte ft = fTailArr[i];
+ int ft = fTailArr[i];
tab[idx++] = (byte)GF16Utils.mulF(ft, 1);
tab[idx++] = (byte)GF16Utils.mulF(ft, 2);
tab[idx++] = (byte)GF16Utils.mulF(ft, 4);
@@ -798,13 +798,8 @@ void ef(byte[] A, int nrows, int ncols)
for (int i = 0, irowLen = 0; i < nrows; i++, irowLen += rowLen)
{
Pack.longToLittleEndian(packedA, irowLen, len_4, bytes, 0);
- int j = 0;
- for (; j < ncols >> 1; j++)
- {
- A[outIndex++] = (byte)(bytes[j] & 0x0F); // Lower nibble
- A[outIndex++] = (byte)((bytes[j] >> 4) & 0x0F); // Upper nibble
- }
- A[outIndex++] = (byte)(bytes[j] & 0x0F);
+ Utils.decode(bytes, 0, A, outIndex, ncols);
+ outIndex += ncols;
}
}
From 9839405918b5af09a95b94eea16bd86826224ef5 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Wed, 12 Mar 2025 12:18:19 +1030
Subject: [PATCH 193/890] Minor refactor on MayoSigner.
---
.../java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
index 254099dd90..21f8b6d75b 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java
@@ -131,11 +131,11 @@ public byte[] generateSignature(byte[] message)
// Generate S = seed_pk || (additional bytes), using SHAKE256.
// Output length is param_pk_seed_bytes + param_O_bytes.
shake.update(seed_sk, 0, seed_sk.length);
- shake.doFinal(seed_pk, 0, pk_seed_bytes + oBytes);
+ shake.doFinal(seed_pk, 0, totalS);
// Decode the portion of S after the first param_pk_seed_bytes into O.
// (In C, this is: decode(S + param_pk_seed_bytes, O, param_v * param_o))
- Utils.decode(seed_pk, pk_seed_bytes, O, 0, v * o);
+ Utils.decode(seed_pk, pk_seed_bytes, O, 0, O.length);
// Expand P1 and P2 into the long array P using seed_pk.
Utils.expandP1P2(params, P, seed_pk);
From 47d3dba986f9075cecc1b1d83ddf9a0be44653fb Mon Sep 17 00:00:00 2001
From: gefeili
Date: Wed, 12 Mar 2025 17:19:10 +1030
Subject: [PATCH 194/890] TODO: gen_F
---
.../pqc/crypto/snova/GF16Utils.java | 13 -
.../pqc/crypto/snova/MapGroup1.java | 16 +-
.../pqc/crypto/snova/MapGroup2.java | 15 +-
.../pqc/crypto/snova/SnovaEngine.java | 228 +++++++++++++++++-
.../crypto/snova/SnovaKeyPairGenerator.java | 51 ++--
5 files changed, 276 insertions(+), 47 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/GF16Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/GF16Utils.java
index 9deda36297..75414b2152 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/GF16Utils.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/GF16Utils.java
@@ -164,19 +164,6 @@ public static byte inv(byte a)
return INV4B[a & 0xF];
}
- public static void convertGF16sToBytes(byte[] output, byte[] gf16s, int gf16Count)
- {
- int pairs = gf16Count / 2;
- for (int i = 0; i < pairs; i++)
- {
- output[i] = (byte)((gf16s[i * 2 + 1] << 4) | gf16s[i * 2]);
- }
- if (gf16Count % 2 == 1)
- {
- output[pairs] = gf16s[gf16Count - 1];
- }
- }
-
static GF16Matrix[][][] create3DArray(int d1, int d2, int d3, int rank)
{
GF16Matrix[][][] arr = new GF16Matrix[d1][d2][d3];
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup1.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup1.java
index cab068f328..552cdfeed7 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup1.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup1.java
@@ -16,14 +16,14 @@ public MapGroup1(SnovaParameters params)
int v = params.getV();
int o = params.getO();
int alpha = params.getAlpha();
-
- p11 = new byte[m][v][v][16];
- p12 = new byte[m][v][o][16];
- p21 = new byte[m][o][v][16];
- aAlpha = new byte[m][alpha][16];
- bAlpha = new byte[m][alpha][16];
- qAlpha1 = new byte[m][alpha][16];
- qAlpha2 = new byte[m][alpha][16];
+ int lsq = params.getL() * params.getL();
+ p11 = new byte[m][v][v][lsq];
+ p12 = new byte[m][v][o][lsq];
+ p21 = new byte[m][o][v][lsq];
+ aAlpha = new byte[m][alpha][lsq];
+ bAlpha = new byte[m][alpha][lsq];
+ qAlpha1 = new byte[m][alpha][lsq];
+ qAlpha2 = new byte[m][alpha][lsq];
}
public int decode(byte[] input, int len)
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup2.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup2.java
index a78141e370..a4c9cb834e 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup2.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup2.java
@@ -2,19 +2,18 @@
public class MapGroup2
{
- public final GF16Matrix[][][] F11; // [m][v][v]
- public final GF16Matrix[][][] F12; // [m][v][o]
- public final GF16Matrix[][][] F21; // [m][o][v]
+ public final byte[][][][] f11; // [m][v][v]
+ public final byte[][][][] f12; // [m][v][o]
+ public final byte[][][][] f21; // [m][o][v]
public MapGroup2(SnovaParameters params)
{
int m = params.getM();
int v = params.getV();
int o = params.getO();
- int rank = params.getL();
-
- F11 = GF16Utils.create3DArray(m, v, v, rank);
- F12 = GF16Utils.create3DArray(m, v, o, rank);
- F21 = GF16Utils.create3DArray(m, o, v, rank);
+ int lsq = params.getL() * params.getL();
+ f11 = new byte[m][v][v][lsq];
+ f12 = new byte[m][v][o][lsq];
+ f21 = new byte[m][o][v][lsq];
}
}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java
index 30c5087c7b..c4330b0f78 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java
@@ -28,11 +28,21 @@ public SnovaEngine(SnovaParameters params)
{
for (int ij = 0; ij < lsq; ++ij)
{
- xS[index][ij] = GF16Utils.gf16FromNibble(S[index][ij]);
+ xS[index][ij] = GF16Utils.gf16FromNibble(S[index][ij]);
}
}
}
+ public byte getGF16m(byte[] gf16m, int x, int y)
+ {
+ return gf16m[x * l + y];
+ }
+
+ public void setGF16m(byte[] gf16m, int x, int y, byte value)
+ {
+ gf16m[x * l + y] = value;
+ }
+
public void be_aI(byte[] target, byte a)
{
// Mask 'a' to ensure it's a valid 4-bit GF16 element
@@ -92,7 +102,7 @@ public void genAFqSCT(byte[] c, int cOff, byte[] ptMatrix)
// Handle last coefficient with constant-time selection
int zero = GF16Utils.ctGF16IsNotZero(c[cOff + l - 1]);
- int val = zero * c[cOff +l - 1] + (1 - zero) * (15 + GF16Utils.ctGF16IsNotZero(c[cOff]) - c[cOff]);
+ int val = zero * c[cOff + l - 1] + (1 - zero) * (15 + GF16Utils.ctGF16IsNotZero(c[cOff]) - c[cOff]);
cX = GF16Utils.gf16FromNibble((byte)val);
for (int ij = 0; ij < lsq; ij++)
@@ -107,4 +117,218 @@ public void genAFqSCT(byte[] c, int cOff, byte[] ptMatrix)
}
Arrays.fill(xTemp, 0); // Secure clear
}
+
+ public void makeInvertibleByAddingAS(byte[] source)
+ {
+ if (gf16Determinant(source) != 0)
+ {
+ return;
+ }
+
+
+ byte[] temp = new byte[l * l];
+
+ for (int a = 1; a < 16; a++)
+ {
+ generateASMatrix(temp, (byte)a);
+ addMatrices(temp, source, source);
+
+ if (gf16Determinant(source) != 0)
+ {
+ return;
+ }
+ }
+ throw new IllegalStateException("Failed to make matrix invertible");
+ }
+
+ private byte gf16Determinant(byte[] matrix)
+ {
+ switch (l)
+ {
+ case 2:
+ return determinant2x2(matrix);
+ case 3:
+ return determinant3x3(matrix);
+ case 4:
+ return determinant4x4(matrix);
+ case 5:
+ return determinant5x5(matrix);
+ default:
+ throw new IllegalStateException();
+ }
+ }
+
+ private byte determinant2x2(byte[] m)
+ {
+ return gf16Add(
+ gf16Mul(getGF16m(m, 0, 0), getGF16m(m, 1, 1)),
+ gf16Mul(getGF16m(m, 0, 1), getGF16m(m, 1, 0)));
+ }
+
+ private byte determinant3x3(byte[] m)
+ {
+ return gf16Add(
+ gf16Add(
+ gf16Mul(getGF16m(m, 0, 0), gf16Add(
+ gf16Mul(getGF16m(m, 1, 1), getGF16m(m, 2, 2)),
+ gf16Mul(getGF16m(m, 1, 2), getGF16m(m, 2, 1))
+ )),
+ gf16Mul(getGF16m(m, 0, 1), gf16Add(
+ gf16Mul(getGF16m(m, 1, 0), getGF16m(m, 2, 2)),
+ gf16Mul(getGF16m(m, 1, 2), getGF16m(m, 2, 0))
+ ))
+ ),
+ gf16Mul(getGF16m(m, 0, 2), gf16Add(
+ gf16Mul(getGF16m(m, 1, 0), getGF16m(m, 2, 1)),
+ gf16Mul(getGF16m(m, 1, 1), getGF16m(m, 2, 0))
+ ))
+ );
+ }
+
+ private byte determinant4x4(byte[] m)
+ {
+ byte d0 = gf16Mul(getGF16m(m, 0, 0), gf16Add(
+ gf16Add(
+ pod(m, 1, 1, 2, 2, 3, 3, 2, 3, 3, 2),
+ pod(m, 1, 2, 2, 1, 3, 3, 2, 3, 3, 1)
+ ),
+ pod(m, 1, 3, 2, 1, 3, 2, 2, 2, 3, 1)
+ ));
+
+ byte d1 = gf16Mul(getGF16m(m, 0, 1), gf16Add(
+ gf16Add(
+ pod(m, 1, 0, 2, 2, 3, 3, 2, 3, 3, 2),
+ pod(m, 1, 2, 2, 0, 3, 3, 2, 3, 3, 0)
+ ),
+ pod(m, 1, 3, 2, 0, 3, 2, 2, 2, 3, 0)
+ ));
+
+ byte d2 = gf16Mul(getGF16m(m, 0, 2), gf16Add(
+ gf16Add(
+ pod(m, 1, 0, 2, 1, 3, 3, 2, 3, 3, 1),
+ pod(m, 1, 1, 2, 0, 3, 3, 2, 3, 3, 0)
+ ),
+ pod(m, 1, 3, 2, 0, 3, 1, 2, 1, 3, 0)
+ ));
+
+ byte d3 = gf16Mul(getGF16m(m, 0, 3), gf16Add(
+ gf16Add(
+ pod(m, 1, 0, 2, 1, 3, 2, 2, 2, 3, 1),
+ pod(m, 1, 1, 2, 0, 3, 2, 2, 2, 3, 0)
+ ),
+ pod(m, 1, 2, 2, 0, 3, 1, 2, 1, 3, 0)
+ ));
+
+ return (byte)(d0 ^ d1 ^ d2 ^ d3);
+ }
+
+ private byte determinant5x5(byte[] m)
+ {
+ return 0;
+ //TODO:
+// byte result;
+//
+// result = gf16Mul(det3x3(m, 0, 1, 2, 0, 1, 2),
+// gf16Add(gf16Mul(m[3][3], m[4][4]), gf16Mul(m[3][4], m[4][3])));
+ // ... similar calculations for other components ...
+ //result ^= gf16Mul(det3x3(m, 0, 1, 2, 0, 1, 2),
+ // gf16Add(gf16Mul(m[3][3], m[4][4]), gf16Mul(m[3][4], m[4][3])));
+ //return result;
+ }
+
+ private byte det3x3(byte[] m, int row1, int row2, int row3, int col1, int col2, int col3)
+ {
+ //TODO:
+// byte[][] sub = new byte[3][3];
+// for (int i = 0; i < 3; i++)
+// {
+// sub[0][i] = m[row1][col1 + i];
+// sub[1][i] = m[row2][col1 + i];
+// sub[2][i] = m[row3][col1 + i];
+// }
+// return determinant3x3(sub);
+ return 0;
+ }
+
+ private void generateASMatrix(byte[] target, byte a)
+ {
+ for (int i = 0; i < l; i++)
+ {
+ for (int j = 0; j < l; j++)
+ {
+ byte coefficient = (byte)(8 - (i + j));
+ if (l == 5 && i == 4 && j == 4)
+ {
+ coefficient = 9;
+ }
+ setGF16m(target, i, j, gf16Mul(coefficient, a));
+ }
+ }
+ }
+
+ // POD -> entry[a][b] * (entry[c][d] * entry[e][f] + entry[g][h] * entry[i][j])
+ private byte pod(byte[] m, int a, int b, int c, int d, int e, int f, int g, int h, int i, int j)
+ {
+ return gf16Add(
+ gf16Mul(getGF16m(m, a, b), gf16Mul(getGF16m(m, c, d), getGF16m(m, e, f))),
+ gf16Mul(getGF16m(m, g, h), getGF16m(m, i, j)));
+ }
+
+ private void addMatrices(byte[] a, byte[] b, byte[] c)
+ {
+ for (int i = 0; i < l; i++)
+ {
+ for (int j = 0; j < l; j++)
+ {
+ setGF16m(c, i, j, gf16Add(getGF16m(a, i, j), getGF16m(b, i, j)));
+ }
+ }
+ }
+
+ // GF(16) arithmetic
+ private static byte gf16Add(byte a, byte b)
+ {
+ return (byte)(a ^ b);
+ }
+
+ // GF(16) multiplication using lookup table
+ private static byte gf16Mul(byte a, byte b)
+ {
+ return GF16Utils.mul(a, b);
+ }
+
+ public void genAFqS(byte[] c, int cOff, byte[] ptMatrix)
+ {
+ byte[] temp = new byte[l * l];
+
+ // Initialize with be_aI
+ be_aI(ptMatrix, c[cOff]);
+
+ // Process middle terms
+ for (int i = 1; i < l - 1; ++i)
+ {
+ gf16mScale(S[i], c[cOff + i], temp);
+ addMatrices(ptMatrix, temp, ptMatrix);
+ }
+
+ // Handle last term with special case
+ byte lastScalar = (c[cOff + l - 1] != 0) ? c[cOff + l - 1] :
+ gf16Add((byte)16, gf16Add(c[cOff], (byte)(c[cOff] == 0 ? 1 : 0)));
+ gf16mScale(S[l - 1], lastScalar, temp);
+ addMatrices(ptMatrix, temp, ptMatrix);
+
+ // Clear temporary matrix
+ //clearMatrix(temp);
+ }
+
+ private void gf16mScale(byte[] a, byte k, byte[] result)
+ {
+ for (int i = 0; i < l; ++i)
+ {
+ for (int j = 0; j < l; ++j)
+ {
+ setGF16m(result, i, j, gf16Mul(getGF16m(a, i, j), k));
+ }
+ }
+ }
}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyPairGenerator.java
index a2c2a51a62..e22bfc4683 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyPairGenerator.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyPairGenerator.java
@@ -254,29 +254,48 @@ private void genABQP(MapGroup1 map1, byte[] pkSeed)
int remaining = prngOutput.length - offset;
System.arraycopy(blockOut, 0, prngOutput, offset, remaining);
}
-
- for (int i = 0; i < prngOutput.length; i += 16)
- {
- byte[] block = new byte[16];
- ctrCipher.processBlock(block, 0, block, 0);
- System.arraycopy(block, 0, prngOutput, i, Math.min(16, prngOutput.length - i));
- }
}
// Convert bytes to GF16 structures
int inOff = map1.decode(prngOutput, (gf16sPrngPublic - qTemp.length) >> 1);
+ GF16Utils.decode(prngOutput, inOff, qTemp, 0, qTemp.length);
//
-// // Post-processing for invertible matrices
-// for (GF16Matrix matrix : map1.Aalpha)
-// {
-// GF16Utils.makeInvertible(matrix);
-// }
-// for (GF16Matrix matrix : map1.Balpha)
-// {
-// GF16Utils.makeInvertible(matrix);
-// }
+ // Post-processing for invertible matrices
+ for (int pi = 0; pi < m; ++pi)
+ {
+ for (int a = 0; a < alpha; ++a)
+ {
+ engine.makeInvertibleByAddingAS(map1.aAlpha[pi][a]);
+ }
+ }
+ for (int pi = 0; pi < m; ++pi)
+ {
+ for (int a = 0; a < alpha; ++a)
+ {
+ engine.makeInvertibleByAddingAS(map1.bAlpha[pi][a]);
+ }
+ }
+
+ int ptArray = 0;
+ for (int pi = 0; pi < m; ++pi)
+ {
+ for (int a = 0; a < alpha; ++a)
+ {
+ engine.genAFqS(qTemp, ptArray, map1.qAlpha1[pi][a]);
+ ptArray += l;
+ }
+ }
+ for (int pi = 0; pi < m; ++pi)
+ {
+ for (int a = 0; a < alpha; ++a)
+ {
+ engine.genAFqS(qTemp, ptArray, map1.qAlpha2[pi][a]);
+ ptArray += l;
+ }
+ }
}
+
// private void genF(MapGroup2 map2, MapGroup1 map1, GF16Matrix[][] T12)
// {
// // Matrix operations from C code's gen_F_ref
From e7f8a727c37ad504015db8afb2221a766562743e Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Wed, 12 Mar 2025 13:57:57 +0700
Subject: [PATCH 195/890] Improve encapsulatedTest
---
.../cms/test/NewSignedDataTest.java | 63 ++++++++++---------
1 file changed, 32 insertions(+), 31 deletions(-)
diff --git a/pkix/src/test/java/org/bouncycastle/cms/test/NewSignedDataTest.java b/pkix/src/test/java/org/bouncycastle/cms/test/NewSignedDataTest.java
index 948d194eb5..9135cb316f 100644
--- a/pkix/src/test/java/org/bouncycastle/cms/test/NewSignedDataTest.java
+++ b/pkix/src/test/java/org/bouncycastle/cms/test/NewSignedDataTest.java
@@ -705,7 +705,7 @@ public class NewSignedDataTest
noParams.add(EdECObjectIdentifiers.id_Ed25519);
noParams.add(EdECObjectIdentifiers.id_Ed448);
}
-
+
public NewSignedDataTest(String name)
{
super(name);
@@ -2492,47 +2492,49 @@ private void encapsulatedTest(
X509Certificate signatureCert,
String signatureAlgorithm,
ASN1ObjectIdentifier sigAlgOid,
- AlgorithmIdentifier digAlgId)
+ AlgorithmIdentifier expectedDigAlgId)
throws Exception
{
- List certList = new ArrayList();
- List crlList = new ArrayList();
- CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes());
-
+ CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+ List certList = new ArrayList();
+ List crlList = new ArrayList();
+
certList.add(signatureCert);
certList.add(_origCert);
crlList.add(_signCrl);
- Store certs = new JcaCertStore(certList);
- Store crlStore = new JcaCRLStore(crlList);
+ Store certStore = new JcaCertStore(certList);
+ Store crlStore = new JcaCRLStore(crlList);
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm).setProvider(BC).build(signaturePair.getPrivate());
- gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(contentSigner, signatureCert));
+ DigestCalculatorProvider digCalcProv = new JcaDigestCalculatorProviderBuilder().setProvider(BC).build();
- gen.addCertificates(certs);
-
- CMSSignedData s = gen.generate(msg, true);
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(digCalcProv).build(contentSigner, signatureCert));
- ByteArrayInputStream bIn = new ByteArrayInputStream(s.getEncoded());
- ASN1InputStream aIn = new ASN1InputStream(bIn);
+ gen.addCertificates(certStore);
+ gen.addCRLs(crlStore);
- s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
+ CMSSignedData s = gen.generate(msg, true);
+
+ s = new CMSSignedData(ContentInfo.getInstance(s.getEncoded()));
Set digestAlgorithms = new HashSet(s.getDigestAlgorithmIDs());
assertTrue(digestAlgorithms.size() > 0);
- if (digAlgId != null)
+ if (expectedDigAlgId != null)
{
- assertTrue(digestAlgorithms.contains(digAlgId));
+ assertTrue(digestAlgorithms.contains(expectedDigAlgId));
}
- certs = s.getCertificates();
-
+ certStore = s.getCertificates();
+ crlStore = s.getCRLs();
+
SignerInformationStore signers = s.getSignerInfos();
Collection c = signers.getSigners();
Iterator it = c.iterator();
@@ -2540,7 +2542,7 @@ private void encapsulatedTest(
while (it.hasNext())
{
SignerInformation signer = (SignerInformation)it.next();
- Collection certCollection = certs.getMatches(signer.getSID());
+ Collection certCollection = certStore.getMatches(signer.getSID());
Iterator certIt = certCollection.iterator();
X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
@@ -2592,18 +2594,17 @@ private void encapsulatedTest(
gen = new CMSSignedDataGenerator();
gen.addSigners(s.getSignerInfos());
-
+
gen.addCertificates(s.getCertificates());
-
+ gen.addCRLs(s.getCRLs());
+
s = gen.generate(msg, true);
-
- bIn = new ByteArrayInputStream(s.getEncoded());
- aIn = new ASN1InputStream(bIn);
-
- s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
-
- certs = s.getCertificates();
-
+
+ s = new CMSSignedData(ContentInfo.getInstance(s.getEncoded()));
+
+ certStore = s.getCertificates();
+ crlStore = s.getCRLs();
+
signers = s.getSignerInfos();
c = signers.getSigners();
it = c.iterator();
@@ -2611,7 +2612,7 @@ private void encapsulatedTest(
while (it.hasNext())
{
SignerInformation signer = (SignerInformation)it.next();
- Collection certCollection = certs.getMatches(signer.getSID());
+ Collection certCollection = certStore.getMatches(signer.getSID());
Iterator certIt = certCollection.iterator();
X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
From ed2d4390eb3cec699f14a4095a6619a2e23a9115 Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Wed, 12 Mar 2025 14:01:13 +0700
Subject: [PATCH 196/890] Add note that only SHA1withRSA issuer is actually
used
---
.../java/org/bouncycastle/cms/test/CMSTestUtil.java | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/pkix/src/test/java/org/bouncycastle/cms/test/CMSTestUtil.java b/pkix/src/test/java/org/bouncycastle/cms/test/CMSTestUtil.java
index 41b04336fa..571d2b318a 100644
--- a/pkix/src/test/java/org/bouncycastle/cms/test/CMSTestUtil.java
+++ b/pkix/src/test/java/org/bouncycastle/cms/test/CMSTestUtil.java
@@ -504,6 +504,10 @@ public static X509Certificate makeOaepCertificate(KeyPair subKP, String _subDN,
private static JcaContentSignerBuilder makeContentSignerBuilder(PublicKey issPub)
{
+ /*
+ * NOTE: Current ALL test certificates are issued under a SHA1withRSA root, so this list is mostly
+ * redundant (and also incomplete in that it doesn't handle EdDSA or ML-DSA issuers).
+ */
JcaContentSignerBuilder contentSignerBuilder;
if (issPub instanceof RSAPublicKey)
{
@@ -521,10 +525,14 @@ else if (issPub.getAlgorithm().equals("ECGOST3410"))
{
contentSignerBuilder = new JcaContentSignerBuilder("GOST3411withECGOST3410");
}
- else
+ else if (issPub.getAlgorithm().equals("GOST3410"))
{
contentSignerBuilder = new JcaContentSignerBuilder("GOST3411WithGOST3410");
}
+ else
+ {
+ throw new UnsupportedOperationException("Algorithm handlers incomplete");
+ }
contentSignerBuilder.setProvider(BouncyCastleProvider.PROVIDER_NAME);
From 9afb944716cd470e06bbe52ff245fb5229bf3c7e Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Wed, 12 Mar 2025 15:12:23 +0700
Subject: [PATCH 197/890] CMS: Expand ML-KEM tests
- adjust KDF, wrap, encryption algorithms
---
.../bouncycastle/cms/test/CMSTestUtil.java | 22 +++-
.../cms/test/NewEnvelopedDataTest.java | 121 ++++++++++++++++--
2 files changed, 129 insertions(+), 14 deletions(-)
diff --git a/pkix/src/test/java/org/bouncycastle/cms/test/CMSTestUtil.java b/pkix/src/test/java/org/bouncycastle/cms/test/CMSTestUtil.java
index 571d2b318a..01db2c4298 100644
--- a/pkix/src/test/java/org/bouncycastle/cms/test/CMSTestUtil.java
+++ b/pkix/src/test/java/org/bouncycastle/cms/test/CMSTestUtil.java
@@ -61,7 +61,9 @@ public class CMSTestUtil
public static KeyPairGenerator ecDsaKpg;
public static KeyPairGenerator ed25519Kpg;
public static KeyPairGenerator ed448Kpg;
- public static KeyPairGenerator mlKemKpg;
+ public static KeyPairGenerator mlKem512Kpg;
+ public static KeyPairGenerator mlKem768Kpg;
+ public static KeyPairGenerator mlKem1024Kpg;
public static KeyPairGenerator ntruKpg;
public static KeyGenerator aes192kg;
public static KeyGenerator desede128kg;
@@ -168,7 +170,9 @@ public class CMSTestUtil
ed448Kpg = KeyPairGenerator.getInstance("Ed448", "BC");
ntruKpg = KeyPairGenerator.getInstance(BCObjectIdentifiers.ntruhps2048509.getId(), "BC");
- mlKemKpg = KeyPairGenerator.getInstance("ML-KEM-768", "BC");
+ mlKem512Kpg = KeyPairGenerator.getInstance("ML-KEM-512", "BC");
+ mlKem768Kpg = KeyPairGenerator.getInstance("ML-KEM-768", "BC");
+ mlKem1024Kpg = KeyPairGenerator.getInstance("ML-KEM-1024", "BC");
aes192kg = KeyGenerator.getInstance("AES", "BC");
aes192kg.init(192, rand);
@@ -281,9 +285,19 @@ public static KeyPair makeNtruKeyPair()
return ntruKpg.generateKeyPair();
}
- public static KeyPair makeMLKemKeyPair()
+ public static KeyPair makeMLKem512KeyPair()
{
- return mlKemKpg.generateKeyPair();
+ return mlKem512Kpg.generateKeyPair();
+ }
+
+ public static KeyPair makeMLKem768KeyPair()
+ {
+ return mlKem768Kpg.generateKeyPair();
+ }
+
+ public static KeyPair makeMLKem1024KeyPair()
+ {
+ return mlKem1024Kpg.generateKeyPair();
}
public static SecretKey makeDesede128Key()
diff --git a/pkix/src/test/java/org/bouncycastle/cms/test/NewEnvelopedDataTest.java b/pkix/src/test/java/org/bouncycastle/cms/test/NewEnvelopedDataTest.java
index b973fe8f3f..d8e8845400 100644
--- a/pkix/src/test/java/org/bouncycastle/cms/test/NewEnvelopedDataTest.java
+++ b/pkix/src/test/java/org/bouncycastle/cms/test/NewEnvelopedDataTest.java
@@ -143,8 +143,12 @@ public class NewEnvelopedDataTest
private static X509Certificate _reciKemsCert;
private static KeyPair _reciNtruKP;
private static X509Certificate _reciNtruCert;
- private static KeyPair _reciMLKemKP;
- private static X509Certificate _reciMLKemCert;
+ private static KeyPair _reciMLKem512KP;
+ private static X509Certificate _reciMLKem512Cert;
+ private static KeyPair _reciMLKem768KP;
+ private static X509Certificate _reciMLKem768Cert;
+ private static KeyPair _reciMLKem1024KP;
+ private static X509Certificate _reciMLKem1024Cert;
private static KeyPair _origDhKP;
private static KeyPair _reciDhKP;
@@ -609,8 +613,14 @@ private static void init()
_reciNtruKP = CMSTestUtil.makeNtruKeyPair();
_reciNtruCert = CMSTestUtil.makeCertificate(_reciNtruKP, _reciDN, _signKP, _signDN);
- _reciMLKemKP = CMSTestUtil.makeMLKemKeyPair();
- _reciMLKemCert = CMSTestUtil.makeCertificate(_reciMLKemKP, _reciDN, _signKP, _signDN);
+ _reciMLKem512KP = CMSTestUtil.makeMLKem512KeyPair();
+ _reciMLKem512Cert = CMSTestUtil.makeCertificate(_reciMLKem512KP, _reciDN, _signKP, _signDN);
+
+ _reciMLKem768KP = CMSTestUtil.makeMLKem768KeyPair();
+ _reciMLKem768Cert = CMSTestUtil.makeCertificate(_reciMLKem768KP, _reciDN, _signKP, _signDN);
+
+ _reciMLKem1024KP = CMSTestUtil.makeMLKem1024KeyPair();
+ _reciMLKem1024Cert = CMSTestUtil.makeCertificate(_reciMLKem1024KP, _reciDN, _signKP, _signDN);
}
}
@@ -716,7 +726,7 @@ public void testContentType()
}
}
- public void testMLKem()
+ public void testMLKem512()
throws Exception
{
byte[] data = "WallaWallaWashington".getBytes();
@@ -725,8 +735,8 @@ public void testMLKem()
CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
// note: use cert req ID as key ID, don't want to use issuer/serial in this case!
- edGen.addRecipientInfoGenerator(new JceKEMRecipientInfoGenerator(_reciMLKemCert, CMSAlgorithm.AES256_WRAP).setKDF(
- new AlgorithmIdentifier(NISTObjectIdentifiers.id_shake256)));
+ edGen.addRecipientInfoGenerator(new JceKEMRecipientInfoGenerator(_reciMLKem512Cert, CMSAlgorithm.AES128_WRAP)
+ .setKDF(new AlgorithmIdentifier(PKCSObjectIdentifiers.id_alg_hkdf_with_sha256)));
CMSEnvelopedData ed = edGen.generate(
new CMSProcessableByteArray(data),
@@ -743,17 +753,108 @@ public void testMLKem()
Iterator it = c.iterator();
int expectedLength = new DefaultKemEncapsulationLengthProvider().getEncapsulationLength(
- SubjectPublicKeyInfo.getInstance(_reciMLKemKP.getPublic().getEncoded()).getAlgorithm());
+ SubjectPublicKeyInfo.getInstance(_reciMLKem512KP.getPublic().getEncoded()).getAlgorithm());
+
+ while (it.hasNext())
+ {
+ KEMRecipientInformation recipient = (KEMRecipientInformation)it.next();
+
+ assertEquals(expectedLength, recipient.getEncapsulation().length);
+
+ assertEquals(NISTObjectIdentifiers.id_alg_ml_kem_512.getId(), recipient.getKeyEncryptionAlgOID());
+
+ CMSTypedStream contentStream = recipient.getContentStream(
+ new JceKEMEnvelopedRecipient(_reciMLKem512KP.getPrivate()).setProvider(BC));
+
+ assertEquals(PKCSObjectIdentifiers.data, contentStream.getContentType());
+ assertEquals(true, Arrays.equals(data, Streams.readAll(contentStream.getContentStream())));
+ }
+ }
+
+ public void testMLKem768()
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+
+ // Send response with encrypted certificate
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ // note: use cert req ID as key ID, don't want to use issuer/serial in this case!
+ edGen.addRecipientInfoGenerator(new JceKEMRecipientInfoGenerator(_reciMLKem768Cert, CMSAlgorithm.AES256_WRAP)
+ .setKDF(new AlgorithmIdentifier(PKCSObjectIdentifiers.id_alg_hkdf_with_sha256)));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES256_CBC).setProvider("BC").build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.AES256_CBC);
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(1, c.size());
+
+ Iterator it = c.iterator();
+
+ int expectedLength = new DefaultKemEncapsulationLengthProvider().getEncapsulationLength(
+ SubjectPublicKeyInfo.getInstance(_reciMLKem768KP.getPublic().getEncoded()).getAlgorithm());
while (it.hasNext())
{
KEMRecipientInformation recipient = (KEMRecipientInformation)it.next();
assertEquals(expectedLength, recipient.getEncapsulation().length);
-
+
assertEquals(NISTObjectIdentifiers.id_alg_ml_kem_768.getId(), recipient.getKeyEncryptionAlgOID());
- CMSTypedStream contentStream = recipient.getContentStream(new JceKEMEnvelopedRecipient(_reciMLKemKP.getPrivate()).setProvider(BC));
+ CMSTypedStream contentStream = recipient.getContentStream(
+ new JceKEMEnvelopedRecipient(_reciMLKem768KP.getPrivate()).setProvider(BC));
+
+ assertEquals(PKCSObjectIdentifiers.data, contentStream.getContentType());
+ assertEquals(true, Arrays.equals(data, Streams.readAll(contentStream.getContentStream())));
+ }
+ }
+
+ public void testMLKem1024()
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+
+ // Send response with encrypted certificate
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ // note: use cert req ID as key ID, don't want to use issuer/serial in this case!
+ edGen.addRecipientInfoGenerator(new JceKEMRecipientInfoGenerator(_reciMLKem1024Cert, CMSAlgorithm.AES256_WRAP)
+ .setKDF(new AlgorithmIdentifier(PKCSObjectIdentifiers.id_alg_hkdf_with_sha256)));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES256_CBC).setProvider("BC").build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.AES256_CBC);
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(1, c.size());
+
+ Iterator it = c.iterator();
+
+ int expectedLength = new DefaultKemEncapsulationLengthProvider().getEncapsulationLength(
+ SubjectPublicKeyInfo.getInstance(_reciMLKem1024KP.getPublic().getEncoded()).getAlgorithm());
+
+ while (it.hasNext())
+ {
+ KEMRecipientInformation recipient = (KEMRecipientInformation)it.next();
+
+ assertEquals(expectedLength, recipient.getEncapsulation().length);
+
+ assertEquals(NISTObjectIdentifiers.id_alg_ml_kem_1024.getId(), recipient.getKeyEncryptionAlgOID());
+
+ CMSTypedStream contentStream = recipient.getContentStream(
+ new JceKEMEnvelopedRecipient(_reciMLKem1024KP.getPrivate()).setProvider(BC));
assertEquals(PKCSObjectIdentifiers.data, contentStream.getContentType());
assertEquals(true, Arrays.equals(data, Streams.readAll(contentStream.getContentStream())));
From bb265da7ba02b9192f9c1178ed9e781c173e1d9b Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Wed, 12 Mar 2025 20:26:06 +0700
Subject: [PATCH 198/890] CMS: Prepare ML-DSA tests (not working yet)
---
.../bouncycastle/cms/test/CMSTestUtil.java | 23 +++++
.../cms/test/NewSignedDataTest.java | 93 ++++++++++++++++++-
2 files changed, 114 insertions(+), 2 deletions(-)
diff --git a/pkix/src/test/java/org/bouncycastle/cms/test/CMSTestUtil.java b/pkix/src/test/java/org/bouncycastle/cms/test/CMSTestUtil.java
index 01db2c4298..dfc7134ef5 100644
--- a/pkix/src/test/java/org/bouncycastle/cms/test/CMSTestUtil.java
+++ b/pkix/src/test/java/org/bouncycastle/cms/test/CMSTestUtil.java
@@ -61,6 +61,9 @@ public class CMSTestUtil
public static KeyPairGenerator ecDsaKpg;
public static KeyPairGenerator ed25519Kpg;
public static KeyPairGenerator ed448Kpg;
+ public static KeyPairGenerator mlDsa44Kpg;
+ public static KeyPairGenerator mlDsa65Kpg;
+ public static KeyPairGenerator mlDsa87Kpg;
public static KeyPairGenerator mlKem512Kpg;
public static KeyPairGenerator mlKem768Kpg;
public static KeyPairGenerator mlKem1024Kpg;
@@ -170,6 +173,11 @@ public class CMSTestUtil
ed448Kpg = KeyPairGenerator.getInstance("Ed448", "BC");
ntruKpg = KeyPairGenerator.getInstance(BCObjectIdentifiers.ntruhps2048509.getId(), "BC");
+
+ mlDsa44Kpg = KeyPairGenerator.getInstance("ML-DSA-44", "BC");
+ mlDsa65Kpg = KeyPairGenerator.getInstance("ML-DSA-65", "BC");
+ mlDsa87Kpg = KeyPairGenerator.getInstance("ML-DSA-87", "BC");
+
mlKem512Kpg = KeyPairGenerator.getInstance("ML-KEM-512", "BC");
mlKem768Kpg = KeyPairGenerator.getInstance("ML-KEM-768", "BC");
mlKem1024Kpg = KeyPairGenerator.getInstance("ML-KEM-1024", "BC");
@@ -300,6 +308,21 @@ public static KeyPair makeMLKem1024KeyPair()
return mlKem1024Kpg.generateKeyPair();
}
+ public static KeyPair makeMLDsa44KeyPair()
+ {
+ return mlDsa44Kpg.generateKeyPair();
+ }
+
+ public static KeyPair makeMLDsa65KeyPair()
+ {
+ return mlDsa65Kpg.generateKeyPair();
+ }
+
+ public static KeyPair makeMLDsa87KeyPair()
+ {
+ return mlDsa87Kpg.generateKeyPair();
+ }
+
public static SecretKey makeDesede128Key()
{
return desede128kg.generateKey();
diff --git a/pkix/src/test/java/org/bouncycastle/cms/test/NewSignedDataTest.java b/pkix/src/test/java/org/bouncycastle/cms/test/NewSignedDataTest.java
index 9135cb316f..4ae2bfa147 100644
--- a/pkix/src/test/java/org/bouncycastle/cms/test/NewSignedDataTest.java
+++ b/pkix/src/test/java/org/bouncycastle/cms/test/NewSignedDataTest.java
@@ -144,6 +144,13 @@ public class NewSignedDataTest
private static KeyPair _signEd448KP;
private static X509Certificate _signEd448Cert;
+ private static KeyPair _signMLDsa44KP;
+ private static X509Certificate _signMLDsa44Cert;
+ private static KeyPair _signMLDsa65KP;
+ private static X509Certificate _signMLDsa65Cert;
+ private static KeyPair _signMLDsa87KP;
+ private static X509Certificate _signMLDsa87Cert;
+
private static String _reciDN;
private static KeyPair _reciKP;
private static X509Certificate _reciCert;
@@ -704,6 +711,9 @@ public class NewSignedDataTest
noParams.add(NISTObjectIdentifiers.id_ecdsa_with_sha3_512);
noParams.add(EdECObjectIdentifiers.id_Ed25519);
noParams.add(EdECObjectIdentifiers.id_Ed448);
+ noParams.add(NISTObjectIdentifiers.id_ml_dsa_44);
+ noParams.add(NISTObjectIdentifiers.id_ml_dsa_65);
+ noParams.add(NISTObjectIdentifiers.id_ml_dsa_87);
}
public NewSignedDataTest(String name)
@@ -776,6 +786,15 @@ private static void init()
_signEd448KP = CMSTestUtil.makeEd448KeyPair();
_signEd448Cert = CMSTestUtil.makeCertificate(_signEd448KP, _signDN, _origKP, _origDN);
+ _signMLDsa44KP = CMSTestUtil.makeMLDsa44KeyPair();
+ _signMLDsa44Cert = CMSTestUtil.makeCertificate(_signMLDsa44KP, _signDN, _origKP, _origDN);
+
+ _signMLDsa65KP = CMSTestUtil.makeMLDsa65KeyPair();
+ _signMLDsa65Cert = CMSTestUtil.makeCertificate(_signMLDsa65KP, _signDN, _origKP, _origDN);
+
+ _signMLDsa87KP = CMSTestUtil.makeMLDsa87KeyPair();
+ _signMLDsa87Cert = CMSTestUtil.makeCertificate(_signMLDsa87KP, _signDN, _origKP, _origDN);
+
_reciDN = "CN=Doug, OU=Sales, O=Bouncy Castle, C=AU";
_reciKP = CMSTestUtil.makeKeyPair();
_reciCert = CMSTestUtil.makeCertificate(_reciKP, _reciDN, _signKP, _signDN);
@@ -1789,13 +1808,32 @@ public void testSHA512_256ithRSADigest()
public void testEd25519()
throws Exception
{
- encapsulatedTest(_signEd25519KP, _signEd25519Cert, "Ed25519", EdECObjectIdentifiers.id_Ed25519, new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512));
+ /*
+ * RFC 8419 3.1. When signing with Ed25519, the digestAlgorithm MUST be id-sha512, and the algorithm
+ * parameters field MUST be absent.
+ *
+ * We confirm here that our implementation defaults to SHA-512 for the digest algorithm.
+ */
+ AlgorithmIdentifier expectedDigAlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512);
+
+ encapsulatedTest(_signEd25519KP, _signEd25519Cert, "Ed25519", EdECObjectIdentifiers.id_Ed25519,
+ expectedDigAlgId);
}
public void testEd448()
throws Exception
{
- encapsulatedTest(_signEd448KP, _signEd448Cert, "Ed448", EdECObjectIdentifiers.id_Ed448, new AlgorithmIdentifier(NISTObjectIdentifiers.id_shake256_len, new ASN1Integer(512)));
+ /*
+ * RFC 8419 3.1. When signing with Ed448, the digestAlgorithm MUST be id-shake256-len, the algorithm
+ * parameters field MUST be present, and the parameter MUST contain 512, encoded as a positive integer
+ * value.
+ *
+ * We confirm here that our implementation defaults to id-shake256-len/512 for the digest algorithm.
+ */
+ AlgorithmIdentifier expectedDigAlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_shake256_len,
+ new ASN1Integer(512));
+
+ encapsulatedTest(_signEd448KP, _signEd448Cert, "Ed448", EdECObjectIdentifiers.id_Ed448, expectedDigAlgId);
}
public void testDetachedEd25519()
@@ -2270,6 +2308,57 @@ public SignerInformationVerifier get(SignerId signerId)
assertTrue(digAlgs.contains(new AlgorithmIdentifier(TeleTrusTObjectIdentifiers.ripemd160, DERNull.INSTANCE)));
}
+// public void testMLDsa44()
+// throws Exception
+// {
+// /*
+// * draft-ietf-lamps-cms-ml-dsa-02 3.3. SHA-512 [FIPS180] MUST be supported for use with the variants
+// * of ML-DSA in this document; however, other hash functions MAY also be supported. When SHA-512 is
+// * used, the id-sha512 [RFC5754] digest algorithm identifier is used and the parameters field MUST be
+// * omitted.
+// *
+// * We confirm here that our implementation defaults to SHA-512 for the digest algorithm.
+// */
+// AlgorithmIdentifier expectedDigAlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512);
+//
+// encapsulatedTest(_signMLDsa44KP, _signMLDsa44Cert, "ML-DSA-44", NISTObjectIdentifiers.id_ml_dsa_44,
+// expectedDigAlgId);
+// }
+//
+// public void testMLDsa65()
+// throws Exception
+// {
+// /*
+// * draft-ietf-lamps-cms-ml-dsa-02 3.3. SHA-512 [FIPS180] MUST be supported for use with the variants
+// * of ML-DSA in this document; however, other hash functions MAY also be supported. When SHA-512 is
+// * used, the id-sha512 [RFC5754] digest algorithm identifier is used and the parameters field MUST be
+// * omitted.
+// *
+// * We confirm here that our implementation defaults to SHA-512 for the digest algorithm.
+// */
+// AlgorithmIdentifier expectedDigAlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512);
+//
+// encapsulatedTest(_signMLDsa65KP, _signMLDsa65Cert, "ML-DSA-65", NISTObjectIdentifiers.id_ml_dsa_65,
+// expectedDigAlgId);
+// }
+//
+// public void testMLDsa87()
+// throws Exception
+// {
+// /*
+// * draft-ietf-lamps-cms-ml-dsa-02 3.3. SHA-512 [FIPS180] MUST be supported for use with the variants
+// * of ML-DSA in this document; however, other hash functions MAY also be supported. When SHA-512 is
+// * used, the id-sha512 [RFC5754] digest algorithm identifier is used and the parameters field MUST be
+// * omitted.
+// *
+// * We confirm here that our implementation defaults to SHA-512 for the digest algorithm.
+// */
+// AlgorithmIdentifier expectedDigAlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512);
+//
+// encapsulatedTest(_signMLDsa87KP, _signMLDsa87Cert, "ML-DSA-87", NISTObjectIdentifiers.id_ml_dsa_87,
+// expectedDigAlgId);
+// }
+
private void rsaPSSTest(String signatureAlgorithmName)
throws Exception
{
From 0f613faaad1ee64639709a38fa6fa91b33d6b5ab Mon Sep 17 00:00:00 2001
From: Tony Washer
Date: Mon, 20 Jan 2025 14:08:39 +0000
Subject: [PATCH 199/890] Enable AsconXof to perform multiple outputs
---
.../crypto/digests/AsconBaseDigest.java | 6 +-
.../crypto/digests/AsconCXof128.java | 85 ++-----------------
.../crypto/digests/AsconXof128.java | 70 +++++++++++++--
3 files changed, 73 insertions(+), 88 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/AsconBaseDigest.java b/core/src/main/java/org/bouncycastle/crypto/digests/AsconBaseDigest.java
index cfe6f466df..50037c731c 100644
--- a/core/src/main/java/org/bouncycastle/crypto/digests/AsconBaseDigest.java
+++ b/core/src/main/java/org/bouncycastle/crypto/digests/AsconBaseDigest.java
@@ -127,7 +127,9 @@ public void update(byte[] input, int inOff, int len)
@Override
public int doFinal(byte[] output, int outOff)
{
- return hash(output, outOff, CRYPTO_BYTES);
+ int rv = hash(output, outOff, CRYPTO_BYTES);
+ reset();
+ return rv;
}
protected void padAndAbsorb()
@@ -149,7 +151,7 @@ protected void squeeze(byte[] output, int outOff, int len)
}
/* squeeze final output block */
setBytes(x0, output, outOff, len);
- reset();
+ p(ASCON_PB_ROUNDS);
}
protected int hash(byte[] output, int outOff, int outLen)
diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/AsconCXof128.java b/core/src/main/java/org/bouncycastle/crypto/digests/AsconCXof128.java
index f54c622675..21296bd9fe 100644
--- a/core/src/main/java/org/bouncycastle/crypto/digests/AsconCXof128.java
+++ b/core/src/main/java/org/bouncycastle/crypto/digests/AsconCXof128.java
@@ -1,8 +1,6 @@
package org.bouncycastle.crypto.digests;
import org.bouncycastle.crypto.DataLengthException;
-import org.bouncycastle.crypto.OutputLengthException;
-import org.bouncycastle.crypto.Xof;
import org.bouncycastle.util.Pack;
/**
@@ -17,10 +15,8 @@
*
*/
public class AsconCXof128
- extends AsconBaseDigest
- implements Xof
+ extends AsconXof128
{
- private boolean m_squeezing = false;
private final long z0, z1, z2, z3, z4;
public AsconCXof128()
@@ -35,6 +31,7 @@ public AsconCXof128(byte[] s)
public AsconCXof128(byte[] s, int off, int len)
{
+ super(false);
if ((off + len) > s.length)
{
throw new DataLengthException("input buffer too short");
@@ -52,90 +49,18 @@ public AsconCXof128(byte[] s, int off, int len)
z4 = x4;
}
- @Override
- public void update(byte in)
- {
- if (m_squeezing)
- {
- throw new IllegalArgumentException("attempt to absorb while squeezing");
- }
- super.update(in);
- }
-
- @Override
- public void update(byte[] input, int inOff, int len)
- {
- if (m_squeezing)
- {
- throw new IllegalArgumentException("attempt to absorb while squeezing");
- }
- super.update(input, inOff, len);
- }
-
- protected long pad(int i)
- {
- return 0x01L << (i << 3);
- }
-
- protected long loadBytes(final byte[] bytes, int inOff)
- {
- return Pack.littleEndianToLong(bytes, inOff);
- }
-
- protected long loadBytes(final byte[] bytes, int inOff, int n)
- {
- return Pack.littleEndianToLong(bytes, inOff, n);
- }
-
- protected void setBytes(long w, byte[] bytes, int inOff)
- {
- Pack.longToLittleEndian(w, bytes, inOff);
- }
-
- protected void setBytes(long w, byte[] bytes, int inOff, int n)
- {
- Pack.longToLittleEndian(w, bytes, inOff, n);
- }
-
- protected void padAndAbsorb()
- {
- m_squeezing = true;
- super.padAndAbsorb();
- }
-
@Override
public String getAlgorithmName()
{
return "Ascon-CXOF128";
}
- @Override
- public int doOutput(byte[] output, int outOff, int outLen)
- {
- if (CRYPTO_BYTES + outOff > output.length)
- {
- throw new OutputLengthException("output buffer is too short");
- }
- padAndAbsorb();
- /* squeeze full output blocks */
- squeeze(output, outOff, outLen);
- return outLen;
- }
-
-
- @Override
- public int doFinal(byte[] output, int outOff, int outLen)
- {
- int rlt = doOutput(output, outOff, outLen);
- reset();
- return rlt;
- }
-
@Override
public void reset()
{
- super.reset();
+ baseReset();
m_squeezing = false;
+ bytesInBuffer = 0;
/* initialize */
x0 = z0;
x1 = z1;
@@ -157,6 +82,6 @@ private void initState(byte[] z, int zOff, int zLen)
update(z, zOff, zLen);
padAndAbsorb();
m_squeezing = false;
+ bytesInBuffer = 0;
}
}
-
diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/AsconXof128.java b/core/src/main/java/org/bouncycastle/crypto/digests/AsconXof128.java
index 31fe0f64a9..0b8f368d9a 100644
--- a/core/src/main/java/org/bouncycastle/crypto/digests/AsconXof128.java
+++ b/core/src/main/java/org/bouncycastle/crypto/digests/AsconXof128.java
@@ -1,5 +1,6 @@
package org.bouncycastle.crypto.digests;
+import org.bouncycastle.crypto.OutputLengthException;
import org.bouncycastle.crypto.Xof;
import org.bouncycastle.util.Pack;
@@ -18,11 +19,22 @@ public class AsconXof128
extends AsconBaseDigest
implements Xof
{
- private boolean m_squeezing = false;
+ protected boolean m_squeezing = false;
+
+ private final byte[] buffer = new byte[ASCON_HASH_RATE];
+ protected int bytesInBuffer;
public AsconXof128()
{
- reset();
+ this(true);
+ }
+
+ protected AsconXof128(final boolean doReset)
+ {
+ if (doReset)
+ {
+ reset();
+ }
}
protected long pad(int i)
@@ -52,8 +64,11 @@ protected void setBytes(long w, byte[] bytes, int inOff, int n)
protected void padAndAbsorb()
{
- m_squeezing = true;
- super.padAndAbsorb();
+ if (!m_squeezing)
+ {
+ m_squeezing = true;
+ super.padAndAbsorb();
+ }
}
@Override
@@ -85,7 +100,45 @@ public void update(byte[] input, int inOff, int len)
@Override
public int doOutput(byte[] output, int outOff, int outLen)
{
- return hash(output, outOff, outLen);
+ if (outLen + outOff > output.length)
+ {
+ throw new OutputLengthException("output buffer is too short");
+ }
+
+ /* Use buffered output first */
+ int bytesOutput = 0;
+ if (bytesInBuffer != 0)
+ {
+ int startPos = ASCON_HASH_RATE - bytesInBuffer;
+ int bytesToOutput = Math.min(outLen, bytesInBuffer);
+ System.arraycopy(buffer, startPos, output, outOff, bytesToOutput);
+ bytesInBuffer -= bytesToOutput;
+ bytesOutput += bytesToOutput;
+ }
+
+ /* If we still need to output data */
+ if (outLen - bytesOutput >= ASCON_HASH_RATE)
+ {
+ /* Output full blocks */
+ int bytesToOutput = ASCON_HASH_RATE * ((outLen - bytesOutput) / ASCON_HASH_RATE);
+ bytesOutput += hash(output, outOff + bytesOutput, bytesToOutput);
+ }
+
+ /* If we need to output a partial buffer */
+ if (bytesOutput < outLen)
+ {
+ /* Access the next buffer's worth of data */
+ hash(buffer, 0, ASCON_HASH_RATE);
+
+ /* Copy required length of data */
+ int bytesToOutput = outLen - bytesOutput;
+ System.arraycopy(buffer, 0, output, outOff + bytesOutput, bytesToOutput);
+ bytesInBuffer = buffer.length - bytesToOutput;
+ bytesOutput += bytesToOutput;
+ }
+
+ /* return the length of data output */
+ return bytesOutput;
}
@Override
@@ -106,6 +159,7 @@ public int getByteLength()
public void reset()
{
m_squeezing = false;
+ bytesInBuffer = 0;
super.reset();
/* initialize */
x0 = -2701369817892108309L;
@@ -114,5 +168,9 @@ public void reset()
x3 = 1072114354614917324L;
x4 = -2282070310009238562L;
}
-}
+ protected void baseReset()
+ {
+ super.reset();
+ }
+}
From eb646dffc56d154a4bf94cb1414518e982daa549 Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Thu, 13 Mar 2025 00:38:56 +0700
Subject: [PATCH 200/890] Refactor checkForVersion3 method
---
.../org/bouncycastle/cms/CMSSignedDataStreamGenerator.java | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataStreamGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataStreamGenerator.java
index 3b45edb06b..519b11941c 100644
--- a/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataStreamGenerator.java
+++ b/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataStreamGenerator.java
@@ -372,13 +372,13 @@ else if (tagged.getTagNo() == 3)
return new ASN1Integer(1);
}
- private boolean checkForVersion3(List signerInfos, List signerInfoGens)
+ private static boolean checkForVersion3(List signerInfos, List signerInfoGens)
{
for (Iterator it = signerInfos.iterator(); it.hasNext();)
{
- SignerInfo s = SignerInfo.getInstance(((SignerInformation)it.next()).toASN1Structure());
+ SignerInfo s = ((SignerInformation)it.next()).toASN1Structure();
- if (s.getVersion().intValueExact() == 3)
+ if (s.getVersion().hasValue(3))
{
return true;
}
From ac3224a6b1481c551b12de6eaa4278ae440bbb7e Mon Sep 17 00:00:00 2001
From: gefeili
Date: Thu, 13 Mar 2025 09:02:28 +1030
Subject: [PATCH 201/890] TODO: genP22
---
.../pqc/crypto/snova/SnovaEngine.java | 102 ++++++++++++++++++
.../crypto/snova/SnovaKeyPairGenerator.java | 6 +-
2 files changed, 105 insertions(+), 3 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java
index c4330b0f78..9e1c42ef83 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java
@@ -331,4 +331,106 @@ private void gf16mScale(byte[] a, byte k, byte[] result)
}
}
}
+
+ public void genF(MapGroup2 map2, MapGroup1 map1, byte[][][] T12) {
+ int m = params.getM();
+ int v = params.getV();
+ int o = params.getO();
+ int l = params.getL();
+ int lsq = l * l;
+
+ // Copy initial matrices
+ copy4DMatrix(map1.p11, map2.f11, m, v, v, lsq);
+ copy4DMatrix(map1.p12, map2.f12, m, v, o, lsq);
+ copy4DMatrix(map1.p21, map2.f21, m, o, v, lsq);
+
+ byte[] temp = new byte[lsq];
+
+ // First matrix operation sequence
+ for (int i = 0; i < m; i++) {
+ for (int j = 0; j < v; j++) {
+ for (int k = 0; k < o; k++) {
+ for (int index = 0; index < v; index++) {
+ GF16Utils.gf16mMul(temp, map1.p11[i][j][index], T12[index][k], l);
+ GF16Utils.gf16mAdd(map2.f12[i][j][k], map2.f12[i][j][k], temp, l);
+ }
+ }
+ }
+ }
+
+ // Second matrix operation sequence
+ for (int i = 0; i < m; i++) {
+ for (int j = 0; j < o; j++) {
+ for (int k = 0; k < v; k++) {
+ for (int index = 0; index < v; index++) {
+ GF16Utils.gf16mMul(temp, T12[index][j], map1.p11[i][index][k], l);
+ GF16Utils.gf16mAdd(map2.f21[i][j][k], map2.f21[i][j][k], temp, l);
+ }
+ }
+ }
+ }
+
+ // Secure clear temporary buffer
+ Arrays.fill(temp, (byte) 0);
+ }
+
+ private static void copy4DMatrix(byte[][][][] src, byte[][][][] dest,
+ int dim1, int dim2, int dim3, int lsq) {
+ for (int i = 0; i < dim1; i++) {
+ for (int j = 0; j < dim2; j++) {
+ for (int k = 0; k < dim3; k++) {
+ System.arraycopy(
+ src[i][j][k], 0,
+ dest[i][j][k], 0,
+ lsq
+ );
+ }
+ }
+ }
+ }
+
+ public void genP22(byte[] outP22, byte[][][] T12, byte[][][][] P21, byte[][][][] F12, SnovaParameters params) {
+ int m = params.getM();
+ int o = params.getO();
+ int v = params.getV();
+ int l = params.getL();
+ int lsq = l * l;
+
+ // Initialize P22 with zeros
+ byte[][][][] P22 = new byte[m][o][o][lsq];
+
+ // Temporary buffers
+ byte[] temp1 = new byte[lsq];
+ byte[] temp2 = new byte[lsq];
+
+ try {
+ for (int i = 0; i < m; i++) {
+ for (int j = 0; j < o; j++) {
+ for (int k = 0; k < o; k++) {
+ for (int index = 0; index < v; index++) {
+ // temp1 = T12[index][j] * F12[i][index][k]
+ GF16Utils.gf16mMul(temp1, T12[index][j], F12[i][index][k], l);
+
+ // temp2 = P21[i][j][index] * T12[index][k]
+ GF16Utils.gf16mMul(temp2, P21[i][j][index], T12[index][k], l);
+
+ // temp1 += temp2
+ GF16Utils.gf16mAdd(temp1, temp1, temp2, l);
+
+ // P22[i][j][k] += temp1
+ GF16Utils.gf16mAdd(P22[i][j][k], P22[i][j][k], temp1, l);
+ }
+ }
+ }
+ }
+
+ // Convert GF16 elements to packed bytes
+ //TODO
+ //GF16Utils.decode(P22, outP22, m * o * o *lsq);
+ } finally {
+ // Secure clear temporary buffers
+ Arrays.fill(temp1, (byte) 0);
+ Arrays.fill(temp2, (byte) 0);
+ }
+ }
}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyPairGenerator.java
index e22bfc4683..8450c2b41d 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyPairGenerator.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyPairGenerator.java
@@ -166,9 +166,9 @@ private void generateKeysCore(SnovaKeyElements keyElements, byte[] pkSeed, byte[
// Generate map components
genABQP(keyElements.map1, pkSeed);
-//
-// // Generate F matrices
-// genF(keyElements.map2, keyElements.map1, keyElements.T12);
+
+ // Generate F matrices
+ engine.genF(keyElements.map2, keyElements.map1, keyElements.T12);
// Generate P22 matrix
// genP22(keyElements.pk.P22, keyElements.T12, keyElements.map1.P21, keyElements.map2.F12);
From 0869f53e7369d0f2869a20116c84c39f51f617f2 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Thu, 13 Mar 2025 09:02:41 +1030
Subject: [PATCH 202/890] TODO: genP22
---
.../pqc/crypto/snova/SnovaEngine.java | 67 ++++++++++++-------
1 file changed, 44 insertions(+), 23 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java
index 9e1c42ef83..e68138385e 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java
@@ -332,7 +332,8 @@ private void gf16mScale(byte[] a, byte k, byte[] result)
}
}
- public void genF(MapGroup2 map2, MapGroup1 map1, byte[][][] T12) {
+ public void genF(MapGroup2 map2, MapGroup1 map1, byte[][][] T12)
+ {
int m = params.getM();
int v = params.getV();
int o = params.getO();
@@ -347,10 +348,14 @@ public void genF(MapGroup2 map2, MapGroup1 map1, byte[][][] T12) {
byte[] temp = new byte[lsq];
// First matrix operation sequence
- for (int i = 0; i < m; i++) {
- for (int j = 0; j < v; j++) {
- for (int k = 0; k < o; k++) {
- for (int index = 0; index < v; index++) {
+ for (int i = 0; i < m; i++)
+ {
+ for (int j = 0; j < v; j++)
+ {
+ for (int k = 0; k < o; k++)
+ {
+ for (int index = 0; index < v; index++)
+ {
GF16Utils.gf16mMul(temp, map1.p11[i][j][index], T12[index][k], l);
GF16Utils.gf16mAdd(map2.f12[i][j][k], map2.f12[i][j][k], temp, l);
}
@@ -359,10 +364,14 @@ public void genF(MapGroup2 map2, MapGroup1 map1, byte[][][] T12) {
}
// Second matrix operation sequence
- for (int i = 0; i < m; i++) {
- for (int j = 0; j < o; j++) {
- for (int k = 0; k < v; k++) {
- for (int index = 0; index < v; index++) {
+ for (int i = 0; i < m; i++)
+ {
+ for (int j = 0; j < o; j++)
+ {
+ for (int k = 0; k < v; k++)
+ {
+ for (int index = 0; index < v; index++)
+ {
GF16Utils.gf16mMul(temp, T12[index][j], map1.p11[i][index][k], l);
GF16Utils.gf16mAdd(map2.f21[i][j][k], map2.f21[i][j][k], temp, l);
}
@@ -371,14 +380,18 @@ public void genF(MapGroup2 map2, MapGroup1 map1, byte[][][] T12) {
}
// Secure clear temporary buffer
- Arrays.fill(temp, (byte) 0);
+ Arrays.fill(temp, (byte)0);
}
private static void copy4DMatrix(byte[][][][] src, byte[][][][] dest,
- int dim1, int dim2, int dim3, int lsq) {
- for (int i = 0; i < dim1; i++) {
- for (int j = 0; j < dim2; j++) {
- for (int k = 0; k < dim3; k++) {
+ int dim1, int dim2, int dim3, int lsq)
+ {
+ for (int i = 0; i < dim1; i++)
+ {
+ for (int j = 0; j < dim2; j++)
+ {
+ for (int k = 0; k < dim3; k++)
+ {
System.arraycopy(
src[i][j][k], 0,
dest[i][j][k], 0,
@@ -389,7 +402,8 @@ private static void copy4DMatrix(byte[][][][] src, byte[][][][] dest,
}
}
- public void genP22(byte[] outP22, byte[][][] T12, byte[][][][] P21, byte[][][][] F12, SnovaParameters params) {
+ public void genP22(byte[] outP22, byte[][][] T12, byte[][][][] P21, byte[][][][] F12, SnovaParameters params)
+ {
int m = params.getM();
int o = params.getO();
int v = params.getV();
@@ -403,11 +417,16 @@ public void genP22(byte[] outP22, byte[][][] T12, byte[][][][] P21, byte[][][][]
byte[] temp1 = new byte[lsq];
byte[] temp2 = new byte[lsq];
- try {
- for (int i = 0; i < m; i++) {
- for (int j = 0; j < o; j++) {
- for (int k = 0; k < o; k++) {
- for (int index = 0; index < v; index++) {
+ try
+ {
+ for (int i = 0; i < m; i++)
+ {
+ for (int j = 0; j < o; j++)
+ {
+ for (int k = 0; k < o; k++)
+ {
+ for (int index = 0; index < v; index++)
+ {
// temp1 = T12[index][j] * F12[i][index][k]
GF16Utils.gf16mMul(temp1, T12[index][j], F12[i][index][k], l);
@@ -427,10 +446,12 @@ public void genP22(byte[] outP22, byte[][][] T12, byte[][][][] P21, byte[][][][]
// Convert GF16 elements to packed bytes
//TODO
//GF16Utils.decode(P22, outP22, m * o * o *lsq);
- } finally {
+ }
+ finally
+ {
// Secure clear temporary buffers
- Arrays.fill(temp1, (byte) 0);
- Arrays.fill(temp2, (byte) 0);
+ Arrays.fill(temp1, (byte)0);
+ Arrays.fill(temp2, (byte)0);
}
}
}
From 79e98f3aeea54235d034d9c5a3635844123dbd51 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Thu, 13 Mar 2025 12:55:19 +1030
Subject: [PATCH 203/890] Remove BufferedLargeMac and ImmediateLargeMac
---
.../crypto/engines/AEADBufferBaseEngine.java | 131 +++++++-----------
.../crypto/engines/AsconEngine.java | 2 +-
.../crypto/engines/ISAPEngine.java | 7 +-
.../crypto/engines/PhotonBeetleEngine.java | 3 +-
4 files changed, 51 insertions(+), 92 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java
index f39f238ab8..7e7664d5e7 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java
@@ -13,9 +13,7 @@ abstract class AEADBufferBaseEngine
protected enum ProcessingBufferType
{
Buffered, // Store a (aad) block size of input and process after the input size exceeds the buffer size
- BufferedLargeMac, // handle the situation when mac size is larger than the block size, used for pb128
Immediate, //process the input immediately when the input size is equal or greater than the block size
- ImmediateLargeMac, // handle the situation when mac size is larger than the block size, used for ascon80pq, ascon128, ISAP_A_128(A)
}
protected enum AADOperatorType
@@ -65,15 +63,9 @@ protected void setInnerMembers(ProcessingBufferType type, AADOperatorType aadOpe
case Buffered:
processor = new BufferedAADProcessor();
break;
- case BufferedLargeMac:
- processor = new BufferedLargeMacAADProcessor();
- break;
case Immediate:
processor = new ImmediateAADProcessor();
break;
- case ImmediateLargeMac:
- processor = new ImmediateLargeMacAADProcessor();
- break;
}
m_bufferSizeDecrypt = BlockSize + MAC_SIZE;
@@ -126,7 +118,7 @@ protected interface AADProcessingBuffer
boolean isLengthExceedingBlockSize(int len, int size);
}
- private abstract class BufferedBaseAADProcessor
+ private class BufferedAADProcessor
implements AADProcessingBuffer
{
public void processAADByte(byte input)
@@ -157,29 +149,15 @@ public int getUpdateOutputSize(int len)
// The -1 is to account for the lazy processing of a full buffer
return Math.max(0, len) - 1;
}
- }
-
- private class BufferedAADProcessor
- extends BufferedBaseAADProcessor
- {
- @Override
- public int processDecryptBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
- {
- return processDecryptionWithSmallMacSize(input, inOff, len, output, outOff);
- }
- }
- private class BufferedLargeMacAADProcessor
- extends BufferedBaseAADProcessor
- {
@Override
public int processDecryptBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
{
- return processDecryptionWithLargeMacSize(input, inOff, len, output, outOff);
+ return processDecryption(input, inOff, len, output, outOff);
}
}
- private abstract class ImmediateBaseAADProcessor
+ private class ImmediateAADProcessor
implements AADProcessingBuffer
{
public void processAADByte(byte input)
@@ -209,25 +187,11 @@ public boolean isLengthExceedingBlockSize(int len, int size)
{
return len >= size;
}
- }
- private class ImmediateAADProcessor
- extends ImmediateBaseAADProcessor
- {
- @Override
- public int processDecryptBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
- {
- return processDecryptionWithSmallMacSize(input, inOff, len, output, outOff);
- }
- }
-
- private class ImmediateLargeMacAADProcessor
- extends ImmediateBaseAADProcessor
- {
@Override
public int processDecryptBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
{
- return processDecryptionWithLargeMacSize(input, inOff, len, output, outOff);
+ return processDecryption(input, inOff, len, output, outOff);
}
}
@@ -582,61 +546,62 @@ protected int processEncDecBytes(byte[] input, int inOff, int len, byte[] output
return resultLength;
}
- private int processDecryptionWithLargeMacSize(byte[] input, int inOff, int len, byte[] output, int outOff)
+ private int processDecryption(byte[] input, int inOff, int len, byte[] output, int outOff)
{
- int resultLength = 0, available;
- // If the mac size is greater than the block size, process the data in m_buf in the loop until
- // there is nearly mac_size data left
- while (processor.isLengthExceedingBlockSize(m_bufPos, BlockSize)
- && processor.isLengthExceedingBlockSize(len + m_bufPos, m_bufferSizeDecrypt))
- {
- processBufferDecrypt(m_buf, resultLength, output, outOff + resultLength);
- m_bufPos -= BlockSize;
- resultLength += BlockSize;
- }
- if (m_bufPos > 0)
+ int resultLength = 0, available = m_bufferSizeDecrypt - m_bufPos;
+ if (MAC_SIZE > BlockSize)
{
- System.arraycopy(m_buf, resultLength, m_buf, 0, m_bufPos);
- if (processor.isLengthExceedingBlockSize(m_bufPos + len, m_bufferSizeDecrypt))
+ // situation: pb128, ascon80pq, ascon128, ISAP_A_128(A)
+ // If the mac size is greater than the block size, process the data in m_buf in the loop until
+ // there is nearly mac_size data left
+ while (processor.isLengthExceedingBlockSize(m_bufPos, BlockSize)
+ && processor.isLengthExceedingBlockSize(len + m_bufPos, m_bufferSizeDecrypt))
{
- available = Math.max(BlockSize - m_bufPos, 0);
- System.arraycopy(input, inOff, m_buf, m_bufPos, available);
- inOff += available;
- processBufferDecrypt(m_buf, 0, output, outOff + resultLength);
+ processBufferDecrypt(m_buf, resultLength, output, outOff + resultLength);
+ m_bufPos -= BlockSize;
+ resultLength += BlockSize;
}
- else
+ if (m_bufPos > 0)
{
- System.arraycopy(input, inOff, m_buf, m_bufPos, len);
- m_bufPos += len;
- return -1;
+ System.arraycopy(m_buf, resultLength, m_buf, 0, m_bufPos);
+ if (processor.isLengthExceedingBlockSize(m_bufPos + len, m_bufferSizeDecrypt))
+ {
+ available = Math.max(BlockSize - m_bufPos, 0);
+ System.arraycopy(input, inOff, m_buf, m_bufPos, available);
+ inOff += available;
+ processBufferDecrypt(m_buf, 0, output, outOff + resultLength);
+ }
+ else
+ {
+ System.arraycopy(input, inOff, m_buf, m_bufPos, len);
+ m_bufPos += len;
+ return -1;
+ }
}
}
- return inOff;
- }
-
- private int processDecryptionWithSmallMacSize(byte[] input, int inOff, int len, byte[] output, int outOff)
- {
- int resultLength = 0, available = m_bufferSizeDecrypt - m_bufPos;
- if (m_bufPos > 0)
+ else
{
- if (processor.isLengthExceedingBlockSize(m_bufPos, BlockSize))
+ if (m_bufPos > 0)
{
- processBufferDecrypt(m_buf, 0, output, outOff);
- m_bufPos -= BlockSize;
- System.arraycopy(m_buf, BlockSize, m_buf, 0, m_bufPos);
- resultLength = BlockSize;
- available += BlockSize;
- if (processor.isLengthWithinAvailableSpace(len, available))
+ if (processor.isLengthExceedingBlockSize(m_bufPos, BlockSize))
{
- System.arraycopy(input, inOff, m_buf, m_bufPos, len);
- m_bufPos += len;
- return -1;
+ processBufferDecrypt(m_buf, 0, output, outOff);
+ m_bufPos -= BlockSize;
+ System.arraycopy(m_buf, BlockSize, m_buf, 0, m_bufPos);
+ resultLength = BlockSize;
+ available += BlockSize;
+ if (processor.isLengthWithinAvailableSpace(len, available))
+ {
+ System.arraycopy(input, inOff, m_buf, m_bufPos, len);
+ m_bufPos += len;
+ return -1;
+ }
}
+ available = Math.max(BlockSize - m_bufPos, 0);
+ System.arraycopy(input, inOff, m_buf, m_bufPos, available);
+ inOff += available;
+ processBufferDecrypt(m_buf, 0, output, outOff + resultLength);
}
- available = Math.max(BlockSize - m_bufPos, 0);
- System.arraycopy(input, inOff, m_buf, m_bufPos, available);
- inOff += available;
- processBufferDecrypt(m_buf, 0, output, outOff + resultLength);
}
return inOff;
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/AsconEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/AsconEngine.java
index bbb807e507..2c9c9f3791 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/AsconEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/AsconEngine.java
@@ -63,7 +63,7 @@ public AsconEngine(AsconParameters asconParameters)
nr = (BlockSize == 8) ? 6 : 8;
AADBufferSize = BlockSize;
dsep = 1L;
- setInnerMembers(asconParameters == AsconParameters.ascon128a ? ProcessingBufferType.Immediate : ProcessingBufferType.ImmediateLargeMac, AADOperatorType.Default, DataOperatorType.Default);
+ setInnerMembers(ProcessingBufferType.Immediate, AADOperatorType.Default, DataOperatorType.Default);
}
protected long pad(int i)
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/ISAPEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/ISAPEngine.java
index a324de8321..e170f0ff96 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/ISAPEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/ISAPEngine.java
@@ -26,34 +26,29 @@ public enum IsapType
public ISAPEngine(IsapType isapType)
{
KEY_SIZE = IV_SIZE = MAC_SIZE = 16;
- ProcessingBufferType bufferType;
switch (isapType)
{
case ISAP_A_128A:
ISAPAEAD = new ISAPAEAD_A_128A();
algorithmName = "ISAP-A-128A AEAD";
- bufferType = ProcessingBufferType.ImmediateLargeMac;
break;
case ISAP_K_128A:
ISAPAEAD = new ISAPAEAD_K_128A();
algorithmName = "ISAP-K-128A AEAD";
- bufferType = ProcessingBufferType.Immediate;
break;
case ISAP_A_128:
ISAPAEAD = new ISAPAEAD_A_128();
algorithmName = "ISAP-A-128 AEAD";
- bufferType = ProcessingBufferType.ImmediateLargeMac;
break;
case ISAP_K_128:
ISAPAEAD = new ISAPAEAD_K_128();
algorithmName = "ISAP-K-128 AEAD";
- bufferType = ProcessingBufferType.Immediate;
break;
default:
throw new IllegalArgumentException("Incorrect ISAP parameter");
}
AADBufferSize = BlockSize;
- setInnerMembers(bufferType, AADOperatorType.Default, DataOperatorType.Counter);
+ setInnerMembers(ProcessingBufferType.Immediate, AADOperatorType.Default, DataOperatorType.Counter);
}
private static final int ISAP_STATE_SZ = 40;
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java
index 5a2afe6ae8..b9b5657add 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java
@@ -72,8 +72,7 @@ public PhotonBeetleEngine(PhotonBeetleParameters pbp)
STATE_INBYTES = (STATE_INBITS + 7) >>> 3;
LAST_THREE_BITS_OFFSET = (STATE_INBITS - ((STATE_INBYTES - 1) << 3) - 3);
algorithmName = "Photon-Beetle AEAD";
- setInnerMembers(pbp == PhotonBeetleParameters.pb128 ? ProcessingBufferType.Buffered : ProcessingBufferType.BufferedLargeMac,
- AADOperatorType.Counter, DataOperatorType.Counter);
+ setInnerMembers(ProcessingBufferType.Buffered, AADOperatorType.Counter, DataOperatorType.Counter);
}
@Override
From 7da1e85163ea19939400cf744b2d681e38d36c3a Mon Sep 17 00:00:00 2001
From: gefeili
Date: Thu, 13 Mar 2025 14:45:48 +1030
Subject: [PATCH 204/890] refactor of processDecryption
---
.../crypto/engines/AEADBufferBaseEngine.java | 79 ++++++-------------
1 file changed, 24 insertions(+), 55 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java
index 7e7664d5e7..06ba3df709 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java
@@ -323,7 +323,6 @@ public int getLen()
@Override
public void reset()
{
-
}
}
@@ -548,60 +547,30 @@ protected int processEncDecBytes(byte[] input, int inOff, int len, byte[] output
private int processDecryption(byte[] input, int inOff, int len, byte[] output, int outOff)
{
- int resultLength = 0, available = m_bufferSizeDecrypt - m_bufPos;
- if (MAC_SIZE > BlockSize)
+ int resultLength = 0, available;
+
+ // loop will run more than once for the following situation: pb128, ascon80pq, ascon128, ISAP_A_128(A)
+ while (processor.isLengthExceedingBlockSize(m_bufPos, BlockSize)
+ && processor.isLengthExceedingBlockSize(len + m_bufPos, m_bufferSizeDecrypt))
{
- // situation: pb128, ascon80pq, ascon128, ISAP_A_128(A)
- // If the mac size is greater than the block size, process the data in m_buf in the loop until
- // there is nearly mac_size data left
- while (processor.isLengthExceedingBlockSize(m_bufPos, BlockSize)
- && processor.isLengthExceedingBlockSize(len + m_bufPos, m_bufferSizeDecrypt))
- {
- processBufferDecrypt(m_buf, resultLength, output, outOff + resultLength);
- m_bufPos -= BlockSize;
- resultLength += BlockSize;
- }
- if (m_bufPos > 0)
- {
- System.arraycopy(m_buf, resultLength, m_buf, 0, m_bufPos);
- if (processor.isLengthExceedingBlockSize(m_bufPos + len, m_bufferSizeDecrypt))
- {
- available = Math.max(BlockSize - m_bufPos, 0);
- System.arraycopy(input, inOff, m_buf, m_bufPos, available);
- inOff += available;
- processBufferDecrypt(m_buf, 0, output, outOff + resultLength);
- }
- else
- {
- System.arraycopy(input, inOff, m_buf, m_bufPos, len);
- m_bufPos += len;
- return -1;
- }
- }
+ processBufferDecrypt(m_buf, resultLength, output, outOff + resultLength);
+ m_bufPos -= BlockSize;
+ resultLength += BlockSize;
}
- else
+
+ if (m_bufPos > 0)
{
- if (m_bufPos > 0)
+ System.arraycopy(m_buf, resultLength, m_buf, 0, m_bufPos);
+ if (processor.isLengthWithinAvailableSpace(m_bufPos + len, m_bufferSizeDecrypt))
{
- if (processor.isLengthExceedingBlockSize(m_bufPos, BlockSize))
- {
- processBufferDecrypt(m_buf, 0, output, outOff);
- m_bufPos -= BlockSize;
- System.arraycopy(m_buf, BlockSize, m_buf, 0, m_bufPos);
- resultLength = BlockSize;
- available += BlockSize;
- if (processor.isLengthWithinAvailableSpace(len, available))
- {
- System.arraycopy(input, inOff, m_buf, m_bufPos, len);
- m_bufPos += len;
- return -1;
- }
- }
- available = Math.max(BlockSize - m_bufPos, 0);
- System.arraycopy(input, inOff, m_buf, m_bufPos, available);
- inOff += available;
- processBufferDecrypt(m_buf, 0, output, outOff + resultLength);
+ System.arraycopy(input, inOff, m_buf, m_bufPos, len);
+ m_bufPos += len;
+ return -1;
}
+ available = Math.max(BlockSize - m_bufPos, 0);
+ System.arraycopy(input, inOff, m_buf, m_bufPos, available);
+ inOff += available;
+ processBufferDecrypt(m_buf, 0, output, outOff + resultLength);
}
return inOff;
}
@@ -649,7 +618,7 @@ public int doFinal(byte[] output, int outOff)
return resultLength;
}
- public int getBlockSize()
+ public final int getBlockSize()
{
return BlockSize;
}
@@ -739,7 +708,7 @@ protected boolean checkData(boolean isDoFinal)
protected abstract void finishAAD(State nextState, boolean isDoFinal);
- protected void bufferReset()
+ protected final void bufferReset()
{
if (m_buf != null)
{
@@ -773,7 +742,7 @@ protected void bufferReset()
dataOperator.reset();
}
- protected void ensureSufficientOutputBuffer(byte[] output, int outOff, int len)
+ protected final void ensureSufficientOutputBuffer(byte[] output, int outOff, int len)
{
if (len >= BlockSize && outOff + len > output.length)
{
@@ -781,7 +750,7 @@ protected void ensureSufficientOutputBuffer(byte[] output, int outOff, int len)
}
}
- protected void ensureSufficientInputBuffer(byte[] input, int inOff, int len)
+ protected final void ensureSufficientInputBuffer(byte[] input, int inOff, int len)
{
if (inOff + len > input.length)
{
@@ -789,7 +758,7 @@ protected void ensureSufficientInputBuffer(byte[] input, int inOff, int len)
}
}
- protected void ensureInitialized()
+ protected final void ensureInitialized()
{
if (m_state == State.Uninitialized)
{
From 063bb449beb0f076deb73ce4f5f09bd7bf4603e1 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Thu, 13 Mar 2025 14:47:49 +1030
Subject: [PATCH 205/890] refactor of processDecryption, remove
AADProcessingBuffer.processDecryptBytes
---
.../crypto/engines/AEADBufferBaseEngine.java | 16 +---------------
1 file changed, 1 insertion(+), 15 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java
index 06ba3df709..6e0aa86aab 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java
@@ -109,8 +109,6 @@ protected interface AADProcessingBuffer
{
void processAADByte(byte input);
- int processDecryptBytes(byte[] input, int inOff, int len, byte[] output, int outOff);
-
int getUpdateOutputSize(int len);
boolean isLengthWithinAvailableSpace(int len, int available);
@@ -149,12 +147,6 @@ public int getUpdateOutputSize(int len)
// The -1 is to account for the lazy processing of a full buffer
return Math.max(0, len) - 1;
}
-
- @Override
- public int processDecryptBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
- {
- return processDecryption(input, inOff, len, output, outOff);
- }
}
private class ImmediateAADProcessor
@@ -187,12 +179,6 @@ public boolean isLengthExceedingBlockSize(int len, int size)
{
return len >= size;
}
-
- @Override
- public int processDecryptBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
- {
- return processDecryption(input, inOff, len, output, outOff);
- }
}
protected interface AADOperator
@@ -525,7 +511,7 @@ protected int processEncDecBytes(byte[] input, int inOff, int len, byte[] output
ensureSufficientOutputBuffer(output, outOff, resultLength);
int originalInOff = inOff;
int originalm_bufPos = m_bufPos;
- if ((inOff = processor.processDecryptBytes(input, inOff, len, output, outOff)) == -1)
+ if ((inOff = processDecryption(input, inOff, len, output, outOff)) == -1)
{
return resultLength;
}
From c6ed370d4065d9f0dae13fcf0837da3e154605f3 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Thu, 13 Mar 2025 16:58:24 +1100
Subject: [PATCH 206/890] corrected PKIX oid.
---
.../internal/asn1/iana/IANAObjectIdentifiers.java | 4 ++--
.../org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java | 5 ++---
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/iana/IANAObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/internal/asn1/iana/IANAObjectIdentifiers.java
index 97a97d0680..2b586baf63 100644
--- a/core/src/main/java/org/bouncycastle/internal/asn1/iana/IANAObjectIdentifiers.java
+++ b/core/src/main/java/org/bouncycastle/internal/asn1/iana/IANAObjectIdentifiers.java
@@ -37,8 +37,8 @@ public interface IANAObjectIdentifiers
/** IANA security nametypes; 1.3.6.1.5.6 */
static final ASN1ObjectIdentifier security_nametypes = security.branch("6");
- /** PKIX base OID: 1.3.6.1.5.6.6 */
- static final ASN1ObjectIdentifier pkix = security_mechanisms.branch("6");
+ /** PKIX base OID: 1.3.6.1.5.5.7 */
+ static final ASN1ObjectIdentifier pkix = security_mechanisms.branch("7");
/** IPSEC base OID: 1.3.6.1.5.5.8 */
diff --git a/util/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java b/util/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java
index 5bfdbab891..3be353ca22 100644
--- a/util/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java
+++ b/util/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java
@@ -37,9 +37,8 @@ public interface IANAObjectIdentifiers
/** IANA security nametypes; 1.3.6.1.5.6 */
static final ASN1ObjectIdentifier security_nametypes = security.branch("6");
- /** PKIX base OID: 1.3.6.1.5.6.6 */
- static final ASN1ObjectIdentifier pkix = security_mechanisms.branch("6");
-
+ /** PKIX base OID: 1.3.6.1.5.5.7 */
+ static final ASN1ObjectIdentifier pkix = security_mechanisms.branch("7");
/** IPSEC base OID: 1.3.6.1.5.5.8 */
static final ASN1ObjectIdentifier ipsec = security_mechanisms.branch("8");
From bee11a91ad41cfeb3c26cd60d629c05d52fca89b Mon Sep 17 00:00:00 2001
From: gefeili
Date: Thu, 13 Mar 2025 16:32:50 +1030
Subject: [PATCH 207/890] refactor of processEncDecBytes
---
.../crypto/engines/AEADBufferBaseEngine.java | 98 +++++++------------
1 file changed, 35 insertions(+), 63 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java
index 6e0aa86aab..8d8c30e502 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java
@@ -465,26 +465,26 @@ public int processBytes(byte[] input, int inOff, int len, byte[] output, int out
protected int processEncDecBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
{
+ boolean forEncryption = checkData(false);
int available, resultLength;
- if (checkData(false))
+ available = (forEncryption ? BlockSize : m_bufferSizeDecrypt) - m_bufPos;
+ // The function is just an operator < or <=
+ if (processor.isLengthWithinAvailableSpace(len, available))
+ {
+ System.arraycopy(input, inOff, m_buf, m_bufPos, len);
+ m_bufPos += len;
+ return 0;
+ }
+ resultLength = processor.getUpdateOutputSize(len) + m_bufPos - (forEncryption ? 0 : MAC_SIZE);
+ ensureSufficientOutputBuffer(output, outOff, resultLength - resultLength % BlockSize);
+ resultLength = 0;
+ if (forEncryption)
{
- resultLength = 0;
- available = processor.getUpdateOutputSize(len) + m_bufPos;
- ensureSufficientOutputBuffer(output, outOff, available - available % BlockSize);
if (m_bufPos > 0)
{
- available = BlockSize - m_bufPos;
- // The function is just an operator < or <=
- if (processor.isLengthWithinAvailableSpace(len, available))
- {
- System.arraycopy(input, inOff, m_buf, m_bufPos, len);
- m_bufPos += len;
- return 0;
- }
System.arraycopy(input, inOff, m_buf, m_bufPos, available);
inOff += available;
len -= available;
-
processBufferEncrypt(m_buf, 0, output, outOff);
resultLength = BlockSize;
}
@@ -499,25 +499,30 @@ protected int processEncDecBytes(byte[] input, int inOff, int len, byte[] output
}
else
{
- available = m_bufferSizeDecrypt - m_bufPos;
- if (processor.isLengthWithinAvailableSpace(len, available))
+ // loop will run more than once for the following situation: pb128, ascon80pq, ascon128, ISAP_A_128(A)
+ while (processor.isLengthExceedingBlockSize(m_bufPos, BlockSize)
+ && processor.isLengthExceedingBlockSize(len + m_bufPos, m_bufferSizeDecrypt))
{
- System.arraycopy(input, inOff, m_buf, m_bufPos, len);
- m_bufPos += len;
- return 0;
+ processBufferDecrypt(m_buf, resultLength, output, outOff + resultLength);
+ m_bufPos -= BlockSize;
+ resultLength += BlockSize;
}
- resultLength = (processor.getUpdateOutputSize(len) + m_bufPos - MAC_SIZE);
- resultLength -= resultLength % BlockSize;
- ensureSufficientOutputBuffer(output, outOff, resultLength);
- int originalInOff = inOff;
- int originalm_bufPos = m_bufPos;
- if ((inOff = processDecryption(input, inOff, len, output, outOff)) == -1)
+ if (m_bufPos > 0)
{
- return resultLength;
+ System.arraycopy(m_buf, resultLength, m_buf, 0, m_bufPos);
+ if (processor.isLengthWithinAvailableSpace(m_bufPos + len, m_bufferSizeDecrypt))
+ {
+ System.arraycopy(input, inOff, m_buf, m_bufPos, len);
+ m_bufPos += len;
+ return resultLength;
+ }
+ available = Math.max(BlockSize - m_bufPos, 0);
+ System.arraycopy(input, inOff, m_buf, m_bufPos, available);
+ inOff += available;
+ len -= available;
+ processBufferDecrypt(m_buf, 0, output, outOff + resultLength);
+ resultLength += BlockSize;
}
- resultLength = inOff - originalInOff;
- len -= resultLength;
- resultLength += originalm_bufPos;
while (processor.isLengthExceedingBlockSize(len, m_bufferSizeDecrypt))
{
processBufferDecrypt(input, inOff, output, outOff + resultLength);
@@ -531,36 +536,6 @@ protected int processEncDecBytes(byte[] input, int inOff, int len, byte[] output
return resultLength;
}
- private int processDecryption(byte[] input, int inOff, int len, byte[] output, int outOff)
- {
- int resultLength = 0, available;
-
- // loop will run more than once for the following situation: pb128, ascon80pq, ascon128, ISAP_A_128(A)
- while (processor.isLengthExceedingBlockSize(m_bufPos, BlockSize)
- && processor.isLengthExceedingBlockSize(len + m_bufPos, m_bufferSizeDecrypt))
- {
- processBufferDecrypt(m_buf, resultLength, output, outOff + resultLength);
- m_bufPos -= BlockSize;
- resultLength += BlockSize;
- }
-
- if (m_bufPos > 0)
- {
- System.arraycopy(m_buf, resultLength, m_buf, 0, m_bufPos);
- if (processor.isLengthWithinAvailableSpace(m_bufPos + len, m_bufferSizeDecrypt))
- {
- System.arraycopy(input, inOff, m_buf, m_bufPos, len);
- m_bufPos += len;
- return -1;
- }
- available = Math.max(BlockSize - m_bufPos, 0);
- System.arraycopy(input, inOff, m_buf, m_bufPos, available);
- inOff += available;
- processBufferDecrypt(m_buf, 0, output, outOff + resultLength);
- }
- return inOff;
- }
-
@Override
public int doFinal(byte[] output, int outOff)
throws IllegalStateException, InvalidCipherTextException
@@ -583,10 +558,7 @@ public int doFinal(byte[] output, int outOff)
resultLength = m_bufPos;
}
- if (outOff > output.length - resultLength)
- {
- throw new OutputLengthException("output buffer too short");
- }
+ ensureSufficientOutputBuffer(output, outOff, resultLength);
mac = new byte[MAC_SIZE];
processFinalBlock(output, outOff);
if (forEncryption)
@@ -730,7 +702,7 @@ protected final void bufferReset()
protected final void ensureSufficientOutputBuffer(byte[] output, int outOff, int len)
{
- if (len >= BlockSize && outOff + len > output.length)
+ if (outOff + len > output.length)
{
throw new OutputLengthException("output buffer too short");
}
From d73b9c7142332b54a6a9212759965c8bb4653584 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Thu, 13 Mar 2025 16:36:13 +1030
Subject: [PATCH 208/890] Remove the debug code in SparkleTest
---
.../java/org/bouncycastle/crypto/test/SparkleTest.java | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/SparkleTest.java b/core/src/test/java/org/bouncycastle/crypto/test/SparkleTest.java
index 6b6914b973..f9fd990e8c 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/SparkleTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/SparkleTest.java
@@ -379,10 +379,10 @@ private void implTestVectorsEngine(SparkleEngine.SparkleParameters pbp, String f
byte[] ad = Hex.decode(map.get("AD"));
byte[] pt = Hex.decode(map.get("PT"));
byte[] ct = Hex.decode(map.get("CT"));
- if (!map.get("Count").equals("17"))
- {
- continue;
- }
+// if (!map.get("Count").equals("17"))
+// {
+// continue;
+// }
CipherParameters parameters = new ParametersWithIV(new KeyParameter(key), nonce);
// Encrypt
From 2c4453a7f3ff30995c327c65a453b08bea4e5fe9 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Fri, 14 Mar 2025 07:12:27 +1030
Subject: [PATCH 209/890] Fix the issue for #2025
---
.../java/org/bouncycastle/crypto/engines/RomulusEngine.java | 2 +-
.../java/org/bouncycastle/crypto/engines/XoodyakEngine.java | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/RomulusEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/RomulusEngine.java
index ff1fd4cc5c..d2196675ff 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/RomulusEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/RomulusEngine.java
@@ -855,7 +855,7 @@ static void hirose_128_128_256(byte[] h, byte[] g, byte[] m, int mOff)
}
@Override
- public void init(byte[] key, byte[] iv)
+ protected void init(byte[] key, byte[] iv)
throws IllegalArgumentException
{
npub = iv;
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/XoodyakEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/XoodyakEngine.java
index 167990b30b..a03755bbbc 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/XoodyakEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/XoodyakEngine.java
@@ -43,7 +43,7 @@ public XoodyakEngine()
}
@Override
- public void init(byte[] key, byte[] iv)
+ protected void init(byte[] key, byte[] iv)
throws IllegalArgumentException
{
K = key;
From f8c09c9786f752a5c7ac911a1025e2ce09ee8523 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Fri, 14 Mar 2025 08:32:16 +1030
Subject: [PATCH 210/890] Fix the issue for #2025
---
.../crypto/engines/AEADBufferBaseEngine.java | 65 +++++++++++--------
.../crypto/engines/PhotonBeetleEngine.java | 2 +-
2 files changed, 38 insertions(+), 29 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java
index 8d8c30e502..983fea482e 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java
@@ -28,7 +28,7 @@ protected enum DataOperatorType
Default,
Counter,
Stream,
- //StreamCipher //TODO: add for Grain 128 AEAD
+ StreamCipher
}
protected enum State
@@ -99,9 +99,10 @@ protected void setInnerMembers(ProcessingBufferType type, AADOperatorType aadOpe
m_buf = new byte[MAC_SIZE];
dataOperator = new StreamDataOperator();
break;
-// case StreamCipher:
-// dataOperator = new StreamCipherOperator();
-// break;
+ case StreamCipher:
+ m_buf = new byte[m_bufferSizeDecrypt];
+ dataOperator = new StreamCipherOperator();
+ break;
}
}
@@ -368,30 +369,38 @@ public void reset()
}
}
-// protected class StreamCipherOperator
-// implements DataOperator
-// {
-// private int len;
-// @Override
-// public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
-// {
-// this.len = len;
-// processBufferEncrypt(input, inOff, output, outOff);
-// return len;
-// }
-//
-// @Override
-// public int getLen()
-// {
-// return 0;
-// }
-//
-// @Override
-// public void reset()
-// {
-//
-// }
-// }
+ protected class StreamCipherOperator
+ implements DataOperator
+ {
+ private int len;
+
+ @Override
+ public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
+ {
+ this.len = len;
+ if (forEncryption)
+ {
+ processBufferEncrypt(input, inOff, output, outOff);
+ }
+ else
+ {
+ processBufferDecrypt(input, inOff, output, outOff);
+ }
+ return len;
+ }
+
+ @Override
+ public int getLen()
+ {
+ return 0;
+ }
+
+ @Override
+ public void reset()
+ {
+
+ }
+ }
protected static final class ErasableOutputStream
extends ByteArrayOutputStream
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java
index b9b5657add..b90ace4c42 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java
@@ -116,7 +116,7 @@ protected void finishAAD(State nextState, boolean isDoFinal)
m_state = nextState;
}
- public void processFinalAAD()
+ protected void processFinalAAD()
{
int aadLen = aadOperator.getLen();
if (aadLen != 0)
From dd3826a1e90aabaa2166c18032b957381f6baf3e Mon Sep 17 00:00:00 2001
From: gefeili
Date: Fri, 14 Mar 2025 08:33:41 +1030
Subject: [PATCH 211/890] Fix the issue for #2025
---
.../org/bouncycastle/crypto/engines/PhotonBeetleEngine.java | 2 +-
.../java/org/bouncycastle/crypto/engines/RomulusEngine.java | 2 +-
.../java/org/bouncycastle/crypto/engines/XoodyakEngine.java | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java
index b9b5657add..b90ace4c42 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java
@@ -116,7 +116,7 @@ protected void finishAAD(State nextState, boolean isDoFinal)
m_state = nextState;
}
- public void processFinalAAD()
+ protected void processFinalAAD()
{
int aadLen = aadOperator.getLen();
if (aadLen != 0)
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/RomulusEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/RomulusEngine.java
index ff1fd4cc5c..d2196675ff 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/RomulusEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/RomulusEngine.java
@@ -855,7 +855,7 @@ static void hirose_128_128_256(byte[] h, byte[] g, byte[] m, int mOff)
}
@Override
- public void init(byte[] key, byte[] iv)
+ protected void init(byte[] key, byte[] iv)
throws IllegalArgumentException
{
npub = iv;
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/XoodyakEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/XoodyakEngine.java
index 167990b30b..a03755bbbc 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/XoodyakEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/XoodyakEngine.java
@@ -43,7 +43,7 @@ public XoodyakEngine()
}
@Override
- public void init(byte[] key, byte[] iv)
+ protected void init(byte[] key, byte[] iv)
throws IllegalArgumentException
{
K = key;
From 20e323f5d1ec824c0466ad8fb774152fedd84fbe Mon Sep 17 00:00:00 2001
From: David Hook
Date: Fri, 14 Mar 2025 14:57:52 +1100
Subject: [PATCH 212/890] updated HQC to always generate 256 bit secrets
---
.../bouncycastle/pqc/crypto/hqc/HQCKEMExtractor.java | 2 +-
.../bouncycastle/pqc/crypto/hqc/HQCKEMGenerator.java | 2 +-
.../org/bouncycastle/pqc/crypto/hqc/HQCParameters.java | 2 +-
.../pqc/jcajce/provider/hqc/HQCCipherSpi.java | 6 +++---
.../pqc/jcajce/provider/util/WrapUtil.java | 10 ++++++++++
.../bouncycastle/pqc/jcajce/provider/test/HQCTest.java | 2 +-
6 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKEMExtractor.java b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKEMExtractor.java
index b565ea41c6..bc3cb1483b 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKEMExtractor.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKEMExtractor.java
@@ -30,7 +30,7 @@ public byte[] extractSecret(byte[] encapsulation)
engine.decaps(session_key, encapsulation, sk);
- return Arrays.copyOfRange(session_key, 0, key.getParameters().getK());
+ return Arrays.copyOfRange(session_key, 0, 32);
}
public int getEncapsulationLength()
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKEMGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKEMGenerator.java
index 85cc4750d0..47caa9476e 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKEMGenerator.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKEMGenerator.java
@@ -36,6 +36,6 @@ public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recip
byte[] cipherText = Arrays.concatenate(u, v, salt);
- return new SecretWithEncapsulationImpl(Arrays.copyOfRange(K, 0, key.getParameters().getK()), cipherText);
+ return new SecretWithEncapsulationImpl(Arrays.copyOfRange(K, 0, 32), cipherText);
}
}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCParameters.java
index 1090848fa8..86b965ec98 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCParameters.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCParameters.java
@@ -118,7 +118,7 @@ HQCEngine getEngine()
public int getSessionKeySize()
{
- return k * 8;
+ return 32 * 8;
}
public String getName()
diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/hqc/HQCCipherSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/hqc/HQCCipherSpi.java
index 2281b93db1..92a6c432dc 100644
--- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/hqc/HQCCipherSpi.java
+++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/hqc/HQCCipherSpi.java
@@ -251,7 +251,7 @@ protected byte[] engineWrap(
Wrapper kWrap = WrapUtil.getWrapper(kemParameterSpec.getKeyAlgorithmName());
- KeyParameter keyParameter = new KeyParameter(secEnc.getSecret());
+ KeyParameter keyParameter = new KeyParameter(WrapUtil.trimSecret(kemParameterSpec.getKeyAlgorithmName(), secEnc.getSecret()));
kWrap.init(true, keyParameter);
@@ -268,7 +268,7 @@ protected byte[] engineWrap(
return rv;
}
catch (IllegalArgumentException e)
- {
+ { e.printStackTrace();
throw new IllegalBlockSizeException("unable to generate KTS secret: " + e.getMessage());
}
catch (DestroyFailedException e)
@@ -296,7 +296,7 @@ protected Key engineUnwrap(
Wrapper kWrap = WrapUtil.getWrapper(kemParameterSpec.getKeyAlgorithmName());
- KeyParameter keyParameter = new KeyParameter(secret);
+ KeyParameter keyParameter = new KeyParameter(WrapUtil.trimSecret(kemParameterSpec.getKeyAlgorithmName(), secret));
Arrays.clear(secret);
diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/util/WrapUtil.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/util/WrapUtil.java
index 41ff97e787..5a99f1cd7d 100644
--- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/util/WrapUtil.java
+++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/util/WrapUtil.java
@@ -91,6 +91,16 @@ else if (keyAlgorithmName.equalsIgnoreCase("ARIA-KWP"))
return kWrap;
}
+ public static byte[] trimSecret(String algName, byte[] secret)
+ {
+ if (algName.equals("SEED"))
+ {
+ return Arrays.copyOfRange(secret, 0, 16);
+ }
+
+ return secret;
+ }
+
private static byte[] makeKeyBytes(KTSParameterSpec ktsSpec, byte[] secret)
throws InvalidKeyException
{
diff --git a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/HQCTest.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/HQCTest.java
index 107512a2be..a818b59897 100644
--- a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/HQCTest.java
+++ b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/HQCTest.java
@@ -123,7 +123,7 @@ public void testGenerateAES()
SecretKeyWithEncapsulation secEnc1 = (SecretKeyWithEncapsulation)keyGen.generateKey();
assertEquals("AES", secEnc1.getAlgorithm());
- assertEquals(16, secEnc1.getEncoded().length);
+ assertEquals(32, secEnc1.getEncoded().length);
keyGen.init(new KEMExtractSpec(kp.getPrivate(), secEnc1.getEncapsulation(), "AES"));
From 81e40ca158070ebcaa4e27102b4069470a2e152f Mon Sep 17 00:00:00 2001
From: gefeili
Date: Fri, 14 Mar 2025 15:30:57 +1030
Subject: [PATCH 213/890] Fix the issue related to Grain128AEADEngine
---
.../crypto/engines/AEADBufferBaseEngine.java | 34 ++-
.../crypto/engines/Grain128AEADEngine.java | 289 ++++++++----------
.../bouncycastle/crypto/test/CipherTest.java | 2 +-
.../crypto/test/Grain128AEADTest.java | 126 ++++----
4 files changed, 224 insertions(+), 227 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java
index 983fea482e..87fee36a32 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java
@@ -100,6 +100,7 @@ protected void setInnerMembers(ProcessingBufferType type, AADOperatorType aadOpe
dataOperator = new StreamDataOperator();
break;
case StreamCipher:
+ BlockSize = 0;
m_buf = new byte[m_bufferSizeDecrypt];
dataOperator = new StreamCipherOperator();
break;
@@ -377,28 +378,51 @@ protected class StreamCipherOperator
@Override
public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
{
- this.len = len;
+ boolean forEncryption = checkData(false);
if (forEncryption)
{
+ this.len = len;
processBufferEncrypt(input, inOff, output, outOff);
+ return len;
}
else
{
- processBufferDecrypt(input, inOff, output, outOff);
+ // keep last mac size bytes
+ int available = Math.max(m_bufPos + len - MAC_SIZE, 0);
+ int rlt = 0;
+ if (m_bufPos > 0)
+ {
+ this.len = Math.min(available, m_bufPos);
+ rlt = this.len;
+ processBufferDecrypt(m_buf, 0, output, outOff);
+ available -= rlt;
+ m_bufPos -= rlt;
+ System.arraycopy(m_buf, rlt, m_buf, 0, m_bufPos);
+ }
+ if (available > 0)
+ {
+ this.len = available;
+ processBufferDecrypt(input, inOff, output, outOff);
+ rlt += available;
+ len -= available;
+ inOff += available;
+ }
+
+ System.arraycopy(input, inOff, m_buf, m_bufPos, len);
+ m_bufPos += len;
+ return rlt;
}
- return len;
}
@Override
public int getLen()
{
- return 0;
+ return len;
}
@Override
public void reset()
{
-
}
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java
index de8766363f..2bffd9fcec 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java
@@ -1,17 +1,12 @@
package org.bouncycastle.crypto.engines;
-import java.io.ByteArrayOutputStream;
-
-import org.bouncycastle.crypto.DataLengthException;
-import org.bouncycastle.crypto.InvalidCipherTextException;
-import org.bouncycastle.crypto.OutputLengthException;
import org.bouncycastle.util.Pack;
/**
* Grain-128 AEAD, based on the current round 3 submission, https://grain-128aead.github.io/
*/
public class Grain128AEADEngine
- extends AEADBaseEngine
+ extends AEADBufferBaseEngine
{
/**
* Constants
@@ -29,16 +24,13 @@ public class Grain128AEADEngine
private int[] authAcc;
private int[] authSr;
- private boolean initialised = false;
- private boolean aadFinished = false;
- private final ErasableOutputStream aadData = new ErasableOutputStream();
-
public Grain128AEADEngine()
{
- algorithmName = "Grain-128AEAD";
+ algorithmName = "Grain-128 AEAD";
KEY_SIZE = 16;
IV_SIZE = 12;
MAC_SIZE = 8;
+ setInnerMembers(ProcessingBufferType.Immediate, AADOperatorType.Stream, DataOperatorType.StreamCipher);
}
/**
@@ -49,11 +41,6 @@ public Grain128AEADEngine()
protected void init(byte[] key, byte[] iv)
throws IllegalArgumentException
{
- /*
- * Grain encryption and decryption is completely symmetrical, so the
- * 'forEncryption' is irrelevant.
- */
-
/*
* Initialize variables.
*/
@@ -63,37 +50,15 @@ protected void init(byte[] key, byte[] iv)
nfsr = new int[STATE_SIZE];
authAcc = new int[2];
authSr = new int[2];
-
+ m_state = forEncryption ? State.EncInit : State.DecInit;
System.arraycopy(iv, 0, workingIV, 0, IV_SIZE);
-
+ workingIV[12] = (byte)0xFF;
+ workingIV[13] = (byte)0xFF;
+ workingIV[14] = (byte)0xFF;
+ workingIV[15] = (byte)0x7F;
reset();
}
- /**
- * 320 clocks initialization phase.
- */
- private void initGrain()
- {
- for (int i = 0; i < 320; ++i)
- {
- int output = getOutput();
- nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0] ^ output) & 1);
- lfsr = shift(lfsr, (getOutputLFSR() ^ output) & 1);
- }
- for (int quotient = 0; quotient < 8; ++quotient)
- {
- for (int remainder = 0; remainder < 8; ++remainder)
- {
- int output = getOutput();
- nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0] ^ output ^ ((workingKey[quotient]) >> remainder)) & 1);
- lfsr = shift(lfsr, (getOutputLFSR() ^ output ^ ((workingKey[quotient + 8]) >> remainder)) & 1);
- }
- }
- initGrain(authAcc);
- initGrain(authSr);
- initialised = true;
- }
-
private void initGrain(int[] auth)
{
for (int quotient = 0; quotient < 2; ++quotient)
@@ -211,84 +176,31 @@ private int[] shift(int[] array, int val)
return array;
}
- /**
- * Set keys, reset cipher.
- *
- * @param keyBytes The key.
- * @param ivBytes The IV.
- */
- private void setKey(byte[] keyBytes, byte[] ivBytes)
+ protected void reset(boolean clearMac)
{
- ivBytes[12] = (byte)0xFF;
- ivBytes[13] = (byte)0xFF;
- ivBytes[14] = (byte)0xFF;
- ivBytes[15] = (byte)0x7F;
- workingKey = keyBytes;
- workingIV = ivBytes;
+ this.aadOperator.reset();
- /*
- * Load NFSR and LFSR
- */
Pack.littleEndianToInt(workingKey, 0, nfsr);
Pack.littleEndianToInt(workingIV, 0, lfsr);
- }
-
- public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
- throws DataLengthException
- {
- if (!initialised)
- {
- throw new IllegalStateException(getAlgorithmName() + " not initialised");
- }
-
- if (!aadFinished)
- {
- doProcessAADBytes(aadData.getBuf(), aadData.size());
- aadFinished = true;
- }
-
- if ((inOff + len) > input.length)
- {
- throw new DataLengthException("input buffer too short");
- }
-
- if ((outOff + len) > output.length)
+ // 320 clocks initialization phase.
+ for (int i = 0; i < 320; ++i)
{
- throw new OutputLengthException("output buffer too short");
+ int output = getOutput();
+ nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0] ^ output) & 1);
+ lfsr = shift(lfsr, (getOutputLFSR() ^ output) & 1);
}
- getKeyStream(input, inOff, len, output, outOff);
- return len;
- }
-
- protected void reset(boolean clearMac)
- {
- this.aadData.reset();
- this.aadFinished = false;
-
- setKey(workingKey, workingIV);
- initGrain();
- super.reset(clearMac);
- }
-
- private void getKeyStream(byte[] input, int inOff, int len, byte[] ciphertext, int outOff)
- {
- for (int i = 0; i < len; ++i)
+ for (int quotient = 0; quotient < 8; ++quotient)
{
- byte cc = 0, input_i = input[inOff + i];
- for (int j = 0; j < 8; ++j)
+ for (int remainder = 0; remainder < 8; ++remainder)
{
int output = getOutput();
- nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0]) & 1);
- lfsr = shift(lfsr, (getOutputLFSR()) & 1);
-
- int input_i_j = (input_i >> j) & 1;
- cc |= (input_i_j ^ output) << j;
-
- updateInternalState(input_i_j);
+ nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0] ^ output ^ ((workingKey[quotient]) >> remainder)) & 1);
+ lfsr = shift(lfsr, (getOutputLFSR() ^ output ^ ((workingKey[quotient + 8]) >> remainder)) & 1);
}
- ciphertext[outOff + i] = cc;
}
-
+ initGrain(authAcc);
+ initGrain(authSr);
+ super.reset(clearMac);
}
private void updateInternalState(int input_i_j)
@@ -302,24 +214,6 @@ private void updateInternalState(int input_i_j)
lfsr = shift(lfsr, (getOutputLFSR()) & 1);
}
- public void processAADByte(byte in)
- {
- if (aadFinished)
- {
- throw new IllegalStateException("associated data must be added before plaintext/ciphertext");
- }
- aadData.write(in);
- }
-
- public void processAADBytes(byte[] input, int inOff, int len)
- {
- if (aadFinished)
- {
- throw new IllegalStateException("associated data must be added before plaintext/ciphertext");
- }
- aadData.write(input, inOff, len);
- }
-
private void doProcessAADBytes(byte[] input, int len)
{
byte[] ader;
@@ -361,47 +255,123 @@ private void doProcessAADBytes(byte[] input, int len)
}
}
- private void accumulate()
- {
- authAcc[0] ^= authSr[0];
- authAcc[1] ^= authSr[1];
- }
-
private void authShift(int val)
{
authSr[0] = (authSr[0] >>> 1) | (authSr[1] << 31);
authSr[1] = (authSr[1] >>> 1) | (val << 31);
}
- public int doFinal(byte[] out, int outOff)
- throws IllegalStateException, InvalidCipherTextException
+ public int getUpdateOutputSize(int len)
{
- if (!aadFinished)
+ int total = processor.getUpdateOutputSize(len);
+ switch (m_state)
{
- doProcessAADBytes(aadData.getBuf(), aadData.size());
- aadFinished = true;
+ case DecInit:
+ case DecAad:
+ case DecData:
+ case DecFinal:
+ total = Math.max(0, total + m_bufPos - MAC_SIZE);
+ break;
+ case EncData:
+ case EncFinal:
+ total = Math.max(0, total + m_bufPos);
+ break;
+ default:
+ break;
+ }
+ return total;
+ }
+//
+// public int getOutputSize(int len)
+// {
+// //the last 8 bytes are from AD
+// return len + MAC_SIZE;
+// }
+
+ @Override
+ protected void finishAAD(State nextState, boolean isDoFinal)
+ {
+ // State indicates whether we ever received AAD
+ switch (m_state)
+ {
+ case DecInit:
+ case DecAad:
+ case EncInit:
+ case EncAad:
+ {
+ processFinalAAD();
+ break;
+ }
+ default:
+ break;
}
- accumulate();
+ m_aadPos = 0;
+ m_state = nextState;
+ }
- this.mac = Pack.intToLittleEndian(authAcc);
+ @Override
+ protected void processFinalBlock(byte[] output, int outOff)
+ {
+ authAcc[0] ^= authSr[0];
+ authAcc[1] ^= authSr[1];
+ Pack.intToLittleEndian(authAcc, mac, 0);
+ }
- System.arraycopy(mac, 0, out, outOff, mac.length);
+ @Override
+ protected void processBufferAAD(byte[] input, int inOff)
+ {
- reset(false);
+ }
- return mac.length;
+ @Override
+ protected void processFinalAAD()
+ {
+ doProcessAADBytes(((StreamAADOperator)aadOperator).getBytes(), aadOperator.getLen());
}
- public int getUpdateOutputSize(int len)
+ @Override
+ protected void processBufferEncrypt(byte[] input, int inOff, byte[] output, int outOff)
{
- return len;
+ int len = dataOperator.getLen();
+ for (int i = 0; i < len; ++i)
+ {
+ byte cc = 0, input_i = input[inOff + i];
+ for (int j = 0; j < 8; ++j)
+ {
+ int rlt = getOutput();
+ nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0]) & 1);
+ lfsr = shift(lfsr, (getOutputLFSR()) & 1);
+
+ int input_i_j = (input_i >> j) & 1;
+ cc |= (input_i_j ^ rlt) << j;
+
+ updateInternalState(input_i_j);
+ }
+ output[outOff + i] = cc;
+ }
}
- public int getOutputSize(int len)
+ @Override
+ protected void processBufferDecrypt(byte[] input, int inOff, byte[] output, int outOff)
{
- //the last 8 bytes are from AD
- return len + 8;
+ int len = dataOperator.getLen();
+ for (int i = 0; i < len; ++i)
+ {
+ byte cc = 0, input_i = input[inOff + i];
+ for (int j = 0; j < 8; ++j)
+ {
+ int rlt = getOutput();
+ nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0]) & 1);
+ lfsr = shift(lfsr, (getOutputLFSR()) & 1);
+
+ int input_i_j = (input_i >> j) & 1;
+ cc |= (input_i_j ^ rlt) << j;
+
+ updateInternalState((cc >> j) & 1);
+ }
+ output[outOff + i] = cc;
+ }
}
private static int len_length(int v)
@@ -418,27 +388,6 @@ private static int len_length(int v)
{
return 3;
}
-
return 4;
}
-
- private static final class ErasableOutputStream
- extends ByteArrayOutputStream
- {
- public ErasableOutputStream()
- {
- }
-
- public byte[] getBuf()
- {
- return buf;
- }
-
-// public void erase()
-// {
-// Arrays.fill(this.buf, (byte)0);
-// // this for JVM compatibility
-// this.reset();
-// }
- }
}
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/CipherTest.java b/core/src/test/java/org/bouncycastle/crypto/test/CipherTest.java
index 1d460fc514..26bbd069d7 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/CipherTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/CipherTest.java
@@ -442,7 +442,7 @@ static void implTestVectorsEngine(AEADCipher cipher, String path, String filenam
if (a < 0)
{
int count = Integer.parseInt((String)map.get("Count"));
-// if (count != 562)
+// if (count != 67)
// {
// continue;
// }
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java b/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java
index 1d9395faaf..579b7522b5 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java
@@ -3,17 +3,22 @@
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.security.SecureRandom;
import java.util.HashMap;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.Grain128AEADEngine;
+import org.bouncycastle.crypto.engines.XoodyakEngine;
+import org.bouncycastle.crypto.modes.AEADCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.test.TestResourceFinder;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
+import org.bouncycastle.util.test.SimpleTestResult;
+import org.bouncycastle.util.test.TestFailedException;
public class Grain128AEADTest
extends SimpleTest
@@ -26,50 +31,25 @@ public String getName()
public void performTest()
throws Exception
{
+
+ checkAEADCipherOutputSize(this, 16, 12, 8, new Grain128AEADEngine());
+ CipherTest.checkCipher(32, 12, 100, 128, new CipherTest.Instance()
+ {
+ @Override
+ public AEADCipher createInstance()
+ {
+ return new Grain128AEADEngine();
+ }
+ });
+ CipherTest.checkAEADCipherMultipleBlocks(this, 1024, 7, 100, 128, 12, new Grain128AEADEngine());
+
+ CipherTest.implTestVectorsEngine(new Grain128AEADEngine(), "crypto", "LWC_AEAD_KAT_128_96.txt", this);
CipherTest.checkAEADParemeter(this, 16, 12, 8, 16, new Grain128AEADEngine());
- testVectors();
testSplitUpdate();
testExceptions();
testLongAEAD();
}
- private void testVectors()
- throws Exception
- {
- Grain128AEADEngine grain = new Grain128AEADEngine();
- CipherParameters params;
- InputStream src = TestResourceFinder.findTestResource("crypto", "LWC_AEAD_KAT_128_96.txt");
- BufferedReader bin = new BufferedReader(new InputStreamReader(src));
- String line;
- byte[] ptByte, adByte;
- byte[] rv;
- HashMap map = new HashMap();
- while ((line = bin.readLine()) != null)
- {
- int a = line.indexOf('=');
- if (a < 0)
- {
- params = new ParametersWithIV(new KeyParameter(Hex.decode((String)map.get("Key"))), Hex.decode((String)map.get("Nonce")));
- grain.init(true, params);
- adByte = Hex.decode((String)map.get("AD"));
- grain.processAADBytes(adByte, 0, adByte.length);
- ptByte = Hex.decode((String)map.get("PT"));
- rv = new byte[ptByte.length];
- grain.processBytes(ptByte, 0, ptByte.length, rv, 0);
- byte[] mac = new byte[8];
- grain.doFinal(mac, 0);
- if (!areEqual(Arrays.concatenate(rv, mac), Hex.decode((String)map.get("CT"))))
- {
- mismatch("Keystream " + map.get("Count"), (String)map.get("CT"), rv);
- }
- map.clear();
- }
- else
- {
- map.put(line.substring(0, a).trim(), line.substring(a + 1).trim());
- }
- }
- }
private void testSplitUpdate()
throws InvalidCipherTextException
@@ -96,7 +76,7 @@ private void testSplitUpdate()
grain.doFinal(rv, len);
isTrue(Arrays.areEqual(rv, CT));
-
+ grain.init(true, params);
grain.processBytes(PT, 0, 10, rv, 0);
try
{
@@ -105,7 +85,7 @@ private void testSplitUpdate()
}
catch (IllegalStateException e)
{
- isEquals("associated data must be added before plaintext/ciphertext", e.getMessage());
+ isEquals("Grain-128 AEAD needs to be initialized", e.getMessage());
}
try
@@ -115,7 +95,7 @@ private void testSplitUpdate()
}
catch (IllegalStateException e)
{
- isEquals("associated data must be added before plaintext/ciphertext", e.getMessage());
+ isEquals("Grain-128 AEAD needs to be initialized", e.getMessage());
}
}
@@ -128,11 +108,11 @@ private void testLongAEAD()
byte[] AD = Hex.decode( // 186 bytes
"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9");
byte[] CT = Hex.decode("731DAA8B1D15317A1CCB4E3DD320095FB27E5BB2A10F2C669F870538637D4F162298C70430A2B560");
-
+
Grain128AEADEngine grain = new Grain128AEADEngine();
ParametersWithIV params = new ParametersWithIV(new KeyParameter(Key), Nonce);
grain.init(true, params);
-
+
grain.processAADBytes(AD, 0, AD.length);
byte[] rv = new byte[CT.length];
@@ -141,7 +121,7 @@ private void testLongAEAD()
len += grain.processBytes(PT, 11, PT.length - 11, rv, len);
grain.doFinal(rv, len);
-
+
isTrue(Arrays.areEqual(rv, CT));
grain.processBytes(PT, 0, 10, rv, 0);
@@ -152,7 +132,7 @@ private void testLongAEAD()
}
catch (IllegalStateException e)
{
- isEquals("associated data must be added before plaintext/ciphertext", e.getMessage());
+ isEquals("Grain-128 AEAD needs to be initialized", e.getMessage());
}
try
@@ -162,7 +142,7 @@ private void testLongAEAD()
}
catch (IllegalStateException e)
{
- isEquals("associated data must be added before plaintext/ciphertext", e.getMessage());
+ isEquals("Grain-128 AEAD needs to be initialized", e.getMessage());
}
}
@@ -178,7 +158,7 @@ private void testExceptions()
}
catch (IllegalArgumentException e)
{
- isEquals("invalid parameters passed to Grain-128AEAD", e.getMessage());
+ isEquals("invalid parameters passed to Grain-128 AEAD", e.getMessage());
}
try
@@ -190,7 +170,7 @@ private void testExceptions()
}
catch (IllegalArgumentException e)
{
- isEquals("Grain-128AEAD requires exactly 12 bytes of IV", e.getMessage());
+ isEquals("Grain-128 AEAD requires exactly 12 bytes of IV", e.getMessage());
}
try
@@ -202,13 +182,57 @@ private void testExceptions()
}
catch (IllegalArgumentException e)
{
- isEquals("Grain-128AEAD key must be 16 bytes long", e.getMessage());
+ isEquals("Grain-128 AEAD key must be 16 bytes long", e.getMessage());
}
}
- private void mismatch(String name, String expected, byte[] found)
+ static void checkAEADCipherOutputSize(SimpleTest parent, int keySize, int ivSize, int tagSize, AEADCipher cipher)
+ throws InvalidCipherTextException
+ {
+ final SecureRandom random = new SecureRandom();
+ int tmpLength = random.nextInt(tagSize - 1) + 1;
+ final byte[] plaintext = new byte[tmpLength];
+ byte[] key = new byte[keySize];
+ byte[] iv = new byte[ivSize];
+ random.nextBytes(key);
+ random.nextBytes(iv);
+ random.nextBytes(plaintext);
+ cipher.init(true, new ParametersWithIV(new KeyParameter(key), iv));
+ byte[] ciphertext = new byte[cipher.getOutputSize(plaintext.length)];
+ //before the encrypt
+ isEqualTo(parent, plaintext.length + tagSize, ciphertext.length);
+ isEqualTo(parent, plaintext.length, cipher.getUpdateOutputSize(plaintext.length));
+ //during the encrypt process of the first block
+ int len = cipher.processBytes(plaintext, 0, tmpLength, ciphertext, 0);
+ isEqualTo(parent, plaintext.length + tagSize, len + cipher.getOutputSize(plaintext.length - tmpLength));
+ isEqualTo(parent, plaintext.length, len + cipher.getUpdateOutputSize(plaintext.length - tmpLength));
+ //process doFinal
+ len += cipher.doFinal(ciphertext, len);
+ isEqualTo(parent, len, ciphertext.length);
+
+ cipher.init(false, new ParametersWithIV(new KeyParameter(key), iv));
+ //before the encrypt
+ isEqualTo(parent, plaintext.length, cipher.getOutputSize(ciphertext.length));
+ isEqualTo(parent, plaintext.length, cipher.getUpdateOutputSize(ciphertext.length));
+ //during the encrypt process of the first block
+ len = cipher.processBytes(ciphertext, 0, tmpLength, plaintext, 0);
+ isEqualTo(parent, plaintext.length, len + cipher.getOutputSize(ciphertext.length - tmpLength));
+ isEqualTo(parent, plaintext.length, len + cipher.getUpdateOutputSize(ciphertext.length - tmpLength));
+ //process doFinal
+ len = cipher.processBytes(ciphertext, tmpLength, tagSize, plaintext, 0);
+ len += cipher.doFinal(plaintext, len);
+ isEqualTo(parent, len, plaintext.length);
+ }
+
+ static void isEqualTo(
+ SimpleTest parent,
+ int a,
+ int b)
{
- fail("mismatch on " + name, expected, new String(Hex.encode(found)));
+ if (a != b)
+ {
+ throw new TestFailedException(SimpleTestResult.failed(parent, "no message"));
+ }
}
public static void main(String[] args)
From b56ace48bdd2492f21677f728f03315e0f2873f1 Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Fri, 14 Mar 2025 12:15:01 +0700
Subject: [PATCH 214/890] Remove debug print
---
.../org/bouncycastle/pqc/jcajce/provider/hqc/HQCCipherSpi.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/hqc/HQCCipherSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/hqc/HQCCipherSpi.java
index 92a6c432dc..8e51066d8b 100644
--- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/hqc/HQCCipherSpi.java
+++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/hqc/HQCCipherSpi.java
@@ -268,7 +268,7 @@ protected byte[] engineWrap(
return rv;
}
catch (IllegalArgumentException e)
- { e.printStackTrace();
+ {
throw new IllegalBlockSizeException("unable to generate KTS secret: " + e.getMessage());
}
catch (DestroyFailedException e)
From f29c16ba00c4cf8b4cc318a694beb89c05207f16 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Fri, 14 Mar 2025 16:13:44 +1030
Subject: [PATCH 215/890] Refactor of Grain128AEADEngine
---
.../crypto/engines/Grain128AEADEngine.java | 130 ++++++++----------
.../crypto/test/Grain128AEADTest.java | 11 +-
2 files changed, 60 insertions(+), 81 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java
index 2bffd9fcec..d53b61caff 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java
@@ -65,9 +65,7 @@ private void initGrain(int[] auth)
{
for (int remainder = 0; remainder < 32; ++remainder)
{
- int output = getOutput();
- nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0]) & 1);
- lfsr = shift(lfsr, (getOutputLFSR()) & 1);
+ int output = getByteKeyStream();
auth[quotient] |= output << remainder;
}
}
@@ -176,6 +174,12 @@ private int[] shift(int[] array, int val)
return array;
}
+ private void shift()
+ {
+ nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0]) & 1);
+ lfsr = shift(lfsr, (getOutputLFSR()) & 1);
+ }
+
protected void reset(boolean clearMac)
{
this.aadOperator.reset();
@@ -208,59 +212,12 @@ private void updateInternalState(int input_i_j)
int mask = -input_i_j;
authAcc[0] ^= authSr[0] & mask;
authAcc[1] ^= authSr[1] & mask;
-
- authShift(getOutput());
- nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0]) & 1);
- lfsr = shift(lfsr, (getOutputLFSR()) & 1);
- }
-
- private void doProcessAADBytes(byte[] input, int len)
- {
- byte[] ader;
- int aderlen;
- //encodeDer
- if (len < 128)
- {
- ader = new byte[1 + len];
- ader[0] = (byte)len;
- aderlen = 0;
- }
- else
- {
- // aderlen is the highest bit position divided by 8
- aderlen = len_length(len);
- ader = new byte[1 + aderlen + len];
- ader[0] = (byte)(0x80 | aderlen);
- int tmp = len;
- for (int i = 0; i < aderlen; ++i)
- {
- ader[1 + i] = (byte)tmp;
- tmp >>>= 8;
- }
- }
- System.arraycopy(input, 0, ader, 1 + aderlen, len);
-
- for (int i = 0; i < ader.length; ++i)
- {
- byte ader_i = ader[i];
- for (int j = 0; j < 8; ++j)
- {
- nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0]) & 1);
- lfsr = shift(lfsr, (getOutputLFSR()) & 1);
-
- int ader_i_j = (ader_i >> j) & 1;
-
- updateInternalState(ader_i_j);
- }
- }
- }
-
- private void authShift(int val)
- {
+ int val = getByteKeyStream();
authSr[0] = (authSr[0] >>> 1) | (authSr[1] << 31);
authSr[1] = (authSr[1] >>> 1) | (val << 31);
}
+
public int getUpdateOutputSize(int len)
{
int total = processor.getUpdateOutputSize(len);
@@ -281,12 +238,6 @@ public int getUpdateOutputSize(int len)
}
return total;
}
-//
-// public int getOutputSize(int len)
-// {
-// //the last 8 bytes are from AD
-// return len + MAC_SIZE;
-// }
@Override
protected void finishAAD(State nextState, boolean isDoFinal)
@@ -327,7 +278,53 @@ protected void processBufferAAD(byte[] input, int inOff)
@Override
protected void processFinalAAD()
{
- doProcessAADBytes(((StreamAADOperator)aadOperator).getBytes(), aadOperator.getLen());
+ int len = aadOperator.getLen();
+ byte[] input = ((StreamAADOperator)aadOperator).getBytes();
+ byte[] ader;
+
+ //encodeDer
+ if (len < 128)
+ {
+ ader = new byte[1];
+ ader[0] = (byte)len;
+ }
+ else
+ {
+ // aderlen is the highest bit position divided by 8
+ int aderlen = len_length(len);
+ ader = new byte[1 + aderlen];
+ ader[0] = (byte)(0x80 | aderlen);
+ int tmp = len;
+ for (int i = 0; i < aderlen; ++i)
+ {
+ ader[1 + i] = (byte)tmp;
+ tmp >>>= 8;
+ }
+ }
+
+ absorbAadData(ader, ader.length);
+ absorbAadData(input, len);
+ }
+
+ private void absorbAadData(byte[] ader, int len)
+ {
+ for (int i = 0; i < len; ++i)
+ {
+ byte ader_i = ader[i];
+ for (int j = 0; j < 8; ++j)
+ {
+ shift();
+ int ader_i_j = (ader_i >> j) & 1;
+ updateInternalState(ader_i_j);
+ }
+ }
+ }
+
+ private int getByteKeyStream()
+ {
+ int rlt = getOutput();
+ shift();
+ return rlt;
}
@Override
@@ -339,13 +336,8 @@ protected void processBufferEncrypt(byte[] input, int inOff, byte[] output, int
byte cc = 0, input_i = input[inOff + i];
for (int j = 0; j < 8; ++j)
{
- int rlt = getOutput();
- nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0]) & 1);
- lfsr = shift(lfsr, (getOutputLFSR()) & 1);
-
int input_i_j = (input_i >> j) & 1;
- cc |= (input_i_j ^ rlt) << j;
-
+ cc |= (input_i_j ^ getByteKeyStream()) << j;
updateInternalState(input_i_j);
}
output[outOff + i] = cc;
@@ -361,13 +353,7 @@ protected void processBufferDecrypt(byte[] input, int inOff, byte[] output, int
byte cc = 0, input_i = input[inOff + i];
for (int j = 0; j < 8; ++j)
{
- int rlt = getOutput();
- nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0]) & 1);
- lfsr = shift(lfsr, (getOutputLFSR()) & 1);
-
- int input_i_j = (input_i >> j) & 1;
- cc |= (input_i_j ^ rlt) << j;
-
+ cc |= (((input_i >> j) & 1) ^ getByteKeyStream()) << j;
updateInternalState((cc >> j) & 1);
}
output[outOff + i] = cc;
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java b/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java
index 579b7522b5..33124af334 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java
@@ -1,19 +1,12 @@
package org.bouncycastle.crypto.test;
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
import java.security.SecureRandom;
-import java.util.HashMap;
-import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.Grain128AEADEngine;
-import org.bouncycastle.crypto.engines.XoodyakEngine;
import org.bouncycastle.crypto.modes.AEADCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
-import org.bouncycastle.test.TestResourceFinder;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
@@ -31,7 +24,7 @@ public String getName()
public void performTest()
throws Exception
{
-
+ CipherTest.implTestVectorsEngine(new Grain128AEADEngine(), "crypto", "LWC_AEAD_KAT_128_96.txt", this);
checkAEADCipherOutputSize(this, 16, 12, 8, new Grain128AEADEngine());
CipherTest.checkCipher(32, 12, 100, 128, new CipherTest.Instance()
{
@@ -43,7 +36,7 @@ public AEADCipher createInstance()
});
CipherTest.checkAEADCipherMultipleBlocks(this, 1024, 7, 100, 128, 12, new Grain128AEADEngine());
- CipherTest.implTestVectorsEngine(new Grain128AEADEngine(), "crypto", "LWC_AEAD_KAT_128_96.txt", this);
+
CipherTest.checkAEADParemeter(this, 16, 12, 8, 16, new Grain128AEADEngine());
testSplitUpdate();
testExceptions();
From 4d6a1825cbe606c05b8bbe199f561fc6288e83c8 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Fri, 14 Mar 2025 16:39:58 +1030
Subject: [PATCH 216/890] Merge AEADBaseEngine and AEADBufferBaseEngine into
one class
---
.../crypto/engines/AEADBaseEngine.java | 769 +++++++++++++++++-
.../crypto/engines/AEADBufferBaseEngine.java | 769 ------------------
.../crypto/engines/AsconAEAD128.java | 4 -
.../crypto/engines/AsconBaseEngine.java | 5 +-
.../crypto/engines/AsconEngine.java | 4 -
.../crypto/engines/ElephantEngine.java | 7 +-
.../crypto/engines/GiftCofbEngine.java | 5 +-
.../crypto/engines/Grain128AEADEngine.java | 5 +-
.../crypto/engines/ISAPEngine.java | 8 +-
.../crypto/engines/PhotonBeetleEngine.java | 10 +-
.../crypto/engines/RomulusEngine.java | 7 +-
.../crypto/engines/SparkleEngine.java | 9 +-
.../crypto/engines/XoodyakEngine.java | 12 +-
.../crypto/test/Grain128AEADTest.java | 10 +-
14 files changed, 795 insertions(+), 829 deletions(-)
delete mode 100644 core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBaseEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/AEADBaseEngine.java
index 25cff6b482..1598e97fbb 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBaseEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/AEADBaseEngine.java
@@ -1,17 +1,56 @@
package org.bouncycastle.crypto.engines;
+import java.io.ByteArrayOutputStream;
+
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.OutputLengthException;
import org.bouncycastle.crypto.constraints.DefaultServiceProperties;
import org.bouncycastle.crypto.modes.AEADCipher;
import org.bouncycastle.crypto.params.AEADParameters;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.util.Arrays;
abstract class AEADBaseEngine
implements AEADCipher
{
+ protected enum ProcessingBufferType
+ {
+ Buffered, // Store a (aad) block size of input and process after the input size exceeds the buffer size
+ Immediate, //process the input immediately when the input size is equal or greater than the block size
+ }
+
+ protected enum AADOperatorType
+ {
+ Default,
+ Counter,//add a counter to count the size of AAD
+ Stream //process AAD data during the process data, used for elephant
+ }
+
+ protected enum DataOperatorType
+ {
+ Default,
+ Counter,
+ Stream,
+ StreamCipher
+ }
+
+ protected enum State
+ {
+ Uninitialized,
+ EncInit,
+ EncAad, // can process AAD
+ EncData, // cannot process AAD
+ EncFinal,
+ DecInit,
+ DecAad, // can process AAD
+ DecData, // cannot process AAD
+ DecFinal,
+ }
+
protected boolean forEncryption;
protected String algorithmName;
protected int KEY_SIZE;
@@ -19,6 +58,17 @@ abstract class AEADBaseEngine
protected int MAC_SIZE;
protected byte[] initialAssociatedText;
protected byte[] mac;
+ protected byte[] m_buf;
+ protected byte[] m_aad;
+ protected int m_bufPos;
+ protected int m_aadPos;
+ protected int AADBufferSize;
+ protected int BlockSize;
+ protected State m_state = State.Uninitialized;
+ protected int m_bufferSizeDecrypt;
+ protected AADProcessingBuffer processor;
+ protected AADOperator aadOperator;
+ protected DataOperator dataOperator;
@Override
public String getAlgorithmName()
@@ -102,20 +152,737 @@ else if (params instanceof ParametersWithIV)
CryptoServicesRegistrar.checkConstraints(new DefaultServiceProperties(
this.getAlgorithmName(), 128, params, Utils.getPurpose(forEncryption)));
+ m_state = forEncryption ? State.EncInit : State.DecInit;
init(k, npub);
+ reset(true);
if (initialAssociatedText != null)
{
processAADBytes(initialAssociatedText, 0, initialAssociatedText.length);
}
}
- protected abstract void init(byte[] key, byte[] iv);
+
protected void reset(boolean clearMac)
{
+ ensureInitialized();
if (clearMac)
{
mac = null;
}
+ if (m_buf != null)
+ {
+ Arrays.fill(m_buf, (byte)0);
+ m_bufPos = 0;
+ }
+ if (m_aad != null)
+ {
+ Arrays.fill(m_aad, (byte)0);
+ m_aadPos = 0;
+ }
+ switch (m_state)
+ {
+ case DecInit:
+ case EncInit:
+ break;
+ case DecAad:
+ case DecData:
+ case DecFinal:
+ m_state = State.DecFinal;
+ break;
+ case EncAad:
+ case EncData:
+ case EncFinal:
+ m_state = State.EncFinal;
+ return;
+ default:
+ throw new IllegalStateException(getAlgorithmName() + " needs to be initialized");
+ }
+ aadOperator.reset();
+ dataOperator.reset();
+ }
+
+ protected void setInnerMembers(ProcessingBufferType type, AADOperatorType aadOperatorType, DataOperatorType dataOperatorType)
+ {
+ switch (type)
+ {
+ case Buffered:
+ processor = new BufferedAADProcessor();
+ break;
+ case Immediate:
+ processor = new ImmediateAADProcessor();
+ break;
+ }
+
+ m_bufferSizeDecrypt = BlockSize + MAC_SIZE;
+
+ switch (aadOperatorType)
+ {
+ case Default:
+ m_aad = new byte[AADBufferSize];
+ aadOperator = new DefaultAADOperator();
+ break;
+ case Counter:
+ m_aad = new byte[AADBufferSize];
+ aadOperator = new CounterAADOperator();
+ break;
+ case Stream:
+ aadOperator = new StreamAADOperator();
+ break;
+ }
+
+ switch (dataOperatorType)
+ {
+ case Default:
+ m_buf = new byte[m_bufferSizeDecrypt];
+ dataOperator = new DefaultDataOperator();
+ break;
+ case Counter:
+ m_buf = new byte[m_bufferSizeDecrypt];
+ dataOperator = new CounterDataOperator();
+ break;
+ case Stream:
+ m_buf = new byte[MAC_SIZE];
+ dataOperator = new StreamDataOperator();
+ break;
+ case StreamCipher:
+ BlockSize = 0;
+ m_buf = new byte[m_bufferSizeDecrypt];
+ dataOperator = new StreamCipherOperator();
+ break;
+ }
+ }
+
+ protected interface AADProcessingBuffer
+ {
+ void processAADByte(byte input);
+
+ int getUpdateOutputSize(int len);
+
+ boolean isLengthWithinAvailableSpace(int len, int available);
+
+ boolean isLengthExceedingBlockSize(int len, int size);
+ }
+
+ private class BufferedAADProcessor
+ implements AADProcessingBuffer
+ {
+ public void processAADByte(byte input)
+ {
+ if (m_aadPos == AADBufferSize)
+ {
+ processBufferAAD(m_aad, 0);
+ m_aadPos = 0;
+ }
+ m_aad[m_aadPos++] = input;
+ }
+
+ @Override
+ public boolean isLengthWithinAvailableSpace(int len, int available)
+ {
+ return len <= available;
+ }
+
+ @Override
+ public boolean isLengthExceedingBlockSize(int len, int size)
+ {
+ return len > size;
+ }
+
+ @Override
+ public int getUpdateOutputSize(int len)
+ {
+ // The -1 is to account for the lazy processing of a full buffer
+ return Math.max(0, len) - 1;
+ }
+ }
+
+ private class ImmediateAADProcessor
+ implements AADProcessingBuffer
+ {
+ public void processAADByte(byte input)
+ {
+ m_aad[m_aadPos++] = input;
+ if (m_aadPos == AADBufferSize)
+ {
+ processBufferAAD(m_aad, 0);
+ m_aadPos = 0;
+ }
+ }
+
+ @Override
+ public int getUpdateOutputSize(int len)
+ {
+ return Math.max(0, len);
+ }
+
+ @Override
+ public boolean isLengthWithinAvailableSpace(int len, int available)
+ {
+ return len < available;
+ }
+
+ @Override
+ public boolean isLengthExceedingBlockSize(int len, int size)
+ {
+ return len >= size;
+ }
+ }
+
+ protected interface AADOperator
+ {
+ void processAADByte(byte input);
+
+ void processAADBytes(byte[] input, int inOff, int len);
+
+ void reset();
+
+ int getLen();
+ }
+
+ protected class DefaultAADOperator
+ implements AADOperator
+ {
+ @Override
+ public void processAADByte(byte input)
+ {
+ processor.processAADByte(input);
+ }
+
+ @Override
+ public void processAADBytes(byte[] input, int inOff, int len)
+ {
+ processAadBytes(input, inOff, len);
+ }
+
+ public void reset()
+ {
+ }
+
+ @Override
+ public int getLen()
+ {
+ return m_aadPos;
+ }
+ }
+
+ protected class CounterAADOperator
+ implements AADOperator
+ {
+ private int aadLen;
+
+ @Override
+ public void processAADByte(byte input)
+ {
+ aadLen++;
+ processor.processAADByte(input);
+ }
+
+ @Override
+ public void processAADBytes(byte[] input, int inOff, int len)
+ {
+ aadLen += len;
+ processAadBytes(input, inOff, len);
+ }
+
+ public int getLen()
+ {
+ return aadLen;
+ }
+
+ public void reset()
+ {
+ aadLen = 0;
+ }
+ }
+
+ protected static class StreamAADOperator
+ implements AADOperator
+ {
+ private final ErasableOutputStream stream = new ErasableOutputStream();
+
+ @Override
+ public void processAADByte(byte input)
+ {
+ stream.write(input);
+ }
+
+ @Override
+ public void processAADBytes(byte[] input, int inOff, int len)
+ {
+ stream.write(input, inOff, len);
+ }
+
+ public byte[] getBytes()
+ {
+ return stream.getBuf();
+ }
+
+ @Override
+ public void reset()
+ {
+ stream.reset();
+ }
+
+ @Override
+ public int getLen()
+ {
+ return stream.size();
+ }
+ }
+
+ protected interface DataOperator
+ {
+ int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff);
+
+ int getLen();
+
+ void reset();
+ }
+
+ protected class DefaultDataOperator
+ implements DataOperator
+ {
+ public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
+ {
+ return processEncDecBytes(input, inOff, len, output, outOff);
+ }
+
+ @Override
+ public int getLen()
+ {
+ return m_bufPos;
+ }
+
+ @Override
+ public void reset()
+ {
+ }
+ }
+
+ protected class CounterDataOperator
+ implements DataOperator
+ {
+ private int messegeLen;
+
+ public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
+ {
+ messegeLen += len;
+ return processEncDecBytes(input, inOff, len, output, outOff);
+ }
+
+ @Override
+ public int getLen()
+ {
+ return messegeLen;
+ }
+
+ @Override
+ public void reset()
+ {
+ messegeLen = 0;
+ }
+ }
+
+ protected class StreamDataOperator
+ implements DataOperator
+ {
+ private final ErasableOutputStream stream = new ErasableOutputStream();
+
+ @Override
+ public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
+ {
+ ensureInitialized();
+ stream.write(input, inOff, len);
+ m_bufPos = stream.size();
+ return 0;
+ }
+
+ public byte[] getBytes()
+ {
+ return stream.getBuf();
+ }
+
+ @Override
+ public int getLen()
+ {
+ return stream.size();
+ }
+
+ @Override
+ public void reset()
+ {
+ stream.reset();
+ }
+ }
+
+ protected class StreamCipherOperator
+ implements DataOperator
+ {
+ private int len;
+
+ @Override
+ public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
+ {
+ boolean forEncryption = checkData(false);
+ if (forEncryption)
+ {
+ this.len = len;
+ processBufferEncrypt(input, inOff, output, outOff);
+ return len;
+ }
+ else
+ {
+ // keep last mac size bytes
+ int available = Math.max(m_bufPos + len - MAC_SIZE, 0);
+ int rlt = 0;
+ if (m_bufPos > 0)
+ {
+ this.len = Math.min(available, m_bufPos);
+ rlt = this.len;
+ processBufferDecrypt(m_buf, 0, output, outOff);
+ available -= rlt;
+ m_bufPos -= rlt;
+ System.arraycopy(m_buf, rlt, m_buf, 0, m_bufPos);
+ }
+ if (available > 0)
+ {
+ this.len = available;
+ processBufferDecrypt(input, inOff, output, outOff);
+ rlt += available;
+ len -= available;
+ inOff += available;
+ }
+
+ System.arraycopy(input, inOff, m_buf, m_bufPos, len);
+ m_bufPos += len;
+ return rlt;
+ }
+ }
+
+ @Override
+ public int getLen()
+ {
+ return len;
+ }
+
+ @Override
+ public void reset()
+ {
+ }
+ }
+
+ protected static final class ErasableOutputStream
+ extends ByteArrayOutputStream
+ {
+ public ErasableOutputStream()
+ {
+ }
+
+ public byte[] getBuf()
+ {
+ return buf;
+ }
+ }
+
+ @Override
+ public void processAADByte(byte input)
+ {
+ checkAAD();
+ aadOperator.processAADByte(input);
+ }
+
+ @Override
+ public void processAADBytes(byte[] input, int inOff, int len)
+ {
+ ensureSufficientInputBuffer(input, inOff, len);
+ // Don't enter AAD state until we actually get input
+ if (len <= 0)
+ {
+ return;
+ }
+
+ checkAAD();
+ aadOperator.processAADBytes(input, inOff, len);
+ }
+
+ private void processAadBytes(byte[] input, int inOff, int len)
+ {
+ if (m_aadPos > 0)
+ {
+ int available = AADBufferSize - m_aadPos;
+ if (processor.isLengthWithinAvailableSpace(len, available))
+ {
+ System.arraycopy(input, inOff, m_aad, m_aadPos, len);
+ m_aadPos += len;
+ return;
+ }
+
+ System.arraycopy(input, inOff, m_aad, m_aadPos, available);
+ inOff += available;
+ len -= available;
+
+ processBufferAAD(m_aad, 0);
+ }
+ while (processor.isLengthExceedingBlockSize(len, AADBufferSize))
+ {
+ processBufferAAD(input, inOff);
+ inOff += AADBufferSize;
+ len -= AADBufferSize;
+ }
+ System.arraycopy(input, inOff, m_aad, 0, len);
+ m_aadPos = len;
+ }
+
+ @Override
+ public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
+ throws DataLengthException
+ {
+ ensureSufficientInputBuffer(input, inOff, len);
+ return dataOperator.processBytes(input, inOff, len, output, outOff);
+ }
+
+ protected int processEncDecBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
+ {
+ boolean forEncryption = checkData(false);
+ int available, resultLength;
+ available = (forEncryption ? BlockSize : m_bufferSizeDecrypt) - m_bufPos;
+ // The function is just an operator < or <=
+ if (processor.isLengthWithinAvailableSpace(len, available))
+ {
+ System.arraycopy(input, inOff, m_buf, m_bufPos, len);
+ m_bufPos += len;
+ return 0;
+ }
+ resultLength = processor.getUpdateOutputSize(len) + m_bufPos - (forEncryption ? 0 : MAC_SIZE);
+ ensureSufficientOutputBuffer(output, outOff, resultLength - resultLength % BlockSize);
+ resultLength = 0;
+ if (forEncryption)
+ {
+ if (m_bufPos > 0)
+ {
+ System.arraycopy(input, inOff, m_buf, m_bufPos, available);
+ inOff += available;
+ len -= available;
+ processBufferEncrypt(m_buf, 0, output, outOff);
+ resultLength = BlockSize;
+ }
+ // The function is just an operator >= or >
+ while (processor.isLengthExceedingBlockSize(len, BlockSize))
+ {
+ processBufferEncrypt(input, inOff, output, outOff + resultLength);
+ inOff += BlockSize;
+ len -= BlockSize;
+ resultLength += BlockSize;
+ }
+ }
+ else
+ {
+ // loop will run more than once for the following situation: pb128, ascon80pq, ascon128, ISAP_A_128(A)
+ while (processor.isLengthExceedingBlockSize(m_bufPos, BlockSize)
+ && processor.isLengthExceedingBlockSize(len + m_bufPos, m_bufferSizeDecrypt))
+ {
+ processBufferDecrypt(m_buf, resultLength, output, outOff + resultLength);
+ m_bufPos -= BlockSize;
+ resultLength += BlockSize;
+ }
+ if (m_bufPos > 0)
+ {
+ System.arraycopy(m_buf, resultLength, m_buf, 0, m_bufPos);
+ if (processor.isLengthWithinAvailableSpace(m_bufPos + len, m_bufferSizeDecrypt))
+ {
+ System.arraycopy(input, inOff, m_buf, m_bufPos, len);
+ m_bufPos += len;
+ return resultLength;
+ }
+ available = Math.max(BlockSize - m_bufPos, 0);
+ System.arraycopy(input, inOff, m_buf, m_bufPos, available);
+ inOff += available;
+ len -= available;
+ processBufferDecrypt(m_buf, 0, output, outOff + resultLength);
+ resultLength += BlockSize;
+ }
+ while (processor.isLengthExceedingBlockSize(len, m_bufferSizeDecrypt))
+ {
+ processBufferDecrypt(input, inOff, output, outOff + resultLength);
+ inOff += BlockSize;
+ len -= BlockSize;
+ resultLength += BlockSize;
+ }
+ }
+ System.arraycopy(input, inOff, m_buf, 0, len);
+ m_bufPos = len;
+ return resultLength;
+ }
+
+ @Override
+ public int doFinal(byte[] output, int outOff)
+ throws IllegalStateException, InvalidCipherTextException
+ {
+ boolean forEncryption = checkData(true);
+ int resultLength;
+ if (forEncryption)
+ {
+ resultLength = m_bufPos + MAC_SIZE;
+ }
+ else
+ {
+ if (m_bufPos < MAC_SIZE)
+ {
+ throw new InvalidCipherTextException("data too short");
+ }
+
+ m_bufPos -= MAC_SIZE;
+
+ resultLength = m_bufPos;
+ }
+
+ ensureSufficientOutputBuffer(output, outOff, resultLength);
+ mac = new byte[MAC_SIZE];
+ processFinalBlock(output, outOff);
+ if (forEncryption)
+ {
+ System.arraycopy(mac, 0, output, outOff + resultLength - MAC_SIZE, MAC_SIZE);
+ }
+ else
+ {
+ if (!Arrays.constantTimeAreEqual(MAC_SIZE, mac, 0, m_buf, m_bufPos))
+ {
+ throw new InvalidCipherTextException(algorithmName + " mac does not match");
+ }
+ }
+ reset(!forEncryption);
+ return resultLength;
+ }
+
+ public final int getBlockSize()
+ {
+ return BlockSize;
+ }
+
+ public int getUpdateOutputSize(int len)
+ {
+ int total = processor.getUpdateOutputSize(len);
+ switch (m_state)
+ {
+ case DecInit:
+ case DecAad:
+ case DecData:
+ case DecFinal:
+ total = Math.max(0, total + m_bufPos - MAC_SIZE);
+ break;
+ case EncData:
+ case EncFinal:
+ total = Math.max(0, total + m_bufPos);
+ break;
+ default:
+ break;
+ }
+ return total - total % BlockSize;
+ }
+
+ public int getOutputSize(int len)
+ {
+ int total = Math.max(0, len);
+
+ switch (m_state)
+ {
+ case DecInit:
+ case DecAad:
+ case DecData:
+ case DecFinal:
+ return Math.max(0, total + m_bufPos - MAC_SIZE);
+ case EncData:
+ case EncFinal:
+ return total + m_bufPos + MAC_SIZE;
+ default:
+ return total + MAC_SIZE;
+ }
+ }
+
+ protected void checkAAD()
+ {
+ switch (m_state)
+ {
+ case DecInit:
+ m_state = State.DecAad;
+ break;
+ case EncInit:
+ m_state = State.EncAad;
+ break;
+ case DecAad:
+ case EncAad:
+ break;
+ case EncFinal:
+ throw new IllegalStateException(getAlgorithmName() + " cannot be reused for encryption");
+ default:
+ throw new IllegalStateException(getAlgorithmName() + " needs to be initialized");
+ }
+ }
+
+ protected boolean checkData(boolean isDoFinal)
+ {
+ switch (m_state)
+ {
+ case DecInit:
+ case DecAad:
+ finishAAD(State.DecData, isDoFinal);
+ return false;
+ case EncInit:
+ case EncAad:
+ finishAAD(State.EncData, isDoFinal);
+ return true;
+ case DecData:
+ return false;
+ case EncData:
+ return true;
+ case EncFinal:
+ throw new IllegalStateException(getAlgorithmName() + " cannot be reused for encryption");
+ default:
+ throw new IllegalStateException(getAlgorithmName() + " needs to be initialized");
+ }
+ }
+
+ protected abstract void finishAAD(State nextState, boolean isDoFinal);
+
+ protected final void bufferReset()
+ {
+
}
+
+ protected final void ensureSufficientOutputBuffer(byte[] output, int outOff, int len)
+ {
+ if (outOff + len > output.length)
+ {
+ throw new OutputLengthException("output buffer too short");
+ }
+ }
+
+ protected final void ensureSufficientInputBuffer(byte[] input, int inOff, int len)
+ {
+ if (inOff + len > input.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+ }
+
+ protected final void ensureInitialized()
+ {
+ if (m_state == State.Uninitialized)
+ {
+ throw new IllegalStateException("Need to call init function before operation");
+ }
+ }
+
+ protected abstract void init(byte[] key, byte[] iv);
+
+ protected abstract void processFinalBlock(byte[] output, int outOff);
+
+ protected abstract void processBufferAAD(byte[] input, int inOff);
+
+ protected abstract void processFinalAAD();
+
+ protected abstract void processBufferEncrypt(byte[] input, int inOff, byte[] output, int outOff);
+
+ protected abstract void processBufferDecrypt(byte[] input, int inOff, byte[] output, int outOff);
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java
deleted file mode 100644
index 87fee36a32..0000000000
--- a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java
+++ /dev/null
@@ -1,769 +0,0 @@
-package org.bouncycastle.crypto.engines;
-
-import java.io.ByteArrayOutputStream;
-
-import org.bouncycastle.crypto.DataLengthException;
-import org.bouncycastle.crypto.InvalidCipherTextException;
-import org.bouncycastle.crypto.OutputLengthException;
-import org.bouncycastle.util.Arrays;
-
-abstract class AEADBufferBaseEngine
- extends AEADBaseEngine
-{
- protected enum ProcessingBufferType
- {
- Buffered, // Store a (aad) block size of input and process after the input size exceeds the buffer size
- Immediate, //process the input immediately when the input size is equal or greater than the block size
- }
-
- protected enum AADOperatorType
- {
- Default,
- Counter,//add a counter to count the size of AAD
- Stream //process AAD data during the process data, used for elephant
- }
-
- protected enum DataOperatorType
- {
- Default,
- Counter,
- Stream,
- StreamCipher
- }
-
- protected enum State
- {
- Uninitialized,
- EncInit,
- EncAad, // can process AAD
- EncData, // cannot process AAD
- EncFinal,
- DecInit,
- DecAad, // can process AAD
- DecData, // cannot process AAD
- DecFinal,
- }
-
- protected byte[] m_buf;
- protected byte[] m_aad;
- protected int m_bufPos;
- protected int m_aadPos;
- protected int AADBufferSize;
- protected int BlockSize;
- protected State m_state = State.Uninitialized;
- protected int m_bufferSizeDecrypt;
- protected AADProcessingBuffer processor;
- protected AADOperator aadOperator;
- protected DataOperator dataOperator;
-
- protected void setInnerMembers(ProcessingBufferType type, AADOperatorType aadOperatorType, DataOperatorType dataOperatorType)
- {
- switch (type)
- {
- case Buffered:
- processor = new BufferedAADProcessor();
- break;
- case Immediate:
- processor = new ImmediateAADProcessor();
- break;
- }
-
- m_bufferSizeDecrypt = BlockSize + MAC_SIZE;
-
- switch (aadOperatorType)
- {
- case Default:
- m_aad = new byte[AADBufferSize];
- aadOperator = new DefaultAADOperator();
- break;
- case Counter:
- m_aad = new byte[AADBufferSize];
- aadOperator = new CounterAADOperator();
- break;
- case Stream:
- aadOperator = new StreamAADOperator();
- break;
- }
-
- switch (dataOperatorType)
- {
- case Default:
- m_buf = new byte[m_bufferSizeDecrypt];
- dataOperator = new DefaultDataOperator();
- break;
- case Counter:
- m_buf = new byte[m_bufferSizeDecrypt];
- dataOperator = new CounterDataOperator();
- break;
- case Stream:
- m_buf = new byte[MAC_SIZE];
- dataOperator = new StreamDataOperator();
- break;
- case StreamCipher:
- BlockSize = 0;
- m_buf = new byte[m_bufferSizeDecrypt];
- dataOperator = new StreamCipherOperator();
- break;
- }
- }
-
- protected interface AADProcessingBuffer
- {
- void processAADByte(byte input);
-
- int getUpdateOutputSize(int len);
-
- boolean isLengthWithinAvailableSpace(int len, int available);
-
- boolean isLengthExceedingBlockSize(int len, int size);
- }
-
- private class BufferedAADProcessor
- implements AADProcessingBuffer
- {
- public void processAADByte(byte input)
- {
- if (m_aadPos == AADBufferSize)
- {
- processBufferAAD(m_aad, 0);
- m_aadPos = 0;
- }
- m_aad[m_aadPos++] = input;
- }
-
- @Override
- public boolean isLengthWithinAvailableSpace(int len, int available)
- {
- return len <= available;
- }
-
- @Override
- public boolean isLengthExceedingBlockSize(int len, int size)
- {
- return len > size;
- }
-
- @Override
- public int getUpdateOutputSize(int len)
- {
- // The -1 is to account for the lazy processing of a full buffer
- return Math.max(0, len) - 1;
- }
- }
-
- private class ImmediateAADProcessor
- implements AADProcessingBuffer
- {
- public void processAADByte(byte input)
- {
- m_aad[m_aadPos++] = input;
- if (m_aadPos == AADBufferSize)
- {
- processBufferAAD(m_aad, 0);
- m_aadPos = 0;
- }
- }
-
- @Override
- public int getUpdateOutputSize(int len)
- {
- return Math.max(0, len);
- }
-
- @Override
- public boolean isLengthWithinAvailableSpace(int len, int available)
- {
- return len < available;
- }
-
- @Override
- public boolean isLengthExceedingBlockSize(int len, int size)
- {
- return len >= size;
- }
- }
-
- protected interface AADOperator
- {
- void processAADByte(byte input);
-
- void processAADBytes(byte[] input, int inOff, int len);
-
- void reset();
-
- int getLen();
- }
-
- protected class DefaultAADOperator
- implements AADOperator
- {
- @Override
- public void processAADByte(byte input)
- {
- processor.processAADByte(input);
- }
-
- @Override
- public void processAADBytes(byte[] input, int inOff, int len)
- {
- processAadBytes(input, inOff, len);
- }
-
- public void reset()
- {
- }
-
- @Override
- public int getLen()
- {
- return m_aadPos;
- }
- }
-
- protected class CounterAADOperator
- implements AADOperator
- {
- private int aadLen;
-
- @Override
- public void processAADByte(byte input)
- {
- aadLen++;
- processor.processAADByte(input);
- }
-
- @Override
- public void processAADBytes(byte[] input, int inOff, int len)
- {
- aadLen += len;
- processAadBytes(input, inOff, len);
- }
-
- public int getLen()
- {
- return aadLen;
- }
-
- public void reset()
- {
- aadLen = 0;
- }
- }
-
- protected static class StreamAADOperator
- implements AADOperator
- {
- private final ErasableOutputStream stream = new ErasableOutputStream();
-
- @Override
- public void processAADByte(byte input)
- {
- stream.write(input);
- }
-
- @Override
- public void processAADBytes(byte[] input, int inOff, int len)
- {
- stream.write(input, inOff, len);
- }
-
- public byte[] getBytes()
- {
- return stream.getBuf();
- }
-
- @Override
- public void reset()
- {
- stream.reset();
- }
-
- @Override
- public int getLen()
- {
- return stream.size();
- }
- }
-
- protected interface DataOperator
- {
- int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff);
-
- int getLen();
-
- void reset();
- }
-
- protected class DefaultDataOperator
- implements DataOperator
- {
- public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
- {
- return processEncDecBytes(input, inOff, len, output, outOff);
- }
-
- @Override
- public int getLen()
- {
- return m_bufPos;
- }
-
- @Override
- public void reset()
- {
- }
- }
-
- protected class CounterDataOperator
- implements DataOperator
- {
- private int messegeLen;
-
- public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
- {
- messegeLen += len;
- return processEncDecBytes(input, inOff, len, output, outOff);
- }
-
- @Override
- public int getLen()
- {
- return messegeLen;
- }
-
- @Override
- public void reset()
- {
- messegeLen = 0;
- }
- }
-
- protected class StreamDataOperator
- implements DataOperator
- {
- private final ErasableOutputStream stream = new ErasableOutputStream();
-
- @Override
- public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
- {
- ensureInitialized();
- stream.write(input, inOff, len);
- m_bufPos = stream.size();
- return 0;
- }
-
- public byte[] getBytes()
- {
- return stream.getBuf();
- }
-
- @Override
- public int getLen()
- {
- return stream.size();
- }
-
- @Override
- public void reset()
- {
- stream.reset();
- }
- }
-
- protected class StreamCipherOperator
- implements DataOperator
- {
- private int len;
-
- @Override
- public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
- {
- boolean forEncryption = checkData(false);
- if (forEncryption)
- {
- this.len = len;
- processBufferEncrypt(input, inOff, output, outOff);
- return len;
- }
- else
- {
- // keep last mac size bytes
- int available = Math.max(m_bufPos + len - MAC_SIZE, 0);
- int rlt = 0;
- if (m_bufPos > 0)
- {
- this.len = Math.min(available, m_bufPos);
- rlt = this.len;
- processBufferDecrypt(m_buf, 0, output, outOff);
- available -= rlt;
- m_bufPos -= rlt;
- System.arraycopy(m_buf, rlt, m_buf, 0, m_bufPos);
- }
- if (available > 0)
- {
- this.len = available;
- processBufferDecrypt(input, inOff, output, outOff);
- rlt += available;
- len -= available;
- inOff += available;
- }
-
- System.arraycopy(input, inOff, m_buf, m_bufPos, len);
- m_bufPos += len;
- return rlt;
- }
- }
-
- @Override
- public int getLen()
- {
- return len;
- }
-
- @Override
- public void reset()
- {
- }
- }
-
- protected static final class ErasableOutputStream
- extends ByteArrayOutputStream
- {
- public ErasableOutputStream()
- {
- }
-
- public byte[] getBuf()
- {
- return buf;
- }
- }
-
- @Override
- public void processAADByte(byte input)
- {
- checkAAD();
- aadOperator.processAADByte(input);
- }
-
- @Override
- public void processAADBytes(byte[] input, int inOff, int len)
- {
- ensureSufficientInputBuffer(input, inOff, len);
- // Don't enter AAD state until we actually get input
- if (len <= 0)
- {
- return;
- }
-
- checkAAD();
- aadOperator.processAADBytes(input, inOff, len);
- }
-
- private void processAadBytes(byte[] input, int inOff, int len)
- {
- if (m_aadPos > 0)
- {
- int available = AADBufferSize - m_aadPos;
- if (processor.isLengthWithinAvailableSpace(len, available))
- {
- System.arraycopy(input, inOff, m_aad, m_aadPos, len);
- m_aadPos += len;
- return;
- }
-
- System.arraycopy(input, inOff, m_aad, m_aadPos, available);
- inOff += available;
- len -= available;
-
- processBufferAAD(m_aad, 0);
- }
- while (processor.isLengthExceedingBlockSize(len, AADBufferSize))
- {
- processBufferAAD(input, inOff);
- inOff += AADBufferSize;
- len -= AADBufferSize;
- }
- System.arraycopy(input, inOff, m_aad, 0, len);
- m_aadPos = len;
- }
-
- @Override
- public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
- throws DataLengthException
- {
- ensureSufficientInputBuffer(input, inOff, len);
- return dataOperator.processBytes(input, inOff, len, output, outOff);
- }
-
- protected int processEncDecBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
- {
- boolean forEncryption = checkData(false);
- int available, resultLength;
- available = (forEncryption ? BlockSize : m_bufferSizeDecrypt) - m_bufPos;
- // The function is just an operator < or <=
- if (processor.isLengthWithinAvailableSpace(len, available))
- {
- System.arraycopy(input, inOff, m_buf, m_bufPos, len);
- m_bufPos += len;
- return 0;
- }
- resultLength = processor.getUpdateOutputSize(len) + m_bufPos - (forEncryption ? 0 : MAC_SIZE);
- ensureSufficientOutputBuffer(output, outOff, resultLength - resultLength % BlockSize);
- resultLength = 0;
- if (forEncryption)
- {
- if (m_bufPos > 0)
- {
- System.arraycopy(input, inOff, m_buf, m_bufPos, available);
- inOff += available;
- len -= available;
- processBufferEncrypt(m_buf, 0, output, outOff);
- resultLength = BlockSize;
- }
- // The function is just an operator >= or >
- while (processor.isLengthExceedingBlockSize(len, BlockSize))
- {
- processBufferEncrypt(input, inOff, output, outOff + resultLength);
- inOff += BlockSize;
- len -= BlockSize;
- resultLength += BlockSize;
- }
- }
- else
- {
- // loop will run more than once for the following situation: pb128, ascon80pq, ascon128, ISAP_A_128(A)
- while (processor.isLengthExceedingBlockSize(m_bufPos, BlockSize)
- && processor.isLengthExceedingBlockSize(len + m_bufPos, m_bufferSizeDecrypt))
- {
- processBufferDecrypt(m_buf, resultLength, output, outOff + resultLength);
- m_bufPos -= BlockSize;
- resultLength += BlockSize;
- }
- if (m_bufPos > 0)
- {
- System.arraycopy(m_buf, resultLength, m_buf, 0, m_bufPos);
- if (processor.isLengthWithinAvailableSpace(m_bufPos + len, m_bufferSizeDecrypt))
- {
- System.arraycopy(input, inOff, m_buf, m_bufPos, len);
- m_bufPos += len;
- return resultLength;
- }
- available = Math.max(BlockSize - m_bufPos, 0);
- System.arraycopy(input, inOff, m_buf, m_bufPos, available);
- inOff += available;
- len -= available;
- processBufferDecrypt(m_buf, 0, output, outOff + resultLength);
- resultLength += BlockSize;
- }
- while (processor.isLengthExceedingBlockSize(len, m_bufferSizeDecrypt))
- {
- processBufferDecrypt(input, inOff, output, outOff + resultLength);
- inOff += BlockSize;
- len -= BlockSize;
- resultLength += BlockSize;
- }
- }
- System.arraycopy(input, inOff, m_buf, 0, len);
- m_bufPos = len;
- return resultLength;
- }
-
- @Override
- public int doFinal(byte[] output, int outOff)
- throws IllegalStateException, InvalidCipherTextException
- {
- boolean forEncryption = checkData(true);
- int resultLength;
- if (forEncryption)
- {
- resultLength = m_bufPos + MAC_SIZE;
- }
- else
- {
- if (m_bufPos < MAC_SIZE)
- {
- throw new InvalidCipherTextException("data too short");
- }
-
- m_bufPos -= MAC_SIZE;
-
- resultLength = m_bufPos;
- }
-
- ensureSufficientOutputBuffer(output, outOff, resultLength);
- mac = new byte[MAC_SIZE];
- processFinalBlock(output, outOff);
- if (forEncryption)
- {
- System.arraycopy(mac, 0, output, outOff + resultLength - MAC_SIZE, MAC_SIZE);
- }
- else
- {
- if (!Arrays.constantTimeAreEqual(MAC_SIZE, mac, 0, m_buf, m_bufPos))
- {
- throw new InvalidCipherTextException(algorithmName + " mac does not match");
- }
- }
- reset(!forEncryption);
- return resultLength;
- }
-
- public final int getBlockSize()
- {
- return BlockSize;
- }
-
- public int getUpdateOutputSize(int len)
- {
- int total = processor.getUpdateOutputSize(len);
- switch (m_state)
- {
- case DecInit:
- case DecAad:
- case DecData:
- case DecFinal:
- total = Math.max(0, total + m_bufPos - MAC_SIZE);
- break;
- case EncData:
- case EncFinal:
- total = Math.max(0, total + m_bufPos);
- break;
- default:
- break;
- }
- return total - total % BlockSize;
- }
-
- public int getOutputSize(int len)
- {
- int total = Math.max(0, len);
-
- switch (m_state)
- {
- case DecInit:
- case DecAad:
- case DecData:
- case DecFinal:
- return Math.max(0, total + m_bufPos - MAC_SIZE);
- case EncData:
- case EncFinal:
- return total + m_bufPos + MAC_SIZE;
- default:
- return total + MAC_SIZE;
- }
- }
-
- protected void checkAAD()
- {
- switch (m_state)
- {
- case DecInit:
- m_state = State.DecAad;
- break;
- case EncInit:
- m_state = State.EncAad;
- break;
- case DecAad:
- case EncAad:
- break;
- case EncFinal:
- throw new IllegalStateException(getAlgorithmName() + " cannot be reused for encryption");
- default:
- throw new IllegalStateException(getAlgorithmName() + " needs to be initialized");
- }
- }
-
- protected boolean checkData(boolean isDoFinal)
- {
- switch (m_state)
- {
- case DecInit:
- case DecAad:
- finishAAD(State.DecData, isDoFinal);
- return false;
- case EncInit:
- case EncAad:
- finishAAD(State.EncData, isDoFinal);
- return true;
- case DecData:
- return false;
- case EncData:
- return true;
- case EncFinal:
- throw new IllegalStateException(getAlgorithmName() + " cannot be reused for encryption");
- default:
- throw new IllegalStateException(getAlgorithmName() + " needs to be initialized");
- }
- }
-
- protected abstract void finishAAD(State nextState, boolean isDoFinal);
-
- protected final void bufferReset()
- {
- if (m_buf != null)
- {
- Arrays.fill(m_buf, (byte)0);
- m_bufPos = 0;
- }
- if (m_aad != null)
- {
- Arrays.fill(m_aad, (byte)0);
- m_aadPos = 0;
- }
- switch (m_state)
- {
- case DecInit:
- case EncInit:
- break;
- case DecAad:
- case DecData:
- case DecFinal:
- m_state = State.DecFinal;
- break;
- case EncAad:
- case EncData:
- case EncFinal:
- m_state = State.EncFinal;
- return;
- default:
- throw new IllegalStateException(getAlgorithmName() + " needs to be initialized");
- }
- aadOperator.reset();
- dataOperator.reset();
- }
-
- protected final void ensureSufficientOutputBuffer(byte[] output, int outOff, int len)
- {
- if (outOff + len > output.length)
- {
- throw new OutputLengthException("output buffer too short");
- }
- }
-
- protected final void ensureSufficientInputBuffer(byte[] input, int inOff, int len)
- {
- if (inOff + len > input.length)
- {
- throw new DataLengthException("input buffer too short");
- }
- }
-
- protected final void ensureInitialized()
- {
- if (m_state == State.Uninitialized)
- {
- throw new IllegalStateException("Need to call init function before operation");
- }
- }
-
- protected abstract void processFinalBlock(byte[] output, int outOff);
-
- protected abstract void processBufferAAD(byte[] input, int inOff);
-
- protected abstract void processFinalAAD();
-
- protected abstract void processBufferEncrypt(byte[] input, int inOff, byte[] output, int outOff);
-
- protected abstract void processBufferDecrypt(byte[] input, int inOff, byte[] output, int outOff);
-}
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/AsconAEAD128.java b/core/src/main/java/org/bouncycastle/crypto/engines/AsconAEAD128.java
index 5be9764901..856eadc359 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/AsconAEAD128.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/AsconAEAD128.java
@@ -144,10 +144,6 @@ protected void init(byte[] key, byte[] iv)
K1 = Pack.littleEndianToLong(key, 8);
N0 = Pack.littleEndianToLong(iv, 0);
N1 = Pack.littleEndianToLong(iv, 8);
-
- m_state = forEncryption ? State.EncInit : State.DecInit;
-
- reset(true);
}
public String getAlgorithmVersion()
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/AsconBaseEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/AsconBaseEngine.java
index 4561bfcf68..b72a3efd3e 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/AsconBaseEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/AsconBaseEngine.java
@@ -1,7 +1,7 @@
package org.bouncycastle.crypto.engines;
abstract class AsconBaseEngine
- extends AEADBufferBaseEngine
+ extends AEADBaseEngine
{
protected int nr;
protected long K0;
@@ -98,9 +98,8 @@ protected void processBufferEncrypt(byte[] buffer, int bufOff, byte[] output, in
protected void reset(boolean clearMac)
{
- bufferReset();
- ascon_aeadinit();
super.reset(clearMac);
+ ascon_aeadinit();
}
public abstract String getAlgorithmVersion();
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/AsconEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/AsconEngine.java
index 2c9c9f3791..f9f8a3995a 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/AsconEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/AsconEngine.java
@@ -226,10 +226,6 @@ else if (KEY_SIZE == 20)
{
throw new IllegalStateException();
}
-
- m_state = forEncryption ? State.EncInit : State.DecInit;
-
- reset(true);
}
public String getAlgorithmVersion()
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/ElephantEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/ElephantEngine.java
index c6789acbad..a546d6246b 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/ElephantEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/ElephantEngine.java
@@ -10,7 +10,7 @@
* Specification: https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-spec-doc/elephant-spec-final.pdf
*/
public class ElephantEngine
- extends AEADBufferBaseEngine
+ extends AEADBaseEngine
{
public enum ElephantParameters
{
@@ -291,8 +291,6 @@ protected void init(byte[] k, byte[] iv)
expanded_key = new byte[BlockSize];
System.arraycopy(k, 0, expanded_key, 0, KEY_SIZE);
instance.permutation(expanded_key);
- m_state = forEncryption ? State.EncInit : State.DecInit;
- reset(false);
}
protected void processBufferEncrypt(byte[] input, int inOff, byte[] output, int outOff)
@@ -479,12 +477,11 @@ protected void processFinalAAD()
protected void reset(boolean clearMac)
{
+ super.reset(clearMac);
Arrays.fill(tag_buffer, (byte)0);
Arrays.fill(previous_outputMessage, (byte)0);
nb_its = 0;
adOff = -1;
- super.reset(clearMac);
- bufferReset();
}
protected void checkAAD()
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/GiftCofbEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/GiftCofbEngine.java
index 6bb4e0aa0b..36f9eb4560 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/GiftCofbEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/GiftCofbEngine.java
@@ -9,7 +9,7 @@
*/
public class GiftCofbEngine
- extends AEADBufferBaseEngine
+ extends AEADBaseEngine
{
private byte[] npub;
private byte[] k;
@@ -234,8 +234,6 @@ protected void init(byte[] key, byte[] iv)
Y = new byte[BlockSize];
input = new byte[16];
offset = new byte[8];
- m_state = forEncryption ? State.EncInit : State.DecInit;
- reset(false);
}
@Override
@@ -302,7 +300,6 @@ protected void processBufferDecrypt(byte[] inputM, int inOff, byte[] output, int
protected void reset(boolean clearMac)
{
- bufferReset();
super.reset(clearMac);
/*nonce is 128-bit*/
System.arraycopy(npub, 0, input, 0, IV_SIZE);
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java
index d53b61caff..02b6bed9aa 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java
@@ -6,7 +6,7 @@
* Grain-128 AEAD, based on the current round 3 submission, https://grain-128aead.github.io/
*/
public class Grain128AEADEngine
- extends AEADBufferBaseEngine
+ extends AEADBaseEngine
{
/**
* Constants
@@ -50,13 +50,12 @@ protected void init(byte[] key, byte[] iv)
nfsr = new int[STATE_SIZE];
authAcc = new int[2];
authSr = new int[2];
- m_state = forEncryption ? State.EncInit : State.DecInit;
+
System.arraycopy(iv, 0, workingIV, 0, IV_SIZE);
workingIV[12] = (byte)0xFF;
workingIV[13] = (byte)0xFF;
workingIV[14] = (byte)0xFF;
workingIV[15] = (byte)0x7F;
- reset();
}
private void initGrain(int[] auth)
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/ISAPEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/ISAPEngine.java
index e170f0ff96..3ec53ff003 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/ISAPEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/ISAPEngine.java
@@ -12,7 +12,7 @@
*
*/
public class ISAPEngine
- extends AEADBufferBaseEngine
+ extends AEADBaseEngine
{
public enum IsapType
@@ -682,8 +682,6 @@ protected void init(byte[] key, byte[] iv)
npub = iv;
k = key;
ISAPAEAD.init();
- m_state = forEncryption ? State.EncInit : State.DecInit;
- reset();
}
@@ -747,9 +745,7 @@ protected void processFinalBlock(byte[] output, int outOff)
protected void reset(boolean clearMac)
{
- ensureInitialized();
- bufferReset();
- ISAPAEAD.reset();
super.reset(clearMac);
+ ISAPAEAD.reset();
}
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java
index b90ace4c42..9ac4b0869b 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java
@@ -12,7 +12,7 @@
*/
public class PhotonBeetleEngine
- extends AEADBufferBaseEngine
+ extends AEADBaseEngine
{
public enum PhotonBeetleParameters
{
@@ -72,6 +72,7 @@ public PhotonBeetleEngine(PhotonBeetleParameters pbp)
STATE_INBYTES = (STATE_INBITS + 7) >>> 3;
LAST_THREE_BITS_OFFSET = (STATE_INBITS - ((STATE_INBYTES - 1) << 3) - 3);
algorithmName = "Photon-Beetle AEAD";
+ state = new byte[STATE_INBYTES];
setInnerMembers(ProcessingBufferType.Buffered, AADOperatorType.Counter, DataOperatorType.Counter);
}
@@ -81,9 +82,6 @@ protected void init(byte[] key, byte[] iv)
{
K = key;
N = iv;
- state = new byte[STATE_INBYTES];
- m_state = forEncryption ? State.EncInit : State.DecInit;
- reset(false);
}
@@ -189,12 +187,10 @@ else if (input_empty)
protected void reset(boolean clearMac)
{
- ensureInitialized();
- bufferReset();
+ super.reset(clearMac);
input_empty = true;
System.arraycopy(K, 0, state, 0, K.length);
System.arraycopy(N, 0, state, K.length, N.length);
- super.reset(clearMac);
}
private static void photonPermutation(byte[] state)
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/RomulusEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/RomulusEngine.java
index d2196675ff..3ada509a3d 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/RomulusEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/RomulusEngine.java
@@ -11,7 +11,7 @@
*/
public class RomulusEngine
- extends AEADBufferBaseEngine
+ extends AEADBaseEngine
{
public enum RomulusParameters
{
@@ -860,8 +860,6 @@ protected void init(byte[] key, byte[] iv)
{
npub = iv;
k = key;
- m_state = forEncryption ? State.EncInit : State.DecInit;
- reset(false);
}
protected void finishAAD(State nextState, boolean isDoFinal)
@@ -913,8 +911,7 @@ protected void processBufferDecrypt(byte[] input, int inOff, byte[] output, int
protected void reset(boolean clearMac)
{
- bufferReset();
- instance.reset();
super.reset(clearMac);
+ instance.reset();
}
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/SparkleEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/SparkleEngine.java
index 889188d1c0..3084588da0 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/SparkleEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/SparkleEngine.java
@@ -11,7 +11,7 @@
* Specification: https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-spec-doc/sparkle-spec-final.pdf
*/
public class SparkleEngine
- extends AEADBufferBaseEngine
+ extends AEADBaseEngine
{
public enum SparkleParameters
{
@@ -111,9 +111,6 @@ public SparkleEngine(SparkleParameters sparkleParameters)
npub = new int[RATE_WORDS];
AADBufferSize = BlockSize = IV_SIZE;
setInnerMembers(ProcessingBufferType.Buffered, AADOperatorType.Default, DataOperatorType.Default);
-
- // Relied on by processBytes method for decryption
-// assert RATE_BYTES >= TAG_BYTES;
}
protected void init(byte[] key, byte[] iv)
@@ -121,9 +118,6 @@ protected void init(byte[] key, byte[] iv)
{
Pack.littleEndianToInt(key, 0, k);
Pack.littleEndianToInt(iv, 0, npub);
- m_state = forEncryption ? State.EncInit : State.DecInit;
-
- reset();
}
protected void finishAAD(State nextState, boolean isDoFinal)
@@ -310,7 +304,6 @@ protected void processFinalAAD()
protected void reset(boolean clearMac)
{
- bufferReset();
encrypted = false;
// The Initialize function loads nonce and key into the state and executes the
// SPARKLE permutation with the big number of steps.
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/XoodyakEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/XoodyakEngine.java
index a03755bbbc..024a7754af 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/XoodyakEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/XoodyakEngine.java
@@ -14,7 +14,7 @@
*/
public class XoodyakEngine
- extends AEADBufferBaseEngine
+ extends AEADBaseEngine
{
private byte[] state;
private int phase;
@@ -34,11 +34,10 @@ public class XoodyakEngine
public XoodyakEngine()
{
algorithmName = "Xoodyak AEAD";
- KEY_SIZE = 16;
- IV_SIZE = 16;
- MAC_SIZE = 16;
+ KEY_SIZE = IV_SIZE = MAC_SIZE = 16;
BlockSize = 24;
AADBufferSize = 44;
+ state = new byte[48];
setInnerMembers(ProcessingBufferType.Immediate, AADOperatorType.Default, DataOperatorType.Counter);
}
@@ -48,9 +47,6 @@ protected void init(byte[] key, byte[] iv)
{
K = key;
this.iv = iv;
- state = new byte[48];
- m_state = forEncryption ? State.EncInit : State.DecInit;
- reset();
}
protected void processBufferAAD(byte[] input, int inOff)
@@ -131,8 +127,6 @@ protected void processFinalBlock(byte[] output, int outOff)
protected void reset(boolean clearMac)
{
- bufferReset();
- ensureInitialized();
super.reset(clearMac);
Arrays.fill(state, (byte)0);
encrypted = false;
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java b/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java
index 33124af334..9a68806b78 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java
@@ -116,7 +116,7 @@ private void testLongAEAD()
grain.doFinal(rv, len);
isTrue(Arrays.areEqual(rv, CT));
-
+ grain.init(true, params);
grain.processBytes(PT, 0, 10, rv, 0);
try
{
@@ -230,7 +230,15 @@ static void isEqualTo(
public static void main(String[] args)
{
+// runTest(new AsconTest());
+// runTest(new ElephantTest());
+// runTest(new GiftCofbTest());
runTest(new Grain128AEADTest());
+// runTest(new ISAPTest());
+// runTest(new PhotonBeetleTest());
+// runTest(new RomulusTest());
+// runTest(new SparkleTest());
+// runTest(new XoodyakTest());
}
}
From c1447279c4c0d87c81002b4880eefe533decb041 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Fri, 14 Mar 2025 17:01:33 +1030
Subject: [PATCH 217/890] Minor changes around aead classes
---
.../crypto/engines/AEADBaseEngine.java | 45 +++++++++----------
.../crypto/engines/AsconEngine.java | 1 -
.../crypto/engines/Grain128AEADEngine.java | 23 +---------
.../crypto/engines/ISAPEngine.java | 1 -
.../crypto/engines/PhotonBeetleEngine.java | 1 -
.../crypto/engines/XoodyakEngine.java | 2 +-
6 files changed, 25 insertions(+), 48 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBaseEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/AEADBaseEngine.java
index 1598e97fbb..b1818ae9d8 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBaseEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/AEADBaseEngine.java
@@ -161,8 +161,6 @@ else if (params instanceof ParametersWithIV)
}
}
-
-
protected void reset(boolean clearMac)
{
ensureInitialized();
@@ -572,19 +570,6 @@ public void reset()
}
}
- protected static final class ErasableOutputStream
- extends ByteArrayOutputStream
- {
- public ErasableOutputStream()
- {
- }
-
- public byte[] getBuf()
- {
- return buf;
- }
- }
-
@Override
public void processAADByte(byte input)
{
@@ -761,6 +746,12 @@ public final int getBlockSize()
}
public int getUpdateOutputSize(int len)
+ {
+ int total = getTotalBytesForUpdate(len);
+ return total - total % BlockSize;
+ }
+
+ protected int getTotalBytesForUpdate(int len)
{
int total = processor.getUpdateOutputSize(len);
switch (m_state)
@@ -778,7 +769,7 @@ public int getUpdateOutputSize(int len)
default:
break;
}
- return total - total % BlockSize;
+ return total;
}
public int getOutputSize(int len)
@@ -843,13 +834,6 @@ protected boolean checkData(boolean isDoFinal)
}
}
- protected abstract void finishAAD(State nextState, boolean isDoFinal);
-
- protected final void bufferReset()
- {
-
- }
-
protected final void ensureSufficientOutputBuffer(byte[] output, int outOff, int len)
{
if (outOff + len > output.length)
@@ -876,6 +860,8 @@ protected final void ensureInitialized()
protected abstract void init(byte[] key, byte[] iv);
+ protected abstract void finishAAD(State nextState, boolean isDoFinal);
+
protected abstract void processFinalBlock(byte[] output, int outOff);
protected abstract void processBufferAAD(byte[] input, int inOff);
@@ -885,4 +871,17 @@ protected final void ensureInitialized()
protected abstract void processBufferEncrypt(byte[] input, int inOff, byte[] output, int outOff);
protected abstract void processBufferDecrypt(byte[] input, int inOff, byte[] output, int outOff);
+
+ protected static final class ErasableOutputStream
+ extends ByteArrayOutputStream
+ {
+ public ErasableOutputStream()
+ {
+ }
+
+ public byte[] getBuf()
+ {
+ return buf;
+ }
+ }
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/AsconEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/AsconEngine.java
index f9f8a3995a..9e9fab811d 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/AsconEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/AsconEngine.java
@@ -208,7 +208,6 @@ protected void finishData(State nextState)
protected void init(byte[] key, byte[] iv)
throws IllegalArgumentException
{
-
N0 = Pack.bigEndianToLong(iv, 0);
N1 = Pack.bigEndianToLong(iv, 8);
if (KEY_SIZE == 16)
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java
index 02b6bed9aa..4039dc3ede 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java
@@ -181,8 +181,7 @@ private void shift()
protected void reset(boolean clearMac)
{
- this.aadOperator.reset();
-
+ super.reset(clearMac);
Pack.littleEndianToInt(workingKey, 0, nfsr);
Pack.littleEndianToInt(workingIV, 0, lfsr);
// 320 clocks initialization phase.
@@ -203,7 +202,6 @@ protected void reset(boolean clearMac)
}
initGrain(authAcc);
initGrain(authSr);
- super.reset(clearMac);
}
private void updateInternalState(int input_i_j)
@@ -216,26 +214,9 @@ private void updateInternalState(int input_i_j)
authSr[1] = (authSr[1] >>> 1) | (val << 31);
}
-
public int getUpdateOutputSize(int len)
{
- int total = processor.getUpdateOutputSize(len);
- switch (m_state)
- {
- case DecInit:
- case DecAad:
- case DecData:
- case DecFinal:
- total = Math.max(0, total + m_bufPos - MAC_SIZE);
- break;
- case EncData:
- case EncFinal:
- total = Math.max(0, total + m_bufPos);
- break;
- default:
- break;
- }
- return total;
+ return getTotalBytesForUpdate(len);
}
@Override
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/ISAPEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/ISAPEngine.java
index 3ec53ff003..2bddc150da 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/ISAPEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/ISAPEngine.java
@@ -684,7 +684,6 @@ protected void init(byte[] key, byte[] iv)
ISAPAEAD.init();
}
-
protected void processBufferAAD(byte[] input, int inOff)
{
ISAPAEAD.absorbMacBlock(input, inOff);
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java
index 9ac4b0869b..014f4acb94 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java
@@ -84,7 +84,6 @@ protected void init(byte[] key, byte[] iv)
N = iv;
}
-
protected void processBufferAAD(byte[] input, int inOff)
{
photonPermutation(state);
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/XoodyakEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/XoodyakEngine.java
index 024a7754af..36c89d6d0b 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/XoodyakEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/XoodyakEngine.java
@@ -16,7 +16,7 @@
public class XoodyakEngine
extends AEADBaseEngine
{
- private byte[] state;
+ private final byte[] state;
private int phase;
private int mode;
private static final int f_bPrime_1 = 47;
From 24cf9b794e6dbc0cd38ea48f0ce8944b9083ebdf Mon Sep 17 00:00:00 2001
From: gefeili
Date: Sat, 15 Mar 2025 14:19:55 +1030
Subject: [PATCH 218/890] finishAAD. Set BufferBaseDigest not public
---
.../crypto/digests/BufferBaseDigest.java | 2 +-
.../crypto/engines/AEADBaseEngine.java | 73 +++++++++++++++++--
.../crypto/engines/ElephantEngine.java | 16 +---
.../crypto/engines/GiftCofbEngine.java | 18 +----
.../crypto/engines/Grain128AEADEngine.java | 73 +++++++------------
.../crypto/engines/ISAPEngine.java | 18 +----
.../crypto/engines/PhotonBeetleEngine.java | 19 +----
.../crypto/engines/RomulusEngine.java | 15 +---
.../crypto/engines/SparkleEngine.java | 16 +---
.../crypto/engines/XoodyakEngine.java | 18 +----
10 files changed, 102 insertions(+), 166 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/BufferBaseDigest.java b/core/src/main/java/org/bouncycastle/crypto/digests/BufferBaseDigest.java
index d038985c4f..55c27d83ce 100644
--- a/core/src/main/java/org/bouncycastle/crypto/digests/BufferBaseDigest.java
+++ b/core/src/main/java/org/bouncycastle/crypto/digests/BufferBaseDigest.java
@@ -5,7 +5,7 @@
import org.bouncycastle.crypto.OutputLengthException;
import org.bouncycastle.util.Arrays;
-public abstract class BufferBaseDigest
+abstract class BufferBaseDigest
implements ExtendedDigest
{
protected enum ProcessingBufferType
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBaseEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/AEADBaseEngine.java
index b1818ae9d8..b79cf198fb 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBaseEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/AEADBaseEngine.java
@@ -96,12 +96,6 @@ public void reset()
reset(true);
}
- public int processByte(byte in, byte[] out, int outOff)
- throws DataLengthException
- {
- return processBytes(new byte[]{in}, 0, 1, out, outOff);
- }
-
public void init(boolean forEncryption, CipherParameters params)
{
this.forEncryption = forEncryption;
@@ -225,6 +219,7 @@ protected void setInnerMembers(ProcessingBufferType type, AADOperatorType aadOpe
aadOperator = new CounterAADOperator();
break;
case Stream:
+ AADBufferSize = 0;
aadOperator = new StreamAADOperator();
break;
}
@@ -619,6 +614,12 @@ private void processAadBytes(byte[] input, int inOff, int len)
m_aadPos = len;
}
+ public int processByte(byte in, byte[] out, int outOff)
+ throws DataLengthException
+ {
+ return processBytes(new byte[]{in}, 0, 1, out, outOff);
+ }
+
@Override
public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
throws DataLengthException
@@ -858,10 +859,68 @@ protected final void ensureInitialized()
}
}
- protected abstract void init(byte[] key, byte[] iv);
+ protected void finishAAD1(State nextState)
+ {
+ switch (m_state)
+ {
+ case DecInit:
+ case DecAad:
+ case EncInit:
+ case EncAad:
+ {
+ processFinalAAD();
+ break;
+ }
+ default:
+ break;
+ }
+ m_state = nextState;
+ }
+
+ protected void finishAAD2(State nextState)
+ {
+ // State indicates whether we ever received AAD
+ switch (m_state)
+ {
+ case DecAad:
+ case EncAad:
+ {
+ processFinalAAD();
+ break;
+ }
+ default:
+ break;
+ }
+
+ m_aadPos = 0;
+ m_state = nextState;
+ }
+
+ protected void finishAAD3(State nextState, boolean isDoFinal)
+ {
+ // State indicates whether we ever received AAD
+ switch (m_state)
+ {
+ case DecInit:
+ case DecAad:
+ if (!isDoFinal && dataOperator.getLen() <= MAC_SIZE)
+ {
+ return;
+ }
+ case EncInit:
+ case EncAad:
+ processFinalAAD();
+ break;
+ }
+
+ m_aadPos = 0;
+ m_state = nextState;
+ }
protected abstract void finishAAD(State nextState, boolean isDoFinal);
+ protected abstract void init(byte[] key, byte[] iv);
+
protected abstract void processFinalBlock(byte[] output, int outOff);
protected abstract void processBufferAAD(byte[] input, int inOff);
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/ElephantEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/ElephantEngine.java
index a546d6246b..c85aaa9ac5 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/ElephantEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/ElephantEngine.java
@@ -439,21 +439,7 @@ public int getOutputSize(int len)
protected void finishAAD(State nextState, boolean isDoFinal)
{
- // State indicates whether we ever received AAD
- switch (m_state)
- {
- case DecAad:
- case EncAad:
- {
- processFinalAAD();
- break;
- }
- default:
- break;
- }
-
- m_aadPos = 0;
- m_state = nextState;
+ finishAAD2(nextState);
}
@Override
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/GiftCofbEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/GiftCofbEngine.java
index 36f9eb4560..a5ac0ae3db 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/GiftCofbEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/GiftCofbEngine.java
@@ -207,23 +207,7 @@ protected void processFinalAAD()
@Override
protected void finishAAD(State nextState, boolean isDoFinal)
{
- // State indicates whether we ever received AAD
- switch (m_state)
- {
- case DecInit:
- case DecAad:
- if (!isDoFinal && dataOperator.getLen() <= MAC_SIZE)
- {
- return;
- }
- case EncInit:
- case EncAad:
- processFinalAAD();
- break;
- }
-
- m_aadPos = 0;
- m_state = nextState;
+ finishAAD3(nextState, isDoFinal);
}
@Override
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java
index 4039dc3ede..04bf4e5491 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java
@@ -1,5 +1,7 @@
package org.bouncycastle.crypto.engines;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Pack;
/**
@@ -19,10 +21,10 @@ public class Grain128AEADEngine
*/
private byte[] workingKey;
private byte[] workingIV;
- private int[] lfsr;
- private int[] nfsr;
- private int[] authAcc;
- private int[] authSr;
+ private final int[] lfsr;
+ private final int[] nfsr;
+ private final int[] authAcc;
+ private final int[] authSr;
public Grain128AEADEngine()
{
@@ -30,13 +32,15 @@ public Grain128AEADEngine()
KEY_SIZE = 16;
IV_SIZE = 12;
MAC_SIZE = 8;
+ lfsr = new int[STATE_SIZE];
+ nfsr = new int[STATE_SIZE];
+ authAcc = new int[2];
+ authSr = new int[2];
setInnerMembers(ProcessingBufferType.Immediate, AADOperatorType.Stream, DataOperatorType.StreamCipher);
}
/**
* Initialize a Grain-128AEAD cipher.
- *
- * @throws IllegalArgumentException If the params argument is inappropriate.
*/
protected void init(byte[] key, byte[] iv)
throws IllegalArgumentException
@@ -46,11 +50,6 @@ protected void init(byte[] key, byte[] iv)
*/
workingIV = new byte[16];
workingKey = key;
- lfsr = new int[STATE_SIZE];
- nfsr = new int[STATE_SIZE];
- authAcc = new int[2];
- authSr = new int[2];
-
System.arraycopy(iv, 0, workingIV, 0, IV_SIZE);
workingIV[12] = (byte)0xFF;
workingIV[13] = (byte)0xFF;
@@ -158,25 +157,23 @@ private int getOutput()
}
/**
- * Shift array 1 bit and add val to index.length - 1.
+ * Shift array 1 bit and add val to index - 1.
*
* @param array The array to shift.
* @param val The value to shift in.
- * @return The shifted array with val added to index.length - 1.
*/
- private int[] shift(int[] array, int val)
+ private void shift(int[] array, int val)
{
array[0] = (array[0] >>> 1) | (array[1] << 31);
array[1] = (array[1] >>> 1) | (array[2] << 31);
array[2] = (array[2] >>> 1) | (array[3] << 31);
array[3] = (array[3] >>> 1) | (val << 31);
- return array;
}
private void shift()
{
- nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0]) & 1);
- lfsr = shift(lfsr, (getOutputLFSR()) & 1);
+ shift(nfsr, (getOutputNFSR() ^ lfsr[0]) & 1);
+ shift(lfsr, (getOutputLFSR()) & 1);
}
protected void reset(boolean clearMac)
@@ -184,34 +181,37 @@ protected void reset(boolean clearMac)
super.reset(clearMac);
Pack.littleEndianToInt(workingKey, 0, nfsr);
Pack.littleEndianToInt(workingIV, 0, lfsr);
+ Arrays.clear(authAcc);
+ Arrays.clear(authSr);
+ int output;
// 320 clocks initialization phase.
for (int i = 0; i < 320; ++i)
{
- int output = getOutput();
- nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0] ^ output) & 1);
- lfsr = shift(lfsr, (getOutputLFSR() ^ output) & 1);
+ output = getOutput();
+ shift(nfsr, (getOutputNFSR() ^ lfsr[0] ^ output) & 1);
+ shift(lfsr, (getOutputLFSR() ^ output) & 1);
}
for (int quotient = 0; quotient < 8; ++quotient)
{
for (int remainder = 0; remainder < 8; ++remainder)
{
- int output = getOutput();
- nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0] ^ output ^ ((workingKey[quotient]) >> remainder)) & 1);
- lfsr = shift(lfsr, (getOutputLFSR() ^ output ^ ((workingKey[quotient + 8]) >> remainder)) & 1);
+ output = getOutput();
+ shift(nfsr, (getOutputNFSR() ^ lfsr[0] ^ output ^ ((workingKey[quotient]) >> remainder)) & 1);
+ shift(lfsr, (getOutputLFSR() ^ output ^ ((workingKey[quotient + 8]) >> remainder)) & 1);
}
}
initGrain(authAcc);
initGrain(authSr);
}
- private void updateInternalState(int input_i_j)
+ private void updateInternalState(int mask)
{
- int mask = -input_i_j;
+ mask = -mask;
authAcc[0] ^= authSr[0] & mask;
authAcc[1] ^= authSr[1] & mask;
- int val = getByteKeyStream();
+ mask = getByteKeyStream();
authSr[0] = (authSr[0] >>> 1) | (authSr[1] << 31);
- authSr[1] = (authSr[1] >>> 1) | (val << 31);
+ authSr[1] = (authSr[1] >>> 1) | (mask << 31);
}
public int getUpdateOutputSize(int len)
@@ -222,23 +222,7 @@ public int getUpdateOutputSize(int len)
@Override
protected void finishAAD(State nextState, boolean isDoFinal)
{
- // State indicates whether we ever received AAD
- switch (m_state)
- {
- case DecInit:
- case DecAad:
- case EncInit:
- case EncAad:
- {
- processFinalAAD();
- break;
- }
- default:
- break;
- }
-
- m_aadPos = 0;
- m_state = nextState;
+ finishAAD1(nextState);
}
@Override
@@ -252,7 +236,6 @@ protected void processFinalBlock(byte[] output, int outOff)
@Override
protected void processBufferAAD(byte[] input, int inOff)
{
-
}
@Override
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/ISAPEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/ISAPEngine.java
index 2bddc150da..5a404540d9 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/ISAPEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/ISAPEngine.java
@@ -697,23 +697,7 @@ protected void processFinalAAD()
@Override
protected void finishAAD(State nextState, boolean isDoFinal)
{
- // State indicates whether we ever received AAD
- switch (m_state)
- {
- case DecInit:
- case DecAad:
- if (!isDoFinal && dataOperator.getLen() <= MAC_SIZE)
- {
- return;
- }
- case EncInit:
- case EncAad:
- processFinalAAD();
- break;
- }
-
- m_aadPos = 0;
- m_state = nextState;
+ finishAAD3(nextState, isDoFinal);
}
protected void processBufferEncrypt(byte[] input, int inOff, byte[] output, int outOff)
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java
index 014f4acb94..29a299da8a 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java
@@ -93,24 +93,7 @@ protected void processBufferAAD(byte[] input, int inOff)
@Override
protected void finishAAD(State nextState, boolean isDoFinal)
{
- // State indicates whether we ever received AAD
- switch (m_state)
- {
- case DecInit:
- case DecAad:
- if (!isDoFinal && dataOperator.getLen() <= MAC_SIZE)
- {
- //m_state = State.DecData;
- return;
- }
- case EncInit:
- case EncAad:
- processFinalAAD();
- break;
- }
-
- m_aadPos = 0;
- m_state = nextState;
+ finishAAD3(nextState, isDoFinal);
}
protected void processFinalAAD()
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/RomulusEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/RomulusEngine.java
index 3ada509a3d..f0b2ba1484 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/RomulusEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/RomulusEngine.java
@@ -865,20 +865,7 @@ protected void init(byte[] key, byte[] iv)
protected void finishAAD(State nextState, boolean isDoFinal)
{
// State indicates whether we ever received AAD
- switch (m_state)
- {
- case DecInit:
- case DecAad:
- case EncInit:
- case EncAad:
- {
- processFinalAAD();
- break;
- }
- default:
- break;
- }
- m_state = nextState;
+ finishAAD1(nextState);
}
protected void processBufferAAD(byte[] input, int inOff)
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/SparkleEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/SparkleEngine.java
index 3084588da0..6e71b16b7b 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/SparkleEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/SparkleEngine.java
@@ -122,21 +122,7 @@ protected void init(byte[] key, byte[] iv)
protected void finishAAD(State nextState, boolean isDoFinal)
{
- // State indicates whether we ever received AAD
- switch (m_state)
- {
- case DecAad:
- case EncAad:
- {
- processFinalAAD();
- break;
- }
- default:
- break;
- }
-
- m_aadPos = 0;
- m_state = nextState;
+ finishAAD2(nextState);
}
@Override
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/XoodyakEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/XoodyakEngine.java
index 36c89d6d0b..b22e39eeea 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/XoodyakEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/XoodyakEngine.java
@@ -63,23 +63,7 @@ protected void processFinalAAD()
@Override
protected void finishAAD(State nextState, boolean isDoFinal)
{
- // State indicates whether we ever received AAD
- switch (m_state)
- {
- case DecInit:
- case DecAad:
- if (!isDoFinal && dataOperator.getLen() <= MAC_SIZE)
- {
- return;
- }
- case EncInit:
- case EncAad:
- processFinalAAD();
- break;
- }
-
- m_aadPos = 0;
- m_state = nextState;
+ finishAAD3(nextState, isDoFinal);
}
protected void processBufferEncrypt(byte[] input, int inOff, byte[] output, int outOff)
From a1e0799f317a0e634c625cc1621c7c54100e336b Mon Sep 17 00:00:00 2001
From: gefeili
Date: Sun, 16 Mar 2025 09:38:03 +1030
Subject: [PATCH 219/890] Refactor on Grain128AEADEngine
---
.../crypto/engines/AEADBaseEngine.java | 3 +++
.../crypto/test/Grain128AEADTest.java | 16 ++++++++--------
2 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBaseEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/AEADBaseEngine.java
index b79cf198fb..c251408f48 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBaseEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/AEADBaseEngine.java
@@ -859,6 +859,7 @@ protected final void ensureInitialized()
}
}
+ // Used for Grain128 AEAD and Romulus Engine
protected void finishAAD1(State nextState)
{
switch (m_state)
@@ -877,6 +878,7 @@ protected void finishAAD1(State nextState)
m_state = nextState;
}
+ // Use for Elephant and Sparkle
protected void finishAAD2(State nextState)
{
// State indicates whether we ever received AAD
@@ -896,6 +898,7 @@ protected void finishAAD2(State nextState)
m_state = nextState;
}
+ // Used for Gift-Cofb, ISAP, PhotonBeetle and Xoodyak
protected void finishAAD3(State nextState, boolean isDoFinal)
{
// State indicates whether we ever received AAD
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java b/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java
index 9a68806b78..ed44d534ce 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java
@@ -230,15 +230,15 @@ static void isEqualTo(
public static void main(String[] args)
{
-// runTest(new AsconTest());
-// runTest(new ElephantTest());
-// runTest(new GiftCofbTest());
+ runTest(new AsconTest());
+ runTest(new ElephantTest());
+ runTest(new GiftCofbTest());
runTest(new Grain128AEADTest());
-// runTest(new ISAPTest());
-// runTest(new PhotonBeetleTest());
-// runTest(new RomulusTest());
-// runTest(new SparkleTest());
-// runTest(new XoodyakTest());
+ runTest(new ISAPTest());
+ runTest(new PhotonBeetleTest());
+ runTest(new RomulusTest());
+ runTest(new SparkleTest());
+ runTest(new XoodyakTest());
}
}
From e150b26c86a9920fd44e147b836072f6af0abfd7 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Sun, 16 Mar 2025 09:38:16 +1030
Subject: [PATCH 220/890] Refactor on Grain128AEADEngine
---
.../crypto/engines/Grain128AEADEngine.java | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java
index 04bf4e5491..ff32602bfa 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java
@@ -1,6 +1,5 @@
package org.bouncycastle.crypto.engines;
-import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Pack;
@@ -63,8 +62,7 @@ private void initGrain(int[] auth)
{
for (int remainder = 0; remainder < 32; ++remainder)
{
- int output = getByteKeyStream();
- auth[quotient] |= output << remainder;
+ auth[quotient] |= getByteKeyStream() << remainder;
}
}
}
@@ -258,9 +256,9 @@ protected void processFinalAAD()
ader = new byte[1 + aderlen];
ader[0] = (byte)(0x80 | aderlen);
int tmp = len;
- for (int i = 0; i < aderlen; ++i)
+ for (int i = 1; i < ader.length; ++i)
{
- ader[1 + i] = (byte)tmp;
+ ader[i] = (byte)tmp;
tmp >>>= 8;
}
}
@@ -277,8 +275,7 @@ private void absorbAadData(byte[] ader, int len)
for (int j = 0; j < 8; ++j)
{
shift();
- int ader_i_j = (ader_i >> j) & 1;
- updateInternalState(ader_i_j);
+ updateInternalState((ader_i >> j) & 1);
}
}
}
From 14d6f2463cffa13192a810bd50c5501bd28c1835 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Sun, 16 Mar 2025 09:39:00 +1030
Subject: [PATCH 221/890] Remove Grain128AEADTest.main
---
.../crypto/test/Grain128AEADTest.java | 24 +++++++++----------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java b/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java
index ed44d534ce..7f1f291db9 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java
@@ -228,17 +228,17 @@ static void isEqualTo(
}
}
- public static void main(String[] args)
- {
- runTest(new AsconTest());
- runTest(new ElephantTest());
- runTest(new GiftCofbTest());
- runTest(new Grain128AEADTest());
- runTest(new ISAPTest());
- runTest(new PhotonBeetleTest());
- runTest(new RomulusTest());
- runTest(new SparkleTest());
- runTest(new XoodyakTest());
- }
+// public static void main(String[] args)
+// {
+// runTest(new AsconTest());
+// runTest(new ElephantTest());
+// runTest(new GiftCofbTest());
+// runTest(new Grain128AEADTest());
+// runTest(new ISAPTest());
+// runTest(new PhotonBeetleTest());
+// runTest(new RomulusTest());
+// runTest(new SparkleTest());
+// runTest(new XoodyakTest());
+// }
}
From b53457d967a452b42e17f19afda0fdbc8c98ee8c Mon Sep 17 00:00:00 2001
From: David Hook
Date: Sun, 16 Mar 2025 15:15:16 +1100
Subject: [PATCH 222/890] removed extra encoding of public key
---
.../org/bouncycastle/pqc/crypto/util/PrivateKeyInfoFactory.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/util/PrivateKeyInfoFactory.java b/core/src/main/java/org/bouncycastle/pqc/crypto/util/PrivateKeyInfoFactory.java
index 9b3aaff843..eb43ac859c 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/util/PrivateKeyInfoFactory.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/util/PrivateKeyInfoFactory.java
@@ -152,7 +152,7 @@ else if (privateKey instanceof SLHDSAPrivateKeyParameters)
AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(Utils.slhdsaOidLookup(params.getParameters()));
- return new PrivateKeyInfo(algorithmIdentifier, params.getEncoded(), attributes, params.getPublicKey());
+ return new PrivateKeyInfo(algorithmIdentifier, params.getEncoded(), attributes);
}
else if (privateKey instanceof PicnicPrivateKeyParameters)
{
From 4361cd76b1599e53fa885d24102c8aabba0d33d4 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Sun, 16 Mar 2025 17:30:12 +1030
Subject: [PATCH 223/890] Refactor ProcessByte
---
.../crypto/engines/AEADBaseEngine.java | 117 ++++++++++++++++--
.../bouncycastle/crypto/test/CipherTest.java | 18 ++-
.../crypto/test/Grain128AEADTest.java | 2 +-
3 files changed, 123 insertions(+), 14 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBaseEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/AEADBaseEngine.java
index c251408f48..09b8382124 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBaseEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/AEADBaseEngine.java
@@ -91,11 +91,7 @@ public byte[] getMac()
return mac;
}
- public void reset()
- {
- reset(true);
- }
-
+ @Override
public void init(boolean forEncryption, CipherParameters params)
{
this.forEncryption = forEncryption;
@@ -155,6 +151,12 @@ else if (params instanceof ParametersWithIV)
}
}
+ @Override
+ public void reset()
+ {
+ reset(true);
+ }
+
protected void reset(boolean clearMac)
{
ensureInitialized();
@@ -246,10 +248,12 @@ protected void setInnerMembers(ProcessingBufferType type, AADOperatorType aadOpe
}
}
- protected interface AADProcessingBuffer
+ private interface AADProcessingBuffer
{
void processAADByte(byte input);
+ int processByte(byte input, byte[] output, int outOff);
+
int getUpdateOutputSize(int len);
boolean isLengthWithinAvailableSpace(int len, int available);
@@ -270,6 +274,15 @@ public void processAADByte(byte input)
m_aad[m_aadPos++] = input;
}
+ @Override
+ public int processByte(byte input, byte[] output, int outOff)
+ {
+ checkData(false);
+ int rlt = processEncDecByte(output, outOff);
+ m_buf[m_bufPos++] = input;
+ return rlt;
+ }
+
@Override
public boolean isLengthWithinAvailableSpace(int len, int available)
{
@@ -303,6 +316,14 @@ public void processAADByte(byte input)
}
}
+ @Override
+ public int processByte(byte input, byte[] output, int outOff)
+ {
+ checkData(false);
+ m_buf[m_bufPos++] = input;
+ return processEncDecByte(output, outOff);
+ }
+
@Override
public int getUpdateOutputSize(int len)
{
@@ -333,7 +354,7 @@ protected interface AADOperator
int getLen();
}
- protected class DefaultAADOperator
+ private class DefaultAADOperator
implements AADOperator
{
@Override
@@ -359,7 +380,7 @@ public int getLen()
}
}
- protected class CounterAADOperator
+ private class CounterAADOperator
implements AADOperator
{
private int aadLen;
@@ -426,6 +447,8 @@ public int getLen()
protected interface DataOperator
{
+ int processByte(byte input, byte[] output, int outOff);
+
int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff);
int getLen();
@@ -433,9 +456,14 @@ protected interface DataOperator
void reset();
}
- protected class DefaultDataOperator
+ private class DefaultDataOperator
implements DataOperator
{
+ public int processByte(byte input, byte[] output, int outOff)
+ {
+ return processor.processByte(input, output, outOff);
+ }
+
public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
{
return processEncDecBytes(input, inOff, len, output, outOff);
@@ -453,11 +481,17 @@ public void reset()
}
}
- protected class CounterDataOperator
+ private class CounterDataOperator
implements DataOperator
{
private int messegeLen;
+ public int processByte(byte input, byte[] output, int outOff)
+ {
+ messegeLen++;
+ return processor.processByte(input, output, outOff);
+ }
+
public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
{
messegeLen += len;
@@ -482,6 +516,14 @@ protected class StreamDataOperator
{
private final ErasableOutputStream stream = new ErasableOutputStream();
+ public int processByte(byte input, byte[] output, int outOff)
+ {
+ ensureInitialized();
+ stream.write(input);
+ m_bufPos = stream.size();
+ return 0;
+ }
+
@Override
public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
{
@@ -509,11 +551,39 @@ public void reset()
}
}
- protected class StreamCipherOperator
+ private class StreamCipherOperator
implements DataOperator
{
+ //TODO: shift index instead of arraycopy
private int len;
+ public int processByte(byte input, byte[] output, int outOff)
+ {
+ boolean forEncryption = checkData(false);
+ if (forEncryption)
+ {
+ this.len = 1;
+ processBufferEncrypt(new byte[]{input}, 0, output, outOff);
+ return 1;
+ }
+ else
+ {
+ if (m_bufPos == MAC_SIZE)
+ {
+ this.len = 1;
+ processBufferDecrypt(m_buf, 0, output, outOff);
+ System.arraycopy(m_buf, 1, m_buf, 0, m_bufPos - 1);
+ m_buf[m_bufPos - 1] = input;
+ return 1;
+ }
+ else
+ {
+ m_buf[m_bufPos++] = input;
+ return 0;
+ }
+ }
+ }
+
@Override
public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
{
@@ -614,10 +684,33 @@ private void processAadBytes(byte[] input, int inOff, int len)
m_aadPos = len;
}
+ @Override
public int processByte(byte in, byte[] out, int outOff)
throws DataLengthException
{
- return processBytes(new byte[]{in}, 0, 1, out, outOff);
+ return dataOperator.processByte(in, out, outOff);
+ }
+
+ protected int processEncDecByte(byte[] output, int outOff)
+ {
+ int rlt = 0;
+ int available = (forEncryption ? BlockSize : m_bufferSizeDecrypt) - m_bufPos;
+ if (available == 0)
+ {
+ ensureSufficientOutputBuffer(output, outOff, BlockSize);
+ if (forEncryption)
+ {
+ processBufferEncrypt(m_buf, 0, output, outOff);
+ }
+ else
+ {
+ processBufferDecrypt(m_buf, 0, output, outOff);
+ System.arraycopy(m_buf, BlockSize, m_buf, 0, m_bufPos - BlockSize);
+ }
+ m_bufPos -= BlockSize;
+ rlt = BlockSize;
+ }
+ return rlt;
}
@Override
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/CipherTest.java b/core/src/test/java/org/bouncycastle/crypto/test/CipherTest.java
index 26bbd069d7..e88201d44e 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/CipherTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/CipherTest.java
@@ -331,7 +331,11 @@ static void checkAEADParemeter(SimpleTest test, int keySize, int ivSize, final i
{
cipher.processAADByte(aad[i]);
}
- int len = cipher.processBytes(plaintext, 0, plaintext.length, ciphertext1, 0);
+ int len = 0;
+ for (int i = 0; i < plaintext.length; ++i)
+ {
+ len += cipher.processByte(plaintext[i], ciphertext1, len);
+ }
len += cipher.doFinal(ciphertext1, len);
int aadSplit = random.nextInt(aad.length) + 1;
cipher.init(true, new AEADParameters(new KeyParameter(key), macSize * 8, iv, Arrays.copyOf(aad, aadSplit)));
@@ -345,6 +349,18 @@ static void checkAEADParemeter(SimpleTest test, int keySize, int ivSize, final i
len = cipher.processBytes(plaintext, 0, plaintext.length, ciphertext3, 0);
len += cipher.doFinal(ciphertext3, len);
test.isTrue("cipher text check", Arrays.areEqual(ciphertext1, ciphertext2));
+ cipher.init(false, new ParametersWithIV(new KeyParameter(key), iv));
+ for (int i = 0; i < aad.length; ++i)
+ {
+ cipher.processAADByte(aad[i]);
+ }
+ len = 0;
+ byte[] plaintext1 = new byte[plaintext.length];
+ for (int i = 0; i < ciphertext1.length; ++i)
+ {
+ len += cipher.processByte(ciphertext1[i], plaintext1, len);
+ }
+ len += cipher.doFinal(plaintext1, len);
test.testException("Invalid value for MAC size: ", "IllegalArgumentException", new TestExceptionOperation()
{
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java b/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java
index 7f1f291db9..bc753137bc 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java
@@ -37,7 +37,7 @@ public AEADCipher createInstance()
CipherTest.checkAEADCipherMultipleBlocks(this, 1024, 7, 100, 128, 12, new Grain128AEADEngine());
- CipherTest.checkAEADParemeter(this, 16, 12, 8, 16, new Grain128AEADEngine());
+ CipherTest.checkAEADParemeter(this, 16, 12, 8, 20, new Grain128AEADEngine());
testSplitUpdate();
testExceptions();
testLongAEAD();
From b8e6d33cb941bbc35db1ac59749625bfdd3622fc Mon Sep 17 00:00:00 2001
From: gefeili
Date: Sun, 16 Mar 2025 19:18:20 +1030
Subject: [PATCH 224/890] refactor for ElephantEngine.rol8 and rotl
---
.../org/bouncycastle/crypto/engines/ElephantEngine.java | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/ElephantEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/ElephantEngine.java
index c85aaa9ac5..aa2488bdd9 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/ElephantEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/ElephantEngine.java
@@ -258,9 +258,11 @@ private void KeccakP200Round(byte[] state, int indexRound)
state[0] ^= KeccakRoundConstants[indexRound];//index(0,0)
}
+ //TODO: search for " >>> (8 - " merge with with CamelliaLightEngine.lRot8,
+ // code in OCBBlockCipher.init, DualECSP800DRBG.pad8,
private byte ROL8(byte a, int offset)
{
- return (byte)(((a & 0xff) << offset) | ((a & 0xff) >> (8 - offset)));
+ return (byte)((a << offset) | ((a & 0xff) >>> (8 - offset)));
}
private int index(int x, int y)
@@ -271,7 +273,7 @@ private int index(int x, int y)
private byte rotl(byte b)
{
- return (byte)(((b & 0xFF) << 1) | ((b & 0xFF) >>> 7));
+ return (byte)((b << 1) | ((b & 0xFF) >>> 7));
}
// State should be BLOCK_SIZE bytes long
From 7f0c8f6d04167951147c550957576c98ae9080df Mon Sep 17 00:00:00 2001
From: gefeili
Date: Mon, 17 Mar 2025 17:24:21 +1030
Subject: [PATCH 225/890] TODO: fix the bugs for packing sk of Snova.
---
.../pqc/crypto/snova/GF16Utils.java | 40 +++++
.../pqc/crypto/snova/MapGroup1.java | 42 ++++-
.../bouncycastle/pqc/crypto/snova/SKGF16.java | 36 ----
.../pqc/crypto/snova/SnovaEngine.java | 21 ++-
.../pqc/crypto/snova/SnovaKeyElements.java | 45 ++++-
.../crypto/snova/SnovaKeyPairGenerator.java | 157 ++----------------
.../pqc/crypto/snova/SnovaParameters.java | 15 +-
7 files changed, 163 insertions(+), 193 deletions(-)
delete mode 100644 core/src/main/java/org/bouncycastle/pqc/crypto/snova/SKGF16.java
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/GF16Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/GF16Utils.java
index 75414b2152..0469a25989 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/GF16Utils.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/GF16Utils.java
@@ -81,6 +81,46 @@ public static void decode(byte[] m, int mOff, byte[] mdec, int decIndex, int mde
}
}
+ /**
+ * Convert two GF16 values to one byte.
+ *
+ * @param m the input array of 4-bit values (stored as bytes, only lower 4 bits used)
+ * @param menc the output byte array that will hold the encoded bytes
+ * @param mlen the number of nibbles in the input array
+ */
+ public static void encode(byte[] m, byte[] menc, int outOff, int mlen)
+ {
+ int i, srcIndex = 0;
+ // Process pairs of 4-bit values
+ for (i = 0; i < mlen / 2; i++)
+ {
+ int lowerNibble = m[srcIndex] & 0x0F;
+ int upperNibble = (m[srcIndex + 1] & 0x0F) << 4;
+ menc[outOff++] = (byte)(lowerNibble | upperNibble);
+ srcIndex += 2;
+ }
+ // If there is an extra nibble (odd number of nibbles), store it directly in lower 4 bits.
+ if ((mlen & 1) == 1)
+ {
+ menc[outOff] = (byte)(m[srcIndex] & 0x0F);
+ }
+ }
+
+ public static void encodeMergeInHalf(byte[] m, int mlen, byte[] menc)
+ {
+ int i, half = (mlen + 1) >>> 1;
+ // Process pairs of 4-bit values
+ for (i = 0; i < mlen / 2; i++, half++)
+ {
+ menc[i] = (byte)(m[i] | (m[half] << 4));
+ }
+ // If there is an extra nibble (odd number of nibbles), store it directly in lower 4 bits.
+ if ((mlen & 1) == 1)
+ {
+ menc[i] = (byte)m[i];
+ }
+ }
+
/**
* Decodes a nibble-packed byte array into an output array.
*
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup1.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup1.java
index 552cdfeed7..19b567b650 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup1.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup1.java
@@ -38,7 +38,19 @@ public int decode(byte[] input, int len)
return inOff;
}
- private int decodeP(byte[] input, int inOff, byte[][][][] p, int len)
+// public int encode(byte[] output, int len)
+// {
+// int outOff = encodeP(p11, output, 0, len);
+// outOff += encodeP(p12, output, outOff, len - outOff);
+// outOff += encodeP(p21, output, outOff, len - outOff);
+// outOff += encodeAlpha(aAlpha, output, outOff, len - outOff);
+// outOff += encodeAlpha(bAlpha, output, outOff, len - outOff);
+// outOff += encodeAlpha(qAlpha1, output, outOff, len - outOff);
+// outOff += encodeAlpha(qAlpha2, output, outOff, len - outOff);
+// return outOff;
+// }
+
+ static int decodeP(byte[] input, int inOff, byte[][][][] p, int len)
{
int rlt = 0;
for (int i = 0; i < p.length; ++i)
@@ -48,7 +60,7 @@ private int decodeP(byte[] input, int inOff, byte[][][][] p, int len)
return rlt;
}
- private int decodeAlpha(byte[] input, int inOff, byte[][][] alpha, int len)
+ private static int decodeAlpha(byte[] input, int inOff, byte[][][] alpha, int len)
{
int rlt = 0;
for (int i = 0; i < alpha.length; ++i)
@@ -64,4 +76,30 @@ private int decodeAlpha(byte[] input, int inOff, byte[][][] alpha, int len)
return rlt;
}
+ static int encodeP(byte[][][][] p, byte[] output, int outOff, int len)
+ {
+ int rlt = 0;
+ for (int i = 0; i < p.length; ++i)
+ {
+ rlt += encodeAlpha(p[i], output, outOff + rlt, len);
+ }
+ return rlt;
+ }
+
+ static int encodeAlpha(byte[][][] alpha, byte[] output, int outOff, int len)
+ {
+ int rlt = 0;
+ for (int i = 0; i < alpha.length; ++i)
+ {
+ for (int j = 0; j < alpha[i].length; ++j)
+ {
+ int tmp = Math.min(alpha[i][j].length, len << 1);
+ GF16Utils.encode(alpha[i][j], output, outOff + rlt, tmp);
+ rlt += (tmp + 1) >> 1;
+ len -= (tmp + 1) >> 1;
+ }
+ }
+ return rlt;
+ }
+
}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SKGF16.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SKGF16.java
deleted file mode 100644
index fe25ffefb6..0000000000
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SKGF16.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package org.bouncycastle.pqc.crypto.snova;
-
-class SKGF16
-{
- public final GF16Matrix[][] Aalpha; // [m][alpha]
- public final GF16Matrix[][] Balpha; // [m][alpha]
- public final GF16Matrix[][] Qalpha1; // [m][alpha]
- public final GF16Matrix[][] Qalpha2; // [m][alpha]
- public final GF16Matrix[][] T12; // [v][o]
- public final GF16Matrix[][][] F11; // [m][v][v]
- public final GF16Matrix[][][] F12; // [m][v][o]
- public final GF16Matrix[][][] F21; // [m][o][v]
- public final byte[] publicKeySeed;
- public final byte[] privateKeySeed;
-
- public SKGF16(SnovaParameters params)
- {
- int m = params.getM();
- int v = params.getV();
- int o = params.getO();
- int alpha = params.getAlpha();
- int rank = params.getL();
-
- Aalpha = GF16Utils.create2DArray(m, alpha, rank);
- Balpha = GF16Utils.create2DArray(m, alpha, rank);
- Qalpha1 = GF16Utils.create2DArray(m, alpha, rank);
- Qalpha2 = GF16Utils.create2DArray(m, alpha, rank);
- T12 = GF16Utils.create2DArray(v, o, rank);
- F11 = GF16Utils.create3DArray(m, v, v, rank);
- F12 = GF16Utils.create3DArray(m, v, o, rank);
- F21 = GF16Utils.create3DArray(m, o, v, rank);
-
- publicKeySeed = new byte[SnovaKeyPairGenerator.publicSeedLength];
- privateKeySeed = new byte[SnovaKeyPairGenerator.privateSeedLength];
- }
-}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java
index e68138385e..f68d399630 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java
@@ -356,8 +356,8 @@ public void genF(MapGroup2 map2, MapGroup1 map1, byte[][][] T12)
{
for (int index = 0; index < v; index++)
{
- GF16Utils.gf16mMul(temp, map1.p11[i][j][index], T12[index][k], l);
- GF16Utils.gf16mAdd(map2.f12[i][j][k], map2.f12[i][j][k], temp, l);
+ GF16Utils.gf16mMul(map1.p11[i][j][index], T12[index][k], temp, l);
+ GF16Utils.gf16mAdd(map2.f12[i][j][k], temp, map2.f12[i][j][k], l);
}
}
}
@@ -372,8 +372,8 @@ public void genF(MapGroup2 map2, MapGroup1 map1, byte[][][] T12)
{
for (int index = 0; index < v; index++)
{
- GF16Utils.gf16mMul(temp, T12[index][j], map1.p11[i][index][k], l);
- GF16Utils.gf16mAdd(map2.f21[i][j][k], map2.f21[i][j][k], temp, l);
+ GF16Utils.gf16mMul(T12[index][j], map1.p11[i][index][k], temp, l);
+ GF16Utils.gf16mAdd(map2.f21[i][j][k], temp, map2.f21[i][j][k], l);
}
}
}
@@ -402,7 +402,7 @@ private static void copy4DMatrix(byte[][][][] src, byte[][][][] dest,
}
}
- public void genP22(byte[] outP22, byte[][][] T12, byte[][][][] P21, byte[][][][] F12, SnovaParameters params)
+ public void genP22(byte[] outP22, byte[][][] T12, byte[][][][] P21, byte[][][][] F12)
{
int m = params.getM();
int o = params.getO();
@@ -428,24 +428,23 @@ public void genP22(byte[] outP22, byte[][][] T12, byte[][][][] P21, byte[][][][]
for (int index = 0; index < v; index++)
{
// temp1 = T12[index][j] * F12[i][index][k]
- GF16Utils.gf16mMul(temp1, T12[index][j], F12[i][index][k], l);
+ GF16Utils.gf16mMul(T12[index][j], F12[i][index][k], temp1, l);
// temp2 = P21[i][j][index] * T12[index][k]
- GF16Utils.gf16mMul(temp2, P21[i][j][index], T12[index][k], l);
+ GF16Utils.gf16mMul(P21[i][j][index], T12[index][k], temp2, l);
// temp1 += temp2
- GF16Utils.gf16mAdd(temp1, temp1, temp2, l);
+ GF16Utils.gf16mAdd(temp1, temp2, temp1, l);
// P22[i][j][k] += temp1
- GF16Utils.gf16mAdd(P22[i][j][k], P22[i][j][k], temp1, l);
+ GF16Utils.gf16mAdd(P22[i][j][k], temp1, P22[i][j][k], l);
}
}
}
}
// Convert GF16 elements to packed bytes
- //TODO
- //GF16Utils.decode(P22, outP22, m * o * o *lsq);
+ MapGroup1.encodeP(P22, outP22, 0, m * o * o *lsq);
}
finally
{
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyElements.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyElements.java
index 1c1d7ea3ea..026677ab92 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyElements.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyElements.java
@@ -6,12 +6,55 @@ class SnovaKeyElements
public final byte[][][] T12; // [v][o]
public final MapGroup2 map2;
public final PublicKey publicKey;
+ private int length;
public SnovaKeyElements(SnovaParameters params)
{
+ int o = params.getO();
+ int l = params.getL();
+ int v = params.getV();
+ int lsq = l * l;
map1 = new MapGroup1(params);
- T12 = new byte[params.getV()][params.getO()][16];
+ T12 = new byte[v][o][lsq];
map2 = new MapGroup2(params);
publicKey = new PublicKey(params);
+ length = o * params.getAlpha() * lsq * 4 + v * o * lsq + (o * v * v + o * v * o + o * o * v) * lsq;
+ }
+
+ public void encodeMergerInHalf(byte[] output)
+ {
+ byte[] input = new byte[length];
+ int inOff = 0;
+ inOff = copy3d(map1.aAlpha, input, inOff);
+ inOff = copy3d(map1.bAlpha, input, inOff);
+ inOff = copy3d(map1.qAlpha1, input, inOff);
+ inOff = copy3d(map1.qAlpha2, input, inOff);
+ inOff = copy3d(T12, input, inOff);
+ inOff = copy4d(map2.f11, input, inOff);
+ inOff = copy4d(map2.f12, input, inOff);
+ inOff = copy4d(map2.f21, input, inOff);
+ GF16Utils.encodeMergeInHalf(input, length, output);
+ }
+
+ public int copy3d(byte[][][] alpha, byte[] output, int outOff)
+ {
+ for (int i = 0; i < alpha.length; ++i)
+ {
+ for (int j = 0; j < alpha[i].length; ++j)
+ {
+ System.arraycopy(alpha[i][j], 0, output, outOff, alpha[i][j].length);
+ outOff += alpha[i][j].length;
+ }
+ }
+ return outOff;
+ }
+
+ public int copy4d(byte[][][][] alpha, byte[] output, int outOff)
+ {
+ for (int i = 0; i < alpha.length; ++i)
+ {
+ outOff = copy3d(alpha[i], output, outOff);
+ }
+ return outOff;
}
}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyPairGenerator.java
index 8450c2b41d..b84a9f2f9a 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyPairGenerator.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyPairGenerator.java
@@ -1,6 +1,5 @@
package org.bouncycastle.pqc.crypto.snova;
-import java.io.ByteArrayOutputStream;
import java.security.SecureRandom;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
@@ -48,19 +47,29 @@ public AsymmetricCipherKeyPair generateKeyPair()
byte[] seedPair = new byte[seedLength];
random.nextBytes(seedPair);
- byte[] pk = new byte[publicSeedLength];
- byte[] sk = new byte[privateSeedLength];
+ byte[] pk = new byte[params.getPublicKeyLength()];
+ byte[] sk = new byte[params.getPrivateKeyLength()];
byte[] ptPublicKeySeed = Arrays.copyOfRange(seedPair, 0, publicSeedLength);
byte[] ptPrivateKeySeed = Arrays.copyOfRange(seedPair, publicSeedLength, seedPair.length);
+// System.arraycopy(ptPublicKeySeed, 0, sk, 0, ptPublicKeySeed.length);
+// System.arraycopy(ptPrivateKeySeed, 0, sk, ptPublicKeySeed.length, ptPrivateKeySeed.length);
+ SnovaKeyElements keyElements = new SnovaKeyElements(params);
+ generateKeysCore(keyElements, ptPublicKeySeed, ptPrivateKeySeed);
+
+ // Pack public key components
+ System.arraycopy(ptPublicKeySeed, 0, pk, 0, ptPublicKeySeed.length);
+ System.arraycopy(keyElements.publicKey.P22, 0, pk, ptPublicKeySeed.length, keyElements.publicKey.P22.length);
+
if (params.isSkIsSeed())
{
- generateKeysSSK(pk, sk, ptPublicKeySeed, ptPrivateKeySeed);
+ sk = seedPair;
}
else
{
- generateKeysESK(pk, sk, ptPublicKeySeed, ptPrivateKeySeed);
+ keyElements.encodeMergerInHalf(sk);
+ System.arraycopy(seedPair, 0, sk, sk.length - seedLength, seedLength);
}
return new AsymmetricCipherKeyPair(
@@ -69,96 +78,6 @@ public AsymmetricCipherKeyPair generateKeyPair()
);
}
- private void generateKeysSSK(byte[] pk, byte[] sk, byte[] ptPublicKeySeed, byte[] ptPrivateKeySeed)
- {
- // Implementation based on C's generate_keys_ssk
- System.arraycopy(ptPublicKeySeed, 0, sk, 0, ptPublicKeySeed.length);
- System.arraycopy(ptPrivateKeySeed, 0, sk, ptPublicKeySeed.length, ptPrivateKeySeed.length);
-
- // Actual key generation would go here using BC's SHAKE/AES implementations
- // This would include the matrix operations from the C code
- generatePublicKey(pk, ptPublicKeySeed, ptPrivateKeySeed);
- }
-
- private void generateKeysESK(byte[] pk, byte[] esk, byte[] ptPublicKeySeed, byte[] ptPrivateKeySeed)
- {
- // Implementation based on C's generate_keys_esk
- // Actual expanded key generation would go here
- generatePublicKey(pk, ptPublicKeySeed, ptPrivateKeySeed);
- packPrivateKey(esk, ptPublicKeySeed, ptPrivateKeySeed);
- }
-
- private void packPrivateKey(byte[] esk, byte[] ptPublicKeySeed, byte[] ptPrivateKeySeed)
- {
- SnovaKeyElements keyElements = new SnovaKeyElements(params);
- generateKeysCore(keyElements, ptPublicKeySeed, ptPrivateKeySeed);
-
- // Serialize all components
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
-
- // Serialize map components
-// serializeMatrixGroup(bos, keyElements.map1.Aalpha);
-// serializeMatrixGroup(bos, keyElements.map1.Balpha);
-// serializeMatrixGroup(bos, keyElements.map1.Qalpha1);
-// serializeMatrixGroup(bos, keyElements.map1.Qalpha2);
-
- // Serialize T12
-// for (GF16Matrix[] row : keyElements.T12)
-// {
-// for (GF16Matrix matrix : row)
-// {
-// serializeMatrix(bos, matrix);
-// }
-// }
-
- // Add public and private seeds
- bos.write(ptPublicKeySeed, 0, ptPublicKeySeed.length);
- bos.write(ptPrivateKeySeed, 0, ptPrivateKeySeed.length);
-
- System.arraycopy(bos.toByteArray(), 0, esk, 0, esk.length);
- }
-
- private void serializeMatrixGroup(ByteArrayOutputStream bos, GF16Matrix[][][] group)
- {
- for (GF16Matrix[][] dim1 : group)
- {
- for (GF16Matrix[] dim2 : dim1)
- {
- for (GF16Matrix matrix : dim2)
- {
- serializeMatrix(bos, matrix);
- }
- }
- }
- }
-
- private void serializeMatrix(ByteArrayOutputStream bos, GF16Matrix matrix)
- {
-// byte[] temp = new byte[(matrix.size * matrix.size + 1) / 2];
-// byte[] gf16s = new byte[matrix.size * matrix.size];
-//
-// int idx = 0;
-// for (int i = 0; i < matrix.size; i++) {
-// for (int j = 0; j < matrix.size; j++) {
-// gf16s[idx++] = matrix.get(i, j);
-// }
-// }
-//
-// GF16Utils.convertGF16sToBytes(temp, gf16s, gf16s.length);
-// bos.write(temp, 0, temp.length);
- }
-
- private void generatePublicKey(byte[] pk, byte[] ptPublicKeySeed, byte[] ptPrivateKeySeed)
- {
-
- // Generate key elements
- SnovaKeyElements keyElements = new SnovaKeyElements(params);
- generateKeysCore(keyElements, ptPublicKeySeed, ptPrivateKeySeed);
-
- // Pack public key components
- //packPublicKey(pk, keyElements);
- }
-
private void generateKeysCore(SnovaKeyElements keyElements, byte[] pkSeed, byte[] skSeed)
{
// Generate T12 matrix
@@ -171,7 +90,7 @@ private void generateKeysCore(SnovaKeyElements keyElements, byte[] pkSeed, byte[
engine.genF(keyElements.map2, keyElements.map1, keyElements.T12);
// Generate P22 matrix
-// genP22(keyElements.pk.P22, keyElements.T12, keyElements.map1.P21, keyElements.map2.F12);
+ engine.genP22(keyElements.publicKey.P22, keyElements.T12, keyElements.map1.p21, keyElements.map2.f12);
}
private void genSeedsAndT12(byte[][][] T12, byte[] skSeed)
@@ -294,50 +213,4 @@ private void genABQP(MapGroup1 map1, byte[] pkSeed)
}
}
}
-
-
-// private void genF(MapGroup2 map2, MapGroup1 map1, GF16Matrix[][] T12)
-// {
-// // Matrix operations from C code's gen_F_ref
-// // Clone initial matrices
-// System.arraycopy(map1.P11, 0, map2.F11, 0, map1.P11.length);
-// System.arraycopy(map1.P12, 0, map2.F12, 0, map1.P12.length);
-// System.arraycopy(map1.P21, 0, map2.F21, 0, map1.P21.length);
-//
-// // Perform matrix multiplications and additions
-// GF16Matrix temp = new GF16Matrix(params.getL());
-// for (int i = 0; i < params.getM(); i++) {
-// for (int j = 0; j < params.getV(); j++) {
-// for (int k = 0; k < params.getO(); k++) {
-// for (int idx = 0; idx < params.getV(); idx++) {
-// GF16Matrix.mul(map1.P11[i][j][idx], T12[idx][k], temp);
-// GF16Matrix.add(map2.F12[i][j][k], temp, map2.F12[i][j][k]);
-// }
-// }
-// }
-// }
-// }
-
- private void genP22(byte[] outP22, GF16Matrix[][] T12, GF16Matrix[][][] P21, GF16Matrix[][][] F12)
- {
-// GF16Matrix[][][] P22 = new GF16Matrix[params.getM()][params.getO()][params.getO()];
-// GF16Matrix temp1 = new GF16Matrix(params.getL());
-// GF16Matrix temp2 = new GF16Matrix(params.getL());
-//
-// for (int i = 0; i < params.getM(); i++) {
-// for (int j = 0; j < params.getO(); j++) {
-// for (int k = 0; k < params.getO(); k++) {
-// for (int idx = 0; idx < params.getV(); idx++) {
-// GF16Matrix.mul(T12[idx][j], F12[i][idx][k], temp1);
-// GF16Matrix.mul(P21[i][j][idx], T12[idx][k], temp2);
-// GF16Matrix.add(temp1, temp2, temp1);
-// GF16Matrix.add(P22[i][j][k], temp1, P22[i][j][k]);
-// }
-// }
-// }
-// }
-//
-// // Convert GF16 matrices to bytes
-// GF16Utils.convertGF16sToBytes(P22, outP22);
- }
}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaParameters.java
index 90436bab3c..b6b0cc0027 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaParameters.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaParameters.java
@@ -111,6 +111,7 @@ public class SnovaParameters
private final int v;
private final int o;
private final int l;
+ private final int alpha;
private final boolean skIsSeed;
private final boolean pkExpandShake;
@@ -120,6 +121,7 @@ public SnovaParameters(String name, int v, int o, int l, boolean skIsSeed, boole
this.v = v;
this.o = o;
this.l = l;
+ this.alpha = l * l + l;
this.skIsSeed = skIsSeed;
this.pkExpandShake = pkExpandShake;
}
@@ -162,6 +164,17 @@ public int getM()
public int getAlpha()
{
- return l * l + l;
+ return alpha;
+ }
+
+ public int getPublicKeyLength()
+ {
+ return SnovaKeyPairGenerator.publicSeedLength + ((o * o * o * l * l + 1) >>> 1);
+ }
+
+ public int getPrivateKeyLength()
+ {
+ return ((l * l * (4 * o * alpha + o * (v * v + v * o + o * v) + v * o) + 1) >> 1)
+ + SnovaKeyPairGenerator.privateSeedLength + SnovaKeyPairGenerator.publicSeedLength;
}
}
From e424fa5dad0269bbe4fd2ef93fa2f6d3492813e3 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Tue, 18 Mar 2025 13:31:29 +1100
Subject: [PATCH 226/890] corrected table inclusion - relates to github #2027
---
.../jcajce/provider/util/SecretKeyUtil.java | 7 ++++--
.../jcajce/provider/test/AllTests.java | 1 +
.../jcajce/provider/test/RandomTest.java | 5 ++--
.../provider/test/SecretKeyUtilTest.java | 24 +++++++++++++++++++
4 files changed, 32 insertions(+), 5 deletions(-)
create mode 100644 prov/src/test/java/org/bouncycastle/jcajce/provider/test/SecretKeyUtilTest.java
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/util/SecretKeyUtil.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/util/SecretKeyUtil.java
index 686d6b8461..42c601a4bb 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/util/SecretKeyUtil.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/util/SecretKeyUtil.java
@@ -9,13 +9,16 @@
import org.bouncycastle.internal.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.util.Integers;
+/**
+ * @deprecated class appears to be no longer in use, maybe getting imported by others though.
+ */
public class SecretKeyUtil
{
- private static Map keySizes = new HashMap();
+ private static Map keySizes = new HashMap();
static
{
- keySizes.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), Integers.valueOf(192));
+ keySizes.put(PKCSObjectIdentifiers.des_EDE3_CBC, Integers.valueOf(192));
keySizes.put(NISTObjectIdentifiers.id_aes128_CBC, Integers.valueOf(128));
keySizes.put(NISTObjectIdentifiers.id_aes192_CBC, Integers.valueOf(192));
diff --git a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/AllTests.java b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/AllTests.java
index 295182830e..b14545d2f2 100644
--- a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/AllTests.java
+++ b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/AllTests.java
@@ -33,6 +33,7 @@ public static Test suite()
suite.addTestSuite(CompositeSignaturesTest.class);
suite.addTestSuite(BouncyCastleProviderTest.class);
suite.addTestSuite(PQCSignatureTest.class);
+ suite.addTestSuite(SecretKeyUtilTest.class);
return new BCTestSetup(suite);
}
diff --git a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/RandomTest.java b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/RandomTest.java
index 5804c43f6d..0b4f11fec4 100644
--- a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/RandomTest.java
+++ b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/RandomTest.java
@@ -2,7 +2,6 @@
import java.security.SecureRandom;
-import junit.framework.Assert;
import junit.framework.TestCase;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
@@ -18,7 +17,7 @@ public void testCheckRandom()
random.nextBytes(rng);
- Assert.assertTrue(checkNonConstant(rng));
+ assertTrue(checkNonConstant(rng));
}
public void testCheckNonceIVRandom()
@@ -30,7 +29,7 @@ public void testCheckNonceIVRandom()
random.nextBytes(rng);
- Assert.assertTrue(checkNonConstant(rng));
+ assertTrue(checkNonConstant(rng));
}
private boolean checkNonConstant(byte[] data)
diff --git a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/SecretKeyUtilTest.java b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/SecretKeyUtilTest.java
new file mode 100644
index 0000000000..a545cdea09
--- /dev/null
+++ b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/SecretKeyUtilTest.java
@@ -0,0 +1,24 @@
+package org.bouncycastle.jcajce.provider.test;
+
+import junit.framework.TestCase;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.internal.asn1.ntt.NTTObjectIdentifiers;
+import org.bouncycastle.jcajce.provider.util.SecretKeyUtil;
+
+public class SecretKeyUtilTest
+ extends TestCase
+{
+ public void testgetKeySize()
+ {
+ assertEquals(192, SecretKeyUtil.getKeySize(PKCSObjectIdentifiers.des_EDE3_CBC));
+
+ assertEquals(128, SecretKeyUtil.getKeySize(NISTObjectIdentifiers.id_aes128_CBC));
+ assertEquals(192, SecretKeyUtil.getKeySize(NISTObjectIdentifiers.id_aes192_CBC));
+ assertEquals(256, SecretKeyUtil.getKeySize(NISTObjectIdentifiers.id_aes256_CBC));
+
+ assertEquals(128, SecretKeyUtil.getKeySize(NTTObjectIdentifiers.id_camellia128_cbc));
+ assertEquals(192, SecretKeyUtil.getKeySize(NTTObjectIdentifiers.id_camellia192_cbc));
+ assertEquals(256, SecretKeyUtil.getKeySize(NTTObjectIdentifiers.id_camellia256_cbc));
+ }
+}
From 05f25fb52c848c72ddd40c753ae4bbd8291d6010 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Tue, 18 Mar 2025 13:34:57 +1100
Subject: [PATCH 227/890] update
---
CONTRIBUTORS.html | 2 ++
1 file changed, 2 insertions(+)
diff --git a/CONTRIBUTORS.html b/CONTRIBUTORS.html
index 77652932e5..5224952758 100644
--- a/CONTRIBUTORS.html
+++ b/CONTRIBUTORS.html
@@ -557,6 +557,8 @@
moonfruit <https://github.com/moonfruit> - Patch to allow for extensions of GMSignatureSpi.
Marcono1234 <https://github.com/Marcono1234> - Updates to OpenBSDBCrypt JavaDoc.
DawidM <https://github.com/dawmit> - Implementation of EC J-PAKE.
+Syed Quasim <https://github.com/HawkItzme> - lint checker fix for EST getTrustAllTrustManager().
+winfriedgerlach <https://github.com/winfriedgerlach> - patch to SecretKeyUtil class.