Skip to content

Commit

Permalink
tests: verifier: scaffolding for verifier integration tests
Browse files Browse the repository at this point in the history
  • Loading branch information
akirillo committed Aug 8, 2023
1 parent b13ce77 commit 4026c30
Show file tree
Hide file tree
Showing 4 changed files with 201 additions and 12 deletions.
8 changes: 4 additions & 4 deletions src/testing/tests/verifier_tests.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ fn test_full_verification_ex_proof() {
'executing verification job'.print();
verifier.step_verification(11);

let verification_job = verifier.get_verification_job(11);
assert(verification_job.verified == Option::Some(true), 'verification failed');
let verified = verifier.check_verification_job_status(11);
assert(verified == Option::Some(true), 'verification failed');
'proof verified!'.print();
}

Expand All @@ -119,8 +119,8 @@ fn test_full_verification_modified_proof() {
'executing verification job'.print();
verifier.step_verification(11);

let verification_job = verifier.get_verification_job(11);
assert(verification_job.verified == Option::Some(true), 'verification failed');
let verified = verifier.check_verification_job_status(11);
assert(verified == Option::Some(true), 'verification failed');
}

// 10x more gas for this test so that verification definitely completes,
Expand Down
10 changes: 6 additions & 4 deletions src/verifier.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ trait IVerifier<TContractState> {
);
fn step_verification(ref self: TContractState, verification_job_id: felt252);
fn get_circuit_params(self: @TContractState) -> CircuitParams;
fn get_verification_job(self: @TContractState, verification_job_id: felt252) -> VerificationJob;
fn check_verification_job_status(
self: @TContractState, verification_job_id: felt252
) -> Option<bool>;
}

#[starknet::contract]
Expand Down Expand Up @@ -295,10 +297,10 @@ mod Verifier {
}
}

fn get_verification_job(
fn check_verification_job_status(
self: @ContractState, verification_job_id: felt252
) -> VerificationJob {
self.verification_queue.read(verification_job_id).inner
) -> Option<bool> {
self.verification_queue.read(verification_job_id).inner.verified
}
}

Expand Down
47 changes: 44 additions & 3 deletions tests/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use starknet::{
providers::Provider,
};
use starknet_scripts::commands::utils::ScriptAccount;
use std::{env, iter, sync::Once};
use std::{env, sync::Once};
use tracing::debug;
use tracing_subscriber::{fmt, EnvFilter};

Expand Down Expand Up @@ -259,13 +259,36 @@ impl MatchPayload {
}
}

pub struct CircuitParams {
pub n: usize,
pub n_plus: usize,
pub k: usize,
pub q: usize,
pub m: usize,
pub b: StarkPoint,
pub b_blind: StarkPoint,
pub w_l: SparseReducedMatrix,
pub w_r: SparseReducedMatrix,
pub w_o: SparseReducedMatrix,
pub w_v: SparseReducedMatrix,
pub c: SparseWeightRow,
}

pub trait CalldataSerializable {
fn to_calldata(&self) -> Vec<FieldElement>;
}

impl CalldataSerializable for usize {
fn to_calldata(&self) -> Vec<FieldElement> {
vec![FieldElement::from(*self)]
}
}

