mithril_stm/signature_scheme/schnorr_signature/
verification_key.rs1use anyhow::{Context, anyhow};
2use dusk_jubjub::SubgroupPoint as JubjubSubgroup;
3use group::{Group, GroupEncoding};
4
5use super::SchnorrSignatureError;
6use crate::StmResult;
7
8#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
11pub struct SchnorrVerificationKey(pub(crate) JubjubSubgroup);
12
13impl SchnorrVerificationKey {
14 pub fn to_bytes(self) -> [u8; 32] {
16 self.0.to_bytes()
17 }
18
19 pub fn from_bytes(bytes: &[u8]) -> StmResult<Self> {
23 if bytes.len() < 32 {
24 return Err(anyhow!(SchnorrSignatureError::SerializationError)).with_context(
25 || "Not enough bytes provided to create a Schnorr verification key.",
26 );
27 }
28 let verification_key_bytes = bytes[0..32]
29 .try_into()
30 .map_err(|_| anyhow!(SchnorrSignatureError::SerializationError))
31 .with_context(|| "Failed to obtain the Schnorr verification key's bytes.")?;
32 let point = JubjubSubgroup::from_bytes(&verification_key_bytes)
33 .into_option()
34 .ok_or(anyhow!(SchnorrSignatureError::SerializationError))
35 .with_context(|| "Failed to create a JubjubSubgroup point from the given bytes.")?;
36
37 Ok(SchnorrVerificationKey(point))
38 }
39}
40
41impl From<&crate::SchnorrSigningKey> for SchnorrVerificationKey {
42 fn from(signing_key: &crate::SchnorrSigningKey) -> Self {
47 let generator = JubjubSubgroup::generator();
48
49 SchnorrVerificationKey(generator * signing_key.0)
50 }
51}
52
53#[cfg(test)]
54mod tests {
55
56 use dusk_jubjub::Fq as JubjubBase;
57 use dusk_jubjub::SubgroupPoint as JubjubSubgroup;
58 use ff::Field;
59 use group::Group;
60 use rand_chacha::ChaCha20Rng;
61 use rand_core::SeedableRng;
62
63 use crate::signature_scheme::{SchnorrSigningKey, SchnorrVerificationKey};
64
65 #[test]
66 fn generate_verification_key() {
67 let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
68 let sk = SchnorrSigningKey::try_generate(&mut rng).unwrap();
69 let g = JubjubSubgroup::generator();
70 let vk = g * sk.0;
71
72 let vk_from_sk = SchnorrVerificationKey::from(&sk);
73
74 assert_eq!(vk, vk_from_sk.0);
75 }
76
77 #[test]
78 fn verify_fail_verification_key_not_on_curve() {
79 let msg = vec![0, 0, 0, 1];
80 let seed = [0u8; 32];
81 let mut rng = ChaCha20Rng::from_seed(seed);
82 let sk = SchnorrSigningKey::try_generate(&mut rng).unwrap();
83 let vk1 = SchnorrVerificationKey::from(&sk);
84 let sig = sk.sign(&msg, &mut rng).unwrap();
85 let vk2 = SchnorrVerificationKey(JubjubSubgroup::from_raw_unchecked(
86 JubjubBase::ONE,
87 JubjubBase::ONE,
88 ));
89
90 let result1 = sig.verify(&msg, &vk1);
91 let result2 = sig.verify(&msg, &vk2);
92
93 result1.expect("Correct verification key used, test should pass.");
94
95 result2.expect_err("Invalid verification key used, test should fail.");
96 }
97
98 #[test]
99 fn serialize_deserialize_vk() {
100 let seed = 0;
101 let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(seed);
102 let sk = SchnorrSigningKey::try_generate(&mut rng).unwrap();
103 let vk = SchnorrVerificationKey::from(&sk);
104
105 let vk_bytes = vk.to_bytes();
106 let vk2 = SchnorrVerificationKey::from_bytes(&vk_bytes).unwrap();
107
108 assert_eq!(vk.0, vk2.0);
109 }
110
111 mod golden {
112
113 use rand_chacha::ChaCha20Rng;
114 use rand_core::SeedableRng;
115
116 use crate::signature_scheme::{SchnorrSigningKey, SchnorrVerificationKey};
117
118 const GOLDEN_BYTES: &[u8; 32] = &[
119 144, 52, 95, 161, 127, 253, 49, 32, 140, 217, 231, 207, 32, 238, 244, 196, 97, 241, 47,
120 95, 101, 9, 70, 136, 194, 66, 187, 253, 200, 32, 218, 43,
121 ];
122
123 fn golden_value() -> SchnorrVerificationKey {
124 let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
125 let sk = SchnorrSigningKey::try_generate(&mut rng).unwrap();
126 SchnorrVerificationKey::from(&sk)
127 }
128
129 #[test]
130 fn golden_conversions() {
131 let value = SchnorrVerificationKey::from_bytes(GOLDEN_BYTES)
132 .expect("This from bytes should not fail");
133 assert_eq!(golden_value(), value);
134
135 let serialized = SchnorrVerificationKey::to_bytes(value);
136 let golden_serialized = SchnorrVerificationKey::to_bytes(golden_value());
137 assert_eq!(golden_serialized, serialized);
138 }
139 }
140}