Skip to content

Commit

Permalink
Add verifier
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewmilson committed Oct 22, 2024
1 parent ecdb398 commit a88d74d
Show file tree
Hide file tree
Showing 27 changed files with 31,984 additions and 114 deletions.
1 change: 1 addition & 0 deletions stwo_cairo_verifier/.cairofmtignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#tests/proofs
16 changes: 16 additions & 0 deletions stwo_cairo_verifier/Scarb.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
# Code generated by scarb DO NOT EDIT.
version = 1

[[package]]
name = "snforge_scarb_plugin"
version = "0.1.0"
source = "git+https://github.com/foundry-rs/starknet-foundry?tag=v0.30.0#196f06b251926697c3d66800f2a93ae595e76496"

[[package]]
name = "snforge_std"
version = "0.30.0"
source = "git+https://github.com/foundry-rs/starknet-foundry?tag=v0.30.0#196f06b251926697c3d66800f2a93ae595e76496"
dependencies = [
"snforge_scarb_plugin",
]

[[package]]
name = "stwo_cairo_verifier"
version = "0.1.0"
dependencies = [
"snforge_std",
]
8 changes: 7 additions & 1 deletion stwo_cairo_verifier/Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,10 @@ sort-module-level-items = true
[dependencies]

[dev-dependencies]
cairo_test = "2.8.0"
# cairo_test = "2.8.0"
snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v0.30.0" }
assert_macros = "2.8.0"


[scripts]
test = "snforge test"
11 changes: 9 additions & 2 deletions stwo_cairo_verifier/src/channel.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ use core::array::SpanTrait;
use core::poseidon::{poseidon_hash_span, hades_permutation};
use core::traits::DivRem;
use stwo_cairo_verifier::fields::qm31::QM31Trait;
use stwo_cairo_verifier::utils::pack4;

use stwo_cairo_verifier::utils::{pack4, U128TrailingZerosImpl};
use stwo_cairo_verifier::{BaseField, SecureField};

const M31_SHIFT: felt252 = 0x80000000; // 2**31.
Expand Down Expand Up @@ -137,6 +136,14 @@ pub impl ChannelImpl of ChannelTrait {
};
bytes
}

fn trailing_zeros(self: @Channel) -> u32 {
// TODO(andrew): Think only used for proof of work. Perhaps better to change to
// verify_proof_of_work(n_bits) to channel so can do this as `(q, r) = self.digest / (1 <<
// n_bits); r == 0`.
let u256 { low, .. } = (*self.digest).into();
low.trailing_zeros()
}
}

#[inline]
Expand Down
31 changes: 30 additions & 1 deletion stwo_cairo_verifier/src/circle.cairo
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use core::num::traits::one::One;
use core::num::traits::zero::Zero;
use core::num::traits::{WrappingAdd, WrappingSub, WrappingMul};
use stwo_cairo_verifier::channel::{Channel, ChannelImpl};
use stwo_cairo_verifier::fields::cm31::CM31;
use stwo_cairo_verifier::fields::m31::{M31, M31Impl};
use stwo_cairo_verifier::fields::qm31::{QM31Impl, QM31, QM31Trait};
use stwo_cairo_verifier::fields::qm31::{QM31Impl, QM31One, QM31, QM31Trait};
use super::utils::pow;

/// A generator for the circle group over [`M31`].
Expand Down Expand Up @@ -99,10 +100,38 @@ impl CirclePointAdd<F, +Add<F>, +Sub<F>, +Mul<F>, +Drop<F>, +Copy<F>> of Add<Cir
}
}

impl CirclePointNeg<F, +Neg<F>, +Drop<F>, +Copy<F>> of Neg<CirclePoint<F>> {
fn neg(a: CirclePoint<F>) -> CirclePoint<F> {
CirclePoint { x: a.x, y: -a.y }
}
}

pub impl CirclePointM31Impl of CirclePointTrait<M31> {}

#[generate_trait]
pub impl CirclePointQM31AddCirclePointM31Impl of CirclePointQM31AddCirclePointM31Trait {
fn add_circle_point_m31(self: CirclePoint<QM31>, rhs: CirclePoint<M31>) -> CirclePoint<QM31> {
CirclePoint {
x: self.x.mul_m31(rhs.x) - self.y.mul_m31(rhs.y),
y: self.x.mul_m31(rhs.y) + self.y.mul_m31(rhs.x)
}
}
}

pub impl CirclePointQM31Impl of CirclePointTrait<QM31> {}

#[generate_trait]
pub impl ChannelGetRandomCirclePointImpl of ChannelGetRandomCirclePointTrait {
fn get_random_point(ref self: Channel) -> CirclePoint<QM31> {
let t = self.draw_felt();
let t_squared = t * t;
let t_squared_plus_1_inv = (t_squared + QM31One::one()).inverse();
let x = (QM31One::one() - t_squared) * t_squared_plus_1_inv;
let y = (t + t) * t_squared_plus_1_inv;
CirclePoint { x, y }
}
}

