1use std::{
4 fmt::Display,
5 io::{Cursor, Read, Write},
6 sync::OnceLock,
7};
8
9use anyhow::Context;
10use ark_serialize::CanonicalDeserialize;
11use decaf377::Fq;
12use f4jumble::{f4jumble, f4jumble_inv};
13use penumbra_sdk_proto::{penumbra::core::keys::v1 as pb, serializers::bech32str, DomainType};
14use rand::{CryptoRng, Rng};
15use serde::{Deserialize, Serialize};
16use sha2::{Digest, Sha256};
17
18mod r1cs;
19pub use r1cs::AddressVar;
20
21mod view;
22pub use view::AddressView;
23
24use crate::{fmd, ka, keys::Diversifier};
25
26pub const TRANSPARENT_ADDRESS_BECH32_PREFIX: &str = "tpenumbra";
27
28pub const ADDRESS_LEN_BYTES: usize = 80;
30
31pub const ADDRESS_NUM_CHARS_SHORT_FORM: usize = 24;
33
34#[derive(Clone, Eq, Serialize, Deserialize)]
36#[serde(try_from = "pb::Address", into = "pb::Address")]
37pub struct Address {
38 d: Diversifier,
40 g_d: OnceLock<decaf377::Element>,
42
43 pk_d: ka::Public,
50 transmission_key_s: Fq,
52
53 ck_d: fmd::ClueKey,
55}
56
57impl std::cmp::PartialEq for Address {
58 fn eq(
59 &self,
60 rhs @ Self {
61 d: rhs_d,
62 g_d: rhs_g_d,
63 pk_d: rhs_pk_d,
64 transmission_key_s: rhs_transmission_key_s,
65 ck_d: rhs_ck_d,
66 }: &Self,
67 ) -> bool {
68 let lhs @ Self {
69 d: lhs_d,
70 g_d: lhs_g_d,
71 pk_d: lhs_pk_d,
72 transmission_key_s: lhs_transmission_key_s,
73 ck_d: lhs_ck_d,
74 } = self;
75
76 lhs.diversified_generator();
81 rhs.diversified_generator();
82
83 lhs_d.eq(rhs_d)
85 && lhs_g_d.eq(rhs_g_d)
86 && lhs_pk_d.eq(rhs_pk_d)
87 && lhs_transmission_key_s.eq(rhs_transmission_key_s)
88 && lhs_ck_d.eq(rhs_ck_d)
89 }
90}
91
92impl std::cmp::PartialOrd for Address {
93 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
94 Some(self.to_vec().cmp(&other.to_vec()))
95 }
96}
97
98impl std::cmp::Ord for Address {
99 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
100 self.to_vec().cmp(&other.to_vec())
101 }
102}
103
104impl std::hash::Hash for Address {
105 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
106 self.to_vec().hash(state)
107 }
108}
109
110impl Address {
111 pub fn from_components(d: Diversifier, pk_d: ka::Public, ck_d: fmd::ClueKey) -> Option<Self> {
116 if let Ok(transmission_key_s) = Fq::deserialize_compressed(&pk_d.0[..]) {
119 Some(Self {
121 d,
122 g_d: OnceLock::new(),
123 pk_d,
124 ck_d,
125 transmission_key_s,
126 })
127 } else {
128 None
129 }
130 }
131
132 pub fn diversifier(&self) -> &Diversifier {
134 &self.d
135 }
136
137 pub fn diversified_generator(&self) -> &decaf377::Element {
142 self.g_d
143 .get_or_init(|| self.diversifier().diversified_generator())
144 }
145
146 pub fn transmission_key(&self) -> &ka::Public {
148 &self.pk_d
149 }
150
151 pub fn clue_key(&self) -> &fmd::ClueKey {
153 &self.ck_d
154 }
155
156 pub fn transmission_key_s(&self) -> &Fq {
158 &self.transmission_key_s
159 }
160
161 pub fn to_vec(&self) -> Vec<u8> {
163 let mut bytes = std::io::Cursor::new(Vec::new());
164 bytes
165 .write_all(&self.diversifier().0)
166 .expect("can write diversifier into vec");
167 bytes
168 .write_all(&self.transmission_key().0)
169 .expect("can write transmission key into vec");
170 bytes
171 .write_all(&self.clue_key().0)
172 .expect("can write clue key into vec");
173
174 f4jumble(bytes.get_ref()).expect("can jumble")
175 }
176
177 pub fn dummy<R: CryptoRng + Rng>(rng: &mut R) -> Self {
179 loop {
180 let mut diversifier_bytes = [0u8; 16];
181 rng.fill_bytes(&mut diversifier_bytes);
182
183 let mut pk_d_bytes = [0u8; 32];
184 rng.fill_bytes(&mut pk_d_bytes);
185
186 let mut clue_key_bytes = [0; 32];
187 rng.fill_bytes(&mut clue_key_bytes);
188
189 let diversifier = Diversifier(diversifier_bytes);
190 let addr = Address::from_components(
191 diversifier,
192 ka::Public(pk_d_bytes),
193 fmd::ClueKey(clue_key_bytes),
194 );
195
196 if let Some(addr) = addr {
197 return addr;
198 }
199 }
200 }
201
202 pub fn display_short_form(&self) -> String {
204 let full_address = format!("{self}");
205 let fixed_prefix = format!("{}{}", bech32str::address::BECH32_PREFIX, '1');
207 let num_chars_to_display = fixed_prefix.len() + ADDRESS_NUM_CHARS_SHORT_FORM;
208
209 format!("{}…", &full_address[0..num_chars_to_display])
210 }
211
212 pub fn compat_encoding(&self) -> String {
214 let proto_address = pb::Address::from(self);
215 bech32str::encode(
216 &proto_address.inner,
217 bech32str::compat_address::BECH32_PREFIX,
218 bech32str::Bech32,
219 )
220 }
221
222 pub fn noble_forwarding_address(&self, channel: &str) -> NobleForwardingAddress {
224 NobleForwardingAddress {
225 channel: channel.to_string(),
226 recipient: format!("{}", self),
227 }
228 }
229
230 pub fn encode_as_transparent_address(&self) -> Option<String> {
233 if self.diversifier().0 != [0u8; 16] {
235 return None;
236 }
237
238 if self.clue_key().0 != [0u8; 32] {
240 return None;
241 }
242
243 Some(bech32str::encode(
245 &self.transmission_key().0,
246 TRANSPARENT_ADDRESS_BECH32_PREFIX,
247 bech32str::Bech32,
248 ))
249 }
250}
251
252#[derive(Clone, Debug, Serialize, Deserialize)]
253pub struct NobleForwardingAddress {
254 pub channel: String,
255 pub recipient: String,
256}
257
258impl NobleForwardingAddress {
259 pub fn bytes(&self) -> Vec<u8> {
260 let channel = self.channel.clone();
262 let recipient = self.recipient.clone();
263 let bz = format!("{channel}{recipient}").as_bytes().to_owned();
264 let th = Sha256::digest("forwarding".as_bytes());
265 let mut hasher = Sha256::new();
266 hasher.update(th);
267 hasher.update(bz);
268
269 hasher.finalize()[12..].to_vec()
272 }
273}
274
275impl Display for NobleForwardingAddress {
276 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
277 let addr_bytes = &self.bytes();
278
279 write!(
280 f,
281 "{}",
282 bech32str::encode(&addr_bytes, "noble", bech32str::Bech32)
283 )
284 }
285}
286
287impl DomainType for Address {
288 type Proto = pb::Address;
289}
290
291impl From<Address> for pb::Address {
292 fn from(a: Address) -> Self {
293 Self::from(&a)
294 }
295}
296
297impl From<&Address> for pb::Address {
298 fn from(a: &Address) -> Self {
299 pb::Address {
300 inner: a.to_vec(),
301 alt_bech32m: String::new(),
303 }
304 }
305}
306
307impl TryFrom<pb::Address> for Address {
308 type Error = anyhow::Error;
309
310 fn try_from(value: pb::Address) -> Result<Self, Self::Error> {
311 match (value.inner.is_empty(), value.alt_bech32m.is_empty()) {
312 (false, true) => value.inner.try_into(),
313 (true, false) => value.alt_bech32m.parse(),
314 (false, false) => Err(anyhow::anyhow!(
315 "Address proto has both inner and alt_bech32m fields set"
316 )),
317 (true, true) => Err(anyhow::anyhow!(
318 "Address proto has neither inner nor alt_bech32m fields set"
319 )),
320 }
321 }
322}
323
324impl std::fmt::Display for Address {
325 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
326 let proto_address = pb::Address::from(self);
327 f.write_str(&bech32str::encode(
328 &proto_address.inner,
329 bech32str::address::BECH32_PREFIX,
330 bech32str::Bech32m,
331 ))
332 }
333}
334
335impl std::fmt::Debug for Address {
336 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
337 <Self as std::fmt::Display>::fmt(self, f)
338 }
339}
340
341impl std::str::FromStr for Address {
342 type Err = anyhow::Error;
343
344 fn from_str(s: &str) -> Result<Self, Self::Err> {
345 if s.starts_with(TRANSPARENT_ADDRESS_BECH32_PREFIX) {
346 let dzero = Diversifier([0u8; 16]);
347
348 let pk_dzero_bytes: [u8; 32] =
349 bech32str::decode(s, TRANSPARENT_ADDRESS_BECH32_PREFIX, bech32str::Bech32)?
350 .try_into()
351 .map_err(|bytes: Vec<u8>| {
352 anyhow::anyhow!("wrong length {}, expected 32", bytes.len())
353 })?;
354 let pk_dzero = ka::Public(pk_dzero_bytes);
355
356 let ck_id = fmd::ClueKey([0u8; 32]);
357
358 let address = Self::from_components(dzero, pk_dzero, ck_id)
359 .ok_or_else(|| anyhow::anyhow!("could not reconstruct transparent address"))?;
360
361 if address.encode_as_transparent_address().is_none() {
363 return Err(anyhow::anyhow!("invalid transparent address components"));
364 }
365
366 Ok(address)
367 } else if s.starts_with(bech32str::compat_address::BECH32_PREFIX) {
368 pb::Address {
369 inner: bech32str::decode(
370 s,
371 bech32str::compat_address::BECH32_PREFIX,
372 bech32str::Bech32,
373 )?,
374 alt_bech32m: String::new(),
375 }
376 .try_into()
377 } else {
378 pb::Address {
379 inner: bech32str::decode(s, bech32str::address::BECH32_PREFIX, bech32str::Bech32m)?,
380 alt_bech32m: String::new(),
381 }
382 .try_into()
383 }
384 }
385}
386
387impl TryFrom<Vec<u8>> for Address {
388 type Error = anyhow::Error;
389
390 fn try_from(jumbled_vec: Vec<u8>) -> Result<Self, Self::Error> {
391 (&jumbled_vec[..]).try_into()
392 }
393}
394
395impl TryFrom<&Vec<u8>> for Address {
396 type Error = anyhow::Error;
397
398 fn try_from(jumbled_vec: &Vec<u8>) -> Result<Self, Self::Error> {
399 (jumbled_vec[..]).try_into()
400 }
401}
402
403impl TryFrom<&[u8]> for Address {
404 type Error = anyhow::Error;
405
406 fn try_from(jumbled_bytes: &[u8]) -> Result<Self, Self::Error> {
407 if jumbled_bytes.len() != ADDRESS_LEN_BYTES {
408 anyhow::bail!("address malformed");
409 }
410
411 let unjumbled_bytes = f4jumble_inv(jumbled_bytes).context("invalid address")?;
412 let mut bytes = Cursor::new(unjumbled_bytes);
413
414 let mut diversifier_bytes = [0u8; 16];
415 bytes
416 .read_exact(&mut diversifier_bytes)
417 .context("could not read diversifier bytes")?;
418
419 let mut pk_d_bytes = [0u8; 32];
420 bytes
421 .read_exact(&mut pk_d_bytes)
422 .context("could not read transmission key bytes")?;
423
424 let mut clue_key_bytes = [0; 32];
425 bytes
426 .read_exact(&mut clue_key_bytes)
427 .context("could not read clue key bytes")?;
428
429 let diversifier = Diversifier(diversifier_bytes);
430
431 Address::from_components(
432 diversifier,
433 ka::Public(pk_d_bytes),
434 fmd::ClueKey(clue_key_bytes),
435 )
436 .ok_or_else(|| anyhow::anyhow!("could not create address from components"))
437 }
438}
439
440#[allow(dead_code)]
443mod assert_address_is_send_and_sync {
444 fn is_send<T: Send>() {}
445 fn is_sync<T: Sync>() {}
446 fn f() {
447 is_send::<super::Address>();
448 is_sync::<super::Address>();
449 }
450}
451
452#[cfg(test)]
453mod tests {
454 use std::str::FromStr;
455
456 use rand_core::OsRng;
457
458 use super::*;
459 use crate::keys::{Bip44Path, SeedPhrase, SpendKey};
460
461 #[test]
462 fn test_address_encoding() {
463 let rng = OsRng;
464 let seed_phrase = SeedPhrase::generate(rng);
465 let sk = SpendKey::from_seed_phrase_bip44(seed_phrase, &Bip44Path::new(0));
466 let fvk = sk.full_viewing_key();
467 let ivk = fvk.incoming();
468 let (dest, _dtk_d) = ivk.payment_address(0u32.into());
469
470 let bech32m_addr = format!("{dest}");
471
472 let addr = Address::from_str(&bech32m_addr).expect("can decode valid address");
473
474 use penumbra_sdk_proto::Message;
475
476 let proto_addr = dest.encode_to_vec();
477 let proto_addr_bech32m = pb::Address {
478 inner: Vec::new(),
479 alt_bech32m: bech32m_addr,
480 }
481 .encode_to_vec();
482 let proto_addr_direct: pb::Address = dest.clone().into();
483 let addr_from_proto: Address = proto_addr_direct
484 .try_into()
485 .expect("can convert from proto back to address");
486
487 let addr2 = Address::decode(proto_addr.as_ref()).expect("can decode valid address");
488 let addr3 = Address::decode(proto_addr_bech32m.as_ref()).expect("can decode valid address");
489
490 assert_eq!(addr, dest);
491 assert_eq!(addr2, dest);
492 assert_eq!(addr3, dest);
493 assert_eq!(addr_from_proto, dest);
494 }
495
496 #[test]
497 fn test_compat_encoding() {
498 let rng = OsRng;
499 let seed_phrase = SeedPhrase::generate(rng);
500 let sk = SpendKey::from_seed_phrase_bip44(seed_phrase, &Bip44Path::new(0));
501 let fvk = sk.full_viewing_key();
502 let ivk = fvk.incoming();
503 let (dest, _dtk_d) = ivk.payment_address(0u32.into());
504
505 let bech32_addr = dest.compat_encoding();
506
507 let addr = Address::from_str(&bech32_addr).expect("can decode valid address");
508
509 let proto_addr = dest.encode_to_vec();
510
511 let addr2 = Address::decode(proto_addr.as_ref()).expect("can decode valid address");
512
513 assert_eq!(addr, dest);
514 assert_eq!(addr2, dest);
515 }
516
517 #[test]
518 fn test_bytes_roundtrip() {
519 let rng = OsRng;
520 let seed_phrase = SeedPhrase::generate(rng);
521 let sk = SpendKey::from_seed_phrase_bip44(seed_phrase, &Bip44Path::new(0));
522 let fvk = sk.full_viewing_key();
523 let ivk = fvk.incoming();
524 let (dest, _dtk_d) = ivk.payment_address(0u32.into());
525
526 let bytes = dest.to_vec();
527 let addr: Address = bytes.try_into().expect("can decode valid address");
528
529 assert_eq!(addr, dest);
530 }
531
532 #[test]
533 fn test_address_keys_are_diversified() {
534 let rng = OsRng;
535 let seed_phrase = SeedPhrase::generate(rng);
536 let sk = SpendKey::from_seed_phrase_bip44(seed_phrase, &Bip44Path::new(0));
537 let fvk = sk.full_viewing_key();
538 let ivk = fvk.incoming();
539 let (dest1, dtk_d1) = ivk.payment_address(0u32.into());
540 let (dest2, dtk_d2) = ivk.payment_address(1u32.into());
541
542 assert!(dest1.transmission_key() != dest2.transmission_key());
543 assert!(dest1.clue_key() != dest2.clue_key());
544 assert!(dtk_d1.to_bytes() != dtk_d2.to_bytes());
545 }
546}