mithril_stm/signature_scheme/unique_schnorr_signature/
verification_key.rs1use anyhow::{Context, Ok, anyhow};
2use serde::{Deserialize, Serialize};
3
4use super::{
5 PrimeOrderProjectivePoint, ProjectivePoint, SchnorrSigningKey, UniqueSchnorrSignatureError,
6};
7use crate::StmResult;
8
9#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
12pub struct SchnorrVerificationKey(pub(crate) PrimeOrderProjectivePoint);
13
14impl SchnorrVerificationKey {
15 pub fn new_from_signing_key(signing_key: SchnorrSigningKey) -> StmResult<Self> {
20 if signing_key.0.is_zero() | signing_key.0.is_one() {
21 return Err(anyhow!(UniqueSchnorrSignatureError::InvalidSigningKey))
22 .with_context(|| "Verification key generation failed.");
23 }
24 let generator = PrimeOrderProjectivePoint::create_generator();
25
26 Ok(SchnorrVerificationKey(signing_key.0 * generator))
27 }
28
29 pub fn is_valid(&self) -> StmResult<Self> {
30 let projective_point = ProjectivePoint::from(self.0);
31 if !projective_point.is_prime_order() {
32 return Err(anyhow!(UniqueSchnorrSignatureError::PointIsNotPrimeOrder(
33 Box::new(self.0)
34 )));
35 }
36 self.0.is_on_curve()?;
37
38 Ok(*self)
39 }
40
41 pub fn to_bytes(self) -> [u8; 32] {
43 self.0.to_bytes()
44 }
45
46 pub fn from_bytes(bytes: &[u8]) -> StmResult<Self> {
50 if bytes.len() < 32 {
51 return Err(anyhow!(UniqueSchnorrSignatureError::Serialization)).with_context(
52 || "Not enough bytes provided to construct a Schnorr verification key.",
53 );
54 }
55 let prime_order_projective_point = PrimeOrderProjectivePoint::from_bytes(bytes)
56 .with_context(|| "Cannot construct Schnorr verification key from given bytes.")?;
57
58 Ok(SchnorrVerificationKey(prime_order_projective_point))
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use rand_chacha::ChaCha20Rng;
65 use rand_core::SeedableRng;
66
67 use crate::signature_scheme::{SchnorrSigningKey, SchnorrVerificationKey};
68
69 #[test]
70 fn create_verification_key_from_signing_key() {
71 let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
72 let sk = SchnorrSigningKey::generate(&mut rng).unwrap();
73
74 let vk = SchnorrVerificationKey::new_from_signing_key(sk);
75
76 assert!(
77 vk.is_ok(),
78 "Verification key creation should succeed for valid signing key"
79 );
80 }
81
82 #[test]
83 fn different_signing_keys_produce_different_verification_keys() {
84 let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
85 let sk1 = SchnorrSigningKey::generate(&mut rng).unwrap();
86 let sk2 = SchnorrSigningKey::generate(&mut rng).unwrap();
87
88 let vk1 = SchnorrVerificationKey::new_from_signing_key(sk1).unwrap();
89 let vk2 = SchnorrVerificationKey::new_from_signing_key(sk2).unwrap();
90
91 assert_ne!(
92 vk1, vk2,
93 "Different signing keys should produce different verification keys"
94 );
95 }
96
97 #[test]
98 fn same_signing_key_produces_same_verification_key() {
99 let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
100 let sk = SchnorrSigningKey::generate(&mut rng).unwrap();
101
102 let vk1 = SchnorrVerificationKey::new_from_signing_key(sk.clone()).unwrap();
103 let vk2 = SchnorrVerificationKey::new_from_signing_key(sk).unwrap();
104
105 assert_eq!(
106 vk1, vk2,
107 "Same signing key should produce same verification key"
108 );
109 }
110
111 #[test]
112 fn valid_verification_key_passes_validation() {
113 let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
114 let sk = SchnorrSigningKey::generate(&mut rng).unwrap();
115 let vk = SchnorrVerificationKey::new_from_signing_key(sk).unwrap();
116
117 let result = vk.is_valid();
118
119 assert!(
120 result.is_ok(),
121 "Valid verification key should pass validation"
122 );
123 }
124
125 #[test]
126 fn from_bytes_not_enough_bytes() {
127 let bytes = vec![0u8; 31];
128 let result = SchnorrVerificationKey::from_bytes(&bytes);
129
130 result.expect_err("Should fail with insufficient bytes");
131 }
132
133 #[test]
134 fn from_bytes_exact_size() {
135 let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
136 let sk = SchnorrSigningKey::generate(&mut rng).unwrap();
137 let vk = SchnorrVerificationKey::new_from_signing_key(sk).unwrap();
138 let vk_bytes = vk.to_bytes();
139
140 let vk_restored = SchnorrVerificationKey::from_bytes(&vk_bytes).unwrap();
141
142 assert_eq!(vk, vk_restored);
143 }
144
145 #[test]
146 fn from_bytes_extra_bytes() {
147 let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
148 let sk = SchnorrSigningKey::generate(&mut rng).unwrap();
149 let vk = SchnorrVerificationKey::new_from_signing_key(sk).unwrap();
150 let vk_bytes = vk.to_bytes();
151
152 let mut extended_bytes = vk_bytes.to_vec();
153 extended_bytes.extend_from_slice(&[0xFF; 10]);
154
155 let vk_restored = SchnorrVerificationKey::from_bytes(&extended_bytes).unwrap();
156
157 assert_eq!(vk, vk_restored);
158 }
159
160 #[test]
161 fn to_bytes_is_deterministic() {
162 let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
163 let sk = SchnorrSigningKey::generate(&mut rng).unwrap();
164 let vk = SchnorrVerificationKey::new_from_signing_key(sk).unwrap();
165
166 let bytes1 = vk.to_bytes();
167 let bytes2 = vk.to_bytes();
168
169 assert_eq!(bytes1, bytes2, "to_bytes should be deterministic");
170 }
171
172 mod golden {
173 use super::*;
174
175 const GOLDEN_BYTES: &[u8; 32] = &[
176 144, 52, 95, 161, 127, 253, 49, 32, 140, 217, 231, 207, 32, 238, 244, 196, 97, 241, 47,
177 95, 101, 9, 70, 136, 194, 66, 187, 253, 200, 32, 218, 43,
178 ];
179
180 fn golden_value() -> SchnorrVerificationKey {
181 let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
182 let sk = SchnorrSigningKey::generate(&mut rng).unwrap();
183 SchnorrVerificationKey::new_from_signing_key(sk).unwrap()
184 }
185
186 #[test]
187 fn golden_conversions() {
188 let value = SchnorrVerificationKey::from_bytes(GOLDEN_BYTES)
189 .expect("This from bytes should not fail");
190 assert_eq!(golden_value(), value);
191
192 let serialized = SchnorrVerificationKey::to_bytes(value);
193 let golden_serialized = SchnorrVerificationKey::to_bytes(golden_value());
194 assert_eq!(golden_serialized, serialized);
195 }
196 }
197
198 mod golden_json {
199 use super::*;
200
201 const GOLDEN_JSON: &str = r#"[144, 52, 95, 161, 127, 253, 49, 32, 140, 217, 231, 207, 32, 238, 244, 196, 97, 241, 47, 95, 101, 9, 70, 136, 194, 66, 187, 253, 200, 32, 218, 43]"#;
202
203 fn golden_value() -> SchnorrVerificationKey {
204 let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
205 let sk = SchnorrSigningKey::generate(&mut rng).unwrap();
206 SchnorrVerificationKey::new_from_signing_key(sk).unwrap()
207 }
208
209 #[test]
210 fn golden_conversions() {
211 let value = serde_json::from_str(GOLDEN_JSON)
212 .expect("This JSON deserialization should not fail");
213 assert_eq!(golden_value(), value);
214
215 let serialized =
216 serde_json::to_string(&value).expect("This JSON serialization should not fail");
217 let golden_serialized = serde_json::to_string(&golden_value())
218 .expect("This JSON serialization should not fail");
219 assert_eq!(golden_serialized, serialized);
220 }
221 }
222}