From cd19cd3899c0a358df2d27c66f75ed0b1e11c292 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Thu, 29 Jul 2021 12:29:33 -0700 Subject: [PATCH] crypto-bigint: add init proptests for equivalence with num-bigint Adds an initial set of property-based tests to check equivalence between `crypto_bigint::U256` and `num_bigint::BigUint`. --- .github/workflows/crypto-bigint.yml | 14 ++++ .gitignore | 1 + crypto-bigint/proptests/Cargo.toml | 16 +++++ crypto-bigint/proptests/lib.rs | 0 crypto-bigint/proptests/tests/equivalence.rs | 70 ++++++++++++++++++++ crypto-bigint/src/uint/mul.rs | 2 +- 6 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 crypto-bigint/proptests/Cargo.toml create mode 100644 crypto-bigint/proptests/lib.rs create mode 100644 crypto-bigint/proptests/tests/equivalence.rs diff --git a/.github/workflows/crypto-bigint.yml b/.github/workflows/crypto-bigint.yml index 2647bfb0..55b69f6d 100644 --- a/.github/workflows/crypto-bigint.yml +++ b/.github/workflows/crypto-bigint.yml @@ -71,6 +71,20 @@ jobs: - run: cargo test --target ${{ matrix.target }} --release --features zeroize - run: cargo test --target ${{ matrix.target }} --release --all-features + proptests: + runs-on: ubuntu-latest + defaults: + run: + working-directory: crypto-bigint/proptests + steps: + - uses: actions/checkout@v1 + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + override: true + - run: cargo test + # Cross-compiled tests cross: strategy: diff --git a/.gitignore b/.gitignore index f25c464e..3f39e8ad 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ target **/Cargo.lock +**/*.proptest-regressions diff --git a/crypto-bigint/proptests/Cargo.toml b/crypto-bigint/proptests/Cargo.toml new file mode 100644 index 00000000..68d36484 --- /dev/null +++ b/crypto-bigint/proptests/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "proptests" +version = "0.0.0" +edition = "2018" +publish = false + +[lib] +path = "./lib.rs" + +[workspace] +members = ["."] + +[dependencies] +crypto-bigint = { path = ".." } +num-bigint = "0.4" +proptest = "1" diff --git a/crypto-bigint/proptests/lib.rs b/crypto-bigint/proptests/lib.rs new file mode 100644 index 00000000..e69de29b diff --git a/crypto-bigint/proptests/tests/equivalence.rs b/crypto-bigint/proptests/tests/equivalence.rs new file mode 100644 index 00000000..311e2b9d --- /dev/null +++ b/crypto-bigint/proptests/tests/equivalence.rs @@ -0,0 +1,70 @@ +//! Equivalence tests between `num-bigint` and `crypto-bigint` + +use crypto_bigint::{Encoding, U256}; +use num_bigint::BigUint; +use proptest::prelude::*; +use std::mem; + +fn to_biguint(uint: &U256) -> BigUint { + BigUint::from_bytes_be(uint.to_be_bytes().as_ref()) +} + +fn to_uint(big_uint: BigUint) -> U256 { + let mut input = [0u8; U256::BYTE_SIZE]; + let encoded = big_uint.to_bytes_be(); + + match U256::BYTE_SIZE.checked_sub(encoded.len()) { + Some(off) => input[off..].copy_from_slice(&encoded), + None => { + let off = encoded.len() - U256::BYTE_SIZE; + input.copy_from_slice(&encoded[off..]); + } + } + + U256::from_be_slice(&input) +} + +prop_compose! { + fn uint()(bytes in any::<[u8; 32]>()) -> U256 { + U256::from_be_slice(&bytes) + } +} + +proptest! { + #[test] + fn wrapping_add(a in uint(), b in uint()) { + let a_bi = to_biguint(&a); + let b_bi = to_biguint(&b); + + let expected = to_uint(a_bi + b_bi); + let actual = a.wrapping_add(&b); + + assert_eq!(expected, actual); + } + + #[test] + fn wrapping_sub(mut a in uint(), mut b in uint()) { + if b > a { + mem::swap(&mut a, &mut b); + } + + let a_bi = to_biguint(&a); + let b_bi = to_biguint(&b); + + let expected = to_uint(a_bi - b_bi); + let actual = a.wrapping_sub(&b); + + assert_eq!(expected, actual); + } + + #[test] + fn wrapping_mul(a in uint(), b in uint()) { + let a_bi = to_biguint(&a); + let b_bi = to_biguint(&b); + + let expected = to_uint(a_bi * b_bi); + let actual = a.wrapping_mul(&b); + + assert_eq!(expected, actual); + } +} diff --git a/crypto-bigint/src/uint/mul.rs b/crypto-bigint/src/uint/mul.rs index a35d9c3d..7113bdf0 100644 --- a/crypto-bigint/src/uint/mul.rs +++ b/crypto-bigint/src/uint/mul.rs @@ -44,7 +44,7 @@ impl UInt { /// Perform wrapping multiplication, discarding overflow. pub const fn wrapping_mul(&self, rhs: &Self) -> Self { - self.mul_wide(rhs).0 + self.mul_wide(rhs).1 } /// Perform checked multiplication, returning a [`CtOption`] which `is_some`