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

program hash and output hash #12

Closed
wants to merge 1 commit into from
Closed
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
14 changes: 11 additions & 3 deletions crates/air/src/layout/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ pub trait LayoutTrait {
trace_generator: &Felt,
) -> Felt;

fn validate(
fn validate_public_input(
public_input: &PublicInput,
stark_domains: &StarkDomains,
) -> Result<(), PublicInputValidateError>;
) -> Result<(), PublicInputError>;

fn traces_commit(
transcript: &mut Transcript,
Expand All @@ -42,6 +42,8 @@ pub trait LayoutTrait {
decommitment: crate::trace::Decommitment,
witness: crate::trace::Witness,
) -> Result<(), crate::trace::decommit::Error>;

fn verify_public_input(public_input: &PublicInput) -> Result<(Felt, Felt), PublicInputError>;
}

use thiserror::Error;
Expand All @@ -53,7 +55,7 @@ pub enum CompositionPolyEvalError {
}

#[derive(Error, Debug)]
pub enum PublicInputValidateError {
pub enum PublicInputError {
#[error("max steps exceeded")]
MaxSteps,

Expand All @@ -72,3 +74,9 @@ pub enum PublicInputValidateError {
#[error("invalid number of builtin uses")]
UsesInvalid,
}

pub mod segments {
pub const EXECUTION: usize = 1;
pub const OUTPUT: usize = 2;
pub const PROGRAM: usize = 0;
}
150 changes: 108 additions & 42 deletions crates/air/src/layout/recursive/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ pub mod global_values;
use crate::{
diluted::get_diluted_product,
periodic_columns::{eval_pedersen_x, eval_pedersen_y},
public_memory::{PublicInput, MAX_LOG_N_STEPS, MAX_RANGE_CHECK},
public_memory::{PublicInput, INITIAL_PC, MAX_ADDRESS, MAX_LOG_N_STEPS, MAX_RANGE_CHECK},
};
use bail_out::ensure;
use cairovm_verifier_commitment::table::{commit::table_commit, decommit::table_decommit};
use global_values::{EcPoint, GlobalValues, InteractionElements};
use starknet_core::types::NonZeroFelt;
use starknet_crypto::Felt;
use starknet_crypto::{poseidon_hash_many, Felt};

use super::{CompositionPolyEvalError, LayoutTrait, PublicInputValidateError};
use super::{CompositionPolyEvalError, LayoutTrait, PublicInputError};

// Recursive layout consts
pub const BITWISE_RATIO: u32 = 8;
Expand Down Expand Up @@ -51,11 +51,8 @@ pub const RANGE_CHECK_N_PARTS: u32 = 8;

pub mod segments {
pub const BITWISE: usize = 5;
pub const EXECUTION: usize = 1;
pub const N_SEGMENTS: usize = 6;
pub const OUTPUT: usize = 2;
pub const PEDERSEN: usize = 3;
pub const PROGRAM: usize = 0;
pub const RANGE_CHECK: usize = 4;
}

Expand Down Expand Up @@ -127,23 +124,31 @@ impl LayoutTrait for RecursiveLayout {
trace_length: *trace_domain_size,
initial_pc: public_input
.segments
.get(segments::PROGRAM)
.ok_or(CompositionPolyEvalError::SegmentMissing { segment: segments::PROGRAM })?
.get(crate::layout::segments::PROGRAM)
.ok_or(CompositionPolyEvalError::SegmentMissing {
segment: crate::layout::segments::PROGRAM,
})?
.begin_addr,
final_pc: public_input
.segments
.get(segments::PROGRAM)
.ok_or(CompositionPolyEvalError::SegmentMissing { segment: segments::PROGRAM })?
.get(crate::layout::segments::PROGRAM)
.ok_or(CompositionPolyEvalError::SegmentMissing {
segment: crate::layout::segments::PROGRAM,
})?
.stop_ptr,
initial_ap: public_input
.segments
.get(segments::EXECUTION)
.ok_or(CompositionPolyEvalError::SegmentMissing { segment: segments::EXECUTION })?
.get(crate::layout::segments::EXECUTION)
.ok_or(CompositionPolyEvalError::SegmentMissing {
segment: crate::layout::segments::EXECUTION,
})?
.begin_addr,
final_ap: public_input
.segments
.get(segments::EXECUTION)
.ok_or(CompositionPolyEvalError::SegmentMissing { segment: segments::EXECUTION })?
.get(crate::layout::segments::EXECUTION)
.ok_or(CompositionPolyEvalError::SegmentMissing {
segment: crate::layout::segments::EXECUTION,
})?
.stop_ptr,
initial_pedersen_addr: public_input
.segments
Expand Down Expand Up @@ -243,94 +248,155 @@ impl LayoutTrait for RecursiveLayout {
witness.interaction,
))?)
}
fn validate(
fn validate_public_input(
public_input: &PublicInput,
stark_domains: &crate::domains::StarkDomains,
) -> Result<(), PublicInputValidateError> {
ensure!(public_input.log_n_steps < MAX_LOG_N_STEPS, PublicInputValidateError::MaxSteps);
) -> Result<(), PublicInputError> {
ensure!(public_input.log_n_steps < MAX_LOG_N_STEPS, PublicInputError::MaxSteps);

let n_steps = Felt::TWO.pow_felt(&public_input.log_n_steps);
let trace_length = stark_domains.trace_domain_size;
ensure!(
n_steps * Felt::from(CPU_COMPONENT_HEIGHT) * Felt::from(CPU_COMPONENT_STEP)
== trace_length,
PublicInputValidateError::TraceLengthInvalid
PublicInputError::TraceLengthInvalid
);

ensure!(
Felt::ZERO <= public_input.range_check_min,
PublicInputValidateError::RangeCheckInvalid
);
ensure!(Felt::ZERO <= public_input.range_check_min, PublicInputError::RangeCheckInvalid);
ensure!(
public_input.range_check_min < public_input.range_check_max,
PublicInputValidateError::RangeCheckInvalid
PublicInputError::RangeCheckInvalid
);
ensure!(
public_input.range_check_max <= MAX_RANGE_CHECK,
PublicInputValidateError::RangeCheckInvalid
PublicInputError::RangeCheckInvalid
);

ensure!(
public_input.layout == LAYOUT_CODE.into(),
PublicInputValidateError::LayoutCodeInvalid
);
ensure!(public_input.layout == LAYOUT_CODE.into(), PublicInputError::LayoutCodeInvalid);

let output_uses = public_input
.segments
.get(segments::OUTPUT)
.ok_or(PublicInputValidateError::SegmentMissing { segment: segments::OUTPUT })?
.get(crate::layout::segments::OUTPUT)
.ok_or(PublicInputError::SegmentMissing { segment: crate::layout::segments::OUTPUT })?
.stop_ptr
- public_input
.segments
.get(segments::OUTPUT)
.ok_or(PublicInputValidateError::SegmentMissing { segment: segments::OUTPUT })?
.get(crate::layout::segments::OUTPUT)
.ok_or(PublicInputError::SegmentMissing {
segment: crate::layout::segments::OUTPUT,
})?
.begin_addr;
ensure!(output_uses < u128::MAX.into(), PublicInputValidateError::UsesInvalid);
ensure!(output_uses < u128::MAX.into(), PublicInputError::UsesInvalid);

let pedersen_copies = trace_length
.field_div(&NonZeroFelt::from_felt_unchecked(Felt::from(PEDERSEN_BUILTIN_ROW_RATIO)));
let pedersen_uses = (public_input
.segments
.get(segments::PEDERSEN)
.ok_or(PublicInputValidateError::SegmentMissing { segment: segments::OUTPUT })?
.ok_or(PublicInputError::SegmentMissing { segment: crate::layout::segments::OUTPUT })?
.stop_ptr
- public_input
.segments
.get(segments::PEDERSEN)
.ok_or(PublicInputValidateError::SegmentMissing { segment: segments::OUTPUT })?
.ok_or(PublicInputError::SegmentMissing {
segment: crate::layout::segments::OUTPUT,
})?
.begin_addr)
.field_div(&NonZeroFelt::from_felt_unchecked(Felt::THREE));
ensure!(pedersen_uses < pedersen_copies, PublicInputValidateError::UsesInvalid);
ensure!(pedersen_uses < pedersen_copies, PublicInputError::UsesInvalid);

let range_check_copies = trace_length.field_div(&NonZeroFelt::from_felt_unchecked(
Felt::from(RANGE_CHECK_BUILTIN_ROW_RATIO),
));
let range_check_uses = public_input
.segments
.get(segments::RANGE_CHECK)
.ok_or(PublicInputValidateError::SegmentMissing { segment: segments::OUTPUT })?
.ok_or(PublicInputError::SegmentMissing { segment: crate::layout::segments::OUTPUT })?
.stop_ptr
- public_input
.segments
.get(segments::RANGE_CHECK)
.ok_or(PublicInputValidateError::SegmentMissing { segment: segments::OUTPUT })?
.ok_or(PublicInputError::SegmentMissing {
segment: crate::layout::segments::OUTPUT,
})?
.begin_addr;
ensure!(range_check_uses < range_check_copies, PublicInputValidateError::UsesInvalid);
ensure!(range_check_uses < range_check_copies, PublicInputError::UsesInvalid);

let bitwise_copies = trace_length
.field_div(&NonZeroFelt::from_felt_unchecked(Felt::from(BITWISE_ROW_RATIO)));
let bitwise_uses = (public_input
.segments
.get(segments::BITWISE)
.ok_or(PublicInputValidateError::SegmentMissing { segment: segments::OUTPUT })?
.ok_or(PublicInputError::SegmentMissing { segment: crate::layout::segments::OUTPUT })?
.stop_ptr
- public_input
.segments
.get(segments::BITWISE)
.ok_or(PublicInputValidateError::SegmentMissing { segment: segments::OUTPUT })?
.ok_or(PublicInputError::SegmentMissing {
segment: crate::layout::segments::OUTPUT,
})?
.begin_addr)
.field_div(&NonZeroFelt::from_felt_unchecked(Felt::from(0x5)));
ensure!(bitwise_uses < bitwise_copies, PublicInputValidateError::UsesInvalid);
ensure!(bitwise_uses < bitwise_copies, PublicInputError::UsesInvalid);
Ok(())
}

fn verify_public_input(public_input: &PublicInput) -> Result<(Felt, Felt), PublicInputError> {
let public_segments = &public_input.segments;

let initial_pc = public_segments
.get(crate::layout::segments::PROGRAM)
.ok_or(PublicInputError::SegmentMissing { segment: crate::layout::segments::PROGRAM })?
.begin_addr;
let final_pc = public_segments
.get(crate::layout::segments::PROGRAM)
.ok_or(PublicInputError::SegmentMissing { segment: crate::layout::segments::PROGRAM })?
.stop_ptr;
let initial_ap = public_segments
.get(crate::layout::segments::EXECUTION)
.ok_or(PublicInputError::SegmentMissing { segment: crate::layout::segments::PROGRAM })?
.begin_addr;
let initial_fp = initial_ap;
let final_ap = public_segments
.get(crate::layout::segments::EXECUTION)
.ok_or(PublicInputError::SegmentMissing { segment: crate::layout::segments::PROGRAM })?
.stop_ptr;
let output_start = public_segments
.get(crate::layout::segments::OUTPUT)
.ok_or(PublicInputError::SegmentMissing { segment: crate::layout::segments::PROGRAM })?
.begin_addr;
let output_stop = public_segments
.get(crate::layout::segments::OUTPUT)
.ok_or(PublicInputError::SegmentMissing { segment: crate::layout::segments::PROGRAM })?
.stop_ptr;

ensure!(initial_ap < MAX_ADDRESS, PublicInputError::MaxSteps);
ensure!(final_ap < MAX_ADDRESS, PublicInputError::MaxSteps);

// TODO support more pages?
ensure!(public_input.continuous_page_headers.is_empty(), PublicInputError::MaxSteps);

let memory = &public_input
.main_page
.iter()
.flat_map(|v| vec![v.address, v.value])
.collect::<Vec<Felt>>();

// 1. Program segment
ensure!(initial_pc == INITIAL_PC, PublicInputError::MaxSteps);
ensure!(final_pc == INITIAL_PC + 4, PublicInputError::MaxSteps);

let program_end_pc = initial_fp - 2;
let program = &memory[initial_pc.to_bigint().try_into().unwrap()
..program_end_pc.to_bigint().try_into().unwrap()];

let program_hash = poseidon_hash_many(program);

let output_len: usize = (output_stop - output_start).to_bigint().try_into().unwrap();
// 3. Output segment
let output = &memory[memory.len() - output_len..memory.len()];
let output_hash = poseidon_hash_many(output);

Ok((program_hash, output_hash))
}
}
6 changes: 4 additions & 2 deletions crates/air/src/public_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ use starknet_core::{serde::unsigned_field_element::UfeHex, types::NonZeroFelt};
use starknet_crypto::{pedersen_hash, poseidon_hash_many, Felt};

