Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
sha256.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 "sha256.hpp"
8
13
14using namespace bb;
15
16namespace bb::stdlib {
17using namespace bb::plookup;
18
19constexpr size_t get_num_blocks(const size_t num_bits)
20{
21 constexpr size_t extra_bits = 65UL;
22
23 return ((num_bits + extra_bits) / 512UL) + ((num_bits + extra_bits) % 512UL > 0);
24}
25
26template <typename Builder> void SHA256<Builder>::prepare_constants(std::array<field_t<Builder>, 8>& input)
27{
28 for (size_t i = 0; i < 8; i++) {
29 input[i] = init_constants[i];
30 }
31}
32
33template <typename Builder>
35{
37
38 sparse_witness_limbs result(w);
39
40 const auto lookup = plookup_read<Builder>::get_lookup_accumulators(MultiTableId::SHA256_WITNESS_INPUT, w);
41
43 lookup[ColumnIdx::C2][0],
44 lookup[ColumnIdx::C2][1],
45 lookup[ColumnIdx::C2][2],
46 lookup[ColumnIdx::C2][3],
47 };
49 lookup[ColumnIdx::C3][0],
50 lookup[ColumnIdx::C3][1],
51 lookup[ColumnIdx::C3][2],
52 lookup[ColumnIdx::C3][3],
53 };
54 result.has_sparse_limbs = true;
55
56 return result;
57}
58
59template <typename Builder>
61{
63
64 Builder* ctx = w_in[0].get_context();
65
67 for (size_t i = 0; i < 16; ++i) {
68 w_sparse[i] = SHA256<Builder>::sparse_witness_limbs(w_in[i]);
69 if (!ctx && w_in[i].get_context()) {
70 ctx = w_in[i].get_context();
71 }
72 }
73
74 for (size_t i = 16; i < 64; ++i) {
75 auto& w_left = w_sparse[i - 15];
76 auto& w_right = w_sparse[i - 2];
77
78 if (!w_left.has_sparse_limbs) {
79 w_left = convert_witness(w_left.normal);
80 }
81 if (!w_right.has_sparse_limbs) {
82 w_right = convert_witness(w_right.normal);
83 }
84
86 w_left.sparse_limbs[0] * left_multipliers[0],
87 w_left.sparse_limbs[1] * left_multipliers[1],
88 w_left.sparse_limbs[2] * left_multipliers[2],
89 w_left.sparse_limbs[3] * left_multipliers[3],
90 };
91
93 w_right.sparse_limbs[0] * right_multipliers[0],
94 w_right.sparse_limbs[1] * right_multipliers[1],
95 w_right.sparse_limbs[2] * right_multipliers[2],
96 w_right.sparse_limbs[3] * right_multipliers[3],
97 };
98
99 const field_pt left_xor_sparse =
100 left[0].add_two(left[1], left[2]).add_two(left[3], w_left.rotated_limbs[1]) * fr(4);
101
102 const field_pt xor_result_sparse = right[0]
103 .add_two(right[1], right[2])
104 .add_two(right[3], w_right.rotated_limbs[2])
105 .add_two(w_right.rotated_limbs[3], left_xor_sparse);
106
108
109 // TODO NORMALIZE WITH RANGE CHECK
110
111 field_pt w_out_raw = xor_result.add_two(w_sparse[i - 16].normal, w_sparse[i - 7].normal);
112 field_pt w_out;
113 if (w_out_raw.is_constant()) {
114 w_out = field_pt(ctx, fr(w_out_raw.get_value().from_montgomery_form().data[0] & (uint64_t)0xffffffffULL));
115
116 } else {
117 w_out = witness_t<Builder>(
118 ctx, fr(w_out_raw.get_value().from_montgomery_form().data[0] & (uint64_t)0xffffffffULL));
119 static constexpr fr inv_pow_two = fr(2).pow(32).invert();
120 // If we multiply the field elements by constants separately and then subtract, then the divisor is
121 // going to be in a normalized state right after subtraction and the call to .normalize() won't add
122 // gates
123 field_pt w_out_raw_inv_pow_two = w_out_raw * inv_pow_two;
124 field_pt w_out_inv_pow_two = w_out * inv_pow_two;
125 field_pt divisor = w_out_raw_inv_pow_two - w_out_inv_pow_two;
126 divisor.create_range_constraint(3);
127 }
128
129 w_sparse[i] = sparse_witness_limbs(w_out);
130 }
131
132 std::array<field_pt, 64> w_extended;
133
134 for (size_t i = 0; i < 64; ++i) {
135 w_extended[i] = w_sparse[i].normal;
136 }
137 return w_extended;
138}
139
140template <typename Builder>
149
150template <typename Builder>
159
160template <typename Builder>
162{
164
166 const auto rotation_coefficients = sha256_tables::get_choose_rotation_multipliers();
167
168 field_pt rotation_result = lookup[ColumnIdx::C3][0];
169
170 e.sparse = lookup[ColumnIdx::C2][0];
171
172 field_pt sparse_limb_3 = lookup[ColumnIdx::C2][2];
173
174 // where is the middle limb used
175 field_pt xor_result = (rotation_result * fr(7))
176 .add_two(e.sparse * (rotation_coefficients[0] * fr(7) + fr(1)),
177 sparse_limb_3 * (rotation_coefficients[2] * fr(7)));
178
179 field_pt choose_result_sparse = xor_result.add_two(f.sparse + f.sparse, g.sparse + g.sparse + g.sparse);
180
181 field_pt choose_result = plookup_read<Builder>::read_from_1_to_2_table(SHA256_CH_OUTPUT, choose_result_sparse);
182
183 return choose_result;
184}
185
186template <typename Builder>
188{
190
192 const auto rotation_coefficients = sha256_tables::get_majority_rotation_multipliers();
193
194 field_pt rotation_result =
195 lookup[ColumnIdx::C3][0]; // last index of first row gives accumulating sum of "non-trival" wraps
196 a.sparse = lookup[ColumnIdx::C2][0];
197 // use these values to compute trivial wraps somehow
198 field_pt sparse_accumulator_2 = lookup[ColumnIdx::C2][1];
199
200 field_pt xor_result = (rotation_result * fr(4))
201 .add_two(a.sparse * (rotation_coefficients[0] * fr(4) + fr(1)),
202 sparse_accumulator_2 * (rotation_coefficients[1] * fr(4)));
203
204 field_pt majority_result_sparse = xor_result.add_two(b.sparse, c.sparse);
205
206 field_pt majority_result = plookup_read<Builder>::read_from_1_to_2_table(SHA256_MAJ_OUTPUT, majority_result_sparse);
207
208 return majority_result;
209}
210
211template <typename Builder>
213{
216
217 Builder* ctx = a.get_context() ? a.get_context() : b.get_context();
218
219 uint256_t sum = a.get_value() + b.get_value();
220
221 uint256_t normalized_sum = static_cast<uint32_t>(sum.data[0]);
222
223 if (a.is_constant() && b.is_constant()) {
224 return field_pt(ctx, normalized_sum);
225 }
226
227 field_pt overflow = witness_pt(ctx, fr((sum - normalized_sum) >> 32));
228
229 field_pt result = a.add_two(b, overflow * field_pt(ctx, -fr((uint64_t)(1ULL << 32ULL))));
230 // Has to be a byte?
231 overflow.create_range_constraint(3);
232 return result;
233}
234
247template <typename Builder>
249 const std::array<field_t<Builder>, 16>& input)
250{
260 sparse_value a = sparse_value(h_init[0]);
261 auto b = map_into_maj_sparse_form(h_init[1]);
262 auto c = map_into_maj_sparse_form(h_init[2]);
263 sparse_value d = sparse_value(h_init[3]);
264 sparse_value e = sparse_value(h_init[4]);
265 auto f = map_into_choose_sparse_form(h_init[5]);
266 auto g = map_into_choose_sparse_form(h_init[6]);
267 sparse_value h = sparse_value(h_init[7]);
268
272 const auto w = extend_witness(input);
273
277 // As opposed to standard sha description - Maj and Choose functions also include required rotations for round
278 for (size_t i = 0; i < 64; ++i) {
279 auto ch = choose(e, f, g);
280 auto maj = majority(a, b, c);
281 auto temp1 = ch.add_two(h.normal, w[i] + fr(round_constants[i]));
282
283 h = g;
284 g = f;
285 f = e;
286 e.normal = add_normalize(d.normal, temp1);
287 d = c;
288 c = b;
289 b = a;
290 a.normal = add_normalize(temp1, maj);
291 }
292
297 output[0] = add_normalize(a.normal, h_init[0]);
298 output[1] = add_normalize(b.normal, h_init[1]);
299 output[2] = add_normalize(c.normal, h_init[2]);
300 output[3] = add_normalize(d.normal, h_init[3]);
301 output[4] = add_normalize(e.normal, h_init[4]);
302 output[5] = add_normalize(f.normal, h_init[5]);
303 output[6] = add_normalize(g.normal, h_init[6]);
304 output[7] = add_normalize(h.normal, h_init[7]);
305
312 for (size_t i = 0; i < 8; i++) {
313 output[i].create_range_constraint(32);
314 }
315
316 return output;
317}
318
320template class SHA256<bb::MegaCircuitBuilder>;
321
322} // namespace bb::stdlib
static field_ct add_normalize(const field_ct &a, const field_ct &b)
Definition sha256.cpp:212
static std::array< field_ct, 64 > extend_witness(const std::array< field_ct, 16 > &w_in)
Definition sha256.cpp:60
static field_ct majority(sparse_value &a, const sparse_value &b, const sparse_value &c)
Definition sha256.cpp:187
static void prepare_constants(std::array< field_ct, 8 > &input)
Definition sha256.cpp:26
static field_ct choose(sparse_value &e, const sparse_value &f, const sparse_value &g)
Definition sha256.cpp:161
static sparse_value map_into_choose_sparse_form(const field_ct &e)
Definition sha256.cpp:141
static sparse_value map_into_maj_sparse_form(const field_ct &e)
Definition sha256.cpp:151
static sparse_witness_limbs convert_witness(const field_ct &w)
Definition sha256.cpp:34
static std::array< field_ct, 8 > sha256_block(const std::array< field_ct, 8 > &h_init, const std::array< field_ct, 16 > &input)
Apply the SHA-256 compression function to a single 512-bit message block.
Definition sha256.cpp:248
void create_range_constraint(size_t num_bits, std::string const &msg="field_t::range_constraint") const
Let x = *this.normalize(), constrain x.v < 2^{num_bits}.
Definition field.cpp:909
bb::fr get_value() const
Given a := *this, compute its value given by a.v * a.mul + a.add.
Definition field.cpp:828
bool is_constant() const
Definition field.hpp:429
field_t add_two(const field_t &add_b, const field_t &add_c) const
Efficiently compute (this + a + b) using big_mul gate.
Definition field.cpp:575
static plookup::ReadData< field_pt > get_lookup_accumulators(const plookup::MultiTableId id, const field_pt &key_a, const field_pt &key_b=0, const bool is_2_to_1_lookup=false)
Definition plookup.cpp:19
static field_pt read_from_1_to_2_table(const plookup::MultiTableId id, const field_pt &key_a)
Definition plookup.cpp:89
FF a
FF b
stdlib::witness_t< bb::UltraCircuitBuilder > witness_pt
stdlib::field_t< UltraCircuitBuilder > field_pt
std::array< bb::fr, 3 > get_choose_rotation_multipliers()
Definition sha256.hpp:189
std::array< bb::fr, 3 > get_majority_rotation_multipliers()
Definition sha256.hpp:164
@ SHA256_CH_INPUT
Definition types.hpp:83
@ SHA256_MAJ_OUTPUT
Definition types.hpp:86
@ SHA256_CH_OUTPUT
Definition types.hpp:84
@ SHA256_WITNESS_OUTPUT
Definition types.hpp:88
@ SHA256_MAJ_INPUT
Definition types.hpp:85
field_t< Builder > add_normalize(const field_t< Builder > &a, const field_t< Builder > &b)
void g(field_t< Builder > state[BLAKE_STATE_SIZE], size_t a, size_t b, size_t c, size_t d, field_t< Builder > x, field_t< Builder > y)
constexpr size_t get_num_blocks(const size_t num_bits)
Definition sha256.cpp:19
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
field< Bn254FrParams > fr
Definition fr.hpp:174
Inner sum(Cont< Inner, Args... > const &in)
Definition container.hpp:70
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
BB_INLINE constexpr field pow(const uint256_t &exponent) const noexcept
constexpr field invert() const noexcept
BB_INLINE constexpr field from_montgomery_form() const noexcept
std::array< field_ct, 4 > rotated_limbs
Definition sha256.hpp:83
std::array< field_ct, 4 > sparse_limbs
Definition sha256.hpp:81