From 195cdac850c8302a5fd5102a62a07d237a60124f Mon Sep 17 00:00:00 2001 From: beeinger Date: Wed, 11 Sep 2024 11:48:34 +0200 Subject: [PATCH] v0.4.7 - Stark Pedersen Rework --- Cargo.toml | 3 +- src/hasher/core.rs | 5 +- src/hasher/hashers/stark_pedersen.rs | 105 +++++++++++++++++++-------- 3 files changed, 77 insertions(+), 36 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 182f193..50bbff7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "accumulators" -version = "0.4.6" +version = "0.4.7" edition = "2021" license-file = "LICENSE" description = "Complete package of multiple Accumulators with Stores and hashing functions (Hashers)" @@ -24,7 +24,6 @@ hex = "0.4.3" # Hex encoding tiny-keccak = "2.0.2" # Keccak hashing starknet = "0.6.0" # StarkNet pedersen starknet-crypto = "0.6.0" # StarkNet poseidon -primitive-types = "0.10" # U256 primitive type in pedersen uuid = { version = "1.4.1", features = ["v4"] } # UUID parking_lot = "0.12.1" # Sync mutex num-bigint = "0.4.4" # Bigints in hashers (TODO: double check if needed) diff --git a/src/hasher/core.rs b/src/hasher/core.rs index 0c8523c..574fbfc 100644 --- a/src/hasher/core.rs +++ b/src/hasher/core.rs @@ -1,3 +1,4 @@ +use starknet::core::types::FromStrError; use std::{fmt::Debug, str::FromStr}; use strum_macros::EnumIter; use thiserror::Error; @@ -16,10 +17,10 @@ pub enum HasherError { }, #[error("Invalid elements length for hashing function")] InvalidElementsLength, - #[error("Fail to convert to U256")] - U256ConversionError, #[error("Fail to decode hex")] HexDecodeError(#[from] hex::FromHexError), + #[error("Fail to convert to felt")] + FeltConversionError(#[from] FromStrError), } /// A trait for hash functions diff --git a/src/hasher/hashers/stark_pedersen.rs b/src/hasher/hashers/stark_pedersen.rs index 0460d07..b7b2c20 100644 --- a/src/hasher/hashers/stark_pedersen.rs +++ b/src/hasher/hashers/stark_pedersen.rs @@ -1,4 +1,3 @@ -use primitive_types::U256; use starknet::core::{crypto::pedersen_hash, types::FieldElement}; use crate::hasher::{byte_size, HasherError, HashingFunction}; @@ -17,43 +16,18 @@ impl Hasher for StarkPedersenHasher { HashingFunction::Pedersen } - /// Hashes a data which is a vector of strings - /// - /// NOTE: data should be of size 2 fn hash(&self, data: Vec) -> Result { - if data.len() != 2 { + if data.len() < 2 { return Err(HasherError::InvalidElementsLength); } - for element in &data { - self.is_element_size_valid(element)?; + let mut elements = data.into_iter(); + let mut hash = elements.next().unwrap(); + for element in elements { + hash = self.internal_hash(vec![hash, element])?; } - let mut clean_data = Vec::with_capacity(data.len()); - for s in data.iter() { - let number_str = if let Some(stripped) = s.strip_prefix("0x") { - U256::from_str_radix(stripped, 16) - } else { - U256::from_str_radix(s, 16) - }; - - match number_str { - Ok(number) => clean_data.push(number.to_string()), - Err(_) => return Err(HasherError::U256ConversionError), - } - } - - let result = pedersen_hash( - &FieldElement::from_dec_str(&clean_data[0]).unwrap_or_default(), - &FieldElement::from_dec_str(&clean_data[1]).unwrap_or_default(), - ) - .to_string(); - - let computed_result = - U256::from_dec_str(result.trim()).map_err(|_| HasherError::U256ConversionError)?; - let padded_hex_str = format!("0x{:064x}", computed_result); - - Ok(padded_hex_str) + Ok(hash) } fn is_element_size_valid(&self, element: &str) -> Result { @@ -83,6 +57,28 @@ impl Hasher for StarkPedersenHasher { } impl StarkPedersenHasher { + /// Hashes a data which is a vector of hex strings + /// + /// NOTE: data should be of size 2 + fn internal_hash(&self, data: Vec) -> Result { + if data.len() != 2 { + return Err(HasherError::InvalidElementsLength); + } + + for element in &data { + self.is_element_size_valid(element)?; + } + + let result = pedersen_hash( + &FieldElement::from_hex_be(&data[0])?, + &FieldElement::from_hex_be(&data[1])?, + ) + .to_bytes_be(); + + let padded_hex_str = format!("0x{:0>64}", hex::encode(result)); + Ok(padded_hex_str) + } + pub fn new() -> Self { Self { block_size_bits: 252, @@ -95,3 +91,48 @@ impl Default for StarkPedersenHasher { Self::new() } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_stark_pedersen_hasher_cairo_playground_reference_1() { + let hasher = StarkPedersenHasher::new(); + let data = vec![ + // 314 + "0x13a".to_string(), + // 159 + "0x9f".to_string(), + ]; + let hash = hasher.hash(data).unwrap(); + assert_eq!( + hash, + // 307958720726328212653290369969069617958360335228383070119367204176047090109 + "0x00ae4c67cf8deb4f68f6bad0ce61be81097cf082b4bfa83c637af99a978fa9bd", + "Hashes do not match" + ); + } + + #[test] + fn test_stark_pedersen_hasher_cairo_playground_reference_2() { + let hasher = StarkPedersenHasher::new(); + let data = vec![ + // 314 + "0x13a".to_string(), + // 159 + "0x9f".to_string(), + // 265 + "0x109".to_string(), + // 358 + "0x166".to_string(), + ]; + let hash = hasher.hash(data).unwrap(); + assert_eq!( + hash, + // 1828757374677754028678056220799392919487521050857166686061558043629802016816 + "0x040b0a3d05cf798d507d2b4b2725bb28b00d16c0ceefa2222aa04cc88518d030", + "Hashes do not match" + ); + } +}