Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
cx_mlkem_indcpa.c
Go to the documentation of this file.
1/*****************************************************************************
2 * (c) 2026 Ledger SAS.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *****************************************************************************/
24#include <string.h>
25
26#include "cx_mlkem_indcpa.h"
27#include "cx_mlkem_poly.h"
28#include "cx_mlkem_polyvec.h"
29#include "cx_mlkem_polymat.h"
30#include "cx_mlkem_util.h"
31#include "cx_mlkem_sample.h"
32
33cx_err_t MLKEM_INDCPA_keypair_derand(uint8_t *pk,
34 size_t pk_len,
35 uint8_t *sk,
36 size_t sk_len,
37 const uint8_t coins[2 * MLKEM_SYMBYTES],
38 const MLKEM_param_info_t *p)
39{
40 uint8_t buf[2U * MLKEM_SYMBYTES] = {0};
41 uint8_t coins_with_k[MLKEM_SYMBYTES + 1U] = {0};
42 const uint8_t *publicseed = NULL;
43 const uint8_t *noiseseed = NULL;
44 polyvec a_row = {0}; // one matrix row at a time
45 polyvec e = {0};
46 polyvec pkpv = {0};
47 polyvec skpv = {0};
48
49 if ((pk == NULL) || (sk == NULL) || (coins == NULL) || (p == NULL)) {
50 return CX_INVALID_PARAMETER;
51 }
52
53 if ((pk_len < p->indcpa_pk_bytes) || (sk_len < p->indcpa_sk_bytes)) {
54 return CX_INVALID_PARAMETER_SIZE;
55 }
56
57 memcpy(coins_with_k, coins, MLKEM_SYMBYTES);
58 coins_with_k[MLKEM_SYMBYTES] = p->k;
59 MLKEM_UTIL_hash_g(buf, coins_with_k, MLKEM_SYMBYTES + 1U);
60
61 publicseed = buf;
62 noiseseed = &buf[MLKEM_SYMBYTES];
63
64 for (uint32_t i = 0U; i < p->k; i++) {
65 MLKEM_SAMPLE_getnoise(&skpv.vec[i], noiseseed, (uint8_t) i, p->eta1);
66 }
67
68 for (uint32_t i = 0U; i < p->k; i++) {
69 MLKEM_SAMPLE_getnoise(&e.vec[i], noiseseed, (uint8_t) (p->k + i), p->eta1);
70 }
71
72 MLKEM_POLYVEC_ntt(&skpv, p->k);
73 MLKEM_POLYVEC_ntt(&e, p->k);
74
75 // Optimization: Generate matrix A row-by-row to avoid storing full k×k polymat
76 for (uint32_t i = 0U; i < p->k; i++) {
77 MLKEM_POLYMAT_gen_matrix_row(&a_row, publicseed, 0, (uint8_t) i, p->k);
78 MLKEM_POLYVEC_basemul_acc_montgomery(&pkpv.vec[i], &a_row, &skpv, p->k);
79 }
80
81 MLKEM_POLYVEC_tomont(&pkpv, p->k);
82 MLKEM_POLYVEC_add(&pkpv, &e, p->k);
83 MLKEM_POLYVEC_reduce(&pkpv, p->k);
84 MLKEM_POLYVEC_reduce(&skpv, p->k);
85
86 MLKEM_POLYVEC_tobytes(sk, &skpv, p->k);
87 MLKEM_POLYVEC_tobytes(pk, &pkpv, p->k);
88 memcpy(&pk[p->polyvec_bytes], publicseed, MLKEM_SYMBYTES);
89
90 explicit_bzero(buf, sizeof(buf));
91 explicit_bzero(coins_with_k, sizeof(coins_with_k));
92 explicit_bzero(&a_row, sizeof(a_row));
93 explicit_bzero(&e, sizeof(e));
94 explicit_bzero(&skpv, sizeof(skpv));
95
96 return CX_OK;
97}
98
99cx_err_t MLKEM_INDCPA_enc(uint8_t *c,
100 size_t c_len,
101 const uint8_t *m,
102 size_t m_len,
103 const uint8_t *pk,
104 size_t pk_len,
105 const uint8_t coins[2 * MLKEM_SYMBYTES],
106 const MLKEM_param_info_t *p)
107{
108 uint8_t seed[MLKEM_SYMBYTES] = {0};
109 polyvec at_row = {0}; // one matrix row at a time
110 polyvec sp = {0};
111 polyvec pkpv = {0};
112 polyvec ep = {0};
113 polyvec b = {0};
114 poly v = {0};
115 poly k = {0};
116 poly epp = {0};
117
118 if ((c == NULL) || (m == NULL) || (pk == NULL) || (coins == NULL) || (p == NULL)) {
119 return CX_INVALID_PARAMETER;
120 }
121
122 if ((m_len < MLKEM_SYMBYTES) || (pk_len < p->indcpa_pk_bytes) || (c_len < p->indcpa_ct_bytes)) {
123 return CX_INVALID_PARAMETER_SIZE;
124 }
125
126 MLKEM_POLYVEC_frombytes(&pkpv, pk, p->k);
127 memcpy(seed, pk + p->polyvec_bytes, MLKEM_SYMBYTES);
128
129 MLKEM_POLY_frommsg(&k, m);
130
131 for (uint32_t i = 0U; i < p->k; i++) {
132 MLKEM_SAMPLE_getnoise(&sp.vec[i], coins, (uint8_t) i, p->eta1);
133 }
134
135 for (uint32_t i = 0U; i < p->k; i++) {
136 MLKEM_SAMPLE_getnoise(&ep.vec[i], coins, (uint8_t) (p->k + i), p->eta2);
137 }
138
139 MLKEM_SAMPLE_getnoise(&epp, coins, (uint8_t) (2U * p->k), p->eta2);
140
141 MLKEM_POLYVEC_ntt(&sp, p->k);
142
143 // Optimization: Generate transposed matrix A^T row-by-row
144 for (uint32_t i = 0U; i < p->k; i++) {
145 MLKEM_POLYMAT_gen_matrix_row(&at_row, seed, 1, (uint8_t) i, p->k);
146 MLKEM_POLYVEC_basemul_acc_montgomery(&b.vec[i], &at_row, &sp, p->k);
147 }
148
150 MLKEM_POLYVEC_add(&b, &ep, p->k);
151 MLKEM_POLYVEC_reduce(&b, p->k);
152
153 MLKEM_POLYVEC_basemul_acc_montgomery(&v, &pkpv, &sp, p->k);
155 MLKEM_POLY_add(&v, &epp);
156 MLKEM_POLY_add(&v, &k);
158
159 MLKEM_POLYVEC_compress(c, &b, p->k, p->du);
160
161 if (p->dv == 4) {
163 }
164 else { // dv == 5
166 }
167
168 explicit_bzero(&at_row, sizeof(at_row));
169 explicit_bzero(&sp, sizeof(sp));
170 explicit_bzero(&ep, sizeof(ep));
171 explicit_bzero(&b, sizeof(b));
172 explicit_bzero(&v, sizeof(v));
173 explicit_bzero(&epp, sizeof(epp));
174 explicit_bzero(&k, sizeof(k));
175
176 return CX_OK;
177}
178
179cx_err_t MLKEM_INDCPA_dec(uint8_t *m,
180 size_t m_len,
181 const uint8_t *c,
182 size_t c_len,
183 const uint8_t *sk,
184 size_t sk_len,
185 const MLKEM_param_info_t *p)
186{
187 polyvec b = {0};
188 polyvec skpv = {0};
189 poly v = {0};
190 poly sb = {0};
191
192 if ((m == NULL) || (c == NULL) || (sk == NULL) || (p == NULL)) {
193 return CX_INVALID_PARAMETER;
194 }
195
196 if ((m_len < MLKEM_SYMBYTES) || (c_len < p->indcpa_ct_bytes) || (sk_len < p->indcpa_sk_bytes)) {
197 return CX_INVALID_PARAMETER_SIZE;
198 }
199
200 MLKEM_POLYVEC_decompress(&b, c, p->k, p->du);
201
202 if (p->dv == 4) {
204 }
205 else { // dv == 5
207 }
208
209 MLKEM_POLYVEC_frombytes(&skpv, sk, p->k);
210
211 MLKEM_POLYVEC_ntt(&b, p->k);
212 MLKEM_POLYVEC_basemul_acc_montgomery(&sb, &skpv, &b, p->k);
214 MLKEM_POLY_sub(&v, &sb);
216 MLKEM_POLY_tomsg(m, &v);
217
218 explicit_bzero(&skpv, sizeof(skpv));
219 explicit_bzero(&sb, sizeof(sb));
220 explicit_bzero(&v, sizeof(v));
221
222 return CX_OK;
223}
cx_err_t MLKEM_INDCPA_keypair_derand(uint8_t *pk, size_t pk_len, uint8_t *sk, size_t sk_len, const uint8_t coins[2 *MLKEM_SYMBYTES], const MLKEM_param_info_t *p)
cx_err_t MLKEM_INDCPA_enc(uint8_t *c, size_t c_len, const uint8_t *m, size_t m_len, const uint8_t *pk, size_t pk_len, const uint8_t coins[2 *MLKEM_SYMBYTES], const MLKEM_param_info_t *p)
cx_err_t MLKEM_INDCPA_dec(uint8_t *m, size_t m_len, const uint8_t *c, size_t c_len, const uint8_t *sk, size_t sk_len, const MLKEM_param_info_t *p)
void MLKEM_POLY_sub(poly *r, const poly *b)
Subtracts polynomial b from polynomial r in place.
void MLKEM_POLY_decompress_d5(poly *r, const uint8_t *a)
Decompresses a polynomial from bytes with dv=5.
void MLKEM_POLY_decompress_d4(poly *r, const uint8_t *a)
Decompresses a polynomial from bytes with dv=4.
void MLKEM_POLY_reduce(poly *r)
Applies Barrett reduction to all coefficients and map to [0, q-1].
void MLKEM_POLY_compress_d5(uint8_t *r, const poly *a)
Compresses a polynomial with dv=5 and serialize to bytes.
void MLKEM_POLY_tomsg(uint8_t *msg, const poly *a)
Encodes a polynomial into a 32-byte message.
void MLKEM_POLY_invntt_tomont(poly *p)
Computes the inverse NTT and multiply by Montgomery factor.
void MLKEM_POLY_add(poly *r, const poly *b)
Adds polynomial b to polynomial r in place.
void MLKEM_POLY_frommsg(poly *r, const uint8_t *msg)
Decodes a 32-byte message into a polynomial.
void MLKEM_POLY_compress_d4(uint8_t *r, const poly *a)
Compresses a polynomial with dv=4 and serialize to bytes.
void MLKEM_POLYMAT_gen_matrix_row(polyvec *row, const uint8_t *seed, int32_t transposed, uint8_t i, uint8_t k)
void MLKEM_POLYVEC_decompress(polyvec *r, const uint8_t *a, uint8_t k, uint8_t du)
Decompresses and deserializes a polynomial vector.
void MLKEM_POLYVEC_invntt_tomont(polyvec *r, uint8_t k)
Applies the inverse NTT to each polynomial in a vector.
void MLKEM_POLYVEC_reduce(polyvec *r, uint8_t k)
Reduces all coefficients of each polynomial in a vector.
void MLKEM_POLYVEC_compress(uint8_t *r, const polyvec *a, uint8_t k, uint8_t du)
Compresses and serializes a polynomial vector.
void MLKEM_POLYVEC_tomont(polyvec *r, uint8_t k)
Converts each polynomial in a vector to Montgomery domain.
void MLKEM_POLYVEC_frombytes(polyvec *r, const uint8_t *a, uint8_t k)
Deserializes a polynomial vector from bytes.
void MLKEM_POLYVEC_tobytes(uint8_t *r, const polyvec *a, uint8_t k)
Serializes a polynomial vector to bytes.
void MLKEM_POLYVEC_add(polyvec *r, const polyvec *b, uint8_t k)
Adds polynomial vector b to r in place.
void MLKEM_POLYVEC_basemul_acc_montgomery(poly *r, const polyvec *a, const polyvec *b, uint8_t k)
Accumulated pointwise multiplication of two polynomial vectors in the NTT domain.
void MLKEM_POLYVEC_ntt(polyvec *r, uint8_t k)
Applies the NTT to each polynomial in a vector.
void MLKEM_SAMPLE_getnoise(poly *r, const uint8_t *seed, uint8_t nonce, uint8_t eta)
Samples a noise polynomial using PRF and CBD.
void MLKEM_UTIL_hash_g(uint8_t *out, const uint8_t *in, size_t in_len)
Computes the G hash function (SHA3-512) as defined in FIPS 203.
#define MLKEM_SYMBYTES
Definition lcx_mlkem.h:38
ML-KEM parameter set descriptor holding all derived sizes.
Definition lcx_mlkem.h:168
uint16_t polyvec_bytes
Definition lcx_mlkem.h:174
uint16_t polyvec_compressed_bytes
Definition lcx_mlkem.h:175
Polynomial with MLKEM_N coefficients.
Vector of polynomials with up to MLKEM_MAX_K elements.
poly vec[MLKEM_MAX_K]