1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
|
/* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0"
*
* Written by Nir Drucker, Shay Gueron and Dusan Kostic,
* AWS Cryptographic Algorithms Group.
*
* [1] The optimizations are based on the description developed in the paper:
* Drucker, Nir, and Shay Gueron. 2019. “A Toolbox for Software Optimization
* of QC-MDPC Code-Based Cryptosystems.” Journal of Cryptographic Engineering,
* January, 1–17. https://doi.org/10.1007/s13389-018-00200-4.
*
* [2] The decoder algorithm is the Black-Gray decoder in
* the early submission of CAKE (due to N. Sandrier and R Misoczki).
*
* [3] The analysis for the constant time implementation is given in
* Drucker, Nir, Shay Gueron, and Dusan Kostic. 2019.
* “On Constant-Time QC-MDPC Decoding with Negligible Failure Rate.”
* Cryptology EPrint Archive, 2019. https://eprint.iacr.org/2019/1289.
*
* [4] it was adapted to BGF in:
* Drucker, Nir, Shay Gueron, and Dusan Kostic. 2019.
* “QC-MDPC decoders with several shades of gray.”
* Cryptology EPrint Archive, 2019. To be published.
*
* [5] Chou, T.: QcBits: Constant-Time Small-Key Code-Based Cryptography.
* In: Gier-lichs, B., Poschmann, A.Y. (eds.) Cryptographic Hardware
* and Embedded Systems– CHES 2016. pp. 280–300. Springer Berlin Heidelberg,
* Berlin, Heidelberg (2016)
*
* [6] The rotate512_small funciton is a derivative of the code described in:
* Guimarães, Antonio, Diego F Aranha, and Edson Borin. 2019.
* “Optimized Implementation of QC-MDPC Code-Based Cryptography.”
* Concurrency and Computation: Practice and Experience 31 (18):
* e5089. https://doi.org/10.1002/cpe.5089.
*/
#include "decode.h"
#include "cleanup.h"
#include "decode_internal.h"
#include "gf2x.h"
#include "utilities.h"
// Decoding (bit-flipping) parameter
#if defined(BG_DECODER)
# if(LEVEL == 1)
# define MAX_IT 3
# elif(LEVEL == 3)
# define MAX_IT 4
# else
# error "Level can only be 1/3"
# endif
#elif defined(BGF_DECODER)
# if(LEVEL == 1)
# define MAX_IT 5
# elif(LEVEL == 3)
# define MAX_IT 5
# else
# error "Level can only be 1/3"
# endif
#endif
ret_t compute_syndrome(OUT syndrome_t *syndrome,
IN const pad_r_t *c0,
IN const pad_r_t *h0,
IN const decode_ctx *ctx)
{
DEFER_CLEANUP(pad_r_t pad_s, pad_r_cleanup);
gf2x_mod_mul(&pad_s, c0, h0);
bike_memcpy((uint8_t *)syndrome->qw, pad_s.val.raw, R_BYTES);
ctx->dup(syndrome);
return SUCCESS;
}
_INLINE_ ret_t recompute_syndrome(OUT syndrome_t *syndrome,
IN const pad_r_t *c0,
IN const pad_r_t *h0,
IN const pad_r_t *pk,
IN const e_t *e,
IN const decode_ctx *ctx)
{
DEFER_CLEANUP(pad_r_t tmp_c0, pad_r_cleanup);
DEFER_CLEANUP(pad_r_t e0 = {0}, pad_r_cleanup);
DEFER_CLEANUP(pad_r_t e1 = {0}, pad_r_cleanup);
e0.val = e->val[0];
e1.val = e->val[1];
// tmp_c0 = pk * e1 + c0 + e0
gf2x_mod_mul(&tmp_c0, &e1, pk);
gf2x_mod_add(&tmp_c0, &tmp_c0, c0);
gf2x_mod_add(&tmp_c0, &tmp_c0, &e0);
// Recompute the syndrome using the updated ciphertext
POSIX_GUARD(compute_syndrome(syndrome, &tmp_c0, h0, ctx));
return SUCCESS;
}
_INLINE_ uint8_t get_threshold(IN const syndrome_t *s)
{
bike_static_assert(sizeof(*s) >= sizeof(r_t), syndrome_is_large_enough);
const uint32_t syndrome_weight = r_bits_vector_weight((const r_t *)s->qw);
// The equations below are defined in BIKE's specification p. 16, Section 5.2
uint32_t thr = THRESHOLD_COEFF0 + (THRESHOLD_COEFF1 * syndrome_weight);
const uint32_t mask = secure_l32_mask(thr, THRESHOLD_MIN);
thr = (u32_barrier(mask) & thr) | (u32_barrier(~mask) & THRESHOLD_MIN);
DMSG(" Threshold: %d\n", thr);
return thr;
}
// Calculate the Unsatisfied Parity Checks (UPCs) and update the errors
// vector (e) accordingly. In addition, update the black and gray errors vector
// with the relevant values.
_INLINE_ void find_err1(OUT e_t *e,
OUT e_t *black_e,
OUT e_t *gray_e,
IN const syndrome_t * syndrome,
IN const compressed_idx_d_ar_t wlist,
IN const uint8_t threshold,
IN const decode_ctx *ctx)
{
// This function uses the bit-slice-adder methodology of [5]:
DEFER_CLEANUP(syndrome_t rotated_syndrome = {0}, syndrome_cleanup);
DEFER_CLEANUP(upc_t upc, upc_cleanup);
for(uint32_t i = 0; i < N0; i++) {
// UPC must start from zero at every iteration
bike_memset(&upc, 0, sizeof(upc));
// 1) Right-rotate the syndrome for every secret key set bit index
// Then slice-add it to the UPC array.
for(size_t j = 0; j < DV; j++) {
ctx->rotate_right(&rotated_syndrome, syndrome, wlist[i].val[j]);
ctx->bit_sliced_adder(&upc, &rotated_syndrome, LOG2_MSB(j + 1));
}
// 2) Subtract the threshold from the UPC counters
ctx->bit_slice_full_subtract(&upc, threshold);
// 3) Update the errors and the black errors vectors.
// The last slice of the UPC array holds the MSB of the accumulated values
// minus the threshold. Every zero bit indicates a potential error bit.
// The errors values are stored in the black array and xored with the
// errors Of the previous iteration.
const r_t *last_slice = &(upc.slice[SLICES - 1].u.r.val);
for(size_t j = 0; j < R_BYTES; j++) {
const uint8_t sum_msb = (~last_slice->raw[j]);
black_e->val[i].raw[j] = sum_msb;
e->val[i].raw[j] ^= sum_msb;
}
// Ensure that the padding bits (upper bits of the last byte) are zero so
// they will not be included in the multiplication and in the hash function.
e->val[i].raw[R_BYTES - 1] &= LAST_R_BYTE_MASK;
// 4) Calculate the gray error array by adding "DELTA" to the UPC array.
// For that we reuse the rotated_syndrome variable setting it to all "1".
for(size_t l = 0; l < DELTA; l++) {
bike_memset((uint8_t *)rotated_syndrome.qw, 0xff, R_BYTES);
ctx->bit_sliced_adder(&upc, &rotated_syndrome, SLICES);
}
// 5) Update the gray list with the relevant bits that are not
// set in the black list.
for(size_t j = 0; j < R_BYTES; j++) {
const uint8_t sum_msb = (~last_slice->raw[j]);
gray_e->val[i].raw[j] = (~(black_e->val[i].raw[j])) & sum_msb;
}
}
}
// Recalculate the UPCs and update the errors vector (e) according to it
// and to the black/gray vectors.
_INLINE_ void find_err2(OUT e_t *e,
IN e_t * pos_e,
IN const syndrome_t * syndrome,
IN const compressed_idx_d_ar_t wlist,
IN const uint8_t threshold,
IN const decode_ctx *ctx)
{
DEFER_CLEANUP(syndrome_t rotated_syndrome = {0}, syndrome_cleanup);
DEFER_CLEANUP(upc_t upc, upc_cleanup);
for(uint32_t i = 0; i < N0; i++) {
// UPC must start from zero at every iteration
bike_memset(&upc, 0, sizeof(upc));
// 1) Right-rotate the syndrome, for every index of a set bit in the secret
// key. Then slice-add it to the UPC array.
for(size_t j = 0; j < DV; j++) {
ctx->rotate_right(&rotated_syndrome, syndrome, wlist[i].val[j]);
ctx->bit_sliced_adder(&upc, &rotated_syndrome, LOG2_MSB(j + 1));
}
// 2) Subtract the threshold from the UPC counters
ctx->bit_slice_full_subtract(&upc, threshold);
// 3) Update the errors vector.
// The last slice of the UPC array holds the MSB of the accumulated values
// minus the threshold. Every zero bit indicates a potential error bit.
const r_t *last_slice = &(upc.slice[SLICES - 1].u.r.val);
for(size_t j = 0; j < R_BYTES; j++) {
const uint8_t sum_msb = (~last_slice->raw[j]);
e->val[i].raw[j] ^= (pos_e->val[i].raw[j] & sum_msb);
}
// Ensure that the padding bits (upper bits of the last byte) are zero, so
// they are not included in the multiplication, and in the hash function.
e->val[i].raw[R_BYTES - 1] &= LAST_R_BYTE_MASK;
}
}
ret_t decode(OUT e_t *e, IN const ct_t *ct, IN const sk_t *sk)
{
// Initialize the decode methods struct
decode_ctx ctx;
decode_ctx_init(&ctx);
DEFER_CLEANUP(e_t black_e = {0}, e_cleanup);
DEFER_CLEANUP(e_t gray_e = {0}, e_cleanup);
DEFER_CLEANUP(pad_r_t c0 = {0}, pad_r_cleanup);
DEFER_CLEANUP(pad_r_t h0 = {0}, pad_r_cleanup);
pad_r_t pk = {0};
// Pad ciphertext (c0), secret key (h0), and public key (h)
c0.val = ct->c0;
h0.val = sk->bin[0];
pk.val = sk->pk;
DEFER_CLEANUP(syndrome_t s = {0}, syndrome_cleanup);
DMSG(" Computing s.\n");
POSIX_GUARD(compute_syndrome(&s, &c0, &h0, &ctx));
ctx.dup(&s);
// Reset (init) the error because it is xored in the find_err functions.
bike_memset(e, 0, sizeof(*e));
for(uint32_t iter = 0; iter < MAX_IT; iter++) {
const uint8_t threshold = get_threshold(&s);
DMSG(" Iteration: %d\n", iter);
DMSG(" Weight of e: %lu\n",
r_bits_vector_weight(&e->val[0]) + r_bits_vector_weight(&e->val[1]));
DMSG(" Weight of syndrome: %lu\n", r_bits_vector_weight((r_t *)s.qw));
find_err1(e, &black_e, &gray_e, &s, sk->wlist, threshold, &ctx);
POSIX_GUARD(recompute_syndrome(&s, &c0, &h0, &pk, e, &ctx));
#if defined(BGF_DECODER)
if(iter >= 1) {
continue;
}
#endif
DMSG(" Weight of e: %lu\n",
r_bits_vector_weight(&e->val[0]) + r_bits_vector_weight(&e->val[1]));
DMSG(" Weight of syndrome: %lu\n", r_bits_vector_weight((r_t *)s.qw));
find_err2(e, &black_e, &s, sk->wlist, ((DV + 1) / 2) + 1, &ctx);
POSIX_GUARD(recompute_syndrome(&s, &c0, &h0, &pk, e, &ctx));
DMSG(" Weight of e: %lu\n",
r_bits_vector_weight(&e->val[0]) + r_bits_vector_weight(&e->val[1]));
DMSG(" Weight of syndrome: %lu\n", r_bits_vector_weight((r_t *)s.qw));
find_err2(e, &gray_e, &s, sk->wlist, ((DV + 1) / 2) + 1, &ctx);
POSIX_GUARD(recompute_syndrome(&s, &c0, &h0, &pk, e, &ctx));
}
if(r_bits_vector_weight((r_t *)s.qw) > 0) {
BIKE_ERROR(E_DECODING_FAILURE);
}
return SUCCESS;
}
|