Skip to content

Commit

Permalink
Add Int type using two's complement representation (#695)
Browse files Browse the repository at this point in the history
See #700
  • Loading branch information
erik-3milabs authored Nov 1, 2024
1 parent b85c162 commit 04079c8
Show file tree
Hide file tree
Showing 22 changed files with 2,660 additions and 72 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,7 @@ harness = false
[[bench]]
name = "uint"
harness = false

[[bench]]
name = "int"
harness = false
344 changes: 344 additions & 0 deletions benches/int.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,344 @@
use std::ops::Div;

use criterion::{black_box, criterion_group, criterion_main, BatchSize, Criterion};
use num_traits::WrappingSub;
use rand_core::OsRng;

use crypto_bigint::{NonZero, Random, I1024, I128, I2048, I256, I4096, I512};

fn bench_mul(c: &mut Criterion) {
let mut group = c.benchmark_group("wrapping ops");

group.bench_function("split_mul, I128xI128", |b| {
b.iter_batched(
|| (I256::random(&mut OsRng), I256::random(&mut OsRng)),
|(x, y)| black_box(x.split_mul(&y)),
BatchSize::SmallInput,
)
});

group.bench_function("split_mul, I256xI256", |b| {
b.iter_batched(
|| (I256::random(&mut OsRng), I256::random(&mut OsRng)),
|(x, y)| black_box(x.split_mul(&y)),
BatchSize::SmallInput,
)
});

group.bench_function("split_mul, I512xI512", |b| {
b.iter_batched(
|| (I512::random(&mut OsRng), I512::random(&mut OsRng)),
|(x, y)| black_box(x.split_mul(&y)),
BatchSize::SmallInput,
)
});

group.bench_function("split_mul, I1024xI1024", |b| {
b.iter_batched(
|| (I1024::random(&mut OsRng), I1024::random(&mut OsRng)),
|(x, y)| black_box(x.split_mul(&y)),
BatchSize::SmallInput,
)
});

group.bench_function("split_mul, I2048xI2048", |b| {
b.iter_batched(
|| (I2048::random(&mut OsRng), I2048::random(&mut OsRng)),
|(x, y)| black_box(x.split_mul(&y)),
BatchSize::SmallInput,
)
});

group.bench_function("split_mul, I4096xI4096", |b| {
b.iter_batched(
|| (I4096::random(&mut OsRng), I4096::random(&mut OsRng)),
|(x, y)| black_box(x.split_mul(&y)),
BatchSize::SmallInput,
)
});
}

fn bench_widening_mul(c: &mut Criterion) {
let mut group = c.benchmark_group("widening ops");

group.bench_function("widening_mul, I128xI128", |b| {
b.iter_batched(
|| (I128::random(&mut OsRng), I128::random(&mut OsRng)),
|(x, y)| black_box(x.widening_mul(&y)),
BatchSize::SmallInput,
)
});

group.bench_function("widening_mul, I256xI256", |b| {
b.iter_batched(
|| (I256::random(&mut OsRng), I256::random(&mut OsRng)),
|(x, y)| black_box(x.widening_mul(&y)),
BatchSize::SmallInput,
)
});

group.bench_function("widening_mul, I512xI512", |b| {
b.iter_batched(
|| (I512::random(&mut OsRng), I512::random(&mut OsRng)),
|(x, y)| black_box(x.widening_mul(&y)),
BatchSize::SmallInput,
)
});

group.bench_function("widening_mul, I1024xI1024", |b| {
b.iter_batched(
|| (I1024::random(&mut OsRng), I1024::random(&mut OsRng)),
|(x, y)| black_box(x.widening_mul(&y)),
BatchSize::SmallInput,
)
});

group.bench_function("widening_mul, I2048xI2048", |b| {
b.iter_batched(
|| (I2048::random(&mut OsRng), I2048::random(&mut OsRng)),
|(x, y)| black_box(x.widening_mul(&y)),
BatchSize::SmallInput,
)
});

group.bench_function("widening_mul, I4096xI4096", |b| {
b.iter_batched(
|| (I4096::random(&mut OsRng), I4096::random(&mut OsRng)),
|(x, y)| black_box(x.widening_mul(&y)),
BatchSize::SmallInput,
)
});
}

