diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 20ecfefe0..56f1163b9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -151,55 +151,9 @@ jobs: - name: test run: make test-ci - name: test-cairo - run: make test-cairo - - test-ubuntu-old: - name: test ubuntu old (linux, amd64) - runs-on: ubuntu-20.04 - env: - MLIR_SYS_190_PREFIX: /usr/lib/llvm-19/ - LLVM_SYS_191_PREFIX: /usr/lib/llvm-19/ - TABLEGEN_190_PREFIX: /usr/lib/llvm-19/ - RUST_LOG: cairo_native=debug,cairo_native_test=debug - steps: - - uses: actions/checkout@v4 - - name: check and free hdd space left run: | - echo "Listing 20 largest packages" - dpkg-query -Wf '${Installed-Size}\t${Package}\n' | sort -n | tail -n 20 - df -h - sudo apt-get update - sudo apt-get remove -y '^llvm-.*' - sudo apt-get remove -y 'php.*' - sudo apt-get remove -y '^dotnet-.*' - sudo apt-get remove -y '^temurin-.*' - sudo apt-get autoremove -y - sudo apt-get clean - df -h - echo "Removing large directories" - # deleting 15GB - sudo rm -rf /usr/share/dotnet/ - sudo rm -rf /usr/local/lib/android - df -h - - name: Setup rust env - uses: dtolnay/rust-toolchain@1.84.1 - - name: Retreive cached dependecies - uses: Swatinem/rust-cache@v2 - - name: add llvm deb repository - uses: myci-actions/add-deb-repo@11 - with: - repo: deb http://apt.llvm.org/focal/ llvm-toolchain-focal-19 main - repo-name: llvm-repo - keys-asc: https://apt.llvm.org/llvm-snapshot.gpg.key - - run: sudo apt-get update && sudo apt-get upgrade -y - - name: Install LLVM - run: sudo apt-get install libzstd-dev llvm-19 llvm-19-dev llvm-19-runtime clang-19 clang-tools-19 lld-19 libpolly-19-dev libmlir-19-dev mlir-19-tools - - name: Install deps - run: make deps - - name: test - run: make test-ci - - name: test-cairo - run: make test-cairo + echo > corelib/src/test/circuit_test.cairo + make test-cairo test_macos: name: Test (macOS, Apple silicon) @@ -229,7 +183,9 @@ jobs: - name: Run tests run: make test-ci - name: test-cairo - run: make test-cairo + run: | + echo > corelib/src/test/circuit_test.cairo + make test-cairo coverage: name: coverage diff --git a/src/error.rs b/src/error.rs index 02b64b19c..82d3d5959 100644 --- a/src/error.rs +++ b/src/error.rs @@ -155,6 +155,7 @@ pub mod panic { impl std::error::Error for NativeAssertError {} impl NativeAssertError { + #[track_caller] pub fn new(msg: String) -> Self { let backtrace = Backtrace::capture(); let info = if BacktraceStatus::Captured == backtrace.status() { diff --git a/src/libfuncs/circuit.rs b/src/libfuncs/circuit.rs index bf4f8637c..f5da27ade 100644 --- a/src/libfuncs/circuit.rs +++ b/src/libfuncs/circuit.rs @@ -2,11 +2,14 @@ //! //! Relevant casm code: https://github.com/starkware-libs/cairo/blob/v2.10.0/crates/cairo-lang-sierra-to-casm/src/invocations/circuit.rs +#![allow(unused_variables, unreachable_code)] + use super::{increment_builtin_counter_by, LibfuncHelper}; use crate::{ error::{Result, SierraAssertError}, libfuncs::r#struct::build_struct_value, metadata::MetadataStorage, + native_panic, types::{circuit::build_u384_struct_type, TypeBuilder}, utils::{get_integer_layout, layout_repeat, BlockExt, ProgramRegistryExt}, }; @@ -33,6 +36,7 @@ use melior::{ }, Context, }; +use num_traits::Signed; /// Select and call the correct libfunc builder function from the selector. pub fn build<'ctx, 'this>( @@ -44,6 +48,8 @@ pub fn build<'ctx, 'this>( metadata: &mut MetadataStorage, selector: &CircuitConcreteLibfunc, ) -> Result<()> { + native_panic!("circuit libfuncs are disabled at the moment, due to limitations in LLVM"); + match selector { CircuitConcreteLibfunc::AddInput(info) => { build_add_input(context, registry, entry, location, helper, metadata, info) @@ -66,11 +72,10 @@ pub fn build<'ctx, 'this>( CircuitConcreteLibfunc::FailureGuaranteeVerify(info) => build_failure_guarantee_verify( context, registry, entry, location, helper, metadata, info, ), - CircuitConcreteLibfunc::IntoU96Guarantee(SignatureAndTypeConcreteLibfunc { - signature, - .. - }) - | CircuitConcreteLibfunc::U96SingleLimbLessThanGuaranteeVerify( + CircuitConcreteLibfunc::IntoU96Guarantee(info) => { + build_into_u96_guarantee(context, registry, entry, location, helper, metadata, info) + } + CircuitConcreteLibfunc::U96SingleLimbLessThanGuaranteeVerify( SignatureOnlyConcreteLibfunc { signature, .. }, ) | CircuitConcreteLibfunc::U96GuaranteeVerify(SignatureOnlyConcreteLibfunc { signature }) => { @@ -1083,6 +1088,52 @@ fn build_array_slice<'ctx>( ) } +/// Converts input to an U96Guarantee. +/// Input type must fit inside of an u96. +/// +/// # Signature +/// ```cairo +/// extern fn into_u96_guarantee(val: T) -> U96Guarantee nopanic; +/// ``` +fn build_into_u96_guarantee<'ctx, 'this>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + _metadata: &mut MetadataStorage, + info: &SignatureAndTypeConcreteLibfunc, +) -> Result<()> { + let src = entry.argument(0)?.into(); + + let src_ty = registry.get_type(&info.param_signatures()[0].ty)?; + + let src_range = src_ty.integer_range(registry)?; + + // We expect the input value to be unsigned, but we check it just in case. + if src_range.lower.is_negative() { + native_panic!("into_u96_guarantee expects an unsigned integer") + } + + // Extend the input value to an u96 + let mut dst = entry.extui(src, IntegerType::new(context, 96).into(), location)?; + + // If the lower bound is positive, we offset the value by the lower bound + // to obtain the actual value. + if src_range.lower.is_positive() { + let klower = entry.const_int_from_type( + context, + location, + src_range.lower, + IntegerType::new(context, 96).into(), + )?; + dst = entry.addi(dst, klower, location)? + } + + entry.append_operation(helper.br(0, &[dst], location)); + Ok(()) +} + #[cfg(test)] mod test { @@ -1094,8 +1145,8 @@ mod test { values::Value, }; use cairo_lang_sierra::extensions::utils::Range; - use num_bigint::BigUint; - use num_traits::Num; + use num_bigint::{BigInt, BigUint}; + use num_traits::{Num, One}; use starknet_types_core::felt::Felt; fn u384(limbs: [&str; 4]) -> Value { @@ -1132,6 +1183,7 @@ mod test { } #[test] + #[ignore] fn run_add_circuit() { let program = load_cairo!( use core::circuit::{ @@ -1168,6 +1220,7 @@ mod test { } #[test] + #[ignore] fn run_sub_circuit() { let program = load_cairo!( use core::circuit::{ @@ -1204,6 +1257,7 @@ mod test { } #[test] + #[ignore] fn run_mul_circuit() { let program = load_cairo!( use core::circuit::{ @@ -1240,6 +1294,7 @@ mod test { } #[test] + #[ignore] fn run_inverse_circuit() { let program = load_cairo!( use core::circuit::{ @@ -1274,6 +1329,7 @@ mod test { } #[test] + #[ignore] fn run_no_coprime_circuit() { let program = load_cairo!( use core::circuit::{ @@ -1310,6 +1366,7 @@ mod test { } #[test] + #[ignore] fn run_mul_overflow_circuit() { let program = load_cairo!( use core::circuit::{ @@ -1355,6 +1412,7 @@ mod test { } #[test] + #[ignore] fn run_full_circuit() { let program = load_cairo!( use core::circuit::{ @@ -1404,4 +1462,46 @@ mod test { ), ); } + + #[test] + #[ignore] + fn run_into_u96_guarantee() { + let program = load_cairo!( + use core::circuit::{into_u96_guarantee, U96Guarantee}; + use core::internal::bounded_int::BoundedInt; + + fn main() -> (U96Guarantee, U96Guarantee, U96Guarantee) { + ( + into_u96_guarantee::>(123), + into_u96_guarantee::>(123), + into_u96_guarantee::(123), + ) + } + ); + + let range = Range { + lower: BigInt::ZERO, + upper: BigInt::one() << 96, + }; + + run_program_assert_output( + &program, + "main", + &[], + jit_struct!( + Value::BoundedInt { + value: 123.into(), + range: range.clone() + }, + Value::BoundedInt { + value: 123.into(), + range: range.clone() + }, + Value::BoundedInt { + value: 123.into(), + range: range.clone() + } + ), + ); + } } diff --git a/src/values.rs b/src/values.rs index 88961322f..34217af77 100644 --- a/src/values.rs +++ b/src/values.rs @@ -15,6 +15,7 @@ use crate::{ use bumpalo::Bump; use cairo_lang_sierra::{ extensions::{ + circuit::CircuitTypeConcrete, core::{CoreLibfunc, CoreType, CoreTypeConcrete}, starknet::{secp256::Secp256PointTypeConcrete, StarkNetTypeConcrete}, utils::Range, @@ -966,6 +967,23 @@ impl Value { range: info.range.clone(), } } + CoreTypeConcrete::Circuit(CircuitTypeConcrete::U96Guarantee(_)) => { + let data = BigInt::from_biguint( + Sign::Plus, + BigUint::from_bytes_le(slice::from_raw_parts( + ptr.cast::().as_ptr(), + 12, + )), + ); + + Self::BoundedInt { + value: data.into(), + range: Range { + lower: BigInt::ZERO, + upper: BigInt::one() << 96, + }, + } + } CoreTypeConcrete::Coupon(_) | CoreTypeConcrete::Circuit(_) | CoreTypeConcrete::RangeCheck96(_) => native_panic!("implement from_ptr"), diff --git a/tests/tests/circuit.rs b/tests/tests/circuit.rs index 049f5a649..28efd04f0 100644 --- a/tests/tests/circuit.rs +++ b/tests/tests/circuit.rs @@ -72,6 +72,7 @@ lazy_static! { } #[test] +#[ignore] fn circuit_guarantee_first_limb() { let program = &TEST; @@ -110,6 +111,7 @@ fn circuit_guarantee_first_limb() { } #[test] +#[ignore] fn circuit_guarantee_last_limb() { let program = &TEST; @@ -148,6 +150,7 @@ fn circuit_guarantee_last_limb() { } #[test] +#[ignore] fn circuit_guarantee_middle_limb() { let program = &TEST;