1use crate::encryption::{decrypt, encrypt};
38use crate::signing::{KeyPair, PublicKey};
39use blake3;
40use rand::RngCore;
41use serde::{Deserialize, Serialize};
42use thiserror::Error;
43
44#[derive(Debug, Error)]
46pub enum OnionError {
47 #[error("No layers to build onion")]
48 NoLayers,
49
50 #[error("Encryption failed")]
51 EncryptionFailed,
52
53 #[error("Decryption failed - invalid key or corrupted data")]
54 DecryptionFailed,
55
56 #[error("Serialization error: {0}")]
57 SerializationError(String),
58
59 #[error("Invalid onion structure")]
60 InvalidStructure,
61}
62
63pub type OnionResult<T> = Result<T, OnionError>;
64
65#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct OnionPacket {
71 ciphertext: Vec<u8>,
73 nonce: [u8; 12],
75 ephemeral_hint: [u8; 32],
77}
78
79impl OnionPacket {
80 pub fn data(&self) -> &[u8] {
82 &self.ciphertext
83 }
84
85 pub fn to_bytes(&self) -> OnionResult<Vec<u8>> {
87 crate::codec::encode(self).map_err(|e| OnionError::SerializationError(e.to_string()))
88 }
89
90 pub fn from_bytes(bytes: &[u8]) -> OnionResult<Self> {
92 crate::codec::decode(bytes).map_err(|e| OnionError::SerializationError(e.to_string()))
93 }
94
95 pub fn peel_layer(&self, keypair: &KeyPair) -> OnionResult<(OnionLayer, Option<OnionPacket>)> {
101 let mut hasher = blake3::Hasher::new();
104 hasher.update(b"CHIE-ONION-V1");
105 hasher.update(&keypair.public_key());
106 hasher.update(&self.ephemeral_hint);
107 let decryption_key = *hasher.finalize().as_bytes();
108
109 let decrypted = decrypt(&self.ciphertext, &decryption_key, &self.nonce)
111 .map_err(|_| OnionError::DecryptionFailed)?;
112
113 let payload: OnionLayerPayload =
115 crate::codec::decode(&decrypted).map_err(|_| OnionError::InvalidStructure)?;
116
117 match payload {
118 OnionLayerPayload::Intermediate {
119 next_hop,
120 next_packet,
121 } => Ok((OnionLayer::Intermediate { next_hop }, Some(next_packet))),
122 OnionLayerPayload::Final { data } => Ok((
123 OnionLayer::Final,
124 Some(OnionPacket {
125 ciphertext: data,
126 nonce: [0; 12],
127 ephemeral_hint: [0; 32],
128 }),
129 )),
130 }
131 }
132}
133
134#[derive(Debug, Clone)]
136pub enum OnionLayer {
137 Intermediate {
139 next_hop: PublicKey,
141 },
142 Final,
144}
145
146#[derive(Debug, Clone, Serialize, Deserialize)]
148enum OnionLayerPayload {
149 Intermediate {
151 next_hop: PublicKey,
152 next_packet: OnionPacket,
153 },
154 Final { data: Vec<u8> },
156}
157
158pub struct OnionBuilder {
160 data: Vec<u8>,
161 layers: Vec<PublicKey>,
162}
163
164impl OnionBuilder {
165 pub fn new(data: &[u8]) -> Self {
167 Self {
168 data: data.to_vec(),
169 layers: Vec::new(),
170 }
171 }
172
173 pub fn add_layer(mut self, pubkey: PublicKey) -> Self {
178 self.layers.push(pubkey);
179 self
180 }
181
182 pub fn add_layers(mut self, pubkeys: &[PublicKey]) -> Self {
184 self.layers.extend_from_slice(pubkeys);
185 self
186 }
187
188 pub fn build(self) -> OnionResult<OnionPacket> {
190 if self.layers.is_empty() {
191 return Err(OnionError::NoLayers);
192 }
193
194 let mut current_payload = OnionLayerPayload::Final { data: self.data };
196
197 for (i, pubkey) in self.layers.iter().enumerate() {
200 let payload_bytes = crate::codec::encode(¤t_payload)
202 .map_err(|e| OnionError::SerializationError(e.to_string()))?;
203
204 let mut ephemeral_hint = [0u8; 32];
206 rand::thread_rng().fill_bytes(&mut ephemeral_hint);
207
208 let mut hasher = blake3::Hasher::new();
210 hasher.update(b"CHIE-ONION-V1");
211 hasher.update(pubkey);
212 hasher.update(&ephemeral_hint);
213 let encryption_key = *hasher.finalize().as_bytes();
214
215 let mut nonce = [0u8; 12];
217 rand::thread_rng().fill_bytes(&mut nonce);
218
219 let ciphertext = encrypt(&payload_bytes, &encryption_key, &nonce)
221 .map_err(|_| OnionError::EncryptionFailed)?;
222
223 let packet = OnionPacket {
224 ciphertext,
225 nonce,
226 ephemeral_hint,
227 };
228
229 if i == self.layers.len() - 1 {
231 return Ok(packet);
232 }
233
234 current_payload = OnionLayerPayload::Intermediate {
237 next_hop: *pubkey,
238 next_packet: packet,
239 };
240 }
241
242 Err(OnionError::InvalidStructure)
243 }
244}
245
246pub struct OnionRoute {
248 path: Vec<PublicKey>,
250}
251
252impl OnionRoute {
253 pub fn new(path: Vec<PublicKey>) -> Self {
255 Self { path }
256 }
257
258 pub fn length(&self) -> usize {
260 self.path.len()
261 }
262
263 pub fn path(&self) -> &[PublicKey] {
265 &self.path
266 }
267
268 pub fn encrypt(&self, data: &[u8]) -> OnionResult<OnionPacket> {
270 let mut builder = OnionBuilder::new(data);
271 for pubkey in &self.path {
272 builder = builder.add_layer(*pubkey);
273 }
274 builder.build()
275 }
276}
277
278pub fn create_onion(data: &[u8], path: &[PublicKey]) -> OnionResult<OnionPacket> {
282 let mut builder = OnionBuilder::new(data);
283 for pubkey in path {
284 builder = builder.add_layer(*pubkey);
285 }
286 builder.build()
287}
288
289#[cfg(test)]
290mod tests {
291 use super::*;
292 use crate::signing::KeyPair;
293
294 #[test]
295 fn test_onion_single_layer() {
296 let data = b"Single layer test";
297 let keypair = KeyPair::generate();
298
299 let onion = OnionBuilder::new(data)
300 .add_layer(keypair.public_key())
301 .build()
302 .unwrap();
303
304 let (layer, next) = onion.peel_layer(&keypair).unwrap();
305 assert!(matches!(layer, OnionLayer::Final));
306
307 let final_data = next.unwrap();
308 assert_eq!(data, &final_data.ciphertext[..]);
309 }
310
311 #[test]
312 fn test_onion_two_layers() {
313 let data = b"Two layer test";
314 let keypair1 = KeyPair::generate();
315 let keypair2 = KeyPair::generate();
316
317 let onion = OnionBuilder::new(data)
318 .add_layer(keypair1.public_key())
319 .add_layer(keypair2.public_key())
320 .build()
321 .unwrap();
322
323 let (layer1, next1) = onion.peel_layer(&keypair2).unwrap();
325 if let OnionLayer::Intermediate { next_hop } = layer1 {
326 assert_eq!(next_hop, keypair1.public_key());
327 } else {
328 panic!("Expected intermediate layer");
329 }
330
331 let onion2 = next1.unwrap();
333 let (layer2, final_data) = onion2.peel_layer(&keypair1).unwrap();
334 assert!(matches!(layer2, OnionLayer::Final));
335
336 let data_packet = final_data.unwrap();
337 assert_eq!(data, &data_packet.ciphertext[..]);
338 }
339
340 #[test]
341 fn test_onion_three_layers() {
342 let data = b"Three layer test message";
343 let keypair1 = KeyPair::generate();
344 let keypair2 = KeyPair::generate();
345 let keypair3 = KeyPair::generate();
346
347 let onion = OnionBuilder::new(data)
348 .add_layer(keypair1.public_key())
349 .add_layer(keypair2.public_key())
350 .add_layer(keypair3.public_key())
351 .build()
352 .unwrap();
353
354 let (layer3, next3) = onion.peel_layer(&keypair3).unwrap();
356 if let OnionLayer::Intermediate { next_hop } = layer3 {
357 assert_eq!(next_hop, keypair2.public_key());
358 } else {
359 panic!("Expected intermediate layer");
360 }
361
362 let onion2 = next3.unwrap();
364 let (layer2, next2) = onion2.peel_layer(&keypair2).unwrap();
365 if let OnionLayer::Intermediate { next_hop } = layer2 {
366 assert_eq!(next_hop, keypair1.public_key());
367 } else {
368 panic!("Expected intermediate layer");
369 }
370
371 let onion1 = next2.unwrap();
373 let (layer1, final_data) = onion1.peel_layer(&keypair1).unwrap();
374 assert!(matches!(layer1, OnionLayer::Final));
375
376 let data_packet = final_data.unwrap();
377 assert_eq!(data, &data_packet.ciphertext[..]);
378 }
379
380 #[test]
381 fn test_onion_wrong_key() {
382 let data = b"Test data";
383 let keypair1 = KeyPair::generate();
384 let keypair2 = KeyPair::generate();
385 let wrong_keypair = KeyPair::generate();
386
387 let onion = OnionBuilder::new(data)
388 .add_layer(keypair1.public_key())
389 .add_layer(keypair2.public_key())
390 .build()
391 .unwrap();
392
393 let result = onion.peel_layer(&wrong_keypair);
395 assert!(matches!(result, Err(OnionError::DecryptionFailed)));
396 }
397
398 #[test]
399 fn test_onion_no_layers() {
400 let data = b"Test";
401 let result = OnionBuilder::new(data).build();
402 assert!(matches!(result, Err(OnionError::NoLayers)));
403 }
404
405 #[test]
406 fn test_onion_serialization() {
407 let data = b"Serialization test";
408 let keypair1 = KeyPair::generate();
409 let keypair2 = KeyPair::generate();
410
411 let onion = OnionBuilder::new(data)
412 .add_layer(keypair1.public_key())
413 .add_layer(keypair2.public_key())
414 .build()
415 .unwrap();
416
417 let bytes = onion.to_bytes().unwrap();
419 let deserialized = OnionPacket::from_bytes(&bytes).unwrap();
420
421 let (_, next) = deserialized.peel_layer(&keypair2).unwrap();
423 let onion2 = next.unwrap();
424 let (_, final_data) = onion2.peel_layer(&keypair1).unwrap();
425
426 assert_eq!(data, &final_data.unwrap().ciphertext[..]);
427 }
428
429 #[test]
430 fn test_onion_route() {
431 let data = b"Route test";
432 let keypair1 = KeyPair::generate();
433 let keypair2 = KeyPair::generate();
434 let keypair3 = KeyPair::generate();
435
436 let path = vec![
437 keypair1.public_key(),
438 keypair2.public_key(),
439 keypair3.public_key(),
440 ];
441
442 let route = OnionRoute::new(path.clone());
443 assert_eq!(route.length(), 3);
444 assert_eq!(route.path(), &path[..]);
445
446 let onion = route.encrypt(data).unwrap();
447
448 let (_, next) = onion.peel_layer(&keypair3).unwrap();
450 let (_, next) = next.unwrap().peel_layer(&keypair2).unwrap();
451 let (_, final_data) = next.unwrap().peel_layer(&keypair1).unwrap();
452
453 assert_eq!(data, &final_data.unwrap().ciphertext[..]);
454 }
455
456 #[test]
457 fn test_create_onion_convenience() {
458 let data = b"Convenience function test";
459 let keypair1 = KeyPair::generate();
460 let keypair2 = KeyPair::generate();
461
462 let path = vec![keypair1.public_key(), keypair2.public_key()];
463
464 let onion = create_onion(data, &path).unwrap();
465
466 let (_, next) = onion.peel_layer(&keypair2).unwrap();
467 let (_, final_data) = next.unwrap().peel_layer(&keypair1).unwrap();
468
469 assert_eq!(data, &final_data.unwrap().ciphertext[..]);
470 }
471
472 #[test]
473 fn test_large_data() {
474 let data = vec![0x42u8; 10_000]; let keypair1 = KeyPair::generate();
476 let keypair2 = KeyPair::generate();
477
478 let onion = OnionBuilder::new(&data)
479 .add_layer(keypair1.public_key())
480 .add_layer(keypair2.public_key())
481 .build()
482 .unwrap();
483
484 let (_, next) = onion.peel_layer(&keypair2).unwrap();
485 let (_, final_data) = next.unwrap().peel_layer(&keypair1).unwrap();
486
487 assert_eq!(data, final_data.unwrap().ciphertext);
488 }
489
490 #[test]
491 fn test_add_layers_batch() {
492 let data = b"Batch layers test";
493 let keypairs: Vec<KeyPair> = (0..5).map(|_| KeyPair::generate()).collect();
494 let pubkeys: Vec<PublicKey> = keypairs.iter().map(|kp| kp.public_key()).collect();
495
496 let onion = OnionBuilder::new(data)
497 .add_layers(&pubkeys)
498 .build()
499 .unwrap();
500
501 let mut current = Some(onion);
503 for keypair in keypairs.iter().rev() {
504 if let Some(pkt) = current {
505 let (_, next) = pkt.peel_layer(keypair).unwrap();
506 current = next;
507 }
508 }
509
510 let final_data = current.unwrap();
511 assert_eq!(data, &final_data.ciphertext[..]);
512 }
513}