Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
blake2s.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: not started, auditors: [], date: YYYY-MM-DD }
3// external_1: { status: not started, auditors: [], date: YYYY-MM-DD }
4// external_2: { status: not started, auditors: [], date: YYYY-MM-DD }
5// =====================
6
7#include "blake_util.hpp"
8
11
19namespace bb::stdlib {
20
40template <typename Builder> void Blake2s<Builder>::increment_counter(blake2s_state& S, const uint32_t inc)
41{
42 field_ct inc_scalar(static_cast<uint256_t>(inc));
43
44 // Note that the initial blake2s_state values are circuit constants.
45 S.t[0] = S.t[0] + inc_scalar;
46
47 // Note that although blake2s_state is a circuit constant, we use designated functions such as
48 // `ranged_less_than` to enforce constraints as appropriate.
49 bool_ct to_inc = S.t[0].template ranged_less_than<32>(inc_scalar);
50 S.t[1] = S.t[1] + field_ct(to_inc);
51}
52
53template <typename Builder> void Blake2s<Builder>::compress(blake2s_state& S, byte_array_ct const& in)
54{
56 using namespace blake_util;
57 field_ct m[BLAKE2S_STATE_SIZE];
58 field_ct v[BLAKE2S_STATE_SIZE];
59
60 for (size_t i = 0; i < BLAKE2S_STATE_SIZE; ++i) {
61 m[i] = static_cast<field_ct>(in.slice(i * 4, 4).reverse());
62 }
63
64 for (size_t i = 0; i < 8; ++i) {
65 v[i] = S.h[i];
66 }
67
68 v[8] = field_ct(uint256_t(blake2s_IV[0]));
69 v[9] = field_ct(uint256_t(blake2s_IV[1]));
70 v[10] = field_ct(uint256_t(blake2s_IV[2]));
71 v[11] = field_ct(uint256_t(blake2s_IV[3]));
72
73 // Use the lookup tables to perform XORs
74 const auto lookup_1 =
76 v[12] = lookup_1[ColumnIdx::C3][0];
77 const auto lookup_2 =
79 v[13] = lookup_2[ColumnIdx::C3][0];
80 const auto lookup_3 =
82 v[14] = lookup_3[ColumnIdx::C3][0];
83 const auto lookup_4 =
85 v[15] = lookup_4[ColumnIdx::C3][0];
86
87 for (size_t idx = 0; idx < 10; idx++) {
88 blake_util::round_fn(v, m, idx);
89 }
90
91 // At this point in the algorithm, the elements (v0, v1, v2, v3) and (v8, v9, v10, v11) in the state matrix 'v' can
92 // be 'overflowed' i.e. contain values > 2^{32}. However we do NOT need to normalize them to be < 2^{32}, the
93 // following `read_sequence_from_table` calls correctly constrain the output to be 32-bits
94 for (size_t i = 0; i < 8; ++i) {
95 const auto lookup_a = plookup_read<Builder>::get_lookup_accumulators(BLAKE_XOR, S.h[i], v[i], true);
96 const auto lookup_b =
97 plookup_read<Builder>::get_lookup_accumulators(BLAKE_XOR, lookup_a[ColumnIdx::C3][0], v[i + 8], true);
98 S.h[i] = lookup_b[ColumnIdx::C3][0];
99 }
100}
101
102template <typename Builder> void Blake2s<Builder>::blake2s(blake2s_state& S, byte_array_ct const& in)
103{
104 using plookup::ColumnIdx;
105 using namespace blake_util;
106
107 size_t offset = 0;
108 size_t size = in.size();
109
110 while (size > BLAKE2S_BLOCKBYTES) {
111 increment_counter(S, BLAKE2S_BLOCKBYTES);
112 compress(S, in.slice(offset, BLAKE2S_BLOCKBYTES));
113 offset += BLAKE2S_BLOCKBYTES;
114 size -= BLAKE2S_BLOCKBYTES;
115 }
116
117 // Set last block.
118 S.f[0] = field_t<Builder>(uint256_t((uint32_t)-1));
119
120 // Build final block: remaining input + constant padding
121 Builder* ctx = in.get_context();
122 auto remaining = in.slice(offset);
123
124 // Combine remaining bytes and constant padding (no constraints needed for constants)
125 byte_array_ct final = remaining; // Copy constrained remaining bytes
126 byte_array_ct padding = byte_array_ct::constant_padding(ctx, BLAKE2S_BLOCKBYTES - size);
127 final.write(padding);
128
129 increment_counter(S, static_cast<uint32_t>(size));
130 compress(S, final);
131}
132
133template <typename Builder> byte_array<Builder> Blake2s<Builder>::hash(const byte_array_ct& input)
134{
136
137 for (size_t i = 0; i < 8; i++) {
138 S.h[i] = field_ct(uint256_t(initial_H[i]));
139 }
140
141 blake2s(S, input);
142
143 // Build result from state values
145 for (const auto& h : S.h) {
146 // byte_array_ct(field, num_bytes) constructor adds range constraints for each byte
147 byte_array_ct v(h, 4);
148 auto reversed = v.reverse();
149 result.write(reversed);
150 }
151 return result;
152}
153
154template class Blake2s<UltraCircuitBuilder>;
155template class Blake2s<MegaCircuitBuilder>;
156
157} // namespace bb::stdlib
static void compress(blake2s_state &S, byte_array_ct const &in)
Definition blake2s.cpp:53
static void blake2s(blake2s_state &S, byte_array_ct const &in)
Definition blake2s.cpp:102
static byte_array_ct hash(const byte_array_ct &input)
Definition blake2s.cpp:133
static void increment_counter(blake2s_state &S, const uint32_t inc)
Definition blake2s.cpp:40
Implements boolean logic in-circuit.
Definition bool.hpp:59
Represents a dynamic array of bytes in-circuit.
byte_array slice(size_t offset) const
Slice bytes from the byte array starting at offset. Does not add any constraints.
byte_array reverse() const
Reverse the bytes in the byte array.
byte_array & write(byte_array const &other)
Appends the contents of another byte_array (other) to the end of this one.
size_t size() const
Builder * get_context() const
static byte_array constant_padding(Builder *parent_context, size_t num_bytes, uint8_t value=0)
WASM_EXPORT void blake2s(uint8_t const *data, out_buf32 out)
Definition c_bind.cpp:13
ssize_t offset
Definition engine.cpp:36
stdlib::field_t< Builder > field_ct
void round_fn(field_t< Builder > state[BLAKE_STATE_SIZE], field_t< Builder > msg[BLAKE_STATE_SIZE], size_t round, const bool which_blake=false)
std::vector< uint8_t > compress(const std::vector< uint8_t > &input)
field_t< Builder > f[2]
Definition blake2s.hpp:35
field_t< Builder > t[2]
Definition blake2s.hpp:34
field_t< Builder > h[8]
Definition blake2s.hpp:33