impl CirclePointQM31PartialOrd of PartialOrd<CirclePoint<QM31>> {
fn lt(lhs: CirclePoint<QM31>, rhs: CirclePoint<QM31>) -> bool {
lhs.x < rhs.x || (lhs.x == rhs.x && lhs.y < rhs.y)
Expand Down
2 changes: 1 addition & 1 deletion stwo_cairo_verifier/src/fields/cm31.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub struct CM31 {
#[generate_trait]
pub impl CM31Impl of CM31Trait {
fn inverse(self: CM31) -> CM31 {
assert_ne!(self, Zero::zero());
assert!(self.is_non_zero());
let denom_inverse: M31 = (self.a * self.a + self.b * self.b).inverse();
CM31 { a: self.a * denom_inverse, b: -self.b * denom_inverse }
}
Expand Down
2 changes: 1 addition & 1 deletion stwo_cairo_verifier/src/fields/m31.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub impl M31Impl of M31Trait {
}

fn inverse(self: M31) -> M31 {
assert_ne!(self, core::num::traits::Zero::zero());
assert!(self.is_non_zero());
let t0 = Self::sqn(self, 2) * self;
let t1 = Self::sqn(t0, 1) * t0;
let t2 = Self::sqn(t1, 3) * t0;
Expand Down
19 changes: 18 additions & 1 deletion stwo_cairo_verifier/src/fields/qm31.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use super::m31::{M31, M31Impl, UnreducedM31};
/// Equals `(2^31 - 1)^4`.
pub const P4: u128 = 21267647892944572736998860269687930881;

pub const QM31_EXTENSION_DEGREE: usize = 4;

pub const R: CM31 = CM31 { a: M31 { inner: 2 }, b: M31 { inner: 1 } };

#[derive(Copy, Drop, Debug, PartialEq)]
Expand All @@ -29,7 +31,7 @@ pub impl QM31Impl of QM31Trait {
}

fn inverse(self: QM31) -> QM31 {
assert_ne!(self, Zero::zero());
assert!(self.is_non_zero());
let b2 = self.b * self.b;
let ib2 = CM31 { a: -b2.b, b: b2.a };
let denom = self.a * self.a - (b2 + b2 + ib2);
Expand Down Expand Up @@ -130,6 +132,13 @@ pub impl QM31Impl of QM31Trait {
d: PP16 + aa_t_bb_b + ab_t_ba_b
}
}

/// Returns the combined value, given the values of its composing base field polynomials at that
/// point.
fn from_partial_evals(evals: [QM31; QM31_EXTENSION_DEGREE]) -> QM31 {
let [e0, e1, e2, e3] = evals;
e0 + e1 * qm31(0, 1, 0, 0) + e2 * qm31(0, 0, 1, 0) + e3 * qm31(0, 0, 0, 1)
}
}

pub impl QM31Add of core::traits::Add<QM31> {
Expand All @@ -153,6 +162,14 @@ pub impl QM31Mul of core::traits::Mul<QM31> {
}
}

pub impl QM31Div of core::traits::Div<QM31> {
#[inline]
fn div(lhs: QM31, rhs: QM31) -> QM31 {
// (a + bu) * (c + du) = (ac + rbd) + (ad + bc)u.
lhs * rhs.inverse()
}
}

pub impl QM31AddAssign of AddAssign<QM31, QM31> {
#[inline]
fn add_assign(ref self: QM31, rhs: QM31) {
Expand Down
21 changes: 9 additions & 12 deletions stwo_cairo_verifier/src/fri.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,7 @@ impl FriLayerVerifierImpl of FriLayerVerifierTrait {
};
i += 1;
};
let actual_decommitment_array = array![
column_0.span(), column_1.span(), column_2.span(), column_3.span()
];
let actual_decommitment_array = array![column_0, column_1, column_2, column_3];

let folded_queries = queries.fold(FOLD_STEP);
let folded_queries_snapshot = @folded_queries;
Expand Down Expand Up @@ -107,7 +105,7 @@ impl FriLayerVerifierImpl of FriLayerVerifierTrait {

let decommitment = self.proof.decommitment.clone();
let result = merkle_verifier
.verify(queries_per_log_size, actual_decommitment_array, decommitment.clone());
.verify(queries_per_log_size, @actual_decommitment_array, decommitment.clone());

let evals_at_folded_queries = sparse_evaluation.fold(*self.folding_alpha);
match result {
Expand Down Expand Up @@ -198,14 +196,13 @@ pub struct FriConfig {
pub n_queries: usize,
}


/// Stores a subset of evaluations in a fri layer with their corresponding merkle decommitments.
///
/// The subset corresponds to the set of evaluations needed by a FRI verifier.
#[derive(Drop, Clone, Debug)]
pub struct FriLayerProof {
pub evals_subset: Array<QM31>,
pub decommitment: MerkleDecommitment::<PoseidonMerkleHasher>,
pub decommitment: MerkleDecommitment<PoseidonMerkleHasher>,
pub commitment: felt252,
}

Expand Down Expand Up @@ -318,7 +315,7 @@ pub impl FriVerifierImpl of FriVerifierTrait {
fn decommit_on_queries(
self: @FriVerifier, queries: @Queries, decommitted_values: Array<SparseCircleEvaluation>
) -> Result<(), FriVerificationError> {
assert_eq!(queries.log_domain_size, self.expected_query_log_domain_size);
assert!(queries.log_domain_size == self.expected_query_log_domain_size);

let (last_layer_queries, last_layer_query_evals) = self
.decommit_inner_layers(queries, @decommitted_values)?;
Expand Down Expand Up @@ -423,7 +420,7 @@ pub impl FriVerifierImpl of FriVerifierTrait {
/// The order of the opening positions corresponds to the order of the column commitment.
fn column_query_positions(
ref self: FriVerifier, ref channel: Channel
) -> (Felt252Dict<Nullable<SparseSubCircleDomain>>, Span<u32>) {
) -> (Felt252Dict<Nullable<@SparseSubCircleDomain>>, Span<u32>) {
let queries = QueriesImpl::generate(
ref channel,
*self.column_bounds[0] + self.config.log_blowup_factor,
Expand Down Expand Up @@ -453,13 +450,13 @@ pub impl FriVerifierImpl of FriVerifierTrait {
/// column opening positions are mapped by their log size.
fn get_opening_positions(
queries: @Queries, column_log_sizes: Span<u32>,
) -> Felt252Dict<Nullable<SparseSubCircleDomain>> {
) -> Felt252Dict<Nullable<@SparseSubCircleDomain>> {
let mut prev_log_size = column_log_sizes[0];
assert!(prev_log_size == queries.log_domain_size);
let mut prev_queries = queries.clone();
let mut positions: Felt252Dict<Nullable<SparseSubCircleDomain>> = Default::default();
let mut positions: Felt252Dict<Nullable<@SparseSubCircleDomain>> = Default::default();
let felt_prev: core::felt252 = (*prev_log_size).into();
positions.insert(felt_prev, NullableTrait::new(prev_queries.opening_positions(FOLD_STEP)));
positions.insert(felt_prev, NullableTrait::new(@prev_queries.opening_positions(FOLD_STEP)));

let mut i = 1;
while i < column_log_sizes.len() {
Expand All @@ -468,7 +465,7 @@ fn get_opening_positions(
let felt_column_log_sizes: core::felt252 = (*column_log_sizes.at(i)).into();
positions
.insert(
felt_column_log_sizes, NullableTrait::new(queries.opening_positions(FOLD_STEP))
felt_column_log_sizes, NullableTrait::new(@queries.opening_positions(FOLD_STEP))
);
prev_log_size = column_log_sizes.at(i);
prev_queries = queries;
Expand Down
39 changes: 16 additions & 23 deletions stwo_cairo_verifier/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -1,27 +1,20 @@
mod channel;
mod circle;
mod fields;
mod fri;
mod pcs;
mod poly;
mod queries;
mod utils;
mod vcs;
pub mod channel;
pub mod circle;
pub mod fields;
pub mod fri;
pub mod pcs;
pub mod poly;
pub mod queries;
pub mod utils;
pub mod vcs;
pub mod verifier;

pub use fields::{BaseField, SecureField};

fn main() {}
/// An array in which each element relates (by index) to a column in the trace.
pub type ColumnArray<T> = Array<T>;

/// An array in which each element relates (by index) to a commitment tree.
pub type TreeArray<T> = Array<T>;

#[derive(Clone, Drop)]
pub enum VerificationError {
/// Proof has invalid structure.
InvalidStructure: felt252,
/// Lookup values do not match.
InvalidLookup: felt252,
/// Merkle proof invalid.
Merkle: vcs::verifier::MerkleVerificationError,
/// Proof of work verification failed.
ProofOfWork,
// OodsNotMatching,
// Fri(#[from] FriVerificationError),
}
fn main() {}
7 changes: 7 additions & 0 deletions stwo_cairo_verifier/src/pcs.cairo
Original file line number Diff line number Diff line change
@@ -1 +1,8 @@
mod quotients;
pub mod verifier;

#[derive(Drop, Copy)]
pub struct PcsConfig {
pub pow_bits: u32,
pub fri_config: stwo_cairo_verifier::fri::FriConfig,
}
2 changes: 1 addition & 1 deletion stwo_cairo_verifier/src/pcs/quotients.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use core::dict::{Felt252Dict, Felt252DictEntryTrait};
use core::iter::{IntoIterator, Iterator};
use core::nullable::{Nullable, NullableTrait, null};
use core::num::traits::{One, Zero};
use stwo_cairo_verifier::VerificationError;
use stwo_cairo_verifier::circle::{
CosetImpl, CirclePointIndexImpl, CirclePoint, M31_CIRCLE_LOG_ORDER
};
Expand All @@ -20,6 +19,7 @@ use stwo_cairo_verifier::queries::{
SparseSubCircleDomain, SparseSubCircleDomainImpl, SubCircleDomainImpl
};
use stwo_cairo_verifier::utils::{bit_reverse_index, pack4, ArrayImpl as ArrayUtilImpl};
use stwo_cairo_verifier::verifier::VerificationError;

pub fn fri_answers(
log_size_per_column: @Array<u32>,
Expand Down
Loading

0 comments on commit a88d74d

Please sign in to comment.