fn bench_div(c: &mut Criterion) {
let mut group = c.benchmark_group("wrapping ops");

group.bench_function("div, I256/I128, full size", |b| {
b.iter_batched(
|| {
let x = I256::random(&mut OsRng);
let y = I128::random(&mut OsRng).resize::<{ I256::LIMBS }>();
(x, NonZero::new(y).unwrap())
},
|(x, y)| black_box(x.div(&y)),
BatchSize::SmallInput,
)
});

group.bench_function("div, I512/I256, full size", |b| {
b.iter_batched(
|| {
let x = I512::random(&mut OsRng);
let y = I256::random(&mut OsRng).resize::<{ I512::LIMBS }>();
(x, NonZero::new(y).unwrap())
},
|(x, y)| black_box(x.div(&y)),
BatchSize::SmallInput,
)
});

group.bench_function("div, I1024/I512, full size", |b| {
b.iter_batched(
|| {
let x = I1024::random(&mut OsRng);
let y = I512::random(&mut OsRng).resize::<{ I1024::LIMBS }>();
(x, NonZero::new(y).unwrap())
},
|(x, y)| black_box(x.div(&y)),
BatchSize::SmallInput,
)
});

group.bench_function("div, I2048/I1024, full size", |b| {
b.iter_batched(
|| {
let x = I2048::random(&mut OsRng);
let y = I1024::random(&mut OsRng).resize::<{ I2048::LIMBS }>();
(x, NonZero::new(y).unwrap())
},
|(x, y)| black_box(x.div(&y)),
BatchSize::SmallInput,
)
});

group.bench_function("div, I4096/I2048, full size", |b| {
b.iter_batched(
|| {
let x = I4096::random(&mut OsRng);
let y = I2048::random(&mut OsRng).resize::<{ I4096::LIMBS }>();
(x, NonZero::new(y).unwrap())
},
|(x, y)| black_box(x.div(&y)),
BatchSize::SmallInput,
)
});

group.finish();
}

fn bench_add(c: &mut Criterion) {
let mut group = c.benchmark_group("wrapping ops");

group.bench_function("add, I128+I128", |b| {
b.iter_batched(
|| {
let x = I128::random(&mut OsRng);
let y = I128::random(&mut OsRng);
(x, y)
},
|(x, y)| black_box(x.wrapping_add(&y)),
BatchSize::SmallInput,
)
});

group.bench_function("add, I256+I256", |b| {
b.iter_batched(
|| {
let x = I256::random(&mut OsRng);
let y = I256::random(&mut OsRng);
(x, y)
},
|(x, y)| black_box(x.wrapping_add(&y)),
BatchSize::SmallInput,
)
});

group.bench_function("add, I512+I512", |b| {
b.iter_batched(
|| {
let x = I512::random(&mut OsRng);
let y = I512::random(&mut OsRng);
(x, y)
},
|(x, y)| black_box(x.wrapping_add(&y)),
BatchSize::SmallInput,
)
});

group.bench_function("add, I1024+I1024", |b| {
b.iter_batched(
|| {
let x = I1024::random(&mut OsRng);
let y = I1024::random(&mut OsRng);
(x, y)
},
|(x, y)| black_box(x.wrapping_add(&y)),
BatchSize::SmallInput,
)
});

group.bench_function("add, I2048+I2048", |b| {
b.iter_batched(
|| {
let x = I2048::random(&mut OsRng);
let y = I2048::random(&mut OsRng);
(x, y)
},
|(x, y)| black_box(x.wrapping_add(&y)),
BatchSize::SmallInput,
)
});

group.bench_function("add, I4096+I4096", |b| {
b.iter_batched(
|| {
let x = I4096::random(&mut OsRng);
let y = I4096::random(&mut OsRng);
(x, y)
},
|(x, y)| black_box(x.wrapping_add(&y)),
BatchSize::SmallInput,
)
});

group.finish();
}

