Skip to content

Commit c21fa2c

Browse files
committed
errors improved, tests added
1 parent 3b0d759 commit c21fa2c

File tree

9 files changed

+291
-156
lines changed

9 files changed

+291
-156
lines changed

mithril-stm/benches/schnorr_sig.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ fn sign_and_verify(c: &mut Criterion, nr_sigs: usize) {
4646
let mut sigs = Vec::new();
4747
for _ in 0..nr_sigs {
4848
let sk = SchnorrSigningKey::generate(&mut rng).unwrap();
49-
let vk = SchnorrVerificationKey::from(sk.clone());
49+
let vk = SchnorrVerificationKey::new_from_signing_key(sk.clone()).unwrap();
5050
let sig = sk.sign(&msg, &mut rng_sig).unwrap();
5151
sigs.push(sig);
5252
mvks.push(vk);

mithril-stm/src/signature_scheme/schnorr_signature/error.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,31 @@ pub enum SchnorrSignatureError {
1313
#[error("Invalid bytes")]
1414
SerializationError,
1515

16+
/// This error occurs when the serialization of the signing key bytes failed
17+
#[error("Invalid scalar field element bytes")]
18+
ScalarFieldElementSerializationError,
19+
20+
/// This error occurs when the serialization of the projective point bytes failed
21+
#[error("Invalid projective point bytes")]
22+
ProjectivePointSerializationError,
23+
24+
/// This error occurs when the serialization of the prime order projective point bytes failed
25+
#[error("Invalid prime order projective point bytes")]
26+
PrimeOrderProjectivePointSerializationError,
27+
1628
/// This error occurs when the random scalar fails to generate during the signature
1729
#[error("Failed generation of the signature's random scalar")]
1830
RandomScalarGenerationError,
1931

32+
/// This error occurs when signing key is zero or one.
33+
#[error("The signing key is invalid.")]
34+
InvalidSigningKey,
35+
2036
/// Given point is not on the curve
2137
#[error("Given point is not on the curve")]
2238
PointIsNotOnCurve(Box<PrimeOrderProjectivePoint>),
39+
40+
/// Given point is not prime order
41+
#[error("Given point is not prime order")]
42+
PointIsNotPrimeOrder(Box<PrimeOrderProjectivePoint>),
2343
}

mithril-stm/src/signature_scheme/schnorr_signature/jubjub_wrapper/curve_points.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use super::{BaseFieldElement, ScalarFieldElement};
99
use crate::{StmResult, signature_scheme::SchnorrSignatureError};
1010

1111
#[derive(Clone)]
12-
pub struct AffinePoint(JubjubAffinePoint);
12+
pub(crate) struct AffinePoint(JubjubAffinePoint);
1313

1414
impl AffinePoint {
1515
pub(crate) fn from_projective_point(projective_point: ProjectivePoint) -> Self {
@@ -34,7 +34,7 @@ impl AffinePoint {
3434
}
3535

3636
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37-
pub struct ProjectivePoint(pub(crate) JubjubExtended);
37+
pub(crate) struct ProjectivePoint(pub(crate) JubjubExtended);
3838

3939
impl ProjectivePoint {
4040
pub(crate) fn hash_to_projective_point(input: &[u8]) -> Self {
@@ -60,7 +60,9 @@ impl ProjectivePoint {
6060

6161
match JubjubExtended::from_bytes(&projective_point_bytes).into_option() {
6262
Some(projective_point) => Ok(Self(projective_point)),
63-
None => Err(anyhow!(SchnorrSignatureError::SerializationError)),
63+
None => Err(anyhow!(
64+
SchnorrSignatureError::ProjectivePointSerializationError
65+
)),
6466
}
6567
}
6668

@@ -69,10 +71,14 @@ impl ProjectivePoint {
6971
) -> Self {
7072
ProjectivePoint(JubjubExtended::from(prime_order_projective_point.0))
7173
}
74+
75+
pub(crate) fn is_prime_order(self) -> bool {
76+
self.0.is_prime_order().into()
77+
}
7278
}
7379

7480
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
75-
pub struct PrimeOrderProjectivePoint(pub(crate) JubjubSubgroup);
81+
pub(crate) struct PrimeOrderProjectivePoint(pub(crate) JubjubSubgroup);
7682

7783
impl PrimeOrderProjectivePoint {
7884
pub(crate) fn create_generator() -> Self {
@@ -98,7 +104,9 @@ impl PrimeOrderProjectivePoint {
98104

99105
match JubjubSubgroup::from_bytes(&prime_order_projective_point_bytes).into_option() {
100106
Some(prime_order_projective_point) => Ok(Self(prime_order_projective_point)),
101-
None => Err(anyhow!(SchnorrSignatureError::SerializationError)),
107+
None => Err(anyhow!(
108+
SchnorrSignatureError::PrimeOrderProjectivePointSerializationError
109+
)),
102110
}
103111
}
104112
}

mithril-stm/src/signature_scheme/schnorr_signature/jubjub_wrapper/field_elements.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rand_core::{CryptoRng, RngCore};
66
use crate::{StmResult, signature_scheme::SchnorrSignatureError};
77

88
#[derive(Debug, Clone, PartialEq, Eq)]
9-
pub struct BaseFieldElement(pub(crate) JubjubBase);
9+
pub(crate) struct BaseFieldElement(pub(crate) JubjubBase);
1010

1111
impl BaseFieldElement {
1212
pub(crate) fn add(&self, other: &Self) -> Self {
@@ -31,7 +31,7 @@ impl BaseFieldElement {
3131
}
3232

3333
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34-
pub struct ScalarFieldElement(pub(crate) JubjubScalar);
34+
pub(crate) struct ScalarFieldElement(pub(crate) JubjubScalar);
3535

3636
impl ScalarFieldElement {
3737
pub(crate) fn new_random_scalar(rng: &mut (impl RngCore + CryptoRng)) -> Self {
@@ -45,6 +45,13 @@ impl ScalarFieldElement {
4545
false
4646
}
4747

48+
pub(crate) fn is_one(&self) -> bool {
49+
if self.0 == JubjubScalar::one() {
50+
return true;
51+
}
52+
false
53+
}
54+
4855
pub(crate) fn new_random_nonzero_scalar(
4956
rng: &mut (impl RngCore + CryptoRng),
5057
) -> StmResult<Self> {
@@ -71,12 +78,17 @@ impl ScalarFieldElement {
7178

7279
pub(crate) fn from_bytes(bytes: &[u8]) -> StmResult<Self> {
7380
let mut scalar_bytes = [0u8; 32];
74-
scalar_bytes
75-
.copy_from_slice(bytes.get(..32).ok_or(SchnorrSignatureError::SerializationError)?);
81+
scalar_bytes.copy_from_slice(
82+
bytes
83+
.get(..32)
84+
.ok_or(SchnorrSignatureError::ScalarFieldElementSerializationError)?,
85+
);
7686

7787
match JubjubScalar::from_bytes(&scalar_bytes).into_option() {
7888
Some(scalar_field_element) => Ok(Self(scalar_field_element)),
79-
None => Err(anyhow!(SchnorrSignatureError::SerializationError)),
89+
None => Err(anyhow!(
90+
SchnorrSignatureError::ScalarFieldElementSerializationError
91+
)),
8092
}
8193
}
8294
}

mithril-stm/src/signature_scheme/schnorr_signature/jubjub_wrapper/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ mod curve_points;
22
mod field_elements;
33
mod poseidon_digest;
44

5-
pub use curve_points::*;
6-
pub use field_elements::*;
5+
pub(crate) use curve_points::*;
6+
pub(crate) use field_elements::*;
77
pub(crate) use poseidon_digest::*;

mithril-stm/src/signature_scheme/schnorr_signature/mod.rs

Lines changed: 152 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,159 @@ mod utils;
66
mod verification_key;
77

88
pub use error::*;
9-
pub use jubjub_wrapper::*;
9+
pub(crate) use jubjub_wrapper::*;
1010
pub use signature::*;
1111
pub use signing_key::*;
1212
pub(crate) use utils::*;
1313
pub use verification_key::*;
14+
15+
#[cfg(test)]
16+
mod tests {
17+
use proptest::prelude::*;
18+
use rand_chacha::ChaCha20Rng;
19+
use rand_core::SeedableRng;
20+
21+
use crate::{SchnorrSignature, signature_scheme::SchnorrSignatureError};
22+
23+
use super::{SchnorrSigningKey, SchnorrVerificationKey};
24+
25+
proptest! {
26+
#![proptest_config(ProptestConfig::with_cases(10))]
27+
28+
#[test]
29+
fn valid_signing_verification(
30+
msg in prop::collection::vec(any::<u8>(), 1..128),
31+
seed in any::<[u8;32]>(),
32+
) {
33+
let sk_result = SchnorrSigningKey::generate(&mut ChaCha20Rng::from_seed(seed));
34+
assert!(sk_result.is_ok(), "Secret ket generation failed");
35+
let sk = sk_result.unwrap();
36+
37+
let vk = SchnorrVerificationKey::new_from_signing_key(sk.clone()).unwrap();
38+
39+
let sig_result = sk.sign(&msg, &mut ChaCha20Rng::from_seed(seed));
40+
assert!(sig_result.is_ok(), "Signature generation failed");
41+
42+
let sig = sig_result.unwrap();
43+
44+
assert!(sig.verify(&msg, &vk).is_ok(), "Verification failed.");
45+
}
46+
47+
#[test]
48+
fn invalid_signature(msg in prop::collection::vec(any::<u8>(), 1..128), seed in any::<[u8;32]>()) {
49+
let mut rng = ChaCha20Rng::from_seed(seed);
50+
let sk1 = SchnorrSigningKey::generate(&mut rng).unwrap();
51+
let vk1 = SchnorrVerificationKey::new_from_signing_key(sk1).unwrap();
52+
let sk2 = SchnorrSigningKey::generate(&mut rng).unwrap();
53+
let fake_sig = sk2.sign(&msg, &mut rng).unwrap();
54+
55+
let error = fake_sig.verify(&msg, &vk1).expect_err("Fake signature should not be verified");
56+
57+
assert!(
58+
matches!(
59+
error.downcast_ref::<SchnorrSignatureError>(),
60+
Some(SchnorrSignatureError::SignatureInvalid(_))
61+
),
62+
"Unexpected error: {error:?}"
63+
);
64+
}
65+
66+
#[test]
67+
fn signing_key_to_from_bytes(seed in any::<[u8;32]>()) {
68+
let mut rng = ChaCha20Rng::from_seed(seed);
69+
let sk = SchnorrSigningKey::generate(&mut rng).unwrap();
70+
71+
let mut sk_bytes = sk.to_bytes();
72+
let recovered_sk = SchnorrSigningKey::from_bytes(&sk_bytes).unwrap();
73+
assert_eq!(sk.0, recovered_sk.0, "Recovered signing key does not match with the original!");
74+
75+
sk_bytes[31] |= 0xff;
76+
77+
let result = SchnorrSigningKey::from_bytes(&sk_bytes).expect_err("From bytes conversion of signing key should fail");
78+
79+
assert!(
80+
matches!(
81+
result.downcast_ref::<SchnorrSignatureError>(),
82+
Some(SchnorrSignatureError::ScalarFieldElementSerializationError)
83+
),
84+
"Unexpected error: {result:?}"
85+
);
86+
}
87+
88+
#[test]
89+
fn verification_key_to_from_bytes(seed in any::<[u8;32]>()) {
90+
let mut rng = ChaCha20Rng::from_seed(seed);
91+
let sk = SchnorrSigningKey::generate(&mut rng).unwrap();
92+
let vk = SchnorrVerificationKey::new_from_signing_key(sk.clone()).unwrap();
93+
94+
let mut vk_bytes = vk.to_bytes();
95+
let recovered_vk = SchnorrVerificationKey::from_bytes(&vk_bytes).unwrap();
96+
assert_eq!(vk.0, recovered_vk.0, "Recovered verification key does not match with the original!");
97+
98+
vk_bytes[31] |= 0xff;
99+
100+
let result = SchnorrVerificationKey::from_bytes(&vk_bytes).expect_err("From bytes conversion of verification key should fail");
101+
102+
assert!(
103+
matches!(
104+
result.downcast_ref::<SchnorrSignatureError>(),
105+
Some(SchnorrSignatureError::PrimeOrderProjectivePointSerializationError)
106+
),
107+
"Unexpected error: {result:?}"
108+
);
109+
}
110+
111+
#[test]
112+
fn signature_to_from_bytes(msg in prop::collection::vec(any::<u8>(), 1..128), seed in any::<[u8;32]>()) {
113+
let mut rng = ChaCha20Rng::from_seed(seed);
114+
115+
let sk = SchnorrSigningKey::generate(&mut rng).unwrap();
116+
let signature = sk.sign(&msg, &mut ChaCha20Rng::from_seed(seed)).unwrap();
117+
118+
let signature_bytes = signature.to_bytes();
119+
let recovered_signature = SchnorrSignature::from_bytes(&signature_bytes).unwrap();
120+
assert_eq!(signature, recovered_signature, "Recovered signature does not match with the original!");
121+
122+
// Test invalid `sigma`
123+
let mut corrupted_bytes = signature_bytes.clone();
124+
corrupted_bytes[31] |= 0xff;
125+
126+
let result = SchnorrSignature::from_bytes(&corrupted_bytes).expect_err("From bytes conversion of signature should fail");
127+
128+
assert!(
129+
matches!(
130+
result.downcast_ref::<SchnorrSignatureError>(),
131+
Some(SchnorrSignatureError::ProjectivePointSerializationError)
132+
),
133+
"Unexpected error: {result:?}"
134+
);
135+
136+
// Test invalid `signature`
137+
let mut corrupted_bytes = signature_bytes.clone();
138+
corrupted_bytes[63] |= 0xff;
139+
140+
let result = SchnorrSignature::from_bytes(&corrupted_bytes).expect_err("From bytes conversion should fail");
141+
142+
assert!(
143+
matches!(
144+
result.downcast_ref::<SchnorrSignatureError>(),
145+
Some(SchnorrSignatureError::ScalarFieldElementSerializationError)
146+
),
147+
"Unexpected error: {result:?}"
148+
);
149+
// Test invalid `challenge`
150+
let mut corrupted_bytes = signature_bytes.clone();
151+
corrupted_bytes[95] |= 0xff;
152+
153+
let result = SchnorrSignature::from_bytes(&corrupted_bytes).expect_err("From bytes conversion should fail");
154+
155+
assert!(
156+
matches!(
157+
result.downcast_ref::<SchnorrSignatureError>(),
158+
Some(SchnorrSignatureError::ScalarFieldElementSerializationError)
159+
),
160+
"Unexpected error: {result:?}"
161+
);
162+
}
163+
}
164+
}

0 commit comments

Comments
 (0)