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
39TYPED_TEST(Sha256Test, BlockNistVectorOne)
40{
42
43 auto builder = Builder();
44
45 // SHA-256 initial hash values (FIPS 180-4 section 5.3.3)
46 constexpr std::array<uint32_t, 8> H_INIT = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
47 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 };
48
49 // Manually padded block for "abc" (FIPS 180-4 section 5.1.1)
50 // Message "abc" = 0x616263
51 // Pad: append 1 bit, then zeros, then 64-bit length
52 // Block: 0x61626380 00000000 ... 00000000 00000018
53 constexpr std::array<uint32_t, 16> PADDED_BLOCK = {
54 0x61626380, // "abc" + padding bit
55 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
56 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
57 0x00000018 // length in bits (24)
58 };
59
60 // Expected output: SHA-256("abc") from NIST
61 constexpr std::array<uint32_t, 8> EXPECTED = { 0xba7816bf, 0x8f01cfea, 0x414140de, 0x5dae2223,
62 0xb00361a3, 0x96177a9c, 0xb410ff61, 0xf20015ad };
63
64 // Verify native implementation first
65 auto native_output = crypto::sha256_block(H_INIT, PADDED_BLOCK);
66 for (size_t i = 0; i < 8; i++) {
67 EXPECT_EQ(native_output[i], EXPECTED[i]) << "Native mismatch at index " << i;
68 }
69
70 // Create circuit witnesses
72 for (size_t i = 0; i < 8; i++) {
73 h_init[i] = witness_ct(&builder, H_INIT[i]);
74 }
75
77 for (size_t i = 0; i < 16; i++) {
78 block[i] = witness_ct(&builder, PADDED_BLOCK[i]);
79 }
80
81 // Run circuit compression
82 auto circuit_output = SHA256<Builder>::sha256_block(h_init, block);
83
84 // Compare outputs
85 for (size_t i = 0; i < 8; i++) {
86 uint32_t circuit_val = static_cast<uint32_t>(uint256_t(circuit_output[i].get_value()));
87 EXPECT_EQ(circuit_val, EXPECTED[i]) << "Circuit mismatch at index " << i;
88 }
89
90 check_circuit_and_gate_count(builder, 6679);
91 EXPECT_EQ(builder.get_tables_size(), 35992);
92}
93
104TYPED_TEST(Sha256Test, BlockNistVectorTwo)
105{
107
108 auto builder = Builder();
109
110 // SHA-256 initial hash values
111 constexpr std::array<uint32_t, 8> H_INIT = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
112 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 };
113
114 // First block: first 64 bytes of padded message
115 // "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" = 56 bytes
116 // After padding bit, need second block for length
117 constexpr std::array<uint32_t, 16> BLOCK_1 = {
118 0x61626364, 0x62636465, 0x63646566, 0x64656667, // "abcd" "bcde" "cdef" "defg"
119 0x65666768, 0x66676869, 0x6768696a, 0x68696a6b, // "efgh" "fghi" "ghij" "hijk"
120 0x696a6b6c, 0x6a6b6c6d, 0x6b6c6d6e, 0x6c6d6e6f, // "ijkl" "jklm" "klmn" "lmno"
121 0x6d6e6f70, 0x6e6f7071, 0x80000000, 0x00000000 // "mnop" "nopq" + padding bit
122 };
123
124 // Second block: zeros + 64-bit length (448 bits = 0x1c0)
125 constexpr std::array<uint32_t, 16> BLOCK_2 = { 0x00000000, 0x00000000, 0x00000000, 0x00000000,
126 0x00000000, 0x00000000, 0x00000000, 0x00000000,
127 0x00000000, 0x00000000, 0x00000000, 0x00000000,
128 0x00000000, 0x00000000, 0x00000000, 0x000001c0 };
129
130 // Expected output from NIST
131 constexpr std::array<uint32_t, 8> EXPECTED = { 0x248d6a61, 0xd20638b8, 0xe5c02693, 0x0c3e6039,
132 0xa33ce459, 0x64ff2167, 0xf6ecedd4, 0x19db06c1 };
133
134 // Verify native implementation
135 auto h_after_block1 = crypto::sha256_block(H_INIT, BLOCK_1);
136 auto native_output = crypto::sha256_block(h_after_block1, BLOCK_2);
137 for (size_t i = 0; i < 8; i++) {
138 EXPECT_EQ(native_output[i], EXPECTED[i]) << "Native mismatch at index " << i;
139 }
140
141 // Circuit: first block
143 for (size_t i = 0; i < 8; i++) {
144 h_init[i] = witness_ct(&builder, H_INIT[i]);
145 }
146
148 for (size_t i = 0; i < 16; i++) {
149 block1[i] = witness_ct(&builder, BLOCK_1[i]);
150 }
151
152 auto h_mid = SHA256<Builder>::sha256_block(h_init, block1);
153
154 // Circuit: second block
156 for (size_t i = 0; i < 16; i++) {
157 block2[i] = witness_ct(&builder, BLOCK_2[i]);
158 }
159
160 auto circuit_output = SHA256<Builder>::sha256_block(h_mid, block2);
161
162 // Compare outputs
163 for (size_t i = 0; i < 8; i++) {
164 uint32_t circuit_val = static_cast<uint32_t>(uint256_t(circuit_output[i].get_value()));
165 EXPECT_EQ(circuit_val, EXPECTED[i]) << "Circuit mismatch at index " << i;
166 }
167
168 check_circuit_and_gate_count(builder, 10611);
169 EXPECT_EQ(builder.get_tables_size(), 35992);
170}
171
180TYPED_TEST(Sha256Test, ExtendWitnessTamperingFailure)
181{
183
185
186 auto builder = Builder();
188
189 // Create random input witnesses and ensure they are constrained
190 for (size_t i = 0; i < 16; i++) {
191 auto random32bits = engine.get_random_uint32();
192 field_ct elt(witness_ct(&builder, fr(random32bits)));
193 elt.fix_witness();
194 input[i] = elt;
195 }
196
197 // Extend the witness
199
200 // Verify circuit is initially valid
201 EXPECT_TRUE(CircuitChecker::check(builder));
202
203 // Try modifying each extended witness and verify circuit fails
204 bool any_modification_passed = false;
205 for (auto& single_extended_witness : w_ext) {
206 auto random32bits = engine.get_random_uint32();
207 uint32_t variable_index = single_extended_witness.get_witness_index();
208
209 // Ensure our random value is different from current
210 while (builder.get_variable(variable_index) == fr(random32bits)) {
211 random32bits = engine.get_random_uint32();
212 }
213
214 auto backup = builder.get_variable(variable_index);
215 builder.set_variable(variable_index, fr(random32bits));
216
217 // Circuit should fail with modified witness
219 any_modification_passed = true;
220 }
221
222 builder.set_variable(variable_index, backup);
223 }
224
225 // If any modification didn't cause failure, we have a problem
226 EXPECT_FALSE(any_modification_passed);
227}
#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:82
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:379
AluTraceBuilder builder
Definition alu.test.cpp:124
ECCVMCircuitBuilder Builder
numeric::RNG & engine
bn254::witness_ct witness_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:190
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(ShpleminiTest, TestSettings)
field< Bn254FrParams > fr
Definition fr.hpp:174
TYPED_TEST(ShpleminiTest, CorrectnessOfMultivariateClaimBatching)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
::testing::Types< UltraCircuitBuilder, MegaCircuitBuilder > BuilderTypes
#define STDLIB_TYPE_ALIASES