impl<T: CalldataSerializable> CalldataSerializable for Vec<T> {
fn to_calldata(&self) -> Vec<FieldElement> {
iter::once(FieldElement::from(self.len()))
self.len()
.to_calldata()
.into_iter()
.chain(self.iter().flat_map(|t| t.to_calldata()))
.collect()
}
Expand All @@ -274,7 +297,9 @@ impl<T: CalldataSerializable> CalldataSerializable for Vec<T> {
// `(usize, Scalar)` represents an entry in a `SparseWeightRow`
impl CalldataSerializable for (usize, Scalar) {
fn to_calldata(&self) -> Vec<FieldElement> {
iter::once(FieldElement::from(self.0))
self.0
.to_calldata()
.into_iter()
.chain(self.1.to_calldata().into_iter())
.collect()
}
Expand Down Expand Up @@ -377,3 +402,19 @@ impl CalldataSerializable for MatchPayload {
.collect()
}
}

impl CalldataSerializable for CircuitParams {
fn to_calldata(&self) -> Vec<FieldElement> {
[self.n, self.n_plus, self.k, self.q, self.m]
.iter()
.flat_map(|s| s.to_calldata())
.chain([self.b, self.b_blind].iter().flat_map(|s| s.to_calldata()))
.chain(
[&self.w_l, &self.w_r, &self.w_o, &self.w_v]
.iter()
.flat_map(|s| s.to_calldata()),
)
.chain(self.c.to_calldata().into_iter())
.collect()
}
}
148 changes: 147 additions & 1 deletion tests/src/verifier/utils.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,160 @@
use dojo_test_utils::sequencer::TestSequencer;
use eyre::{eyre, Result};
use merlin::HashChainTranscript;
use mpc_bulletproof::{
r1cs::{ConstraintSystem, Prover, R1CSProof, Variable, Verifier},
BulletproofGens, PedersenGens,
};
use mpc_stark::algebra::{scalar::Scalar, stark_curve::StarkPoint};
use once_cell::sync::OnceCell;
use rand::thread_rng;
use starknet::core::types::{DeclareTransactionResult, FieldElement};
use starknet_scripts::commands::utils::{
calculate_contract_address, declare, deploy, get_artifacts, initialize, ScriptAccount,
};
use std::{env, iter};
use tracing::debug;

use crate::utils::TRANSCRIPT_SEED;
use crate::utils::{
call_contract, global_setup, invoke_contract, CalldataSerializable, CircuitParams,
ARTIFACTS_PATH_ENV_VAR, TRANSCRIPT_SEED,
};

const VERIFIER_CONTRACT_NAME: &str = "renegade_contracts_Verifier";

const QUEUE_VERIFICATION_JOB_FN_NAME: &str = "queue_verification_job";
const STEP_VERIFICATION_FN_NAME: &str = "step_verification";
const CHECK_VERIFICATION_JOB_STATUS_FN_NAME: &str = "check_verification_job_status";

static VERIFIER_ADDRESS: OnceCell<FieldElement> = OnceCell::new();

// ---------------------
// | META TEST HELPERS |
// ---------------------

pub async fn setup_verifier_test<'t, 'g>(
verifier: &mut Verifier<'t, 'g>,
pc_gens: PedersenGens,
) -> Result<TestSequencer> {
let artifacts_path = env::var(ARTIFACTS_PATH_ENV_VAR).unwrap();

let sequencer = global_setup().await;
let account = sequencer.account();

debug!("Declaring & deploying verifier contract...");
let verifier_address = deploy_verifier(artifacts_path, &account).await?;
if VERIFIER_ADDRESS.get().is_none() {
// When running multiple tests, it's possible for the OnceCell to already be set.
// However, we still want to deploy the contract, since each test gets its own sequencer.
VERIFIER_ADDRESS.set(verifier_address).unwrap();
}

debug!("Initializing verifier contract...");
initialize_verifier(&account, verifier_address, verifier, pc_gens).await?;

Ok(sequencer)
}

pub async fn deploy_verifier(
artifacts_path: String,
account: &ScriptAccount,
) -> Result<FieldElement> {
let (verifier_sierra_path, verifier_casm_path) =
get_artifacts(&artifacts_path, VERIFIER_CONTRACT_NAME);
let DeclareTransactionResult { class_hash, .. } =
declare(verifier_sierra_path, verifier_casm_path, account).await?;

deploy(account, class_hash, &[]).await?;
Ok(calculate_contract_address(class_hash, &[]))
}

// --------------------------------
// | CONTRACT INTERACTION HELPERS |
// --------------------------------

pub async fn initialize_verifier<'t, 'g>(
account: &ScriptAccount,
verifier_address: FieldElement,
verifier: &Verifier<'t, 'g>,
pc_gens: PedersenGens,
) -> Result<()> {
let circuit_weights = verifier.get_weights();
let circuit_params = CircuitParams {
n: DUMMY_CIRCUIT_N,
n_plus: DUMMY_CIRCUIT_N_PLUS,
k: DUMMY_CIRCUIT_K,
q: DUMMY_CIRCUIT_Q,
m: DUMMY_CIRCUIT_M,
b: pc_gens.B,
b_blind: pc_gens.B_blinding,
w_l: circuit_weights.w_l,
w_o: circuit_weights.w_o,
w_r: circuit_weights.w_r,
w_v: circuit_weights.w_v,
c: circuit_weights.c,
};
let calldata = circuit_params.to_calldata();

initialize(account, verifier_address, calldata)
.await
.map(|_| ())
}

pub async fn queue_verification_job(
account: &ScriptAccount,
proof: &R1CSProof,
witness_commitments: &Vec<StarkPoint>,
verification_job_id: FieldElement,
) -> Result<()> {
let calldata = proof
.to_calldata()
.into_iter()
.chain(witness_commitments.to_calldata().into_iter())
.chain(iter::once(verification_job_id))
.collect();

invoke_contract(
account,
*VERIFIER_ADDRESS.get().unwrap(),
QUEUE_VERIFICATION_JOB_FN_NAME,
calldata,
)
.await
}

pub async fn step_verification(
account: &ScriptAccount,
verification_job_id: FieldElement,
) -> Result<()> {
invoke_contract(
account,
*VERIFIER_ADDRESS.get().unwrap(),
STEP_VERIFICATION_FN_NAME,
vec![verification_job_id],
)
.await
}

pub async fn check_verification_job_status(
account: &ScriptAccount,
verification_job_id: FieldElement,
) -> Result<Option<bool>> {
call_contract(
account,
*VERIFIER_ADDRESS.get().unwrap(),
CHECK_VERIFICATION_JOB_STATUS_FN_NAME,
vec![verification_job_id],
)
.await
.map(|r| {
if r[0] == FieldElement::ONE {
// This is how Cairo serializes an Option::None
None
} else {
Some(r[1] == FieldElement::ONE)
}
})
}

// -------------------------
// | DUMMY CIRCUIT HELPERS |
Expand Down

0 comments on commit 4026c30

Please sign in to comment.