1use alloc::borrow::ToOwned;
2use alloc::string::{String, ToString};
3use alloc::vec::Vec;
4
5use bech32::primitives::decode::CheckedHrpstring;
6use bech32::{Bech32m, Hrp};
7
8use crate::address::AddressInterface;
9use crate::crypto::dsa::{ecdsa_k256_keccak, eddsa_25519_sha512};
10use crate::crypto::ies::SealingKey;
11use crate::errors::{AddressError, Bech32Error};
12use crate::note::NoteTag;
13use crate::utils::serde::{
14 ByteReader,
15 ByteWriter,
16 Deserializable,
17 DeserializationError,
18 Serializable,
19};
20use crate::utils::sync::LazyLock;
21
22static ROUTING_PARAMETERS_HRP: LazyLock<Hrp> =
29 LazyLock::new(|| Hrp::parse("mrp").expect("hrp should be valid"));
30
31const BECH32_SEPARATOR: &str = "1";
33
34const ABSENT_NOTE_TAG_LEN: u8 = 63;
42
43const RECEIVER_PROFILE_PARAM_KEY: u8 = 0;
45
46const ENCRYPTION_KEY_PARAM_KEY: u8 = 1;
48
49const X25519_PUBLIC_KEY_LENGTH: usize = 32;
51
52const K256_PUBLIC_KEY_LENGTH: usize = 33;
54
55const ENCRYPTION_KEY_X25519_XCHACHA20POLY1305: u8 = 0;
57const ENCRYPTION_KEY_K256_XCHACHA20POLY1305: u8 = 1;
58const ENCRYPTION_KEY_X25519_AEAD_POSEIDON2: u8 = 2;
59const ENCRYPTION_KEY_K256_AEAD_POSEIDON2: u8 = 3;
60const ENCRYPTION_KEY_X25519_AEAD_EIDOS: u8 = 4;
61const ENCRYPTION_KEY_K256_AEAD_EIDOS: u8 = 5;
62
63#[derive(Debug, Clone, PartialEq, Eq)]
66pub struct RoutingParameters {
67 interface: AddressInterface,
68 note_tag_len: Option<u8>,
69 encryption_key: Option<SealingKey>,
70}
71
72impl RoutingParameters {
73 pub fn new(interface: AddressInterface) -> Self {
79 Self {
80 interface,
81 note_tag_len: None,
82 encryption_key: None,
83 }
84 }
85
86 pub fn with_note_tag_len(mut self, note_tag_len: u8) -> Result<Self, AddressError> {
99 if note_tag_len > NoteTag::MAX_ACCOUNT_TARGET_TAG_LENGTH {
100 return Err(AddressError::TagLengthTooLarge(note_tag_len));
101 }
102
103 self.note_tag_len = Some(note_tag_len);
104 Ok(self)
105 }
106
107 pub fn note_tag_len(&self) -> Option<u8> {
115 self.note_tag_len
116 }
117
118 pub fn interface(&self) -> AddressInterface {
120 self.interface
121 }
122
123 pub fn encryption_key(&self) -> Option<&SealingKey> {
125 self.encryption_key.as_ref()
126 }
127
128 pub fn with_encryption_key(mut self, key: SealingKey) -> Self {
133 self.encryption_key = Some(key);
134 self
135 }
136
137 pub(crate) fn encode_to_bytes(&self) -> Vec<u8> {
142 let mut encoded = Vec::new();
143
144 encoded.push(RECEIVER_PROFILE_PARAM_KEY);
146 encoded.extend(encode_receiver_profile(self.interface, self.note_tag_len));
147
148 if let Some(encryption_key) = &self.encryption_key {
150 encoded.push(ENCRYPTION_KEY_PARAM_KEY);
151 encode_encryption_key(encryption_key, &mut encoded);
152 }
153
154 encoded
155 }
156
157 pub(crate) fn encode_to_string(&self) -> String {
159 let encoded = self.encode_to_bytes();
160
161 let bech32_str =
162 bech32::encode::<Bech32m>(*ROUTING_PARAMETERS_HRP, &encoded).expect("TODO");
163 let encoded_str = bech32_str
164 .strip_prefix(ROUTING_PARAMETERS_HRP.as_str())
165 .expect("bech32 str should start with the hrp");
166 let encoded_str = encoded_str
167 .strip_prefix(BECH32_SEPARATOR)
168 .expect("encoded str should start with bech32 separator `1`");
169 encoded_str.to_owned()
170 }
171
172 pub(crate) fn decode(mut bech32_string: String) -> Result<Self, AddressError> {
174 bech32_string.insert_str(0, BECH32_SEPARATOR);
178 bech32_string.insert_str(0, ROUTING_PARAMETERS_HRP.as_str());
179
180 let checked_string =
183 CheckedHrpstring::new::<Bech32m>(&bech32_string).map_err(|source| {
184 AddressError::decode_error_with_source(
189 "failed to decode routing parameters bech32 string",
190 Bech32Error::DecodeError(source.to_string().into()),
191 )
192 })?;
193
194 Self::decode_from_bytes(checked_string.byte_iter())
195 }
196
197 pub(crate) fn decode_from_bytes(
199 mut byte_iter: impl ExactSizeIterator<Item = u8>,
200 ) -> Result<Self, AddressError> {
201 let mut interface = None;
202 let mut note_tag_len = None;
203 let mut encryption_key = None;
204
205 while let Some(key) = byte_iter.next() {
206 match key {
207 RECEIVER_PROFILE_PARAM_KEY => {
208 if interface.is_some() {
209 return Err(AddressError::decode_error(
210 "duplicate receiver profile routing parameter",
211 ));
212 }
213 let receiver_profile = decode_receiver_profile(&mut byte_iter)?;
214 interface = Some(receiver_profile.0);
215 note_tag_len = receiver_profile.1;
216 },
217 ENCRYPTION_KEY_PARAM_KEY => {
218 if encryption_key.is_some() {
219 return Err(AddressError::decode_error(
220 "duplicate encryption key routing parameter",
221 ));
222 }
223 encryption_key = Some(decode_encryption_key(&mut byte_iter)?);
224 },
225 other => {
226 return Err(AddressError::UnknownRoutingParameterKey(other));
227 },
228 }
229 }
230
231 let interface = interface.ok_or_else(|| {
232 AddressError::decode_error("interface must be present in routing parameters")
233 })?;
234
235 let mut routing_parameters = RoutingParameters::new(interface);
236 routing_parameters.note_tag_len = note_tag_len;
237 routing_parameters.encryption_key = encryption_key;
238
239 Ok(routing_parameters)
240 }
241}
242
243impl Serializable for RoutingParameters {
244 fn write_into<W: ByteWriter>(&self, target: &mut W) {
245 let bytes = self.encode_to_bytes();
246 let num_bytes = bytes.len() as u16;
248
249 target.write_u16(num_bytes);
250 target.write_many(bytes);
251 }
252}
253
254impl Deserializable for RoutingParameters {
255 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
256 let num_bytes = source.read_u16()?;
257 let bytes: Vec<u8> =
258 source.read_many_iter(num_bytes as usize)?.collect::<Result<_, _>>()?;
259
260 Self::decode_from_bytes(bytes.into_iter())
261 .map_err(|err| DeserializationError::InvalidValue(err.to_string()))
262 }
263}
264
265fn encode_receiver_profile(interface: AddressInterface, note_tag_len: Option<u8>) -> [u8; 2] {
270 let note_tag_len = note_tag_len.unwrap_or(ABSENT_NOTE_TAG_LEN);
271
272 let interface = interface as u16;
273 debug_assert_eq!(interface >> 10, 0, "address interface should fit into 10 bits");
274
275 let tag_len = (note_tag_len as u16) << 10;
278 let receiver_profile: u16 = tag_len | interface;
279 receiver_profile.to_be_bytes()
280}
281
282fn decode_receiver_profile(
284 byte_iter: &mut impl ExactSizeIterator<Item = u8>,
285) -> Result<(AddressInterface, Option<u8>), AddressError> {
286 if byte_iter.len() < 2 {
287 return Err(AddressError::decode_error("expected two bytes to decode receiver profile"));
288 };
289
290 let byte0 = byte_iter.next().expect("byte0 should exist");
291 let byte1 = byte_iter.next().expect("byte1 should exist");
292 let receiver_profile = u16::from_be_bytes([byte0, byte1]);
293
294 let tag_len = (receiver_profile >> 10) as u8;
295 let note_tag_len = match tag_len {
296 ABSENT_NOTE_TAG_LEN => None,
297 0..=32 => Some(tag_len),
298 _ => {
299 return Err(AddressError::decode_error(format!("invalid note tag length {}", tag_len)));
300 },
301 };
302
303 let addr_interface = receiver_profile & 0b0000_0011_1111_1111;
304 let addr_interface = AddressInterface::try_from(addr_interface).map_err(|err| {
305 AddressError::decode_error_with_source("failed to decode address interface", err)
306 })?;
307
308 Ok((addr_interface, note_tag_len))
309}
310
311fn encode_encryption_key(key: &SealingKey, encoded: &mut Vec<u8>) {
313 match key {
314 SealingKey::X25519XChaCha20Poly1305(pk) => {
315 encoded.push(ENCRYPTION_KEY_X25519_XCHACHA20POLY1305);
316 encoded.extend(&pk.to_bytes());
317 },
318 SealingKey::K256XChaCha20Poly1305(pk) => {
319 encoded.push(ENCRYPTION_KEY_K256_XCHACHA20POLY1305);
320 encoded.extend(&pk.to_bytes());
321 },
322 SealingKey::X25519AeadPoseidon2(pk) => {
323 encoded.push(ENCRYPTION_KEY_X25519_AEAD_POSEIDON2);
324 encoded.extend(&pk.to_bytes());
325 },
326 SealingKey::K256AeadPoseidon2(pk) => {
327 encoded.push(ENCRYPTION_KEY_K256_AEAD_POSEIDON2);
328 encoded.extend(&pk.to_bytes());
329 },
330 SealingKey::X25519AeadEidos(pk) => {
331 encoded.push(ENCRYPTION_KEY_X25519_AEAD_EIDOS);
332 encoded.extend(&pk.to_bytes());
333 },
334 SealingKey::K256AeadEidos(pk) => {
335 encoded.push(ENCRYPTION_KEY_K256_AEAD_EIDOS);
336 encoded.extend(&pk.to_bytes());
337 },
338 }
339}
340
341fn decode_encryption_key(
343 byte_iter: &mut impl ExactSizeIterator<Item = u8>,
344) -> Result<SealingKey, AddressError> {
345 let Some(variant) = byte_iter.next() else {
347 return Err(AddressError::decode_error(
348 "expected at least 1 byte for encryption key variant",
349 ));
350 };
351
352 let public_encryption_key = match variant {
354 ENCRYPTION_KEY_X25519_XCHACHA20POLY1305 => {
355 SealingKey::X25519XChaCha20Poly1305(read_x25519_pub_key(byte_iter)?)
356 },
357 ENCRYPTION_KEY_K256_XCHACHA20POLY1305 => {
358 SealingKey::K256XChaCha20Poly1305(read_k256_pub_key(byte_iter)?)
359 },
360 ENCRYPTION_KEY_X25519_AEAD_POSEIDON2 => {
361 SealingKey::X25519AeadPoseidon2(read_x25519_pub_key(byte_iter)?)
362 },
363 ENCRYPTION_KEY_K256_AEAD_POSEIDON2 => {
364 SealingKey::K256AeadPoseidon2(read_k256_pub_key(byte_iter)?)
365 },
366 ENCRYPTION_KEY_X25519_AEAD_EIDOS => {
367 SealingKey::X25519AeadEidos(read_x25519_pub_key(byte_iter)?)
368 },
369 ENCRYPTION_KEY_K256_AEAD_EIDOS => SealingKey::K256AeadEidos(read_k256_pub_key(byte_iter)?),
370 other => {
371 return Err(AddressError::decode_error(format!(
372 "unknown encryption key variant: {}",
373 other
374 )));
375 },
376 };
377
378 Ok(public_encryption_key)
379}
380
381fn read_x25519_pub_key(
382 byte_iter: &mut impl ExactSizeIterator<Item = u8>,
383) -> Result<eddsa_25519_sha512::PublicKey, AddressError> {
384 if byte_iter.len() < X25519_PUBLIC_KEY_LENGTH {
385 return Err(AddressError::decode_error(format!(
386 "expected {} bytes to decode X25519 public key",
387 X25519_PUBLIC_KEY_LENGTH
388 )));
389 }
390 let key_bytes: [u8; X25519_PUBLIC_KEY_LENGTH] = read_byte_array(byte_iter);
391 eddsa_25519_sha512::PublicKey::read_from_bytes(&key_bytes).map_err(|err| {
392 AddressError::decode_error_with_source("failed to decode X25519 public key", err)
393 })
394}
395
396fn read_k256_pub_key(
397 byte_iter: &mut impl ExactSizeIterator<Item = u8>,
398) -> Result<ecdsa_k256_keccak::PublicKey, AddressError> {
399 if byte_iter.len() < K256_PUBLIC_KEY_LENGTH {
400 return Err(AddressError::decode_error(format!(
401 "expected {} bytes to decode K256 public key",
402 K256_PUBLIC_KEY_LENGTH
403 )));
404 }
405 let key_bytes: [u8; K256_PUBLIC_KEY_LENGTH] = read_byte_array(byte_iter);
406 ecdsa_k256_keccak::PublicKey::read_from_bytes(&key_bytes).map_err(|err| {
407 AddressError::decode_error_with_source("failed to decode K256 public key", err)
408 })
409}
410
411fn read_byte_array<const N: usize>(byte_iter: &mut impl ExactSizeIterator<Item = u8>) -> [u8; N] {
415 let mut array = [0u8; N];
416 for byte in array.iter_mut() {
417 *byte = byte_iter.next().expect("iterator should have enough bytes");
418 }
419 array
420}
421
422#[cfg(test)]
426mod tests {
427 use bech32::{Bech32m, Checksum, Hrp};
428
429 use super::*;
430
431 #[test]
436 fn bech32_code_length_assertions() -> anyhow::Result<()> {
437 let hrp = Hrp::parse("mrp").unwrap();
438 let separator_len = BECH32_SEPARATOR.len();
439 let fixed_num_bytes = hrp.as_str().len() + separator_len + Bech32m::CHECKSUM_LENGTH;
441 let num_allowed_chars = Bech32m::CODE_LENGTH - fixed_num_bytes;
442 let num_allowed_bytes = num_allowed_chars * 5 / 8;
444
445 assert_eq!(num_allowed_bytes, 633);
447
448 let data_ok = vec![5; num_allowed_bytes];
450 let data_too_long = vec![5; num_allowed_bytes + 1];
452
453 assert!(bech32::encode::<Bech32m>(hrp, &data_ok).is_ok());
454 assert!(bech32::encode::<Bech32m>(hrp, &data_too_long).is_err());
455
456 Ok(())
457 }
458
459 #[test]
461 fn routing_parameters_bech32_encode_decode_roundtrip() -> anyhow::Result<()> {
462 let params_no_tag = RoutingParameters::new(AddressInterface::BasicWallet);
464 let encoded = params_no_tag.encode_to_string();
465 let decoded = RoutingParameters::decode(encoded)?;
466 assert_eq!(params_no_tag, decoded);
467 assert_eq!(decoded.note_tag_len(), None);
468
469 let params_tag_0 =
471 RoutingParameters::new(AddressInterface::BasicWallet).with_note_tag_len(0)?;
472 let encoded = params_tag_0.encode_to_string();
473 let decoded = RoutingParameters::decode(encoded)?;
474 assert_eq!(params_tag_0, decoded);
475 assert_eq!(decoded.note_tag_len(), Some(0));
476
477 let params_tag_6 =
479 RoutingParameters::new(AddressInterface::BasicWallet).with_note_tag_len(6)?;
480 let encoded = params_tag_6.encode_to_string();
481 let decoded = RoutingParameters::decode(encoded)?;
482 assert_eq!(params_tag_6, decoded);
483 assert_eq!(decoded.note_tag_len(), Some(6));
484
485 let params_tag_max = RoutingParameters::new(AddressInterface::BasicWallet)
487 .with_note_tag_len(NoteTag::MAX_ACCOUNT_TARGET_TAG_LENGTH)?;
488 let encoded = params_tag_max.encode_to_string();
489 let decoded = RoutingParameters::decode(encoded)?;
490 assert_eq!(params_tag_max, decoded);
491 assert_eq!(decoded.note_tag_len(), Some(NoteTag::MAX_ACCOUNT_TARGET_TAG_LENGTH));
492
493 Ok(())
494 }
495
496 #[test]
498 fn routing_parameters_serialization() -> anyhow::Result<()> {
499 let params_no_tag = RoutingParameters::new(AddressInterface::BasicWallet);
501 let serialized = params_no_tag.to_bytes();
502 let deserialized = RoutingParameters::read_from_bytes(&serialized)?;
503 assert_eq!(params_no_tag, deserialized);
504 assert_eq!(deserialized.note_tag_len(), None);
505
506 let params_tag_0 =
508 RoutingParameters::new(AddressInterface::BasicWallet).with_note_tag_len(0)?;
509 let serialized = params_tag_0.to_bytes();
510 let deserialized = RoutingParameters::read_from_bytes(&serialized)?;
511 assert_eq!(params_tag_0, deserialized);
512 assert_eq!(deserialized.note_tag_len(), Some(0));
513
514 let params_tag_6 =
516 RoutingParameters::new(AddressInterface::BasicWallet).with_note_tag_len(6)?;
517 let serialized = params_tag_6.to_bytes();
518 let deserialized = RoutingParameters::read_from_bytes(&serialized)?;
519 assert_eq!(params_tag_6, deserialized);
520 assert_eq!(deserialized.note_tag_len(), Some(6));
521
522 let params_tag_max = RoutingParameters::new(AddressInterface::BasicWallet)
524 .with_note_tag_len(NoteTag::MAX_ACCOUNT_TARGET_TAG_LENGTH)?;
525 let serialized = params_tag_max.to_bytes();
526 let deserialized = RoutingParameters::read_from_bytes(&serialized)?;
527 assert_eq!(params_tag_max, deserialized);
528 assert_eq!(deserialized.note_tag_len(), Some(NoteTag::MAX_ACCOUNT_TARGET_TAG_LENGTH));
529
530 Ok(())
531 }
532
533 #[test]
535 fn routing_parameters_all_encryption_key_variants() -> anyhow::Result<()> {
536 fn test_encryption_key_roundtrip(encryption_key: SealingKey) -> anyhow::Result<()> {
538 let routing_params = RoutingParameters::new(AddressInterface::BasicWallet)
539 .with_encryption_key(encryption_key.clone());
540
541 let encoded = routing_params.encode_to_string();
543 let decoded = RoutingParameters::decode(encoded)?;
544 assert_eq!(routing_params, decoded);
545 assert_eq!(decoded.encryption_key(), Some(&encryption_key));
546
547 let serialized = routing_params.to_bytes();
549 let deserialized = RoutingParameters::read_from_bytes(&serialized)?;
550 assert_eq!(routing_params, deserialized);
551 assert_eq!(deserialized.encryption_key(), Some(&encryption_key));
552
553 Ok(())
554 }
555
556 {
558 use crate::crypto::dsa::eddsa_25519_sha512::KeyExchangeKey;
559 let secret_key = KeyExchangeKey::with_rng(&mut rand::rng());
560 let public_key = secret_key.public_key();
561 let encryption_key = SealingKey::X25519XChaCha20Poly1305(public_key);
562 test_encryption_key_roundtrip(encryption_key)?;
563 }
564
565 {
567 use crate::crypto::dsa::ecdsa_k256_keccak::KeyExchangeKey;
568 let secret_key = KeyExchangeKey::with_rng(&mut rand::rng());
569 let public_key = secret_key.public_key();
570 let encryption_key = SealingKey::K256XChaCha20Poly1305(public_key);
571 test_encryption_key_roundtrip(encryption_key)?;
572 }
573
574 {
576 use crate::crypto::dsa::eddsa_25519_sha512::KeyExchangeKey;
577 let secret_key = KeyExchangeKey::with_rng(&mut rand::rng());
578 let public_key = secret_key.public_key();
579 let encryption_key = SealingKey::X25519AeadPoseidon2(public_key);
580 test_encryption_key_roundtrip(encryption_key)?;
581 }
582
583 {
585 use crate::crypto::dsa::ecdsa_k256_keccak::KeyExchangeKey;
586 let secret_key = KeyExchangeKey::with_rng(&mut rand::rng());
587 let public_key = secret_key.public_key();
588 let encryption_key = SealingKey::K256AeadPoseidon2(public_key);
589 test_encryption_key_roundtrip(encryption_key)?;
590 }
591
592 {
594 use crate::crypto::dsa::eddsa_25519_sha512::KeyExchangeKey;
595 let secret_key = KeyExchangeKey::with_rng(&mut rand::rng());
596 let public_key = secret_key.public_key();
597 let encryption_key = SealingKey::X25519AeadEidos(public_key);
598 test_encryption_key_roundtrip(encryption_key)?;
599 }
600
601 {
603 use crate::crypto::dsa::ecdsa_k256_keccak::KeyExchangeKey;
604 let secret_key = KeyExchangeKey::with_rng(&mut rand::rng());
605 let public_key = secret_key.public_key();
606 let encryption_key = SealingKey::K256AeadEidos(public_key);
607 test_encryption_key_roundtrip(encryption_key)?;
608 }
609
610 Ok(())
611 }
612}