3#include "../../commitment/pedersen/pedersen.hpp"
4#include "../../hash/blake3s/blake3s.hpp"
5#include "../../primitives/bigfield/bigfield.hpp"
6#include "../../primitives/biggroup/biggroup.hpp"
7#include "../../primitives/bool/bool.hpp"
8#include "../../primitives/curves/bn254.hpp"
9#include "../../primitives/field/field.hpp"
10#include "../../primitives/witness/witness.hpp"
11#include "../verification_key/verification_key.hpp"
12#include "barretenberg/ecc/curves/bn254/fq.hpp"
13#include "barretenberg/ecc/curves/bn254/fr.hpp"
14#include "barretenberg/ecc/curves/bn254/g1.hpp"
15#include "barretenberg/plonk/transcript/transcript.hpp"
17namespace proof_system::plonk::stdlib::recursion {
28 , transcript_base(input_manifest, transcript::HashType::PedersenBlake3s, 16)
29 , current_challenge(in_context)
33 const std::vector<uint8_t>& input_transcript,
36 , transcript_base(input_transcript, input_manifest, transcript::HashType::PedersenBlake3s, 16)
37 , current_challenge(in_context)
59 const std::vector<field_pt>& field_buffer,
60 const size_t num_public_inputs)
62 , transcript_base(input_manifest, transcript::HashType::PedersenBlake3s, 16)
63 , current_challenge(in_context)
67 const auto num_rounds = input_manifest.get_num_rounds();
68 for (
size_t i = 0; i < num_rounds; ++i) {
69 for (
auto manifest_element : input_manifest.get_round_manifest(i).elements) {
70 if (!manifest_element.derived_by_verifier) {
71 if (manifest_element.num_bytes == 32 && manifest_element.name !=
"public_inputs") {
72 add_field_element(manifest_element.name, field_buffer[count++]);
73 }
else if (manifest_element.num_bytes == 64 && manifest_element.name !=
"public_inputs") {
74 const auto x_lo = field_buffer[count++];
75 const auto x_hi = field_buffer[count++];
76 const auto y_lo = field_buffer[count++];
77 const auto y_hi = field_buffer[count++];
81 add_group_element(manifest_element.name,
element);
83 ASSERT(manifest_element.name ==
"public_inputs");
84 std::vector<field_pt> public_inputs;
85 for (
size_t i = 0; i < num_public_inputs; ++i) {
86 public_inputs.emplace_back(field_buffer[count++]);
88 add_field_element_vector(manifest_element.name, public_inputs);
97 int check_field_element_cache(
const std::string& element_name)
const
99 for (
size_t i = 0; i < field_keys.size(); ++i) {
100 if (field_keys[i] == element_name) {
101 return static_cast<int>(i);
107 int check_field_element_vector_cache(
const std::string& element_name)
const
109 for (
size_t i = 0; i < field_vector_keys.size(); ++i) {
110 if (field_vector_keys[i] == element_name) {
111 return static_cast<int>(i);
117 int check_group_element_cache(
const std::string& element_name)
const
119 for (
size_t i = 0; i < group_keys.size(); ++i) {
120 if (group_keys[i] == element_name) {
121 return static_cast<int>(i);
127 int check_challenge_cache(
const std::string& challenge_name,
const size_t challenge_idx)
const
129 for (
size_t i = 0; i < challenge_keys.size(); ++i) {
130 if (challenge_keys[i] == challenge_name) {
131 ASSERT(challenge_values[i].size() > challenge_idx);
132 return static_cast<int>(i);
138 void add_field_element(
const std::string& element_name,
const field_pt& element)
140 std::vector<uint8_t> buffer = element.get_value().to_buffer();
144 std::vector<uint8_t> sliced_buffer(buffer.end() - (std::ptrdiff_t)element_size, buffer.end());
145 transcript_base.add_element(element_name, sliced_buffer);
146 field_keys.push_back(element_name);
147 field_values.push_back(element);
150 void add_group_element(
const std::string& element_name,
const group_pt& element)
155 transcript_base.add_element(element_name, converted.to_buffer());
156 group_keys.push_back(element_name);
157 group_values.push_back(element);
160 void add_field_element_vector(
const std::string& element_name,
const std::vector<field_pt>& elements)
162 std::vector<barretenberg::fr> values;
163 for (
size_t i = 0; i < elements.size(); ++i) {
164 values.push_back(elements[i].get_value());
166 transcript_base.add_element(element_name, to_buffer(values));
167 field_vector_keys.push_back(element_name);
168 field_vector_values.push_back(elements);
171 void apply_fiat_shamir(
const std::string& challenge_name)
173 const size_t num_challenges = get_manifest().get_round_manifest(current_round).num_challenges;
176 if (num_challenges == 0) {
180 field_pt working_element(context);
185 static constexpr size_t NUM_BITS_PER_PREIMAGE_ELEMENT = 31UL * 8UL;
186 PedersenPreimageBuilder<Builder, NUM_BITS_PER_PREIMAGE_ELEMENT> preimage_buffer(context);
187 if (current_round > 0) {
188 preimage_buffer.add_element(current_challenge);
190 for (
auto manifest_element : get_manifest().get_round_manifest(current_round).elements) {
191 if (manifest_element.num_bytes == 32 && manifest_element.name !=
"public_inputs") {
192 preimage_buffer.add_element(get_field_element(manifest_element.name));
193 }
else if (manifest_element.num_bytes == 64 && manifest_element.name !=
"public_inputs") {
194 group_pt point = get_circuit_group_element(manifest_element.name);
198 const auto& x = point.x;
199 const auto& y = point.y;
200 constexpr size_t last_limb_bits = 256 - (fq_pt::NUM_LIMB_BITS * 3);
201 preimage_buffer.add_element_with_existing_range_constraint(y.binary_basis_limbs[3].element,
203 preimage_buffer.add_element_with_existing_range_constraint(y.binary_basis_limbs[2].element,
204 fq_pt::NUM_LIMB_BITS);
205 preimage_buffer.add_element_with_existing_range_constraint(y.binary_basis_limbs[1].element,
206 fq_pt::NUM_LIMB_BITS);
207 preimage_buffer.add_element_with_existing_range_constraint(y.binary_basis_limbs[0].element,
208 fq_pt::NUM_LIMB_BITS);
209 preimage_buffer.add_element_with_existing_range_constraint(x.binary_basis_limbs[3].element,
211 preimage_buffer.add_element_with_existing_range_constraint(x.binary_basis_limbs[2].element,
212 fq_pt::NUM_LIMB_BITS);
213 preimage_buffer.add_element_with_existing_range_constraint(x.binary_basis_limbs[1].element,
214 fq_pt::NUM_LIMB_BITS);
215 preimage_buffer.add_element_with_existing_range_constraint(x.binary_basis_limbs[0].element,
216 fq_pt::NUM_LIMB_BITS);
218 }
else if (manifest_element.name ==
"public_inputs") {
219 std::vector<field_pt> field_array = get_field_element_vector(manifest_element.name);
220 for (
size_t i = 0; i < field_array.size(); ++i) {
221 preimage_buffer.add_element(field_array[i]);
223 }
else if (manifest_element.num_bytes < 32 && manifest_element.name !=
"public_inputs") {
225 preimage_buffer.add_element_with_existing_range_constraint(get_field_element(manifest_element.name),
226 manifest_element.num_bytes * 8);
229 std::vector<field_pt> round_challenges_new;
232 T0 = preimage_buffer.hash();
235 const auto slice_into_halves = [&](
const field_pt& in,
const size_t low_bits = 128) {
240 field_pt y_lo = field_pt::from_witness(context, lo);
241 field_pt y_hi = field_pt::from_witness(context, hi);
243 y_lo.create_range_constraint(low_bits);
244 y_hi.create_range_constraint(254 - low_bits);
246 in.add_two(-y_lo, -y_hi * (
uint256_t(1) << low_bits)).assert_equal(0);
249 constexpr uint256_t modulus = fr::modulus;
250 const field_pt r_lo = field_pt(context, modulus.
slice(0, low_bits));
251 const field_pt r_hi = field_pt(context, modulus.
slice(low_bits, 256));
254 field_pt borrow = field_pt::from_witness(context, need_borrow);
258 context->create_new_range_constraint(borrow.get_witness_index(), 1,
"borrow");
260 context->create_range_constraint(borrow.get_witness_index(), 1,
"borrow");
265 field_pt res_hi = (r_hi - y_hi) - borrow;
266 field_pt res_lo = (r_lo - y_lo) + (borrow * (
uint256_t(1) << low_bits));
268 res_hi.create_range_constraint(modulus.get_msb() + 1 - low_bits);
269 res_lo.create_range_constraint(low_bits);
271 return std::array<field_pt, 2>{ y_lo, y_hi };
274 field_pt base_hash = stdlib::pedersen_hash<Builder>::hash(std::vector<field_pt>{ T0 }, 0);
275 auto hash_halves = slice_into_halves(base_hash);
276 round_challenges_new.push_back(hash_halves[1]);
278 if (num_challenges > 1) {
279 round_challenges_new.push_back(hash_halves[0]);
281 base_hash = (slice_into_halves(base_hash, 8)[1] * 256).normalize();
286 for (
size_t i = 2; i < num_challenges; i += 2) {
288 field_pt hash_output = stdlib::pedersen_hash<Builder>::hash(
289 std::vector<field_pt>{ (base_hash + field_pt(i / 2)).normalize() }, 0);
290 auto hash_halves = slice_into_halves(hash_output);
291 round_challenges_new.push_back(hash_halves[1]);
292 if (i + 1 < num_challenges) {
293 round_challenges_new.push_back(hash_halves[0]);
296 current_challenge = round_challenges_new[round_challenges_new.size() - 1];
298 challenge_keys.push_back(challenge_name);
300 std::vector<field_pt> challenge_elements;
301 for (
const auto& challenge : round_challenges_new) {
302 challenge_elements.push_back(challenge);
304 challenge_values.push_back(challenge_elements);
307 field_pt get_field_element(
const std::string& element_name)
const
309 const int cache_idx = check_field_element_cache(element_name);
310 if (cache_idx != -1) {
311 return field_values[
static_cast<size_t>(cache_idx)];
314 barretenberg::fr::serialize_from_buffer(&(transcript_base.
get_element(element_name))[0]);
315 field_pt result(witness_pt(context, value));
316 field_keys.push_back(element_name);
317 field_values.push_back(result);
321 std::vector<field_pt> get_field_element_vector(
const std::string& element_name)
const
323 const int cache_idx = check_field_element_vector_cache(element_name);
324 if (cache_idx != -1) {
325 return field_vector_values[
static_cast<size_t>(cache_idx)];
327 std::vector<barretenberg::fr> values = many_from_buffer<fr>(transcript_base.
get_element(element_name));
328 std::vector<field_pt> result;
330 for (
auto& value : values) {
331 result.push_back(witness_pt(context, value));
334 field_vector_keys.push_back(element_name);
335 field_vector_values.push_back(result);
339 bool has_challenge(
const std::string& challenge_name)
const
344 field_pt get_challenge_field_element(
const std::string& challenge_name,
const size_t challenge_idx = 0)
const
346 const int cache_idx = check_challenge_cache(challenge_name, challenge_idx);
347 ASSERT(cache_idx != -1);
348 return challenge_values[
static_cast<size_t>(cache_idx)][challenge_idx];
351 field_pt get_challenge_field_element_from_map(
const std::string& challenge_name,
352 const std::string& challenge_map_name)
const
355 if (challenge_idx == -1) {
356 return field_pt(
nullptr, 1);
358 const int cache_idx = check_challenge_cache(challenge_name,
static_cast<size_t>(challenge_idx));
359 ASSERT(cache_idx != -1);
360 return challenge_values[
static_cast<size_t>(cache_idx)][
static_cast<size_t>(challenge_idx)];
366 barretenberg::g1::affine_element::serialize_from_buffer(&(transcript_base.
get_element(element_name))[0]);
370 group_pt get_circuit_group_element(
const std::string& element_name)
const
372 int cache_idx = check_group_element_cache(element_name);
373 if (cache_idx != -1) {
374 return group_values[
static_cast<size_t>(cache_idx)];
377 barretenberg::g1::affine_element::serialize_from_buffer(&(transcript_base.
get_element(element_name))[0]);
378 group_pt result = convert_g1(context, value);
379 group_keys.push_back(element_name);
380 group_values.push_back(result);
384 static fq_pt convert_fq(
Builder* ctx,
const barretenberg::fq& input) {
return fq_pt::from_witness(ctx, input); };
388 return group_pt::from_witness(ctx, input);
391 size_t get_num_challenges(
const std::string& challenge_name)
const
400 field_pt current_challenge;
402 mutable std::vector<std::string> field_vector_keys;
403 mutable std::vector<std::vector<field_pt>> field_vector_values;
405 mutable std::vector<std::string> field_keys;
406 mutable std::vector<field_pt> field_values;
408 mutable std::vector<std::string> group_keys;
409 mutable std::vector<group_pt> group_values;
411 std::vector<std::string> challenge_keys;
412 std::vector<std::vector<field_pt>> challenge_values;
414 size_t current_round = 0;
Definition: affine_element.hpp:11
Definition: uint256.hpp:25
constexpr uint256_t slice(uint64_t start, uint64_t end) const
Definition: uint256_impl.hpp:157
Definition: standard_circuit_builder.hpp:12
Definition: biggroup.hpp:22
Definition: transcript.hpp:18
Transcript(Builder *in_context, const transcript::Manifest &input_manifest, const std::vector< field_pt > &field_buffer, const size_t num_public_inputs)
Construct a new Transcript object using a proof represented as a field_pt vector.
Definition: transcript.hpp:57
Definition: witness.hpp:10
Definition: manifest.hpp:11
Definition: transcript.hpp:34
std::vector< uint8_t > get_element(const std::string &element_name) const
Definition: transcript.cpp:392
size_t get_num_challenges(const std::string &challenge_name) const
Definition: transcript.cpp:377
int get_challenge_index_from_map(const std::string &challenge_map_name) const
Definition: transcript.cpp:324
bool has_challenge(const std::string &challenge_name) const
Definition: transcript.cpp:337
void apply_fiat_shamir(const std::string &challenge_name)
Definition: transcript.cpp:171
size_t get_element_size(const std::string &element_name) const
Definition: transcript.cpp:405
Contains all the headers required to adequately compile the types defined in circuit_builders_fwd....
Definition: circuit_builders.hpp:11
Definition: verification_key.hpp:235