From 6f8c152678b411553dcd7f460ad96c97f2b67c53 Mon Sep 17 00:00:00 2001 From: FrancoGiachetta Date: Mon, 31 Mar 2025 16:00:51 -0300 Subject: [PATCH 01/11] implement blake libfunc --- src/libfuncs.rs | 5 +- src/libfuncs/blake.rs | 120 +++++++++++++++++++++++++++ src/metadata/runtime_bindings.rs | 37 +++++++++ src/runtime.rs | 20 ++++- src/types.rs | 19 +++-- src/types/blake.rs | 83 +++++++++++++++++++ src/utils.rs | 1 + src/utils/blake_utils.rs | 134 +++++++++++++++++++++++++++++++ 8 files changed, 410 insertions(+), 9 deletions(-) create mode 100644 src/libfuncs/blake.rs create mode 100644 src/types/blake.rs create mode 100644 src/utils/blake_utils.rs diff --git a/src/libfuncs.rs b/src/libfuncs.rs index 9277e2c2e0..c08b3915b3 100644 --- a/src/libfuncs.rs +++ b/src/libfuncs.rs @@ -33,6 +33,7 @@ use num_bigint::BigInt; use std::{cell::Cell, error::Error, ops::Deref}; mod array; +mod blake; mod r#bool; mod bounded_int; mod r#box; @@ -179,7 +180,9 @@ impl LibfuncBuilder for CoreConcreteLibfunc { Self::IntRange(selector) => self::int_range::build( context, registry, entry, location, helper, metadata, selector, ), - Self::Blake(_) => native_panic!("Implement blake libfunc"), + Self::Blake(selector) => self::blake::build( + context, registry, entry, location, helper, metadata, selector, + ), Self::Mem(selector) => self::mem::build( context, registry, entry, location, helper, metadata, selector, ), diff --git a/src/libfuncs/blake.rs b/src/libfuncs/blake.rs new file mode 100644 index 0000000000..e5b0ab6801 --- /dev/null +++ b/src/libfuncs/blake.rs @@ -0,0 +1,120 @@ +use cairo_lang_sierra::{ + extensions::{ + blake::BlakeConcreteLibfunc, + core::{CoreLibfunc, CoreType}, + lib_func::SignatureOnlyConcreteLibfunc, + }, + program_registry::ProgramRegistry, +}; +use melior::{ + ir::{Block, BlockLike, Location}, + Context, +}; + +use crate::{ + error::{panic::ToNativeAssertError, Result}, + metadata::{runtime_bindings::RuntimeBindingsMeta, MetadataStorage}, + utils::BlockExt, +}; + +use super::LibfuncHelper; + +pub fn build<'ctx, 'this>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + metadata: &mut MetadataStorage, + selector: &BlakeConcreteLibfunc, +) -> Result<()> { + match selector { + BlakeConcreteLibfunc::Blake2sCompress(info) => build_blake_operation( + context, registry, entry, location, helper, metadata, info, false, + ), + BlakeConcreteLibfunc::Blake2sFinalize(info) => build_blake_operation( + context, registry, entry, location, helper, metadata, info, true, + ), + } +} + +/// Performs a blake2s compression. +/// +/// `bytes_count` is the total amount of bytes hashed after hashing the message. +/// `finalize` is wether the libfunc call is a finalize or not. +#[allow(clippy::too_many_arguments)] +fn build_blake_operation<'ctx, 'this>( + context: &'ctx Context, + _registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + metadata: &mut MetadataStorage, + _info: &SignatureOnlyConcreteLibfunc, + finalize: bool, +) -> Result<()> { + let state_ptr = entry.arg(0)?; + let bytes_count = entry.arg(1)?; + let message = entry.arg(2)?; + let k_finalize = entry.const_int(context, location, finalize, 1)?; + + let runtime_bindings = metadata + .get_mut::() + .to_native_assert_error("runtime library should be available")?; + + runtime_bindings.libfunc_blake_compress( + context, + helper, + entry, + state_ptr, + message, + bytes_count, + k_finalize, + location, + )?; + + entry.append_operation(helper.br(0, &[state_ptr], location)); + + Ok(()) +} + +#[cfg(test)] +mod tests { + use crate::{ + utils::test::{jit_struct, load_cairo, run_program}, + Value, + }; + + #[test] + fn test_blake() { + let program = load_cairo!( + use core::blake::{blake2s_compress, blake2s_finalize}; + + fn run_test() -> [u32; 8] nopanic { + let state = BoxTrait::new([0_u32; 8]); + let msg = BoxTrait::new([0_u32; 16]); + let byte_count = 64_u32; + + let _res = blake2s_compress(state, byte_count, msg).unbox(); + + blake2s_finalize(state, byte_count, msg).unbox() + } + ); + + let result = run_program(&program, "run_test", &[]).return_value; + + assert_eq!( + result, + jit_struct!( + Value::Uint32(128291589), + Value::Uint32(1454945417), + Value::Uint32(3191583614), + Value::Uint32(1491889056), + Value::Uint32(794023379), + Value::Uint32(651000200), + Value::Uint32(3725903680), + Value::Uint32(1044330286), + ) + ); + } +} diff --git a/src/metadata/runtime_bindings.rs b/src/metadata/runtime_bindings.rs index cda200d967..01fb2903b4 100644 --- a/src/metadata/runtime_bindings.rs +++ b/src/metadata/runtime_bindings.rs @@ -40,6 +40,7 @@ enum RuntimeBinding { DictDrop, DictDup, GetGasBuiltin, + BlakeCompress, DebugPrint, #[cfg(feature = "with-cheatcode")] VtableCheatcode, @@ -65,6 +66,7 @@ impl RuntimeBinding { RuntimeBinding::DictDrop => "cairo_native__dict_drop", RuntimeBinding::DictDup => "cairo_native__dict_dup", RuntimeBinding::GetGasBuiltin => "cairo_native__get_costs_builtin", + RuntimeBinding::BlakeCompress => "cairo_native_libfunc_blake_compress", #[cfg(feature = "with-cheatcode")] RuntimeBinding::VtableCheatcode => "cairo_native__vtable_cheatcode", } @@ -109,6 +111,9 @@ impl RuntimeBinding { RuntimeBinding::GetGasBuiltin => { crate::runtime::cairo_native__get_costs_builtin as *const () } + RuntimeBinding::BlakeCompress => { + crate::runtime::cairo_native_libfunc_blake_compress as *const () + } #[cfg(feature = "with-cheatcode")] RuntimeBinding::VtableCheatcode => { crate::starknet::cairo_native__vtable_cheatcode as *const () @@ -257,6 +262,37 @@ impl RuntimeBindingsMeta { )) } + #[allow(clippy::too_many_arguments)] + pub fn libfunc_blake_compress<'c, 'a>( + &mut self, + context: &'c Context, + module: &Module, + block: &'a Block<'c>, + state: Value<'c, 'a>, + message: Value<'c, 'a>, + count_bytes: Value<'c, 'a>, + finalize: Value<'c, 'a>, + location: Location<'c>, + ) -> Result> + where + 'c: 'a, + { + let function = self.build_function( + context, + module, + block, + location, + RuntimeBinding::BlakeCompress, + )?; + + Ok(block.append_operation( + OperationBuilder::new("llvm.call", location) + .add_operands(&[function]) + .add_operands(&[state, message, count_bytes, finalize]) + .build()?, + )) + } + /// Register if necessary, then invoke the `ec_point_from_x_nz()` function. pub fn libfunc_ec_point_from_x_nz<'c, 'a>( &mut self, @@ -681,6 +717,7 @@ pub fn setup_runtime(find_symbol_ptr: impl Fn(&str) -> Option<*mut c_void>) { RuntimeBinding::DictDrop, RuntimeBinding::DictDup, RuntimeBinding::GetGasBuiltin, + RuntimeBinding::BlakeCompress, RuntimeBinding::DebugPrint, #[cfg(feature = "with-cheatcode")] RuntimeBinding::VtableCheatcode, diff --git a/src/runtime.rs b/src/runtime.rs index 14039e5d8d..e478dc2288 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -1,6 +1,6 @@ #![allow(non_snake_case)] -use crate::utils::BuiltinCosts; +use crate::utils::{blake_utils, BuiltinCosts}; use cairo_lang_sierra_gas::core_libfunc_cost::{ DICT_SQUASH_REPEATED_ACCESS_COST, DICT_SQUASH_UNIQUE_KEY_COST, }; @@ -142,6 +142,24 @@ pub unsafe extern "C" fn cairo_native__libfunc__hades_permutation( *op2 = state[2].to_bytes_le(); } +pub unsafe extern "C" fn cairo_native_libfunc_blake_compress( + state: &mut [u32; 8], + message: &[u32; 16], + count_bytes: u32, + finalize: bool, +) { + let new_state = blake_utils::blake2s_compress( + state, + message, + count_bytes, + 0, + if finalize { 0xFFFFFFFF } else { 0 }, + 0, + ); + + *state = new_state; +} + /// Felt252 type used in cairo native runtime #[derive(Debug)] pub struct FeltDict { diff --git a/src/types.rs b/src/types.rs index 6469f85fb2..2590fa5bad 100644 --- a/src/types.rs +++ b/src/types.rs @@ -31,6 +31,7 @@ use std::{alloc::Layout, error::Error, ops::Deref, sync::OnceLock}; pub mod array; mod bitwise; +mod blake; mod bounded_int; mod r#box; mod builtin_costs; @@ -436,7 +437,13 @@ impl TypeBuilder for CoreTypeConcrete { metadata, WithSelf::new(self_ty, info), ), - Self::Blake(_) => native_panic!("Build Blake type"), + Self::Blake(info) => blake::build( + context, + module, + registry, + metadata, + WithSelf::new(self_ty, info), + ), } } @@ -543,7 +550,7 @@ impl TypeBuilder for CoreTypeConcrete { CoreTypeConcrete::Circuit(info) => circuit::is_complex(info), CoreTypeConcrete::IntRange(_info) => false, - CoreTypeConcrete::Blake(_info) => native_panic!("Implement is_complex for Blake type") + CoreTypeConcrete::Blake(_) => false, }) } @@ -628,7 +635,7 @@ impl TypeBuilder for CoreTypeConcrete { let type_info = registry.get_type(&info.ty)?; type_info.is_zst(registry)? } - CoreTypeConcrete::Blake(_info) => native_panic!("Implement is_zst for Blake type"), + CoreTypeConcrete::Blake(_) => false, }) } @@ -739,7 +746,7 @@ impl TypeBuilder for CoreTypeConcrete { let inner = registry.get_type(&info.ty)?.layout(registry)?; inner.extend(inner)?.0 } - CoreTypeConcrete::Blake(_info) => native_panic!("Implement layout for Blake type"), + CoreTypeConcrete::Blake(_info) => Layout::new::<*mut ()>(), } .pad_to_align()) } @@ -752,9 +759,7 @@ impl TypeBuilder for CoreTypeConcrete { // arguments. Ok(match self { CoreTypeConcrete::IntRange(_) => false, - CoreTypeConcrete::Blake(_info) => { - native_panic!("Implement is_memory_allocated for Blake type") - } + CoreTypeConcrete::Blake(_) => false, CoreTypeConcrete::Array(_) => false, CoreTypeConcrete::Bitwise(_) => false, CoreTypeConcrete::Box(_) => false, diff --git a/src/types/blake.rs b/src/types/blake.rs new file mode 100644 index 0000000000..78426ea7e1 --- /dev/null +++ b/src/types/blake.rs @@ -0,0 +1,83 @@ +use cairo_lang_sierra::{ + extensions::{ + core::{CoreLibfunc, CoreType}, + types::InfoOnlyConcreteType, + }, + program_registry::ProgramRegistry, +}; +use melior::{ + dialect::{func, llvm, ods}, + ir::{ + attribute::IntegerAttribute, r#type::IntegerType, Block, BlockLike, Location, Module, + Region, Type, + }, + Context, +}; + +use crate::{ + error::Result, + metadata::{ + drop_overrides::DropOverridesMeta, dup_overrides::DupOverridesMeta, + realloc_bindings::ReallocBindingsMeta, MetadataStorage, + }, + utils::BlockExt, +}; + +use super::WithSelf; + +/// Build the MLIR type. +/// +/// Check out [the module](self) for more info. +pub fn build<'ctx>( + context: &'ctx Context, + module: &Module<'ctx>, + registry: &ProgramRegistry, + metadata: &mut MetadataStorage, + info: WithSelf, +) -> Result> { + let location = Location::unknown(context); + if metadata.get::().is_none() { + metadata.insert(ReallocBindingsMeta::new(context, module)); + } + + DupOverridesMeta::register_with(context, module, registry, metadata, info.self_ty(), |_| { + let region = Region::new(); + let block = + region.append_block(Block::new(&[(llvm::r#type::pointer(context, 0), location)])); + + let null_ptr = + block.append_op_result(llvm::zero(llvm::r#type::pointer(context, 0), location))?; + let k32 = block.const_int(context, location, 32, 64)?; + let new_ptr = block.append_op_result(ReallocBindingsMeta::realloc( + context, null_ptr, k32, location, + )?)?; + + block.append_operation( + ods::llvm::intr_memcpy_inline( + context, + new_ptr, + block.arg(0)?, + IntegerAttribute::new(IntegerType::new(context, 64).into(), 32), + IntegerAttribute::new(IntegerType::new(context, 1).into(), 0), + location, + ) + .into(), + ); + + block.append_operation(func::r#return(&[block.arg(0)?, new_ptr], location)); + Ok(Some(region)) + })?; + DropOverridesMeta::register_with(context, module, registry, metadata, info.self_ty(), |_| { + let region = Region::new(); + let block = + region.append_block(Block::new(&[(llvm::r#type::pointer(context, 0), location)])); + + block.append_operation(ReallocBindingsMeta::free(context, block.arg(0)?, location)?); + + block.append_operation(func::r#return(&[], location)); + Ok(Some(region)) + })?; + + // A ptr to a heap (realloc) allocated [u32; 8] + Ok(llvm::r#type::pointer(context, 0)) +} diff --git a/src/utils.rs b/src/utils.rs index 43beaba058..ddc653cbfe 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -30,6 +30,7 @@ use std::{ }; use thiserror::Error; +pub mod blake_utils; mod block_ext; pub mod mem_tracing; mod program_registry_ext; diff --git a/src/utils/blake_utils.rs b/src/utils/blake_utils.rs new file mode 100644 index 0000000000..3623224606 --- /dev/null +++ b/src/utils/blake_utils.rs @@ -0,0 +1,134 @@ +// This file is completely inspired in LambdaClass' cairo-vm blake compression implementation +// For more info check: https://github.com/lambdaclass/cairo-vm/blob/main/vm/src/hint_processor/builtin_hint_processor/blake2s_hash.rs#L24 + +use std::ops::Shl; + +pub const IV: [u32; 8] = [ + 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19, +]; + +const SIGMA: [[usize; 16]; 10] = [ + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], + [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3], + [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4], + [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8], + [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13], + [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9], + [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11], + [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10], + [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5], + [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0], +]; + +// Rotate right +fn right_rot(value: u32, n: u32) -> u32 { + (value >> n) | ((value & (1_u32.shl(n) - 1)) << (32 - n)) +} + +// Mixes two 8-bytes words from the message with the hash state +fn mix(a: u32, b: u32, c: u32, d: u32, m0: u32, m1: u32) -> (u32, u32, u32, u32) { + let a = a.wrapping_add(b).wrapping_add(m0); + let d = right_rot(d ^ a, 16); + let c = c.wrapping_add(d); + let b = right_rot(b ^ c, 12); + let a = a.wrapping_add(b).wrapping_add(m1); + let d = right_rot(d ^ a, 8); + let c = c.wrapping_add(d); + let b = right_rot(b ^ c, 7); + (a, b, c, d) +} + +// Performs a round of mixing +fn blake_round(mut state: Vec, message: &[u32; 16], sigma: [usize; 16]) -> Vec { + (state[0], state[4], state[8], state[12]) = mix( + state[0], + state[4], + state[8], + state[12], + message[sigma[0]], + message[sigma[1]], + ); + (state[1], state[5], state[9], state[13]) = mix( + state[1], + state[5], + state[9], + state[13], + message[sigma[2]], + message[sigma[3]], + ); + (state[2], state[6], state[10], state[14]) = mix( + state[2], + state[6], + state[10], + state[14], + message[sigma[4]], + message[sigma[5]], + ); + (state[3], state[7], state[11], state[15]) = mix( + state[3], + state[7], + state[11], + state[15], + message[sigma[6]], + message[sigma[7]], + ); + (state[0], state[5], state[10], state[15]) = mix( + state[0], + state[5], + state[10], + state[15], + message[sigma[8]], + message[sigma[9]], + ); + (state[1], state[6], state[11], state[12]) = mix( + state[1], + state[6], + state[11], + state[12], + message[sigma[10]], + message[sigma[11]], + ); + (state[2], state[7], state[8], state[13]) = mix( + state[2], + state[7], + state[8], + state[13], + message[sigma[12]], + message[sigma[13]], + ); + (state[3], state[4], state[9], state[14]) = mix( + state[3], + state[4], + state[9], + state[14], + message[sigma[14]], + message[sigma[15]], + ); + state +} + +pub fn blake2s_compress( + h: &[u32; 8], + message: &[u32; 16], + t0: u32, + t1: u32, + f0: u32, + f1: u32, +) -> [u32; 8] { + let mut state = h.to_vec(); + state.extend(&IV[0..4]); + state.extend(&vec![ + (IV[4] ^ t0), + (IV[5] ^ t1), + (IV[6] ^ f0), + (IV[7] ^ f1), + ]); + for sigma_list in SIGMA { + state = blake_round(state, message, sigma_list); + } + let mut new_state = [0; 8]; + for i in 0..8 { + new_state[i] = h[i] ^ state[i] ^ state[8 + i]; + } + new_state +} From 94729dc43a3c7cd1d31222e475e62562c94d923d Mon Sep 17 00:00:00 2001 From: FrancoGiachetta Date: Mon, 31 Mar 2025 16:07:48 -0300 Subject: [PATCH 02/11] doc --- src/utils/blake_utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/blake_utils.rs b/src/utils/blake_utils.rs index 3623224606..1bf36cf4e4 100644 --- a/src/utils/blake_utils.rs +++ b/src/utils/blake_utils.rs @@ -1,4 +1,4 @@ -// This file is completely inspired in LambdaClass' cairo-vm blake compression implementation +// This file is completely inspired in LambdaClass' cairo-vm blake2s compression implementation // For more info check: https://github.com/lambdaclass/cairo-vm/blob/main/vm/src/hint_processor/builtin_hint_processor/blake2s_hash.rs#L24 use std::ops::Shl; From abfe9980d0514d507a778712baaab9ef1cc030a9 Mon Sep 17 00:00:00 2001 From: FrancoGiachetta Date: Mon, 7 Apr 2025 17:09:16 -0300 Subject: [PATCH 03/11] rename runtime function --- src/metadata/runtime_bindings.rs | 2 +- src/runtime.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/metadata/runtime_bindings.rs b/src/metadata/runtime_bindings.rs index e7f4b2d1ab..208a578fb1 100644 --- a/src/metadata/runtime_bindings.rs +++ b/src/metadata/runtime_bindings.rs @@ -112,7 +112,7 @@ impl RuntimeBinding { crate::runtime::cairo_native__get_costs_builtin as *const () } RuntimeBinding::BlakeCompress => { - crate::runtime::cairo_native_libfunc_blake_compress as *const () + crate::runtime::cairo_native__libfunc__blake_compress as *const () } #[cfg(feature = "with-cheatcode")] RuntimeBinding::VtableCheatcode => { diff --git a/src/runtime.rs b/src/runtime.rs index 620b8efa70..64ce7a0fad 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -142,7 +142,7 @@ pub unsafe extern "C" fn cairo_native__libfunc__hades_permutation( *op2 = state[2].to_bytes_le(); } -pub unsafe extern "C" fn cairo_native_libfunc_blake_compress( +pub unsafe extern "C" fn cairo_native__libfunc__blake_compress( state: &mut [u32; 8], message: &[u32; 16], count_bytes: u32, From 5c774a974aee81d13d97f0b8900ea359eb67cdec Mon Sep 17 00:00:00 2001 From: FrancoGiachetta Date: Tue, 8 Apr 2025 11:06:20 -0300 Subject: [PATCH 04/11] remove blake type and fix runtime blake symbol --- src/metadata/runtime_bindings.rs | 2 +- src/types.rs | 17 ++----- src/types/blake.rs | 83 -------------------------------- 3 files changed, 6 insertions(+), 96 deletions(-) delete mode 100644 src/types/blake.rs diff --git a/src/metadata/runtime_bindings.rs b/src/metadata/runtime_bindings.rs index 208a578fb1..81622a37d2 100644 --- a/src/metadata/runtime_bindings.rs +++ b/src/metadata/runtime_bindings.rs @@ -66,7 +66,7 @@ impl RuntimeBinding { RuntimeBinding::DictDrop => "cairo_native__dict_drop", RuntimeBinding::DictDup => "cairo_native__dict_dup", RuntimeBinding::GetCostsBuiltin => "cairo_native__get_costs_builtin", - RuntimeBinding::BlakeCompress => "cairo_native_libfunc_blake_compress", + RuntimeBinding::BlakeCompress => "cairo_native__libfunc__blake_compress", #[cfg(feature = "with-cheatcode")] RuntimeBinding::VtableCheatcode => "cairo_native__vtable_cheatcode", } diff --git a/src/types.rs b/src/types.rs index e51c9f27c3..2061a6d658 100644 --- a/src/types.rs +++ b/src/types.rs @@ -31,7 +31,6 @@ use std::{alloc::Layout, error::Error, ops::Deref, sync::OnceLock}; pub mod array; mod bitwise; -mod blake; mod bounded_int; mod r#box; mod builtin_costs; @@ -437,13 +436,7 @@ impl TypeBuilder for CoreTypeConcrete { metadata, WithSelf::new(self_ty, info), ), - Self::Blake(info) => blake::build( - context, - module, - registry, - metadata, - WithSelf::new(self_ty, info), - ), + Self::Blake(_) => native_panic!("Build Blake type"), CoreTypeConcrete::QM31(_) => native_panic!("Build QM31 type"), } } @@ -552,7 +545,7 @@ impl TypeBuilder for CoreTypeConcrete { CoreTypeConcrete::IntRange(_info) => false, - CoreTypeConcrete::Blake(_) => false, + CoreTypeConcrete::Blake(_) => native_panic!("Implement is_complex for Blake type"), CoreTypeConcrete::QM31(_info) => native_panic!("Implement is_complex for QM31 type"), }) } @@ -638,7 +631,7 @@ impl TypeBuilder for CoreTypeConcrete { let type_info = registry.get_type(&info.ty)?; type_info.is_zst(registry)? } - CoreTypeConcrete::Blake(_) => false, + CoreTypeConcrete::Blake(_) => native_panic!("Implement is_zst for Blake type"), CoreTypeConcrete::QM31(_info) => native_panic!("Implement is_zst for QM31 type"), }) } @@ -750,7 +743,7 @@ impl TypeBuilder for CoreTypeConcrete { let inner = registry.get_type(&info.ty)?.layout(registry)?; inner.extend(inner)?.0 } - CoreTypeConcrete::Blake(_info) => Layout::new::<*mut ()>(), + CoreTypeConcrete::Blake(_info) => native_panic!("Implement layout for Blake type"), CoreTypeConcrete::QM31(_info) => native_panic!("Implement layout for QM31 type"), } .pad_to_align()) @@ -764,7 +757,6 @@ impl TypeBuilder for CoreTypeConcrete { // arguments. Ok(match self { CoreTypeConcrete::IntRange(_) => false, - CoreTypeConcrete::Blake(_) => false, CoreTypeConcrete::Array(_) => false, CoreTypeConcrete::Bitwise(_) => false, CoreTypeConcrete::Box(_) => false, @@ -840,6 +832,7 @@ impl TypeBuilder for CoreTypeConcrete { .is_memory_allocated(registry)?, CoreTypeConcrete::Coupon(_) => false, CoreTypeConcrete::Circuit(_) => false, + CoreTypeConcrete::Blake(_) => native_panic!("Implement is_memory_allocated for Blake type"), CoreTypeConcrete::QM31(_) => native_panic!("Implement is_memory_allocated for QM31"), }) } diff --git a/src/types/blake.rs b/src/types/blake.rs deleted file mode 100644 index 78426ea7e1..0000000000 --- a/src/types/blake.rs +++ /dev/null @@ -1,83 +0,0 @@ -use cairo_lang_sierra::{ - extensions::{ - core::{CoreLibfunc, CoreType}, - types::InfoOnlyConcreteType, - }, - program_registry::ProgramRegistry, -}; -use melior::{ - dialect::{func, llvm, ods}, - ir::{ - attribute::IntegerAttribute, r#type::IntegerType, Block, BlockLike, Location, Module, - Region, Type, - }, - Context, -}; - -use crate::{ - error::Result, - metadata::{ - drop_overrides::DropOverridesMeta, dup_overrides::DupOverridesMeta, - realloc_bindings::ReallocBindingsMeta, MetadataStorage, - }, - utils::BlockExt, -}; - -use super::WithSelf; - -/// Build the MLIR type. -/// -/// Check out [the module](self) for more info. -pub fn build<'ctx>( - context: &'ctx Context, - module: &Module<'ctx>, - registry: &ProgramRegistry, - metadata: &mut MetadataStorage, - info: WithSelf, -) -> Result> { - let location = Location::unknown(context); - if metadata.get::().is_none() { - metadata.insert(ReallocBindingsMeta::new(context, module)); - } - - DupOverridesMeta::register_with(context, module, registry, metadata, info.self_ty(), |_| { - let region = Region::new(); - let block = - region.append_block(Block::new(&[(llvm::r#type::pointer(context, 0), location)])); - - let null_ptr = - block.append_op_result(llvm::zero(llvm::r#type::pointer(context, 0), location))?; - let k32 = block.const_int(context, location, 32, 64)?; - let new_ptr = block.append_op_result(ReallocBindingsMeta::realloc( - context, null_ptr, k32, location, - )?)?; - - block.append_operation( - ods::llvm::intr_memcpy_inline( - context, - new_ptr, - block.arg(0)?, - IntegerAttribute::new(IntegerType::new(context, 64).into(), 32), - IntegerAttribute::new(IntegerType::new(context, 1).into(), 0), - location, - ) - .into(), - ); - - block.append_operation(func::r#return(&[block.arg(0)?, new_ptr], location)); - Ok(Some(region)) - })?; - DropOverridesMeta::register_with(context, module, registry, metadata, info.self_ty(), |_| { - let region = Region::new(); - let block = - region.append_block(Block::new(&[(llvm::r#type::pointer(context, 0), location)])); - - block.append_operation(ReallocBindingsMeta::free(context, block.arg(0)?, location)?); - - block.append_operation(func::r#return(&[], location)); - Ok(Some(region)) - })?; - - // A ptr to a heap (realloc) allocated [u32; 8] - Ok(llvm::r#type::pointer(context, 0)) -} From da14c5ef414e4c8fe672e4f05d5f42017fb75465 Mon Sep 17 00:00:00 2001 From: FrancoGiachetta Date: Tue, 8 Apr 2025 11:21:30 -0300 Subject: [PATCH 05/11] fmt --- src/types.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/types.rs b/src/types.rs index 2061a6d658..abac3abe06 100644 --- a/src/types.rs +++ b/src/types.rs @@ -832,7 +832,9 @@ impl TypeBuilder for CoreTypeConcrete { .is_memory_allocated(registry)?, CoreTypeConcrete::Coupon(_) => false, CoreTypeConcrete::Circuit(_) => false, - CoreTypeConcrete::Blake(_) => native_panic!("Implement is_memory_allocated for Blake type"), + CoreTypeConcrete::Blake(_) => { + native_panic!("Implement is_memory_allocated for Blake type") + } CoreTypeConcrete::QM31(_) => native_panic!("Implement is_memory_allocated for QM31"), }) } From ed82cfbf9f742666f6d72ad8fbd1f66a5dd7f5d5 Mon Sep 17 00:00:00 2001 From: FrancoGiachetta Date: Tue, 15 Apr 2025 16:36:50 -0300 Subject: [PATCH 06/11] add blake libfuncs' firms to the comments --- src/libfuncs/blake.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libfuncs/blake.rs b/src/libfuncs/blake.rs index e5b0ab6801..ef0003a645 100644 --- a/src/libfuncs/blake.rs +++ b/src/libfuncs/blake.rs @@ -42,6 +42,18 @@ pub fn build<'ctx, 'this>( /// /// `bytes_count` is the total amount of bytes hashed after hashing the message. /// `finalize` is wether the libfunc call is a finalize or not. +/// ```cairo +/// pub extern fn blake2s_compress( +/// state: Blake2sState, byte_count: u32, msg: Blake2sInput, +/// ) -> Blake2sState nopanic; +/// ``` +/// +/// Similar to `blake2s_compress`, but it marks the end of the compression +/// ```cairo +/// pub extern fn blake2s_finalize( +/// state: Blake2sState, byte_count: u32, msg: Blake2sInput, +/// ) -> Blake2sState nopanic; +/// ``` #[allow(clippy::too_many_arguments)] fn build_blake_operation<'ctx, 'this>( context: &'ctx Context, From 5d5d65c0b73aaedbb61d3658050b8c53c032711b Mon Sep 17 00:00:00 2001 From: FrancoGiachetta Date: Fri, 17 Oct 2025 09:44:20 -0300 Subject: [PATCH 07/11] fmt --- src/libfuncs/blake.rs | 6 +++--- src/utils.rs | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libfuncs/blake.rs b/src/libfuncs/blake.rs index ef0003a645..b6818cab45 100644 --- a/src/libfuncs/blake.rs +++ b/src/libfuncs/blake.rs @@ -7,14 +7,14 @@ use cairo_lang_sierra::{ program_registry::ProgramRegistry, }; use melior::{ - ir::{Block, BlockLike, Location}, + helpers::{ArithBlockExt, BuiltinBlockExt}, + ir::{Block, Location}, Context, }; use crate::{ error::{panic::ToNativeAssertError, Result}, metadata::{runtime_bindings::RuntimeBindingsMeta, MetadataStorage}, - utils::BlockExt, }; use super::LibfuncHelper; @@ -85,7 +85,7 @@ fn build_blake_operation<'ctx, 'this>( location, )?; - entry.append_operation(helper.br(0, &[state_ptr], location)); + helper.br(entry, 0, &[state_ptr], location); Ok(()) } diff --git a/src/utils.rs b/src/utils.rs index ca447db499..0b92149471 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -32,7 +32,6 @@ use std::{ use thiserror::Error; pub mod blake_utils; -mod block_ext; pub mod mem_tracing; mod program_registry_ext; mod range_ext; From b36248c879c2e0bdd34f68fc3b83ca3241359e69 Mon Sep 17 00:00:00 2001 From: FrancoGiachetta Date: Fri, 17 Oct 2025 09:52:49 -0300 Subject: [PATCH 08/11] post merge fix --- programs/contracts/blake2s_contract.cairo | 12 ++++++++++++ src/libfuncs/blake.rs | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 programs/contracts/blake2s_contract.cairo diff --git a/programs/contracts/blake2s_contract.cairo b/programs/contracts/blake2s_contract.cairo new file mode 100644 index 0000000000..eca7d105f4 --- /dev/null +++ b/programs/contracts/blake2s_contract.cairo @@ -0,0 +1,12 @@ +#[starknet::interface] +pub trait IBlake2sContract { + +} + +#[starknet::contract] +mod Blake2sContract { + #[storage] + struct Storage {} + + impl IBlake2sContractImpl of super::IBlake2sContract {} +} diff --git a/src/libfuncs/blake.rs b/src/libfuncs/blake.rs index b6818cab45..6f8369e417 100644 --- a/src/libfuncs/blake.rs +++ b/src/libfuncs/blake.rs @@ -68,7 +68,7 @@ fn build_blake_operation<'ctx, 'this>( let state_ptr = entry.arg(0)?; let bytes_count = entry.arg(1)?; let message = entry.arg(2)?; - let k_finalize = entry.const_int(context, location, finalize, 1)?; + let k_finalize = entry.const_int(context, location, finalize as u8, 1)?; let runtime_bindings = metadata .get_mut::() @@ -85,7 +85,7 @@ fn build_blake_operation<'ctx, 'this>( location, )?; - helper.br(entry, 0, &[state_ptr], location); + helper.br(entry, 0, &[state_ptr], location)?; Ok(()) } From 8d6b3f68fa8332b7b28a9a8ca9ba1e67e42d6d21 Mon Sep 17 00:00:00 2001 From: FrancoGiachetta Date: Fri, 17 Oct 2025 09:53:33 -0300 Subject: [PATCH 09/11] post merge fix --- programs/contracts/blake2s_contract.cairo | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 programs/contracts/blake2s_contract.cairo diff --git a/programs/contracts/blake2s_contract.cairo b/programs/contracts/blake2s_contract.cairo deleted file mode 100644 index eca7d105f4..0000000000 --- a/programs/contracts/blake2s_contract.cairo +++ /dev/null @@ -1,12 +0,0 @@ -#[starknet::interface] -pub trait IBlake2sContract { - -} - -#[starknet::contract] -mod Blake2sContract { - #[storage] - struct Storage {} - - impl IBlake2sContractImpl of super::IBlake2sContract {} -} From 6b7a5ab31ddd69b63e90375d4784868cbc5f68d8 Mon Sep 17 00:00:00 2001 From: FrancoGiachetta Date: Fri, 17 Oct 2025 18:19:41 -0300 Subject: [PATCH 10/11] add tests --- src/libfuncs/blake.rs | 37 ++++++++++--------- .../cairo_vm/contracts/heavy_blake2s.cairo | 22 +++++++++++ tests/tests/cases.rs | 4 ++ 3 files changed, 46 insertions(+), 17 deletions(-) create mode 100644 tests/cases/cairo_vm/contracts/heavy_blake2s.cairo diff --git a/src/libfuncs/blake.rs b/src/libfuncs/blake.rs index 6f8369e417..0fab6e898e 100644 --- a/src/libfuncs/blake.rs +++ b/src/libfuncs/blake.rs @@ -40,8 +40,8 @@ pub fn build<'ctx, 'this>( /// Performs a blake2s compression. /// -/// `bytes_count` is the total amount of bytes hashed after hashing the message. -/// `finalize` is wether the libfunc call is a finalize or not. +/// `bytes_count`: total amount of bytes hashed after hashing the message. +/// `finalize`: wether the libfunc call is a finalize or not. /// ```cairo /// pub extern fn blake2s_compress( /// state: Blake2sState, byte_count: u32, msg: Blake2sInput, @@ -97,19 +97,22 @@ mod tests { Value, }; + // This test is taken from the Blake2s-256 implementeation RFC-7693, Appendix B. + // https://www.rfc-editor.org/rfc/rfc7693#appendix-B. #[test] - fn test_blake() { + fn test_blake_3_bytes_compress() { let program = load_cairo!( use core::blake::{blake2s_compress, blake2s_finalize}; fn run_test() -> [u32; 8] nopanic { - let state = BoxTrait::new([0_u32; 8]); - let msg = BoxTrait::new([0_u32; 16]); - let byte_count = 64_u32; + let initial_state: Box<[u32; 8]> = BoxTrait::new([ + 0x6B08E647, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19, + ]); + // This number represents the bytes for "abc" string. + let abc_bytes = 0x00636261; + let msg: Box<[u32; 16]> = BoxTrait::new([abc_bytes, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - let _res = blake2s_compress(state, byte_count, msg).unbox(); - - blake2s_finalize(state, byte_count, msg).unbox() + blake2s_finalize(initial_state, 3, msg).unbox() } ); @@ -118,14 +121,14 @@ mod tests { assert_eq!( result, jit_struct!( - Value::Uint32(128291589), - Value::Uint32(1454945417), - Value::Uint32(3191583614), - Value::Uint32(1491889056), - Value::Uint32(794023379), - Value::Uint32(651000200), - Value::Uint32(3725903680), - Value::Uint32(1044330286), + Value::Uint32(0x8C5E8C50), + Value::Uint32(0xE2147C32), + Value::Uint32(0xA32BA7E1), + Value::Uint32(0x2F45EB4E), + Value::Uint32(0x208B4537), + Value::Uint32(0x293AD69E), + Value::Uint32(0x4C9B994D), + Value::Uint32(0x82596786), ) ); } diff --git a/tests/cases/cairo_vm/contracts/heavy_blake2s.cairo b/tests/cases/cairo_vm/contracts/heavy_blake2s.cairo new file mode 100644 index 0000000000..88b239256d --- /dev/null +++ b/tests/cases/cairo_vm/contracts/heavy_blake2s.cairo @@ -0,0 +1,22 @@ +#[starknet::contract] +mod HeavyBlake2s { + use core::blake::{blake2s_finalize, blake2s_compress}; + + #[storage] + struct Storage {} + + #[external(v0)] + fn heavy_blake2s(self: @ContractState) -> [u32; 8] { + let initial_state = BoxTrait::new([0x13245678, 0x87654321, 0x21324354, 0x54433221, 0x11223344, 0x44332211, 0x55667788, 0x88776655]); + let msg = BoxTrait::new(['Hi', ',', 'this', 'is', 'a', 'msg', 'to', 'send', 0, 0, 0, 0, 0, 0, 0, 0]); + let byte_count = 4; + let mut counter = 0; + + while counter != 6 { + let _res = blake2s_compress(initial_state, byte_count, msg); + counter += 1; + } + + blake2s_finalize(initial_state, byte_count, msg).unbox() + } +} diff --git a/tests/tests/cases.rs b/tests/tests/cases.rs index ac09b957b7..72d770c436 100644 --- a/tests/tests/cases.rs +++ b/tests/tests/cases.rs @@ -177,6 +177,7 @@ fn test_program_cases(program_path: &str) { #[test_case("tests/cases/cairo_vm/contracts/field_sqrt.cairo", &[])] #[test_case("tests/cases/cairo_vm/contracts/random_ec_point.cairo", &[])] #[test_case("tests/cases/cairo_vm/contracts/alloc_constant_size.cairo", &[10, 10, 10])] +#[test_case("tests/cases/cairo_vm/contracts/heavy_blake2s.cairo", &[])] fn test_contract_cases(program_path: &str, args: &[u128]) { let args = args.iter().map(|&arg| arg.into()).collect_vec(); @@ -207,5 +208,8 @@ fn test_contract_cases(program_path: &str, args: &[u128]) { let vm_output = run_vm_contract(&contract, &entrypoint.selector, &args); + dbg!(&native_output); + dbg!(&vm_output); + assert_eq_sorted!(vm_output, native_output); } From 7ceb9acd742537dbb83993fc67e26d6efbabb8f6 Mon Sep 17 00:00:00 2001 From: FrancoGiachetta Date: Fri, 17 Oct 2025 18:25:00 -0300 Subject: [PATCH 11/11] change test --- tests/cases/cairo_vm/contracts/heavy_blake2s.cairo | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/cases/cairo_vm/contracts/heavy_blake2s.cairo b/tests/cases/cairo_vm/contracts/heavy_blake2s.cairo index 88b239256d..949efd98c4 100644 --- a/tests/cases/cairo_vm/contracts/heavy_blake2s.cairo +++ b/tests/cases/cairo_vm/contracts/heavy_blake2s.cairo @@ -9,12 +9,13 @@ mod HeavyBlake2s { fn heavy_blake2s(self: @ContractState) -> [u32; 8] { let initial_state = BoxTrait::new([0x13245678, 0x87654321, 0x21324354, 0x54433221, 0x11223344, 0x44332211, 0x55667788, 0x88776655]); let msg = BoxTrait::new(['Hi', ',', 'this', 'is', 'a', 'msg', 'to', 'send', 0, 0, 0, 0, 0, 0, 0, 0]); - let byte_count = 4; + let mut byte_count = 1; let mut counter = 0; while counter != 6 { let _res = blake2s_compress(initial_state, byte_count, msg); counter += 1; + byte_count += 2; } blake2s_finalize(initial_state, byte_count, msg).unbox()