Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Solidity Ultra Verifier with tests #363

Merged
merged 17 commits into from
Apr 27, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .circleci/build_local
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ PUSH_LABEL=$3

PROJECTS=(
cpp:barretenberg-cpp:./dockerfiles/Dockerfile.x86_64-linux-clang:barretenberg-x86_64-linux-clang
cpp:barretenberg-cpp:./dockerfiles/Dockerfile.x86_64-linux-clang-assert:barretenberg-x86_64-linux-clang-assert
cpp:barretenberg-cpp:./dockerfiles/Dockerfile.wasm-linux-clang:barretenberg-wasm-linux-clang
# js:barretenberg-js
)
Expand Down
12 changes: 12 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,17 @@ jobs:
name: "Build"
command: cond_spot_run_build barretenberg-x86_64-linux-clang-assert 64

solidity-verifier-tests:
docker:
- image: aztecprotocol/alpine-build-image
resource_class: small
steps:
- *checkout
- *setup_env
- run:
name: "Test"
command: build sol

barretenberg-tests:
docker:
- image: aztecprotocol/alpine-build-image
Expand Down Expand Up @@ -247,6 +258,7 @@ workflows:
- x86_64-linux-clang
- x86_64-linux-clang-assert
- wasm-linux-clang
- solidity-verifier-tests: *bb_test
- honk-tests: *bb_test
- barretenberg-tests: *bb_test
- stdlib-primitives-tests: *bb_test
Expand Down
9 changes: 9 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
[submodule "foundation"]
path = foundation
url = [email protected]:AztecProtocol/foundation.git
[submodule "sol/lib/forge-std"]
path = sol/lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "sol/lib/solidity-stringutils"]
path = sol/lib/solidity-stringutils
url = https://github.com/Arachnid/solidity-stringutils
[submodule "sol/lib/openzeppelin-contracts"]
path = sol/lib/openzeppelin-contracts
url = https://github.com/OpenZeppelin/openzeppelin-contracts
6 changes: 6 additions & 0 deletions build_manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,11 @@
"dockerfile": "js/Dockerfile",
"rebuildPatterns": ["^js/"],
"dependencies": ["barretenberg-wasm-linux-clang"]
},
"sol": {
"buildDir": "sol",
"dockerfile": "sol/Dockerfile",
"rebuildPatterns": ["^sol/"],
"dependencies": ["barretenberg-x86_64-linux-clang-assert"]
}
}
2 changes: 1 addition & 1 deletion cpp/dockerfiles/Dockerfile.x86_64-linux-clang
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ RUN cmake --preset default && cmake --build --preset default

