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

derive & implement Arbitrary for better property based testing #231

Merged
merged 4 commits into from
Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ documentation = "https://triton-vm.org/spec/"

[workspace.dependencies]
anyhow = "1.0"
arbitrary = { version = "1", features = ["derive"] }
bincode = "1.3"
colored = "2.0"
criterion = { version = "0.5", features = ["html_reports"] }
Expand All @@ -35,6 +36,7 @@ num-traits = "0.2"
prettyplease = "0.2"
proc-macro2 = "1.0"
proptest = "1.2"
proptest-arbitrary-interop = "0.1"
quote = "1.0"
rand = "0.8.5"
rand_core = "0.6.4"
Expand Down
2 changes: 2 additions & 0 deletions triton-vm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ readme.workspace = true

[dependencies]
anyhow.workspace = true
arbitrary.workspace = true
bincode.workspace = true
colored.workspace = true
criterion.workspace = true
Expand All @@ -43,6 +44,7 @@ unicode-width.workspace = true
[dev-dependencies]
cargo-husky.workspace = true
proptest.workspace = true
proptest-arbitrary-interop.workspace = true

[[bench]]
name = "prove_halt"
Expand Down
11 changes: 11 additions & 0 deletions triton-vm/src/fri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,7 @@ mod tests {
use itertools::Itertools;
use proptest::collection::vec;
use proptest::prelude::*;
use proptest_arbitrary_interop::arb;
use rand::prelude::IteratorRandom;
use rand::prelude::StdRng;
use rand_core::SeedableRng;
Expand Down Expand Up @@ -1081,4 +1082,14 @@ mod tests {
_ => None,
}
}

proptest! {
#[test]
fn verifying_arbitrary_proof_does_not_panic(
fri in arbitrary_fri(),
mut proof_stream in arb::<ProofStream<Tip5>>(),
) {
let _ = fri.verify(&mut proof_stream, &mut None);
}
}
}
19 changes: 17 additions & 2 deletions triton-vm/src/proof.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use anyhow::Result;
use arbitrary::Arbitrary;
use get_size::GetSize;
use itertools::Itertools;
use serde::Deserialize;
Expand All @@ -13,7 +14,7 @@ use crate::stark;

/// Contains the necessary cryptographic information to verify a computation.
/// Should be used together with a [`Claim`].
#[derive(Debug, Clone, GetSize, Serialize, Deserialize, PartialEq, Eq, BFieldCodec)]
#[derive(Debug, Clone, GetSize, Serialize, Deserialize, PartialEq, Eq, BFieldCodec, Arbitrary)]
pub struct Proof(pub Vec<BFieldElement>);

