Skip to content

Commit c7bc838

Browse files
committed
Add gateway-probe localnet mode with WireGuard tunnel support
Adds localnet testing mode to gateway-probe for LP development: - Add TestMode enum for different probe configurations - Add --gateway-ip flag for direct gateway testing - Implement two-hop WireGuard tunnel for localnet - Add mock ecash support for testing without real credentials - Add netstack Go bindings for userspace networking - Restructure probe with mode and common modules - Update README with localnet mode documentation
1 parent bcba4c8 commit c7bc838

File tree

39 files changed

+2538
-1964
lines changed

39 files changed

+2538
-1964
lines changed

CLAUDE.md

Lines changed: 0 additions & 686 deletions
This file was deleted.

common/nym-kkt/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "nym-kkt"
33
version = "0.1.0"
44
authors = ["Georgio Nicolas <[email protected]>"]
5-
edition = "2021"
5+
edition = { workspace = true }
66
license.workspace = true
77

88
[dependencies]

common/nym-kkt/benches/benches.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
// Copyright 2025 - Nym Technologies SA <[email protected]>
22
// SPDX-License-Identifier: Apache-2.0
33

4-
use criterion::{criterion_group, criterion_main, Criterion};
4+
use criterion::{Criterion, criterion_group, criterion_main};
55

66
use nym_crypto::asymmetric::ed25519;
77
use nym_kkt::{
8-
ciphersuite::{Ciphersuite, EncapsulationKey, HashFunction, SignatureScheme, KEM},
8+
ciphersuite::{Ciphersuite, EncapsulationKey, HashFunction, KEM, SignatureScheme},
99
context::KKTMode,
1010
frame::KKTFrame,
1111
key_utils::{generate_keypair_libcrux, generate_keypair_mceliece, hash_encapsulation_key},

common/nym-kkt/src/ciphersuite.rs

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -157,16 +157,6 @@ impl Ciphersuite {
157157
self.hash_length as usize
158158
}
159159

160-
pub fn default() -> Self {
161-
Self::resolve_ciphersuite(
162-
KEM::XWing,
163-
HashFunction::Blake3,
164-
SignatureScheme::Ed25519,
165-
None,
166-
)
167-
.unwrap()
168-
}
169-
170160
pub fn resolve_ciphersuite(
171161
kem: KEM,
172162
hash_function: HashFunction,
@@ -185,9 +175,9 @@ impl Ciphersuite {
185175
None => HASH_LEN_256,
186176
};
187177
Ok(Self {
188-
hash_function: hash_function,
189-
signature_scheme: signature_scheme,
190-
kem: kem,
178+
hash_function,
179+
signature_scheme,
180+
kem,
191181
hash_length: hash_len,
192182
encapsulation_key_length: match kem {
193183
// 1184 bytes
@@ -230,7 +220,7 @@ impl Ciphersuite {
230220
},
231221
match self.hash_length {
232222
HASH_LEN_256 => 0,
233-
_ => self.hash_length as u8,
223+
_ => self.hash_length,
234224
},
235225
match self.signature_scheme {
236226
SignatureScheme::Ed25519 => 0,
@@ -247,7 +237,7 @@ impl Ciphersuite {
247237
_ => {
248238
return Err(KKTError::CiphersuiteDecodingError {
249239
info: format!("Undefined KEM: {}", encoding[0]),
250-
})
240+
});
251241
}
252242
};
253243
let hash_function = match encoding[1] {
@@ -258,7 +248,7 @@ impl Ciphersuite {
258248
_ => {
259249
return Err(KKTError::CiphersuiteDecodingError {
260250
info: format!("Undefined Hash Function: {}", encoding[1]),
261-
})
251+
});
262252
}
263253
};
264254

@@ -272,19 +262,19 @@ impl Ciphersuite {
272262
_ => {
273263
return Err(KKTError::CiphersuiteDecodingError {
274264
info: format!("Undefined Signature Scheme: {}", encoding[3]),
275-
})
265+
});
276266
}
277267
};
278268

279269
Self::resolve_ciphersuite(kem, hash_function, signature_scheme, custom_hash_length)
280270
} else {
281-
return Err(KKTError::CiphersuiteDecodingError {
271+
Err(KKTError::CiphersuiteDecodingError {
282272
info: format!(
283273
"Incorrect Encoding Length: actual: {} != expected: {}",
284274
encoding.len(),
285275
CIPHERSUITE_ENCODING_LEN
286276
),
287-
});
277+
})
288278
}
289279
}
290280
}
@@ -306,6 +296,6 @@ pub const fn map_kem_to_libcrux_kem(kem: KEM) -> Algorithm {
306296
KEM::MlKem768 => Algorithm::MlKem768,
307297
KEM::XWing => Algorithm::XWingKemDraft06,
308298
KEM::X25519 => Algorithm::X25519,
309-
_ => unreachable!(),
299+
KEM::McEliece => panic!("McEliece is not supported in libcrux_kem"),
310300
}
311301
}

