barretenberg
Loading...
Searching...
No Matches
recursive_circuit.hpp
1#pragma once
2#include "barretenberg/ecc/curves/bn254/fq12.hpp"
3#include "barretenberg/ecc/curves/bn254/pairing.hpp"
4#include "barretenberg/plonk/composer/ultra_composer.hpp"
5#include "barretenberg/plonk/proof_system/proving_key/serialize.hpp"
6#include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders_fwd.hpp"
7#include "barretenberg/stdlib/primitives/curves/bn254.hpp"
8#include "barretenberg/stdlib/recursion/verifier/program_settings.hpp"
9#include "barretenberg/stdlib/recursion/verifier/verifier.hpp"
10#include "barretenberg/transcript/transcript.hpp"
11
12using namespace proof_system::plonk;
13using namespace stdlib;
15
16template <typename OuterBuilder> class RecursiveCircuit {
18 using InnerBuilder = typename InnerComposer::CircuitBuilder;
19
22
26
32
33 using inner_scalar_field = typename inner_curve::ScalarFieldNative;
34 using outer_scalar_field = typename outer_curve::BaseFieldNative;
36 static constexpr bool is_ultra_to_ultra = std::is_same_v<OuterBuilder, proof_system::UltraCircuitBuilder>;
37 using ProverOfInnerCircuit =
38 std::conditional_t<is_ultra_to_ultra, plonk::UltraProver, plonk::UltraToStandardProver>;
39 using VerifierOfInnerProof =
40 std::conditional_t<is_ultra_to_ultra, plonk::UltraVerifier, plonk::UltraToStandardVerifier>;
41 using RecursiveSettings =
42 std::conditional_t<is_ultra_to_ultra, recursive_settings, ultra_to_standard_recursive_settings>;
43
44 struct circuit_outputs {
46 std::shared_ptr<verification_key_pt> verification_key;
47 };
48
49 static void create_inner_circuit_no_tables(InnerBuilder& builder, uint256_t public_inputs[])
50 {
51 // A nice Pythagorean triples circuit example: "I know a & b s.t. a^2 + b^2 = c^2".
52 inner_scalar_field_ct a(witness_ct(&builder, public_inputs[0]));
53 inner_scalar_field_ct b(witness_ct(&builder, public_inputs[1]));
54 inner_scalar_field_ct c(witness_ct(&builder, public_inputs[2]));
55
56 auto c_sq = c * c;
57
58 (c).assert_equal(a + b);
59
60 c_sq.set_public();
61 };
62
63 static circuit_outputs create_outer_circuit(InnerBuilder& inner_circuit, OuterBuilder& outer_builder)
64 {
65 ProverOfInnerCircuit prover;
66 InnerComposer inner_composer;
67 if constexpr (is_ultra_to_ultra) {
68 prover = inner_composer.create_prover(inner_circuit);
69 } else {
70 prover = inner_composer.create_ultra_to_standard_prover(inner_circuit);
71 }
72
73 const auto verification_key_native = inner_composer.compute_verification_key(inner_circuit);
74 // Convert the verification key's elements into _circuit_ types, using the OUTER composer.
75 std::shared_ptr<verification_key_pt> verification_key =
76 verification_key_pt::from_witness(&outer_builder, verification_key_native);
77
78 plonk::proof proof_to_recursively_verify = prover.construct_proof();
79
80 {
81 // Native check is mainly for comparison vs circuit version of the verifier.
82 VerifierOfInnerProof native_verifier;
83
84 if constexpr (is_ultra_to_ultra) {
85 native_verifier = inner_composer.create_verifier(inner_circuit);
86 } else {
87 native_verifier = inner_composer.create_ultra_to_standard_verifier(inner_circuit);
88 }
89
90 auto native_result = native_verifier.verify_proof(proof_to_recursively_verify);
91 if (native_result == false) {
92 throw_or_abort("Native verification failed");
93 }
94 }
95
96 transcript::Manifest recursive_manifest = InnerComposer::create_manifest(prover.key->num_public_inputs);
97
98 auto output = recursion::verify_proof<outer_curve, RecursiveSettings>(
99 &outer_builder, verification_key, recursive_manifest, proof_to_recursively_verify);
100
101 return { output, verification_key };
102 };
103
104 static bool check_recursive_proof_public_inputs(OuterBuilder& builder,
106 {
107 if (builder.contains_recursive_proof && builder.recursive_proof_public_input_indices.size() == 16) {
108 const auto& inputs = builder.public_inputs;
109 const auto recover_fq_from_public_inputs =
110 [&inputs, &builder](const size_t idx0, const size_t idx1, const size_t idx2, const size_t idx3) {
111 const uint256_t l0 = builder.get_variable(inputs[idx0]);
112 const uint256_t l1 = builder.get_variable(inputs[idx1]);
113 const uint256_t l2 = builder.get_variable(inputs[idx2]);
114 const uint256_t l3 = builder.get_variable(inputs[idx3]);
115
116 const uint256_t limb = l0 + (l1 << NUM_LIMB_BITS_IN_FIELD_SIMULATION) +
117 (l2 << (NUM_LIMB_BITS_IN_FIELD_SIMULATION * 2)) +
118 (l3 << (NUM_LIMB_BITS_IN_FIELD_SIMULATION * 3));
119 return outer_scalar_field(limb);
120 };
121
122 const auto x0 = recover_fq_from_public_inputs(builder.recursive_proof_public_input_indices[0],
123 builder.recursive_proof_public_input_indices[1],
124 builder.recursive_proof_public_input_indices[2],
125 builder.recursive_proof_public_input_indices[3]);
126 const auto y0 = recover_fq_from_public_inputs(builder.recursive_proof_public_input_indices[4],
127 builder.recursive_proof_public_input_indices[5],
128 builder.recursive_proof_public_input_indices[6],
129 builder.recursive_proof_public_input_indices[7]);
130 const auto x1 = recover_fq_from_public_inputs(builder.recursive_proof_public_input_indices[8],
131 builder.recursive_proof_public_input_indices[9],
132 builder.recursive_proof_public_input_indices[10],
133 builder.recursive_proof_public_input_indices[11]);
134 const auto y1 = recover_fq_from_public_inputs(builder.recursive_proof_public_input_indices[12],
135 builder.recursive_proof_public_input_indices[13],
136 builder.recursive_proof_public_input_indices[14],
137 builder.recursive_proof_public_input_indices[15]);
138 g1::affine_element P_affine[2]{
139 { x0, y0 },
140 { x1, y1 },
141 };
142
143 pairing_target_field result =
144 barretenberg::pairing::reduced_ate_pairing_batch_precomputed(P_affine, lines, 2);
145
146 return (result == pairing_target_field::one());
147 }
148 if (builder.contains_recursive_proof && builder.recursive_proof_public_input_indices.size() != 16) {
149 return false;
150 }
151 return true;
152 }
153 static void check_pairing(const circuit_outputs& circuit_output)
154 {
155 auto g2_lines = barretenberg::srs::get_crs_factory()->get_verifier_crs()->get_precomputed_g2_lines();
157 P[0].x = outer_scalar_field(circuit_output.aggregation_state.P0.x.get_value().lo);
158 P[0].y = outer_scalar_field(circuit_output.aggregation_state.P0.y.get_value().lo);
159 P[1].x = outer_scalar_field(circuit_output.aggregation_state.P1.x.get_value().lo);
160 P[1].y = outer_scalar_field(circuit_output.aggregation_state.P1.y.get_value().lo);
161 pairing_target_field inner_proof_result =
162 barretenberg::pairing::reduced_ate_pairing_batch_precomputed(P, g2_lines, 2);
163 if (inner_proof_result != pairing_target_field::one()) {
164 throw_or_abort("inner proof result != 1");
165 }
166 }
167
168 public:
169 static OuterBuilder generate(uint256_t inputs[])
170 {
171 InnerBuilder inner_circuit;
172 OuterBuilder outer_circuit;
173
174 create_inner_circuit_no_tables(inner_circuit, inputs);
175
176 auto circuit_output = create_outer_circuit(inner_circuit, outer_circuit);
177
178 circuit_output.aggregation_state.assign_object_to_proof_outputs();
179 if (outer_circuit.failed()) {
180 throw_or_abort("outer composer failed");
181 }
182
183 return outer_circuit;
184 }
185};
Definition: recursive_circuit.hpp:16
Definition: field12.hpp:5
Definition: affine_element.hpp:11
Definition: uint256.hpp:25
Definition: ultra_circuit_builder.hpp:31
Definition: ultra_composer.hpp:16
UltraToStandardProver create_ultra_to_standard_prover(CircuitBuilder &circuit_constructor)
Uses slightly different settings from the UltraProver.
Definition: ultra_composer.cpp:199
UltraToStandardVerifier create_ultra_to_standard_verifier(CircuitBuilder &circuit_constructor)
Create a verifier using pedersen hash for the transcript.
Definition: ultra_composer.cpp:314
UltraVerifier create_verifier(CircuitBuilder &circuit_constructor)
Definition: ultra_composer.cpp:294
std::shared_ptr< plonk::verification_key > compute_verification_key(CircuitBuilder &circuit_constructor)
Definition: ultra_composer.cpp:478
static transcript::Manifest create_manifest(const size_t num_public_inputs)
Create a manifest object.
Definition: ultra_composer.hpp:94
bool verify_proof(const plonk::proof &proof)
Definition: verifier.cpp:39
Definition: bigfield.hpp:17
Definition: byte_array.hpp:9
Definition: field.hpp:10
Definition: witness.hpp:10
Definition: manifest.hpp:11
Definition: widget.bench.cpp:13
Definition: pairing.hpp:27
Definition: proof.hpp:11
Definition: bn254.hpp:10
static std::shared_ptr< verification_key > from_witness(Builder *ctx, const std::shared_ptr< plonk::verification_key > &input_key)
Converts a 'native' verification key into a standard library type, instantiating the input_key parame...
Definition: verification_key.hpp:286
Definition: verification_key.hpp:48