fn bench_sub(c: &mut Criterion) {
let mut group = c.benchmark_group("wrapping ops");

group.bench_function("sub, I128-I128", |b| {
b.iter_batched(
|| {
let x = I128::random(&mut OsRng);
let y = I128::random(&mut OsRng);
(x, y)
},
|(x, y)| black_box(x.wrapping_sub(&y)),
BatchSize::SmallInput,
)
});

group.bench_function("sub, I256-I256", |b| {
b.iter_batched(
|| {
let x = I256::random(&mut OsRng);
let y = I256::random(&mut OsRng);
(x, y)
},
|(x, y)| black_box(x.wrapping_sub(&y)),
BatchSize::SmallInput,
)
});

group.bench_function("sub, I512-I512", |b| {
b.iter_batched(
|| {
let x = I512::random(&mut OsRng);
let y = I512::random(&mut OsRng);
(x, y)
},
|(x, y)| black_box(x.wrapping_sub(&y)),
BatchSize::SmallInput,
)
});

group.bench_function("sub, I1024-I1024", |b| {
b.iter_batched(
|| {
let x = I1024::random(&mut OsRng);
let y = I1024::random(&mut OsRng);
(x, y)
},
|(x, y)| black_box(x.wrapping_sub(&y)),
BatchSize::SmallInput,
)
});

group.bench_function("sub, I2048-I2048", |b| {
b.iter_batched(
|| {
let x = I2048::random(&mut OsRng);
let y = I2048::random(&mut OsRng);
(x, y)
},
|(x, y)| black_box(x.wrapping_sub(&y)),
BatchSize::SmallInput,
)
});

group.bench_function("sub, I4096-I4096", |b| {
b.iter_batched(
|| {
let x = I4096::random(&mut OsRng);
let y = I4096::random(&mut OsRng);
(x, y)
},
|(x, y)| black_box(x.wrapping_sub(&y)),
BatchSize::SmallInput,
)
});

group.finish();
}

criterion_group!(
benches,
bench_mul,
bench_widening_mul,
bench_div,
bench_add,
bench_sub,
);

criterion_main!(benches);
20 changes: 19 additions & 1 deletion src/const_choice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ impl ConstChoice {
Self(value.wrapping_neg())
}

/// Returns the truthy value if the most significant bit of `value` is `1`,
/// and the falsy value if it equals `0`.
#[inline]
pub(crate) const fn from_word_msb(value: Word) -> Self {
Self::from_word_lsb(value >> (Word::BITS - 1))
}

/// Returns the truthy value if `value == 1`, and the falsy value if `value == 0`.
/// Panics for other values.
#[inline]
Expand Down Expand Up @@ -187,6 +194,16 @@ impl ConstChoice {
Self(self.0 ^ other.0)
}

#[inline]
pub(crate) const fn ne(&self, other: Self) -> Self {
Self::xor(self, other)
}

#[inline]
pub(crate) const fn eq(&self, other: Self) -> Self {
Self::ne(self, other).not()
}

/// Return `b` if `self` is truthy, otherwise return `a`.
#[inline]
pub(crate) const fn select_word(&self, a: Word, b: Word) -> Word {
Expand Down Expand Up @@ -450,9 +467,10 @@ impl<const SAT_LIMBS: usize, const UNSAT_LIMBS: usize>

#[cfg(test)]
mod tests {
use super::ConstChoice;
use crate::{WideWord, Word};

use super::ConstChoice;

#[test]
fn from_u64_lsb() {
assert_eq!(ConstChoice::from_u64_lsb(0), ConstChoice::FALSE);
Expand Down
Loading

0 comments on commit 04079c8

Please sign in to comment.