Skip to content

Commit df5842d

Browse files
Merge pull request #641 from input-output-hk/proptest-chain-crypto
2 parents 7e56c8b + 0fe5ae1 commit df5842d

File tree

12 files changed

+210
-63
lines changed

12 files changed

+210
-63
lines changed

.github/workflows/main.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ on:
77
- ci/test
88
pull_request:
99

10+
env:
11+
PROPTEST_CASES: 100
12+
1013
jobs:
1114
update_deps:
1215
name: Update dependencies

chain-crypto/Cargo.toml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,25 @@ generic-array = "^0.14"
1919
rand_core = "0.6"
2020
rand = { version = "0.8", features = ["small_rng"], optional = true }
2121
rayon = "1.5"
22-
quickcheck = { version = "0.9", optional = true }
2322
ed25519-bip32 = "0.4"
2423
hex = "0.4.0"
2524
typed-bytes = { path = "../typed-bytes" }
2625

2726
criterion = { version = "0.3.0", optional = true }
28-
27+
quickcheck = { version = "0.9", optional = true }
28+
proptest = { git = "https://github.com/input-output-hk/proptest.git", optional = true }
29+
test-strategy = { version = "0.1", optional = true }
2930

3031
[dev-dependencies]
3132
quickcheck = "0.9"
32-
quickcheck_macros = "0.9"
33+
proptest = { git = "https://github.com/input-output-hk/proptest.git" }
34+
test-strategy = "0.1"
3335
rand = { version = "0.8", features = ["small_rng"] }
3436
smoke = "^0.2.1"
3537

3638
[features]
3739
with-bench = ["criterion"]
38-
property-test-api = [ "quickcheck", "rand" ]
40+
property-test-api = [ "quickcheck", "rand", "proptest", "test-strategy" ]
3941
p256k1 = ["eccoxide"]
4042

4143
[[bench]]

