Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 4 additions & 1 deletion barretenberg/acir_tests/browser-test-app/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,10 @@ function installClientIvcGlobal() {
threads,
logger: console.log,
});
const [proof, verificationKey] = await backend.prove(witnessBufs, vkBufs);
const [_, proof, verificationKey] = await backend.prove(
witnessBufs,
vkBufs
);
await backend.destroy();
return { proof, verificationKey };
}
Expand Down
6 changes: 3 additions & 3 deletions barretenberg/cpp/scripts/ci_benchmark_ivc_flows.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,18 @@ function verify_ivc_flow {
# TODO(AD): Checking which one would be good, but there isn't too much that can go wrong here.
set +e
echo_stderr "Private verify."
"./$native_build_dir/bin/bb" verify --scheme client_ivc -p "$proof" -k ../../yarn-project/bb-prover/artifacts/private-civc-vk 1>&2
"./$native_build_dir/bin/bb" verify --scheme client_ivc -p "$proof" -k ../../noir-projects/noir-protocol-circuits/target/keys/hiding_kernel_to_rollup.ivc.vk 1>&2
local private_result=$?
echo_stderr "Private verify: $private_result."
"./$native_build_dir/bin/bb" verify --scheme client_ivc -p "$proof" -k ../../yarn-project/bb-prover/artifacts/public-civc-vk 1>&2
"./$native_build_dir/bin/bb" verify --scheme client_ivc -p "$proof" -k ../../noir-projects/noir-protocol-circuits/target/keys/hiding_kernel_to_public.ivc.vk 1>&2
local public_result=$?
echo_stderr "Public verify: $public_result."
if [[ $private_result -eq $public_result ]]; then
echo_stderr "Verification failed for $flow. Both keys returned $private_result - only one should."
exit 1
fi
if [[ $private_result -ne 0 ]] && [[ $public_result -ne 0 ]]; then
echo_stderr "Verification failed for $flow. Did not verify with precalculated verification key - we may need to revisit how it is generated in yarn-project/bb-prover."
echo_stderr "Verification failed for $flow. Did not verify with precalculated verification key - we may need to revisit how it is generated in noir-projects/noir-protocol-circuits."
exit 1
fi
}
Expand Down
27 changes: 19 additions & 8 deletions barretenberg/cpp/src/barretenberg/api/api_client_ivc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,16 @@ namespace { // anonymous namespace
*
* @param bytecode_path
* @param witness_path
* @param use_structured_trace Whether to utilize structured trace when computing VK for circuit
*/
void write_standalone_vk(const std::filesystem::path& bytecode_path, const std::filesystem::path& output_path)
void write_standalone_vk(std::vector<uint8_t> bytecode,
const std::filesystem::path& output_path,
bool use_structured_trace = true)
{
auto bytecode = get_bytecode(bytecode_path);
auto trace_settings = use_structured_trace ? TraceSettings{ AZTEC_TRACE_STRUCTURE } : TraceSettings{};
auto response = bbapi::ClientIvcComputeStandaloneVk{
.circuit = { .name = "standalone_circuit", .bytecode = std::move(bytecode) }
}.execute();
}.execute({ .trace_settings = trace_settings });

bool is_stdout = output_path == "-";
if (is_stdout) {
Expand Down Expand Up @@ -84,17 +87,18 @@ void ClientIVCAPI::prove(const Flags& flags,
const bool output_to_stdout = output_dir == "-";

const auto write_proof = [&]() {
const auto buf = to_buffer(proof);
const auto buf = to_buffer(proof.to_field_elements());
if (output_to_stdout) {
vinfo("writing ClientIVC proof to stdout");
write_bytes_to_stdout(buf);
} else {
vinfo("writing ClientIVC proof in directory ", output_dir);
proof.to_file_msgpack(output_dir / "proof");
write_file(output_dir / "proof", buf);
}
};

write_proof();

if (flags.write_vk) {
vinfo("writing ClientIVC vk in directory ", output_dir);
// write CIVC vk using the bytecode of the hiding circuit (the last step of the execution)
Expand All @@ -108,8 +112,11 @@ bool ClientIVCAPI::verify([[maybe_unused]] const Flags& flags,
const std::filesystem::path& vk_path)
{
BB_BENCH_NAME("ClientIVCAPI::verify");
auto proof = ClientIVC::Proof::from_file_msgpack(proof_path);
auto proof_fields = many_from_buffer<fr>(read_file(proof_path));
auto proof = ClientIVC::Proof::from_field_elements(proof_fields);

auto vk_buffer = read_file(vk_path);

auto response = bbapi::ClientIvcVerify{ .proof = std::move(proof), .vk = std::move(vk_buffer) }.execute();
return response.valid;
}
Expand Down Expand Up @@ -177,10 +184,14 @@ void ClientIVCAPI::write_vk(const Flags& flags,
const std::filesystem::path& output_path)
{
BB_BENCH_NAME("ClientIVCAPI::write_vk");
auto bytecode = get_bytecode(bytecode_path);
if (flags.verifier_type == "ivc") {
write_civc_vk(get_bytecode(bytecode_path), output_path);
write_civc_vk(bytecode, output_path);
} else if (flags.verifier_type == "standalone") {
write_standalone_vk(bytecode_path, output_path);
write_standalone_vk(bytecode, output_path);
} else if (flags.verifier_type == "standalone_hiding") {
// write the VK for the hiding kernel which DOES NOT utilize a structured trace
write_standalone_vk(bytecode, output_path, false);
} else {
const std::string msg = std::string("Can't write vk for verifier type ") + flags.verifier_type;
throw_or_abort(msg);
Expand Down
8 changes: 5 additions & 3 deletions barretenberg/cpp/src/barretenberg/bb/cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,9 +241,11 @@ int parse_and_run_cli_command(int argc, char* argv[])
"recursive verifier) or is it for an ivc verifier? `standalone` produces a verification key "
"is sufficient for verifying proofs about a single circuit (including the non-encsapsulated "
"use case where an IVC scheme is manually constructed via recursive UltraHonk proof "
"verification). `ivc` produces a verification key for verifying the stack of run though a "
"dedicated ivc verifier class (currently the only option is the ClientIVC class) ")
->check(CLI::IsMember({ "standalone", "ivc" }).name("is_member"));
"verification). `standalone_hiding` is similar to `standalone` but is used for the last step "
"where the structured trace is not utilized. `ivc` produces a verification key for verifying "
"the stack of run though a dedicated ivc verifier class (currently the only option is the "
"ClientIVC class)")
->check(CLI::IsMember({ "standalone", "standalone_hiding", "ivc" }).name("is_member"));
};

const auto add_verbose_flag = [&](CLI::App* subcommand) {
Expand Down
37 changes: 37 additions & 0 deletions barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,43 @@ std::vector<ClientIVC::FF> ClientIVC::Proof::to_field_elements() const
return proof;
};

ClientIVC::Proof ClientIVC::Proof::from_field_elements(const std::vector<ClientIVC::FF>& fields)
{
HonkProof mega_proof;
GoblinProof goblin_proof;

size_t custom_public_inputs_size = fields.size() - ClientIVC::Proof::PROOF_LENGTH();

// Mega proof
auto start_idx = fields.begin();
auto end_idx = start_idx + static_cast<std::ptrdiff_t>(
MegaZKFlavor::PROOF_LENGTH_WITHOUT_PUB_INPUTS(MegaZKFlavor::VIRTUAL_LOG_N) +
bb::HidingKernelIO::PUBLIC_INPUTS_SIZE + custom_public_inputs_size);
mega_proof.insert(mega_proof.end(), start_idx, end_idx);

// Merge proof
start_idx = end_idx;
end_idx += static_cast<std::ptrdiff_t>(MERGE_PROOF_SIZE);
goblin_proof.merge_proof.insert(goblin_proof.merge_proof.end(), start_idx, end_idx);

// ECCVM pre-ipa proof
start_idx = end_idx;
end_idx += static_cast<std::ptrdiff_t>(ECCVMFlavor::PROOF_LENGTH_WITHOUT_PUB_INPUTS - IPA_PROOF_LENGTH);
goblin_proof.eccvm_proof.pre_ipa_proof.insert(goblin_proof.eccvm_proof.pre_ipa_proof.end(), start_idx, end_idx);

// ECCVM ipa proof
start_idx = end_idx;
end_idx += static_cast<std::ptrdiff_t>(IPA_PROOF_LENGTH);
goblin_proof.eccvm_proof.ipa_proof.insert(goblin_proof.eccvm_proof.ipa_proof.end(), start_idx, end_idx);

// Translator proof
start_idx = end_idx;
end_idx += static_cast<std::ptrdiff_t>(TranslatorFlavor::PROOF_LENGTH_WITHOUT_PUB_INPUTS);
goblin_proof.translator_proof.insert(goblin_proof.translator_proof.end(), start_idx, end_idx);

return { mega_proof, goblin_proof };
};

msgpack::sbuffer ClientIVC::Proof::to_msgpack_buffer() const
{
msgpack::sbuffer buffer;
Expand Down
2 changes: 2 additions & 0 deletions barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ class ClientIVC {
*/
std::vector<FF> to_field_elements() const;

static Proof from_field_elements(const std::vector<ClientIVC::FF>& fields);

// TODO(https://github.com/AztecProtocol/barretenberg/issues/1299): The following msgpack methods are generic
// and should leverage some kind of shared msgpack utility.
msgpack::sbuffer to_msgpack_buffer() const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ create_civc_recursion_constraints(Builder& builder,
// Recursively verify CIVC proof
auto mega_vk = std::make_shared<VerificationKey>(builder, key_fields);
auto mega_vk_and_hash = std::make_shared<RecursiveVKAndHash>(mega_vk, vk_hash);
ClientIVCRecursiveVerifier::StdlibProof stdlib_proof(proof_fields);
ClientIVCRecursiveVerifier::StdlibProof stdlib_proof(proof_fields, input.public_inputs.size());

ClientIVCRecursiveVerifier verifier(&builder, mega_vk_and_hash);
ClientIVCRecursiveVerifier::Output verification_output = verifier.verify(stdlib_proof);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,13 @@ class ClientIVCRecursiveVerifier {
* @param proof_indices
* @param virtual_log_n
*/
StdlibProof(const std::vector<field_t<Builder>>& proof_indices, size_t virtual_log_n = Flavor::VIRTUAL_LOG_N)
StdlibProof(const std::vector<field_t<Builder>>& proof_indices,
size_t public_inputs_size,
size_t virtual_log_n = Flavor::VIRTUAL_LOG_N)
{

BB_ASSERT_EQ(proof_indices.size(),
PROOF_LENGTH(virtual_log_n),
PROOF_LENGTH(virtual_log_n) + public_inputs_size,
"Number of indices differs from the expected proof size.");

auto it = proof_indices.begin();
Expand All @@ -70,7 +72,7 @@ class ClientIVCRecursiveVerifier {
std::ptrdiff_t start_idx = 0;
std::ptrdiff_t end_idx = static_cast<std::ptrdiff_t>(
RecursiveFlavor::NativeFlavor::PROOF_LENGTH_WITHOUT_PUB_INPUTS(virtual_log_n) +
HidingKernelIO<Builder>::PUBLIC_INPUTS_SIZE);
HidingKernelIO<Builder>::PUBLIC_INPUTS_SIZE + public_inputs_size);
mega_proof.insert(mega_proof.end(), it + start_idx, it + end_idx);

// Merge proof
Expand All @@ -96,7 +98,7 @@ class ClientIVCRecursiveVerifier {
goblin_proof.translator_proof.insert(goblin_proof.translator_proof.end(), it + start_idx, it + end_idx);

BB_ASSERT_EQ(static_cast<uint32_t>(end_idx),
PROOF_LENGTH(virtual_log_n),
PROOF_LENGTH(virtual_log_n) + public_inputs_size,
"Reconstructed a ClientIVC proof of wrong the length from proof indices.");
}
};
Expand Down
13 changes: 10 additions & 3 deletions barretenberg/ts/src/barretenberg/backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
uint8ArrayToHex,
hexToUint8Array,
} from '../proof/index.js';
import { fromClientIVCProof, toClientIVCProof } from '../cbind/generated/api_types.js';
import { ClientIVCProof, fromClientIVCProof, toClientIVCProof } from '../cbind/generated/api_types.js';
import { ungzip } from 'pako';
import { Buffer } from 'buffer';
import { Decoder, Encoder } from 'msgpackr';
Expand Down Expand Up @@ -267,7 +267,7 @@ export class AztecClientBackend {
}
}

async prove(witnessBuf: Uint8Array[], vksBuf: Uint8Array[] = []): Promise<[Uint8Array, Uint8Array]> {
async prove(witnessBuf: Uint8Array[], vksBuf: Uint8Array[] = []): Promise<[Uint8Array[], Uint8Array, Uint8Array]> {
if (vksBuf.length !== 0 && this.acirBuf.length !== witnessBuf.length) {
throw new AztecClientBackendError('Witness and bytecodes must have the same stack depth!');
}
Expand Down Expand Up @@ -315,12 +315,19 @@ export class AztecClientBackend {
bytecode: this.acirBuf[this.acirBuf.length - 1],
} });

const proofFields = [
proveResult.proof.megaProof,
proveResult.proof.goblinProof.mergeProof,
proveResult.proof.goblinProof.eccvmProof.preIpaProof,
proveResult.proof.goblinProof.eccvmProof.ipaProof,
proveResult.proof.goblinProof.translatorProof,
].flat();

// Note: Verification may not work correctly until we properly serialize the proof
if (!(await this.verify(proof, vkResult.bytes))) {
throw new AztecClientBackendError('Failed to verify the private (ClientIVC) transaction proof!');
}
return [proof, vkResult.bytes];
return [proofFields, proof, vkResult.bytes];
}

async verify(proof: Uint8Array, vk: Uint8Array): Promise<boolean> {
Expand Down
7 changes: 2 additions & 5 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
"cimg",
"ciphertext",
"ciphertexts",
"civc",
"clonedeep",
"clonedeepwith",
"cmd",
Expand Down Expand Up @@ -394,9 +395,5 @@
"lib",
"*.cmake"
],
"flagWords": [
"anonymous",
"offence",
"offences"
]
"flagWords": ["anonymous", "offence", "offences"]
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use dep::mock_types::{RollupPublicInputs, TubeData};
use dep::mock_types::{CivcProofData, RollupPublicInputs};

fn main(tube_data: TubeData) -> pub RollupPublicInputs {
tube_data.verify();
fn main(civc_proof_data: CivcProofData) -> pub RollupPublicInputs {
civc_proof_data.verify();
RollupPublicInputs::new(1)
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
use dep::mock_types::{
AVM_V2_PROOF_LENGTH_IN_FIELDS_PADDED, AVM_V2_VERIFICATION_KEY_LENGTH_IN_FIELDS_PADDED,
AvmCircuitPublicInputs, PROOF_TYPE_AVM, RollupPublicInputs, TubeData, VerificationKey,
AvmCircuitPublicInputs, CivcProofData, PROOF_TYPE_AVM, RollupPublicInputs, VerificationKey,
};

fn main(
tube_data: TubeData,
civc_proof_data: CivcProofData,
verification_key: VerificationKey<AVM_V2_VERIFICATION_KEY_LENGTH_IN_FIELDS_PADDED>,
proof: [Field; AVM_V2_PROOF_LENGTH_IN_FIELDS_PADDED],
public_inputs: AvmCircuitPublicInputs,
) -> pub RollupPublicInputs {
tube_data.verify();
civc_proof_data.verify();
std::verify_proof_with_type(
verification_key.key,
proof,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ pub use protocol_types::{
abis::avm_circuit_public_inputs::AvmCircuitPublicInputs,
constants::{
AVM_V2_PROOF_LENGTH_IN_FIELDS_PADDED, AVM_V2_VERIFICATION_KEY_LENGTH_IN_FIELDS_PADDED,
MEGA_VK_LENGTH_IN_FIELDS, NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH, PROOF_TYPE_AVM,
PROOF_TYPE_OINK, PROOF_TYPE_PG, PROOF_TYPE_PG_FINAL, PROOF_TYPE_PG_TAIL,
PROOF_TYPE_ROLLUP_HONK, PROOF_TYPE_ROOT_ROLLUP_HONK, TUBE_PROOF_LENGTH,
ULTRA_VK_LENGTH_IN_FIELDS,
CIVC_PROOF_LENGTH, CIVC_VK_LENGTH_IN_FIELDS, MEGA_VK_LENGTH_IN_FIELDS,
NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH, PROOF_TYPE_AVM, PROOF_TYPE_CIVC, PROOF_TYPE_OINK,
PROOF_TYPE_PG, PROOF_TYPE_PG_FINAL, PROOF_TYPE_PG_TAIL, PROOF_TYPE_ROLLUP_HONK,
PROOF_TYPE_ROOT_ROLLUP_HONK,
},
proof::verification_key::{RollupHonkVerificationKey, VerificationKey},
traits::Serialize,
Expand Down Expand Up @@ -163,21 +163,21 @@ impl PreviousRollupData {
}
}

pub struct TubeData {
pub struct CivcProofData {
pub public_inputs: KernelPublicInputs,
pub proof: [Field; TUBE_PROOF_LENGTH],
pub vk_data: VerificationKey<ULTRA_VK_LENGTH_IN_FIELDS>,
pub proof: [Field; CIVC_PROOF_LENGTH],
pub vk_data: VerificationKey<CIVC_VK_LENGTH_IN_FIELDS>,
}

impl TubeData {
impl CivcProofData {
pub fn verify(self) {
let inputs = KernelPublicInputs::serialize(self.public_inputs);
std::verify_proof_with_type(
self.vk_data.key,
self.proof,
inputs,
self.vk_data.hash,
PROOF_TYPE_ROLLUP_HONK,
PROOF_TYPE_CIVC,
);
}
}
1 change: 1 addition & 0 deletions noir-projects/noir-protocol-circuits/Nargo.template.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ members = [
"crates/reset-kernel-lib",
"crates/hiding-kernel-to-rollup",
"crates/hiding-kernel-to-public",
"crates/tube-public",
"crates/rollup-lib",
"crates/rollup-merge",
"crates/rollup-base-private",
Expand Down
8 changes: 4 additions & 4 deletions noir-projects/noir-protocol-circuits/bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ readarray -t ivc_tail_patterns < <(jq -r '.[]' "../client_ivc_tail_circuits.json
readarray -t rollup_honk_patterns < <(jq -r '.[]' "../rollup_honk_circuits.json")
# Convert to regex string here and export for use in exported functions.
export ivc_regex=$(IFS="|"; echo "${ivc_patterns[*]}")
export private_tail_regex=$(IFS="|"; echo "${ivc_tail_patterns[*]}")
export ivc_tail_regex=$(IFS="|"; echo "${ivc_tail_patterns[*]}")
export rollup_honk_regex=$(IFS="|"; echo "${rollup_honk_patterns[*]}")

function on_exit {
Expand Down Expand Up @@ -90,9 +90,9 @@ function compile {
local outdir=$(mktemp -d)
trap "rm -rf $outdir" EXIT
function write_vk {
if echo "$name" | grep -qE "${private_tail_regex}"; then
if echo "$name" | grep -qE "${ivc_tail_regex}"; then
# We still need the standalone IVC vk. We also create the final IVC vk from the tail (specifically, the number of public inputs is used from it).
denoise "$BB write_vk --scheme client_ivc --verifier_type standalone -b - -o $outdir"
denoise "$BB write_vk --scheme client_ivc --verifier_type standalone_hiding -b - -o $outdir"
elif echo "$name" | grep -qE "${ivc_regex}"; then
denoise "$BB write_vk --scheme client_ivc --verifier_type standalone -b - -o $outdir"
elif echo "$name" | grep -qE "${rollup_honk_regex}"; then
Expand Down Expand Up @@ -130,7 +130,7 @@ function compile {
echo_stderr "Root rollup verifier at: $verifier_path (${SECONDS}s)"
# Include the verifier path if we create it.
cache_upload vk-$hash.tar.gz $key_path $verifier_path &> /dev/null
elif echo "$name" | grep -qE "${private_tail_regex}"; then
elif echo "$name" | grep -qE "${ivc_tail_regex}"; then
# If we are a tail kernel circuit, we also need to generate the ivc vk.
SECONDS=0
local ivc_vk_path="$key_dir/${name}.ivc.vk"
Expand Down
Loading
Loading