Skip to content

Commit

Permalink
refactor: Use a generic backend for BigIntN & UintN structs used for …
Browse files Browse the repository at this point in the history
…hints (#1399)

* Generalize BigInt3

* Use generalized backend for BigInt5

* Use generalized backend for Uint512

* Use generalized backend for Uint768

* clippy
  • Loading branch information
fmoletta authored Aug 30, 2023
1 parent 30de5a2 commit 91eeff5
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 319 deletions.
12 changes: 7 additions & 5 deletions vm/src/hint_processor/builtin_hint_processor/bigint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,15 @@ pub fn bigint_pack_div_mod_hint(
let x_bigint5 = BigInt5::from_var_name("x", vm, ids_data, ap_tracking)?;
// pack only takes the first three limbs
let x_lower = BigInt3 {
d0: x_bigint5.d0,
d1: x_bigint5.d1,
d2: x_bigint5.d2,
limbs: [
x_bigint5.limbs[0].clone(),
x_bigint5.limbs[1].clone(),
x_bigint5.limbs[2].clone(),
],
};
let x_lower = x_lower.pack86();
let d3 = x_bigint5.d3.as_ref().to_signed_felt();
let d4 = x_bigint5.d4.as_ref().to_signed_felt();
let d3 = x_bigint5.limbs[3].as_ref().to_signed_felt();
let d4 = x_bigint5.limbs[4].as_ref().to_signed_felt();
x_lower + d3 * BigInt::from(BASE.pow(3)) + d4 * BigInt::from(BASE.pow(4))
};
let y: BigInt = BigInt3::from_var_name("y", vm, ids_data, ap_tracking)?.pack86();
Expand Down
1 change: 0 additions & 1 deletion vm/src/hint_processor/builtin_hint_processor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ pub mod squash_dict_utils;
pub mod uint256_utils;
pub mod uint384;
pub mod uint384_extension;
pub mod uint512_utils;
pub mod uint_utils;
pub mod usort;
pub mod vrf;
163 changes: 63 additions & 100 deletions vm/src/hint_processor/builtin_hint_processor/secp/bigint_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,32 +21,33 @@ use felt::Felt252;
use num_bigint::{BigInt, BigUint};
use num_traits::Bounded;

// Uint384 and BigInt3 are used interchangeably with BigInt3
pub(crate) type Uint384<'a> = BigInt3<'a>;
pub(crate) type BigInt3<'a> = BigIntN<'a, 3>;
pub(crate) type Uint384<'a> = BigIntN<'a, 3>;
pub(crate) type Uint512<'a> = BigIntN<'a, 4>;
pub(crate) type BigInt5<'a> = BigIntN<'a, 5>;
pub(crate) type Uint768<'a> = BigIntN<'a, 6>;

#[derive(Debug, PartialEq)]
pub(crate) struct BigInt3<'a> {
pub d0: Cow<'a, Felt252>,
pub d1: Cow<'a, Felt252>,
pub d2: Cow<'a, Felt252>,
pub(crate) struct BigIntN<'a, const NUM_LIMBS: usize> {
pub(crate) limbs: [Cow<'a, Felt252>; NUM_LIMBS],
}

impl BigInt3<'_> {
impl<const NUM_LIMBS: usize> BigIntN<'_, NUM_LIMBS> {
pub(crate) fn from_base_addr<'a>(
addr: Relocatable,
name: &str,
vm: &'a VirtualMachine,
) -> Result<BigInt3<'a>, HintError> {
Ok(BigInt3 {
d0: vm.get_integer(addr).map_err(|_| {
HintError::IdentifierHasNoMember(Box::new((name.to_string(), "d0".to_string())))
})?,
d1: vm.get_integer((addr + 1)?).map_err(|_| {
HintError::IdentifierHasNoMember(Box::new((name.to_string(), "d1".to_string())))
})?,
d2: vm.get_integer((addr + 2)?).map_err(|_| {
HintError::IdentifierHasNoMember(Box::new((name.to_string(), "d2".to_string())))
})?,
) -> Result<BigIntN<'a, NUM_LIMBS>, HintError> {
let mut limbs = vec![];
for i in 0..NUM_LIMBS {
limbs.push(vm.get_integer((addr + i)?).map_err(|_| {
HintError::IdentifierHasNoMember(Box::new((name.to_string(), format!("d{}", i))))
})?)
}
Ok(BigIntN {
limbs: limbs
.try_into()
.map_err(|_| HintError::FixedSizeArrayFail(NUM_LIMBS))?,
})
}

