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 = "sha2")]
12mod derive;
13#[cfg(feature = "error")]
14pub mod error;
15#[cfg(feature = "rand")]
16mod hasher;
17#[cfg(any(feature = "curve25519", feature = "syscalls"))]
18pub mod syscalls;
19
20#[cfg(feature = "sha2")]
21use crate::error::AddressError;
22#[cfg(feature = "decode")]
23use crate::error::ParseAddressError;
24#[cfg(all(feature = "rand", not(any(target_os = "solana", target_arch = "bpf"))))]
25pub use crate::hasher::{AddressHasher, AddressHasherBuilder};
26
27#[cfg(feature = "alloc")]
28extern crate alloc;
29#[cfg(feature = "std")]
30extern crate std;
31#[cfg(feature = "alloc")]
32use alloc::vec::Vec;
33#[cfg(feature = "dev-context-only-utils")]
34use arbitrary::Arbitrary;
35#[cfg(feature = "bytemuck")]
36use bytemuck_derive::{Pod, Zeroable};
37#[cfg(feature = "decode")]
38use core::str::FromStr;
39use core::{
40 array,
41 convert::TryFrom,
42 hash::{Hash, Hasher},
43 ptr::read_unaligned,
44};
45#[cfg(feature = "serde")]
46use serde_derive::{Deserialize, Serialize};
47#[cfg(feature = "wincode")]
48use wincode::{SchemaRead, SchemaWrite};
49#[cfg(feature = "borsh")]
50use {
51 alloc::string::ToString,
52 borsh::{BorshDeserialize, BorshSchema, BorshSerialize},
53};
54
55pub const ADDRESS_BYTES: usize = 32;
57pub const MAX_SEED_LEN: usize = 32;
59pub const MAX_SEEDS: usize = 16;
61#[cfg(feature = "decode")]
62const MAX_BASE58_LEN: usize = 44;
64
65#[cfg(target_arch = "bpf")]
67pub static PDA_MARKER: &[u8; 21] = b"ProgramDerivedAddress";
68#[cfg(not(target_arch = "bpf"))]
70pub const PDA_MARKER: &[u8; 21] = b"ProgramDerivedAddress";
71
72#[repr(transparent)]
87#[cfg_attr(
88 feature = "frozen-abi",
89 derive(
90 solana_frozen_abi_macro::AbiExample,
91 solana_frozen_abi_macro::StableAbi,
92 solana_frozen_abi_macro::StableAbiSample
93 )
94)]
95#[cfg_attr(
96 feature = "borsh",
97 derive(BorshSerialize, BorshDeserialize),
98 borsh(crate = "borsh")
99)]
100#[cfg_attr(feature = "borsh", derive(BorshSchema))]
101#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
102#[cfg_attr(feature = "bytemuck", derive(Pod, Zeroable))]
103#[cfg_attr(feature = "wincode", derive(SchemaWrite, SchemaRead))]
104#[cfg_attr(feature = "dev-context-only-utils", derive(Arbitrary))]
105#[cfg_attr(not(feature = "decode"), derive(Debug))]
106#[cfg_attr(feature = "copy", derive(Copy))]
107#[derive(Clone, Default, Eq, Ord, PartialEq, PartialOrd)]
108pub struct Address(pub(crate) [u8; 32]);
109
110#[cfg(feature = "sanitize")]
111impl solana_sanitize::Sanitize for Address {}
112
113#[cfg(feature = "decode")]
114impl FromStr for Address {
115 type Err = ParseAddressError;
116
117 fn from_str(s: &str) -> Result<Self, Self::Err> {
118 use five8::DecodeError;
119 if s.len() > MAX_BASE58_LEN {
120 return Err(ParseAddressError::WrongSize);
121 }
122 let mut bytes = [0; ADDRESS_BYTES];
123 five8::decode_32(s, &mut bytes).map_err(|e| match e {
124 DecodeError::InvalidChar(_) => ParseAddressError::Invalid,
125 DecodeError::TooLong
126 | DecodeError::TooShort
127 | DecodeError::LargestTermTooHigh
128 | DecodeError::OutputTooLong => ParseAddressError::WrongSize,
129 })?;
130 Ok(Address(bytes))
131 }
132}
133
134impl Hash for Address {
139 fn hash<H: Hasher>(&self, state: &mut H) {
140 state.write(self.as_array());
141 }
142}
143
144impl From<&Address> for Address {
145 #[inline]
146 fn from(value: &Address) -> Self {
147 Self(value.0)
148 }
149}
150
151impl From<[u8; 32]> for Address {
152 #[inline]
153 fn from(from: [u8; 32]) -> Self {
154 Self(from)
155 }
156}
157
158impl TryFrom<&[u8]> for Address {
159 type Error = array::TryFromSliceError;
160
161 #[inline]
162 fn try_from(address: &[u8]) -> Result<Self, Self::Error> {
163 <[u8; 32]>::try_from(address).map(Self::from)
164 }
165}
166
167#[cfg(feature = "alloc")]
168impl TryFrom<Vec<u8>> for Address {
169 type Error = Vec<u8>;
170
171 #[inline]
172 fn try_from(address: Vec<u8>) -> Result<Self, Self::Error> {
173 <[u8; 32]>::try_from(address).map(Self::from)
174 }
175}
176
177#[cfg(feature = "decode")]
178impl TryFrom<&str> for Address {
179 type Error = ParseAddressError;
180 fn try_from(s: &str) -> Result<Self, Self::Error> {
181 Address::from_str(s)
182 }
183}
184
185#[cfg(any(feature = "curve25519", feature = "syscalls"))]
187#[inline(always)]
188pub fn bytes_are_curve_point<T: AsRef<[u8]>>(bytes: T) -> bool {
189 #[cfg(not(any(target_os = "solana", target_arch = "bpf")))]
190 {
191 #[cfg(feature = "curve25519")]
192 {
193 let Ok(compressed_edwards_y) =
194 curve25519_dalek::edwards::CompressedEdwardsY::from_slice(bytes.as_ref())
195 else {
196 return false;
197 };
198 compressed_edwards_y.decompress().is_some()
199 }
200
201 #[cfg(not(feature = "curve25519"))]
202 {
203 core::hint::black_box(bytes);
204 panic!("bytes_are_curve_point is only available with the `curve25519` feature enabled on this crate")
205 }
206 }
207
208 #[cfg(any(target_os = "solana", target_arch = "bpf"))]
209 {
210 const CURVE25519_EDWARDS: u64 = 0;
212
213 let result = unsafe {
218 syscalls::sol_curve_validate_point(
219 CURVE25519_EDWARDS,
220 bytes.as_ref() as *const _ as *const u8,
221 core::ptr::null_mut(),
222 )
223 };
224
225 result == 0
226 }
227}
228
229impl Address {
230 pub const fn new_from_array(address_array: [u8; 32]) -> Self {
231 Self(address_array)
232 }
233
234 #[cfg(feature = "decode")]
235 pub const fn from_str_const(s: &str) -> Self {
237 let id_array = five8_const::decode_32_const(s);
238 Address::new_from_array(id_array)
239 }
240
241 #[cfg(feature = "atomic")]
242 pub fn new_unique() -> Self {
244 use solana_atomic_u64::AtomicU64;
245 static I: AtomicU64 = AtomicU64::new(1);
246 type T = u32;
247 const COUNTER_BYTES: usize = core::mem::size_of::<T>();
248 let mut b = [0u8; ADDRESS_BYTES];
249 #[cfg(feature = "std")]
250 let mut i = I.fetch_add(1) as T;
251 #[cfg(not(feature = "std"))]
252 let i = I.fetch_add(1) as T;
253 b[0..COUNTER_BYTES].copy_from_slice(&i.to_be_bytes());
256 #[cfg(feature = "std")]
259 {
260 let mut hash = std::hash::DefaultHasher::new();
261 for slice in b[COUNTER_BYTES..].chunks_mut(COUNTER_BYTES) {
262 hash.write_u32(i);
263 i += 1;
264 slice.copy_from_slice(&hash.finish().to_ne_bytes()[0..COUNTER_BYTES]);
265 }
266 }
267 #[cfg(not(feature = "std"))]
270 {
271 for b in b[COUNTER_BYTES..].iter_mut() {
272 *b = (i & 0xFF) as u8;
273 }
274 }
275 Self::from(b)
276 }
277
278 #[cfg(feature = "sha2")]
283 pub fn create_with_seed(
284 base: &Address,
285 seed: &str,
286 owner: &Address,
287 ) -> Result<Address, AddressError> {
288 if seed.len() > MAX_SEED_LEN {
289 return Err(AddressError::MaxSeedLengthExceeded);
290 }
291
292 let owner = owner.as_ref();
293 if owner.len() >= PDA_MARKER.len() {
294 let slice = &owner[owner.len() - PDA_MARKER.len()..];
295 if slice == PDA_MARKER {
296 return Err(AddressError::IllegalOwner);
297 }
298 }
299 let hash = solana_sha256_hasher::hashv(&[base.as_ref(), seed.as_ref(), owner]);
300 Ok(Address::from(hash.to_bytes()))
301 }
302
303 pub const fn to_bytes(&self) -> [u8; 32] {
304 self.0
305 }
306
307 #[inline(always)]
309 pub const fn as_array(&self) -> &[u8; 32] {
310 &self.0
311 }
312
313 #[cfg(any(feature = "curve25519", feature = "syscalls"))]
319 #[inline(always)]
320 pub fn is_on_curve(&self) -> bool {
321 bytes_are_curve_point(self)
322 }
323
324 #[cfg(all(not(any(target_os = "solana", target_arch = "bpf")), feature = "std"))]
326 pub fn log(&self) {
327 std::println!("{}", std::string::ToString::to_string(&self));
328 }
329}
330
331impl AsRef<[u8]> for Address {
332 fn as_ref(&self) -> &[u8] {
333 &self.0[..]
334 }
335}
336
337impl AsMut<[u8]> for Address {
338 fn as_mut(&mut self) -> &mut [u8] {
339 &mut self.0[..]
340 }
341}
342
343#[cfg(feature = "decode")]
344fn write_as_base58(f: &mut core::fmt::Formatter, p: &Address) -> core::fmt::Result {
345 let mut out = [0u8; MAX_BASE58_LEN];
346 let len = five8::encode_32(&p.0, &mut out) as usize;
347 let as_str = unsafe { core::str::from_utf8_unchecked(&out[..len]) };
349 f.write_str(as_str)
350}
351
352#[cfg(feature = "decode")]
353impl core::fmt::Debug for Address {
354 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
355 write_as_base58(f, self)
356 }
357}
358
359#[cfg(feature = "decode")]
360impl core::fmt::Display for Address {
361 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
362 write_as_base58(f, self)
363 }
364}
365
366#[inline(always)]
377pub fn address_eq(a1: &Address, a2: &Address) -> bool {
378 let p1_ptr = a1.0.as_ptr().cast::<u64>();
379 let p2_ptr = a2.0.as_ptr().cast::<u64>();
380
381 unsafe {
382 read_unaligned(p1_ptr) == read_unaligned(p2_ptr)
383 && read_unaligned(p1_ptr.add(1)) == read_unaligned(p2_ptr.add(1))
384 && read_unaligned(p1_ptr.add(2)) == read_unaligned(p2_ptr.add(2))
385 && read_unaligned(p1_ptr.add(3)) == read_unaligned(p2_ptr.add(3))
386 }
387}
388
389#[cfg(feature = "nullable")]
393impl solana_nullable::Nullable for Address {
394 const NONE: Self = Address::new_from_array([0u8; ADDRESS_BYTES]);
395}
396
397#[cfg(feature = "decode")]
398#[macro_export]
414macro_rules! address {
415 ($input:literal) => {
416 $crate::Address::from_str_const($input)
417 };
418}
419
420#[cfg(feature = "decode")]
442#[macro_export]
443macro_rules! declare_id {
444 ($address:expr) => {
445 #[cfg(not(target_arch = "bpf"))]
446 pub const ID: $crate::Address = $crate::Address::from_str_const($address);
448 #[cfg(target_arch = "bpf")]
449 pub static ID: $crate::Address = $crate::Address::from_str_const($address);
451
452 pub fn check_id(id: &$crate::Address) -> bool {
456 id == &ID
457 }
458
459 pub const fn id() -> $crate::Address {
461 #[cfg(not(target_arch = "bpf"))]
462 {
463 ID
464 }
465 #[cfg(target_arch = "bpf")]
466 $crate::Address::from_str_const($address)
467 }
468
469 #[cfg(test)]
470 #[test]
471 fn test_id() {
472 assert!(check_id(&id()));
473 }
474 };
475}
476
477#[cfg(feature = "decode")]
479#[macro_export]
480macro_rules! declare_deprecated_id {
481 ($address:expr) => {
482 #[cfg(not(target_arch = "bpf"))]
483 pub const ID: $crate::Address = $crate::Address::from_str_const($address);
485 #[cfg(target_arch = "bpf")]
486 pub static ID: $crate::Address = $crate::Address::from_str_const($address);
488
489 #[deprecated()]
493 pub fn check_id(id: &$crate::Address) -> bool {
494 id == &ID
495 }
496
497 #[deprecated()]
499 pub const fn id() -> $crate::Address {
500 #[cfg(not(target_arch = "bpf"))]
501 {
502 ID
503 }
504 #[cfg(target_arch = "bpf")]
505 $crate::Address::from_str_const($address)
506 }
507
508 #[cfg(test)]
509 #[test]
510 #[allow(deprecated)]
511 fn test_id() {
512 assert!(check_id(&id()));
513 }
514 };
515}
516
517#[cfg(test)]
518mod tests {
519 use {super::*, core::str::from_utf8, std::string::String};
520
521 fn encode_address(address: &[u8; 32]) -> String {
522 let mut buffer = [0u8; 44];
523 let count = five8::encode_32(address, &mut buffer);
524 from_utf8(&buffer[..count as usize]).unwrap().to_string()
525 }
526
527 #[test]
528 fn test_new_unique() {
529 assert!(Address::new_unique() != Address::new_unique());
530 }
531
532 #[test]
533 fn address_fromstr() {
534 let address = Address::new_unique();
535 let mut address_base58_str = encode_address(&address.0);
536
537 assert_eq!(address_base58_str.parse::<Address>(), Ok(address));
538
539 address_base58_str.push_str(&encode_address(&address.0));
540 assert_eq!(
541 address_base58_str.parse::<Address>(),
542 Err(ParseAddressError::WrongSize)
543 );
544
545 address_base58_str.truncate(address_base58_str.len() / 2);
546 assert_eq!(address_base58_str.parse::<Address>(), Ok(address));
547
548 address_base58_str.truncate(address_base58_str.len() / 2);
549 assert_eq!(
550 address_base58_str.parse::<Address>(),
551 Err(ParseAddressError::WrongSize)
552 );
553
554 let mut address_base58_str = encode_address(&address.0);
555 assert_eq!(address_base58_str.parse::<Address>(), Ok(address));
556
557 address_base58_str.replace_range(..1, "I");
559 assert_eq!(
560 address_base58_str.parse::<Address>(),
561 Err(ParseAddressError::Invalid)
562 );
563
564 let mut too_long = encode_address(&[255u8; ADDRESS_BYTES]);
567 too_long.push('1');
569 assert_eq!(
570 too_long.parse::<Address>(),
571 Err(ParseAddressError::WrongSize)
572 );
573 }
574
575 #[test]
576 fn test_create_with_seed() {
577 assert!(
578 Address::create_with_seed(&Address::new_unique(), "☉", &Address::new_unique()).is_ok()
579 );
580 assert_eq!(
581 Address::create_with_seed(
582 &Address::new_unique(),
583 from_utf8(&[127; MAX_SEED_LEN + 1]).unwrap(),
584 &Address::new_unique()
585 ),
586 Err(AddressError::MaxSeedLengthExceeded)
587 );
588 assert!(Address::create_with_seed(
589 &Address::new_unique(),
590 "\
591 \u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\
592 ",
593 &Address::new_unique()
594 )
595 .is_ok());
596 assert_eq!(
598 Address::create_with_seed(
599 &Address::new_unique(),
600 "\
601 x\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\
602 ",
603 &Address::new_unique()
604 ),
605 Err(AddressError::MaxSeedLengthExceeded)
606 );
607
608 assert!(Address::create_with_seed(
609 &Address::new_unique(),
610 from_utf8(&[0; MAX_SEED_LEN]).unwrap(),
611 &Address::new_unique(),
612 )
613 .is_ok());
614
615 assert!(
616 Address::create_with_seed(&Address::new_unique(), "", &Address::new_unique(),).is_ok()
617 );
618
619 assert_eq!(
620 Address::create_with_seed(
621 &Address::default(),
622 "limber chicken: 4/45",
623 &Address::default(),
624 ),
625 Ok("9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq"
626 .parse()
627 .unwrap())
628 );
629 }
630
631 #[test]
632 fn test_create_program_address() {
633 let exceeded_seed = &[127; MAX_SEED_LEN + 1];
634 let max_seed = &[0; MAX_SEED_LEN];
635 let exceeded_seeds: &[&[u8]] = &[
636 &[1],
637 &[2],
638 &[3],
639 &[4],
640 &[5],
641 &[6],
642 &[7],
643 &[8],
644 &[9],
645 &[10],
646 &[11],
647 &[12],
648 &[13],
649 &[14],
650 &[15],
651 &[16],
652 &[17],
653 ];
654 let max_seeds: &[&[u8]] = &[
655 &[1],
656 &[2],
657 &[3],
658 &[4],
659 &[5],
660 &[6],
661 &[7],
662 &[8],
663 &[9],
664 &[10],
665 &[11],
666 &[12],
667 &[13],
668 &[14],
669 &[15],
670 &[16],
671 ];
672 let program_id = Address::from_str("BPFLoaderUpgradeab1e11111111111111111111111").unwrap();
673 let public_key = Address::from_str("SeedPubey1111111111111111111111111111111111").unwrap();
674
675 assert_eq!(
676 Address::create_program_address(&[exceeded_seed], &program_id),
677 Err(AddressError::MaxSeedLengthExceeded)
678 );
679 assert_eq!(
680 Address::create_program_address(&[b"short_seed", exceeded_seed], &program_id),
681 Err(AddressError::MaxSeedLengthExceeded)
682 );
683 assert!(Address::create_program_address(&[max_seed], &program_id).is_ok());
684 assert_eq!(
685 Address::create_program_address(exceeded_seeds, &program_id),
686 Err(AddressError::MaxSeedLengthExceeded)
687 );
688 assert!(Address::create_program_address(max_seeds, &program_id).is_ok());
689 assert_eq!(
690 Address::create_program_address(&[b"", &[1]], &program_id),
691 Ok("BwqrghZA2htAcqq8dzP1WDAhTXYTYWj7CHxF5j7TDBAe"
692 .parse()
693 .unwrap())
694 );
695 assert_eq!(
696 Address::create_program_address(&["☉".as_ref(), &[0]], &program_id),
697 Ok("13yWmRpaTR4r5nAktwLqMpRNr28tnVUZw26rTvPSSB19"
698 .parse()
699 .unwrap())
700 );
701 assert_eq!(
702 Address::create_program_address(&[b"Talking", b"Squirrels"], &program_id),
703 Ok("2fnQrngrQT4SeLcdToJAD96phoEjNL2man2kfRLCASVk"
704 .parse()
705 .unwrap())
706 );
707 assert_eq!(
708 Address::create_program_address(&[public_key.as_ref(), &[1]], &program_id),
709 Ok("976ymqVnfE32QFe6NfGDctSvVa36LWnvYxhU6G2232YL"
710 .parse()
711 .unwrap())
712 );
713 assert_ne!(
714 Address::create_program_address(&[b"Talking", b"Squirrels"], &program_id).unwrap(),
715 Address::create_program_address(&[b"Talking"], &program_id).unwrap(),
716 );
717 }
718
719 #[test]
720 fn test_address_off_curve() {
721 let mut addresses = std::vec![];
724 for _ in 0..1_000 {
725 let program_id = Address::new_unique();
726 let bytes1 = rand::random::<[u8; 10]>();
727 let bytes2 = rand::random::<[u8; 32]>();
728 if let Ok(program_address) =
729 Address::create_program_address(&[&bytes1, &bytes2], &program_id)
730 {
731 assert!(!program_address.is_on_curve());
732 assert!(!addresses.contains(&program_address));
733 addresses.push(program_address);
734 }
735 }
736 }
737
738 #[test]
739 fn test_find_program_address() {
740 for _ in 0..1_000 {
741 let program_id = Address::new_unique();
742 let (address, bump_seed) =
743 Address::find_program_address(&[b"Lil'", b"Bits"], &program_id);
744 assert_eq!(
745 address,
746 Address::create_program_address(&[b"Lil'", b"Bits", &[bump_seed]], &program_id)
747 .unwrap()
748 );
749 }
750 }
751
752 fn address_from_seed_by_marker(marker: &[u8]) -> Result<Address, AddressError> {
753 let key = Address::new_unique();
754 let owner = Address::default();
755
756 let mut to_fake = owner.to_bytes().to_vec();
757 to_fake.extend_from_slice(marker);
758
759 let seed = from_utf8(&to_fake[..to_fake.len() - 32]).expect("not utf8");
760 let base = &Address::try_from(&to_fake[to_fake.len() - 32..]).unwrap();
761
762 Address::create_with_seed(&key, seed, base)
763 }
764
765 #[test]
766 fn test_create_with_seed_rejects_illegal_owner() {
767 assert_eq!(
768 address_from_seed_by_marker(PDA_MARKER),
769 Err(AddressError::IllegalOwner)
770 );
771 assert!(address_from_seed_by_marker(&PDA_MARKER[1..]).is_ok());
772 }
773
774 #[test]
775 fn test_as_array() {
776 let bytes = [1u8; 32];
777 let key = Address::from(bytes);
778 assert_eq!(key.as_array(), &bytes);
779 assert_eq!(key.as_array(), &key.to_bytes());
780 assert_eq!(key.as_array().as_ptr(), key.0.as_ptr());
782 }
783
784 #[test]
785 fn test_address_macro() {
786 const ADDRESS: Address =
787 Address::from_str_const("9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq");
788 assert_eq!(
789 address!("9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq"),
790 ADDRESS
791 );
792 assert_eq!(
793 Address::from_str("9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq").unwrap(),
794 ADDRESS
795 );
796 }
797
798 #[test]
799 fn test_address_eq_matches_default_eq() {
800 for i in 0..u8::MAX {
801 let p1 = Address::from([i; ADDRESS_BYTES]);
802 let p2 = Address::from([i; ADDRESS_BYTES]);
803
804 assert!(p1 == p2);
806 assert!(p1.eq(&p2));
807 assert_eq!(p1.eq(&p2), p1.0 == p2.0);
808 assert!(address_eq(&p1, &p2));
809
810 let p3 = Address::from([u8::MAX - i; ADDRESS_BYTES]);
811
812 assert!(p1 != p3);
814 assert!(!p1.eq(&p3));
815 assert_eq!(!p1.eq(&p3), p1.0 != p3.0);
816 assert!(!address_eq(&p1, &p3));
817 }
818 }
819}