Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LurkField + refactor quickcheck -> proptest #240

Merged
merged 29 commits into from
Feb 8, 2023
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
65bafd6
refactor: convert quickcheck -> proptest
huitseeker Jan 25, 2023
37f02e2
nix flake build
johnchandlerburnham Jan 31, 2023
0a6d8c7
set toolchain to 1.67.0
johnchandlerburnham Jan 31, 2023
89f3cc9
Add minimal CODEOWNERS file. (#235)
porcuquine Jan 28, 2023
6965843
Implement coercion to u32 (and to char) (#223)
emmorais Jan 31, 2023
8882c3e
nix flake build
johnchandlerburnham Jan 31, 2023
485f340
Test Rust install on CI
samuelburnham Jan 31, 2023
b56fe1a
Another test
samuelburnham Jan 31, 2023
f7fb687
Fix CI
samuelburnham Jan 31, 2023
30c8fd4
Fix CI
samuelburnham Jan 31, 2023
f3ee6a0
refactor LurkField trait
johnchandlerburnham Feb 1, 2023
6578d23
Merge branch 'jcb/build' of github.com:lurk-lang/lurk-rs into jcb/lur…
johnchandlerburnham Feb 1, 2023
4d1f59b
fix flake
johnchandlerburnham Feb 1, 2023
0873ce0
fix formatting
johnchandlerburnham Feb 1, 2023
80e3609
Merge branch 'master' of github.com:lurk-lang/lurk-rs into jcb/lurk_ff
johnchandlerburnham Feb 1, 2023
49a19f3
update property testing based on #229
johnchandlerburnham Feb 1, 2023
1e1676c
fix fcomm
johnchandlerburnham Feb 1, 2023
fee2a99
fix clippy warnings
johnchandlerburnham Feb 1, 2023
b48b7d7
Merge branch 'jcb/lurk_ff' of github.com:lurk-lang/lurk-rs into jcb/p…
johnchandlerburnham Feb 1, 2023
9627bab
remove unnecessary canonical bytes trait methods, add repr canonicity…
johnchandlerburnham Feb 2, 2023
5834b0d
Merge branch 'master' of github.com:lurk-lang/lurk-rs into jcb/lurk_ff
johnchandlerburnham Feb 2, 2023
ce62b5f
remove vec_f functions from LurkField, refactor tests
johnchandlerburnham Feb 7, 2023
59320e3
remove no longer needed store tests
johnchandlerburnham Feb 7, 2023
3e21c79
Merge branch 'jcb/lurk_ff' of github.com:lurk-lang/lurk-rs into jcb/p…
johnchandlerburnham Feb 7, 2023
f65e73e
Merge branch 'master' of github.com:lurk-lang/lurk-rs into jcb/proptest
johnchandlerburnham Feb 8, 2023
054fba7
update FWrap Arbitrary
johnchandlerburnham Feb 8, 2023
3c98a33
Merge branch 'master' of github.com:lurk-lang/lurk-rs into jcb/proptest
johnchandlerburnham Feb 8, 2023
ef566df
Support Wasm by moving proptest to dev-dependencies
samuelburnham Feb 8, 2023
04404ac
Switch back to simple conditional compilation
samuelburnham Feb 8, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
270 changes: 185 additions & 85 deletions Cargo.lock

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ multihash = { version = "0.16.1", default-features = false, features = ["alloc",
num-bigint = "0.4.3"
num-integer = "0.1.45"
num-traits = "0.2.15"
proptest = "1.0.0"
proptest-derive = "0.3.0"

[features]
default = []
Expand All @@ -53,8 +55,7 @@ gpu = ["neptune/opencl"]
[dev-dependencies]
criterion = "0.3.5"
structopt = { version = "0.3", default-features = false }
quickcheck = "1.0.3"
quickcheck_macros = "1.0.0"
tap = "1.0.1"

[[bench]]
name = "eval"
Expand Down
99 changes: 47 additions & 52 deletions src/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,45 +224,37 @@ pub mod tests {
use blstrs::Scalar as Fr;

use super::*;
use quickcheck::{Arbitrary, Gen};
use proptest::prelude::*;

impl<F: LurkField> Arbitrary for FWrap<F> {
fn arbitrary(_: &mut Gen) -> Self {
let f = F::random(rand::thread_rng());
FWrap(f)
}
}

// For working around the orphan trait impl rule
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct VecFWrap<F: LurkField>(pub Vec<F>);
type Parameters = ();
type Strategy = BoxedStrategy<Self>;

impl<F: LurkField> Arbitrary for VecFWrap<F> {
fn arbitrary(g: &mut Gen) -> Self {
let vec_f: Vec<FWrap<F>> = Arbitrary::arbitrary(g);
VecFWrap(vec_f.into_iter().map(|f| f.0).collect())
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
let strategy = Just(FWrap(F::random(rand::thread_rng())));
johnchandlerburnham marked this conversation as resolved.
Show resolved Hide resolved
strategy.boxed()
}
}

fn repr_bytes_consistency<F: LurkField>(f1: FWrap<F>) -> bool {
fn repr_bytes_consistency<F: LurkField>(f1: FWrap<F>) {
let bytes = f1.0.to_repr().as_ref().to_owned();
let f2 = <F as LurkField>::from_bytes(&bytes);
Some(f1.0) == f2
}

#[quickcheck]
fn prop_blstrs_repr_bytes_consistency(f1: FWrap<Fr>) -> bool {
repr_bytes_consistency(f1)
}

#[quickcheck]
fn prop_pallas_repr_bytes_consistency(f1: FWrap<pasta_curves::Fp>) -> bool {
repr_bytes_consistency(f1)
let f2 = <F as LurkField>::from_bytes(&bytes).expect("from_bytes");
assert_eq!(f1.0, f2)
}

#[quickcheck]
fn prop_vesta_repr_bytes_consistency(f1: FWrap<pasta_curves::Fq>) -> bool {
proptest! {
#[test]
fn prop_bls_repr_bytes_consistency(f1 in any::<FWrap<Fr>>()) {
johnchandlerburnham marked this conversation as resolved.
Show resolved Hide resolved
repr_bytes_consistency(f1)
}
#[test]
fn prop_pallas_repr_bytes_consistency(f1 in any::<FWrap<pasta_curves::Fp>>()) {
repr_bytes_consistency(f1)
}
#[test]
fn prop_vesta_repr_bytes_consistency(f1 in any::<FWrap<pasta_curves::Fq>>()) {
repr_bytes_consistency(f1)
}
}

// Construct canonical bytes from a field element
Expand Down Expand Up @@ -300,34 +292,37 @@ pub mod tests {
res
}

fn repr_canonicity<F: LurkField>(f1: FWrap<F>) -> bool {
fn repr_canonicity<F: LurkField>(f1: FWrap<F>) {
let repr_bytes = f1.0.to_bytes();
let canonical_bytes = to_le_bytes_canonical(f1.0);
let f2_repr = F::from_bytes(&repr_bytes).unwrap();
let f2_repr = F::from_bytes(&repr_bytes).expect("from_bytes");
let f2_canonical = from_le_bytes_canonical::<F>(&canonical_bytes);
repr_bytes == canonical_bytes && f2_repr == f2_canonical
assert_eq!(repr_bytes, canonical_bytes);
assert_eq!(f2_repr, f2_canonical)
}

#[quickcheck]
fn prop_blstrs_repr_canonicity(f1: FWrap<Fr>) -> bool {
proptest! {
#[test]
fn prop_bls_repr_canonicity(f1 in any::<FWrap<Fr>>()) {
repr_canonicity(f1)
}

#[quickcheck]
fn prop_pallas_repr_canonicity(f1: FWrap<pasta_curves::Fp>) -> bool {
repr_canonicity(f1)
}

#[quickcheck]
fn prop_vesta_repr_canonicity(f1: FWrap<pasta_curves::Fq>) -> bool {
repr_canonicity(f1)
}

#[quickcheck]
fn prop_tag_consistency(x: ExprTag) -> bool {
let f1 = Fr::from_expr_tag(x);
let tag = <Fr as LurkField>::to_expr_tag(&f1).unwrap();
let f2 = Fr::from_expr_tag(tag);
f1 == f2 && x == tag
}
#[test]
fn prop_pallas_repr_canonicity(f1 in any::<FWrap<pasta_curves::Fp>>()) {
repr_canonicity(f1)
}
#[test]
fn prop_vesta_repr_canonicity(f1 in any::<FWrap<pasta_curves::Fq>>()) {
repr_canonicity(f1)
}
}

proptest! {
fn prop_tag_consistency(x in any::<ExprTag>()) {
let f1 = Fr::from_expr_tag(x);
let tag = <Fr as LurkField>::to_expr_tag(&f1).unwrap();
let f2 = Fr::from_expr_tag(tag);
assert_eq!(f1, f2);
assert_eq!(x, tag)
}
}
}
34 changes: 0 additions & 34 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,6 @@ extern crate core;
#[macro_use]
extern crate alloc;

#[cfg(test)]
extern crate quickcheck;
#[cfg(test)]
#[macro_use(quickcheck)]
extern crate quickcheck_macros;

pub mod circuit;
pub mod eval;
pub mod field;
Expand All @@ -36,31 +30,3 @@ pub use uint::UInt;
pub const TEST_SEED: [u8; 16] = [
0x62, 0x59, 0x5d, 0xbe, 0x3d, 0x76, 0x3d, 0x8d, 0xdb, 0x17, 0x32, 0x37, 0x06, 0x54, 0xe5, 0xbc,
];

#[cfg(test)]
pub mod test {
use quickcheck::Gen;
use rand::Rng;

// This is a useful testing utility for generating Arbitrary instances of
// enums, by providing generators for each variant, plus a frequency weight
// for how often to choose that variant. It's included in lib::test to make
// it easier to import in the test modules of specific submodules.
pub fn frequency<T, F: Fn(&mut Gen) -> T>(g: &mut Gen, gens: Vec<(i64, F)>) -> T {
if gens.iter().any(|(v, _)| *v < 0) {
panic!("Negative weight");
}
let sum: i64 = gens.iter().map(|x| x.0).sum();
let mut rng = rand::thread_rng();
let mut weight: i64 = rng.gen_range(1..=sum);
// let mut weight: i64 = g.rng.gen_range(1, sum);
for gen in gens {
if weight - gen.0 <= 0 {
return gen.1(g);
} else {
weight -= gen.0;
}
}
panic!("Calculation error for weight = {}", weight);
}
}
43 changes: 18 additions & 25 deletions src/num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,40 +262,33 @@ impl<'de, F: LurkField> Deserialize<'de> for Num<F> {
mod tests {
use super::*;

use quickcheck::{Arbitrary, Gen};
use proptest::prelude::*;

use crate::field::FWrap;
use crate::test::frequency;
use blstrs::Scalar;
use blstrs::Scalar as Fr;
use ff::Field;

impl Arbitrary for Num<Fr> {
fn arbitrary(g: &mut Gen) -> Self {
let input: Vec<(i64, Box<dyn Fn(&mut Gen) -> Num<Fr>>)> = vec![
(100, Box::new(|g| Num::U64(Arbitrary::arbitrary(g)))),
(
100,
Box::new(|g| {
let f = FWrap::arbitrary(g);
Num::Scalar(f.0)
}),
),
];
frequency(g, input)
impl<Fr: LurkField> Arbitrary for Num<Fr> {
type Parameters = ();
type Strategy = BoxedStrategy<Self>;

fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
prop_oneof!(
any::<u64>().prop_map(Num::U64),
any::<FWrap<Fr>>().prop_map(|f| Num::Scalar(f.0)),
)
.boxed()
}
}

#[quickcheck]
fn prop_num_ipld(x: Num<Fr>) -> bool {
if let Ok(ipld) = libipld::serde::to_ipld(x) {
if let Ok(y) = libipld::serde::from_ipld(ipld) {
Num::Scalar(x.into_scalar()) == y
} else {
false
}
} else {
false
proptest! {
#[test]
fn prop_num_ipld(x: Num<Fr>) {
let to_ipld = libipld::serde::to_ipld(x).unwrap();
let y = libipld::serde::from_ipld(to_ipld).unwrap();
assert_eq!(
Num::Scalar(x.into_scalar()), y);
}
}

Expand Down
Loading