Botan 3.9.0
Crypto and TLS for C&
goppa_code.cpp
Go to the documentation of this file.
1/*
2 * (C) Copyright Projet SECRET, INRIA, Rocquencourt
3 * (C) Bhaskar Biswas and Nicolas Sendrier
4 *
5 * (C) 2014 cryptosource GmbH
6 * (C) 2014 Falko Strenzke fstrenzke@cryptosource.de
7 *
8 * Botan is released under the Simplified BSD License (see license.txt)
9 *
10 */
11
12#include <botan/internal/mce_internal.h>
13
14#include <botan/mem_ops.h>
15#include <botan/internal/code_based_util.h>
16
17namespace Botan {
18
19namespace {
20
21void matrix_arr_mul(std::vector<uint32_t> matrix,
22 size_t numo_rows,
23 size_t words_per_row,
24 const uint8_t input_vec[],
25 uint32_t output_vec[],
26 size_t output_vec_len) {
27 for(size_t j = 0; j < numo_rows; j++) {
28 if(((input_vec[j / 8] >> (j % 8)) & 1) != 0) {
29 for(size_t i = 0; i < output_vec_len; i++) {
30 output_vec[i] ^= matrix[j * (words_per_row) + i];
31 }
32 }
33 }
34}
35
36/**
37* returns the error vector to the syndrome
38*/
39secure_vector<gf2m> goppa_decode(const polyn_gf2m& syndrom_polyn,
40 const polyn_gf2m& g,
41 const std::vector<polyn_gf2m>& sqrtmod,
42 const std::vector<gf2m>& Linv) {
43 const size_t code_length = Linv.size();
44 uint32_t t = g.get_degree();
45
46 std::shared_ptr<GF2m_Field> sp_field = g.get_sp_field();
47
48 std::pair<polyn_gf2m, polyn_gf2m> h_aux = polyn_gf2m::eea_with_coefficients(syndrom_polyn, g, 1);
49 polyn_gf2m& h = h_aux.first;
50 polyn_gf2m& aux = h_aux.second;
51 gf2m a = sp_field->gf_inv(aux.get_coef(0));
52 gf2m log_a = sp_field->gf_log(a);
53 for(int i = 0; i <= h.get_degree(); ++i) {
54 h.set_coef(i, sp_field->gf_mul_zrz(log_a, h.get_coef(i)));
55 }
56
57 // compute h(z) += z
58 h.add_to_coef(1, 1);
59 // compute S square root of h (using sqrtmod)
60 polyn_gf2m S(t - 1, g.get_sp_field());
61
62 for(uint32_t i = 0; i < t; i++) {
63 a = sp_field->gf_sqrt(h.get_coef(i));
64
65 if((i & 1) != 0) {
66 for(uint32_t j = 0; j < t; j++) {
67 S.add_to_coef(j, sp_field->gf_mul(a, sqrtmod[i / 2].get_coef(j)));
68 }
69 } else {
70 S.add_to_coef(i / 2, a);
71 }
72 } /* end for loop (i) */
73
74 S.get_degree();
75
76 std::pair<polyn_gf2m, polyn_gf2m> v_u = polyn_gf2m::eea_with_coefficients(S, g, t / 2 + 1);
77 polyn_gf2m& u = v_u.second;
78 polyn_gf2m& v = v_u.first;
79
80 // sigma = u^2+z*v^2
81 polyn_gf2m sigma(t, g.get_sp_field());
82
83 const int u_deg = u.get_degree();
84 BOTAN_ASSERT(u_deg >= 0, "Valid degree");
85 for(int i = 0; i <= u_deg; ++i) {
86 sigma.set_coef(2 * i, sp_field->gf_square(u.get_coef(i)));
87 }
88
89 const int v_deg = v.get_degree();
90 BOTAN_ASSERT(v_deg >= 0, "Valid degree");
91 for(int i = 0; i <= v_deg; ++i) {
92 sigma.set_coef(2 * i + 1, sp_field->gf_square(v.get_coef(i)));
93 }
94
96 size_t d = res.size();
97
98 secure_vector<gf2m> result(d);
99 for(uint32_t i = 0; i < d; ++i) {
100 gf2m current = res[i];
101
102 gf2m tmp = gray_to_lex(current);
103 /// XXX double assignment, possible bug?
104 if(tmp >= code_length) /* invalid root */
105 {
106 result[i] = static_cast<gf2m>(i);
107 }
108 result[i] = Linv[tmp];
109 }
110
111 return result;
112}
113} // namespace
114
116 secure_vector<uint8_t>& error_mask_out,
117 const secure_vector<uint8_t>& ciphertext,
118 const McEliece_PrivateKey& key) {
119 mceliece_decrypt(plaintext_out, error_mask_out, ciphertext.data(), ciphertext.size(), key);
120}
121
123 secure_vector<uint8_t>& error_mask,
124 const uint8_t ciphertext[],
125 size_t ciphertext_len,
126 const McEliece_PrivateKey& key) {
127 secure_vector<gf2m> error_pos;
128 plaintext = mceliece_decrypt(error_pos, ciphertext, ciphertext_len, key);
129
130 const size_t code_length = key.get_code_length();
131 secure_vector<uint8_t> result((code_length + 7) / 8);
132 for(auto&& pos : error_pos) {
133 if(pos > code_length) {
134 throw Invalid_Argument("error position larger than code size");
135 }
136 result[pos / 8] |= (1 << (pos % 8));
137 }
138
139 error_mask = result;
140}
141
142/**
143* @p p_err_pos_len must point to the available length of @p error_pos on input, the
144* function will set it to the actual number of errors returned in the @p error_pos
145* array */
147 const uint8_t* ciphertext,
148 size_t ciphertext_len,
149 const McEliece_PrivateKey& key) {
150 const size_t dimension = key.get_dimension();
151 const size_t codimension = key.get_codimension();
152 const uint32_t t = key.get_goppa_polyn().get_degree();
153 polyn_gf2m syndrome_polyn(key.get_goppa_polyn().get_sp_field()); // init as zero polyn
154 const unsigned unused_pt_bits = dimension % 8;
155 const uint8_t unused_pt_bits_mask = (1 << unused_pt_bits) - 1;
156
157 if(ciphertext_len != (key.get_code_length() + 7) / 8) {
158 throw Invalid_Argument("wrong size of McEliece ciphertext");
159 }
160 const size_t cleartext_len = (key.get_message_word_bit_length() + 7) / 8;
161
162 if(cleartext_len != bit_size_to_byte_size(dimension)) {
163 throw Invalid_Argument("mce-decryption: wrong length of cleartext buffer");
164 }
165
166 secure_vector<uint32_t> syndrome_vec(bit_size_to_32bit_size(codimension));
167 matrix_arr_mul(key.get_H_coeffs(),
168 key.get_code_length(),
169 bit_size_to_32bit_size(codimension),
170 ciphertext,
171 syndrome_vec.data(),
172 syndrome_vec.size());
173
174 secure_vector<uint8_t> syndrome_byte_vec(bit_size_to_byte_size(codimension));
175 const size_t syndrome_byte_vec_size = syndrome_byte_vec.size();
176 for(size_t i = 0; i < syndrome_byte_vec_size; i++) {
177 syndrome_byte_vec[i] = static_cast<uint8_t>(syndrome_vec[i / 4] >> (8 * (i % 4)));
178 }
179
180 syndrome_polyn = polyn_gf2m(
181 t - 1, syndrome_byte_vec.data(), bit_size_to_byte_size(codimension), key.get_goppa_polyn().get_sp_field());
182
183 syndrome_polyn.get_degree();
184 error_pos = goppa_decode(syndrome_polyn, key.get_goppa_polyn(), key.get_sqrtmod(), key.get_Linv());
185
186 const size_t nb_err = error_pos.size();
187
188 secure_vector<uint8_t> cleartext(cleartext_len);
189 copy_mem(cleartext.data(), ciphertext, cleartext_len);
190
191 for(size_t i = 0; i < nb_err; i++) {
192 gf2m current = error_pos[i];
193
194 if(current >= cleartext_len * 8) {
195 // an invalid position, this shouldn't happen
196 continue;
197 }
198 cleartext[current / 8] ^= (1 << (current % 8));
199 }
200
201 if(unused_pt_bits > 0) {
202 cleartext[cleartext_len - 1] &= unused_pt_bits_mask;
203 }
204
205 return cleartext;
206}
207
208} // namespace Botan
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:62
const std::vector< polyn_gf2m > & get_sqrtmod() const
Definition mceliece.h:123
size_t get_codimension() const
Definition mceliece.h:127
size_t get_dimension() const
Definition mceliece.h:125
const polyn_gf2m & get_goppa_polyn() const
const std::vector< gf2m > & get_Linv() const
Definition mceliece.h:121
const std::vector< uint32_t > & get_H_coeffs() const
Definition mceliece.h:119
size_t get_message_word_bit_length() const
size_t get_code_length() const
Definition mceliece.h:52
int get_degree() const
std::shared_ptr< GF2m_Field > get_sp_field() const
Definition polyn_gf2m.h:79
static std::pair< polyn_gf2m, polyn_gf2m > eea_with_coefficients(const polyn_gf2m &p, const polyn_gf2m &g, int break_deg)
void mceliece_decrypt(secure_vector< uint8_t > &plaintext_out, secure_vector< uint8_t > &error_mask_out, const secure_vector< uint8_t > &ciphertext, const McEliece_PrivateKey &key)
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:145
gf2m gray_to_lex(gf2m gray)
BOTAN_FORCE_INLINE constexpr T sigma(T x)
Definition rotate.h:45
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:69
size_t bit_size_to_32bit_size(size_t bit_size)
secure_vector< gf2m > find_roots_gf2m_decomp(const polyn_gf2m &polyn, size_t code_length)
size_t bit_size_to_byte_size(size_t bit_size)
uint16_t gf2m