Skip to content

Commit

Permalink
feat: solidity honk verifier (#5485)
Browse files Browse the repository at this point in the history
This PR introduces a Honk Verifier for 3 different types of circuit. 
- The logic in each circuit is duplicated as (at the time of writing)
solidity does not allow for generic data structures, so as the constants
(LOG_N) are different, then each transcript needs to compile with a new
log_n value.
- In follow up prs i will adjust the tests to run against acir
artifacts, where we will codegen the verifier, so i can remove all but
the basic case in this test suite

Note: this is not an optimal impl, that will follow

As this uses padded proofs, in which N is 2^28, the proof verification
cost has shot up to 1 793 675.
  • Loading branch information
Maddiaa0 authored Jul 22, 2024
1 parent bf774c2 commit 8dfebe4
Show file tree
Hide file tree
Showing 52 changed files with 8,038 additions and 164 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ template <typename Curve_> class KZG {
* computed
* @param prover_transcript Prover transcript
*/
template <typename Transcript>
static void compute_opening_proof(std::shared_ptr<CK> ck,
const ProverOpeningClaim<Curve>& opening_claim,
const std::shared_ptr<NativeTranscript>& prover_trancript)
const std::shared_ptr<Transcript>& prover_trancript)
{
Polynomial quotient = opening_claim.polynomial;
OpeningPair<Curve> pair = opening_claim.opening_pair;
Expand All @@ -56,7 +57,9 @@ template <typename Curve_> class KZG {
* - P₀ = C − v⋅[1]₁ + r⋅[W(x)]₁
* - P₁ = [W(x)]₁
*/
static VerifierAccumulator reduce_verify(const OpeningClaim<Curve>& claim, const auto& verifier_transcript)
template <typename Transcript>
static VerifierAccumulator reduce_verify(const OpeningClaim<Curve>& claim,
const std::shared_ptr<Transcript>& verifier_transcript)
{
auto quotient_commitment = verifier_transcript->template receive_from_prover<Commitment>("KZG:W");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -322,14 +322,15 @@ template <typename Curve> class ZeroMorphProver_ {
*
* @todo https://github.com/AztecProtocol/barretenberg/issues/1030: document concatenation trick
*/
template <typename Transcript>
static OpeningClaim prove(FF circuit_size,
RefSpan<Polynomial> f_polynomials,
RefSpan<Polynomial> g_polynomials,
RefSpan<FF> f_evaluations,
RefSpan<FF> g_shift_evaluations,
std::span<FF> multilinear_challenge,
const std::shared_ptr<CommitmentKey<Curve>>& commitment_key,
const std::shared_ptr<NativeTranscript>& transcript,
const std::shared_ptr<Transcript>& transcript,
RefSpan<Polynomial> concatenated_polynomials = {},
RefSpan<FF> concatenated_evaluations = {},
const std::vector<RefVector<Polynomial>>& concatenation_groups = {})
Expand Down Expand Up @@ -725,14 +726,15 @@ template <typename Curve> class ZeroMorphVerifier_ {
* @param transcript
* @return VerifierAccumulator Inputs to the final PCS verification check that will be accumulated
*/
template <typename Transcript>
static OpeningClaim<Curve> verify(FF circuit_size,
RefSpan<Commitment> unshifted_commitments,
RefSpan<Commitment> to_be_shifted_commitments,
RefSpan<FF> unshifted_evaluations,
RefSpan<FF> shifted_evaluations,
std::span<FF> multivariate_challenge,
const Commitment& g1_identity,
auto& transcript,
const std::shared_ptr<Transcript>& transcript,
const std::vector<RefVector<Commitment>>& concatenation_group_commitments = {},
RefSpan<FF> concatenated_evaluations = {})
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "barretenberg/plonk/proof_system/proving_key/proving_key.hpp"
#include "barretenberg/stdlib_circuit_builders/mega_flavor.hpp"
#include "barretenberg/stdlib_circuit_builders/ultra_flavor.hpp"
#include "barretenberg/stdlib_circuit_builders/ultra_keccak.hpp"
namespace bb {

template <class Flavor>
Expand Down Expand Up @@ -162,6 +163,7 @@ void ExecutionTrace_<Flavor>::add_ecc_op_wires_to_proving_key(Builder& builder,
}

template class ExecutionTrace_<UltraFlavor>;
template class ExecutionTrace_<UltraKeccakFlavor>;
template class ExecutionTrace_<MegaFlavor>;
template class ExecutionTrace_<plonk::flavor::Standard>;
template class ExecutionTrace_<plonk::flavor::Ultra>;
Expand Down
11 changes: 7 additions & 4 deletions barretenberg/cpp/src/barretenberg/flavor/flavor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ template <typename Tuple, std::size_t Index = 0> static constexpr auto create_tu
namespace bb {
class UltraFlavor;
class ECCVMFlavor;
class UltraKeccakFlavor;
class MegaFlavor;
class TranslatorFlavor;
template <typename BuilderType> class UltraRecursiveFlavor_;
Expand Down Expand Up @@ -383,16 +384,16 @@ template <typename T>
concept IsPlonkFlavor = IsAnyOf<T, plonk::flavor::Standard, plonk::flavor::Ultra>;

template <typename T>
concept IsUltraPlonkFlavor = IsAnyOf<T, plonk::flavor::Ultra>;
concept IsUltraPlonkFlavor = IsAnyOf<T, plonk::flavor::Ultra, UltraKeccakFlavor>;

template <typename T>
concept IsUltraPlonkOrHonk = IsAnyOf<T, plonk::flavor::Ultra, UltraFlavor, MegaFlavor>;
concept IsUltraPlonkOrHonk = IsAnyOf<T, plonk::flavor::Ultra, UltraFlavor, UltraKeccakFlavor, MegaFlavor>;

template <typename T>
concept IsHonkFlavor = IsAnyOf<T, UltraFlavor, MegaFlavor>;
concept IsHonkFlavor = IsAnyOf<T, UltraFlavor, UltraKeccakFlavor, MegaFlavor>;

template <typename T>
concept IsUltraFlavor = IsAnyOf<T, UltraFlavor, MegaFlavor>;
concept IsUltraFlavor = IsAnyOf<T, UltraFlavor, UltraKeccakFlavor, MegaFlavor>;

template <typename T>
concept IsGoblinFlavor = IsAnyOf<T, MegaFlavor,
Expand All @@ -417,6 +418,8 @@ template <typename T> concept IsECCVMRecursiveFlavor = IsAnyOf<T, ECCVMRecursive
template <typename T> concept IsGrumpkinFlavor = IsAnyOf<T, ECCVMFlavor>;

template <typename T> concept IsFoldingFlavor = IsAnyOf<T, UltraFlavor,
// Note(md): must be here to use oink prover
UltraKeccakFlavor,
MegaFlavor,
UltraRecursiveFlavor_<UltraCircuitBuilder>,
UltraRecursiveFlavor_<MegaCircuitBuilder>,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
barretenberg_module(stdlib_solidity_helpers stdlib_sha256 stdlib_blake3s stdlib_blake2s stdlib_pedersen_commitment plonk)
barretenberg_module(stdlib_solidity_helpers ultra_honk stdlib_sha256 stdlib_blake3s stdlib_blake2s stdlib_pedersen_commitment plonk)

if (NOT(FUZZING))
# Honk
add_executable(honk_solidity_key_gen honk_key_gen.cpp)

target_link_libraries(
honk_solidity_key_gen
stdlib_solidity_helpers
)

add_executable(honk_solidity_proof_gen honk_proof_gen.cpp)

target_link_libraries(
honk_solidity_proof_gen
stdlib_solidity_helpers
)

# Plonk
add_executable(solidity_key_gen key_gen.cpp)

add_executable(solidity_proof_gen proof_gen.cpp)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include "barretenberg/stdlib/primitives/field/field.hpp"
#include "barretenberg/stdlib/primitives/witness/witness.hpp"

namespace bb {

template <typename Builder> class EcdsaCircuit {
public:
using field_ct = stdlib::field_t<Builder>;
Expand Down Expand Up @@ -89,4 +91,6 @@ template <typename Builder> class EcdsaCircuit {

return builder;
}
};
};

} // namespace bb
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@

#include <iostream>
#include <memory>

#include "barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp"
#include "barretenberg/ultra_honk/ultra_prover.hpp"
#include "barretenberg/ultra_honk/ultra_verifier.hpp"

#include "./honk_sol_gen.hpp"

#include "circuits/add_2_circuit.hpp"
#include "circuits/blake_circuit.hpp"
#include "circuits/ecdsa_circuit.hpp"

using namespace bb;

using ProverInstance = ProverInstance_<UltraKeccakFlavor>;
using VerificationKey = UltraKeccakFlavor::VerificationKey;

template <template <typename> typename Circuit>
void generate_keys_honk(std::string output_path, std::string flavour_prefix, std::string circuit_name)
{
uint256_t public_inputs[4] = { 0, 0, 0, 0 };
UltraCircuitBuilder builder = Circuit<UltraCircuitBuilder>::generate(public_inputs);

auto instance = std::make_shared<ProverInstance>(builder);
UltraKeccakProver prover(instance);
auto verification_key = std::make_shared<VerificationKey>(instance->proving_key);

// Make verification key file upper case
circuit_name.at(0) = static_cast<char>(std::toupper(static_cast<unsigned char>(circuit_name.at(0))));
flavour_prefix.at(0) = static_cast<char>(std::toupper(static_cast<unsigned char>(flavour_prefix.at(0))));

std::string vk_class_name = circuit_name + flavour_prefix + "VerificationKey";
std::string base_class_name = "Base" + flavour_prefix + "Verifier";
std::string instance_class_name = circuit_name + flavour_prefix + "Verifier";

{
auto vk_filename = output_path + "/keys/" + vk_class_name + ".sol";
std::ofstream os(vk_filename);
bb::output_vk_sol_ultra_honk(os, verification_key, vk_class_name);
info("VK contract written to: ", vk_filename);
}
}

/*
* @brief Main entry point for the verification key generator
*
* 1. project_root_path: path to the solidity project root
* 2. srs_path: path to the srs db
*/
int main(int argc, char** argv)
{
std::vector<std::string> args(argv, argv + argc);

if (args.size() < 5) {
info("usage: ", args[0], "[plonk flavour] [circuit flavour] [output path] [srs path]");
return 1;
}

const std::string plonk_flavour = args[1];
const std::string circuit_flavour = args[2];
const std::string output_path = args[3];
const std::string srs_path = args[4];

bb::srs::init_crs_factory(srs_path);
// @todo - Add support for unrolled standard verifier. Needs a new solidity verifier contract.

if (plonk_flavour != "honk") {
info("honk");
return 1;
}

info("Generating ", plonk_flavour, " keys for ", circuit_flavour, " circuit");

if (plonk_flavour == "honk") {
if (circuit_flavour == "add2") {
generate_keys_honk<Add2Circuit>(output_path, plonk_flavour, circuit_flavour);
} else if (circuit_flavour == "blake") {
generate_keys_honk<BlakeCircuit>(output_path, plonk_flavour, circuit_flavour);
} else if (circuit_flavour == "ecdsa") {
generate_keys_honk<bb::EcdsaCircuit>(output_path, plonk_flavour, circuit_flavour);
// TODO: recursive proofs
} else {
info("Unsupported circuit");
return 1;
}
}
return 0;
} // namespace bb
105 changes: 105 additions & 0 deletions barretenberg/cpp/src/barretenberg/solidity_helpers/honk_proof_gen.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@

#include "barretenberg/honk/proof_system/types/proof.hpp"
#include "barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp"
#include "barretenberg/ultra_honk/ultra_prover.hpp"
#include "barretenberg/ultra_honk/ultra_verifier.hpp"

#include "circuits/add_2_circuit.hpp"
#include "circuits/blake_circuit.hpp"
#include "circuits/ecdsa_circuit.hpp"
#include "utils/utils.hpp"

#include <iostream>
#include <sstream>

using namespace bb;
using numeric::uint256_t;

using ProverInstance = ProverInstance_<UltraKeccakFlavor>;
using VerificationKey = UltraKeccakFlavor::VerificationKey;
using Prover = UltraKeccakProver;
using Verifier = UltraKeccakVerifier;

template <template <typename> typename Circuit> void generate_proof(uint256_t inputs[])
{

UltraCircuitBuilder builder = Circuit<UltraCircuitBuilder>::generate(inputs);

auto instance = std::make_shared<ProverInstance>(builder);
Prover prover(instance);
auto verification_key = std::make_shared<VerificationKey>(instance->proving_key);
Verifier verifier(verification_key);

HonkProof proof = prover.construct_proof();
{
if (!verifier.verify_proof(proof)) {
throw_or_abort("Verification failed");
}

std::vector<uint8_t> proof_bytes = to_buffer(proof);
std::string p = bytes_to_hex_string(proof_bytes);
std::cout << p;
}
}

std::string pad_left(std::string input, size_t length)
{
return std::string(length - std::min(length, input.length()), '0') + input;
}

/**
* @brief Main entry point for the proof generator.
* Expected inputs:
* 1. plonk_flavour: ultra
* 2. circuit_flavour: blake, add2
* 3. public_inputs: comma separated list of public inputs
* 4. project_root_path: path to the solidity project root
* 5. srs_path: path to the srs db
*/
int main(int argc, char** argv)
{
std::vector<std::string> args(argv, argv + argc);

if (args.size() < 5) {
info("usage: ", args[0], "[plonk flavour] [circuit flavour] [srs path] [public inputs]");
return 1;
}

const std::string plonk_flavour = args[1];
const std::string circuit_flavour = args[2];
const std::string srs_path = args[3];
const std::string string_input = args[4];

bb::srs::init_crs_factory(srs_path);

// @todo dynamically allocate this
uint256_t inputs[] = { 0, 0, 0, 0, 0, 0 };

size_t count = 0;
std::stringstream s_stream(string_input);
while (s_stream.good()) {
std::string sub;
getline(s_stream, sub, ',');
if (sub.substr(0, 2) == "0x") {
sub = sub.substr(2);
}
std::string padded = pad_left(sub, 64);
inputs[count++] = uint256_t(padded);
}

if (plonk_flavour != "honk") {
info("Only honk flavor allowed");
return 1;
}

if (circuit_flavour == "blake") {
generate_proof<BlakeCircuit>(inputs);
} else if (circuit_flavour == "add2") {
generate_proof<Add2Circuit>(inputs);
} else if (circuit_flavour == "ecdsa") {
generate_proof<EcdsaCircuit>(inputs);
} else {
info("Invalid circuit flavour: " + circuit_flavour);
return 1;
}
}
Loading

0 comments on commit 8dfebe4

Please sign in to comment.