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 TryFrom<Initializer> for RegistrationEntry {
87 type Error = anyhow::Error;
88
89 fn try_from(initializer: Initializer) -> StmResult<Self> {
90 Self::new(
91 initializer.bls_verification_key_proof_of_possession,
92 initializer.stake,
93 #[cfg(feature = "future_snark")]
94 initializer.schnorr_verification_key,
95 )
96 }
97}
98
99impl Hash for RegistrationEntry {
100 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
102 self.1.hash(state);
103 self.0.hash(state);
104 #[cfg(feature = "future_snark")]
105 self.2.hash(state);
106 }
107
108 fn hash_slice<H: std::hash::Hasher>(data: &[Self], state: &mut H)
109 where
110 Self: Sized,
111 {
112 for piece in data {
113 piece.hash(state)
114 }
115 }
116}
117
118impl PartialOrd for RegistrationEntry {
119 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
120 Some(std::cmp::Ord::cmp(self, other))
121 }
122}
123
124impl Ord for RegistrationEntry {
125 fn cmp(&self, other: &Self) -> Ordering {
127 self.1.cmp(&other.1).then(self.0.cmp(&other.0))
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use rand_chacha::ChaCha20Rng;
134 use rand_core::SeedableRng;
135 use std::cmp::Ordering;
136
137 use crate::{
138 VerificationKeyProofOfPossessionForConcatenation, signature_scheme::BlsSigningKey,
139 };
140
141 #[cfg(feature = "future_snark")]
142 use crate::{VerificationKeyForSnark, signature_scheme::SchnorrSigningKey};
143
144 use super::*;
145
146 fn create_registration_entry(rng: &mut ChaCha20Rng, stake: Stake) -> RegistrationEntry {
147 let bls_sk = BlsSigningKey::generate(rng);
148 let bls_pk = VerificationKeyProofOfPossessionForConcatenation::from(&bls_sk);
149
150 #[cfg(feature = "future_snark")]
151 let schnorr_verification_key = {
152 let sk = SchnorrSigningKey::generate(rng);
153 VerificationKeyForSnark::new_from_signing_key(sk)
154 };
155 RegistrationEntry::new(
156 bls_pk,
157 stake,
158 #[cfg(feature = "future_snark")]
159 Some(schnorr_verification_key),
160 )
161 .unwrap()
162 }
163
164 #[test]
165 fn test_ord_different_stakes() {
166 let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
167
168 let entry_low_stake = create_registration_entry(&mut rng, 100);
169 let entry_high_stake = create_registration_entry(&mut rng, 200);
170
171 assert_eq!(entry_low_stake.cmp(&entry_high_stake), Ordering::Less);
172 assert_eq!(entry_high_stake.cmp(&entry_low_stake), Ordering::Greater);
173 }
174
175 #[test]
176 fn test_ord_same_stake_different_keys() {
177 let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
178
179 let entry1 = create_registration_entry(&mut rng, 100);
180 let entry2 = create_registration_entry(&mut rng, 100);
181
182 let cmp_result = entry1.cmp(&entry2);
183 assert!(cmp_result == Ordering::Less || cmp_result == Ordering::Greater);
184
185 assert_eq!(entry2.cmp(&entry1), cmp_result.reverse());
186 }
187}