Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
keccak.test.cpp
Go to the documentation of this file.
2#include "../../primitives/plookup/plookup.hpp"
5#include "keccak.hpp"
6#include <gtest/gtest.h>
7
8using namespace bb;
9
15
16namespace {
18}
19
20TEST(stdlib_keccak, keccak_format_input_table)
21{
23
24 for (size_t i = 0; i < 25; ++i) {
25 uint64_t limb_native = engine.get_random_uint64();
26 field_ct limb(witness_ct(&builder, limb_native));
27
29
30 field_ct sparse_limb = accumulators[plookup::ColumnIdx::C2][0];
31 field_ct msb = accumulators[plookup::ColumnIdx::C3][accumulators[plookup::ColumnIdx::C3].size() - 1];
32
33 uint256_t expected_sparse = stdlib::keccak<Builder>::convert_to_sparse(limb_native);
34 uint64_t expected_msb = (limb_native >> 63) & 1ULL;
35
36 EXPECT_EQ(static_cast<uint256_t>(sparse_limb.get_value()), expected_sparse);
37 EXPECT_EQ(static_cast<uint64_t>(msb.get_value()), expected_msb);
38 }
39
40 bool proof_result = CircuitChecker::check(builder);
41 EXPECT_EQ(proof_result, true);
42}
43
44TEST(stdlib_keccak, keccak_format_output_table)
45{
47
48 for (size_t i = 0; i < 25; ++i) {
49 uint64_t limb_native = engine.get_random_uint64();
50 uint256_t extended_native = stdlib::keccak<Builder>::convert_to_sparse(limb_native);
51 field_ct limb(witness_ct(&builder, extended_native));
52
54 field_ct normalized_limb = accumulators[plookup::ColumnIdx::C2][0];
55 EXPECT_EQ(static_cast<uint256_t>(normalized_limb.get_value()), limb_native);
56 }
57 bool proof_result = CircuitChecker::check(builder);
58 EXPECT_EQ(proof_result, true);
59}
60
61TEST(stdlib_keccak, keccak_theta_output_table)
62{
64
65 for (size_t i = 0; i < 25; ++i) {
66 uint256_t extended_native = 0;
67 uint256_t expected_normalized = 0;
68 for (size_t j = 0; j < 8; ++j) {
69 extended_native *= 11;
70 expected_normalized *= 11;
71 uint64_t base_value = (engine.get_random_uint64() % 11);
72 uint64_t bit = base_value & 1;
73 extended_native += base_value;
74 expected_normalized += bit;
75 }
76
77 field_ct limb(witness_ct(&builder, extended_native));
79
80 EXPECT_EQ(static_cast<uint256_t>(normalized.get_value()), expected_normalized);
81 }
82
83 bool proof_result = CircuitChecker::check(builder);
84 EXPECT_EQ(proof_result, true);
85}
86
87TEST(stdlib_keccak, keccak_rho_output_table)
88{
90
91 constexpr_for<0, 25, 1>([&]<size_t i> {
92 uint256_t extended_native = 0;
93 uint256_t binary_native = 0;
94 for (size_t j = 0; j < 64; ++j) {
95 extended_native *= 11;
96 binary_native = binary_native << 1;
97 uint64_t base_value = (engine.get_random_uint64() % 3);
98 extended_native += base_value;
99 binary_native += (base_value & 1);
100 }
101 const size_t left_bits = stdlib::keccak<Builder>::ROTATIONS[i];
102 const size_t right_bits = 64 - left_bits;
103 const uint256_t left = binary_native >> right_bits;
104 const uint256_t right = binary_native - (left << right_bits);
105 const uint256_t binary_rotated = left + (right << left_bits);
106
107 const uint256_t expected_limb = stdlib::keccak<Builder>::convert_to_sparse(binary_rotated);
108 // msb is the MSB of the normalized limb without rotation
109 const uint256_t expected_msb = (binary_native >> 63);
110 field_ct limb(witness_ct(&builder, extended_native));
111 field_ct result_msb;
112 field_ct result_limb = stdlib::keccak<Builder>::normalize_and_rotate<i>(limb, result_msb);
113 EXPECT_EQ(static_cast<uint256_t>(result_limb.get_value()), expected_limb);
114 EXPECT_EQ(static_cast<uint256_t>(result_msb.get_value()), expected_msb);
115 });
116
117 info("num gates = ", builder.get_num_finalized_gates_inefficient());
118 bool proof_result = CircuitChecker::check(builder);
119 EXPECT_EQ(proof_result, true);
120}
121
122TEST(stdlib_keccak, keccak_chi_output_table)
123{
124 static constexpr uint64_t chi_normalization_table[5]{
125 0, // 1 + 2a - b + c => a xor (~b & c)
126 0, 1, 1, 0,
127 };
129
130 for (size_t i = 0; i < 25; ++i) {
131 uint256_t normalized_native = 0;
132 uint256_t extended_native = 0;
133 uint256_t binary_native = 0;
134 for (size_t j = 0; j < 8; ++j) {
135 extended_native *= 11;
136 normalized_native *= 11;
137 binary_native = binary_native << 1;
138 uint64_t base_value = (engine.get_random_uint64() % 5);
139 extended_native += base_value;
140 normalized_native += chi_normalization_table[base_value];
141 binary_native += chi_normalization_table[base_value];
142 }
143 field_ct limb(witness_ct(&builder, extended_native));
144 const auto accumulators =
146
147 field_ct normalized = accumulators[plookup::ColumnIdx::C2][0];
148 field_ct msb = accumulators[plookup::ColumnIdx::C3][accumulators[plookup::ColumnIdx::C3].size() - 1];
149
150 EXPECT_EQ(static_cast<uint256_t>(normalized.get_value()), normalized_native);
151 EXPECT_EQ(static_cast<uint256_t>(msb.get_value()), binary_native >> 63);
152 }
153 info("num gates = n", builder.get_num_finalized_gates_inefficient());
154 bool proof_result = CircuitChecker::check(builder);
155 EXPECT_EQ(proof_result, true);
156}
157
158// Matches the fuzzer logic
159TEST(stdlib_keccak, permutation_opcode)
160{
162
163 // Create a random state (25 lanes of 64 bits)
164 std::array<uint64_t, 25> native_state;
165 for (size_t i = 0; i < 25; ++i) {
166 native_state[i] = engine.get_random_uint64();
167 }
168
169 // Run native permutation
170 std::array<uint64_t, 25> expected_state = native_state;
171 ethash_keccakf1600(expected_state.data());
172
173 // Convert state to circuit field elements
174 std::array<field_ct, 25> circuit_state;
175 for (size_t i = 0; i < 25; i++) {
176 circuit_state[i] = witness_ct(&builder, native_state[i]);
177 }
178
179 // Run circuit permutation
180 auto circuit_output = stdlib::keccak<Builder>::permutation_opcode(circuit_state, &builder);
181
182 // Verify circuit correctness
183 bool proof_result = CircuitChecker::check(builder);
184 EXPECT_EQ(proof_result, true);
185
186 // Compare outputs
187 for (size_t i = 0; i < 25; i++) {
188 uint64_t circuit_value = static_cast<uint64_t>(circuit_output[i].get_value());
189 EXPECT_EQ(circuit_value, expected_state[i]);
190 }
191
192 info("num gates = ", builder.get_num_finalized_gates_inefficient());
193}
static bool check(const Builder &circuit)
Check the witness satisifies the circuit.
virtual uint64_t get_random_uint64()=0
Represents a dynamic array of bytes in-circuit.
bb::fr get_value() const
Given a := *this, compute its value given by a.v * a.mul + a.add.
Definition field.cpp:828
KECCAAAAAAAAAAK.
Definition keccak.hpp:25
static std::array< field_ct, NUM_KECCAK_LANES > permutation_opcode(std::array< field_ct, NUM_KECCAK_LANES > state, Builder *context)
Definition keccak.cpp:498
static constexpr uint256_t convert_to_sparse(uint256_t input)
Convert a binary integer into a base11 integer.
Definition keccak.hpp:65
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
void info(Args... args)
Definition log.hpp:89
AluTraceBuilder builder
Definition alu.test.cpp:124
void ethash_keccakf1600(uint64_t state[KECCAKF1600_LANES]) NOEXCEPT
numeric::RNG & engine
RNG & get_debug_randomness(bool reset, std::uint_fast64_t seed)
Definition engine.cpp:190
@ KECCAK_FORMAT_INPUT
Definition types.hpp:128
@ KECCAK_FORMAT_OUTPUT
Definition types.hpp:129
@ KECCAK_CHI_OUTPUT
Definition types.hpp:127
@ KECCAK_THETA_OUTPUT
Definition types.hpp:126
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
UltraCircuitBuilder_< UltraExecutionTraceBlocks > UltraCircuitBuilder
TEST(BoomerangMegaCircuitBuilder, BasicCircuit)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
stdlib::witness_t< Builder > witness_ct
UltraCircuitBuilder Builder