1#![no_std]
7#![cfg_attr(docsrs, feature(doc_cfg))]
8#![cfg_attr(feature = "frozen-abi", feature(min_specialization))]
9#![allow(clippy::arithmetic_side_effects)]
10
11#[cfg(feature = "error")]
12pub mod error;
13#[cfg(feature = "rand")]
14mod hasher;
15#[cfg(any(feature = "curve25519", feature = "syscalls"))]
16pub mod syscalls;
17
18#[cfg(feature = "sha2")]
19use crate::error::AddressError;
20#[cfg(feature = "decode")]
21use crate::error::ParseAddressError;
22#[cfg(all(feature = "rand", not(any(target_os = "solana", target_arch = "bpf"))))]
23pub use crate::hasher::{AddressHasher, AddressHasherBuilder};
24
25#[cfg(feature = "alloc")]
26extern crate alloc;
27#[cfg(feature = "std")]
28extern crate std;
29#[cfg(feature = "alloc")]
30use alloc::vec::Vec;
31#[cfg(feature = "dev-context-only-utils")]
32use arbitrary::Arbitrary;
33#[cfg(feature = "bytemuck")]
34use bytemuck_derive::{Pod, Zeroable};
35#[cfg(feature = "decode")]
36use core::str::FromStr;
37use core::{
38 array,
39 convert::TryFrom,
40 hash::{Hash, Hasher},
41 ptr::read_unaligned,
42};
43#[cfg(feature = "serde")]
44use serde_derive::{Deserialize, Serialize};
45#[cfg(feature = "borsh")]
46use {
47 alloc::string::ToString,
48 borsh::{BorshDeserialize, BorshSchema, BorshSerialize},
49};
50
51pub const ADDRESS_BYTES: usize = 32;
53pub const MAX_SEED_LEN: usize = 32;
55pub const MAX_SEEDS: usize = 16;
57#[cfg(feature = "decode")]
58const MAX_BASE58_LEN: usize = 44;
60
61#[cfg(target_arch = "bpf")]
63pub static PDA_MARKER: &[u8; 21] = b"ProgramDerivedAddress";
64#[cfg(not(target_arch = "bpf"))]
66pub const PDA_MARKER: &[u8; 21] = b"ProgramDerivedAddress";
67
68#[repr(transparent)]
83#[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))]
84#[cfg_attr(
85 feature = "borsh",
86 derive(BorshSerialize, BorshDeserialize),
87 borsh(crate = "borsh")
88)]
89#[cfg_attr(feature = "borsh", derive(BorshSchema))]
90#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
91#[cfg_attr(feature = "bytemuck", derive(Pod, Zeroable))]
92#[cfg_attr(feature = "dev-context-only-utils", derive(Arbitrary))]
93#[cfg_attr(not(feature = "decode"), derive(Debug))]
94#[cfg_attr(feature = "copy", derive(Copy))]
95#[derive(Clone, Default, Eq, Ord, PartialEq, PartialOrd)]
96pub struct Address(pub(crate) [u8; 32]);
97
98#[cfg(feature = "sanitize")]
99impl solana_sanitize::Sanitize for Address {}
100
101#[cfg(feature = "decode")]
102impl FromStr for Address {
103 type Err = ParseAddressError;
104
105 fn from_str(s: &str) -> Result<Self, Self::Err> {
106 use five8::DecodeError;
107 if s.len() > MAX_BASE58_LEN {
108 return Err(ParseAddressError::WrongSize);
109 }
110 let mut bytes = [0; ADDRESS_BYTES];
111 five8::decode_32(s, &mut bytes).map_err(|e| match e {
112 DecodeError::InvalidChar(_) => ParseAddressError::Invalid,
113 DecodeError::TooLong
114 | DecodeError::TooShort
115 | DecodeError::LargestTermTooHigh
116 | DecodeError::OutputTooLong => ParseAddressError::WrongSize,
117 })?;
118 Ok(Address(bytes))
119 }
120}
121
122impl Hash for Address {
127 fn hash<H: Hasher>(&self, state: &mut H) {
128 state.write(self.as_array());
129 }
130}
131
132impl From<&Address> for Address {
133 #[inline]
134 fn from(value: &Address) -> Self {
135 Self(value.0)
136 }
137}
138
139impl From<[u8; 32]> for Address {
140 #[inline]
141 fn from(from: [u8; 32]) -> Self {
142 Self(from)
143 }
144}
145
146impl TryFrom<&[u8]> for Address {
147 type Error = array::TryFromSliceError;
148
149 #[inline]
150 fn try_from(address: &[u8]) -> Result<Self, Self::Error> {
151 <[u8; 32]>::try_from(address).map(Self::from)
152 }
153}
154
155#[cfg(feature = "alloc")]
156impl TryFrom<Vec<u8>> for Address {
157 type Error = Vec<u8>;
158
159 #[inline]
160 fn try_from(address: Vec<u8>) -> Result<Self, Self::Error> {
161 <[u8; 32]>::try_from(address).map(Self::from)
162 }
163}
164#[cfg(feature = "decode")]
165impl TryFrom<&str> for Address {
166 type Error = ParseAddressError;
167 fn try_from(s: &str) -> Result<Self, Self::Error> {
168 Address::from_str(s)
169 }
170}
171
172#[cfg(any(target_os = "solana", target_arch = "bpf", feature = "curve25519"))]
176#[allow(clippy::used_underscore_binding)]
177pub fn bytes_are_curve_point<T: AsRef<[u8]>>(_bytes: T) -> bool {
178 #[cfg(not(any(target_os = "solana", target_arch = "bpf")))]
179 {
180 let Ok(compressed_edwards_y) =
181 curve25519_dalek::edwards::CompressedEdwardsY::from_slice(_bytes.as_ref())
182 else {
183 return false;
184 };
185 compressed_edwards_y.decompress().is_some()
186 }
187 #[cfg(any(target_os = "solana", target_arch = "bpf"))]
188 unimplemented!();
189}
190
191impl Address {
192 pub const fn new_from_array(address_array: [u8; 32]) -> Self {
193 Self(address_array)
194 }
195
196 #[cfg(feature = "decode")]
197 pub const fn from_str_const(s: &str) -> Self {
199 let id_array = five8_const::decode_32_const(s);
200 Address::new_from_array(id_array)
201 }
202
203 #[cfg(feature = "atomic")]
204 pub fn new_unique() -> Self {
206 use solana_atomic_u64::AtomicU64;
207 static I: AtomicU64 = AtomicU64::new(1);
208 type T = u32;
209 const COUNTER_BYTES: usize = core::mem::size_of::<T>();
210 let mut b = [0u8; ADDRESS_BYTES];
211 #[cfg(feature = "std")]
212 let mut i = I.fetch_add(1) as T;
213 #[cfg(not(feature = "std"))]
214 let i = I.fetch_add(1) as T;
215 b[0..COUNTER_BYTES].copy_from_slice(&i.to_be_bytes());
218 #[cfg(feature = "std")]
221 {
222 let mut hash = std::hash::DefaultHasher::new();
223 for slice in b[COUNTER_BYTES..].chunks_mut(COUNTER_BYTES) {
224 hash.write_u32(i);
225 i += 1;
226 slice.copy_from_slice(&hash.finish().to_ne_bytes()[0..COUNTER_BYTES]);
227 }
228 }
229 #[cfg(not(feature = "std"))]
232 {
233 for b in b[COUNTER_BYTES..].iter_mut() {
234 *b = (i & 0xFF) as u8;
235 }
236 }
237 Self::from(b)
238 }
239
240 #[cfg(feature = "sha2")]
245 pub fn create_with_seed(
246 base: &Address,
247 seed: &str,
248 owner: &Address,
249 ) -> Result<Address, AddressError> {
250 if seed.len() > MAX_SEED_LEN {
251 return Err(AddressError::MaxSeedLengthExceeded);
252 }
253
254 let owner = owner.as_ref();
255 if owner.len() >= PDA_MARKER.len() {
256 let slice = &owner[owner.len() - PDA_MARKER.len()..];
257 if slice == PDA_MARKER {
258 return Err(AddressError::IllegalOwner);
259 }
260 }
261 let hash = solana_sha256_hasher::hashv(&[base.as_ref(), seed.as_ref(), owner]);
262 Ok(Address::from(hash.to_bytes()))
263 }
264
265 pub const fn to_bytes(&self) -> [u8; 32] {
266 self.0
267 }
268
269 #[inline(always)]
271 pub const fn as_array(&self) -> &[u8; 32] {
272 &self.0
273 }
274
275 #[cfg(any(target_os = "solana", target_arch = "bpf", feature = "curve25519"))]
279 pub fn is_on_curve(&self) -> bool {
280 bytes_are_curve_point(self)
281 }
282
283 #[cfg(all(not(any(target_os = "solana", target_arch = "bpf")), feature = "std"))]
285 pub fn log(&self) {
286 std::println!("{}", std::string::ToString::to_string(&self));
287 }
288}
289
290impl AsRef<[u8]> for Address {
291 fn as_ref(&self) -> &[u8] {
292 &self.0[..]
293 }
294}
295
296impl AsMut<[u8]> for Address {
297 fn as_mut(&mut self) -> &mut [u8] {
298 &mut self.0[..]
299 }
300}
301
302#[cfg(feature = "decode")]
303fn write_as_base58(f: &mut core::fmt::Formatter, p: &Address) -> core::fmt::Result {
304 let mut out = [0u8; MAX_BASE58_LEN];
305 let len = five8::encode_32(&p.0, &mut out) as usize;
306 let as_str = unsafe { core::str::from_utf8_unchecked(&out[..len]) };
308 f.write_str(as_str)
309}
310
311#[cfg(feature = "decode")]
312impl core::fmt::Debug for Address {
313 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
314 write_as_base58(f, self)
315 }
316}
317
318#[cfg(feature = "decode")]
319impl core::fmt::Display for Address {
320 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
321 write_as_base58(f, self)
322 }
323}
324
325#[inline(always)]
336pub fn address_eq(a1: &Address, a2: &Address) -> bool {
337 let p1_ptr = a1.0.as_ptr().cast::<u64>();
338 let p2_ptr = a2.0.as_ptr().cast::<u64>();
339
340 unsafe {
341 read_unaligned(p1_ptr) == read_unaligned(p2_ptr)
342 && read_unaligned(p1_ptr.add(1)) == read_unaligned(p2_ptr.add(1))
343 && read_unaligned(p1_ptr.add(2)) == read_unaligned(p2_ptr.add(2))
344 && read_unaligned(p1_ptr.add(3)) == read_unaligned(p2_ptr.add(3))
345 }
346}
347
348#[cfg(feature = "decode")]
349#[macro_export]
365macro_rules! address {
366 ($input:literal) => {
367 $crate::Address::from_str_const($input)
368 };
369}
370
371#[cfg(feature = "decode")]
393#[macro_export]
394macro_rules! declare_id {
395 ($address:expr) => {
396 #[cfg(not(target_arch = "bpf"))]
397 pub const ID: $crate::Address = $crate::Address::from_str_const($address);
399 #[cfg(target_arch = "bpf")]
400 pub static ID: $crate::Address = $crate::Address::from_str_const($address);
402
403 pub fn check_id(id: &$crate::Address) -> bool {
407 id == &ID
408 }
409
410 pub const fn id() -> $crate::Address {
412 #[cfg(not(target_arch = "bpf"))]
413 {
414 ID
415 }
416 #[cfg(target_arch = "bpf")]
417 $crate::Address::from_str_const($address)
418 }
419
420 #[cfg(test)]
421 #[test]
422 fn test_id() {
423 assert!(check_id(&id()));
424 }
425 };
426}
427
428#[cfg(feature = "decode")]
430#[macro_export]
431macro_rules! declare_deprecated_id {
432 ($address:expr) => {
433 #[cfg(not(target_arch = "bpf"))]
434 pub const ID: $crate::Address = $crate::Address::from_str_const($address);
436 #[cfg(target_arch = "bpf")]
437 pub static ID: $crate::Address = $crate::Address::from_str_const($address);
439
440 #[deprecated()]
444 pub fn check_id(id: &$crate::Address) -> bool {
445 id == &ID
446 }
447
448 #[deprecated()]
450 pub const fn id() -> $crate::Address {
451 #[cfg(not(target_arch = "bpf"))]
452 {
453 ID
454 }
455 #[cfg(target_arch = "bpf")]
456 $crate::Address::from_str_const($address)
457 }
458
459 #[cfg(test)]
460 #[test]
461 #[allow(deprecated)]
462 fn test_id() {
463 assert!(check_id(&id()));
464 }
465 };
466}
467
468#[cfg(test)]
469mod tests {
470 use {super::*, core::str::from_utf8, std::string::String};
471
472 fn encode_address(address: &[u8; 32]) -> String {
473 let mut buffer = [0u8; 44];
474 let count = five8::encode_32(address, &mut buffer);
475 from_utf8(&buffer[..count as usize]).unwrap().to_string()
476 }
477
478 #[test]
479 fn test_new_unique() {
480 assert!(Address::new_unique() != Address::new_unique());
481 }
482
483 #[test]
484 fn address_fromstr() {
485 let address = Address::new_unique();
486 let mut address_base58_str = encode_address(&address.0);
487
488 assert_eq!(address_base58_str.parse::<Address>(), Ok(address));
489
490 address_base58_str.push_str(&encode_address(&address.0));
491 assert_eq!(
492 address_base58_str.parse::<Address>(),
493 Err(ParseAddressError::WrongSize)
494 );
495
496 address_base58_str.truncate(address_base58_str.len() / 2);
497 assert_eq!(address_base58_str.parse::<Address>(), Ok(address));
498
499 address_base58_str.truncate(address_base58_str.len() / 2);
500 assert_eq!(
501 address_base58_str.parse::<Address>(),
502 Err(ParseAddressError::WrongSize)
503 );
504
505 let mut address_base58_str = encode_address(&address.0);
506 assert_eq!(address_base58_str.parse::<Address>(), Ok(address));
507
508 address_base58_str.replace_range(..1, "I");
510 assert_eq!(
511 address_base58_str.parse::<Address>(),
512 Err(ParseAddressError::Invalid)
513 );
514
515 let mut too_long = encode_address(&[255u8; ADDRESS_BYTES]);
518 too_long.push('1');
520 assert_eq!(
521 too_long.parse::<Address>(),
522 Err(ParseAddressError::WrongSize)
523 );
524 }
525
526 #[test]
527 fn test_create_with_seed() {
528 assert!(
529 Address::create_with_seed(&Address::new_unique(), "☉", &Address::new_unique()).is_ok()
530 );
531 assert_eq!(
532 Address::create_with_seed(
533 &Address::new_unique(),
534 from_utf8(&[127; MAX_SEED_LEN + 1]).unwrap(),
535 &Address::new_unique()
536 ),
537 Err(AddressError::MaxSeedLengthExceeded)
538 );
539 assert!(Address::create_with_seed(
540 &Address::new_unique(),
541 "\
542 \u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\
543 ",
544 &Address::new_unique()
545 )
546 .is_ok());
547 assert_eq!(
549 Address::create_with_seed(
550 &Address::new_unique(),
551 "\
552 x\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\
553 ",
554 &Address::new_unique()
555 ),
556 Err(AddressError::MaxSeedLengthExceeded)
557 );
558
559 assert!(Address::create_with_seed(
560 &Address::new_unique(),
561 from_utf8(&[0; MAX_SEED_LEN]).unwrap(),
562 &Address::new_unique(),
563 )
564 .is_ok());
565
566 assert!(
567 Address::create_with_seed(&Address::new_unique(), "", &Address::new_unique(),).is_ok()
568 );
569
570 assert_eq!(
571 Address::create_with_seed(
572 &Address::default(),
573 "limber chicken: 4/45",
574 &Address::default(),
575 ),
576 Ok("9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq"
577 .parse()
578 .unwrap())
579 );
580 }
581
582 #[test]
583 fn test_create_program_address() {
584 let exceeded_seed = &[127; MAX_SEED_LEN + 1];
585 let max_seed = &[0; MAX_SEED_LEN];
586 let exceeded_seeds: &[&[u8]] = &[
587 &[1],
588 &[2],
589 &[3],
590 &[4],
591 &[5],
592 &[6],
593 &[7],
594 &[8],
595 &[9],
596 &[10],
597 &[11],
598 &[12],
599 &[13],
600 &[14],
601 &[15],
602 &[16],
603 &[17],
604 ];
605 let max_seeds: &[&[u8]] = &[
606 &[1],
607 &[2],
608 &[3],
609 &[4],
610 &[5],
611 &[6],
612 &[7],
613 &[8],
614 &[9],
615 &[10],
616 &[11],
617 &[12],
618 &[13],
619 &[14],
620 &[15],
621 &[16],
622 ];
623 let program_id = Address::from_str("BPFLoaderUpgradeab1e11111111111111111111111").unwrap();
624 let public_key = Address::from_str("SeedPubey1111111111111111111111111111111111").unwrap();
625
626 assert_eq!(
627 Address::create_program_address(&[exceeded_seed], &program_id),
628 Err(AddressError::MaxSeedLengthExceeded)
629 );
630 assert_eq!(
631 Address::create_program_address(&[b"short_seed", exceeded_seed], &program_id),
632 Err(AddressError::MaxSeedLengthExceeded)
633 );
634 assert!(Address::create_program_address(&[max_seed], &program_id).is_ok());
635 assert_eq!(
636 Address::create_program_address(exceeded_seeds, &program_id),
637 Err(AddressError::MaxSeedLengthExceeded)
638 );
639 assert!(Address::create_program_address(max_seeds, &program_id).is_ok());
640 assert_eq!(
641 Address::create_program_address(&[b"", &[1]], &program_id),
642 Ok("BwqrghZA2htAcqq8dzP1WDAhTXYTYWj7CHxF5j7TDBAe"
643 .parse()
644 .unwrap())
645 );
646 assert_eq!(
647 Address::create_program_address(&["☉".as_ref(), &[0]], &program_id),
648 Ok("13yWmRpaTR4r5nAktwLqMpRNr28tnVUZw26rTvPSSB19"
649 .parse()
650 .unwrap())
651 );
652 assert_eq!(
653 Address::create_program_address(&[b"Talking", b"Squirrels"], &program_id),
654 Ok("2fnQrngrQT4SeLcdToJAD96phoEjNL2man2kfRLCASVk"
655 .parse()
656 .unwrap())
657 );
658 assert_eq!(
659 Address::create_program_address(&[public_key.as_ref(), &[1]], &program_id),
660 Ok("976ymqVnfE32QFe6NfGDctSvVa36LWnvYxhU6G2232YL"
661 .parse()
662 .unwrap())
663 );
664 assert_ne!(
665 Address::create_program_address(&[b"Talking", b"Squirrels"], &program_id).unwrap(),
666 Address::create_program_address(&[b"Talking"], &program_id).unwrap(),
667 );
668 }
669
670 #[test]
671 fn test_address_off_curve() {
672 let mut addresses = std::vec![];
675 for _ in 0..1_000 {
676 let program_id = Address::new_unique();
677 let bytes1 = rand::random::<[u8; 10]>();
678 let bytes2 = rand::random::<[u8; 32]>();
679 if let Ok(program_address) =
680 Address::create_program_address(&[&bytes1, &bytes2], &program_id)
681 {
682 assert!(!program_address.is_on_curve());
683 assert!(!addresses.contains(&program_address));
684 addresses.push(program_address);
685 }
686 }
687 }
688
689 #[test]
690 fn test_find_program_address() {
691 for _ in 0..1_000 {
692 let program_id = Address::new_unique();
693 let (address, bump_seed) =
694 Address::find_program_address(&[b"Lil'", b"Bits"], &program_id);
695 assert_eq!(
696 address,
697 Address::create_program_address(&[b"Lil'", b"Bits", &[bump_seed]], &program_id)
698 .unwrap()
699 );
700 }
701 }
702
703 fn address_from_seed_by_marker(marker: &[u8]) -> Result<Address, AddressError> {
704 let key = Address::new_unique();
705 let owner = Address::default();
706
707 let mut to_fake = owner.to_bytes().to_vec();
708 to_fake.extend_from_slice(marker);
709
710 let seed = from_utf8(&to_fake[..to_fake.len() - 32]).expect("not utf8");
711 let base = &Address::try_from(&to_fake[to_fake.len() - 32..]).unwrap();
712
713 Address::create_with_seed(&key, seed, base)
714 }
715
716 #[test]
717 fn test_create_with_seed_rejects_illegal_owner() {
718 assert_eq!(
719 address_from_seed_by_marker(PDA_MARKER),
720 Err(AddressError::IllegalOwner)
721 );
722 assert!(address_from_seed_by_marker(&PDA_MARKER[1..]).is_ok());
723 }
724
725 #[test]
726 fn test_as_array() {
727 let bytes = [1u8; 32];
728 let key = Address::from(bytes);
729 assert_eq!(key.as_array(), &bytes);
730 assert_eq!(key.as_array(), &key.to_bytes());
731 assert_eq!(key.as_array().as_ptr(), key.0.as_ptr());
733 }
734
735 #[test]
736 fn test_address_macro() {
737 const ADDRESS: Address =
738 Address::from_str_const("9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq");
739 assert_eq!(
740 address!("9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq"),
741 ADDRESS
742 );
743 assert_eq!(
744 Address::from_str("9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq").unwrap(),
745 ADDRESS
746 );
747 }
748
749 #[test]
750 fn test_address_eq_matches_default_eq() {
751 for i in 0..u8::MAX {
752 let p1 = Address::from([i; ADDRESS_BYTES]);
753 let p2 = Address::from([i; ADDRESS_BYTES]);
754
755 assert!(p1 == p2);
757 assert!(p1.eq(&p2));
758 assert_eq!(p1.eq(&p2), p1.0 == p2.0);
759 assert!(address_eq(&p1, &p2));
760
761 let p3 = Address::from([u8::MAX - i; ADDRESS_BYTES]);
762
763 assert!(p1 != p3);
765 assert!(!p1.eq(&p3));
766 assert_eq!(!p1.eq(&p3), p1.0 != p3.0);
767 assert!(!address_eq(&p1, &p3));
768 }
769 }
770}