Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
sponge.hpp
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#pragma once
8
9#include <array>
10#include <cstddef>
11#include <cstdint>
12#include <span>
13
17
18namespace bb::stdlib {
19
34template <size_t rate, size_t capacity, size_t t, typename Permutation, typename Builder> class FieldSponge {
35 public:
43 enum Mode {
46 };
48
49 // sponge state. t = rate + capacity. capacity = 1 field element (~256 bits)
51
52 // cached elements that have been absorbed.
54 size_t cache_size = 0;
57
58 FieldSponge(Builder& builder_, field_t domain_iv = 0)
59 : builder(&builder_)
60 {
61 for (size_t i = 0; i < rate; ++i) {
63 }
64 state[rate] = witness_t<Builder>::create_constant_witness(builder, domain_iv.get_value());
65 }
66
68 {
69 // zero-pad the cache
70 for (size_t i = cache_size; i < rate; ++i) {
72 }
73 // add the cache into sponge state
74 for (size_t i = 0; i < rate; ++i) {
75 state[i] += cache[i];
76 }
78 // return `rate` number of field elements from the sponge state.
80 for (size_t i = 0; i < rate; ++i) {
81 output[i] = state[i];
82 }
83 // variables with indices from rate to size of state - 1 won't be used anymore
84 // after permutation. But they aren't dangerous and needed to put in used witnesses
85 if constexpr (IsUltraBuilder<Builder>) {
86 for (size_t i = rate; i < t; i++) {
87 builder->update_used_witnesses(state[i].witness_index);
88 }
89 }
90 return output;
91 }
92
93 void absorb(const field_t& input)
94 {
95 if (mode == Mode::ABSORB && cache_size == rate) {
96 // If we're absorbing, and the cache is full, apply the sponge permutation to compress the cache
98 cache[0] = input;
99 cache_size = 1;
100 } else if (mode == Mode::ABSORB && cache_size < rate) {
101 // If we're absorbing, and the cache is not full, add the input into the cache
102 cache[cache_size] = input;
103 cache_size += 1;
104 } else if (mode == Mode::SQUEEZE) {
105 // If we're in squeeze mode, switch to absorb mode and add the input into the cache.
106 // N.B. I don't think this code path can be reached?!
107 cache[0] = input;
108 cache_size = 1;
110 }
111 }
112
114 {
115 if (mode == Mode::SQUEEZE && cache_size == 0) {
116 // If we're in squeze mode and the cache is empty, there is nothing left to squeeze out of the sponge!
117 // Switch to absorb mode.
119 cache_size = 0;
120 }
121 if (mode == Mode::ABSORB) {
122 // If we're in absorb mode, apply sponge permutation to compress the cache, populate cache with compressed
123 // state and switch to squeeze mode. Note: this code block will execute if the previous `if` condition was
124 // matched
125 auto new_output_elements = perform_duplex();
127 for (size_t i = 0; i < rate; ++i) {
128 cache[i] = new_output_elements[i];
129 }
130 cache_size = rate;
131 }
132 // By this point, we should have a non-empty cache. Pop one item off the top of the cache and return it.
133 field_t result = cache[0];
134 for (size_t i = 1; i < cache_size; ++i) {
135 cache[i - 1] = cache[i];
136 }
137 cache_size -= 1;
139 return result;
140 }
141
150 template <size_t out_len>
152 {
153 size_t in_len = input.size();
154 const uint256_t iv = (static_cast<uint256_t>(in_len) << 64) + out_len - 1;
155 FieldSponge sponge(builder, iv);
156
157 for (size_t i = 0; i < in_len; ++i) {
158 BB_ASSERT_EQ(input[i].witness_index == IS_CONSTANT, false, "Sponge inputs should not be stdlib constants.");
159 sponge.absorb(input[i]);
160 }
161
163 for (size_t i = 0; i < out_len; ++i) {
164 output[i] = sponge.squeeze();
165 }
166 // variables with indices won't be used in the circuit.
167 // but they aren't dangerous and needed to put in used witnesses
168 if constexpr (IsUltraBuilder<Builder>) {
169 for (const auto& elem : sponge.cache) {
170 if (elem.witness_index != IS_CONSTANT) {
171 builder.update_used_witnesses(elem.witness_index);
172 }
173 }
174 }
175 return output;
176 }
177
179 {
180 return hash_internal<1>(builder, input)[0];
181 }
182};
183} // namespace bb::stdlib
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:59
Implements the circuit form of a cryptographic sponge over prime fields. Implements the sponge specif...
Definition sponge.hpp:34
std::array< field_t, t > state
Definition sponge.hpp:50
std::array< field_t, rate > cache
Definition sponge.hpp:53
static field_t hash_internal(Builder &builder, std::span< const field_t > input)
Definition sponge.hpp:178
std::array< field_t, rate > perform_duplex()
Definition sponge.hpp:67
void absorb(const field_t &input)
Definition sponge.hpp:93
Mode
Defines what phase of the sponge algorithm we are in.
Definition sponge.hpp:43
static std::array< field_t, out_len > hash_internal(Builder &builder, std::span< const field_t > input)
Use the sponge to hash an input string.
Definition sponge.hpp:151
FieldSponge(Builder &builder_, field_t domain_iv=0)
Definition sponge.hpp:58
static State permutation(Builder *builder, const State &input)
Circuit form of Poseidon2 permutation from https://eprint.iacr.org/2023/323.
static witness_t create_constant_witness(Builder *parent_context, const bb::fr &in)
Definition witness.hpp:45
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13