common/nym-kkt/src/context.rs

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
use std::fmt::Display;
55

6-
use crate::{ciphersuite::Ciphersuite, error::KKTError, frame::KKT_SESSION_ID_LEN, KKT_VERSION};
6+
use crate::{KKT_VERSION, ciphersuite::Ciphersuite, error::KKTError, frame::KKT_SESSION_ID_LEN};
77

88
pub const KKT_CONTEXT_LEN: usize = 7;
99

@@ -66,14 +66,14 @@ impl KKTContext {
6666
version: KKT_VERSION,
6767
message_sequence: 0,
6868
status: KKTStatus::Ok,
69-
mode: mode,
70-
role: role,
71-
ciphersuite: ciphersuite,
69+
mode,
70+
role,
71+
ciphersuite,
7272
})
7373
}
7474

7575
pub fn derive_responder_header(&self) -> Result<Self, KKTError> {
76-
let mut responder_header = self.clone();
76+
let mut responder_header = *self;
7777

7878
responder_header.increment_message_sequence_count()?;
7979
responder_header.role = KKTRole::Responder;
@@ -155,16 +155,16 @@ impl KKTContext {
155155
header_bytes.push(
156156
match self.status {
157157
KKTStatus::Ok => 0,
158-
KKTStatus::InvalidRequestFormat => 0b001_000_00,
159-
KKTStatus::InvalidResponseFormat => 0b010_000_00,
160-
KKTStatus::InvalidSignature => 0b011_000_00,
161-
KKTStatus::UnsupportedCiphersuite => 0b100_000_00,
162-
KKTStatus::UnsupportedKKTVersion => 0b101_000_00,
163-
KKTStatus::InvalidKey => 0b110_000_00,
164-
KKTStatus::Timeout => 0b111_000_00,
158+
KKTStatus::InvalidRequestFormat => 0b0010_0000,
159+
KKTStatus::InvalidResponseFormat => 0b0100_0000,
160+
KKTStatus::InvalidSignature => 0b0110_0000,
161+
KKTStatus::UnsupportedCiphersuite => 0b1000_0000,
162+
KKTStatus::UnsupportedKKTVersion => 0b1010_0000,
163+
KKTStatus::InvalidKey => 0b1100_0000,
164+
KKTStatus::Timeout => 0b1110_0000,
165165
} + match self.mode {
166166
KKTMode::OneWay => 0,
167-
KKTMode::Mutual => 0b000_001_00,
167+
KKTMode::Mutual => 0b0000_0100,
168168
} + match self.role {
169169
KKTRole::Initiator => 0,
170170
KKTRole::Responder => 1,
@@ -191,57 +191,57 @@ impl KKTContext {
191191
});
192192
}
193193

194-
let status = match header_bytes[1] & 0b111_000_00 {
194+
let status = match header_bytes[1] & 0b1110_0000 {
195195
0 => KKTStatus::Ok,
196-
0b001_000_00 => KKTStatus::InvalidRequestFormat,
197-
0b010_000_00 => KKTStatus::InvalidResponseFormat,
198-
0b011_000_00 => KKTStatus::InvalidSignature,
199-
0b100_000_00 => KKTStatus::UnsupportedCiphersuite,
200-
0b101_000_00 => KKTStatus::UnsupportedKKTVersion,
201-
0b110_000_00 => KKTStatus::InvalidKey,
202-
0b111_000_00 => KKTStatus::Timeout,
196+
0b0010_0000 => KKTStatus::InvalidRequestFormat,
197+
0b0100_0000 => KKTStatus::InvalidResponseFormat,
198+
0b0110_0000 => KKTStatus::InvalidSignature,
199+
0b1000_0000 => KKTStatus::UnsupportedCiphersuite,
200+
0b1010_0000 => KKTStatus::UnsupportedKKTVersion,
201+
0b1100_0000 => KKTStatus::InvalidKey,
202+
0b1110_0000 => KKTStatus::Timeout,
203203
_ => {
204204
return Err(KKTError::FrameDecodingError {
205205
info: format!(
206206
"Header - Invalid KKT Status: {}",
207-
header_bytes[1] & 0b111_000_00
207+
header_bytes[1] & 0b1110_0000
208208
),
209-
})
209+
});
210210
}
211211
};
212212

213-
let role = match header_bytes[1] & 0b000_000_11 {
213+
let role = match header_bytes[1] & 0b0000_0011 {
214214
0 => KKTRole::Initiator,
215215
1 => KKTRole::Responder,
216216
2 => KKTRole::AnonymousInitiator,
217217
_ => {
218218
return Err(KKTError::FrameDecodingError {
219219
info: format!(
220220
"Header - Invalid KKT Role: {}",
221-
header_bytes[1] & 0b000_000_11
221+
header_bytes[1] & 0b0000_0011
222222
),
223-
})
223+
});
224224
}
225225
};
226226

