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