1pub const ADDRESS_BYTES: usize = 32;
5
6pub const MAX_SEED_LEN: usize = 32;
8
9pub const MAX_SEEDS: usize = 16;
11
12pub const PDA_MARKER: &[u8; 21] = b"ProgramDerivedAddress";
14
15#[repr(transparent)]
25#[cfg_attr(feature = "copy", derive(Copy))]
26#[derive(Clone, Default, Ord, PartialOrd)]
27pub struct Address(pub(crate) [u8; 32]);
28
29impl PartialEq for Address {
30 #[inline(always)]
33 fn eq(&self, other: &Self) -> bool {
34 address_eq(self, other)
35 }
36}
37
38impl Eq for Address {}
41
42impl Address {
43 #[inline(always)]
45 pub const fn new_from_array(bytes: [u8; 32]) -> Self {
46 Self(bytes)
47 }
48
49 #[inline(always)]
51 pub const fn to_bytes(&self) -> [u8; 32] {
52 self.0
53 }
54
55 #[inline(always)]
57 pub const fn as_array(&self) -> &[u8; 32] {
58 &self.0
59 }
60}
61
62impl From<[u8; 32]> for Address {
63 #[inline(always)]
64 fn from(bytes: [u8; 32]) -> Self {
65 Self(bytes)
66 }
67}
68
69impl From<Address> for [u8; 32] {
70 #[inline(always)]
71 fn from(addr: Address) -> [u8; 32] {
72 addr.0
73 }
74}
75
76impl TryFrom<&[u8]> for Address {
77 type Error = core::array::TryFromSliceError;
78
79 #[inline]
80 fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
81 let arr: [u8; 32] = slice.try_into()?;
82 Ok(Self(arr))
83 }
84}
85
86impl AsRef<[u8]> for Address {
87 #[inline(always)]
88 fn as_ref(&self) -> &[u8] {
89 &self.0
90 }
91}
92
93impl AsMut<[u8]> for Address {
94 #[inline(always)]
95 fn as_mut(&mut self) -> &mut [u8] {
96 &mut self.0
97 }
98}
99
100impl AsRef<[u8; 32]> for Address {
101 #[inline(always)]
102 fn as_ref(&self) -> &[u8; 32] {
103 &self.0
104 }
105}
106
107impl core::hash::Hash for Address {
108 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
109 self.0.hash(state);
110 }
111}
112
113impl core::fmt::Debug for Address {
114 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
115 write!(f, "Address({:?})", &self.0[..4])
116 }
117}
118
119pub const fn decode_base58_32(input: &str) -> [u8; 32] {
121 let bytes = input.as_bytes();
122 let mut out = [0u8; ADDRESS_BYTES];
123 let mut i = 0;
124
125 while i < bytes.len() {
126 let mut carry = base58_digit(bytes[i]) as u32;
127 let mut j = ADDRESS_BYTES;
128
129 while j > 0 {
130 j -= 1;
131 let value = (out[j] as u32) * 58 + carry;
132 out[j] = value as u8;
133 carry = value >> 8;
134 }
135
136 if carry != 0 {
137 panic!("base58 address literal overflows 32 bytes");
138 }
139
140 i += 1;
141 }
142
143 out
144}
145
146const fn base58_digit(byte: u8) -> u8 {
147 match byte {
148 b'1'..=b'9' => byte - b'1',
149 b'A'..=b'H' => byte - b'A' + 9,
150 b'J'..=b'N' => byte - b'J' + 17,
151 b'P'..=b'Z' => byte - b'P' + 22,
152 b'a'..=b'k' => byte - b'a' + 33,
153 b'm'..=b'z' => byte - b'm' + 44,
154 _ => panic!("invalid base58 address literal"),
155 }
156}
157
158#[inline(always)]
165pub fn address_eq(a: &Address, b: &Address) -> bool {
166 let a_ptr = a.0.as_ptr() as *const u64;
167 let b_ptr = b.0.as_ptr() as *const u64;
168 unsafe {
172 core::ptr::read_unaligned(a_ptr) == core::ptr::read_unaligned(b_ptr)
173 && core::ptr::read_unaligned(a_ptr.add(1)) == core::ptr::read_unaligned(b_ptr.add(1))
174 && core::ptr::read_unaligned(a_ptr.add(2)) == core::ptr::read_unaligned(b_ptr.add(2))
175 && core::ptr::read_unaligned(a_ptr.add(3)) == core::ptr::read_unaligned(b_ptr.add(3))
176 }
177}
178
179#[macro_export]
183macro_rules! address {
184 ( $literal:expr ) => {
185 $crate::address::Address::new_from_array($crate::address::decode_base58_32($literal))
186 };
187}
188
189#[cfg(test)]
190mod tests {
191 use super::*;
192
193 #[test]
194 fn decodes_system_program_literal() {
195 const SYSTEM: [u8; 32] = decode_base58_32("11111111111111111111111111111111");
196 assert_eq!(SYSTEM, [0u8; 32]);
197 }
198
199 #[test]
200 fn address_macro_uses_local_decoder() {
201 const SYSTEM: Address = crate::address!("11111111111111111111111111111111");
202 assert_eq!(SYSTEM.to_bytes(), [0u8; 32]);
203 }
204
205 fn edge_patterns() -> [[u8; 32]; 6] {
207 let mut ramp = [0u8; 32];
208 let mut i = 0;
209 while i < 32 {
210 ramp[i] = i as u8;
211 i += 1;
212 }
213 let mut last_hi = [0u8; 32];
214 last_hi[31] = 0xFF;
215 let mut first_hi = [0u8; 32];
216 first_hi[0] = 0xFF;
217 [
218 [0u8; 32],
219 [0xFFu8; 32],
220 ramp,
221 last_hi,
222 first_hi,
223 [0xA5u8; 32],
224 ]
225 }
226
227 #[test]
228 fn address_eq_matches_bytewise_on_equal_arrays() {
229 for pat in edge_patterns() {
230 let a = Address::new_from_array(pat);
231 let b = Address::new_from_array(pat);
232 assert!(address_eq(&a, &b));
233 assert_eq!(a, b);
234 }
235 }
236
237 #[test]
238 fn address_eq_detects_single_byte_difference_at_every_index() {
239 for base in edge_patterns() {
240 for idx in 0..32 {
241 let mut other = base;
242 other[idx] ^= 0x01;
243 let a = Address::new_from_array(base);
244 let b = Address::new_from_array(other);
245 assert!(!address_eq(&a, &b), "missed diff at byte {idx}");
246 assert_ne!(a, b);
247 assert_eq!(address_eq(&a, &b), base == other);
249 }
250 }
251 }
252
253 #[test]
254 fn address_eq_differs_only_in_last_byte() {
255 let base = [7u8; 32];
256 let mut other = base;
257 other[31] = 8;
258 let a = Address::new_from_array(base);
259 let b = Address::new_from_array(other);
260 assert!(!address_eq(&a, &b));
261 assert_ne!(a, b);
262 }
263
264 #[test]
265 fn eq_is_consistent_with_derived_ord() {
266 use core::cmp::Ordering;
267 let patterns = edge_patterns();
268 for a in patterns {
269 for b in patterns {
270 let aa = Address::new_from_array(a);
271 let ab = Address::new_from_array(b);
272 assert_eq!(aa == ab, aa.cmp(&ab) == Ordering::Equal);
274 assert_eq!(aa == ab, a == b);
276 for idx in 0..32 {
277 let mut c = a;
278 c[idx] = c[idx].wrapping_add(1);
279 let ac = Address::new_from_array(c);
280 assert_eq!(aa == ac, aa.cmp(&ac) == Ordering::Equal);
281 assert_eq!(aa == ac, a == c);
282 }
283 }
284 }
285 }
286}