227-
let mode = match (header_bytes[1] & 0b000_111_00) >> 2 {
227+
let mode = match (header_bytes[1] & 0b0001_1100) >> 2 {
228228
0 => KKTMode::OneWay,
229229
1 => KKTMode::Mutual,
230230
_ => {
231231
return Err(KKTError::FrameDecodingError {
232232
info: format!(
233233
"Header - Invalid KKT Mode: {}",
234-
(header_bytes[1] & 0b000_111_00) >> 2
234+
(header_bytes[1] & 0b0001_1100) >> 2
235235
),
236-
})
236+
});
237237
}
238238
};
239239

240240
Ok(KKTContext {
241241
version: kkt_version,
242-
status: status,
243-
mode: mode,
244-
role: role,
242+
status,
243+
mode,
244+
role,
245245
ciphersuite: Ciphersuite::decode(&header_bytes[2..6])?,
246246
message_sequence: message_sequence_counter,
247247
})

common/nym-kkt/src/error.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,9 @@ pub enum KKTError {
3939

4040
#[error("{}", info)]
4141
X25519Error { info: &'static str },
42-
// #[error("Protocol did not complete")]
43-
// ProtocolError,
4442

45-
// #[error("encountered an IO error: {0}")]
46-
// IoError(#[from] io::Error),s
47-
48-
// #[error("Handshake timeout")]
49-
// HandshakeTimeout(#[from] tokio::time::error::Elapsed),
43+
#[error("Generic libcrux error")]
44+
LibcruxError,
5045
}
5146

5247
impl From<libcrux_kem::Error> for KKTError {
@@ -84,7 +79,7 @@ impl From<libcrux_ecdh::Error> for KKTError {
8479
libcrux_ecdh::Error::InvalidPoint => KKTError::KEMError {
8580
info: "Invalid Remote Public Key",
8681
},
87-
_ => todo!(),
82+
_ => KKTError::LibcruxError,
8883
}
8984
}
9085
}

common/nym-kkt/src/frame.rs

Lines changed: 12 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,8 @@
77
// [2..=5] => Ciphersuite
88
// [6] => Reserved
99

10-
use nym_crypto::asymmetric::x25519::PublicKey;
11-
1210
use crate::{
13-
context::{KKTContext, KKT_CONTEXT_LEN},
11+
context::{KKT_CONTEXT_LEN, KKTContext},
1412
error::KKTError,
1513
};
1614

@@ -37,27 +35,27 @@ impl KKTFrame {
3735
signature: Vec::from(signature),
3836
}
3937
}
40-
pub fn context_ref<'a>(&'a self) -> &'a [u8] {
38+
pub fn context_ref(&self) -> &[u8] {
4139
&self.context
4240
}
43-
pub fn signature_ref<'a>(&'a self) -> &'a [u8] {
41+
pub fn signature_ref(&self) -> &[u8] {
4442
&self.signature
4543
}
46-
pub fn body_ref<'a>(&'a self) -> &'a [u8] {
44+
pub fn body_ref(&self) -> &[u8] {
4745
&self.body
4846
}
4947