FROM alpine:3.17
RUN apk update && apk add openmp
COPY --from=builder /usr/src/barretenberg/cpp/srs_db /usr/src/barretenberg/cpp/srs_db
COPY --from=builder /usr/src/barretenberg/cpp/srs_db /usr/src/barretenberg/cpp/srs_db
3 changes: 2 additions & 1 deletion cpp/dockerfiles/Dockerfile.x86_64-linux-clang-assert
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ RUN cmake --preset default -DCMAKE_BUILD_TYPE=RelWithAssert -DCI=ON && cmake --b
FROM alpine:3.17
RUN apk update && apk add curl openmp
COPY --from=builder /usr/src/barretenberg/cpp/srs_db /usr/src/barretenberg/cpp/srs_db
COPY --from=builder /usr/src/barretenberg/cpp/build/bin/*_tests /usr/src/barretenberg/cpp/build/bin/
COPY --from=builder /usr/src/barretenberg/cpp/build/bin/*_tests /usr/src/barretenberg/cpp/build/bin/
COPY --from=builder /usr/src/barretenberg/cpp/build/bin/solidity* /usr/src/barretenberg/cpp/build/bin/
1 change: 1 addition & 0 deletions cpp/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ add_subdirectory(barretenberg/plonk)
add_subdirectory(barretenberg/stdlib)
add_subdirectory(barretenberg/join_split_example)
add_subdirectory(barretenberg/dsl)
add_subdirectory(barretenberg/solidity_helpers)

if(BENCHMARKS)
add_subdirectory(barretenberg/benchmark)
Expand Down
17 changes: 17 additions & 0 deletions cpp/src/barretenberg/solidity_helpers/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
barretenberg_module(stdlib_solidity_helpers plonk proof_system transcript crypto_pedersen_commitment polynomials crypto_sha256 ecc crypto_blake3s stdlib_primitives stdlib_pedersen_commitment stdlib_blake3s stdlib_blake2s)

add_executable(solidity_key_gen key_gen.cpp)

add_executable(solidity_proof_gen proof_gen.cpp)

target_link_libraries(
solidity_key_gen
stdlib_solidity_helpers
env
)

target_link_libraries(
solidity_proof_gen
stdlib_solidity_helpers
env
)
32 changes: 32 additions & 0 deletions cpp/src/barretenberg/solidity_helpers/circuits/add_2_circuit.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include "barretenberg/stdlib/primitives/field/field.hpp"
#include "barretenberg/stdlib/primitives/witness/witness.hpp"
#include "barretenberg/stdlib/primitives/uint/uint.hpp"
#include "barretenberg/stdlib/primitives/bool/bool.hpp"

// #include <stdlib/primitives/field/field.hpp>
Maddiaa0 marked this conversation as resolved.
Show resolved Hide resolved
// #include <stdlib/primitives/witness/witness.hpp>
// #include <stdlib/primitives/uint/uint.hpp>
// #include <stdlib/primitives/bool/bool.hpp>

// using numeric::uint256_t;

template <typename Composer> class Add2Circuit {
public:
typedef stdlib::field_t<Composer> field_ct;
typedef stdlib::witness_t<Composer> witness_ct;
typedef stdlib::public_witness_t<Composer> public_witness_ct;

// Three public inputs
static Composer generate(std::string srs_path, uint256_t inputs[])
{

Composer composer(srs_path);

field_ct a(public_witness_ct(&composer, inputs[0]));
field_ct b(public_witness_ct(&composer, inputs[1]));
field_ct c(public_witness_ct(&composer, inputs[2]));
c.assert_equal(a + b);

return composer;
}
};
35 changes: 35 additions & 0 deletions cpp/src/barretenberg/solidity_helpers/circuits/blake_circuit.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include "barretenberg/stdlib/primitives/field/field.hpp"
#include "barretenberg/stdlib/primitives/witness/witness.hpp"
#include "barretenberg/stdlib/hash/blake2s/blake2s.hpp"

//#include <stdlib/primitives/field/field.hpp>
Maddiaa0 marked this conversation as resolved.
Show resolved Hide resolved
//#include <stdlib/primitives/witness/witness.hpp>
//#include <stdlib/hash/blake2s/blake2s.hpp>

using namespace proof_system::plonk;
using namespace proof_system::plonk::stdlib;

using numeric::uint256_t;

template <typename Composer> class BlakeCircuit {
public:
typedef stdlib::field_t<Composer> field_ct;
typedef stdlib::public_witness_t<Composer> public_witness_ct;
typedef stdlib::byte_array<Composer> byte_array_ct;

static constexpr size_t NUM_PUBLIC_INPUTS = 4;

static Composer generate(std::string srs_path, uint256_t public_inputs[])
{
Composer composer(srs_path);

byte_array_ct input_buffer(&composer);
for (size_t i = 0; i < NUM_PUBLIC_INPUTS; ++i) {
input_buffer.write(byte_array_ct(field_ct(public_witness_ct(&composer, public_inputs[i]))));
}

stdlib::blake2s<Composer>(input_buffer);

return composer;
}
};
144 changes: 144 additions & 0 deletions cpp/src/barretenberg/solidity_helpers/circuits/recursive_circuit.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
#include "barretenberg/transcript/transcript.hpp"
#include "barretenberg/plonk/proof_system/proving_key/serialize.hpp"
#include "barretenberg/stdlib/primitives/curves/bn254.hpp"
#include "barretenberg/stdlib/recursion/verifier/verifier.hpp"
#include "barretenberg/stdlib/recursion/verifier/program_settings.hpp"
#include "barretenberg/ecc/curves/bn254/fq12.hpp"
#include "barretenberg/ecc/curves/bn254/pairing.hpp"

//#include <transcript/transcript.hpp>
Maddiaa0 marked this conversation as resolved.
Show resolved Hide resolved
//#include <proof_system/proving_key/serialize.hpp>
//#include <stdlib/primitives/curves/bn254.hpp>
//#include <stdlib/recursion/verifier/verifier.hpp>
//#include <stdlib/recursion/verifier/program_settings.hpp>
//#include <ecc/curves/bn254/fq12.hpp>
//#include <ecc/curves/bn254/pairing.hpp>

using namespace proof_system::plonk;

using numeric::uint256_t;

template <typename OuterComposer> class RecursiveCircuit {
using InnerComposer = UltraComposer;

typedef stdlib::field_t<InnerComposer> field_ct;
typedef stdlib::bn254<InnerComposer> inner_curve;
typedef stdlib::bn254<OuterComposer> outer_curve;
typedef stdlib::recursion::verification_key<outer_curve> verification_key_pt;
typedef stdlib::recursion::recursive_ultra_verifier_settings<outer_curve> recursive_settings;
typedef stdlib::recursion::recursive_ultra_to_standard_verifier_settings<outer_curve>
ultra_to_standard_recursive_settings;
typedef inner_curve::fr_ct fr_ct;
typedef inner_curve::public_witness_ct public_witness_ct;
typedef inner_curve::witness_ct witness_ct;

struct circuit_outputs {
stdlib::recursion::aggregation_state<outer_curve> aggregation_state;
std::shared_ptr<verification_key_pt> verification_key;
};

static void create_inner_circuit_no_tables(InnerComposer& composer, uint256_t inputs[])
{
field_ct a(public_witness_ct(&composer, inputs[0]));
field_ct b(public_witness_ct(&composer, inputs[1]));
field_ct c(public_witness_ct(&composer, inputs[2]));

// @note For some reason, if we don't have this line, the circuit fails to verify.
auto c_sq = c * c;

c.assert_equal(a + b);
c_sq.assert_equal(c * c);
};

static circuit_outputs create_outer_circuit(InnerComposer& inner_composer, OuterComposer& outer_composer)
{
// These constexpr definitions are to allow for the following:
// An Ultra Pedersen hash evaluates to a different value from the Turbo/Standard versions of the Pedersen hash.
// Therefore, the fiat-shamir challenges generated by the prover and verifier _could_ accidentally be different
// if an ultra proof is generated using ultra-pedersen challenges, but is being verified within a non-ultra
// circuit which uses non-ultra-pedersen challenges. We need the prover and verifier hashes to be the same. The
// solution is to select the relevant prover and verifier types (whose settings use the same hash for
// fiat-shamir), depending on the Inner-Outer combo. It's a bit clunky, but the alternative is to have a
// template argument for the hashtype, and that would pervade the entire UltraComposer, which would be
// horrendous.
constexpr bool is_ultra_to_ultra = std::is_same<OuterComposer, UltraComposer>::value;
typedef
typename std::conditional<is_ultra_to_ultra, UltraProver, UltraToStandardProver>::type ProverOfInnerCircuit;
typedef typename std::conditional<is_ultra_to_ultra, UltraVerifier, UltraToStandardVerifier>::type
VerifierOfInnerProof;
typedef
typename std::conditional<is_ultra_to_ultra, recursive_settings, ultra_to_standard_recursive_settings>::type
RecursiveSettings;

ProverOfInnerCircuit prover;
if constexpr (is_ultra_to_ultra) {
prover = inner_composer.create_prover();
} else {
prover = inner_composer.create_ultra_to_standard_prover();
}

const auto verification_key_native = inner_composer.compute_verification_key();

// Convert the verification key's elements into _circuit_ types, using the OUTER composer.
std::shared_ptr<verification_key_pt> verification_key =
verification_key_pt::from_witness(&outer_composer, verification_key_native);

proof recursive_proof = prover.construct_proof();

{
// Native check is mainly for comparison vs circuit version of the verifier.
VerifierOfInnerProof native_verifier;

if constexpr (is_ultra_to_ultra) {
native_verifier = inner_composer.create_verifier();
} else {
native_verifier = inner_composer.create_ultra_to_standard_verifier();
}
auto native_result = native_verifier.verify_proof(recursive_proof);
if (native_result == false) {
throw std::runtime_error("Native verification failed");
}
}

transcript::Manifest recursive_manifest = InnerComposer::create_manifest(prover.key->num_public_inputs);

// Verifying the ultra (inner) proof with CIRCUIT TYPES (i.e. within a standard or ultra plonk arithmetic
// circuit)
stdlib::recursion::aggregation_state<outer_curve> output =
stdlib::recursion::verify_proof<outer_curve, RecursiveSettings>(
&outer_composer, verification_key, recursive_manifest, recursive_proof);

return { output, verification_key };
};

public:
static OuterComposer generate(std::string srs_path, uint256_t inputs[])
{
InnerComposer inner_composer = InnerComposer(srs_path);
OuterComposer outer_composer = OuterComposer(srs_path);

create_inner_circuit_no_tables(inner_composer, inputs);
auto circuit_output = create_outer_circuit(inner_composer, outer_composer);

g1::affine_element P[2];
P[0].x = barretenberg::fq(circuit_output.aggregation_state.P0.x.get_value().lo);
P[0].y = barretenberg::fq(circuit_output.aggregation_state.P0.y.get_value().lo);
P[1].x = barretenberg::fq(circuit_output.aggregation_state.P1.x.get_value().lo);
P[1].y = barretenberg::fq(circuit_output.aggregation_state.P1.y.get_value().lo);

barretenberg::fq12 inner_proof_result = barretenberg::pairing::reduced_ate_pairing_batch_precomputed(
P, circuit_output.verification_key->reference_string->get_precomputed_g2_lines(), 2);

if (inner_proof_result != barretenberg::fq12::one()) {
throw std::runtime_error("inner proof result != 1");
}

circuit_output.aggregation_state.add_proof_outputs_as_public_inputs();

if (outer_composer.failed()) {
throw std::runtime_error("outer composer failed");
}

return outer_composer;
}
};
Loading