diff --git a/crates/starknet_os/src/lib.rs b/crates/starknet_os/src/lib.rs index 0faa8ee0d3c..7e5c0609c62 100644 --- a/crates/starknet_os/src/lib.rs +++ b/crates/starknet_os/src/lib.rs @@ -6,6 +6,7 @@ pub mod hint_processor; pub mod hints; pub mod io; pub mod metrics; +pub mod proof_fact_fold; pub mod runner; pub mod syscall_handler_utils; #[cfg(any(test, feature = "testing"))] diff --git a/crates/starknet_os/src/proof_fact_fold.rs b/crates/starknet_os/src/proof_fact_fold.rs new file mode 100644 index 00000000000..8bd09d872e6 --- /dev/null +++ b/crates/starknet_os/src/proof_fact_fold.rs @@ -0,0 +1,31 @@ +//! Reproduces the proving side's recursive proof-tree digests over privacy transactions' +//! proof facts. Matches the goldens from the `proving` crate `stwo_run_and_prove_recursive_tree`. + +use blake2::{Blake2s256, Digest}; +use starknet_types_core::felt::Felt; +use starknet_types_core::hash::Blake2Felt252; + +#[cfg(test)] +#[path = "proof_fact_fold_test.rs"] +mod proof_fact_fold_test; + +pub const BLAKE2S_DIGEST_N_WORDS: usize = 8; + +/// A Blake2s-256 digest as little-endian u32 words. +pub type Blake2sDigestWords = [u32; BLAKE2S_DIGEST_N_WORDS]; + +/// Computes one transaction's leaf output digest: +/// blake2s(encode_felt252s_to_u32s(proof_facts[2..])). The preimage drops the two +/// version markers, keeping [program_hash, ...virtual OS output]. +pub fn compute_leaf_output_digest(proof_facts: &[Felt]) -> Blake2sDigestWords { + assert!(proof_facts.len() >= 3, "proof facts must contain at least 3 felts"); + blake2s_over_u32_words(&Blake2Felt252::encode_felts_to_u32s(&proof_facts[2..])) +} + +pub fn blake2s_over_u32_words(words: &[u32]) -> Blake2sDigestWords { + let bytes: Vec = words.iter().flat_map(|word| word.to_le_bytes()).collect(); + let digest_bytes: [u8; 32] = Blake2s256::digest(&bytes).into(); + std::array::from_fn(|word_index| { + u32::from_le_bytes(digest_bytes[word_index * 4..(word_index + 1) * 4].try_into().unwrap()) + }) +} diff --git a/crates/starknet_os/src/proof_fact_fold_test.rs b/crates/starknet_os/src/proof_fact_fold_test.rs new file mode 100644 index 00000000000..0dc7dcd22a9 --- /dev/null +++ b/crates/starknet_os/src/proof_fact_fold_test.rs @@ -0,0 +1,23 @@ +use starknet_types_core::felt::Felt; + +use super::{compute_leaf_output_digest, Blake2sDigestWords}; + +#[test] +fn test_leaf_output_digest_matches_proving_side_golden() { + let proving_side_preimage = [ + Felt::from_dec_str( + "1433852663250257978909904594223798547176815246431631498282706690602142197827", + ) + .unwrap(), + Felt::from(11), + Felt::from(13), + Felt::from(17), + ]; + let proof_facts: Vec = + [Felt::ZERO, Felt::ZERO].into_iter().chain(proving_side_preimage).collect(); + let expected_digest_words: Blake2sDigestWords = [ + 1603116091, 3258597502, 2711032228, 4175407283, 343882323, 1898618121, 1344732087, + 1064799167, + ]; + assert_eq!(compute_leaf_output_digest(&proof_facts), expected_digest_words); +}