50-
pub fn session_id_ref<'a>(&'a self) -> &'a [u8] {
48+
pub fn session_id_ref(&self) -> &[u8] {
5149
&self.session_id
5250
}
53-
pub fn signature_mut<'a>(&'a mut self) -> &'a mut [u8] {
51+
pub fn signature_mut(&mut self) -> &mut [u8] {
5452
&mut self.signature
5553
}
56-
pub fn body_mut<'a>(&'a mut self) -> &'a mut [u8] {
54+
pub fn body_mut(&mut self) -> &mut [u8] {
5755
&mut self.body
5856
}
5957

60-
pub fn session_id_mut<'a>(&'a mut self) -> &'a mut [u8] {
58+
pub fn session_id_mut(&mut self) -> &mut [u8] {
6159
&mut self.session_id
6260
}
6361

@@ -76,13 +74,13 @@ impl KKTFrame {
7674

7775
pub fn from_bytes(bytes: &[u8]) -> Result<(Self, KKTContext), KKTError> {
7876
if bytes.len() < KKT_CONTEXT_LEN {
79-
return Err(KKTError::FrameDecodingError {
77+
Err(KKTError::FrameDecodingError {
8078
info: format!(
8179
"Frame is shorter than expected context length: actual {} != expected {}",
8280
bytes.len(),
8381
KKT_CONTEXT_LEN
8482
),
85-
});
83+
})
8684
} else {
8785
let context_bytes = Vec::from(&bytes[0..KKT_CONTEXT_LEN]);
8886

@@ -118,29 +116,14 @@ impl KKTFrame {
118116
context,
119117
))
120118
} else {
121-
return Err(KKTError::FrameDecodingError {
119+
Err(KKTError::FrameDecodingError {
122120
info: format!(
123121
"Frame is shorter than expected: actual {} != expected {}",
124122
bytes.len(),
125123
context.full_message_len()
126124
),
127-
});
125+
})
128126
}
129127
}
130128
}
131129
}
132-
133-
pub struct EncryptedKKTRequest {
134-
ephermeral_key: PublicKey,
135-
body: Vec<u8>,
136-
}
137-
impl EncryptedKKTRequest {
138-
pub fn to_bytes(mut self) -> Vec<u8> {
139-
self.body.extend(self.ephermeral_key.to_bytes());
140-
self.body
141-
}
142-
}
143-
144-
pub struct EncryptedKKTResponse {
145-
body: Vec<u8>,
146-
}

common/nym-kkt/src/key_utils.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::{
44
};
55

66
use classic_mceliece_rust::keypair_boxed;
7-
use libcrux_kem::{key_gen, Algorithm};
7+
use libcrux_kem::{Algorithm, key_gen};
88

99
use libcrux_sha3;
1010
use rand::{CryptoRng, RngCore};
@@ -55,13 +55,13 @@ pub fn hash_key_bytes(
5555
hasher.reset();
5656
}
5757
HashFunction::SHAKE256 => {
58-
libcrux_sha3::shake256_ema(&mut hashed_key, &key_bytes);
58+
libcrux_sha3::shake256_ema(&mut hashed_key, key_bytes);
5959
}
6060
HashFunction::SHAKE128 => {
61-
libcrux_sha3::shake128_ema(&mut hashed_key, &key_bytes);
61+
libcrux_sha3::shake128_ema(&mut hashed_key, key_bytes);
6262
}
6363
HashFunction::SHA256 => {
64-
libcrux_sha3::sha256_ema(&mut hashed_key, &key_bytes);
64+
libcrux_sha3::sha256_ema(&mut hashed_key, key_bytes);
6565
}
6666
}
6767

@@ -103,5 +103,5 @@ pub fn hash_encapsulation_key(
103103
hash_length: usize,
104104
encapsulation_key: &[u8],
105105
) -> Vec<u8> {
106-
hash_key_bytes(hash_function, hash_length, &encapsulation_key)
106+
hash_key_bytes(hash_function, hash_length, encapsulation_key)
107107
}

0 commit comments

Comments
 (0)