barretenberg
Loading...
Searching...
No Matches
hmac.hpp
1#pragma once
2
3#include "barretenberg/common/serialize.hpp"
4#include "barretenberg/numeric/uintx/uintx.hpp"
5#include <algorithm>
6#include <array>
7#include <cstdint>
8#include <string>
9#include <vector>
10
11namespace crypto {
22template <typename Hash, typename MessageContainer, typename KeyContainer>
23std::array<uint8_t, Hash::OUTPUT_SIZE> hmac(const MessageContainer& message, const KeyContainer& key)
24{
25 constexpr size_t B = Hash::BLOCK_SIZE;
26 // ensures truncated_key fits into k_prime
27 static_assert(Hash::OUTPUT_SIZE <= B);
28 constexpr uint8_t IPAD_CONST = 0x36;
29 constexpr uint8_t OPAD_CONST = 0x5c;
30 std::array<uint8_t, B> ipad;
31 std::array<uint8_t, B> opad;
32 ipad.fill(IPAD_CONST);
33 opad.fill(OPAD_CONST);
34
35 // initialize k_prime to 0x00,...,0x00
36 // copy key or truncated key to start.
37 // TODO: securely erase `k_prime`
38 std::array<uint8_t, B> k_prime{};
39 if (key.size() > B) {
40 const auto truncated_key = Hash::hash(key);
41 std::copy(truncated_key.begin(), truncated_key.end(), k_prime.begin());
42 } else {
43 std::copy(key.begin(), key.end(), k_prime.begin());
44 }
45
46 // TODO: securely erase `h1`
47 std::array<uint8_t, B> h1;
48 for (size_t i = 0; i < B; ++i) {
49 h1[i] = k_prime[i] ^ opad[i];
50 }
51
52 // TODO: securely erase `h2`
53 std::array<uint8_t, B> h2;
54 for (size_t i = 0; i < B; ++i) {
55 h2[i] = k_prime[i] ^ ipad[i];
56 }
57
58 // TODO: securely erase copy of `h2` in `message_buffer`,
59 // ensure `message_buffer` is not re-allocated
60 std::vector<uint8_t> message_buffer;
61 std::copy(h2.begin(), h2.end(), std::back_inserter(message_buffer));
62 std::copy(message.begin(), message.end(), std::back_inserter(message_buffer));
63
64 const auto h3 = Hash::hash(message_buffer);
65
66 // TODO: securely erase copy of `h1` in `hmac_buffer`,
67 // ensure `hmac_buffer` is not re-allocated
68 std::vector<uint8_t> hmac_buffer;
69 std::copy(h1.begin(), h1.end(), std::back_inserter(hmac_buffer));
70 std::copy(h3.begin(), h3.end(), std::back_inserter(hmac_buffer));
71
72 const auto hmac_key = Hash::hash(hmac_buffer);
73
74 std::array<uint8_t, Hash::OUTPUT_SIZE> result;
75 std::copy(hmac_key.begin(), hmac_key.end(), result.begin());
76 return result;
77}
78
95template <typename Hash, typename Fr, typename MessageContainer, typename KeyContainer>
96Fr get_unbiased_field_from_hmac(const MessageContainer& message, const KeyContainer& key)
97 requires(Hash::OUTPUT_SIZE == 32)
98{
99 // Strong assumption that works for now with our suite of Hashers
100 static_assert(Hash::BLOCK_SIZE > Hash::OUTPUT_SIZE);
101 constexpr size_t DOMAIN_SEPARATOR_SIZE = Hash::BLOCK_SIZE - Hash::OUTPUT_SIZE;
102
103 // Domain separators whose size ensures we hash a block of the exact size expected by
104 // the Hasher.
105 constexpr std::array<uint8_t, DOMAIN_SEPARATOR_SIZE> KLO_DOMAIN_SEPARATOR{ 0x0 };
106 constexpr std::array<uint8_t, DOMAIN_SEPARATOR_SIZE> KHI_DOMAIN_SEPARATOR{ 0x1 };
107
108 auto input = hmac<Hash, MessageContainer, KeyContainer>(message, key);
109
110 // klo = H(00...0 || input)
111 std::vector<uint8_t> lo_buffer(KLO_DOMAIN_SEPARATOR.begin(), KLO_DOMAIN_SEPARATOR.end());
112 std::copy(input.begin(), input.end(), std::back_inserter(lo_buffer));
113 auto klo = Hash::hash(lo_buffer);
114
115 // khi = H(10...0 || input)
116 std::vector<uint8_t> hi_buffer(KHI_DOMAIN_SEPARATOR.begin(), KHI_DOMAIN_SEPARATOR.end());
117 std::copy(input.begin(), input.end(), std::back_inserter(hi_buffer));
118 auto khi = Hash::hash(hi_buffer);
119
120 // full_buffer = khi || klo
121 std::vector<uint8_t> full_buffer(khi.begin(), khi.end());
122 std::copy(klo.begin(), klo.end(), std::back_inserter(full_buffer));
123
124 auto field_as_u512 = from_buffer<numeric::uint512_t>(full_buffer);
125
126 Fr result((field_as_u512 % Fr::modulus).lo);
127 return result;
128}
129} // namespace crypto
Definition: aes128.cpp:9
std::array< uint8_t, Hash::OUTPUT_SIZE > hmac(const MessageContainer &message, const KeyContainer &key)
Compute an HMAC given a secret key and a message.
Definition: hmac.hpp:23
Fr get_unbiased_field_from_hmac(const MessageContainer &message, const KeyContainer &key)
Takes a size-HASH_OUTPUT buffer from HMAC and converts into a field element.
Definition: hmac.hpp:96