Expand All @@ -55,17 +56,15 @@ impl BigInt3<'_> {
vm: &'a VirtualMachine,
ids_data: &HashMap<String, HintReference>,
ap_tracking: &ApTracking,
) -> Result<BigInt3<'a>, HintError> {
) -> Result<BigIntN<'a, NUM_LIMBS>, HintError> {
let base_addr = get_relocatable_from_var_name(name, vm, ids_data, ap_tracking)?;
BigInt3::from_base_addr(base_addr, name, vm)
BigIntN::from_base_addr(base_addr, name, vm)
}

pub(crate) fn from_values(limbs: [Felt252; 3]) -> Self {
let [d0, d1, d2] = limbs;
let d0 = Cow::Owned(d0);
let d1 = Cow::Owned(d1);
let d2 = Cow::Owned(d2);
Self { d0, d1, d2 }
pub(crate) fn from_values(limbs: [Felt252; NUM_LIMBS]) -> Self {
Self {
limbs: limbs.map(Cow::Owned),
}
}

pub(crate) fn insert_from_var_name(
Expand All @@ -76,22 +75,20 @@ impl BigInt3<'_> {
ap_tracking: &ApTracking,
) -> Result<(), HintError> {
let addr = get_relocatable_from_var_name(var_name, vm, ids_data, ap_tracking)?;

vm.insert_value(addr, self.d0.into_owned())?;
vm.insert_value((addr + 1)?, self.d1.into_owned())?;
vm.insert_value((addr + 2)?, self.d2.into_owned())?;

for i in 0..NUM_LIMBS {
vm.insert_value((addr + i)?, self.limbs[i].as_ref().clone())?;
}
Ok(())
}

pub(crate) fn pack(self) -> BigUint {
pack([self.d0, self.d1, self.d2], 128)
pack(self.limbs, 128)
}

pub(crate) fn pack86(self) -> BigInt {
let limbs = [self.d0, self.d1, self.d2];
limbs
self.limbs
.into_iter()
.take(3)
.enumerate()
.map(|(idx, value)| value.to_signed_felt().shl(idx * 86))
.sum()
Expand All @@ -103,50 +100,12 @@ impl BigInt3<'_> {
}
}

#[derive(Debug, PartialEq)]
pub(crate) struct BigInt5<'a> {
pub d0: Cow<'a, Felt252>,
pub d1: Cow<'a, Felt252>,
pub d2: Cow<'a, Felt252>,
pub d3: Cow<'a, Felt252>,
pub d4: Cow<'a, Felt252>,
}

impl BigInt5<'_> {
pub(crate) fn from_base_addr<'a>(
addr: Relocatable,
name: &str,
vm: &'a VirtualMachine,
) -> Result<BigInt5<'a>, HintError> {
Ok(BigInt5 {
d0: vm.get_integer(addr).map_err(|_| {
HintError::IdentifierHasNoMember(Box::new((name.to_string(), "d0".to_string())))
})?,
d1: vm.get_integer((addr + 1)?).map_err(|_| {
HintError::IdentifierHasNoMember(Box::new((name.to_string(), "d1".to_string())))
})?,
d2: vm.get_integer((addr + 2)?).map_err(|_| {
HintError::IdentifierHasNoMember(Box::new((name.to_string(), "d2".to_string())))
})?,
d3: vm.get_integer((addr + 3)?).map_err(|_| {
HintError::IdentifierHasNoMember(Box::new((name.to_string(), "d3".to_string())))
})?,
d4: vm.get_integer((addr + 4)?).map_err(|_| {
HintError::IdentifierHasNoMember(Box::new((name.to_string(), "d4".to_string())))
})?,
})
}

pub(crate) fn from_var_name<'a>(
name: &str,
vm: &'a VirtualMachine,
ids_data: &HashMap<String, HintReference>,
ap_tracking: &ApTracking,
) -> Result<BigInt5<'a>, HintError> {
let base_addr = get_relocatable_from_var_name(name, vm, ids_data, ap_tracking)?;
BigInt5::from_base_addr(base_addr, name, vm)
impl<'a, const NUM_LIMBS: usize> From<&'a BigUint> for BigIntN<'a, NUM_LIMBS> {
fn from(value: &'a BigUint) -> Self {
Self::split(value)
}
}