pub const MAX_LOG_N_STEPS: Felt = Felt::from_hex_unchecked("50");
pub const MAX_RANGE_CHECK: Felt = Felt::from_hex_unchecked("0xffff"); // 2 ** 16 - 1
pub const MAX_RANGE_CHECK: Felt = Felt::from_hex_unchecked("0xffff");
pub const MAX_ADDRESS: Felt = Felt::from_hex_unchecked("0xffffffffffffffff");
pub const INITIAL_PC: Felt = Felt::from_hex_unchecked("0x1");

#[serde_as]
#[derive(Debug, PartialEq, Serialize, Deserialize)]
Expand Down Expand Up @@ -65,7 +67,7 @@ impl PublicInput {
(prod, total_length)
}

pub fn get_public_input_hash(&self) -> Felt {
pub fn get_hash(&self) -> Felt {
let mut main_page_hash = Felt::ZERO;
for memory in self.main_page.iter() {
main_page_hash = pedersen_hash(&main_page_hash, &memory.address);
Expand Down
2 changes: 1 addition & 1 deletion crates/air/src/tests/public_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use starknet_crypto::Felt;
fn test_public_input_hash() {
let public_input = get();
assert_eq!(
public_input.get_public_input_hash(),
public_input.get_hash(),
Felt::from_hex_unchecked(
"0xaf91f2c71f4a594b1575d258ce82464475c82d8fb244142d0db450491c1b52"
)
Expand Down
14 changes: 7 additions & 7 deletions crates/stark/src/stark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ use crate::{
};

impl StarkProof {
pub fn verify<Layout: LayoutTrait>(&self, security_bits: Felt) -> Result<Felt, Error> {
pub fn verify<Layout: LayoutTrait>(&self, security_bits: Felt) -> Result<(Felt, Felt), Error> {
self.config.validate(security_bits)?;

// Validate the public input.
let stark_domains =
StarkDomains::new(self.config.log_trace_domain_size, self.config.log_n_cosets);

Layout::validate(&self.public_input, &stark_domains)?;
Layout::validate_public_input(&self.public_input, &stark_domains)?;

// Compute the initial hash seed for the Fiat-Shamir transcript.
let digest = self.public_input.get_public_input_hash();
let digest = self.public_input.get_hash();
// Construct the transcript.
let mut transcript = Transcript::new(digest);

Expand Down Expand Up @@ -43,15 +43,15 @@ impl StarkProof {
&stark_domains,
)?;

Ok(digest)
Ok(Layout::verify_public_input(&self.public_input)?)
}
}

use cairovm_verifier_air::{
domains::StarkDomains,
layout::{
recursive::{NUM_COLUMNS_FIRST, NUM_COLUMNS_SECOND},
LayoutTrait, PublicInputValidateError,
LayoutTrait, PublicInputError,
},
};
use cairovm_verifier_transcript::transcript::Transcript;
Expand All @@ -63,8 +63,8 @@ pub enum Error {
#[error("Vector Error")]
Validation(#[from] crate::config::Error),

#[error("PublicInputValidateError Error")]
PublicInputValidateError(#[from] PublicInputValidateError),
#[error("PublicInputError Error")]
PublicInputError(#[from] PublicInputError),

#[error("Commit Error")]
Commit(#[from] crate::commit::Error),
Expand Down
4 changes: 3 additions & 1 deletion crates/stark/src/tests/proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,7 @@ fn test_stark_proof_fibonacci_verify() {
witness: witness::get(),
};

stark_proof.verify::<RecursiveLayout>(security_bits).unwrap();
let (program_hash, output_hash) = stark_proof.verify::<RecursiveLayout>(security_bits).unwrap();
assert_eq!(program_hash, Felt::from_hex_unchecked("0x603f45d671891116de1e763d11d71d25102ff93707dafc97a8d06e18145baf5"));
assert_eq!(output_hash, Felt::from_hex_unchecked("0x21e35055ced9a22156eed737abcea133f8406f7f7e78222cf4f0f1271216adb"));
}
Loading