mithril_stm/protocol/key_registration/
registration_entry.rs1use std::cmp::Ordering;
2use std::hash::Hash;
3
4use serde::{Deserialize, Serialize};
5
6#[cfg(feature = "future_snark")]
7use crate::VerificationKeyForSnark;
8use crate::{
9 Initializer, RegisterError, Stake, StmResult, VerificationKeyForConcatenation,
10 VerificationKeyProofOfPossessionForConcatenation,
11};
12
13use super::ClosedRegistrationEntry;
14
15#[derive(PartialEq, Eq, Clone, Debug, Copy, Serialize, Deserialize)]
17pub struct RegistrationEntry(
18 VerificationKeyForConcatenation,
19 Stake,
20 #[cfg(feature = "future_snark")]
21 #[serde(skip_serializing_if = "Option::is_none")]
22 Option<VerificationKeyForSnark>,
23);
24
25impl RegistrationEntry {
26 pub fn new(
29 bls_verification_key_proof_of_possession: VerificationKeyProofOfPossessionForConcatenation,
30 stake: Stake,
31 #[cfg(feature = "future_snark")] schnorr_verification_key: Option<VerificationKeyForSnark>,
32 ) -> StmResult<Self> {
33 bls_verification_key_proof_of_possession
34 .verify_proof_of_possession()
35 .map_err(|_| {
36 RegisterError::ConcatenationKeyInvalid(Box::new(
37 bls_verification_key_proof_of_possession.vk,
38 ))
39 })?;
40
41 #[cfg(feature = "future_snark")]
42 schnorr_verification_key
43 .map(|schnorr_vk| {
44 schnorr_vk
45 .is_valid()
46 .map_err(|_| RegisterError::SnarkKeyInvalid(Box::new(schnorr_vk)))
47 })
48 .transpose()?;
49
50 Ok(RegistrationEntry(
51 bls_verification_key_proof_of_possession.vk,
52 stake,
53 #[cfg(feature = "future_snark")]
54 schnorr_verification_key,
55 ))
56 }
57
58 pub fn get_verification_key_for_concatenation(&self) -> VerificationKeyForConcatenation {
60 self.0
61 }
62
63 #[cfg(feature = "future_snark")]
64 pub fn get_verification_key_for_snark(&self) -> Option<VerificationKeyForSnark> {
66 self.2
67 }
68
69 pub fn get_stake(&self) -> Stake {
71 self.1
72 }
73}
74
75impl From<ClosedRegistrationEntry> for RegistrationEntry {
76 fn from(entry: ClosedRegistrationEntry) -> Self {
77 RegistrationEntry(
78 entry.get_verification_key_for_concatenation(),
79 entry.get_stake(),
80 #[cfg(feature = "future_snark")]
81 entry.get_verification_key_for_snark(),
82 )
83 }
84}
85
86impl From<Initializer> for RegistrationEntry {
87 fn from(initializer: Initializer) -> Self {
88 Self(
89 initializer.bls_verification_key_proof_of_possession.vk,
90 initializer.stake,
91 #[cfg(feature = "future_snark")]
92 initializer.schnorr_verification_key,
93 )
94 }
95}
96
97impl Hash for RegistrationEntry {
98 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
100 self.1.hash(state);
101 self.0.hash(state);
102 #[cfg(feature = "future_snark")]
103 self.2.hash(state);
104 }
105
106 fn hash_slice<H: std::hash::Hasher>(data: &[Self], state: &mut H)
107 where
108 Self: Sized,
109 {
110 for piece in data {
111 piece.hash(state)
112 }
113 }
114}
115
116impl PartialOrd for RegistrationEntry {
117 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
118 Some(std::cmp::Ord::cmp(self, other))
119 }
120}
121
122impl Ord for RegistrationEntry {
123 fn cmp(&self, other: &Self) -> Ordering {
125 self.1.cmp(&other.1).then(self.0.cmp(&other.0))
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use rand_chacha::ChaCha20Rng;
132 use rand_core::SeedableRng;
133 use std::cmp::Ordering;
134
135 use crate::{
136 VerificationKeyProofOfPossessionForConcatenation, signature_scheme::BlsSigningKey,
137 };
138
139 #[cfg(feature = "future_snark")]
140 use crate::{VerificationKeyForSnark, signature_scheme::SchnorrSigningKey};
141
142 use super::*;
143
144 fn create_registration_entry(rng: &mut ChaCha20Rng, stake: Stake) -> RegistrationEntry {
145 let bls_sk = BlsSigningKey::generate(rng);
146 let bls_pk = VerificationKeyProofOfPossessionForConcatenation::from(&bls_sk);
147
148 #[cfg(feature = "future_snark")]
149 let schnorr_verification_key = {
150 let sk = SchnorrSigningKey::generate(rng);
151 VerificationKeyForSnark::new_from_signing_key(sk)
152 };
153 RegistrationEntry::new(
154 bls_pk,
155 stake,
156 #[cfg(feature = "future_snark")]
157 Some(schnorr_verification_key),
158 )
159 .unwrap()
160 }
161
162 #[test]
163 fn test_ord_different_stakes() {
164 let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
165
166 let entry_low_stake = create_registration_entry(&mut rng, 100);
167 let entry_high_stake = create_registration_entry(&mut rng, 200);
168
169 assert_eq!(entry_low_stake.cmp(&entry_high_stake), Ordering::Less);
170 assert_eq!(entry_high_stake.cmp(&entry_low_stake), Ordering::Greater);
171 }
172
173 #[test]
174 fn test_ord_same_stake_different_keys() {
175 let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
176
177 let entry1 = create_registration_entry(&mut rng, 100);
178 let entry2 = create_registration_entry(&mut rng, 100);
179
180 let cmp_result = entry1.cmp(&entry2);
181 assert!(cmp_result == Ordering::Less || cmp_result == Ordering::Greater);
182
183 assert_eq!(entry2.cmp(&entry1), cmp_result.reverse());
184 }
185}