1use crate::constants::HEADER_INTEGRITY_MAC_SIZE;
16use crate::header::delays::Delay;
17use crate::header::filler::Filler;
18use crate::header::keys::KeyMaterial;
19use crate::header::routing::{EncapsulatedRoutingInformation, ENCRYPTED_ROUTING_INFO_SIZE};
20use crate::header::shared_secret::{ExpandSecret, ExpandedSharedSecret};
21use crate::packet::ProcessedPacketData;
22use crate::payload::key::{derive_payload_key, PayloadKey, PayloadKeySeed};
23use crate::payload::Payload;
24use crate::route::{Destination, DestinationAddressBytes, Node, NodeAddressBytes, SURBIdentifier};
25use crate::version::Version;
26use crate::{Error, ErrorKind, ProcessedPacket, Result, SphinxPacket};
27use x25519_dalek::{PublicKey, StaticSecret};
28
29pub mod delays;
30pub mod filler;
31pub mod keys;
32pub mod mac;
33pub mod routing;
34pub mod shared_secret;
35
36pub const HEADER_SIZE: usize = 32 + HEADER_INTEGRITY_MAC_SIZE + ENCRYPTED_ROUTING_INFO_SIZE;
38
39#[derive(Debug)]
40#[cfg_attr(test, derive(Clone))]
41pub struct SphinxHeader {
42 pub shared_secret: PublicKey,
44 pub routing_info: Box<EncapsulatedRoutingInformation>,
45}
46
47pub struct ProcessedHeader {
48 payload_key: PayloadKey,
49 version: Version,
50 data: ProcessedHeaderData,
51}
52
53pub enum ProcessedHeaderData {
54 FinalHop {
55 destination: DestinationAddressBytes,
56 identifier: SURBIdentifier,
57 },
58 ForwardHop {
59 updated_header: SphinxHeader,
60 next_hop_address: NodeAddressBytes,
61 delay: Delay,
62 },
63}
64
65impl ProcessedHeader {
66 pub(crate) fn payload_key(&self) -> &PayloadKey {
67 &self.payload_key
68 }
69
70 pub(crate) fn attach_payload(self, payload: Payload) -> ProcessedPacket {
71 match self.data {
72 ProcessedHeaderData::ForwardHop {
73 updated_header,
74 next_hop_address,
75 delay,
76 } => ProcessedPacket {
77 version: self.version,
78 data: ProcessedPacketData::ForwardHop {
79 next_hop_packet: SphinxPacket {
80 header: updated_header,
81 payload,
82 },
83 next_hop_address,
84 delay,
85 },
86 },
87 ProcessedHeaderData::FinalHop {
88 destination,
89 identifier,
90 } => ProcessedPacket {
91 version: self.version,
92 data: ProcessedPacketData::FinalHop {
93 destination,
94 identifier,
95 payload,
96 },
97 },
98 }
99 }
100}
101
102impl SphinxHeader {
103 #[cfg(test)]
104 pub(crate) fn new_current(
105 initial_secret: &StaticSecret,
106 route: &[Node],
107 delays: &[Delay],
108 destination: &Destination,
109 ) -> BuiltHeader {
110 let key_material = keys::KeyMaterial::derive(route, initial_secret);
111 Self::build_header(
112 key_material,
113 route,
114 delays,
115 destination,
116 crate::version::CURRENT_VERSION,
117 )
118 }
119
120 #[cfg(test)]
121 #[deprecated]
122 #[allow(deprecated)]
123 pub(crate) fn new_legacy(
124 initial_secret: &StaticSecret,
125 route: &[Node],
126 delays: &[Delay],
127 destination: &Destination,
128 ) -> BuiltHeader {
129 let key_material = keys::KeyMaterial::derive_legacy(route, initial_secret);
130 Self::build_header(
131 key_material,
132 route,
133 delays,
134 destination,
135 crate::version::UPDATED_LEGACY_VERSION,
136 )
137 }
138
139 #[allow(deprecated)]
140 pub(crate) fn new_versioned(
141 initial_secret: &StaticSecret,
142 route: &[Node],
143 delays: &[Delay],
144 destination: &Destination,
145 version: Version,
146 ) -> BuiltHeader {
147 let key_material = if version.is_legacy() {
148 keys::KeyMaterial::derive_legacy(route, initial_secret)
149 } else {
150 keys::KeyMaterial::derive(route, initial_secret)
151 };
152 Self::build_header(key_material, route, delays, destination, version)
153 }
154
155 fn build_header(
156 key_material: KeyMaterial,
157 route: &[Node],
158 delays: &[Delay],
159 destination: &Destination,
160 version: Version,
161 ) -> BuiltHeader {
162 let filler_string = Filler::new(&key_material.expanded_shared_secrets[..route.len() - 1]);
163 let routing_info = EncapsulatedRoutingInformation::new(
164 route,
165 destination,
166 delays,
167 &key_material.expanded_shared_secrets,
168 filler_string,
169 version,
170 );
171
172 BuiltHeader::new(version, key_material, routing_info)
174 }
175
176 #[allow(deprecated)]
241 pub fn process_with_expanded_secret(
242 self,
243 expanded_secret: &ExpandedSharedSecret,
244 ) -> Result<ProcessedHeader> {
245 self.ensure_header_integrity(expanded_secret)?;
246
247 let unwrapped_routing_information = self
248 .routing_info
249 .enc_routing_information
250 .unwrap(expanded_secret.stream_cipher_key())?;
251
252 if unwrapped_routing_information.version.is_legacy() {
253 Ok(unwrapped_routing_information
254 .legacy_into_processed_header(self.shared_secret, expanded_secret))
255 } else {
256 Ok(unwrapped_routing_information
257 .into_processed_header(self.shared_secret, expanded_secret))
258 }
259 }
260
261 #[allow(deprecated)]
262 pub fn process(self, node_secret_key: &StaticSecret) -> Result<ProcessedHeader> {
263 let expanded_secret = self.compute_expanded_shared_secret(node_secret_key);
264 self.process_with_expanded_secret(&expanded_secret)
265 }
266
267 pub fn compute_expanded_shared_secret(
269 &self,
270 node_secret_key: &StaticSecret,
271 ) -> ExpandedSharedSecret {
272 node_secret_key
273 .diffie_hellman(&self.shared_secret)
274 .expand_shared_secret()
275 }
276
277 pub fn ensure_header_integrity(
278 &self,
279 expanded_shared_secret: &ExpandedSharedSecret,
280 ) -> Result<()> {
281 if !self.routing_info.integrity_mac.verify(
282 expanded_shared_secret.header_integrity_hmac_key(),
283 self.routing_info.enc_routing_information.as_ref(),
284 ) {
285 return Err(Error::new(
286 ErrorKind::InvalidHeader,
287 "failed to verify integrity MAC",
288 ));
289 }
290 Ok(())
291 }
292
293 #[deprecated]
294 pub fn unchecked_process_as_current(
295 self,
296 node_secret_key: &StaticSecret,
297 ) -> Result<ProcessedHeader> {
298 let expanded_secret = self.compute_expanded_shared_secret(node_secret_key);
299 self.ensure_header_integrity(&expanded_secret)?;
300
301 let unwrapped_routing_information = self
302 .routing_info
303 .enc_routing_information
304 .unwrap(expanded_secret.stream_cipher_key())?;
305
306 Ok(unwrapped_routing_information
307 .into_processed_header(self.shared_secret, &expanded_secret))
308 }
309
310 #[deprecated]
311 #[allow(deprecated)]
312 pub fn unchecked_process_as_legacy(
313 self,
314 node_secret_key: &StaticSecret,
315 ) -> Result<ProcessedHeader> {
316 let expanded_secret = self.compute_expanded_shared_secret(node_secret_key);
317 self.ensure_header_integrity(&expanded_secret)?;
318
319 let unwrapped_routing_information = self
320 .routing_info
321 .enc_routing_information
322 .unwrap(expanded_secret.stream_cipher_key())?;
323
324 Ok(unwrapped_routing_information
325 .legacy_into_processed_header(self.shared_secret, &expanded_secret))
326 }
327
328 pub fn to_bytes(&self) -> Vec<u8> {
329 self.shared_secret
330 .as_bytes()
331 .iter()
332 .cloned()
333 .chain(self.routing_info.to_bytes())
334 .collect()
335 }
336
337 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
338 if bytes.len() != HEADER_SIZE {
339 return Err(Error::new(
340 ErrorKind::InvalidHeader,
341 format!(
342 "tried to recover using {} bytes, expected {}",
343 bytes.len(),
344 HEADER_SIZE
345 ),
346 ));
347 }
348
349 let mut shared_secret_bytes = [0u8; 32];
350 shared_secret_bytes.copy_from_slice(&bytes[..32]);
352 let shared_secret = PublicKey::from(shared_secret_bytes);
353
354 let routing_info = Box::new(EncapsulatedRoutingInformation::from_bytes(&bytes[32..])?);
356
357 Ok(SphinxHeader {
358 shared_secret,
359 routing_info,
360 })
361 }
362
363 fn blind_the_shared_secret(
364 shared_secret: PublicKey,
365 blinding_factor: StaticSecret,
366 ) -> PublicKey {
367 let new_shared_secret = blinding_factor.diffie_hellman(&shared_secret);
369 PublicKey::from(new_shared_secret.to_bytes())
370 }
371
372 #[deprecated]
374 fn legacy_blind_shared_secret(
375 shared_secret: PublicKey,
376 blinding_factor: StaticSecret,
377 ) -> PublicKey {
378 let blinding_factor =
379 curve25519_dalek::scalar::Scalar::from_bytes_mod_order(blinding_factor.to_bytes());
380 let mp = curve25519_dalek::montgomery::MontgomeryPoint(shared_secret.to_bytes());
381 PublicKey::from((blinding_factor * mp).to_bytes())
382 }
383}
384
385pub(crate) struct BuiltHeader {
386 header: SphinxHeader,
387 version: Version,
388 expanded_secrets: Vec<ExpandedSharedSecret>,
389}
390
391impl BuiltHeader {
392 fn new(
393 version: Version,
394 key_material: KeyMaterial,
395 routing_information: EncapsulatedRoutingInformation,
396 ) -> Self {
397 BuiltHeader {
398 header: SphinxHeader {
399 shared_secret: key_material.initial_shared_secret,
400 routing_info: Box::new(routing_information),
401 },
402 version,
403 expanded_secrets: key_material.expanded_shared_secrets,
404 }
405 }
406
407 pub(crate) fn derive_payload_keys(&self) -> Vec<PayloadKey> {
410 if self.version.expects_legacy_full_payload_keys() {
411 self.legacy_full_payload_keys()
412 } else {
413 self.expanded_secrets
414 .iter()
415 .map(|s| derive_payload_key(s.payload_key_seed()))
416 .collect()
417 }
418 }
419
420 pub(crate) fn legacy_full_payload_keys(&self) -> Vec<PayloadKey> {
421 self.expanded_secrets
422 .iter()
423 .map(|s| *s.legacy_payload_key())
424 .collect()
425 }
426
427 pub(crate) fn payload_key_seeds(&self) -> Vec<PayloadKeySeed> {
428 self.expanded_secrets
429 .iter()
430 .map(|s| *s.payload_key_seed())
431 .collect()
432 }
433
434 pub(crate) fn into_header(self) -> SphinxHeader {
435 self.header
436 }
437}
438
439#[cfg(test)]
440mod create_and_process_sphinx_packet_header {
441 use super::*;
442 use crate::crypto::PrivateKey;
443 use crate::{
444 constants::NODE_ADDRESS_LENGTH,
445 test_utils::fixtures::{destination_fixture, keygen},
446 };
447 use std::time::Duration;
448
449 #[test]
450 fn it_returns_correct_routing_information_at_each_hop_for_route_of_3_mixnodes() {
451 let (node1_sk, node1_pk) = keygen();
452 let node1 = Node {
453 address: NodeAddressBytes::from_bytes([5u8; NODE_ADDRESS_LENGTH]),
454 pub_key: node1_pk,
455 };
456 let (node2_sk, node2_pk) = keygen();
457 let node2 = Node {
458 address: NodeAddressBytes::from_bytes([4u8; NODE_ADDRESS_LENGTH]),
459 pub_key: node2_pk,
460 };
461 let (node3_sk, node3_pk) = keygen();
462 let node3 = Node {
463 address: NodeAddressBytes::from_bytes([2u8; NODE_ADDRESS_LENGTH]),
464 pub_key: node3_pk,
465 };
466 let route = [node1, node2, node3];
467 let route_destination = destination_fixture();
468 let initial_secret = StaticSecret::random();
469 let average_delay = 1;
470 let delays =
471 delays::generate_from_average_duration(route.len(), Duration::from_secs(average_delay));
472 let sphinx_header =
473 SphinxHeader::new_current(&initial_secret, &route, &delays, &route_destination)
474 .into_header();
475
476 let new_header = match sphinx_header.process(&node1_sk).unwrap().data {
478 ProcessedHeaderData::ForwardHop {
479 updated_header,
480 next_hop_address,
481 delay,
482 } => {
483 assert_eq!(
484 NodeAddressBytes::from_bytes([4u8; NODE_ADDRESS_LENGTH]),
485 next_hop_address
486 );
487 assert_eq!(delays[0].to_nanos(), delay.to_nanos());
488 updated_header
489 }
490 _ => panic!(),
491 };
492
493 let new_header2 = match new_header.process(&node2_sk).unwrap().data {
494 ProcessedHeaderData::ForwardHop {
495 updated_header,
496 next_hop_address,
497 delay,
498 } => {
499 assert_eq!(
500 NodeAddressBytes::from_bytes([2u8; NODE_ADDRESS_LENGTH]),
501 next_hop_address
502 );
503 assert_eq!(delays[1].to_nanos(), delay.to_nanos());
504 updated_header
505 }
506 _ => panic!(),
507 };
508 match new_header2.process(&node3_sk).unwrap().data {
509 ProcessedHeaderData::FinalHop {
510 destination,
511 identifier: _,
512 } => {
513 assert_eq!(route_destination.address, destination);
514 }
515 _ => panic!(),
516 };
517 }
518
519 #[test]
520 #[allow(deprecated)]
521 fn it_returns_correct_routing_information_at_each_hop_for_route_of_3_mixnodes_with_legacy_processing(
522 ) {
523 let node1_sk = PrivateKey::from([
524 202, 37, 190, 57, 90, 36, 148, 40, 37, 203, 207, 229, 5, 80, 8, 77, 227, 95, 67, 20,
525 47, 83, 220, 34, 164, 207, 5, 212, 97, 151, 142, 168,
526 ]);
527 let node1_pk = PublicKey::from([
528 105, 91, 210, 146, 245, 155, 27, 169, 192, 123, 75, 121, 19, 204, 59, 187, 190, 150,
529 131, 118, 151, 77, 180, 144, 253, 88, 6, 212, 63, 5, 51, 7,
530 ]);
531
532 let node2_sk = PrivateKey::from([
533 130, 31, 0, 83, 139, 16, 225, 239, 132, 130, 122, 18, 217, 187, 91, 87, 250, 137, 152,
534 220, 254, 153, 246, 249, 252, 43, 153, 191, 152, 48, 154, 170,
535 ]);
536 let node2_pk = PublicKey::from([
537 178, 47, 98, 179, 103, 199, 16, 245, 35, 85, 9, 63, 138, 212, 83, 233, 169, 31, 205,
538 20, 73, 238, 141, 204, 19, 35, 226, 138, 44, 67, 225, 46,
539 ]);
540
541 let node3_sk = PrivateKey::from([
542 116, 204, 108, 186, 75, 233, 232, 22, 79, 66, 65, 176, 196, 246, 253, 30, 133, 153,
543 109, 229, 133, 177, 40, 42, 175, 72, 80, 70, 161, 7, 187, 155,
544 ]);
545 let node3_pk = PublicKey::from([
546 21, 93, 4, 80, 178, 177, 7, 218, 192, 213, 58, 157, 239, 242, 139, 45, 75, 26, 225, 54,
547 174, 21, 159, 25, 62, 87, 187, 46, 92, 246, 136, 81,
548 ]);
549
550 let node1 = Node::new(
551 NodeAddressBytes::from_bytes([1u8; NODE_ADDRESS_LENGTH]),
552 node1_pk,
553 );
554 let node2 = Node::new(
555 NodeAddressBytes::from_bytes([2u8; NODE_ADDRESS_LENGTH]),
556 node2_pk,
557 );
558 let node3 = Node::new(
559 NodeAddressBytes::from_bytes([3u8; NODE_ADDRESS_LENGTH]),
560 node3_pk,
561 );
562 let initial_secret = StaticSecret::from([
563 104, 106, 58, 28, 53, 127, 216, 216, 8, 84, 74, 171, 220, 71, 145, 25, 205, 24, 253,
564 23, 120, 124, 255, 114, 14, 246, 179, 119, 101, 14, 10, 89,
565 ]);
566
567 let route = [node1, node2, node3];
568 let route_destination = destination_fixture();
569 let average_delay = 1;
570 let delays =
571 delays::generate_from_average_duration(route.len(), Duration::from_secs(average_delay));
572 let sphinx_header =
573 SphinxHeader::new_legacy(&initial_secret, &route, &delays, &route_destination)
574 .into_header();
575
576 let new_header = match sphinx_header
578 .unchecked_process_as_legacy(&node1_sk)
579 .unwrap()
580 .data
581 {
582 ProcessedHeaderData::ForwardHop {
583 updated_header,
584 next_hop_address,
585 delay,
586 } => {
587 assert_eq!(
588 NodeAddressBytes::from_bytes([2u8; NODE_ADDRESS_LENGTH]),
589 next_hop_address
590 );
591 assert_eq!(delays[0].to_nanos(), delay.to_nanos());
592 updated_header
593 }
594 _ => panic!(),
595 };
596
597 let new_header2 = match new_header
598 .unchecked_process_as_legacy(&node2_sk)
599 .unwrap()
600 .data
601 {
602 ProcessedHeaderData::ForwardHop {
603 updated_header,
604 next_hop_address,
605 delay,
606 } => {
607 assert_eq!(
608 NodeAddressBytes::from_bytes([3u8; NODE_ADDRESS_LENGTH]),
609 next_hop_address
610 );
611 assert_eq!(delays[1].to_nanos(), delay.to_nanos());
612 updated_header
613 }
614 _ => panic!(),
615 };
616 match new_header2
617 .unchecked_process_as_legacy(&node3_sk)
618 .unwrap()
619 .data
620 {
621 ProcessedHeaderData::FinalHop {
622 destination,
623 identifier: _,
624 } => {
625 assert_eq!(route_destination.address, destination);
626 }
627 _ => panic!(),
628 };
629 }
630}
631
632#[cfg(test)]
633mod unwrap_routing_information {
634 use crate::constants::{
635 HEADER_INTEGRITY_MAC_SIZE, NODE_ADDRESS_LENGTH, NODE_META_INFO_SIZE,
636 STREAM_CIPHER_OUTPUT_LENGTH,
637 };
638 use crate::crypto;
639 use crate::header::routing::nodes::{
640 EncryptedRoutingInformation, ParsedRawRoutingInformationData,
641 };
642 use crate::header::routing::{ENCRYPTED_ROUTING_INFO_SIZE, FORWARD_HOP};
643 use crate::utils;
644
645 #[test]
646 fn it_returns_correct_unwrapped_routing_information() {
647 let mut routing_info = [9u8; ENCRYPTED_ROUTING_INFO_SIZE];
648 routing_info[0] = FORWARD_HOP;
649 routing_info[1] = 0;
651
652 let stream_cipher_key = [1u8; crypto::STREAM_CIPHER_KEY_SIZE];
653 let pseudorandom_bytes = crypto::generate_pseudorandom_bytes(
654 &stream_cipher_key,
655 &crypto::STREAM_CIPHER_INIT_VECTOR,
656 STREAM_CIPHER_OUTPUT_LENGTH,
657 );
658 let encrypted_routing_info_vec = utils::bytes::xor(
659 &routing_info,
660 &pseudorandom_bytes[..ENCRYPTED_ROUTING_INFO_SIZE],
661 );
662 let mut encrypted_routing_info_array = [0u8; ENCRYPTED_ROUTING_INFO_SIZE];
663 encrypted_routing_info_array.copy_from_slice(&encrypted_routing_info_vec);
664
665 let enc_routing_info =
666 EncryptedRoutingInformation::from_bytes(encrypted_routing_info_array);
667
668 let expected_next_hop_encrypted_routing_information = [
669 routing_info[NODE_META_INFO_SIZE + HEADER_INTEGRITY_MAC_SIZE..].to_vec(),
670 pseudorandom_bytes
671 [NODE_META_INFO_SIZE + HEADER_INTEGRITY_MAC_SIZE + ENCRYPTED_ROUTING_INFO_SIZE..]
672 .to_vec(),
673 ]
674 .concat();
675 let next_hop_encapsulated_routing_info =
676 match enc_routing_info.unwrap(&stream_cipher_key).unwrap().data {
677 ParsedRawRoutingInformationData::ForwardHop {
678 next_hop_address,
679 new_routing_information,
680 ..
681 } => {
682 assert_eq!(
683 routing_info[2..2 + NODE_ADDRESS_LENGTH],
684 next_hop_address.to_bytes()
685 );
686 assert_eq!(
687 routing_info
688 [NODE_ADDRESS_LENGTH..NODE_ADDRESS_LENGTH + HEADER_INTEGRITY_MAC_SIZE]
689 .to_vec(),
690 new_routing_information.integrity_mac.as_bytes().to_vec()
691 );
692 new_routing_information
693 }
694 _ => panic!(),
695 };
696
697 let next_hop_encrypted_routing_information = next_hop_encapsulated_routing_info
698 .enc_routing_information
699 .as_ref();
700
701 for i in 0..expected_next_hop_encrypted_routing_information.len() {
702 assert_eq!(
703 expected_next_hop_encrypted_routing_information[i],
704 next_hop_encrypted_routing_information[i]
705 );
706 }
707 }
708}
709
710#[cfg(test)]
711mod unwrapping_using_previously_expanded_shared_secret {
712 use super::*;
713 use crate::constants::NODE_ADDRESS_LENGTH;
714 use crate::test_utils::fixtures::{destination_fixture, keygen};
715 use std::time::Duration;
716
717 #[test]
718 fn produces_same_result_for_forward_hop() {
719 let (node1_sk, node1_pk) = keygen();
720 let node1 = Node {
721 address: NodeAddressBytes::from_bytes([5u8; NODE_ADDRESS_LENGTH]),
722 pub_key: node1_pk,
723 };
724 let (_, node2_pk) = keygen();
725 let node2 = Node {
726 address: NodeAddressBytes::from_bytes([4u8; NODE_ADDRESS_LENGTH]),
727 pub_key: node2_pk,
728 };
729 let route = [node1, node2];
730 let destination = destination_fixture();
731 let initial_secret = StaticSecret::random();
732 let average_delay = 1;
733 let delays =
734 delays::generate_from_average_duration(route.len(), Duration::from_secs(average_delay));
735 let sphinx_header =
736 SphinxHeader::new_current(&initial_secret, &route, &delays, &destination).into_header();
737 let initial_secret = sphinx_header.shared_secret;
738
739 let normally_unwrapped = match sphinx_header.clone().process(&node1_sk).unwrap().data {
740 ProcessedHeaderData::ForwardHop { updated_header, .. } => updated_header,
741 _ => unreachable!(),
742 };
743
744 let expanded_secret = node1_sk
745 .diffie_hellman(&initial_secret)
746 .expand_shared_secret();
747
748 let derived_unwrapped = match sphinx_header
749 .process_with_expanded_secret(&expanded_secret)
750 .unwrap()
751 .data
752 {
753 ProcessedHeaderData::ForwardHop { updated_header, .. } => updated_header,
754 _ => unreachable!(),
755 };
756
757 assert_eq!(
758 normally_unwrapped.shared_secret,
759 derived_unwrapped.shared_secret
760 );
761 assert_eq!(
762 normally_unwrapped.routing_info.to_bytes(),
763 derived_unwrapped.routing_info.to_bytes()
764 )
765 }
766
767 #[test]
768 fn produces_same_result_for_final_hop() {
769 let (node1_sk, node1_pk) = keygen();
770 let node1 = Node {
771 address: NodeAddressBytes::from_bytes([5u8; NODE_ADDRESS_LENGTH]),
772 pub_key: node1_pk,
773 };
774 let route = [node1];
775 let destination = destination_fixture();
776 let initial_secret = StaticSecret::random();
777 let average_delay = 1;
778 let delays =
779 delays::generate_from_average_duration(route.len(), Duration::from_secs(average_delay));
780 let sphinx_header =
781 SphinxHeader::new_current(&initial_secret, &route, &delays, &destination).into_header();
782 let initial_secret = sphinx_header.shared_secret;
783
784 let normally_unwrapped = sphinx_header.clone().process(&node1_sk).unwrap();
785 let normally_unwrapped = match normally_unwrapped.data {
786 ProcessedHeaderData::FinalHop {
787 destination,
788 identifier,
789 } => (destination, identifier, normally_unwrapped.payload_key),
790 _ => unreachable!(),
791 };
792
793 let expanded_secret = node1_sk
794 .diffie_hellman(&initial_secret)
795 .expand_shared_secret();
796
797 let derived_unwrapped = sphinx_header
798 .process_with_expanded_secret(&expanded_secret)
799 .unwrap();
800
801 let derived_unwrapped = match derived_unwrapped.data {
802 ProcessedHeaderData::FinalHop {
803 destination,
804 identifier,
805 } => (destination, identifier, derived_unwrapped.payload_key),
806 _ => unreachable!(),
807 };
808
809 assert_eq!(normally_unwrapped.0, derived_unwrapped.0);
810 assert_eq!(normally_unwrapped.1, derived_unwrapped.1);
811 assert_eq!(normally_unwrapped.2.to_vec(), derived_unwrapped.2.to_vec())
812 }
813}
814
815#[cfg(test)]
816mod converting_header_to_bytes {
817 use super::*;
818 use crate::test_utils::fixtures::encapsulated_routing_information_fixture;
819
820 #[test]
821 fn it_is_possible_to_convert_back_and_forth() {
822 let encapsulated_routing_info = Box::new(encapsulated_routing_information_fixture());
823 let header = SphinxHeader {
824 shared_secret: PublicKey::from(&StaticSecret::random()),
825 routing_info: encapsulated_routing_info,
826 };
827
828 let header_bytes = header.to_bytes();
829 let recovered_header = SphinxHeader::from_bytes(&header_bytes).unwrap();
830
831 assert_eq!(
832 header.shared_secret.as_bytes(),
833 recovered_header.shared_secret.as_bytes()
834 );
835 assert_eq!(
836 header.routing_info.to_bytes(),
837 recovered_header.routing_info.to_bytes()
838 );
839 }
840}