chain-crypto/src/algorithms/ed25519.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,13 +123,16 @@ mod test {
123123
use crate::key::KeyPair;
124124
use crate::sign::test::{keypair_signing_ko, keypair_signing_ok};
125125

126-
#[quickcheck]
127-
fn sign_ok(input: (KeyPair<Ed25519>, Vec<u8>)) -> bool {
128-
keypair_signing_ok(input)
126+
use proptest::prelude::*;
127+
use test_strategy::proptest;
128+
129+
#[proptest]
130+
fn sign_ok(input: (KeyPair<Ed25519>, Vec<u8>)) {
131+
prop_assert!(keypair_signing_ok(input))
129132
}
130133

131-
#[quickcheck]
132-
fn sign_ko(input: (KeyPair<Ed25519>, KeyPair<Ed25519>, Vec<u8>)) -> bool {
133-
keypair_signing_ko(input)
134+
#[proptest]
135+
fn sign_ko(input: (KeyPair<Ed25519>, KeyPair<Ed25519>, Vec<u8>)) {
136+
prop_assert!(keypair_signing_ko(input))
134137
}
135138
}

chain-crypto/src/algorithms/ed25519_derive.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,15 @@ mod test {
110110
use crate::key::KeyPair;
111111
use crate::sign::test::{keypair_signing_ko, keypair_signing_ok};
112112

113-
#[quickcheck]
114-
fn sign_ok(input: (KeyPair<Ed25519Bip32>, Vec<u8>)) -> bool {
115-
keypair_signing_ok(input)
113+
use proptest::prelude::*;
114+
use test_strategy::proptest;
115+
116+
#[proptest]
117+
fn sign_ok(input: (KeyPair<Ed25519Bip32>, Vec<u8>)) {
118+
prop_assert!(keypair_signing_ok(input))
116119
}
117-
#[quickcheck]
118-
fn sign_ko(input: (KeyPair<Ed25519Bip32>, KeyPair<Ed25519Bip32>, Vec<u8>)) -> bool {
119-
keypair_signing_ko(input)
120+
#[proptest]
121+
fn sign_ko(input: (KeyPair<Ed25519Bip32>, KeyPair<Ed25519Bip32>, Vec<u8>)) {
122+
prop_assert!(keypair_signing_ko(input))
120123
}
121124
}

chain-crypto/src/algorithms/ed25519_extended.rs

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -75,24 +75,40 @@ mod test {
7575
use crate::key::KeyPair;
7676
use crate::sign::test::{keypair_signing_ko, keypair_signing_ok};
7777

78-
#[quickcheck]
79-
fn sign_ok(input: (KeyPair<Ed25519Extended>, Vec<u8>)) -> bool {
80-
keypair_signing_ok(input)
78+
use proptest::prelude::*;
79+
use test_strategy::proptest;
80+
81+
#[proptest]
82+
fn sign_ok(input: (KeyPair<Ed25519Extended>, Vec<u8>)) {
83+
prop_assert!(keypair_signing_ok(input))
84+
}
85+
86+
#[proptest]
87+
fn sign_ko(input: (KeyPair<Ed25519Extended>, KeyPair<Ed25519Extended>, Vec<u8>)) {
88+
prop_assert!(keypair_signing_ko(input))
89+
}
90+
91+
#[test]
92+
fn secret_from_binary_correct_size() {
93+
Ed25519Extended::secret_from_binary(&vec![0; EXTENDED_KEY_SIZE]).unwrap();
8194
}
8295

83-
#[quickcheck]
84-
fn sign_ko(input: (KeyPair<Ed25519Extended>, KeyPair<Ed25519Extended>, Vec<u8>)) -> bool {
85-
keypair_signing_ko(input)
96+
#[test]
97+
fn secret_from_binary_empty_slice() {
98+
assert!(matches!(
99+
Ed25519Extended::secret_from_binary(&[]),
100+
Err(SecretKeyError::SizeInvalid)
101+
))
86102
}
87103

88-
#[quickcheck]
89-
/// `secret_from_binary` should fail if the provided byte array does not match the public key size
90-
fn secret_from_binary_size_check(n: usize) {
104+
// `secret_from_binary` should fail if the provided byte array does not match the public key size
105+
#[proptest]
106+
fn secret_from_binary_size_check(#[strategy(..EXTENDED_KEY_SIZE * 10)] n: usize) {
91107
let secret_key = Ed25519Extended::secret_from_binary(&vec![0; n]);
92108

93-
assert_eq!(
109+
prop_assert_eq!(
94110
n != EXTENDED_KEY_SIZE,
95-
matches!(secret_key, Err(SecretKeyError::SizeInvalid { .. }))
111+
matches!(secret_key, Err(SecretKeyError::SizeInvalid))
96112
);
97113
}
98114
}

chain-crypto/src/algorithms/sumed25519/common.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ use ed25519_dalek as ed25519;
44
pub struct Hash([u8; 32]);
55

66
#[derive(Debug, Clone, PartialEq, Eq)]
7+
#[cfg_attr(
8+
any(test, feature = "property-test-api"),
9+
derive(test_strategy::Arbitrary)
10+
)]
711
pub struct Seed([u8; 32]);
812

913
impl AsRef<[u8]> for Seed {
@@ -36,7 +40,19 @@ impl Seed {
3640
}
3741

3842
#[derive(Debug, Copy, Clone)]
39-
pub struct Depth(pub usize);
43+
#[cfg_attr(
44+
any(test, feature = "property-test-api"),
45+
derive(test_strategy::Arbitrary)
46+
)]
47+
pub struct Depth(
48+
// a bigger range here would result into unreasobable testing times and
49+
// possible segfaults due to excessive allocations
50+
#[cfg_attr(
51+
any(test, feature = "property-test-api"),
52+
strategy(..10usize)
53+
)]
54+
pub usize,
55+
);
4056

4157
impl Depth {
4258
pub fn total(self) -> usize {

chain-crypto/src/algorithms/sumed25519/mod.rs

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -120,28 +120,56 @@ impl KeyEvolvingSignatureAlgorithm for SumEd25519_12 {
120120
mod tests {
121121
use super::*;
122122

123-
#[quickcheck]
124-
/// `public_from_binary`should fail if the provided byte array does not match the public key size
125-
fn public_from_binary_size_check(n: usize) {
123+
use proptest::prelude::*;
124+
use test_strategy::proptest;
125+
126+
#[test]
127+
fn public_from_binary_correct_size() {
128+
SumEd25519_12::public_from_binary(&vec![0; SumEd25519_12::PUBLIC_KEY_SIZE]).unwrap();
129+
}
130+
131+
#[test]
132+
fn public_from_binary_empty_slice() {
133+
assert!(matches!(
134+
SumEd25519_12::public_from_binary(&[]),
135+
Err(PublicKeyError::SizeInvalid)
136+
))
137+
}
138+
139+
// `secret_from_binary` should fail if the provided byte array does not match the public key size
140+
#[proptest]
141+
fn public_from_binary_size_check(#[strategy(..SumEd25519_12::PUBLIC_KEY_SIZE * 10)] n: usize) {
126142
let public_key = SumEd25519_12::public_from_binary(&vec![0; n]);
127143

128-
assert_eq!(
144+
prop_assert_eq!(
129145
n != SumEd25519_12::PUBLIC_KEY_SIZE,
130-
public_key == Err(PublicKeyError::SizeInvalid)
146+
matches!(public_key, Err(PublicKeyError::SizeInvalid))
131147
);
132148
}
133149

134-
#[quickcheck]
135-
/// `signature_from_bytes` should fail if the provided byte array does not match the public key size
136-
fn signature_from_bytes_size_check(n: usize) {
137-
let verification_algorithm = SumEd25519_12::signature_from_bytes(&vec![0; n]);
150+
#[test]
151+
fn signature_from_binary_correct_size() {
152+
SumEd25519_12::signature_from_bytes(&vec![0; SumEd25519_12::SIGNATURE_SIZE]).unwrap();
153+
}
154+
155+
#[test]
156+
fn signature_from_binary_empty_slice() {
157+
assert!(matches!(
158+
SumEd25519_12::signature_from_bytes(&[]),
159+
Err(SignatureError::SizeInvalid { .. })
160+
))
161+
}
162+
163+
// `secret_from_binary` should fail if the provided byte array does not match the public key size
164+
#[proptest]
165+
fn signature_from_binary_size_check(
166+
#[strategy(..SumEd25519_12::SIGNATURE_SIZE * 10)] n: usize,
167+
) {
168+
let signature = SumEd25519_12::signature_from_bytes(&vec![0; n]);
138169

139-
assert_eq!(
170+
prop_assert_eq!(
140171
n != SumEd25519_12::SIGNATURE_SIZE,
141-
matches!(
142-
verification_algorithm,
143-
Err(SignatureError::SizeInvalid { .. })
144-
)
172+
matches!(signature, Err(SignatureError::SizeInvalid { .. }))
145173
);
146174
}
147175
}

chain-crypto/src/algorithms/sumed25519/sum.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -681,10 +681,14 @@ pub fn update(secret: &mut SecretKey) -> Result<(), Error> {
681681

682682
#[cfg(test)]
683683
mod tests {
684+
use super::super::sumrec;
684685
use super::*;
685686

686-
use super::super::sumrec;
687+
use proptest::prelude::*;
688+
use test_strategy::proptest;
689+
687690
use quickcheck::{Arbitrary, Gen};
691+
688692
impl Arbitrary for Seed {
689693
fn arbitrary<G: Gen>(g: &mut G) -> Self {
690694
let mut b = [0u8; 32];
@@ -782,28 +786,28 @@ mod tests {
782786
}
783787
}
784788

785-
#[quickcheck]
786-
fn check_public(depth: Depth, seed: Seed) -> bool {
789+
#[proptest]
790+
fn check_public(depth: Depth, seed: Seed) {
787791
let (_, pk) = keygen(depth, &seed);
788792
let pk_pub = pkeygen(depth, &seed);
789-
pk == pk_pub
793+
prop_assert_eq!(pk, pk_pub);
790794
}
791795

792-
#[quickcheck]
793-
fn check_sig(depth: Depth, seed: Seed) -> bool {
796+
#[proptest]
797+
fn check_sig(depth: Depth, seed: Seed) {
794798
let (sk, pk) = keygen(depth, &seed);
795799

796800
let m = b"Arbitrary message";
797801

798802
let sig = sign(&sk, m);
799-
verify(&pk, m, &sig)
803+
prop_assert!(verify(&pk, m, &sig));
800804
}
801805

802-
#[quickcheck]
803-
fn check_recver_equivalent(depth: Depth, seed: Seed) -> bool {
806+
#[proptest]
807+
fn check_recver_equivalent(depth: Depth, seed: Seed) {
804808
let (_, pk) = keygen(depth, &seed);
805809

806810
let (_, pkrec) = sumrec::keygen(depth, &seed);
807-
pk.as_bytes() == pkrec.as_bytes()
811+
prop_assert_eq!(pk.as_bytes(), pkrec.as_bytes());
808812
}
809813
}

chain-crypto/src/algorithms/vrf/mod.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,14 +89,30 @@ impl VerifiableRandomFunction for RistrettoGroup2HashDh {
8989
mod tests {
9090
use super::*;
9191

92-
#[quickcheck]
93-
/// `secret_from_binary` should fail if the provided byte array does not match the public key size
94-
fn secret_from_binary_size_check(n: usize) {
92+
use proptest::prelude::*;
93+
use test_strategy::proptest;
94+
95+
#[test]
96+
fn secret_from_binary_correct_size() {
97+
RistrettoGroup2HashDh::secret_from_binary(&vec![0; vrf::SecretKey::BYTES_LEN]).unwrap();
98+
}
99+
100+
#[test]
101+
fn secret_from_binary_empty_slice() {
102+
assert!(matches!(
103+
RistrettoGroup2HashDh::secret_from_binary(&[]),
104+
Err(SecretKeyError::SizeInvalid)
105+
))
106+
}
107+
108+
// `secret_from_binary` should fail if the provided byte array does not match the public key size
109+
#[proptest]
110+
fn secret_from_binary_size_check(#[strategy(..vrf::SecretKey::BYTES_LEN * 10)] n: usize) {
95111
let secret_key = RistrettoGroup2HashDh::secret_from_binary(&vec![0; n]);
96112

97-
assert_eq!(
113+
prop_assert_eq!(
98114
n != vrf::SecretKey::BYTES_LEN,
99-
secret_key == Err(SecretKeyError::SizeInvalid)
115+
matches!(secret_key, Err(SecretKeyError::SizeInvalid))
100116
);
101117
}
102118
}

0 commit comments

Comments
 (0)