/src/botan/src/lib/pubkey/classic_mceliece/cmce_keys_internal.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Classic McEliece key generation with Internal Private and Public Key classes |
3 | | * (C) 2023 Jack Lloyd |
4 | | * 2023,2024 Fabian Albert, Amos Treiber - Rohde & Schwarz Cybersecurity |
5 | | * |
6 | | * Botan is released under the Simplified BSD License (see license.txt) |
7 | | **/ |
8 | | |
9 | | #include <botan/internal/cmce_keys_internal.h> |
10 | | |
11 | | namespace Botan { |
12 | | |
13 | | namespace { |
14 | | |
15 | | /** |
16 | | * @brief Try to generate a Classic McEliece keypair for a given seed. |
17 | | * |
18 | | * @param[out] out_next_seed The next seed to use for key generation, if this iteration fails |
19 | | * @param params Classic McEliece parameters |
20 | | * @param seed The seed to used for this key generation iteration |
21 | | * @return a keypair on success, std::nullopt otherwise |
22 | | */ |
23 | | std::optional<Classic_McEliece_KeyPair_Internal> try_generate_keypair(std::span<uint8_t> out_next_seed, |
24 | | const Classic_McEliece_Parameters& params, |
25 | 0 | CmceKeyGenSeed seed) { |
26 | 0 | BOTAN_ASSERT_EQUAL(seed.size(), 32, "Valid seed length"); |
27 | 0 | BOTAN_ASSERT_EQUAL(out_next_seed.size(), 32, "Valid output seed length"); |
28 | |
|
29 | 0 | auto big_e_xof = params.prg(seed); |
30 | |
|
31 | 0 | auto s = big_e_xof->output<CmceRejectionSeed>(params.n() / 8); |
32 | 0 | auto ordering_bits = big_e_xof->output<CmceOrderingBits>((params.sigma2() * params.q()) / 8); |
33 | 0 | auto irreducible_bits = big_e_xof->output<CmceIrreducibleBits>((params.sigma1() * params.t()) / 8); |
34 | 0 | big_e_xof->output(out_next_seed); |
35 | | |
36 | | // Field-ordering generation - Classic McEliece ISO 8.2 |
37 | 0 | auto field_ordering = Classic_McEliece_Field_Ordering::create_field_ordering(params, ordering_bits); |
38 | 0 | if(!field_ordering) { |
39 | 0 | return std::nullopt; |
40 | 0 | } |
41 | | |
42 | | // Irreducible-polynomial generation - Classic McEliece ISO 8.1 |
43 | 0 | auto g = params.poly_ring().compute_minimal_polynomial(irreducible_bits); |
44 | 0 | if(!g) { |
45 | 0 | return std::nullopt; |
46 | 0 | } |
47 | | |
48 | | // Matrix generation for Goppa codes - Classic McEliece ISO 7.2 |
49 | 0 | auto pk_matrix_and_pivots = |
50 | 0 | Classic_McEliece_Matrix::create_matrix_and_apply_pivots(params, field_ordering.value(), g.value()); |
51 | 0 | if(!pk_matrix_and_pivots) { |
52 | 0 | return std::nullopt; |
53 | 0 | } |
54 | 0 | auto& [pk_matrix, pivots] = pk_matrix_and_pivots.value(); |
55 | | |
56 | | // Key generation was successful - Create and return keys |
57 | 0 | return Classic_McEliece_KeyPair_Internal{ |
58 | 0 | .private_key = std::make_shared<Classic_McEliece_PrivateKeyInternal>( |
59 | 0 | params, std::move(seed), pivots, std::move(g.value()), std::move(field_ordering.value()), std::move(s)), |
60 | 0 | .public_key = std::make_shared<Classic_McEliece_PublicKeyInternal>(params, std::move(pk_matrix))}; |
61 | 0 | } |
62 | | |
63 | | } // namespace |
64 | | |
65 | | Classic_McEliece_PrivateKeyInternal Classic_McEliece_PrivateKeyInternal::from_bytes( |
66 | 0 | const Classic_McEliece_Parameters& params, std::span<const uint8_t> sk_bytes) { |
67 | 0 | BOTAN_ASSERT(sk_bytes.size() == params.sk_size_bytes(), "Valid private key size"); |
68 | 0 | BufferSlicer sk_slicer(sk_bytes); |
69 | |
|
70 | 0 | auto delta = sk_slicer.copy<CmceKeyGenSeed>(params.seed_len()); |
71 | 0 | auto c = CmceColumnSelection(sk_slicer.take(params.sk_c_bytes())); |
72 | 0 | auto g = Classic_McEliece_Minimal_Polynomial::from_bytes(sk_slicer.take(params.sk_poly_g_bytes()), params.poly_f()); |
73 | 0 | auto field_ordering = Classic_McEliece_Field_Ordering::create_from_control_bits( |
74 | 0 | params, secure_bitvector(sk_slicer.take(params.sk_alpha_control_bytes()))); |
75 | 0 | auto s = sk_slicer.copy<CmceRejectionSeed>(params.sk_s_bytes()); |
76 | 0 | BOTAN_ASSERT_NOMSG(sk_slicer.empty()); |
77 | |
|
78 | 0 | return Classic_McEliece_PrivateKeyInternal( |
79 | 0 | params, std::move(delta), std::move(c), std::move(g), std::move(field_ordering), std::move(s)); |
80 | 0 | } |
81 | | |
82 | 0 | secure_vector<uint8_t> Classic_McEliece_PrivateKeyInternal::serialize() const { |
83 | 0 | auto control_bits = m_field_ordering.alphas_control_bits(); |
84 | | |
85 | | /* NIST Impl. guide 6.1 Control-Bit Gen: |
86 | | * As low-cost protection against faults in the control-bit computation, implementors are advised |
87 | | * to check after the computation that applying the Benes network produces pi, and to |
88 | | * restart key generation if this test fails; applying the Benes network is very fast. |
89 | | * |
90 | | * Here, we just assert that applying the Benes network produces pi. |
91 | | */ |
92 | 0 | BOTAN_ASSERT(Classic_McEliece_Field_Ordering::create_from_control_bits(m_params, control_bits) |
93 | 0 | .ct_is_equal(m_field_ordering) |
94 | 0 | .as_bool(), |
95 | 0 | "Control Bit Computation Check"); |
96 | |
|
97 | 0 | return concat(m_delta.get(), m_c.get().to_bytes(), m_g.serialize(), control_bits.to_bytes(), m_s); |
98 | 0 | } |
99 | | |
100 | 0 | bool Classic_McEliece_PrivateKeyInternal::check_key() const { |
101 | 0 | auto prg = m_params.prg(m_delta); |
102 | |
|
103 | 0 | const auto s = prg->output<CmceRejectionSeed>(m_params.n() / 8); |
104 | 0 | const auto ordering_bits = prg->output<CmceOrderingBits>((m_params.sigma2() * m_params.q()) / 8); |
105 | 0 | const auto irreducible_bits = prg->output<CmceIrreducibleBits>((m_params.sigma1() * m_params.t()) / 8); |
106 | | |
107 | | // Recomputing s as hash of delta |
108 | 0 | auto ret = CT::Mask<size_t>::expand(CT::is_equal<uint8_t>(s.data(), m_s.data(), m_params.n() / 8)); |
109 | | |
110 | | // Checking weight of c |
111 | 0 | ret &= CT::Mask<size_t>::is_equal(c().hamming_weight(), 32); |
112 | |
|
113 | 0 | if(auto g = m_params.poly_ring().compute_minimal_polynomial(irreducible_bits)) { |
114 | 0 | for(size_t i = 0; i < g->degree() - 1; ++i) { |
115 | 0 | ret &= CT::Mask<size_t>::expand(GF_Mask::is_equal(g->coef_at(i), m_g.coef_at(i)).elem_mask()); |
116 | 0 | } |
117 | 0 | } else { |
118 | 0 | ret = CT::Mask<size_t>::cleared(); |
119 | 0 | } |
120 | | |
121 | | // Check alpha control bits |
122 | 0 | if(auto field_ord_from_seed = Classic_McEliece_Field_Ordering::create_field_ordering(m_params, ordering_bits)) { |
123 | 0 | field_ord_from_seed->permute_with_pivots(m_params, c()); |
124 | 0 | ret &= CT::Mask<size_t>::expand(field_ord_from_seed->ct_is_equal(field_ordering())); |
125 | 0 | } else { |
126 | 0 | ret = CT::Mask<size_t>::cleared(); |
127 | 0 | } |
128 | |
|
129 | 0 | return ret.as_bool(); |
130 | 0 | } |
131 | | |
132 | | std::shared_ptr<Classic_McEliece_PublicKeyInternal> Classic_McEliece_PublicKeyInternal::create_from_private_key( |
133 | 0 | const Classic_McEliece_PrivateKeyInternal& sk) { |
134 | 0 | auto pk_matrix_and_pivot = Classic_McEliece_Matrix::create_matrix(sk.params(), sk.field_ordering(), sk.g()); |
135 | 0 | if(!pk_matrix_and_pivot.has_value()) { |
136 | 0 | throw Decoding_Error("Cannot create public key from private key. Private key is invalid."); |
137 | 0 | } |
138 | 0 | auto& [pk_matrix, pivot] = pk_matrix_and_pivot.value(); |
139 | | |
140 | | // There should not be a pivot of any other form. Otherwise the gauss |
141 | | // algorithm failed effectively. |
142 | 0 | if(!CT::driveby_unpoison(pivot.equals(bitvector{0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}))) { |
143 | 0 | throw Decoding_Error("Cannot create public key from private key. Private key is invalid."); |
144 | 0 | } |
145 | | |
146 | 0 | return std::make_shared<Classic_McEliece_PublicKeyInternal>(sk.params(), std::move(pk_matrix)); |
147 | 0 | } |
148 | | |
149 | | Classic_McEliece_KeyPair_Internal Classic_McEliece_KeyPair_Internal::generate(const Classic_McEliece_Parameters& params, |
150 | 0 | StrongSpan<const CmceInitialSeed> seed) { |
151 | 0 | BOTAN_ASSERT_EQUAL(seed.size(), params.seed_len(), "Valid seed length"); |
152 | |
|
153 | 0 | CmceKeyGenSeed next_seed(seed.size()); |
154 | 0 | CmceKeyGenSeed current_seed(seed.begin(), seed.end()); |
155 | |
|
156 | 0 | while(true) { |
157 | 0 | if(auto keypair = try_generate_keypair(next_seed, params, std::move(current_seed))) { |
158 | 0 | return keypair.value(); |
159 | 0 | } |
160 | 0 | current_seed = next_seed; |
161 | 0 | } |
162 | 0 | } |
163 | | |
164 | | } // namespace Botan |