impl Proof {
Expand All @@ -37,7 +38,9 @@ impl Proof {
/// One additional piece of public information not explicitly listed in the [`Claim`] is the
/// `padded_height`, an upper bound on the length of the computation.
/// It is derivable from a [`Proof`] by calling [`Proof::padded_height()`].
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, GetSize, BFieldCodec, Hash)]
#[derive(
Debug, Clone, Serialize, Deserialize, PartialEq, Eq, GetSize, BFieldCodec, Hash, Arbitrary,
)]
pub struct Claim {
/// The hash digest of the program that was executed. The hash function in use is Tip5.
pub program_digest: Digest,
Expand Down Expand Up @@ -65,12 +68,15 @@ impl Claim {

#[cfg(test)]
pub mod test_claim_proof {
use proptest::collection::vec;
use proptest::prelude::*;
use rand::random;
use twenty_first::shared_math::b_field_element::BFieldElement;
use twenty_first::shared_math::bfield_codec::BFieldCodec;
use twenty_first::shared_math::other::random_elements;

use crate::proof_item::ProofItem;
use crate::shared_tests::arbitrary_bfield_element;
use crate::stark::StarkHasher;

use super::*;
Expand Down Expand Up @@ -121,4 +127,13 @@ pub mod test_claim_proof {
let maybe_padded_height = proof.padded_height();
assert!(maybe_padded_height.is_err());
}

proptest! {
#[test]
fn decoding_arbitrary_proof_data_does_not_panic(
proof_data in vec(arbitrary_bfield_element(), 0..1000),
) {
let _ = Proof::decode(&proof_data);
}
}
}
16 changes: 3 additions & 13 deletions triton-vm/src/proof_item.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use anyhow::bail;
use anyhow::Result;
use arbitrary::Arbitrary;
use strum_macros::Display;
use strum_macros::EnumCount;
use twenty_first::shared_math::b_field_element::BFieldElement;
Expand All @@ -13,15 +14,15 @@ use crate::stark::NUM_QUOTIENT_SEGMENTS;
/// A `FriResponse` is an `AuthenticationStructure` together with the values of the
/// revealed leaves of the Merkle tree. Together, they correspond to the
/// queried indices of the FRI codeword (of that round).
#[derive(Debug, Clone, PartialEq, Eq, Hash, BFieldCodec)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, BFieldCodec, Arbitrary)]
pub struct FriResponse {
/// The authentication structure of the Merkle tree.
pub auth_structure: AuthenticationStructure,
/// The values of the opened leaves of the Merkle tree.
pub revealed_leaves: Vec<XFieldElement>,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash, Display, EnumCount)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Display, EnumCount, Arbitrary)]
pub enum ProofItem {
AuthenticationStructure(AuthenticationStructure),
MasterBaseTableRows(Vec<Vec<BFieldElement>>),
Expand Down Expand Up @@ -200,17 +201,6 @@ impl BFieldCodec for ProofItem {
fn encode(&self) -> Vec<BFieldElement> {
use ProofItem::*;

#[cfg(debug_assertions)]
{
use crate::table::master_table::NUM_BASE_COLUMNS;
use crate::table::master_table::NUM_EXT_COLUMNS;
match self {
OutOfDomainBaseRow(row) => assert_eq!(NUM_BASE_COLUMNS, row.len()),
OutOfDomainExtRow(row) => assert_eq!(NUM_EXT_COLUMNS, row.len()),
_ => (),
}
}

let discriminant = vec![self.discriminant()];
let encoding = match self {
AuthenticationStructure(something) => something.encode(),
Expand Down
3 changes: 2 additions & 1 deletion triton-vm/src/proof_stream.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use anyhow::bail;
use anyhow::Result;
use arbitrary::Arbitrary;
use twenty_first::shared_math::b_field_element::BFieldElement;
use twenty_first::shared_math::b_field_element::BFIELD_ONE;
use twenty_first::shared_math::b_field_element::BFIELD_ZERO;
Expand All @@ -11,7 +12,7 @@ use twenty_first::util_types::algebraic_hasher::AlgebraicHasher;
use crate::proof::Proof;
use crate::proof_item::ProofItem;

#[derive(Default, Debug, Clone, PartialEq, Eq)]
#[derive(Default, Debug, Clone, PartialEq, Eq, Arbitrary)]
pub struct ProofStream<H>
where
H: AlgebraicHasher,
Expand Down
23 changes: 23 additions & 0 deletions triton-vm/src/stark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use std::ops::Mul;

use anyhow::bail;
use anyhow::Result;
use arbitrary::Arbitrary;
use arbitrary::Unstructured;
use itertools::izip;
use itertools::Itertools;
use ndarray::prelude::*;
Expand Down Expand Up @@ -125,6 +127,14 @@ impl Default for StarkParameters {
}
}

impl<'a> Arbitrary<'a> for StarkParameters {
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
let security_level = u.int_in_range(1..=640)?;
let log_2_of_fri_expansion_factor = u.int_in_range(1..=8)?;
Ok(Self::new(security_level, log_2_of_fri_expansion_factor))
}
}

pub struct Stark {}

impl Stark {
Expand Down Expand Up @@ -1095,6 +1105,8 @@ impl Stark {
pub(crate) mod triton_stark_tests {
use itertools::izip;
use num_traits::Zero;
use proptest::prelude::*;
use proptest_arbitrary_interop::arb;
use rand::prelude::ThreadRng;
use rand::thread_rng;
use rand::Rng;
Expand Down Expand Up @@ -1902,6 +1914,17 @@ pub(crate) mod triton_stark_tests {
println!("{report}");
}

proptest! {
#[test]
fn verifying_arbitrary_proof_does_not_panic(
parameters in arb::<StarkParameters>(),
claim in arb::<Claim>(),
proof in arb::<Proof>(),
) {
let _ = Stark::verify(&parameters, &claim, &proof, &mut None);
}
}

#[test]
#[ignore = "stress test"]
fn prove_fib_successively_larger() {
Expand Down
Loading