1mod errors;
6mod network;
7mod payload;
8mod protocol;
9
10use std::borrow::Cow;
11use std::fmt;
12use std::hash::Hash;
13use std::str::FromStr;
14
15use data_encoding::Encoding;
16use data_encoding_macro::new_encoding;
17use fvm_ipld_encoding::strict_bytes;
18use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
19
20pub use self::errors::Error;
21pub use self::network::{Network, current_network, set_current_network};
22pub use self::payload::{DelegatedAddress, Payload};
23pub use self::protocol::Protocol;
24use crate::ActorID;
25
26const ADDRESS_ENCODER: Encoding = new_encoding! {
28 symbols: "abcdefghijklmnopqrstuvwxyz234567",
29 padding: None,
30};
31
32pub const PAYLOAD_HASH_LEN: usize = 20;
34
35pub const SECP_PUB_LEN: usize = 65;
37
38pub const BLS_PUB_LEN: usize = 48;
40
41pub const MAX_SUBADDRESS_LEN: usize = 54;
43
44pub const FIRST_NON_SINGLETON_ADDR: ActorID = 100;
46
47lazy_static::lazy_static! {
48 static ref BLS_ZERO_ADDR_BYTES: [u8; BLS_PUB_LEN] = {
49 let bz_addr = Network::Mainnet.parse_address("f3yaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaby2smx7a");
50 if let Ok(Address {payload: Payload::BLS(pubkey), ..}) = bz_addr {
51 pubkey
52 } else {
53 panic!("failed to parse BLS address from provided BLS_ZERO_ADDR string")
54 }
55 };
56}
57
58pub const CHECKSUM_HASH_LEN: usize = 4;
60
61pub const MAX_ADDRESS_LEN: usize = 65;
63
64const MAX_ADDRRESS_TEXT_LEN: usize = 138;
65const MAINNET_PREFIX: &str = "f";
66const TESTNET_PREFIX: &str = "t";
67
68#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
71#[cfg_attr(feature = "testing", derive(Default))]
72#[cfg_attr(feature = "arb", derive(arbitrary::Arbitrary))]
73pub struct Address {
74 payload: Payload,
75}
76
77impl Address {
78 fn new(protocol: Protocol, bz: &[u8]) -> Result<Self, Error> {
80 Ok(Self {
81 payload: Payload::new(protocol, bz)?,
82 })
83 }
84
85 pub fn from_bytes(bz: &[u8]) -> Result<Self, Error> {
87 if bz.len() < 2 {
88 Err(Error::InvalidLength)
89 } else {
90 let protocol = Protocol::from_byte(bz[0]).ok_or(Error::UnknownProtocol)?;
91 Self::new(protocol, &bz[1..])
92 }
93 }
94
95 pub const fn new_id(id: u64) -> Self {
97 Self {
98 payload: Payload::ID(id),
99 }
100 }
101
102 pub fn new_secp256k1(pubkey: &[u8]) -> Result<Self, Error> {
104 if pubkey.len() != SECP_PUB_LEN {
105 return Err(Error::InvalidSECPLength(pubkey.len()));
106 }
107 Ok(Self {
108 payload: Payload::Secp256k1(address_hash(pubkey)),
109 })
110 }
111
112 pub fn new_actor(data: &[u8]) -> Self {
114 Self {
115 payload: Payload::Actor(address_hash(data)),
116 }
117 }
118
119 pub fn new_delegated(ns: ActorID, subaddress: &[u8]) -> Result<Self, Error> {
121 Ok(Self {
122 payload: Payload::Delegated(DelegatedAddress::new(ns, subaddress)?),
123 })
124 }
125
126 pub fn new_bls(pubkey: &[u8]) -> Result<Self, Error> {
128 if pubkey.len() != BLS_PUB_LEN {
129 return Err(Error::InvalidBLSLength(pubkey.len()));
130 }
131 let mut key = [0u8; BLS_PUB_LEN];
132 key.copy_from_slice(pubkey);
133 Ok(Self {
134 payload: Payload::BLS(key),
135 })
136 }
137
138 pub fn is_bls_zero_address(&self) -> bool {
139 match self.payload {
140 Payload::BLS(payload_bytes) => payload_bytes == *BLS_ZERO_ADDR_BYTES,
141 _ => false,
142 }
143 }
144
145 pub fn protocol(&self) -> Protocol {
147 Protocol::from(self.payload)
148 }
149
150 pub fn payload(&self) -> &Payload {
153 &self.payload
154 }
155
156 pub fn into_payload(self) -> Payload {
159 self.payload
160 }
161
162 pub fn payload_bytes(&self) -> Vec<u8> {
164 self.payload.to_raw_bytes()
165 }
166
167 pub fn to_bytes(self) -> Vec<u8> {
169 self.payload.to_bytes()
170 }
171
172 pub fn id(&self) -> Result<u64, Error> {
174 match self.payload {
175 Payload::ID(id) => Ok(id),
176 _ => Err(Error::NonIDAddress),
177 }
178 }
179}
180
181impl fmt::Display for Address {
182 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183 let protocol = self.protocol();
184
185 write!(f, "{}{}", current_network().to_prefix(), protocol)?;
187
188 fn write_payload(
189 f: &mut fmt::Formatter<'_>,
190 protocol: Protocol,
191 prefix: Option<&[u8]>,
192 data: &[u8],
193 ) -> fmt::Result {
194 let mut hasher = blake2b_simd::Params::new()
195 .hash_length(CHECKSUM_HASH_LEN)
196 .to_state();
197 hasher.update(&[protocol as u8]);
198 if let Some(prefix) = prefix {
199 hasher.update(prefix);
200 }
201 hasher.update(data);
202
203 let mut buf = Vec::with_capacity(data.len() + CHECKSUM_HASH_LEN);
204 buf.extend(data);
205 buf.extend(hasher.finalize().as_bytes());
206
207 f.write_str(&ADDRESS_ENCODER.encode(&buf))
208 }
209
210 match self.payload() {
211 Payload::ID(id) => write!(f, "{}", id),
212 Payload::Secp256k1(data) | Payload::Actor(data) => {
213 write_payload(f, protocol, None, data)
214 }
215 Payload::BLS(data) => write_payload(f, protocol, None, data),
216 Payload::Delegated(addr) => {
217 write!(f, "{}f", addr.namespace())?;
218 write_payload(
219 f,
220 protocol,
221 Some(unsigned_varint::encode::u64(
222 addr.namespace(),
223 &mut unsigned_varint::encode::u64_buffer(),
224 )),
225 addr.subaddress(),
226 )
227 }
228 }
229 }
230}
231
232#[cfg(feature = "arb")]
233impl quickcheck::Arbitrary for Address {
234 fn arbitrary(g: &mut quickcheck::Gen) -> Self {
235 Self {
236 payload: Payload::arbitrary(g),
237 }
238 }
239}
240
241fn parse_address(addr: &str) -> Result<(Address, Network), Error> {
242 if addr.len() > MAX_ADDRRESS_TEXT_LEN || addr.len() < 3 {
243 return Err(Error::InvalidLength);
244 }
245 let network = Network::from_prefix(addr.get(0..1).ok_or(Error::UnknownNetwork)?)?;
246
247 let protocol: Protocol = match addr.get(1..2).ok_or(Error::UnknownProtocol)? {
249 "0" => Protocol::ID,
250 "1" => Protocol::Secp256k1,
251 "2" => Protocol::Actor,
252 "3" => Protocol::BLS,
253 "4" => Protocol::Delegated,
254 _ => {
255 return Err(Error::UnknownProtocol);
256 }
257 };
258
259 fn validate_and_split_checksum<'a>(
260 protocol: Protocol,
261 prefix: Option<&[u8]>,
262 payload: &'a [u8],
263 ) -> Result<&'a [u8], Error> {
264 if payload.len() < CHECKSUM_HASH_LEN {
265 return Err(Error::InvalidLength);
266 }
267 let (payload, csum) = payload.split_at(payload.len() - CHECKSUM_HASH_LEN);
268 let mut hasher = blake2b_simd::Params::new()
269 .hash_length(CHECKSUM_HASH_LEN)
270 .to_state();
271 hasher.update(&[protocol as u8]);
272 if let Some(prefix) = prefix {
273 hasher.update(prefix);
274 }
275 hasher.update(payload);
276 if hasher.finalize().as_bytes() != csum {
277 return Err(Error::InvalidChecksum);
278 }
279 Ok(payload)
280 }
281
282 let raw = addr.get(2..).ok_or(Error::InvalidPayload)?;
284 let addr = match protocol {
285 Protocol::ID => {
286 if raw.len() > 20 {
287 return Err(Error::InvalidLength);
289 }
290 let id = raw.parse::<u64>()?;
291 Address {
292 payload: Payload::ID(id),
293 }
294 }
295 Protocol::Delegated => {
296 let (id, subaddr) = raw.split_once('f').ok_or(Error::InvalidPayload)?;
297 if id.len() > 20 {
298 return Err(Error::InvalidLength);
300 }
301 let id = id.parse::<u64>()?;
302 let subaddr_csum = ADDRESS_ENCODER.decode(subaddr.as_bytes())?;
304 let subaddr = validate_and_split_checksum(
306 protocol,
307 Some(unsigned_varint::encode::u64(
308 id,
309 &mut unsigned_varint::encode::u64_buffer(),
310 )),
311 &subaddr_csum,
312 )?;
313
314 Address {
315 payload: Payload::Delegated(DelegatedAddress::new(id, subaddr)?),
316 }
317 }
318 Protocol::Secp256k1 | Protocol::Actor | Protocol::BLS => {
319 let payload_csum = ADDRESS_ENCODER.decode(raw.as_bytes())?;
321 let payload = validate_and_split_checksum(protocol, None, &payload_csum)?;
323
324 if match protocol {
326 Protocol::Secp256k1 | Protocol::Actor => PAYLOAD_HASH_LEN,
327 Protocol::BLS => BLS_PUB_LEN,
328 _ => unreachable!(),
329 } != payload.len()
330 {
331 return Err(Error::InvalidPayload);
332 }
333
334 Address::new(protocol, payload)?
335 }
336 };
337 Ok((addr, network))
338}
339
340impl FromStr for Address {
341 type Err = Error;
342 fn from_str(addr: &str) -> Result<Self, Error> {
343 current_network().parse_address(addr)
344 }
345}
346
347impl Serialize for Address {
348 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
349 where
350 S: Serializer,
351 {
352 let address_bytes = self.to_bytes();
353 strict_bytes::Serialize::serialize(&address_bytes, s)
354 }
355}
356
357impl<'de> Deserialize<'de> for Address {
358 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
359 where
360 D: Deserializer<'de>,
361 {
362 let bz: Cow<'de, [u8]> = strict_bytes::Deserialize::deserialize(deserializer)?;
363
364 Address::from_bytes(&bz).map_err(de::Error::custom)
366 }
367}
368
369pub(crate) fn to_leb_bytes(id: u64) -> Vec<u8> {
370 unsigned_varint::encode::u64(id, &mut unsigned_varint::encode::u64_buffer()).into()
372}
373
374pub(crate) fn from_leb_bytes(bz: &[u8]) -> Result<u64, Error> {
375 let (id, remaining) = unsigned_varint::decode::u64(bz)?;
377 if !remaining.is_empty() {
378 return Err(Error::InvalidPayload);
379 }
380 Ok(id)
381}
382
383fn address_hash(ingest: &[u8]) -> [u8; 20] {
385 let digest = blake2b_simd::Params::new()
386 .hash_length(PAYLOAD_HASH_LEN)
387 .to_state()
388 .update(ingest)
389 .finalize();
390
391 let mut hash = [0u8; 20];
392 hash.copy_from_slice(digest.as_bytes());
393 hash
394}
395
396#[cfg(test)]
397mod tests {
398 use crate::address::errors::Error;
400 use crate::address::{from_leb_bytes, to_leb_bytes};
401
402 #[test]
403 fn test_from_leb_bytes_passing() {
404 let passing = vec![67];
405 assert_eq!(to_leb_bytes(from_leb_bytes(&passing).unwrap()), vec![67]);
406 }
407
408 #[test]
409 fn test_from_leb_bytes_extra_bytes() {
410 let extra_bytes = vec![67, 0, 1, 2];
411
412 match from_leb_bytes(&extra_bytes) {
413 Ok(id) => {
414 println!(
415 "Successfully decoded bytes when it was not supposed to. Result was: {:?}",
416 &to_leb_bytes(id)
417 );
418 panic!();
419 }
420 Err(e) => {
421 assert_eq!(e, Error::InvalidPayload);
422 }
423 }
424 }
425
426 #[test]
427 fn test_from_leb_bytes_minimal_encoding() {
428 let minimal_encoding = vec![67, 0, 130, 0];
429
430 match from_leb_bytes(&minimal_encoding) {
431 Ok(id) => {
432 println!(
433 "Successfully decoded bytes when it was not supposed to. Result was: {:?}",
434 &to_leb_bytes(id)
435 );
436 panic!();
437 }
438 Err(e) => {
439 assert_eq!(e, Error::InvalidPayload);
440 }
441 }
442 }
443}