|
5 | 5 | import org.bouncycastle.crypto.AsymmetricCipherKeyPair; |
6 | 6 | import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; |
7 | 7 | import org.bouncycastle.crypto.KeyGenerationParameters; |
8 | | -import org.bouncycastle.util.Pack; |
| 8 | +import org.bouncycastle.util.Arrays; |
| 9 | +import org.bouncycastle.util.Longs; |
9 | 10 |
|
10 | 11 | public class MayoKeyPairGenerator |
11 | 12 | implements AsymmetricCipherKeyPairGenerator |
12 | 13 | { |
13 | 14 | private MayoParameters p; |
14 | 15 | private SecureRandom random; |
15 | 16 |
|
16 | | - |
17 | 17 | public void init(KeyGenerationParameters param) |
18 | 18 | { |
19 | 19 | this.p = ((MayoKeyGenerationParameters)param).getParameters(); |
20 | 20 | this.random = param.getRandom(); |
21 | 21 | } |
22 | 22 |
|
23 | | - |
24 | 23 | @Override |
25 | 24 | public AsymmetricCipherKeyPair generateKeyPair() |
26 | 25 | { |
27 | | - int ret = MayoEngine.MAYO_OK; |
| 26 | + // Retrieve parameters from p. |
| 27 | + int mVecLimbs = p.getMVecLimbs(); |
| 28 | + int m = p.getM(); |
| 29 | + int v = p.getV(); |
| 30 | + int o = p.getO(); |
| 31 | + int oBytes = p.getOBytes(); |
| 32 | + int p1Limbs = p.getP1Limbs(); |
| 33 | + int p3Limbs = p.getP3Limbs(); |
| 34 | + int pkSeedBytes = p.getPkSeedBytes(); |
| 35 | + int skSeedBytes = p.getSkSeedBytes(); |
| 36 | + |
28 | 37 | byte[] cpk = new byte[p.getCpkBytes()]; |
29 | 38 | // seed_sk points to csk. |
30 | 39 | byte[] seed_sk = new byte[p.getCskBytes()]; |
31 | 40 |
|
32 | 41 | // Allocate S = new byte[PK_SEED_BYTES_MAX + O_BYTES_MAX] |
33 | | - byte[] S = new byte[p.getPkSeedBytes() + p.getOBytes()]; |
| 42 | + byte[] seed_pk = new byte[pkSeedBytes + oBytes]; |
34 | 43 |
|
35 | 44 | // Allocate P as a long array of size (P1_LIMBS_MAX + P2_LIMBS_MAX) |
36 | | - long[] P = new long[p.getP1Limbs() + p.getP2Limbs()]; |
| 45 | + long[] P = new long[p1Limbs + p.getP2Limbs()]; |
37 | 46 |
|
38 | 47 | // Allocate P3 as a long array of size (O_MAX * O_MAX * M_VEC_LIMBS_MAX), zero-initialized. |
39 | | - long[] P3 = new long[p.getO() * p.getO() * p.getMVecLimbs()]; |
40 | | - |
41 | | - // seed_pk will be a reference into S. |
42 | | - byte[] seed_pk; |
| 48 | + long[] P3 = new long[o * o * mVecLimbs]; |
43 | 49 |
|
44 | 50 | // Allocate O as a byte array of size (V_MAX * O_MAX). |
45 | 51 | // Here we assume V_MAX is given by p.getV() (or replace with a constant if needed). |
46 | | - byte[] O = new byte[p.getV() * p.getO()]; |
47 | | - |
48 | | - // Retrieve parameters from p. |
49 | | - int m_vec_limbs = p.getMVecLimbs(); |
50 | | - int param_m = p.getM(); |
51 | | - int param_v = p.getV(); |
52 | | - int param_o = p.getO(); |
53 | | - int param_O_bytes = p.getOBytes(); |
54 | | - int param_P1_limbs = p.getP1Limbs(); |
55 | | - int param_P3_limbs = p.getP3Limbs(); |
56 | | - int param_pk_seed_bytes = p.getPkSeedBytes(); |
57 | | - int param_sk_seed_bytes = p.getSkSeedBytes(); |
58 | | - |
59 | | - // In the C code, P1 is P and P2 is P offset by param_P1_limbs. |
60 | | - // In Java, we will have functions (like expandP1P2) work on the full array P. |
| 52 | + byte[] O = new byte[v * o]; |
61 | 53 |
|
62 | 54 | // Generate secret key seed (seed_sk) using a secure random generator. |
63 | 55 | random.nextBytes(seed_sk); |
64 | 56 |
|
65 | 57 | // S ← shake256(seed_sk, pk_seed_bytes + O_bytes) |
66 | | - Utils.shake256(S, param_pk_seed_bytes + param_O_bytes, seed_sk, param_sk_seed_bytes); |
67 | | - |
68 | | - // seed_pk is the beginning of S. |
69 | | - seed_pk = S; |
| 58 | + Utils.shake256(seed_pk, pkSeedBytes + oBytes, seed_sk, skSeedBytes); |
70 | 59 |
|
71 | 60 | // o ← Decode_o(S[ param_pk_seed_bytes : param_pk_seed_bytes + O_bytes ]) |
72 | 61 | // Decode nibbles from S starting at offset param_pk_seed_bytes into O, |
73 | 62 | // with expected output length = param_v * param_o. |
74 | | - Utils.decode(S, param_pk_seed_bytes, O, param_v * param_o); |
| 63 | + Utils.decode(seed_pk, pkSeedBytes, O, v * o); |
75 | 64 |
|
76 | 65 | // Expand P1 and P2 into the array P using seed_pk. |
77 | 66 | MayoEngine.expandP1P2(p, P, seed_pk); |
78 | 67 |
|
79 | 68 | // For compute_P3, we need to separate P1 and P2. |
80 | 69 | // Here, we treat P1 as the first param_P1_limbs elements of P, |
81 | 70 | // and P2 as the remaining elements. |
82 | | - long[] P1 = P; |
83 | | - long[] P2 = new long[P.length - param_P1_limbs]; |
84 | | - System.arraycopy(P, param_P1_limbs, P2, 0, P2.length); |
85 | | - |
86 | | - // Compute P3, which (in the process) modifies P2. |
87 | | - computeP3(p, P1, P2, O, P3); |
88 | | - |
89 | | - // Store seed_pk into the public key cpk. |
90 | | - System.arraycopy(seed_pk, 0, cpk, 0, param_pk_seed_bytes); |
91 | | - |
92 | | - // Allocate an array for the "upper" part of P3. |
93 | | - long[] P3_upper = new long[p.getP3Limbs()]; |
94 | | - |
95 | | - // Compute Upper(P3) and store the result in P3_upper. |
96 | | - mUpper(p, P3, P3_upper, param_o); |
97 | | - |
98 | | - // Pack the m-vectors in P3_upper into cpk (after the seed_pk). |
99 | | - // The number of m-vectors to pack is (param_P3_limbs / m_vec_limbs), |
100 | | - // and param_m is used as the m value. |
101 | | - Utils.packMVecs(P3_upper, cpk, param_pk_seed_bytes, param_P3_limbs / m_vec_limbs, param_m); |
102 | | - // Securely clear sensitive data. |
103 | | -// secureClear(O); |
104 | | -// secureClear(P2); |
105 | | -// secureClear(P3); |
106 | | - |
107 | | - return new AsymmetricCipherKeyPair(new MayoPublicKeyParameter(p, cpk), new MayoPrivateKeyParameter(p, seed_sk)); |
108 | | - } |
109 | | - |
110 | | - /** |
111 | | - * Computes P3 from P1, P2, and O. |
112 | | - * <p> |
113 | | - * In C, compute_P3 does: |
114 | | - * 1. Compute P1*O + P2, storing result in P2. |
115 | | - * 2. Compute P3 = O^T * (P1*O + P2). |
116 | | - * |
117 | | - * @param p the parameter object. |
118 | | - * @param P1 the P1 matrix as a long[] array. |
119 | | - * @param P2 the P2 matrix as a long[] array; on output, P1*O is added to it. |
120 | | - * @param O the O matrix as a byte[] array. |
121 | | - * @param P3 the output matrix (as a long[] array) which will receive O^T*(P1*O + P2). |
122 | | - */ |
123 | | - public static void computeP3(MayoParameters p, long[] P1, long[] P2, byte[] O, long[] P3) |
124 | | - { |
125 | | - int mVecLimbs = p.getMVecLimbs(); |
126 | | - int paramV = p.getV(); |
127 | | - int paramO = p.getO(); |
| 71 | + long[] P2 = new long[P.length - p1Limbs]; |
| 72 | + System.arraycopy(P, p1Limbs, P2, 0, P2.length); |
128 | 73 |
|
129 | 74 | // Compute P1 * O + P2 and store the result in P2. |
130 | | - GF16Utils.P1TimesO(p, P1, O, P2); |
| 75 | + GF16Utils.P1TimesO(p, P, O, P2); |
131 | 76 |
|
132 | 77 | // Compute P3 = O^T * (P1*O + P2). |
133 | 78 | // Here, treat P2 as the bsMat for the multiplication. |
134 | 79 | // Dimensions: mat = O (size: paramV x paramO), bsMat = P2 (size: paramV x paramO), |
135 | 80 | // and acc (P3) will have dimensions: (paramO x paramO), each entry being an m-vector. |
136 | | - GF16Utils.mulAddMatTransXMMat(mVecLimbs, O, P2, P3, paramV, paramO, paramO); |
137 | | - } |
| 81 | + GF16Utils.mulAddMatTransXMMat(mVecLimbs, O, P2, P3, v, o, o); |
138 | 82 |
|
139 | | - /** |
140 | | - * Reproduces the behavior of the C function m_upper. |
141 | | - * <p> |
142 | | - * For each pair (r, c) with 0 <= r <= c < size, it copies the m-vector at |
143 | | - * position (r, c) from 'in' to the next position in 'out' and, if r != c, |
144 | | - * it adds (XORs) the m-vector at position (c, r) into that same output vector. |
145 | | - * |
146 | | - * @param p the parameter object (used to get mVecLimbs) |
147 | | - * @param in the input long array (each vector is mVecLimbs in length) |
148 | | - * @param out the output long array (must be large enough to store all output vectors) |
149 | | - * @param size the size parameter defining the matrix dimensions. |
150 | | - */ |
151 | | - public static void mUpper(MayoParameters p, long[] in, long[] out, int size) |
152 | | - { |
153 | | - int mVecLimbs = p.getMVecLimbs(); |
| 83 | + // Store seed_pk into the public key cpk. |
| 84 | + System.arraycopy(seed_pk, 0, cpk, 0, pkSeedBytes); |
| 85 | + |
| 86 | + // Allocate an array for the "upper" part of P3. |
| 87 | + long[] P3_upper = new long[p3Limbs]; |
| 88 | + |
| 89 | + // Compute Upper(P3) and store the result in P3_upper. |
154 | 90 | int mVecsStored = 0; |
155 | | - for (int r = 0; r < size; r++) |
| 91 | + for (int r = 0; r < o; r++) |
156 | 92 | { |
157 | | - for (int c = r; c < size; c++) |
| 93 | + for (int c = r; c < o; c++) |
158 | 94 | { |
159 | 95 | // Compute the starting index for the (r, c) vector in the input array. |
160 | | - int srcOffset = mVecLimbs * (r * size + c); |
| 96 | + int srcOffset = mVecLimbs * (r * o + c); |
161 | 97 | // Compute the output offset for the current stored vector. |
162 | 98 | int destOffset = mVecLimbs * mVecsStored; |
163 | 99 |
|
164 | 100 | // Copy the vector at (r, c) into the output. |
165 | | - System.arraycopy(in, srcOffset, out, destOffset, mVecLimbs); |
| 101 | + System.arraycopy(P3, srcOffset, P3_upper, destOffset, mVecLimbs); |
166 | 102 |
|
167 | 103 | // If off-diagonal, add (XOR) the vector at (c, r) into the same output vector. |
168 | 104 | if (r != c) |
169 | 105 | { |
170 | | - int srcOffset2 = mVecLimbs * (c * size + r); |
171 | | - GF16Utils.mVecAdd(mVecLimbs, in, srcOffset2, out, destOffset); |
| 106 | + int srcOffset2 = mVecLimbs * (c * o + r); |
| 107 | + Longs.xorTo(mVecLimbs, P3, srcOffset2, P3_upper, destOffset); |
172 | 108 | } |
173 | 109 | mVecsStored++; |
174 | 110 | } |
175 | 111 | } |
| 112 | + |
| 113 | + // Pack the m-vectors in P3_upper into cpk (after the seed_pk). |
| 114 | + // The number of m-vectors to pack is (param_P3_limbs / m_vec_limbs), |
| 115 | + // and param_m is used as the m value. |
| 116 | + Utils.packMVecs(P3_upper, cpk, pkSeedBytes, p3Limbs / mVecLimbs, m); |
| 117 | + // Securely clear sensitive data. |
| 118 | + Arrays.clear(O); |
| 119 | + Arrays.clear(P2); |
| 120 | + Arrays.clear(P3); |
| 121 | + |
| 122 | + return new AsymmetricCipherKeyPair(new MayoPublicKeyParameter(p, cpk), new MayoPrivateKeyParameter(p, seed_sk)); |
176 | 123 | } |
177 | 124 | } |
0 commit comments