Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
sha256.test.cpp
Go to the documentation of this file.
1#include "sha256.hpp"
9
10using namespace bb;
11using namespace bb::stdlib;
12
13namespace {
15}
16
17#define STDLIB_TYPE_ALIASES \
18 using Builder = TypeParam; \
19 using field_ct = field_t<Builder>; \
20 using witness_ct = witness_t<Builder>;
21
22template <class Builder> class Sha256Test : public ::testing::Test {};
23
24using BuilderTypes = ::testing::Types<bb::UltraCircuitBuilder, bb::MegaCircuitBuilder>;
26
28
29// Common test data: SHA-256 initial hash values (FIPS 180-4 section 5.3.3)
30constexpr std::array<uint32_t, 8> SHA256_IV = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
31 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 };
32
33// Padded block for "abc" (FIPS 180-4 section 5.1.1)
34constexpr std::array<uint32_t, 16> ABC_PADDED_BLOCK = { 0x61626380, 0x00000000, 0x00000000, 0x00000000,
35 0x00000000, 0x00000000, 0x00000000, 0x00000000,
36 0x00000000, 0x00000000, 0x00000000, 0x00000000,
37 0x00000000, 0x00000000, 0x00000000, 0x00000018 };
38
39// Expected output: SHA-256("abc") from NIST
40constexpr std::array<uint32_t, 8> ABC_EXPECTED = { 0xba7816bf, 0x8f01cfea, 0x414140de, 0x5dae2223,
41 0xb00361a3, 0x96177a9c, 0xb410ff61, 0xf20015ad };
42
53TYPED_TEST(Sha256Test, BlockNistVectorOne)
54{
56
58
59 // Verify native implementation first
60 auto native_output = crypto::sha256_block(SHA256_IV, ABC_PADDED_BLOCK);
61 for (size_t i = 0; i < 8; i++) {
62 EXPECT_EQ(native_output[i], ABC_EXPECTED[i]) << "Native mismatch at index " << i;
63 }
64
65 // Create circuit witnesses
67 for (size_t i = 0; i < 8; i++) {
68 h_init[i] = witness_ct(&builder, SHA256_IV[i]);
69 }
70
72 for (size_t i = 0; i < 16; i++) {
73 block[i] = witness_ct(&builder, ABC_PADDED_BLOCK[i]);
74 }
75
76 // Run circuit compression
77 auto circuit_output = SHA256<Builder>::sha256_block(h_init, block);
78
79 // Compare outputs
80 for (size_t i = 0; i < 8; i++) {
81 uint32_t circuit_val = static_cast<uint32_t>(uint256_t(circuit_output[i].get_value()));
82 EXPECT_EQ(circuit_val, ABC_EXPECTED[i]) << "Circuit mismatch at index " << i;
83 }
84
85 check_circuit_and_gate_count(builder, 6702);
86 EXPECT_EQ(builder.get_tables_size(), 35992);
87}
88
99TYPED_TEST(Sha256Test, BlockNistVectorTwo)
100{
102
104
105 constexpr std::array<uint32_t, 16> BLOCK_1 = {
106 0x61626364, 0x62636465, 0x63646566, 0x64656667, // "abcd" "bcde" "cdef" "defg"
107 0x65666768, 0x66676869, 0x6768696a, 0x68696a6b, // "efgh" "fghi" "ghij" "hijk"
108 0x696a6b6c, 0x6a6b6c6d, 0x6b6c6d6e, 0x6c6d6e6f, // "ijkl" "jklm" "klmn" "lmno"
109 0x6d6e6f70, 0x6e6f7071, 0x80000000, 0x00000000 // "mnop" "nopq" + padding bit
110 };
111
112 constexpr std::array<uint32_t, 16> BLOCK_2 = { 0x00000000, 0x00000000, 0x00000000, 0x00000000,
113 0x00000000, 0x00000000, 0x00000000, 0x00000000,
114 0x00000000, 0x00000000, 0x00000000, 0x00000000,
115 0x00000000, 0x00000000, 0x00000000, 0x000001c0 };
116
117 constexpr std::array<uint32_t, 8> EXPECTED = { 0x248d6a61, 0xd20638b8, 0xe5c02693, 0x0c3e6039,
118 0xa33ce459, 0x64ff2167, 0xf6ecedd4, 0x19db06c1 };
119
120 // Verify native implementation
121 auto h_after_block1 = crypto::sha256_block(SHA256_IV, BLOCK_1);
122 auto native_output = crypto::sha256_block(h_after_block1, BLOCK_2);
123 for (size_t i = 0; i < 8; i++) {
124 EXPECT_EQ(native_output[i], EXPECTED[i]) << "Native mismatch at index " << i;
125 }
126
127 // Circuit: first block
129 for (size_t i = 0; i < 8; i++) {
130 h_init[i] = witness_ct(&builder, SHA256_IV[i]);
131 }
132
134 for (size_t i = 0; i < 16; i++) {
135 block1[i] = witness_ct(&builder, BLOCK_1[i]);
136 }
137
138 auto h_mid = SHA256<Builder>::sha256_block(h_init, block1);
139
140 // Circuit: second block
142 for (size_t i = 0; i < 16; i++) {
143 block2[i] = witness_ct(&builder, BLOCK_2[i]);
144 }
145
146 auto circuit_output = SHA256<Builder>::sha256_block(h_mid, block2);
147
148 // Compare outputs
149 for (size_t i = 0; i < 8; i++) {
150 uint32_t circuit_val = static_cast<uint32_t>(uint256_t(circuit_output[i].get_value()));
151 EXPECT_EQ(circuit_val, EXPECTED[i]) << "Circuit mismatch at index " << i;
152 }
153
154 check_circuit_and_gate_count(builder, 10646);
155 EXPECT_EQ(builder.get_tables_size(), 35992);
156}
157
164TYPED_TEST(Sha256Test, BlockAllConstants)
165{
166 using Builder = TypeParam;
168
170
171 // Create all inputs as constants (with builder context)
173 for (size_t i = 0; i < 8; i++) {
174 h_init[i] = field_ct(&builder, SHA256_IV[i]);
175 ASSERT_TRUE(h_init[i].is_constant());
176 }
177
179 for (size_t i = 0; i < 16; i++) {
180 block[i] = field_ct(&builder, ABC_PADDED_BLOCK[i]);
181 ASSERT_TRUE(block[i].is_constant());
182 }
183
184 auto circuit_output = SHA256<Builder>::sha256_block(h_init, block);
185
186 for (size_t i = 0; i < 8; i++) {
187 uint32_t circuit_val = static_cast<uint32_t>(uint256_t(circuit_output[i].get_value()));
188 EXPECT_EQ(circuit_val, ABC_EXPECTED[i]) << "All-constant mismatch at index " << i;
189 }
190
191 check_circuit_and_gate_count(builder, 0);
192 EXPECT_EQ(builder.get_tables_size(), 0);
193}
194
203TYPED_TEST(Sha256Test, BlockConstantHinitWitnessInput)
204{
206
208
210 for (size_t i = 0; i < 8; i++) {
211 h_init[i] = field_ct(&builder, SHA256_IV[i]);
212 }
213
215 for (size_t i = 0; i < 16; i++) {
216 block[i] = witness_ct(&builder, ABC_PADDED_BLOCK[i]);
217 }
218
219 auto circuit_output = SHA256<Builder>::sha256_block(h_init, block);
220
221 for (size_t i = 0; i < 8; i++) {
222 uint32_t circuit_val = static_cast<uint32_t>(uint256_t(circuit_output[i].get_value()));
223 EXPECT_EQ(circuit_val, ABC_EXPECTED[i]) << "Constant h_init mismatch at index " << i;
224 }
225
226 check_circuit_and_gate_count(builder, 6650);
227 EXPECT_EQ(builder.get_tables_size(), 35992);
228}
229
238TYPED_TEST(Sha256Test, BlockWitnessHinitConstantInput)
239{
241
243
245 for (size_t i = 0; i < 8; i++) {
246 h_init[i] = witness_ct(&builder, SHA256_IV[i]);
247 }
248
250 for (size_t i = 0; i < 16; i++) {
251 block[i] = field_ct(&builder, ABC_PADDED_BLOCK[i]);
252 }
253
254 auto circuit_output = SHA256<Builder>::sha256_block(h_init, block);
255
256 for (size_t i = 0; i < 8; i++) {
257 uint32_t circuit_val = static_cast<uint32_t>(uint256_t(circuit_output[i].get_value()));
258 EXPECT_EQ(circuit_val, ABC_EXPECTED[i]) << "Witness h_init mismatch at index " << i;
259 }
260
261 check_circuit_and_gate_count(builder, 5523);
262 EXPECT_EQ(builder.get_tables_size(), 15120);
263}
264
273TYPED_TEST(Sha256Test, BlockMixedConstantsAndWitnesses)
274{
276
278
279 // Even-indexed = constant, odd-indexed = witness
281 for (size_t i = 0; i < 8; i++) {
282 if (i % 2 == 0) {
283 h_init[i] = field_ct(&builder, SHA256_IV[i]);
284 } else {
285 h_init[i] = witness_ct(&builder, SHA256_IV[i]);
286 }
287 }
288
290 for (size_t i = 0; i < 16; i++) {
291 if (i % 2 == 0) {
292 block[i] = field_ct(&builder, ABC_PADDED_BLOCK[i]);
293 } else {
294 block[i] = witness_ct(&builder, ABC_PADDED_BLOCK[i]);
295 }
296 }
297
298 auto circuit_output = SHA256<Builder>::sha256_block(h_init, block);
299
300 for (size_t i = 0; i < 8; i++) {
301 uint32_t circuit_val = static_cast<uint32_t>(uint256_t(circuit_output[i].get_value()));
302 EXPECT_EQ(circuit_val, ABC_EXPECTED[i]) << "Mixed mismatch at index " << i;
303 }
304
305 check_circuit_and_gate_count(builder, 6644);
306 EXPECT_EQ(builder.get_tables_size(), 35992);
307}
308
316TYPED_TEST(Sha256Test, ExtendWitnessMixedInputs)
317{
319
321
322 // Make first and last words witnesses, rest constants
324 for (size_t i = 0; i < 16; i++) {
325 if (i == 0 || i == 15) {
326 input[i] = witness_ct(&builder, ABC_PADDED_BLOCK[i]);
327 } else {
328 input[i] = field_ct(&builder, ABC_PADDED_BLOCK[i]);
329 }
330 }
331
332 // Compute circuit extension
334
335 // Compute native extension for comparison
336 std::array<uint32_t, 64> w_native;
337 for (size_t i = 0; i < 16; i++) {
338 w_native[i] = ABC_PADDED_BLOCK[i];
339 }
340 for (size_t i = 16; i < 64; i++) {
341 uint32_t s0 = std::rotr(w_native[i - 15], 7) ^ std::rotr(w_native[i - 15], 18) ^ (w_native[i - 15] >> 3);
342 uint32_t s1 = std::rotr(w_native[i - 2], 17) ^ std::rotr(w_native[i - 2], 19) ^ (w_native[i - 2] >> 10);
343 w_native[i] = w_native[i - 16] + s0 + w_native[i - 7] + s1;
344 }
345
346 // Verify all 64 words match
347 for (size_t i = 0; i < 64; i++) {
348 uint32_t circuit_val = static_cast<uint32_t>(uint256_t(w_ext[i].get_value()));
349 EXPECT_EQ(circuit_val, w_native[i]) << "extend_witness mismatch at index " << i;
350 }
351
352 check_circuit_and_gate_count(builder, 3815);
353 EXPECT_EQ(builder.get_tables_size(), 20872);
354}
355
364TYPED_TEST(Sha256Test, ExtendWitnessTamperingFailure)
365{
367
369
372
373 // Create random input witnesses and ensure they are constrained
374 for (size_t i = 0; i < 16; i++) {
375 auto random32bits = engine.get_random_uint32();
376 field_ct elt(witness_ct(&builder, fr(random32bits)));
377 elt.fix_witness();
378 input[i] = elt;
379 }
380
381 // Extend the witness
383
384 // Verify circuit is initially valid
385 EXPECT_TRUE(CircuitChecker::check(builder));
386
387 // Try modifying each extended witness and verify circuit fails
388 bool any_modification_passed = false;
389 for (auto& single_extended_witness : w_ext) {
390 auto random32bits = engine.get_random_uint32();
391 uint32_t variable_index = single_extended_witness.get_witness_index();
392
393 // Ensure our random value is different from current
394 while (builder.get_variable(variable_index) == fr(random32bits)) {
395 random32bits = engine.get_random_uint32();
396 }
397
398 auto backup = builder.get_variable(variable_index);
399 builder.set_variable(variable_index, fr(random32bits));
400
401 // Circuit should fail with modified witness
403 any_modification_passed = true;
404 }
405
406 builder.set_variable(variable_index, backup);
407 }
408
409 // If any modification didn't cause failure, we have a problem
410 EXPECT_FALSE(any_modification_passed);
411}
#define BB_DISABLE_ASSERTS()
Definition assert.hpp:33
static bool check(const Builder &circuit)
Check the witness satisifies the circuit.
virtual uint32_t get_random_uint32()=0
static std::array< field_ct, 64 > extend_witness(const std::array< field_ct, 16 > &w_in)
Extend the 16-word message block to 64 words per SHA-256 specification.
Definition sha256.cpp:83
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:333
AluTraceBuilder builder
Definition alu.test.cpp:124
numeric::RNG & engine
stdlib::witness_t< Builder > witness_ct
stdlib::field_t< Builder > field_ct
std::array< uint32_t, 8 > sha256_block(const std::array< uint32_t, 8 > &h_init, const std::array< uint32_t, 16 > &input)
SHA-256 compression function (FIPS 180-4 Section 6.2.2)
Definition sha256.cpp:73
RNG & get_debug_randomness(bool reset, std::uint_fast64_t seed)
Definition engine.cpp:245
void check_circuit_and_gate_count(Builder &builder, uint32_t expected_gates_without_base)
Utility function for gate count checking and circuit verification.
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
TYPED_TEST_SUITE(CommitmentKeyTest, Curves)
field< Bn254FrParams > fr
Definition fr.hpp:155
TYPED_TEST(CommitmentKeyTest, CommitToZeroPoly)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
::testing::Types< UltraCircuitBuilder, MegaCircuitBuilder > BuilderTypes
#define STDLIB_TYPE_ALIASES
constexpr std::array< uint32_t, 8 > ABC_EXPECTED
constexpr std::array< uint32_t, 8 > SHA256_IV
constexpr std::array< uint32_t, 16 > ABC_PADDED_BLOCK