sphinx_packet/header/
keys.rs1use crate::constants::INTEGRITY_MAC_KEY_SIZE;
16use crate::crypto::STREAM_CIPHER_KEY_SIZE;
17use crate::header::shared_secret::{expand_shared_secret, ExpandedSharedSecret};
18use crate::route::Node;
19use curve25519_dalek::Scalar;
20use x25519_dalek::{PublicKey, StaticSecret};
21
22pub type StreamCipherKey = [u8; STREAM_CIPHER_KEY_SIZE];
23pub type HeaderIntegrityMacKey = [u8; INTEGRITY_MAC_KEY_SIZE];
24
25pub struct KeyMaterial {
26 pub initial_shared_secret: PublicKey,
27 pub expanded_shared_secrets: Vec<ExpandedSharedSecret>,
28}
29
30impl KeyMaterial {
31 pub fn derive(route: &[Node], initial_secret: &StaticSecret) -> Self {
33 let initial_shared_secret = PublicKey::from(initial_secret);
34
35 let mut expanded_shared_secrets = Vec::new();
36 let mut blinding_factors = Vec::new();
37
38 for (i, node) in route.iter().enumerate() {
39 let mut acc = node.pub_key;
40
41 for blinding_factor in std::iter::once(initial_secret).chain(&blinding_factors) {
43 let shared_secret = blinding_factor.diffie_hellman(&acc);
44 acc = PublicKey::from(shared_secret.to_bytes());
45 }
46
47 let expanded_shared_secret = expand_shared_secret(acc.as_bytes());
48
49 if i != route.len() - 1 {
50 blinding_factors.push(expanded_shared_secret.blinding_factor());
51 }
52 expanded_shared_secrets.push(expanded_shared_secret);
53 }
54
55 Self {
56 initial_shared_secret,
57 expanded_shared_secrets,
58 }
59 }
60
61 #[deprecated]
62 pub fn derive_legacy(route: &[Node], initial_secret: &StaticSecret) -> Self {
63 let initial_secret_scalar = Scalar::from_bytes_mod_order(initial_secret.to_bytes());
64
65 let initial_shared_secret =
66 curve25519_dalek::MontgomeryPoint::mul_base(&initial_secret_scalar);
67
68 let mut expanded_shared_secrets = Vec::with_capacity(route.len());
69
70 let mut accumulator = initial_secret_scalar;
71 for (i, node) in route.iter().enumerate() {
72 let pk_mt = curve25519_dalek::MontgomeryPoint(node.pub_key.to_bytes());
74 let shared_key = pk_mt * accumulator;
75
76 let expanded_shared_secret = expand_shared_secret(shared_key.as_bytes());
77
78 if i != route.len() + 1 {
80 let blinding_factor_scalar =
83 &Scalar::from_bytes_mod_order(*expanded_shared_secret.blinding_factor_bytes());
84
85 accumulator *= blinding_factor_scalar;
86 }
87
88 expanded_shared_secrets.push(expanded_shared_secret);
89 }
90 Self {
91 initial_shared_secret: PublicKey::from(initial_shared_secret.0),
92 expanded_shared_secrets,
93 }
94 }
95}
96
97#[cfg(test)]
98mod deriving_key_material {
99 use super::*;
100 use crate::route::Node;
101
102 #[cfg(test)]
103 mod with_an_empty_route {
104 use super::*;
105
106 #[test]
107 fn it_returns_no_routing_keys() {
108 let empty_route: Vec<Node> = vec![];
109 let initial_secret = StaticSecret::random();
110 let key_material = KeyMaterial::derive(&empty_route, &initial_secret);
111 assert_eq!(0, key_material.expanded_shared_secrets.len());
112 assert_eq!(
113 PublicKey::from(&initial_secret).as_bytes(),
114 key_material.initial_shared_secret.as_bytes()
115 )
116 }
117 }
118
119 #[cfg(test)]
120 mod for_a_route_with_3_forward_hops {
121 use super::*;
122 use crate::test_utils::random_node;
123
124 fn setup() -> (Vec<Node>, StaticSecret, KeyMaterial) {
125 let route: Vec<Node> = vec![random_node(), random_node(), random_node()];
126 let initial_secret = StaticSecret::random();
127 let key_material = KeyMaterial::derive(&route, &initial_secret);
128 (route, initial_secret, key_material)
129 }
130
131 #[test]
132 fn it_returns_number_of_shared_keys_equal_to_length_of_the_route() {
133 let (_, _, key_material) = setup();
134 assert_eq!(3, key_material.expanded_shared_secrets.len());
135 }
136
137 #[test]
138 fn it_returns_correctly_inited_shared_secret() {
139 let (_, initial_secret, key_material) = setup();
140 assert_eq!(
141 PublicKey::from(&initial_secret).as_bytes(),
142 key_material.initial_shared_secret.as_bytes()
143 );
144 }
145
146 #[test]
147 fn it_generates_correct_expanded_shared_secret() {
148 let (route, initial_secret, key_material) = setup();
149 let mut expected_accumulator = vec![initial_secret];
155 for (i, node) in route.iter().enumerate() {
156 let expected_shared_key =
157 expected_accumulator
158 .iter()
159 .fold(node.pub_key, |acc, blinding_factor| {
160 PublicKey::from(blinding_factor.diffie_hellman(&acc).to_bytes())
161 });
162
163 let expected_expanded_ss = expand_shared_secret(expected_shared_key.as_bytes());
164
165 expected_accumulator.push(expected_expanded_ss.blinding_factor());
166 assert_eq!(
167 expected_expanded_ss,
168 key_material.expanded_shared_secrets[i]
169 )
170 }
171 }
172 }
173}