1#![no_std]
7#![cfg_attr(docsrs, feature(doc_auto_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(target_os = "atlas")))]
23pub use crate::hasher::{AddressHasher, AddressHasherBuilder};
24
25#[cfg(feature = "std")]
26extern crate std;
27#[cfg(feature = "dev-context-only-utils")]
28use arbitrary::Arbitrary;
29#[cfg(feature = "bytemuck")]
30use bytemuck_derive::{Pod, Zeroable};
31#[cfg(feature = "decode")]
32use core::str::FromStr;
33use core::{
34 array,
35 convert::TryFrom,
36 hash::{Hash, Hasher},
37};
38#[cfg(feature = "serde")]
39use serde_derive::{Deserialize, Serialize};
40#[cfg(feature = "std")]
41use std::vec::Vec;
42#[cfg(feature = "borsh")]
43use {
44 borsh::{BorshDeserialize, BorshSchema, BorshSerialize},
45 std::string::ToString,
46};
47
48pub const ADDRESS_BYTES: usize = 32;
50pub const MAX_SEED_LEN: usize = 32;
52pub const MAX_SEEDS: usize = 16;
54#[cfg(feature = "decode")]
55const MAX_BASE58_LEN: usize = 44;
57
58#[cfg(feature = "sha2")]
59const PDA_MARKER: &[u8; 21] = b"ProgramDerivedAddress";
60
61#[repr(transparent)]
76#[cfg_attr(feature = "frozen-abi", derive(atlas_frozen_abi_macro::AbiExample))]
77#[cfg_attr(
78 feature = "borsh",
79 derive(BorshSerialize, BorshDeserialize),
80 borsh(crate = "borsh")
81)]
82#[cfg_attr(all(feature = "borsh", feature = "std"), derive(BorshSchema))]
83#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
84#[cfg_attr(feature = "bytemuck", derive(Pod, Zeroable))]
85#[derive(Clone, Copy, Default, Eq, Ord, PartialEq, PartialOrd)]
86#[cfg_attr(feature = "dev-context-only-utils", derive(Arbitrary))]
87pub struct Address(pub(crate) [u8; 32]);
88
89#[cfg(feature = "sanitize")]
90impl atlas_sanitize::Sanitize for Address {}
91
92#[cfg(feature = "decode")]
93impl FromStr for Address {
94 type Err = ParseAddressError;
95
96 fn from_str(s: &str) -> Result<Self, Self::Err> {
97 use five8::DecodeError;
98 if s.len() > MAX_BASE58_LEN {
99 return Err(ParseAddressError::WrongSize);
100 }
101 let mut bytes = [0; ADDRESS_BYTES];
102 five8::decode_32(s, &mut bytes).map_err(|e| match e {
103 DecodeError::InvalidChar(_) => ParseAddressError::Invalid,
104 DecodeError::TooLong
105 | DecodeError::TooShort
106 | DecodeError::LargestTermTooHigh
107 | DecodeError::OutputTooLong => ParseAddressError::WrongSize,
108 })?;
109 Ok(Address(bytes))
110 }
111}
112
113impl Hash for Address {
118 fn hash<H: Hasher>(&self, state: &mut H) {
119 state.write(self.as_array());
120 }
121}
122
123impl From<&Address> for Address {
124 #[inline]
125 fn from(value: &Address) -> Self {
126 *value
127 }
128}
129
130impl From<[u8; 32]> for Address {
131 #[inline]
132 fn from(from: [u8; 32]) -> Self {
133 Self(from)
134 }
135}
136
137impl TryFrom<&[u8]> for Address {
138 type Error = array::TryFromSliceError;
139
140 #[inline]
141 fn try_from(address: &[u8]) -> Result<Self, Self::Error> {
142 <[u8; 32]>::try_from(address).map(Self::from)
143 }
144}
145
146#[cfg(feature = "std")]
147impl TryFrom<Vec<u8>> for Address {
148 type Error = Vec<u8>;
149
150 #[inline]
151 fn try_from(address: Vec<u8>) -> Result<Self, Self::Error> {
152 <[u8; 32]>::try_from(address).map(Self::from)
153 }
154}
155#[cfg(feature = "decode")]
156impl TryFrom<&str> for Address {
157 type Error = ParseAddressError;
158 fn try_from(s: &str) -> Result<Self, Self::Error> {
159 Address::from_str(s)
160 }
161}
162
163#[cfg(any(target_os = "atlas", feature = "curve25519"))]
167#[allow(clippy::used_underscore_binding)]
168pub fn bytes_are_curve_point<T: AsRef<[u8]>>(_bytes: T) -> bool {
169 #[cfg(not(target_os = "atlas"))]
170 {
171 let Ok(compressed_edwards_y) =
172 curve25519_dalek::edwards::CompressedEdwardsY::from_slice(_bytes.as_ref())
173 else {
174 return false;
175 };
176 compressed_edwards_y.decompress().is_some()
177 }
178 #[cfg(target_os = "atlas")]
179 unimplemented!();
180}
181
182impl Address {
183 pub const fn new_from_array(address_array: [u8; 32]) -> Self {
184 Self(address_array)
185 }
186
187 #[cfg(feature = "decode")]
188 pub const fn from_str_const(s: &str) -> Self {
190 let id_array = five8_const::decode_32_const(s);
191 Address::new_from_array(id_array)
192 }
193
194 #[cfg(feature = "atomic")]
195 pub fn new_unique() -> Self {
197 use atlas_atomic_u64::AtomicU64;
198 static I: AtomicU64 = AtomicU64::new(1);
199 type T = u32;
200 const COUNTER_BYTES: usize = core::mem::size_of::<T>();
201 let mut b = [0u8; ADDRESS_BYTES];
202 #[cfg(feature = "std")]
203 let mut i = I.fetch_add(1) as T;
204 #[cfg(not(feature = "std"))]
205 let i = I.fetch_add(1) as T;
206 b[0..COUNTER_BYTES].copy_from_slice(&i.to_be_bytes());
209 #[cfg(feature = "std")]
212 {
213 let mut hash = std::hash::DefaultHasher::new();
214 for slice in b[COUNTER_BYTES..].chunks_mut(COUNTER_BYTES) {
215 hash.write_u32(i);
216 i += 1;
217 slice.copy_from_slice(&hash.finish().to_ne_bytes()[0..COUNTER_BYTES]);
218 }
219 }
220 #[cfg(not(feature = "std"))]
223 {
224 for b in b[COUNTER_BYTES..].iter_mut() {
225 *b = (i & 0xFF) as u8;
226 }
227 }
228 Self::from(b)
229 }
230
231 #[cfg(feature = "sha2")]
236 pub fn create_with_seed(
237 base: &Address,
238 seed: &str,
239 owner: &Address,
240 ) -> Result<Address, AddressError> {
241 if seed.len() > MAX_SEED_LEN {
242 return Err(AddressError::MaxSeedLengthExceeded);
243 }
244
245 let owner = owner.as_ref();
246 if owner.len() >= PDA_MARKER.len() {
247 let slice = &owner[owner.len() - PDA_MARKER.len()..];
248 if slice == PDA_MARKER {
249 return Err(AddressError::IllegalOwner);
250 }
251 }
252 let hash = atlas_sha256_hasher::hashv(&[base.as_ref(), seed.as_ref(), owner]);
253 Ok(Address::from(hash.to_bytes()))
254 }
255
256 pub const fn to_bytes(self) -> [u8; 32] {
257 self.0
258 }
259
260 #[inline(always)]
262 pub const fn as_array(&self) -> &[u8; 32] {
263 &self.0
264 }
265
266 #[cfg(any(target_os = "atlas", feature = "curve25519"))]
270 pub fn is_on_curve(&self) -> bool {
271 bytes_are_curve_point(self)
272 }
273}
274
275impl AsRef<[u8]> for Address {
276 fn as_ref(&self) -> &[u8] {
277 &self.0[..]
278 }
279}
280
281impl AsMut<[u8]> for Address {
282 fn as_mut(&mut self) -> &mut [u8] {
283 &mut self.0[..]
284 }
285}
286
287#[cfg(feature = "decode")]
288fn write_as_base58(f: &mut core::fmt::Formatter, p: &Address) -> core::fmt::Result {
289 let mut out = [0u8; MAX_BASE58_LEN];
290 let len = five8::encode_32(&p.0, &mut out) as usize;
291 let as_str = unsafe { core::str::from_utf8_unchecked(&out[..len]) };
293 f.write_str(as_str)
294}
295
296#[cfg(feature = "decode")]
297impl core::fmt::Debug for Address {
298 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
299 write_as_base58(f, self)
300 }
301}
302
303#[cfg(feature = "decode")]
304impl core::fmt::Display for Address {
305 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
306 write_as_base58(f, self)
307 }
308}
309
310#[macro_export]
326macro_rules! address {
327 ($input:literal) => {
328 $crate::Address::from_str_const($input)
329 };
330}
331
332#[cfg(test)]
333mod tests {
334 use {super::*, core::str::from_utf8, std::string::String};
335
336 fn encode_address(address: &[u8; 32]) -> String {
337 let mut buffer = [0u8; 44];
338 let count = five8::encode_32(address, &mut buffer);
339 from_utf8(&buffer[..count as usize]).unwrap().to_string()
340 }
341
342 #[test]
343 fn test_new_unique() {
344 assert!(Address::new_unique() != Address::new_unique());
345 }
346
347 #[test]
348 fn address_fromstr() {
349 let address = Address::new_unique();
350 let mut address_base58_str = encode_address(&address.0);
351
352 assert_eq!(address_base58_str.parse::<Address>(), Ok(address));
353
354 address_base58_str.push_str(&encode_address(&address.0));
355 assert_eq!(
356 address_base58_str.parse::<Address>(),
357 Err(ParseAddressError::WrongSize)
358 );
359
360 address_base58_str.truncate(address_base58_str.len() / 2);
361 assert_eq!(address_base58_str.parse::<Address>(), Ok(address));
362
363 address_base58_str.truncate(address_base58_str.len() / 2);
364 assert_eq!(
365 address_base58_str.parse::<Address>(),
366 Err(ParseAddressError::WrongSize)
367 );
368
369 let mut address_base58_str = encode_address(&address.0);
370 assert_eq!(address_base58_str.parse::<Address>(), Ok(address));
371
372 address_base58_str.replace_range(..1, "I");
374 assert_eq!(
375 address_base58_str.parse::<Address>(),
376 Err(ParseAddressError::Invalid)
377 );
378
379 let mut too_long = encode_address(&[255u8; ADDRESS_BYTES]);
382 too_long.push('1');
384 assert_eq!(
385 too_long.parse::<Address>(),
386 Err(ParseAddressError::WrongSize)
387 );
388 }
389
390 #[test]
391 fn test_create_with_seed() {
392 assert!(
393 Address::create_with_seed(&Address::new_unique(), "☉", &Address::new_unique()).is_ok()
394 );
395 assert_eq!(
396 Address::create_with_seed(
397 &Address::new_unique(),
398 from_utf8(&[127; MAX_SEED_LEN + 1]).unwrap(),
399 &Address::new_unique()
400 ),
401 Err(AddressError::MaxSeedLengthExceeded)
402 );
403 assert!(Address::create_with_seed(
404 &Address::new_unique(),
405 "\
406 \u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\
407 ",
408 &Address::new_unique()
409 )
410 .is_ok());
411 assert_eq!(
413 Address::create_with_seed(
414 &Address::new_unique(),
415 "\
416 x\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\
417 ",
418 &Address::new_unique()
419 ),
420 Err(AddressError::MaxSeedLengthExceeded)
421 );
422
423 assert!(Address::create_with_seed(
424 &Address::new_unique(),
425 from_utf8(&[0; MAX_SEED_LEN]).unwrap(),
426 &Address::new_unique(),
427 )
428 .is_ok());
429
430 assert!(
431 Address::create_with_seed(&Address::new_unique(), "", &Address::new_unique(),).is_ok()
432 );
433
434 assert_eq!(
435 Address::create_with_seed(
436 &Address::default(),
437 "limber chicken: 4/45",
438 &Address::default(),
439 ),
440 Ok("9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq"
441 .parse()
442 .unwrap())
443 );
444 }
445
446 #[test]
447 fn test_create_program_address() {
448 let exceeded_seed = &[127; MAX_SEED_LEN + 1];
449 let max_seed = &[0; MAX_SEED_LEN];
450 let exceeded_seeds: &[&[u8]] = &[
451 &[1],
452 &[2],
453 &[3],
454 &[4],
455 &[5],
456 &[6],
457 &[7],
458 &[8],
459 &[9],
460 &[10],
461 &[11],
462 &[12],
463 &[13],
464 &[14],
465 &[15],
466 &[16],
467 &[17],
468 ];
469 let max_seeds: &[&[u8]] = &[
470 &[1],
471 &[2],
472 &[3],
473 &[4],
474 &[5],
475 &[6],
476 &[7],
477 &[8],
478 &[9],
479 &[10],
480 &[11],
481 &[12],
482 &[13],
483 &[14],
484 &[15],
485 &[16],
486 ];
487 let program_id = Address::from_str("BPFLoaderUpgradeab1e11111111111111111111111").unwrap();
488 let public_key = Address::from_str("SeedPubey1111111111111111111111111111111111").unwrap();
489
490 assert_eq!(
491 Address::create_program_address(&[exceeded_seed], &program_id),
492 Err(AddressError::MaxSeedLengthExceeded)
493 );
494 assert_eq!(
495 Address::create_program_address(&[b"short_seed", exceeded_seed], &program_id),
496 Err(AddressError::MaxSeedLengthExceeded)
497 );
498 assert!(Address::create_program_address(&[max_seed], &program_id).is_ok());
499 assert_eq!(
500 Address::create_program_address(exceeded_seeds, &program_id),
501 Err(AddressError::MaxSeedLengthExceeded)
502 );
503 assert!(Address::create_program_address(max_seeds, &program_id).is_ok());
504 assert_eq!(
505 Address::create_program_address(&[b"", &[1]], &program_id),
506 Ok("BwqrghZA2htAcqq8dzP1WDAhTXYTYWj7CHxF5j7TDBAe"
507 .parse()
508 .unwrap())
509 );
510 assert_eq!(
511 Address::create_program_address(&["☉".as_ref(), &[0]], &program_id),
512 Ok("13yWmRpaTR4r5nAktwLqMpRNr28tnVUZw26rTvPSSB19"
513 .parse()
514 .unwrap())
515 );
516 assert_eq!(
517 Address::create_program_address(&[b"Talking", b"Squirrels"], &program_id),
518 Ok("2fnQrngrQT4SeLcdToJAD96phoEjNL2man2kfRLCASVk"
519 .parse()
520 .unwrap())
521 );
522 assert_eq!(
523 Address::create_program_address(&[public_key.as_ref(), &[1]], &program_id),
524 Ok("976ymqVnfE32QFe6NfGDctSvVa36LWnvYxhU6G2232YL"
525 .parse()
526 .unwrap())
527 );
528 assert_ne!(
529 Address::create_program_address(&[b"Talking", b"Squirrels"], &program_id).unwrap(),
530 Address::create_program_address(&[b"Talking"], &program_id).unwrap(),
531 );
532 }
533
534 #[test]
535 fn test_address_off_curve() {
536 let mut addresses = std::vec![];
539 for _ in 0..1_000 {
540 let program_id = Address::new_unique();
541 let bytes1 = rand::random::<[u8; 10]>();
542 let bytes2 = rand::random::<[u8; 32]>();
543 if let Ok(program_address) =
544 Address::create_program_address(&[&bytes1, &bytes2], &program_id)
545 {
546 assert!(!program_address.is_on_curve());
547 assert!(!addresses.contains(&program_address));
548 addresses.push(program_address);
549 }
550 }
551 }
552
553 #[test]
554 fn test_find_program_address() {
555 for _ in 0..1_000 {
556 let program_id = Address::new_unique();
557 let (address, bump_seed) =
558 Address::find_program_address(&[b"Lil'", b"Bits"], &program_id);
559 assert_eq!(
560 address,
561 Address::create_program_address(&[b"Lil'", b"Bits", &[bump_seed]], &program_id)
562 .unwrap()
563 );
564 }
565 }
566
567 fn address_from_seed_by_marker(marker: &[u8]) -> Result<Address, AddressError> {
568 let key = Address::new_unique();
569 let owner = Address::default();
570
571 let mut to_fake = owner.to_bytes().to_vec();
572 to_fake.extend_from_slice(marker);
573
574 let seed = from_utf8(&to_fake[..to_fake.len() - 32]).expect("not utf8");
575 let base = &Address::try_from(&to_fake[to_fake.len() - 32..]).unwrap();
576
577 Address::create_with_seed(&key, seed, base)
578 }
579
580 #[test]
581 fn test_create_with_seed_rejects_illegal_owner() {
582 assert_eq!(
583 address_from_seed_by_marker(PDA_MARKER),
584 Err(AddressError::IllegalOwner)
585 );
586 assert!(address_from_seed_by_marker(&PDA_MARKER[1..]).is_ok());
587 }
588
589 #[test]
590 fn test_as_array() {
591 let bytes = [1u8; 32];
592 let key = Address::from(bytes);
593 assert_eq!(key.as_array(), &bytes);
594 assert_eq!(key.as_array(), &key.to_bytes());
595 assert_eq!(key.as_array().as_ptr(), key.0.as_ptr());
597 }
598
599 #[test]
600 fn test_address_macro() {
601 const ADDRESS: Address =
602 Address::from_str_const("9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq");
603 assert_eq!(
604 address!("9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq"),
605 ADDRESS
606 );
607 assert_eq!(
608 Address::from_str("9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq").unwrap(),
609 ADDRESS
610 );
611 }
612}