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;
60
61#[derive(Debug, Clone, PartialEq, Eq)]
64pub struct RoutingParameters {
65 interface: AddressInterface,
66 note_tag_len: Option<u8>,
67 encryption_key: Option<SealingKey>,
68}
69
70impl RoutingParameters {
71 pub fn new(interface: AddressInterface) -> Self {
77 Self {
78 interface,
79 note_tag_len: None,
80 encryption_key: None,
81 }
82 }
83
84 pub fn with_note_tag_len(mut self, note_tag_len: u8) -> Result<Self, AddressError> {
97 if note_tag_len > NoteTag::MAX_ACCOUNT_TARGET_TAG_LENGTH {
98 return Err(AddressError::TagLengthTooLarge(note_tag_len));
99 }
100
101 self.note_tag_len = Some(note_tag_len);
102 Ok(self)
103 }
104
105 pub fn note_tag_len(&self) -> Option<u8> {
113 self.note_tag_len
114 }
115
116 pub fn interface(&self) -> AddressInterface {
118 self.interface
119 }
120
121 pub fn encryption_key(&self) -> Option<&SealingKey> {
123 self.encryption_key.as_ref()
124 }
125
126 pub fn with_encryption_key(mut self, key: SealingKey) -> Self {
131 self.encryption_key = Some(key);
132 self
133 }
134
135 pub(crate) fn encode_to_bytes(&self) -> Vec<u8> {
140 let mut encoded = Vec::new();
141
142 encoded.push(RECEIVER_PROFILE_PARAM_KEY);
144 encoded.extend(encode_receiver_profile(self.interface, self.note_tag_len));
145
146 if let Some(encryption_key) = &self.encryption_key {
148 encoded.push(ENCRYPTION_KEY_PARAM_KEY);
149 encode_encryption_key(encryption_key, &mut encoded);
150 }
151
152 encoded
153 }
154
155 pub(crate) fn encode_to_string(&self) -> String {
157 let encoded = self.encode_to_bytes();
158
159 let bech32_str =
160 bech32::encode::<Bech32m>(*ROUTING_PARAMETERS_HRP, &encoded).expect("TODO");
161 let encoded_str = bech32_str
162 .strip_prefix(ROUTING_PARAMETERS_HRP.as_str())
163 .expect("bech32 str should start with the hrp");
164 let encoded_str = encoded_str
165 .strip_prefix(BECH32_SEPARATOR)
166 .expect("encoded str should start with bech32 separator `1`");
167 encoded_str.to_owned()
168 }
169
170 pub(crate) fn decode(mut bech32_string: String) -> Result<Self, AddressError> {
172 bech32_string.insert_str(0, BECH32_SEPARATOR);
176 bech32_string.insert_str(0, ROUTING_PARAMETERS_HRP.as_str());
177
178 let checked_string =
181 CheckedHrpstring::new::<Bech32m>(&bech32_string).map_err(|source| {
182 AddressError::decode_error_with_source(
187 "failed to decode routing parameters bech32 string",
188 Bech32Error::DecodeError(source.to_string().into()),
189 )
190 })?;
191
192 Self::decode_from_bytes(checked_string.byte_iter())
193 }
194
195 pub(crate) fn decode_from_bytes(
197 mut byte_iter: impl ExactSizeIterator<Item = u8>,
198 ) -> Result<Self, AddressError> {
199 let mut interface = None;
200 let mut note_tag_len = None;
201 let mut encryption_key = None;
202
203 while let Some(key) = byte_iter.next() {
204 match key {
205 RECEIVER_PROFILE_PARAM_KEY => {
206 if interface.is_some() {
207 return Err(AddressError::decode_error(
208 "duplicate receiver profile routing parameter",
209 ));
210 }
211 let receiver_profile = decode_receiver_profile(&mut byte_iter)?;
212 interface = Some(receiver_profile.0);
213 note_tag_len = receiver_profile.1;
214 },
215 ENCRYPTION_KEY_PARAM_KEY => {
216 if encryption_key.is_some() {
217 return Err(AddressError::decode_error(
218 "duplicate encryption key routing parameter",
219 ));
220 }
221 encryption_key = Some(decode_encryption_key(&mut byte_iter)?);
222 },
223 other => {
224 return Err(AddressError::UnknownRoutingParameterKey(other));
225 },
226 }
227 }
228
229 let interface = interface.ok_or_else(|| {
230 AddressError::decode_error("interface must be present in routing parameters")
231 })?;
232
233 let mut routing_parameters = RoutingParameters::new(interface);
234 routing_parameters.note_tag_len = note_tag_len;
235 routing_parameters.encryption_key = encryption_key;
236
237 Ok(routing_parameters)
238 }
239}
240
241impl Serializable for RoutingParameters {
242 fn write_into<W: ByteWriter>(&self, target: &mut W) {
243 let bytes = self.encode_to_bytes();
244 let num_bytes = bytes.len() as u16;
246
247 target.write_u16(num_bytes);
248 target.write_many(bytes);
249 }
250}
251
252impl Deserializable for RoutingParameters {
253 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
254 let num_bytes = source.read_u16()?;
255 let bytes: Vec<u8> =
256 source.read_many_iter(num_bytes as usize)?.collect::<Result<_, _>>()?;
257
258 Self::decode_from_bytes(bytes.into_iter())
259 .map_err(|err| DeserializationError::InvalidValue(err.to_string()))
260 }
261}
262
263fn encode_receiver_profile(interface: AddressInterface, note_tag_len: Option<u8>) -> [u8; 2] {
268 let note_tag_len = note_tag_len.unwrap_or(ABSENT_NOTE_TAG_LEN);
269
270 let interface = interface as u16;
271 debug_assert_eq!(interface >> 10, 0, "address interface should fit into 10 bits");
272
273 let tag_len = (note_tag_len as u16) << 10;
276 let receiver_profile: u16 = tag_len | interface;
277 receiver_profile.to_be_bytes()
278}
279
280fn decode_receiver_profile(
282 byte_iter: &mut impl ExactSizeIterator<Item = u8>,
283) -> Result<(AddressInterface, Option<u8>), AddressError> {
284 if byte_iter.len() < 2 {
285 return Err(AddressError::decode_error("expected two bytes to decode receiver profile"));
286 };
287
288 let byte0 = byte_iter.next().expect("byte0 should exist");
289 let byte1 = byte_iter.next().expect("byte1 should exist");
290 let receiver_profile = u16::from_be_bytes([byte0, byte1]);
291
292 let tag_len = (receiver_profile >> 10) as u8;
293 let note_tag_len = match tag_len {
294 ABSENT_NOTE_TAG_LEN => None,
295 0..=32 => Some(tag_len),
296 _ => {
297 return Err(AddressError::decode_error(format!("invalid note tag length {}", tag_len)));
298 },
299 };
300
301 let addr_interface = receiver_profile & 0b0000_0011_1111_1111;
302 let addr_interface = AddressInterface::try_from(addr_interface).map_err(|err| {
303 AddressError::decode_error_with_source("failed to decode address interface", err)
304 })?;
305
306 Ok((addr_interface, note_tag_len))
307}
308
309fn encode_encryption_key(key: &SealingKey, encoded: &mut Vec<u8>) {
311 match key {
312 SealingKey::X25519XChaCha20Poly1305(pk) => {
313 encoded.push(ENCRYPTION_KEY_X25519_XCHACHA20POLY1305);
314 encoded.extend(&pk.to_bytes());
315 },
316 SealingKey::K256XChaCha20Poly1305(pk) => {
317 encoded.push(ENCRYPTION_KEY_K256_XCHACHA20POLY1305);
318 encoded.extend(&pk.to_bytes());
319 },
320 SealingKey::X25519AeadPoseidon2(pk) => {
321 encoded.push(ENCRYPTION_KEY_X25519_AEAD_POSEIDON2);
322 encoded.extend(&pk.to_bytes());
323 },
324 SealingKey::K256AeadPoseidon2(pk) => {
325 encoded.push(ENCRYPTION_KEY_K256_AEAD_POSEIDON2);
326 encoded.extend(&pk.to_bytes());
327 },
328 }
329}
330
331fn decode_encryption_key(
333 byte_iter: &mut impl ExactSizeIterator<Item = u8>,
334) -> Result<SealingKey, AddressError> {
335 let Some(variant) = byte_iter.next() else {
337 return Err(AddressError::decode_error(
338 "expected at least 1 byte for encryption key variant",
339 ));
340 };
341
342 let public_encryption_key = match variant {
344 ENCRYPTION_KEY_X25519_XCHACHA20POLY1305 => {
345 SealingKey::X25519XChaCha20Poly1305(read_x25519_pub_key(byte_iter)?)
346 },
347 ENCRYPTION_KEY_K256_XCHACHA20POLY1305 => {
348 SealingKey::K256XChaCha20Poly1305(read_k256_pub_key(byte_iter)?)
349 },
350 ENCRYPTION_KEY_X25519_AEAD_POSEIDON2 => {
351 SealingKey::X25519AeadPoseidon2(read_x25519_pub_key(byte_iter)?)
352 },
353 ENCRYPTION_KEY_K256_AEAD_POSEIDON2 => {
354 SealingKey::K256AeadPoseidon2(read_k256_pub_key(byte_iter)?)
355 },
356 other => {
357 return Err(AddressError::decode_error(format!(
358 "unknown encryption key variant: {}",
359 other
360 )));
361 },
362 };
363
364 Ok(public_encryption_key)
365}
366
367fn read_x25519_pub_key(
368 byte_iter: &mut impl ExactSizeIterator<Item = u8>,
369) -> Result<eddsa_25519_sha512::PublicKey, AddressError> {
370 if byte_iter.len() < X25519_PUBLIC_KEY_LENGTH {
371 return Err(AddressError::decode_error(format!(
372 "expected {} bytes to decode X25519 public key",
373 X25519_PUBLIC_KEY_LENGTH
374 )));
375 }
376 let key_bytes: [u8; X25519_PUBLIC_KEY_LENGTH] = read_byte_array(byte_iter);
377 eddsa_25519_sha512::PublicKey::read_from_bytes(&key_bytes).map_err(|err| {
378 AddressError::decode_error_with_source("failed to decode X25519 public key", err)
379 })
380}
381
382fn read_k256_pub_key(
383 byte_iter: &mut impl ExactSizeIterator<Item = u8>,
384) -> Result<ecdsa_k256_keccak::PublicKey, AddressError> {
385 if byte_iter.len() < K256_PUBLIC_KEY_LENGTH {
386 return Err(AddressError::decode_error(format!(
387 "expected {} bytes to decode K256 public key",
388 K256_PUBLIC_KEY_LENGTH
389 )));
390 }
391 let key_bytes: [u8; K256_PUBLIC_KEY_LENGTH] = read_byte_array(byte_iter);
392 ecdsa_k256_keccak::PublicKey::read_from_bytes(&key_bytes).map_err(|err| {
393 AddressError::decode_error_with_source("failed to decode K256 public key", err)
394 })
395}
396
397fn read_byte_array<const N: usize>(byte_iter: &mut impl ExactSizeIterator<Item = u8>) -> [u8; N] {
401 let mut array = [0u8; N];
402 for byte in array.iter_mut() {
403 *byte = byte_iter.next().expect("iterator should have enough bytes");
404 }
405 array
406}
407
408#[cfg(test)]
412mod tests {
413 use bech32::{Bech32m, Checksum, Hrp};
414
415 use super::*;
416
417 #[test]
422 fn bech32_code_length_assertions() -> anyhow::Result<()> {
423 let hrp = Hrp::parse("mrp").unwrap();
424 let separator_len = BECH32_SEPARATOR.len();
425 let fixed_num_bytes = hrp.as_str().len() + separator_len + Bech32m::CHECKSUM_LENGTH;
427 let num_allowed_chars = Bech32m::CODE_LENGTH - fixed_num_bytes;
428 let num_allowed_bytes = num_allowed_chars * 5 / 8;
430
431 assert_eq!(num_allowed_bytes, 633);
433
434 let data_ok = vec![5; num_allowed_bytes];
436 let data_too_long = vec![5; num_allowed_bytes + 1];
438
439 assert!(bech32::encode::<Bech32m>(hrp, &data_ok).is_ok());
440 assert!(bech32::encode::<Bech32m>(hrp, &data_too_long).is_err());
441
442 Ok(())
443 }
444
445 #[test]
447 fn routing_parameters_bech32_encode_decode_roundtrip() -> anyhow::Result<()> {
448 let params_no_tag = RoutingParameters::new(AddressInterface::BasicWallet);
450 let encoded = params_no_tag.encode_to_string();
451 let decoded = RoutingParameters::decode(encoded)?;
452 assert_eq!(params_no_tag, decoded);
453 assert_eq!(decoded.note_tag_len(), None);
454
455 let params_tag_0 =
457 RoutingParameters::new(AddressInterface::BasicWallet).with_note_tag_len(0)?;
458 let encoded = params_tag_0.encode_to_string();
459 let decoded = RoutingParameters::decode(encoded)?;
460 assert_eq!(params_tag_0, decoded);
461 assert_eq!(decoded.note_tag_len(), Some(0));
462
463 let params_tag_6 =
465 RoutingParameters::new(AddressInterface::BasicWallet).with_note_tag_len(6)?;
466 let encoded = params_tag_6.encode_to_string();
467 let decoded = RoutingParameters::decode(encoded)?;
468 assert_eq!(params_tag_6, decoded);
469 assert_eq!(decoded.note_tag_len(), Some(6));
470
471 let params_tag_max = RoutingParameters::new(AddressInterface::BasicWallet)
473 .with_note_tag_len(NoteTag::MAX_ACCOUNT_TARGET_TAG_LENGTH)?;
474 let encoded = params_tag_max.encode_to_string();
475 let decoded = RoutingParameters::decode(encoded)?;
476 assert_eq!(params_tag_max, decoded);
477 assert_eq!(decoded.note_tag_len(), Some(NoteTag::MAX_ACCOUNT_TARGET_TAG_LENGTH));
478
479 Ok(())
480 }
481
482 #[test]
484 fn routing_parameters_serialization() -> anyhow::Result<()> {
485 let params_no_tag = RoutingParameters::new(AddressInterface::BasicWallet);
487 let serialized = params_no_tag.to_bytes();
488 let deserialized = RoutingParameters::read_from_bytes(&serialized)?;
489 assert_eq!(params_no_tag, deserialized);
490 assert_eq!(deserialized.note_tag_len(), None);
491
492 let params_tag_0 =
494 RoutingParameters::new(AddressInterface::BasicWallet).with_note_tag_len(0)?;
495 let serialized = params_tag_0.to_bytes();
496 let deserialized = RoutingParameters::read_from_bytes(&serialized)?;
497 assert_eq!(params_tag_0, deserialized);
498 assert_eq!(deserialized.note_tag_len(), Some(0));
499
500 let params_tag_6 =
502 RoutingParameters::new(AddressInterface::BasicWallet).with_note_tag_len(6)?;
503 let serialized = params_tag_6.to_bytes();
504 let deserialized = RoutingParameters::read_from_bytes(&serialized)?;
505 assert_eq!(params_tag_6, deserialized);
506 assert_eq!(deserialized.note_tag_len(), Some(6));
507
508 let params_tag_max = RoutingParameters::new(AddressInterface::BasicWallet)
510 .with_note_tag_len(NoteTag::MAX_ACCOUNT_TARGET_TAG_LENGTH)?;
511 let serialized = params_tag_max.to_bytes();
512 let deserialized = RoutingParameters::read_from_bytes(&serialized)?;
513 assert_eq!(params_tag_max, deserialized);
514 assert_eq!(deserialized.note_tag_len(), Some(NoteTag::MAX_ACCOUNT_TARGET_TAG_LENGTH));
515
516 Ok(())
517 }
518
519 #[test]
521 fn routing_parameters_all_encryption_key_variants() -> anyhow::Result<()> {
522 fn test_encryption_key_roundtrip(encryption_key: SealingKey) -> anyhow::Result<()> {
524 let routing_params = RoutingParameters::new(AddressInterface::BasicWallet)
525 .with_encryption_key(encryption_key.clone());
526
527 let encoded = routing_params.encode_to_string();
529 let decoded = RoutingParameters::decode(encoded)?;
530 assert_eq!(routing_params, decoded);
531 assert_eq!(decoded.encryption_key(), Some(&encryption_key));
532
533 let serialized = routing_params.to_bytes();
535 let deserialized = RoutingParameters::read_from_bytes(&serialized)?;
536 assert_eq!(routing_params, deserialized);
537 assert_eq!(deserialized.encryption_key(), Some(&encryption_key));
538
539 Ok(())
540 }
541
542 {
544 use crate::crypto::dsa::eddsa_25519_sha512::SecretKey;
545 let secret_key = SecretKey::with_rng(&mut rand::rng());
546 let public_key = secret_key.public_key();
547 let encryption_key = SealingKey::X25519XChaCha20Poly1305(public_key);
548 test_encryption_key_roundtrip(encryption_key)?;
549 }
550
551 {
553 use crate::crypto::dsa::ecdsa_k256_keccak::SecretKey;
554 let secret_key = SecretKey::with_rng(&mut rand::rng());
555 let public_key = secret_key.public_key();
556 let encryption_key = SealingKey::K256XChaCha20Poly1305(public_key);
557 test_encryption_key_roundtrip(encryption_key)?;
558 }
559
560 {
562 use crate::crypto::dsa::eddsa_25519_sha512::SecretKey;
563 let secret_key = SecretKey::with_rng(&mut rand::rng());
564 let public_key = secret_key.public_key();
565 let encryption_key = SealingKey::X25519AeadPoseidon2(public_key);
566 test_encryption_key_roundtrip(encryption_key)?;
567 }
568
569 {
571 use crate::crypto::dsa::ecdsa_k256_keccak::SecretKey;
572 let secret_key = SecretKey::with_rng(&mut rand::rng());
573 let public_key = secret_key.public_key();
574 let encryption_key = SealingKey::K256AeadPoseidon2(public_key);
575 test_encryption_key_roundtrip(encryption_key)?;
576 }
577
578 Ok(())
579 }
580}