hopr_internal_types/
protocol.rs1use hopr_crypto_random::Randomizable;
2use hopr_crypto_types::prelude::*;
3#[cfg(feature = "rayon")]
4use hopr_parallelize::cpu::rayon::prelude::*;
5use hopr_primitive_types::prelude::*;
6
7use crate::{
8 errors::{CoreTypesError, Result},
9 prelude::UnacknowledgedTicket,
10};
11
12pub const INTERMEDIATE_HOPS: usize = 3;
14
15pub const DEFAULT_MINIMUM_INCOMING_TICKET_WIN_PROB: f64 = 1.0;
17
18pub const DEFAULT_MAXIMUM_INCOMING_TICKET_WIN_PROB: f64 = 1.0; pub type HoprPseudonym = SimplePseudonym;
24
25#[derive(Copy, Clone, Debug, PartialEq, Eq)]
32#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
33pub struct Acknowledgement(#[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] [u8; Self::SIZE]);
34
35impl AsRef<[u8]> for Acknowledgement {
36 fn as_ref(&self) -> &[u8] {
37 &self.0
38 }
39}
40
41impl TryFrom<&[u8]> for Acknowledgement {
42 type Error = GeneralError;
43
44 fn try_from(value: &[u8]) -> std::result::Result<Self, Self::Error> {
45 Ok(Self(
46 value
47 .try_into()
48 .map_err(|_| GeneralError::ParseError("Acknowledgement".into()))?,
49 ))
50 }
51}
52
53impl BytesRepresentable for Acknowledgement {
54 const SIZE: usize = HalfKey::SIZE + OffchainSignature::SIZE;
55}
56
57pub const MIN_BATCH_SIZE: usize = 4; impl Acknowledgement {
61 pub fn verify(self, sender_node_key: &OffchainPublicKey) -> Result<VerifiedAcknowledgement> {
63 let signature = OffchainSignature::try_from(&self.0[HalfKey::SIZE..HalfKey::SIZE + OffchainSignature::SIZE])?;
64 if signature.verify_message(&self.0[0..HalfKey::SIZE], sender_node_key) {
65 Ok(VerifiedAcknowledgement {
66 ack_key_share: HalfKey::try_from(&self.0[0..HalfKey::SIZE])?,
67 signature,
68 })
69 } else {
70 Err(CoreTypesError::InvalidAcknowledgement)
71 }
72 }
73
74 pub fn verify_batch<I: IntoIterator<Item = (OffchainPublicKey, Self)>>(
91 acknowledgements: I,
92 ) -> Vec<Result<VerifiedAcknowledgement>> {
93 let acknowledgements = acknowledgements.into_iter();
94 let (sz_lower_bound, _) = acknowledgements.size_hint();
95
96 if sz_lower_bound < MIN_BATCH_SIZE {
98 return acknowledgements
99 .into_iter()
100 .map(|(key, ack)| ack.verify(&key))
101 .collect();
102 }
103
104 let mut optimistic_result = Vec::with_capacity(sz_lower_bound);
105 let mut keys = Vec::with_capacity(sz_lower_bound);
106
107 let optimistic_check = OffchainSignature::verify_batch(acknowledgements.filter_map(|(key, ack)| {
108 let maybe_ack_int = HalfKey::try_from(&ack.0[0..HalfKey::SIZE]).and_then(|ack_key_share| {
109 OffchainSignature::try_from(&ack.0[HalfKey::SIZE..HalfKey::SIZE + OffchainSignature::SIZE])
110 .map(|signature| (ack_key_share, signature))
111 });
112
113 match maybe_ack_int {
114 Ok((ack_key_share, signature)) => {
115 optimistic_result.push(Ok(VerifiedAcknowledgement {
116 ack_key_share,
117 signature,
118 }));
119 keys.push(Some(key)); Some(((ack_key_share, signature), key))
121 }
122 Err(err) => {
123 optimistic_result.push(Err(err.into()));
124 keys.push(None);
125 None
126 }
127 }
128 }));
129
130 if optimistic_check {
133 optimistic_result
134 } else {
135 #[cfg(feature = "rayon")]
136 let iter = (keys, optimistic_result).into_par_iter();
137
138 #[cfg(not(feature = "rayon"))]
139 let iter = keys.into_iter().zip(optimistic_result.into_iter());
140
141 iter.filter_map(|(key, res)| key.zip(res.ok().map(VerifiedAcknowledgement::leak)))
142 .map(|(key, ack)| ack.verify(&key))
143 .collect()
144 }
145 }
146}
147
148#[derive(Copy, Clone, Debug, PartialEq)]
152pub struct VerifiedAcknowledgement {
153 ack_key_share: HalfKey,
154 signature: OffchainSignature,
155}
156
157impl VerifiedAcknowledgement {
158 pub fn new(ack_key_share: HalfKey, node_keypair: &OffchainKeypair) -> Self {
160 let signature = OffchainSignature::sign_message(ack_key_share.as_ref(), node_keypair);
161 Self {
162 ack_key_share,
163 signature,
164 }
165 }
166
167 pub fn random(offchain_keypair: &OffchainKeypair) -> Self {
169 Self::new(HalfKey::random(), offchain_keypair)
170 }
171
172 pub fn leak(self) -> Acknowledgement {
174 let mut ret = [0u8; Acknowledgement::SIZE];
175 ret[0..HalfKey::SIZE].copy_from_slice(self.ack_key_share.as_ref());
176 ret[HalfKey::SIZE..HalfKey::SIZE + OffchainSignature::SIZE].copy_from_slice(self.signature.as_ref());
177 Acknowledgement(ret)
178 }
179
180 pub fn ack_key_share(&self) -> &HalfKey {
184 &self.ack_key_share
185 }
186}
187
188#[derive(Clone, Debug, PartialEq, Eq)]
191#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
192pub enum PendingAcknowledgement {
193 WaitingAsSender,
195 WaitingAsRelayer(Box<UnacknowledgedTicket>),
197}
198
199#[cfg(test)]
200mod tests {
201 use std::ops::Not;
202
203 use super::*;
204
205 #[test]
206 fn acknowledgement_should_verify() -> anyhow::Result<()> {
207 let kp = OffchainKeypair::random();
208 let v_ack_1 = VerifiedAcknowledgement::random(&kp);
209 let v_ack_2 = v_ack_1.leak().verify(kp.public())?;
210
211 assert_eq!(v_ack_1, v_ack_2);
212 Ok(())
213 }
214
215 #[parameterized::parameterized(batch_size = {1, 2, 100 })]
216 fn acknowledgement_should_verify_batch(batch_size: usize) -> anyhow::Result<()> {
217 let mut verified_acks = Vec::with_capacity(100);
218 let batch = (0..batch_size)
219 .map(|_| {
220 let kp = OffchainKeypair::random();
221 let ack = VerifiedAcknowledgement::random(&kp);
222 verified_acks.push(ack);
223 (*kp.public(), ack.leak())
224 })
225 .collect::<Vec<_>>();
226
227 let res = Acknowledgement::verify_batch(batch);
228
229 assert_eq!(batch_size, res.len());
230 assert!(res.iter().all(|r| r.is_ok()));
231 assert_eq!(verified_acks, res.into_iter().map(|r| r.unwrap()).collect::<Vec<_>>());
232
233 Ok(())
234 }
235
236 #[test]
237 fn acknowledgement_should_return_failed_ack_in_the_batch_verification() -> anyhow::Result<()> {
238 let mut verified_acks = Vec::with_capacity(100);
239 let batch = (0..100)
240 .map(|i| {
241 let kp = OffchainKeypair::random();
242 let ack = VerifiedAcknowledgement::random(&kp);
243 if i == 50 {
244 let mut non_verified = ack.leak();
245 non_verified.0[3] = non_verified.0[3].not();
246 (*kp.public(), non_verified)
247 } else {
248 verified_acks.push(ack);
249 (*kp.public(), ack.leak())
250 }
251 })
252 .collect::<Vec<_>>();
253
254 let res = Acknowledgement::verify_batch(batch);
255
256 assert_eq!(100, res.len());
257 assert!(res[50].is_err());
258 assert!(res.iter().enumerate().all(|(i, r)| r.is_ok() || i == 50));
259 assert_eq!(
260 verified_acks,
261 res.into_iter().filter_map(|r| r.ok()).collect::<Vec<_>>()
262 );
263
264 Ok(())
265 }
266}