1use std::{
2 io::{Cursor, Read, Write},
3 time::{Duration, SystemTime, UNIX_EPOCH},
4};
5
6use anyhow::{Context, Result};
7use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
8use hotshot_types::traits::signature_key::SignatureKey;
9
10use super::{RequestHash, Serializable, request::Request};
11
12#[derive(Clone, Debug)]
14#[cfg_attr(test, derive(PartialEq, Eq))]
15pub enum Message<R: Request, K: SignatureKey> {
16 Request(RequestMessage<R, K>),
18 Response(ResponseMessage<R>),
20}
21
22#[derive(Clone, Debug)]
24#[cfg_attr(test, derive(PartialEq, Eq))]
25pub struct RequestMessage<R: Request, K: SignatureKey> {
26 pub public_key: K,
28 pub signature: K::PureAssembledSignatureType,
30 pub timestamp_unix_seconds: u64,
33 pub request: R,
35}
36
37#[derive(Clone, Debug)]
39#[cfg_attr(test, derive(PartialEq, Eq))]
40pub struct ResponseMessage<R: Request> {
41 pub request_hash: RequestHash,
44 pub response: R::Response,
46}
47
48const REQUEST_TAG: u8 = 0;
50const RESPONSE_TAG: u8 = 1;
52
53#[derive(Clone, Copy, Debug)]
57pub enum MessageFrame<'a> {
58 Request { body: &'a [u8] },
60 Response {
62 request_hash: RequestHash,
63 body: &'a [u8],
64 },
65}
66
67impl<'a> MessageFrame<'a> {
68 pub fn parse(bytes: &'a [u8]) -> Result<Self> {
74 let (&type_byte, body) = bytes.split_first().context("empty message")?;
75
76 match type_byte {
77 REQUEST_TAG => Ok(Self::Request { body }),
78 RESPONSE_TAG => {
79 let (request_hash, body) = split_request_hash(body)?;
80 Ok(Self::Response { request_hash, body })
81 },
82 _ => Err(anyhow::anyhow!("invalid message type")),
83 }
84 }
85}
86
87impl<R: Request, K: SignatureKey> RequestMessage<R, K> {
88 pub fn new_signed(public_key: &K, private_key: &K::PrivateKey, request: &R) -> Result<Self>
97 where
98 <K as SignatureKey>::SignError: 'static,
99 {
100 let timestamp_unix_seconds = SystemTime::now()
102 .duration_since(UNIX_EPOCH)
103 .expect("time went backwards")
104 .as_secs();
105
106 let content_to_sign = [
108 request
109 .to_bytes()
110 .with_context(|| "failed to serialize request content")?
111 .as_slice(),
112 timestamp_unix_seconds.to_le_bytes().as_slice(),
113 b"espresso-request-response",
114 ]
115 .concat();
116
117 let signature =
119 K::sign(private_key, &content_to_sign).with_context(|| "failed to sign message")?;
120
121 Ok(RequestMessage {
123 public_key: public_key.clone(),
124 signature,
125 timestamp_unix_seconds,
126 request: request.clone(),
127 })
128 }
129
130 pub fn validate(&self, incoming_request_ttl: Duration) -> Result<()> {
140 if self
142 .timestamp_unix_seconds
143 .saturating_add(incoming_request_ttl.as_secs())
144 < SystemTime::now()
145 .duration_since(UNIX_EPOCH)
146 .expect("time went backwards")
147 .as_secs()
148 {
149 return Err(anyhow::anyhow!("request is too old"));
150 }
151 if !self.public_key.validate(
153 &self.signature,
154 &[
155 self.request.to_bytes()?,
156 self.timestamp_unix_seconds.to_le_bytes().to_vec(),
157 b"espresso-request-response".to_vec(),
158 ]
159 .concat(),
160 ) {
161 return Err(anyhow::anyhow!("invalid request signature"));
162 }
163
164 self.request.validate()
166 }
167}
168
169impl<R: Request, K: SignatureKey> Serializable for Message<R, K> {
171 fn to_bytes(&self) -> Result<Vec<u8>> {
173 let mut bytes = Vec::new();
175
176 match self {
178 Message::Request(request_message) => {
179 bytes.push(REQUEST_TAG);
181
182 bytes.extend_from_slice(request_message.to_bytes()?.as_slice());
184 },
185 Message::Response(response_message) => {
186 bytes.push(RESPONSE_TAG);
188
189 bytes.extend_from_slice(response_message.to_bytes()?.as_slice());
191 },
192 };
193
194 Ok(bytes)
195 }
196
197 fn from_bytes(bytes: &[u8]) -> Result<Self> {
199 Ok(match MessageFrame::parse(bytes)? {
200 MessageFrame::Request { body } => Message::Request(RequestMessage::from_bytes(body)?),
201 MessageFrame::Response { request_hash, body } => Message::Response(ResponseMessage {
202 request_hash,
203 response: R::Response::from_bytes(body)?,
204 }),
205 })
206 }
207}
208
209impl<R: Request, K: SignatureKey> Serializable for RequestMessage<R, K> {
210 fn to_bytes(&self) -> Result<Vec<u8>> {
211 let mut bytes = Vec::new();
213
214 write_length_prefixed(&mut bytes, &self.public_key.to_bytes())?;
216
217 write_length_prefixed(&mut bytes, &bincode::serialize(&self.signature)?)?;
219
220 bytes.write_all(&self.timestamp_unix_seconds.to_le_bytes())?;
222
223 bytes.write_all(self.request.to_bytes()?.as_slice())?;
225
226 Ok(bytes)
227 }
228
229 fn from_bytes(bytes: &[u8]) -> Result<Self> {
230 let mut bytes = Cursor::new(bytes);
232
233 let public_key = K::from_bytes(&read_length_prefixed(&mut bytes)?)?;
235
236 let signature = bincode::deserialize(&read_length_prefixed(&mut bytes)?)?;
238
239 let timestamp = bytes.read_u64::<LittleEndian>()?;
241
242 let request = R::from_bytes(&read_to_end(&mut bytes)?)?;
244
245 Ok(Self {
246 public_key,
247 signature,
248 timestamp_unix_seconds: timestamp,
249 request,
250 })
251 }
252}
253
254impl<R: Request> Serializable for ResponseMessage<R> {
255 fn to_bytes(&self) -> Result<Vec<u8>> {
256 let mut bytes = Vec::new();
258
259 bytes.write_all(self.request_hash.as_bytes())?;
261
262 bytes.write_all(self.response.to_bytes()?.as_slice())?;
264
265 Ok(bytes)
266 }
267
268 fn from_bytes(bytes: &[u8]) -> Result<Self> {
269 let (request_hash, body) = split_request_hash(bytes)?;
270 Ok(Self {
271 request_hash,
272 response: R::Response::from_bytes(body)?,
273 })
274 }
275}
276
277fn split_request_hash(bytes: &[u8]) -> Result<(RequestHash, &[u8])> {
279 let (hash, body) = bytes
280 .split_at_checked(blake3::OUT_LEN)
281 .context("response message is shorter than a request hash")?;
282 let hash: [u8; blake3::OUT_LEN] = hash.try_into()?;
283 Ok((RequestHash::from(hash), body))
284}
285
286fn write_length_prefixed<W: Write>(writer: &mut W, value: &[u8]) -> Result<()> {
288 writer.write_u32::<LittleEndian>(
290 u32::try_from(value.len()).with_context(|| "value was too large")?,
291 )?;
292
293 writer.write_all(value)?;
295 Ok(())
296}
297
298fn read_length_prefixed<R: Read>(reader: &mut R) -> Result<Vec<u8>> {
300 let length = u64::from(reader.read_u32::<LittleEndian>()?);
302
303 let mut value = Vec::with_capacity(length.min(64 * 1024) as usize);
304 let read = reader.take(length).read_to_end(&mut value)?;
305 if read as u64 != length {
306 return Err(anyhow::anyhow!("length prefix exceeds available data"));
307 }
308 Ok(value)
309}
310
311fn read_to_end<R: Read>(reader: &mut R) -> Result<Vec<u8>> {
313 let mut value = Vec::new();
314 reader.read_to_end(&mut value)?;
315 Ok(value)
316}
317
318#[cfg(test)]
319mod tests {
320 use hotshot_types::signature_key::BLSPubKey;
321 use rand::Rng;
322
323 use super::*;
324
325 impl Serializable for Vec<u8> {
327 fn to_bytes(&self) -> Result<Vec<u8>> {
328 Ok(self.clone())
329 }
330 fn from_bytes(bytes: &[u8]) -> Result<Self> {
331 Ok(bytes.to_vec())
332 }
333 }
334
335 impl Request for Vec<u8> {
337 type Response = Vec<u8>;
338
339 fn validate(&self) -> Result<()> {
340 Ok(())
341 }
342 }
343
344 #[test]
347 fn test_request_validation() {
348 let mut rng = rand::thread_rng();
350
351 for _ in 0..100 {
352 let (public_key, private_key) =
354 BLSPubKey::generated_from_seed_indexed([1; 32], rng.r#gen::<u64>());
355
356 let mut request = RequestMessage::new_signed(
358 &public_key,
359 &private_key,
360 &vec![rng.r#gen::<u8>(); rng.gen_range(1..10000)],
361 )
362 .expect("Failed to create signed request");
363
364 let (should_be_valid, request_ttl) = match rng.gen_range(0..4) {
365 0 => (true, Duration::from_secs(1)),
366
367 1 => {
368 request.request[0] = !request.request[0];
370
371 (false, Duration::from_secs(1))
373 },
374
375 2 => {
376 request.timestamp_unix_seconds += 1000;
378
379 (false, Duration::from_secs(1))
381 },
382
383 3 => {
384 (true, Duration::from_secs(0))
387 },
388
389 _ => unreachable!(),
390 };
391
392 assert_eq!(request.validate(request_ttl).is_ok(), should_be_valid);
394 }
395 }
396
397 #[test]
399 fn test_message_parity() {
400 for _ in 0..100 {
401 let mut rng = rand::thread_rng();
403
404 let is_request = rng.r#gen::<u8>() % 2 == 0;
406
407 let request = vec![rng.r#gen::<u8>(); rng.gen_range(0..10000)];
409
410 let message = if is_request {
412 let (public_key, private_key) =
414 BLSPubKey::generated_from_seed_indexed([1; 32], rng.r#gen::<u64>());
415
416 let request = RequestMessage::new_signed(&public_key, &private_key, &request)
418 .expect("Failed to create signed request");
419
420 Message::Request(request)
421 } else {
422 Message::Response(ResponseMessage {
424 request_hash: blake3::hash(&request),
425 response: vec![rng.r#gen::<u8>(); rng.gen_range(0..10000)],
426 })
427 };
428
429 let serialized = message.to_bytes().expect("Failed to serialize message");
431
432 let deserialized =
434 Message::from_bytes(&serialized).expect("Failed to deserialize message");
435
436 assert_eq!(message, deserialized);
438
439 let frame = MessageFrame::parse(&serialized).expect("Failed to parse frame");
441 match (&message, frame) {
442 (Message::Request(_), MessageFrame::Request { .. }) => {},
443 (Message::Response(response), MessageFrame::Response { request_hash, .. }) => {
444 assert_eq!(request_hash, response.request_hash);
445 },
446 (message, frame) => panic!("frame {frame:?} does not match {message:?}"),
447 }
448 }
449 }
450
451 #[test]
453 fn test_frame_rejects_malformed_messages() {
454 assert!(MessageFrame::parse(&[]).is_err(), "empty message");
455 assert!(MessageFrame::parse(&[2]).is_err(), "unknown type byte");
456 assert!(
457 MessageFrame::parse(&[RESPONSE_TAG; 20]).is_err(),
458 "response shorter than a hash"
459 );
460 assert!(matches!(
461 MessageFrame::parse(&[REQUEST_TAG]),
462 Ok(MessageFrame::Request { body: &[] })
463 ));
464 }
465
466 #[test]
468 fn test_length_prefix_parity() {
469 let mut rng = rand::thread_rng();
471
472 for _ in 0..100 {
473 let mut bytes = Vec::new();
475
476 let value = vec![rng.r#gen::<u8>(); rng.gen_range(0..10000)];
478
479 write_length_prefixed(&mut bytes, &value).unwrap();
481
482 let mut reader = Cursor::new(bytes);
484
485 let value = read_length_prefixed(&mut reader).unwrap();
487 assert_eq!(value, value);
488 }
489 }
490}