Skip to content

Commit 8649bf3

Browse files
authored
feat: ExpandedSharedSecret /w ReplyTag (with legacy compat) (#101)
* add version method to allow constructing surbs with legacy headers * introduce derivation of reply tag
1 parent e535fe2 commit 8649bf3

File tree

16 files changed

+796
-371
lines changed

16 files changed

+796
-371
lines changed

Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "sphinx-packet"
3-
version = "0.4.0"
3+
version = "0.5.0"
44
authors = ["Ania Piotrowska <[email protected]>", "Dave Hrycyszyn <[email protected]>", "Jędrzej Stuczyński <[email protected]>"]
55
edition = "2018"
66
license = "Apache-2.0"
@@ -16,6 +16,9 @@ ctr = "0.9.2"
1616
bs58 = "0.5.1"
1717
x25519-dalek = { version = "2.0.1", features = ["static_secrets", "getrandom", "zeroize"] }
1818

19+
# for legacy compat
20+
curve25519-dalek = { version = "4.1.3" }
21+
1922
hmac = "0.12.1"
2023
digest = "0.10.7"
2124
rand = "0.8.5"
@@ -28,11 +31,13 @@ chacha = "0.3.0"
2831
blake2 = "0.8.0" # cannot be updated due to outdated dependency inside lioness
2932
byteorder = "1.5.0"
3033
subtle = "2.4.1"
34+
zeroize = "1.7.0"
3135

3236

3337

3438
[dev-dependencies]
3539
criterion = "0.5.1"
40+
rand_chacha = "0.3.1"
3641

3742
[[bench]]
3843
name = "benchmarks"

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,21 @@ of this library
4141

4242
added additional public methods on the `Version`
4343

44+
#### v0.3.2
45+
46+
added version method to allow constructing SURBs with legacy headers
47+
4448
#### v0.4.0
4549

4650
removed processing and creation of packets with undefined operations
4751

52+
#### v0.5.0
53+
54+
- temporarily restored processing and creation of packets with undefined operations as additional breaking changes had
55+
to be added to v0.3.2 release
56+
- removed `RoutingKeys` in favour of `ExpandedSharedSecret` and added `ReplyTag`
57+
- type adjustments
58+
4859
### Benchmarks
4960

5061
To run benchmarks, use:

src/constants.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,16 @@ use sha2::Sha256;
1919
pub const SECURITY_PARAMETER: usize = 16; // k in the Sphinx paper. Measured in bytes; 128 bits.
2020
pub const MAX_PATH_LENGTH: usize = 5; // r in the Sphinx paper
2121
pub const BLINDING_FACTOR_SIZE: usize = 2 * SECURITY_PARAMETER;
22-
pub const ROUTING_KEYS_LENGTH: usize = crypto::STREAM_CIPHER_KEY_SIZE
22+
23+
/// Output of the h𝜏 hash function / random oracle
24+
pub const REPLAY_TAG_SIZE: usize = 2 * SECURITY_PARAMETER;
25+
26+
pub const EXPANDED_SHARED_SECRET_LENGTH: usize = crypto::STREAM_CIPHER_KEY_SIZE
2327
+ INTEGRITY_MAC_KEY_SIZE
2428
+ PAYLOAD_KEY_SIZE
25-
+ BLINDING_FACTOR_SIZE;
29+
+ BLINDING_FACTOR_SIZE
30+
+ REPLAY_TAG_SIZE;
31+
2632
pub const HKDF_INPUT_SEED: &[u8; 97] = b"Dwste mou enan moxlo arketa makru kai ena upomoxlio gia na ton topothetisw kai tha kinisw thn gh.";
2733
pub const STREAM_CIPHER_OUTPUT_LENGTH: usize =
2834
(NODE_META_INFO_SIZE + HEADER_INTEGRITY_MAC_SIZE) * (MAX_PATH_LENGTH + 1);

src/header/filler.rs

Lines changed: 49 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,23 @@
1414

1515
use crate::constants::{HEADER_INTEGRITY_MAC_SIZE, MAX_PATH_LENGTH, NODE_META_INFO_SIZE};
1616
use crate::crypto;
17-
use crate::header::keys::RoutingKeys;
17+
use crate::header::shared_secret::ExpandedSharedSecret;
1818
use crate::{constants, utils};
1919

2020
pub const FILLER_STEP_SIZE_INCREASE: usize = NODE_META_INFO_SIZE + HEADER_INTEGRITY_MAC_SIZE;
2121

2222
#[derive(Debug, PartialEq, Eq)]
23-
pub struct Filler {
24-
value: Vec<u8>,
25-
}
23+
pub struct Filler(Vec<u8>);
2624

2725
impl Filler {
28-
pub fn new(routing_keys: &[RoutingKeys]) -> Self {
29-
assert!(routing_keys.len() <= MAX_PATH_LENGTH);
30-
let filler_value = routing_keys
26+
pub(crate) fn new(expanded_shared_secrets: &[ExpandedSharedSecret]) -> Self {
27+
assert!(expanded_shared_secrets.len() <= MAX_PATH_LENGTH);
28+
let filler_value = expanded_shared_secrets
3129
.iter()
32-
.map(|node_routing_keys| node_routing_keys.stream_cipher_key) // we only want the cipher key
30+
.map(|ess| ess.stream_cipher_key()) // we only want the cipher key
3331
.map(|cipher_key| {
3432
crypto::generate_pseudorandom_bytes(
35-
&cipher_key,
33+
cipher_key,
3634
&crypto::STREAM_CIPHER_INIT_VECTOR,
3735
constants::STREAM_CIPHER_OUTPUT_LENGTH,
3836
)
@@ -45,9 +43,7 @@ impl Filler {
4543
Self::filler_step(filler_string_accumulator, i, pseudorandom_bytes)
4644
},
4745
);
48-
Self {
49-
value: filler_value,
50-
}
46+
Self(filler_value)
5147
}
5248

5349
fn filler_step(
@@ -75,41 +71,44 @@ impl Filler {
7571

7672
filler_string_accumulator
7773
}
74+
}
7875

79-
pub fn get_value(self) -> Vec<u8> {
80-
self.value
76+
impl From<Vec<u8>> for Filler {
77+
fn from(raw_bytes: Vec<u8>) -> Self {
78+
Self(raw_bytes)
8179
}
80+
}
8281

83-
pub(crate) fn from_raw(raw_value: Vec<u8>) -> Self {
84-
Filler { value: raw_value }
82+
impl From<Filler> for Vec<u8> {
83+
fn from(filler: Filler) -> Self {
84+
filler.0
8585
}
8686
}
8787

8888
#[cfg(test)]
8989
mod test_creating_pseudorandom_bytes {
90-
use crate::header::keys;
91-
9290
use super::*;
91+
use crate::header::shared_secret::ExpandSecret;
9392
use x25519_dalek::{PublicKey, StaticSecret};
9493

9594
#[test]
9695
fn with_no_keys_it_generates_empty_filler_string() {
97-
let routing_keys: Vec<RoutingKeys> = vec![];
98-
let filler_string = Filler::new(&routing_keys);
96+
let expanded_shared_secret: Vec<_> = vec![];
97+
let filler_string = Filler::new(&expanded_shared_secret);
9998

100-
assert_eq!(0, filler_string.value.len());
99+
assert_eq!(0, filler_string.0.len());
101100
}
102101

103102
#[test]
104103
fn with_1_key_it_generates_filler_of_length_1_times_3_times_security_parameter() {
105104
let shared_keys = [PublicKey::from(&StaticSecret::random())];
106-
let routing_keys: Vec<_> = shared_keys
105+
let expanded_shared_secret: Vec<_> = shared_keys
107106
.iter()
108-
.map(|&key| keys::RoutingKeys::derive(key))
107+
.map(|&key| key.expand_shared_secret())
109108
.collect();
110-
let filler_string = Filler::new(&routing_keys);
109+
let filler_string = Filler::new(&expanded_shared_secret);
111110

112-
assert_eq!(FILLER_STEP_SIZE_INCREASE, filler_string.value.len());
111+
assert_eq!(FILLER_STEP_SIZE_INCREASE, filler_string.0.len());
113112
}
114113

115114
#[test]
@@ -119,12 +118,12 @@ mod test_creating_pseudorandom_bytes {
119118
PublicKey::from(&StaticSecret::random()),
120119
PublicKey::from(&StaticSecret::random()),
121120
];
122-
let routing_keys: Vec<_> = shared_keys
121+
let expanded_shared_secret: Vec<_> = shared_keys
123122
.iter()
124-
.map(|&key| keys::RoutingKeys::derive(key))
123+
.map(|&key| key.expand_shared_secret())
125124
.collect();
126-
let filler_string = Filler::new(&routing_keys);
127-
assert_eq!(3 * FILLER_STEP_SIZE_INCREASE, filler_string.value.len());
125+
let filler_string = Filler::new(&expanded_shared_secret);
126+
assert_eq!(3 * FILLER_STEP_SIZE_INCREASE, filler_string.0.len());
128127
}
129128

130129
#[test]
@@ -133,43 +132,43 @@ mod test_creating_pseudorandom_bytes {
133132
let shared_keys: Vec<_> = std::iter::repeat_n((), constants::MAX_PATH_LENGTH + 1)
134133
.map(|_| PublicKey::from(&StaticSecret::random()))
135134
.collect();
136-
let routing_keys: Vec<_> = shared_keys
135+
let expanded_shared_secrets: Vec<_> = shared_keys
137136
.iter()
138-
.map(|&key| keys::RoutingKeys::derive(key))
137+
.map(|&key| key.expand_shared_secret())
139138
.collect();
140-
Filler::new(&routing_keys);
139+
Filler::new(&expanded_shared_secrets);
141140
}
142141
}
143142

144143
#[cfg(test)]
145144
mod test_new_filler_bytes {
146145
use super::*;
147-
use crate::test_utils::fixtures::routing_keys_fixture;
146+
use crate::test_utils::fixtures::expanded_shared_secret_fixture;
148147

149148
#[test]
150-
fn it_retusn_filler_bytes_of_correct_length_for_3_routing_keys() {
151-
let routing_key_1 = routing_keys_fixture();
152-
let routing_key_2 = routing_keys_fixture();
153-
let routing_key_3 = routing_keys_fixture();
154-
let routing_keys = [routing_key_1, routing_key_2, routing_key_3];
155-
let filler = Filler::new(&routing_keys);
149+
fn it_retusn_filler_bytes_of_correct_length_for_3_expanded_shared_secret() {
150+
let routing_key_1 = expanded_shared_secret_fixture();
151+
let routing_key_2 = expanded_shared_secret_fixture();
152+
let routing_key_3 = expanded_shared_secret_fixture();
153+
let expanded_shared_secret = [routing_key_1, routing_key_2, routing_key_3];
154+
let filler = Filler::new(&expanded_shared_secret);
156155
assert_eq!(
157-
FILLER_STEP_SIZE_INCREASE * (routing_keys.len()),
158-
filler.get_value().len()
156+
FILLER_STEP_SIZE_INCREASE * (expanded_shared_secret.len()),
157+
filler.0.len()
159158
)
160159
}
161160

162161
#[test]
163-
fn it_retusn_filler_bytes_of_correct_length_for_4_routing_keys() {
164-
let routing_key_1 = routing_keys_fixture();
165-
let routing_key_2 = routing_keys_fixture();
166-
let routing_key_3 = routing_keys_fixture();
167-
let routing_key_4 = routing_keys_fixture();
168-
let routing_keys = [routing_key_1, routing_key_2, routing_key_3, routing_key_4];
169-
let filler = Filler::new(&routing_keys);
162+
fn it_retusn_filler_bytes_of_correct_length_for_4_expanded_shared_secret() {
163+
let routing_key_1 = expanded_shared_secret_fixture();
164+
let routing_key_2 = expanded_shared_secret_fixture();
165+
let routing_key_3 = expanded_shared_secret_fixture();
166+
let routing_key_4 = expanded_shared_secret_fixture();
167+
let expanded_shared_secret = [routing_key_1, routing_key_2, routing_key_3, routing_key_4];
168+
let filler = Filler::new(&expanded_shared_secret);
170169
assert_eq!(
171-
FILLER_STEP_SIZE_INCREASE * (routing_keys.len()),
172-
filler.get_value().len()
170+
FILLER_STEP_SIZE_INCREASE * (expanded_shared_secret.len()),
171+
filler.0.len()
173172
)
174173
}
175174
}

0 commit comments

Comments
 (0)