/*
Implements hint:
%{
Expand Down Expand Up @@ -204,8 +163,8 @@ pub fn hi_max_bitlen(
let scalar_u = BigInt3::from_var_name("scalar_u", vm, ids_data, ap_tracking)?;
let scalar_v = BigInt3::from_var_name("scalar_v", vm, ids_data, ap_tracking)?;

let len_hi_u = scalar_u.d2.bits();
let len_hi_v = scalar_v.d2.bits();
let len_hi_u = scalar_u.limbs[2].bits();
let len_hi_v = scalar_v.limbs[2].bits();

let len_hi = len_hi_u.max(len_hi_v);

Expand Down Expand Up @@ -318,9 +277,9 @@ mod tests {
let mut vm = vm!();
vm.segments = segments![((0, 0), 1), ((0, 1), 2), ((0, 2), 3)];
let x = BigInt3::from_base_addr((0, 0).into(), "x", &vm).unwrap();
assert_eq!(x.d0.as_ref(), &Felt252::one());
assert_eq!(x.d1.as_ref(), &Felt252::from(2));
assert_eq!(x.d2.as_ref(), &Felt252::from(3));
assert_eq!(x.limbs[0].as_ref(), &Felt252::one());
assert_eq!(x.limbs[1].as_ref(), &Felt252::from(2));
assert_eq!(x.limbs[2].as_ref(), &Felt252::from(3));
}

#[test]
Expand All @@ -335,11 +294,11 @@ mod tests {
((0, 4), 5)
];
let x = BigInt5::from_base_addr((0, 0).into(), "x", &vm).unwrap();
assert_eq!(x.d0.as_ref(), &Felt252::one());
assert_eq!(x.d1.as_ref(), &Felt252::from(2));
assert_eq!(x.d2.as_ref(), &Felt252::from(3));
assert_eq!(x.d3.as_ref(), &Felt252::from(4));
assert_eq!(x.d4.as_ref(), &Felt252::from(5));
assert_eq!(x.limbs[0].as_ref(), &Felt252::one());
assert_eq!(x.limbs[1].as_ref(), &Felt252::from(2));
assert_eq!(x.limbs[2].as_ref(), &Felt252::from(3));
assert_eq!(x.limbs[3].as_ref(), &Felt252::from(4));
assert_eq!(x.limbs[4].as_ref(), &Felt252::from(5));
}

#[test]
Expand Down Expand Up @@ -373,9 +332,9 @@ mod tests {
vm.segments = segments![((1, 0), 1), ((1, 1), 2), ((1, 2), 3)];
let ids_data = ids_data!["x"];
let x = BigInt3::from_var_name("x", &vm, &ids_data, &ApTracking::default()).unwrap();
assert_eq!(x.d0.as_ref(), &Felt252::one());
assert_eq!(x.d1.as_ref(), &Felt252::from(2));
assert_eq!(x.d2.as_ref(), &Felt252::from(3));
assert_eq!(x.limbs[0].as_ref(), &Felt252::one());
assert_eq!(x.limbs[1].as_ref(), &Felt252::from(2));
assert_eq!(x.limbs[2].as_ref(), &Felt252::from(3));
}

#[test]
Expand All @@ -392,11 +351,11 @@ mod tests {
];
let ids_data = ids_data!["x"];
let x = BigInt5::from_var_name("x", &vm, &ids_data, &ApTracking::default()).unwrap();
assert_eq!(x.d0.as_ref(), &Felt252::one());
assert_eq!(x.d1.as_ref(), &Felt252::from(2));
assert_eq!(x.d2.as_ref(), &Felt252::from(3));
assert_eq!(x.d3.as_ref(), &Felt252::from(4));
assert_eq!(x.d4.as_ref(), &Felt252::from(5));
assert_eq!(x.limbs[0].as_ref(), &Felt252::one());
assert_eq!(x.limbs[1].as_ref(), &Felt252::from(2));
assert_eq!(x.limbs[2].as_ref(), &Felt252::from(3));
assert_eq!(x.limbs[3].as_ref(), &Felt252::from(4));
assert_eq!(x.limbs[4].as_ref(), &Felt252::from(5));
}

#[test]
Expand Down Expand Up @@ -481,9 +440,11 @@ mod tests {
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn u384_pack86() {
let pack_1 = Uint384 {
d0: Cow::Borrowed(&Felt252::new(10_i32)),
d1: Cow::Borrowed(&Felt252::new(10_i32)),
d2: Cow::Borrowed(&Felt252::new(10_i32)),
limbs: [
Cow::Borrowed(&Felt252::new(10_i32)),
Cow::Borrowed(&Felt252::new(10_i32)),
Cow::Borrowed(&Felt252::new(10_i32)),
],
}
.pack86();
assert_eq!(
Expand All @@ -492,9 +453,11 @@ mod tests {
);

let pack_2 = Uint384 {
d0: Cow::Borrowed(&felt_str!("773712524553362")),
d1: Cow::Borrowed(&felt_str!("57408430697461422066401280")),
d2: Cow::Borrowed(&felt_str!("1292469707114105")),
limbs: [
Cow::Borrowed(&felt_str!("773712524553362")),
Cow::Borrowed(&felt_str!("57408430697461422066401280")),
Cow::Borrowed(&felt_str!("1292469707114105")),
],
}
.pack86();
assert_eq!(
Expand Down
12 changes: 6 additions & 6 deletions vm/src/hint_processor/builtin_hint_processor/secp/ec_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1272,12 +1272,12 @@ mod tests {
let ids_data = ids_data!["e"];
let ap_tracking = ApTracking::default();
let e = EcPoint::from_var_name("e", &vm, &ids_data, &ap_tracking).unwrap();
assert_eq!(e.x.d0.as_ref(), &Felt252::one());
assert_eq!(e.x.d1.as_ref(), &Felt252::from(2));
assert_eq!(e.x.d2.as_ref(), &Felt252::from(3));
assert_eq!(e.y.d0.as_ref(), &Felt252::from(4));
assert_eq!(e.y.d1.as_ref(), &Felt252::from(5));
assert_eq!(e.y.d2.as_ref(), &Felt252::from(6));
assert_eq!(e.x.limbs[0].as_ref(), &Felt252::one());
assert_eq!(e.x.limbs[1].as_ref(), &Felt252::from(2));
assert_eq!(e.x.limbs[2].as_ref(), &Felt252::from(3));
assert_eq!(e.y.limbs[0].as_ref(), &Felt252::from(4));
assert_eq!(e.y.limbs[1].as_ref(), &Felt252::from(5));
assert_eq!(e.y.limbs[2].as_ref(), &Felt252::from(6));
}

#[test]
Expand Down
6 changes: 3 additions & 3 deletions vm/src/hint_processor/builtin_hint_processor/uint384.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,11 @@ pub fn add_no_uint384_check(
// This hint is not from the cairo commonlib, and its lib can be found under different paths, so we cant rely on a full path name
let shift = get_constant_from_var_name("SHIFT", constants)?.to_biguint();

let sum_d0 = a.d0.to_biguint() + b.d0.to_biguint();
let sum_d0 = a.limbs[0].to_biguint() + b.limbs[0].to_biguint();
let carry_d0 = Felt252::from((sum_d0 >= shift) as usize);
let sum_d1 = a.d1.to_biguint() + b.d1.to_biguint() + carry_d0.to_biguint();
let sum_d1 = a.limbs[1].to_biguint() + b.limbs[1].to_biguint() + carry_d0.to_biguint();
let carry_d1 = Felt252::from((sum_d1 >= shift) as usize);
let sum_d2 = a.d2.to_biguint() + b.d2.to_biguint() + carry_d1.to_biguint();
let sum_d2 = a.limbs[2].to_biguint() + b.limbs[2].to_biguint() + carry_d1.to_biguint();
let carry_d2 = Felt252::from((sum_d2 >= shift) as usize);

insert_value_from_var_name("carry_d0", carry_d0, vm, ids_data, ap_tracking)?;
Expand Down
Loading

1 comment on commit 91eeff5

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.30.

Benchmark suite Current: 91eeff5 Previous: 30de5a2 Ratio
add_u64_with_felt/1 4 ns/iter (± 0) 2 ns/iter (± 0) 2
add_u64_with_felt/2 4 ns/iter (± 0) 2 ns/iter (± 0) 2
add_u64_with_felt/5 2 ns/iter (± 0) 1 ns/iter (± 0) 2
add_u64_with_felt/6 4 ns/iter (± 0) 2 ns/iter (± 0) 2
add_u64_with_felt/7 4 ns/iter (± 0) 3 ns/iter (± 0) 1.33
add_u64_with_felt/8 3 ns/iter (± 0) 2 ns/iter (± 0) 1.50

This comment was automatically generated by workflow using github-action-benchmark.

CC: @unbalancedparentheses

Please sign in to comment.