Skip to content
This repository was archived by the owner on Feb 17, 2025. It is now read-only.

Commit 2b84621

Browse files
author
Ilias Khairullin
committed
Rfc6979-specific version of hmac_drbg draft implementation added. #3
1 parent 1b3a950 commit 2b84621

File tree

4 files changed

+479
-0
lines changed

4 files changed

+479
-0
lines changed

CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ target_link_libraries(${CMAKE_WORKSPACE_NAME}_${CURRENT_PROJECT_NAME} INTERFACE
3939
crypto3::hash
4040
crypto3::mac
4141
crypto3::stream
42+
marshalling::crypto3_algebra
4243

4344
${Boost_LIBRARIES})
4445
target_include_directories(${CMAKE_WORKSPACE_NAME}_${CURRENT_PROJECT_NAME} INTERFACE
+303
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
1+
//---------------------------------------------------------------------------//
2+
// Copyright (c) 2021 Mikhail Komarov <[email protected]>
3+
// Copyright (c) 2021 Ilias Khairullin <[email protected]>
4+
//
5+
// MIT License
6+
//
7+
// Permission is hereby granted, free of charge, to any person obtaining a copy
8+
// of this software and associated documentation files (the "Software"), to deal
9+
// in the Software without restriction, including without limitation the rights
10+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
// copies of the Software, and to permit persons to whom the Software is
12+
// furnished to do so, subject to the following conditions:
13+
//
14+
// The above copyright notice and this permission notice shall be included in all
15+
// copies or substantial portions of the Software.
16+
//
17+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23+
// SOFTWARE.
24+
//---------------------------------------------------------------------------//
25+
26+
#ifndef CRYPTO3_RANDOM_HMAC_DRBG_HPP
27+
#define CRYPTO3_RANDOM_HMAC_DRBG_HPP
28+
29+
#include <type_traits>
30+
#include <ostream>
31+
#include <istream>
32+
#include <bitset>
33+
34+
#include <boost/random/detail/seed.hpp>
35+
36+
#include <nil/crypto3/mac/hmac.hpp>
37+
#include <nil/crypto3/mac/algorithm/compute.hpp>
38+
39+
#include <nil/crypto3/algebra/marshalling.hpp>
40+
#include <nil/marshalling/field_type.hpp>
41+
#include <nil/crypto3/marshalling/types/integral.hpp>
42+
#include <nil/crypto3/marshalling/types/algebra/field_element.hpp>
43+
44+
#include <nil/crypto3/detail/type_traits.hpp>
45+
#include <nil/crypto3/algebra/type_traits.hpp>
46+
#include <nil/crypto3/detail/pack.hpp>
47+
48+
namespace nil {
49+
namespace crypto3 {
50+
namespace random {
51+
// TODO: extend this rfc6979-specific version of HMAC_DRBG
52+
// (https://datatracker.ietf.org/doc/html/rfc6979#section-3.2) according to
53+
// https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf
54+
//
55+
// TODO: fix reseed
56+
template<typename ResultType, typename Hash, typename = void>
57+
struct rfc6979;
58+
59+
template<typename ResultType, typename Hash>
60+
struct rfc6979<
61+
ResultType,
62+
Hash,
63+
typename std::enable_if<algebra::is_field<typename ResultType::field_type>::value &&
64+
!algebra::is_extended_field<typename ResultType::field_type>::value>::type> {
65+
typedef Hash hash_type;
66+
typedef mac::hmac<hash_type> hmac_policy;
67+
typedef mac::mac_key<hmac_policy> key_type;
68+
typedef ResultType result_type;
69+
typedef result_type field_value_type;
70+
typedef typename result_type::field_type field_type;
71+
typedef typename field_type::modular_type modular_type;
72+
typedef typename field_type::integral_type integral_type;
73+
typedef typename hash_type::digest_type digest_type;
74+
typedef mac::computation_accumulator_set<mac::computation_policy<hmac_policy>>
75+
internal_accumulator_type;
76+
77+
typedef ::nil::crypto3::marshalling::types::
78+
field_element<::nil::marshalling::field_type<::nil::marshalling::option::big_endian>, field_type>
79+
marshalling_field_element_be_type;
80+
typedef ::nil::crypto3::marshalling::types::
81+
integral<::nil::marshalling::field_type<::nil::marshalling::option::big_endian>, integral_type>
82+
marshalling_integral_value_be_type;
83+
typedef ::nil::crypto3::marshalling::types::
84+
integral<::nil::marshalling::field_type<::nil::marshalling::option::little_endian>, integral_type>
85+
marshalling_integral_value_le_type;
86+
87+
constexpr static std::size_t modulus_bits = field_type::modulus_bits;
88+
constexpr static std::size_t modulus_octets =
89+
modulus_bits / 8 + static_cast<std::size_t>(modulus_bits % 8 != 0);
90+
constexpr static std::size_t digest_bits = hmac_policy::digest_bits;
91+
constexpr static std::size_t digest_octets =
92+
digest_bits / 8 + static_cast<std::size_t>(digest_bits % 8 != 0);
93+
constexpr static std::size_t digest_chunks =
94+
modulus_bits / digest_bits + static_cast<std::size_t>(modulus_bits % digest_bits != 0);
95+
96+
typedef std::array<std::uint8_t, modulus_octets> modulus_octets_container_type;
97+
98+
static_assert(
99+
std::is_same<std::uint8_t,
100+
typename std::iterator_traits<typename digest_type::iterator>::value_type>::value,
101+
"Hash output value type is not uint8_t");
102+
103+
explicit rfc6979(const result_type& x, const digest_type& h1) {
104+
seed(x, h1);
105+
}
106+
107+
static inline modulus_octets_container_type int2octets(const field_value_type& x) {
108+
marshalling_field_element_be_type marshalling_field_element_be =
109+
::nil::crypto3::marshalling::types::fill_field_element<field_type,
110+
::nil::marshalling::option::big_endian>(
111+
x);
112+
modulus_octets_container_type modulus_octet_container;
113+
auto it = modulus_octet_container.begin();
114+
marshalling_field_element_be.template write(it, modulus_octets);
115+
return modulus_octet_container;
116+
}
117+
118+
// TODO: move to marshalling
119+
// TODO: creating of new vector is a bottleneck
120+
template<typename InputRange,
121+
typename ValueType = typename std::iterator_traits<typename InputRange::iterator>::value_type,
122+
typename std::enable_if<std::is_unsigned<ValueType>::value, bool>::type = true>
123+
static inline std::vector<ValueType> adjust_bitstring(InputRange& range) {
124+
// TODO: local_char_bits is supposed to equal chunk_size from import_bits call in marshalling
125+
constexpr std::size_t local_char_bits = 8;
126+
constexpr std::size_t adjustment_shift = modulus_octets * local_char_bits - modulus_bits;
127+
constexpr std::size_t bits_remain = local_char_bits - adjustment_shift;
128+
constexpr std::size_t chunk_size = std::numeric_limits<ValueType>::digits;
129+
using bitset_repr_type = std::bitset<chunk_size>;
130+
131+
auto carry_bits = [&](bitset_repr_type& current_bits,
132+
const bitset_repr_type& carried_bits) -> bitset_repr_type {
133+
bitset_repr_type new_carried_bits;
134+
135+
for (auto i = 0; i < adjustment_shift; ++i) {
136+
new_carried_bits.set(adjustment_shift - 1 - i, current_bits[adjustment_shift - 1 - i]);
137+
}
138+
current_bits >>= adjustment_shift;
139+
for (auto i = 0; i < adjustment_shift; ++i) {
140+
current_bits.set(local_char_bits - 1 - i, carried_bits[adjustment_shift - 1 - i]);
141+
}
142+
143+
return new_carried_bits;
144+
};
145+
146+
std::vector<ValueType> result;
147+
bitset_repr_type carried_bits;
148+
149+
for (const auto v : range) {
150+
bitset_repr_type v_bitset_repr(v);
151+
carried_bits = carry_bits(v_bitset_repr, carried_bits);
152+
result.template emplace_back(static_cast<ValueType>(v_bitset_repr.to_ullong()));
153+
}
154+
bitset_repr_type v_bitset_repr;
155+
carry_bits(v_bitset_repr, carried_bits);
156+
result.template emplace_back(static_cast<ValueType>(v_bitset_repr.to_ullong()));
157+
158+
return result;
159+
}
160+
161+
template<
162+
typename InputRange,
163+
typename std::enable_if<
164+
std::is_same<std::uint8_t,
165+
typename std::iterator_traits<typename InputRange::iterator>::value_type>::value,
166+
bool>::type = true>
167+
static inline integral_type bits2int(const InputRange& range) {
168+
integral_type result;
169+
if (modulus_bits < range.size() * 8) {
170+
auto adjusted_range = adjust_bitstring(range);
171+
marshalling_integral_value_be_type marshalling_integral_value_be;
172+
auto it = adjusted_range.cbegin();
173+
marshalling_integral_value_be.template read(it, modulus_octets);
174+
result = marshalling_integral_value_be.value();
175+
std::cout << result << std::endl;
176+
} else {
177+
// TODO: check correctness of this case
178+
marshalling_integral_value_le_type marshalling_integral_value_le;
179+
auto it = range.crbegin();
180+
marshalling_integral_value_le.template read(it, range.size());
181+
result = marshalling_integral_value_le.value();
182+
}
183+
return result;
184+
}
185+
186+
template<typename InputRange>
187+
static inline modulus_octets_container_type bits2octets(const InputRange &range) {
188+
field_value_type z2(bits2int(range));
189+
return int2octets(z2);
190+
}
191+
192+
inline void seed(const result_type& x, const digest_type& h1) {
193+
// b.
194+
std::fill(V.begin(), V.end(), 1);
195+
196+
// c.
197+
digest_type K;
198+
std::fill(K.begin(), K.end(), 0);
199+
Key = key_type(K);
200+
201+
// d.
202+
internal_accumulator_type acc_d(Key);
203+
compute<hmac_policy>(V, acc_d);
204+
compute<hmac_policy>(std::array<std::uint8_t, 1> {0}, acc_d);
205+
// int2octets(x)
206+
marshalling_field_element_be_type marshalling_field_element =
207+
::nil::crypto3::marshalling::types::fill_field_element<field_type,
208+
::nil::marshalling::option::big_endian>(
209+
x);
210+
modulus_octets_container_type modulus_octet_container;
211+
marshalling_field_element.template write(modulus_octet_container.begin(), modulus_octets);
212+
compute<hmac_policy>(modulus_octet_container, acc_d);
213+
compute<hmac_policy>(h1, acc_d);
214+
Key = key_type(
215+
::nil::crypto3::accumulators::extract::mac<mac::computation_policy<hmac_policy>>(acc_d));
216+
217+
// e.
218+
internal_accumulator_type acc_e(Key);
219+
compute<hmac_policy>(V, acc_e);
220+
V = ::nil::crypto3::accumulators::extract::mac<mac::computation_policy<hmac_policy>>(acc_e);
221+
222+
// f.
223+
internal_accumulator_type acc_f(Key);
224+
compute<hmac_policy>(V, acc_f);
225+
compute<hmac_policy>(std::array<std::uint8_t, 1> {1}, acc_f);
226+
compute<hmac_policy>(modulus_octet_container, acc_f);
227+
compute<hmac_policy>(h1, acc_f);
228+
Key = key_type(
229+
::nil::crypto3::accumulators::extract::mac<mac::computation_policy<hmac_policy>>(acc_f));
230+
231+
// g.
232+
internal_accumulator_type acc_g(Key);
233+
compute<hmac_policy>(V, acc_g);
234+
V = ::nil::crypto3::accumulators::extract::mac<mac::computation_policy<hmac_policy>>(acc_g);
235+
}
236+
237+
inline result_type operator()() {
238+
// h.
239+
do {
240+
std::vector<std::uint8_t> T;
241+
242+
// h.2.
243+
for (auto i = 0; i < digest_chunks; i++) {
244+
digest_type T_temp = compute<hmac_policy>(V, Key);
245+
std::copy(T_temp.cbegin(), T_temp.cend(), std::back_inserter(T));
246+
}
247+
248+
// h.3.
249+
// TODO: use marshalling
250+
integral_type k;
251+
::nil::crypto3::multiprecision::import_bits(k, T.begin(), T.begin() + modulus_octets, 8, false);
252+
if (1 < k && k < field_type::modulus) {
253+
return k;
254+
}
255+
256+
// marshalling_field_element_type marshalling_field_element;
257+
// marshalling_field_element.read(T.begin(), modulus_octets);
258+
// return crypto3::marshalling::types::construct_field_element<field_type, endianness>(
259+
// marshalling_field_element);
260+
} while (true);
261+
}
262+
263+
// inline void discard(std::size_t n) {
264+
// if (n > 0 && !cached) {
265+
// operator()();
266+
// }
267+
// }
268+
//
269+
// inline bool operator==(const hash& other) const {
270+
// return state == other.state;
271+
// }
272+
//
273+
// inline bool operator!=(const hash& other) const {
274+
// return !(*this == other);
275+
// }
276+
//
277+
// /** Writes a rfc6979 to a @c std::ostream */
278+
// template<class CharT, class Traits>
279+
// friend std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os,
280+
// const algebraic_engine& e) {
281+
// os << e.state;
282+
// return os;
283+
// }
284+
//
285+
// /** Reads a rfc6979 from a @c std::istream */
286+
// template<class CharT, class Traits>
287+
// friend std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& is,
288+
// algebraic_engine& e) {
289+
// input_type x;
290+
// is >> x;
291+
// e.seed(x);
292+
// return is;
293+
// }
294+
295+
protected:
296+
digest_type V;
297+
key_type Key;
298+
};
299+
} // namespace random
300+
} // namespace crypto3
301+
} // namespace nil
302+
303+
#endif // CRYPTO3_RANDOM_HMAC_DRBG_HPP

test/CMakeLists.txt

+4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ cm_test_link_libraries(${CMAKE_WORKSPACE_NAME}_${CURRENT_PROJECT_NAME}
1818
${CMAKE_WORKSPACE_NAME}::mac
1919
${CMAKE_WORKSPACE_NAME}::stream
2020
${CMAKE_WORKSPACE_NAME}::multiprecision
21+
marshalling::crypto3_algebra
2122

2223
${Boost_LIBRARIES})
2324

@@ -35,4 +36,7 @@ set_target_properties(${CURRENT_PROJECT_NAME}_hash_test PROPERTIES CXX_STANDARD
3536
cm_test(NAME ${CURRENT_PROJECT_NAME}_algebraic_engine_test SOURCES ${CURRENT_TEST_SOURCES_DIR}/algebraic_engine.cpp)
3637
set_target_properties(${CURRENT_PROJECT_NAME}_algebraic_engine_test PROPERTIES CXX_STANDARD 17)
3738

39+
cm_test(NAME ${CURRENT_PROJECT_NAME}_rfc6979_engine_test SOURCES ${CURRENT_TEST_SOURCES_DIR}/rfc6979.cpp)
40+
set_target_properties(${CURRENT_PROJECT_NAME}_rfc6979_engine_test PROPERTIES CXX_STANDARD 17)
41+
3842
include_directories(${CMAKE_WORKSPACE_SOURCES_DIR})

0 commit comments

Comments
 (0)