Skip to content

Commit

Permalink
Add Uint512DivMod Hint (#1171)
Browse files Browse the repository at this point in the history
* Add Uint512DivMod Hint

* Update changelog

* Implement test for hint

* Fix test for hint

* Fix changelog

* Fix changelog

---------

Co-authored-by: Pedro Fontana <fontana.pedro93@gmail.com>
  • Loading branch information
mmsc2 and pefontana authored May 16, 2023
1 parent fd2e499 commit 92a81f7
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 29 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#### Upcoming Changes


* fix: Fix felt sqrt and Signed impl [#1150](https://github.com/lambdaclass/cairo-rs/pull/1150)

* BREAKING: Fix `Felt252` methods `abs`, `signum`, `is_positive`, `is_negative` and `sqrt`
Expand All @@ -21,7 +22,8 @@

* Fix implementation of `InitSquashData` and `ShouldSkipSquashLoop`

* Add more hints to `Cairo1HintProcessor` [#1143](https://github.com/lambdaclass/cairo-rs/pull/1143)
* Add more hints to `Cairo1HintProcessor` [#1171](https://github.com/lambdaclass/cairo-rs/pull/1171)
[#1143](https://github.com/lambdaclass/cairo-rs/pull/1143)

* `Cairo1HintProcessor` can now run the following hints:
* Felt252DictEntryInit
Expand All @@ -32,6 +34,7 @@
* GetCurrentAccessIndex
* ShouldContinueSquashLoop
* FieldSqrt
* Uint512DivMod

* Add some small considerations regarding Cairo 1 programs [#1144](https://github.com/lambdaclass/cairo-rs/pull/1144):

Expand Down
47 changes: 23 additions & 24 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ felt = { package = "cairo-felt", path = "./felt", version = "0.4.0", default-fea
bitvec = { version = "1", default-features = false, features = ["alloc"] }

# Dependencies for cairo-1-hints feature
cairo-lang-starknet = { git = "https://github.com/starkware-libs/cairo.git", rev = "44fdeb26231f5022f2441bf89018272460c4e326", optional = true}
cairo-lang-casm = { git = "https://github.com/starkware-libs/cairo.git", rev = "44fdeb26231f5022f2441bf89018272460c4e326", optional = true }
cairo-lang-starknet = { git = "https://github.com/starkware-libs/cairo.git", rev = "4afacfd574de1121d61dea28f8c73e1516c7e07d", optional = true}
cairo-lang-casm = { git = "https://github.com/starkware-libs/cairo.git", rev = "4afacfd574de1121d61dea28f8c73e1516c7e07d", optional = true }

# TODO: check these dependencies for wasm compatibility
ark-ff = {version = "0.4.0-alpha.7", default-features = false, optional = true}
Expand Down
26 changes: 26 additions & 0 deletions cairo_programs/cairo-1-contracts/uint512_div_mod.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#[contract]
mod UintDivMod {

use integer::{u512, u512_safe_div_rem_by_u256};

#[external]
fn div_mod() -> () {
let zero = u512 { limb0: 0, limb1: 0, limb2: 0, limb3: 0 };
let one = u512 { limb0: 1, limb1: 0, limb2: 0, limb3: 0 };

let (q, r) = u512_safe_div_rem_by_u256(zero, integer::u256_as_non_zero(1));
assert(q == zero, '0 / 1 != 0');
assert(r == 0, '0 % 1 != 0');

let (q, r) = u512_safe_div_rem_by_u256(one, integer::u256_as_non_zero(1));
assert(q == one, '1 / 1 != 1');
assert(r == 0, '1 % 1 != 0');

let two = u512 {limb0: 0, limb1: 0, limb2: 0, limb3: 2};
let (q, r) = u512_safe_div_rem_by_u256(two, integer::u256_as_non_zero(1));
assert(q == two, '2/1 != 2');
assert(r == 0, '2/1 != 0');

return ();
}
}
87 changes: 85 additions & 2 deletions src/hint_processor/cairo_1_hint_processor/hint_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ use crate::any_box;
use crate::felt::{felt_str, Felt252};
use crate::hint_processor::cairo_1_hint_processor::dict_manager::DictSquashExecScope;
use crate::hint_processor::hint_processor_definition::HintReference;
use crate::types::relocatable::Relocatable;

use crate::stdlib::collections::HashMap;
use crate::stdlib::prelude::*;
use crate::types::relocatable::Relocatable;
use crate::{
hint_processor::hint_processor_definition::HintProcessor,
types::exec_scope::ExecutionScopes,
Expand All @@ -27,6 +26,7 @@ use core::ops::Mul;
use num_bigint::BigUint;
use num_integer::Integer;
use num_traits::{cast::ToPrimitive, Zero};
use std::ops::Shl;

/// Execution scope for constant memory allocation.
struct MemoryExecScope {
Expand Down Expand Up @@ -232,6 +232,25 @@ impl Cairo1HintProcessor {
high,
low,
})) => self.wide_mul_128(vm, lhs, rhs, high, low),

Hint::Core(CoreHintBase::Core(CoreHint::Uint512DivModByUint256 {
dividend0,
dividend1,
dividend2,
dividend3,
divisor0,
divisor1,
quotient0,
quotient1,
quotient2,
quotient3,
remainder0,
remainder1,
})) => self.uint512_div_mod(
vm, dividend0, dividend1, dividend2, dividend3, divisor0, divisor1, quotient0,
quotient1, quotient2, quotient3, remainder0, remainder1,
),

hint => Err(HintError::UnknownHint(hint.to_string())),
}
}
Expand Down Expand Up @@ -600,6 +619,70 @@ impl Cairo1HintProcessor {
Ok(())
}

#[allow(clippy::too_many_arguments)]
fn uint512_div_mod(
&self,
vm: &mut VirtualMachine,
dividend0: &ResOperand,
dividend1: &ResOperand,
dividend2: &ResOperand,
dividend3: &ResOperand,
divisor0: &ResOperand,
divisor1: &ResOperand,
quotient0: &CellRef,
quotient1: &CellRef,
quotient2: &CellRef,
quotient3: &CellRef,
remainder0: &CellRef,
remainder1: &CellRef,
) -> Result<(), HintError> {
let pow_2_128 = BigUint::from(u128::MAX) + 1u32;
let dividend0 = res_operand_get_val(vm, dividend0)?.to_biguint();
let dividend1 = res_operand_get_val(vm, dividend1)?.to_biguint();
let dividend2 = res_operand_get_val(vm, dividend2)?.to_biguint();
let dividend3 = res_operand_get_val(vm, dividend3)?.to_biguint();
let divisor0 = res_operand_get_val(vm, divisor0)?.to_biguint();
let divisor1 = res_operand_get_val(vm, divisor1)?.to_biguint();
let dividend: BigUint =
dividend0 + dividend1.shl(128) + dividend2.shl(256) + dividend3.shl(384);
let divisor = divisor0 + divisor1.shl(128);
let (quotient, remainder) = dividend.div_rem(&divisor);
let (quotient, limb0) = quotient.div_rem(&pow_2_128);

vm.insert_value(
cell_ref_to_relocatable(quotient0, vm)?,
Felt252::from(limb0),
)?;

let (quotient, limb1) = quotient.div_rem(&pow_2_128);
vm.insert_value(
cell_ref_to_relocatable(quotient1, vm)?,
Felt252::from(limb1),
)?;
let (limb3, limb2) = quotient.div_rem(&pow_2_128);

vm.insert_value(
cell_ref_to_relocatable(quotient2, vm)?,
Felt252::from(limb2),
)?;
vm.insert_value(
cell_ref_to_relocatable(quotient3, vm)?,
Felt252::from(limb3),
)?;
let (limb1, limb0) = remainder.div_rem(&pow_2_128);

vm.insert_value(
cell_ref_to_relocatable(remainder0, vm)?,
Felt252::from(limb0),
)?;
vm.insert_value(
cell_ref_to_relocatable(remainder1, vm)?,
Felt252::from(limb1),
)?;

Ok(())
}

#[allow(clippy::too_many_arguments)]
fn uint256_square_root(
&self,
Expand Down
Loading

0 comments on commit 92a81f7

Please sign in to comment.