cml_chain/byron/
utils.rs

1use cbor_event::cbor;
2
3use super::*;
4use crate::{
5    address::{Address, AddressError},
6    crypto::BootstrapWitness,
7    genesis::network_info::NetworkInfo,
8};
9use cml_core::{
10    error::{DeserializeError, DeserializeFailure},
11    serialization::{Deserialize, ToBytes},
12};
13use cml_crypto::{
14    chain_crypto::{self, Sha3_256},
15    impl_hash_type, Bip32PrivateKey, Bip32PublicKey, CryptoError, Ed25519Signature,
16    LegacyDaedalusPrivateKey, PublicKey, RawBytesEncoding, TransactionHash,
17};
18use std::{convert::TryFrom, fmt};
19
20#[derive(Debug, thiserror::Error)]
21pub enum ByronAddressError {
22    #[error("UnknownNetwork: {0}")]
23    UnknownNetwork(ProtocolMagic),
24    #[error("InvalidCRC: found {found}, expected {expected}")]
25    InvalidCRC { found: Crc32, expected: Crc32 },
26}
27
28impl_hash_type!(AddressId, 28);
29// not sure if this is a hash but it likely is and has the same byte format
30impl_hash_type!(ByronScript, 32);
31impl_hash_type!(StakeholderId, 28);
32
33impl StakeholderId {
34    pub fn new(pubk: &Bip32PublicKey) -> StakeholderId {
35        // the reason for this unwrap is that we have to dynamically allocate 66 bytes
36        // to serialize 64 bytes in cbor (2 bytes of cbor overhead).
37        let buf = cbor!(pubk.0.as_ref()).unwrap();
38
39        let hash = Sha3_256::new(&buf);
40        StakeholderId(Blake2b224::new(hash.as_ref()).into())
41    }
42}
43
44impl AddrAttributes {
45    pub fn new_bootstrap_era(
46        hdap: Option<HDAddressPayload>,
47        protocol_magic: Option<ProtocolMagic>,
48    ) -> Self {
49        let adjusted_magic = match &protocol_magic {
50            Some(magic) => {
51                if *magic == NetworkInfo::mainnet().protocol_magic() {
52                    None
53                } else {
54                    protocol_magic
55                }
56            }
57            None => None,
58        };
59        AddrAttributes {
60            derivation_path: hdap,
61            stake_distribution: Some(StakeDistribution::BootstrapEra),
62            protocol_magic: adjusted_magic,
63        }
64    }
65    pub fn new_single_key(
66        pubk: &Bip32PublicKey,
67        hdap: Option<HDAddressPayload>,
68        protocol_magic: ProtocolMagic,
69    ) -> Self {
70        AddrAttributes {
71            derivation_path: hdap,
72            stake_distribution: Some(StakeDistribution::new_single_key(StakeholderId::new(pubk))),
73            protocol_magic: Some(protocol_magic),
74        }
75    }
76}
77
78impl AddressId {
79    pub fn new(
80        addr_type: ByronAddrType,
81        spending_data: &SpendingData,
82        attrs: &AddrAttributes,
83    ) -> Self {
84        // the reason for this unwrap is that we have to dynamically allocate 66 bytes
85        // to serialize 64 bytes in cbor (2 bytes of cbor overhead).
86        let addr_type_uint = addr_type as u32;
87        let buf = cbor!(&(&addr_type_uint, spending_data, attrs))
88            .expect("serialize the AddressId's digest data");
89
90        let hash = Sha3_256::new(&buf);
91        AddressId(*Blake2b224::new(hash.as_ref()).as_hash_bytes())
92    }
93}
94
95impl From<AddressContent> for ByronAddress {
96    fn from(content: AddressContent) -> Self {
97        let content_bytes = content.to_bytes();
98        let crc = super::crc32::crc32(&content_bytes).into();
99        ByronAddress { content, crc }
100    }
101}
102
103impl AddressContent {
104    pub fn hash_and_create(
105        addr_type: ByronAddrType,
106        spending_data: &SpendingData,
107        attributes: AddrAttributes,
108    ) -> AddressContent {
109        let address_id = AddressId::new(addr_type, spending_data, &attributes);
110        AddressContent::new(address_id, attributes, addr_type)
111    }
112
113    // bootstrap era + no hdpayload address
114    pub fn new_redeem(pubkey: PublicKey, protocol_magic: Option<ProtocolMagic>) -> Self {
115        let attributes = AddrAttributes::new_bootstrap_era(None, protocol_magic);
116        let addr_type = ByronAddrType::Redeem;
117        let spending_data = &SpendingData::new_spending_data_redeem(pubkey);
118
119        AddressContent::hash_and_create(addr_type, spending_data, attributes)
120    }
121
122    // bootstrap era + no hdpayload address
123    pub fn new_simple(xpub: Bip32PublicKey, protocol_magic: Option<ProtocolMagic>) -> Self {
124        let attributes = AddrAttributes::new_bootstrap_era(None, protocol_magic);
125        let addr_type = ByronAddrType::PublicKey;
126        let spending_data = SpendingData::new_spending_data_pub_key(xpub);
127
128        AddressContent::hash_and_create(addr_type, &spending_data, attributes)
129    }
130
131    /// Do we want to remove this or keep it for people who were using old Byron code?
132    pub fn to_address(&self) -> ByronAddress {
133        self.clone().into()
134    }
135
136    /// returns the byron protocol magic embedded in the address, or mainnet id if none is present
137    /// note: for bech32 addresses, you need to use network_id instead
138    pub fn byron_protocol_magic(&self) -> ProtocolMagic {
139        match self.addr_attributes.protocol_magic {
140            Some(x) => x,
141            None => NetworkInfo::mainnet().protocol_magic(), // mainnet is implied if omitted
142        }
143    }
144
145    pub fn network_id(&self) -> Result<u8, ByronAddressError> {
146        // premise: during the Byron-era, we had one mainnet (764824073) and many many testnets
147        // with each testnet getting a different protocol magic
148        // in Shelley, this changes so that:
149        // 1) all testnets use the same u8 protocol magic
150        // 2) mainnet is re-mapped to a single u8 protocol magic
151
152        // recall: in Byron mainnet, the network_id is omitted from the address to save a few bytes
153        // so here we return the mainnet id if none is found in the address
154
155        // mainnet is implied if omitted
156        let protocol_magic = self.byron_protocol_magic();
157        if protocol_magic == NetworkInfo::mainnet().protocol_magic() {
158            Ok(NetworkInfo::mainnet().network_id())
159        } else if protocol_magic == NetworkInfo::testnet().protocol_magic()
160            || protocol_magic == NetworkInfo::preprod().protocol_magic()
161            || protocol_magic == NetworkInfo::preview().protocol_magic()
162            || protocol_magic == NetworkInfo::sancho_testnet().protocol_magic()
163        {
164            Ok(NetworkInfo::testnet().network_id())
165        } else {
166            Err(ByronAddressError::UnknownNetwork(protocol_magic))
167        }
168    }
169
170    // icarus-style address (Ae2)
171    pub fn icarus_from_key(key: Bip32PublicKey, protocol_magic: ProtocolMagic) -> AddressContent {
172        // need to ensure we use None for mainnet since Byron-era addresses omitted the network id
173        let filtered_protocol_magic = if protocol_magic == NetworkInfo::mainnet().protocol_magic() {
174            None
175        } else {
176            Some(protocol_magic)
177        };
178        AddressContent::new_simple(key, filtered_protocol_magic)
179    }
180
181    /// Check if the Addr can be reconstructed with a specific xpub
182    pub fn identical_with_pubkey(&self, xpub: Bip32PublicKey) -> bool {
183        let addr_type = ByronAddrType::PublicKey;
184        let spending_data = SpendingData::new_spending_data_pub_key(xpub);
185        let newea = AddressContent::hash_and_create(
186            addr_type,
187            &spending_data,
188            self.addr_attributes.clone(),
189        );
190
191        *self == newea
192    }
193}
194
195impl ByronAddress {
196    pub fn to_base58(&self) -> String {
197        base58::encode(&self.to_bytes())
198    }
199
200    pub fn from_base58(s: &str) -> Result<ByronAddress, ParseExtendedAddrError> {
201        let bytes = base58::decode(s).map_err(ParseExtendedAddrError::Base58Error)?;
202        //.map_err(|_| JsError::from_str("ByronAddress::from_base58 failed to parse base58"))?;
203        Self::from_cbor_bytes(&bytes).map_err(ParseExtendedAddrError::DeserializeError)
204        //.map_err(|_| JsError::from_str("ByronAddress::from_base58 failed to parse bytes"))
205    }
206
207    pub fn is_valid(s: &str) -> bool {
208        use std::str::FromStr;
209        match ByronAddress::from_str(s) {
210            Ok(_v) => true,
211            Err(_err) => false,
212        }
213    }
214
215    pub fn to_address(self) -> Address {
216        self.into()
217    }
218
219    pub fn from_address(addr: &Address) -> Option<Self> {
220        match addr {
221            Address::Byron(byron) => Some(byron.clone()),
222            _ => None,
223        }
224    }
225}
226
227impl TryFrom<Address> for ByronAddress {
228    type Error = AddressError;
229
230    fn try_from(addr: Address) -> Result<Self, Self::Error> {
231        match addr {
232            Address::Byron(byron) => Ok(byron),
233            _ => Err(AddressError::WrongKind(addr.kind())),
234        }
235    }
236}
237
238impl From<ByronAddress> for Address {
239    fn from(byron: ByronAddress) -> Self {
240        Self::Byron(byron)
241    }
242}
243
244impl fmt::Display for ByronAddress {
245    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
246        write!(f, "{}", self.to_base58())
247    }
248}
249
250impl ::std::str::FromStr for ByronAddress {
251    type Err = ParseExtendedAddrError;
252    fn from_str(s: &str) -> Result<Self, Self::Err> {
253        Self::from_base58(s)
254    }
255}
256
257#[derive(Debug, thiserror::Error)]
258pub enum ParseExtendedAddrError {
259    #[error("Deserialize: {0:?}")]
260    DeserializeError(DeserializeError),
261    #[error("Base58: {0:?}")]
262    Base58Error(base58::Error),
263}
264
265pub fn make_daedalus_bootstrap_witness(
266    tx_body_hash: TransactionHash,
267    addr: ByronAddress,
268    key: LegacyDaedalusPrivateKey,
269) -> BootstrapWitness {
270    let chain_code = key.chaincode();
271
272    let pubkey = Bip32PublicKey::from_raw_bytes(key.as_ref().to_public().as_ref()).unwrap();
273    let vkey = pubkey.to_raw_key();
274    let signature =
275        Ed25519Signature::from_raw_bytes(key.as_ref().sign(&tx_body_hash.to_raw_bytes()).as_ref())
276            .unwrap();
277
278    BootstrapWitness::new(vkey, signature, chain_code, addr.content.addr_attributes).unwrap()
279}
280
281pub fn make_icarus_bootstrap_witness(
282    tx_body_hash: TransactionHash,
283    addr: ByronAddress,
284    key: &Bip32PrivateKey,
285) -> BootstrapWitness {
286    let chain_code = key.chaincode();
287
288    let raw_key = key.to_raw_key();
289    let vkey = raw_key.to_public();
290    let signature = raw_key.sign(tx_body_hash.to_raw_bytes());
291
292    BootstrapWitness::new(vkey, signature, chain_code, addr.content.addr_attributes).unwrap()
293}
294
295impl serde::Serialize for ByronAddress {
296    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
297    where
298        S: serde::Serializer,
299    {
300        serializer.serialize_str(&self.to_base58())
301    }
302}
303
304impl<'de> serde::de::Deserialize<'de> for ByronAddress {
305    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
306    where
307        D: serde::de::Deserializer<'de>,
308    {
309        let base58 = <String as serde::de::Deserialize>::deserialize(deserializer)?;
310        Self::from_base58(&base58).map_err(|_e| {
311            serde::de::Error::invalid_value(
312                serde::de::Unexpected::Str(&base58),
313                &"base58 byron address string",
314            )
315        })
316    }
317}
318
319impl schemars::JsonSchema for ByronAddress {
320    fn schema_name() -> String {
321        String::from("ByronAddress")
322    }
323    fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
324        String::json_schema(gen)
325    }
326    fn is_referenceable() -> bool {
327        String::is_referenceable()
328    }
329}
330
331#[cfg(test)]
332mod tests {
333    use super::ByronAddress;
334    use crate::genesis::network_info::NetworkInfo;
335    use cml_core::serialization::ToBytes;
336    use cml_crypto::{
337        chain_crypto::{self, Ed25519Bip32},
338        Deserialize,
339    };
340
341    fn assert_same_address(address: ByronAddress, xpub: chain_crypto::PublicKey<Ed25519Bip32>) {
342        assert!(
343            address.content.identical_with_pubkey(xpub.into()),
344            "{}",
345            "expected public key {xpub} to match address {address}",
346        )
347    }
348
349    #[test]
350    fn test_vector_1() {
351        let address: ByronAddress = "DdzFFzCqrhsrcTVhLygT24QwTnNqQqQ8mZrq5jykUzMveU26sxaH529kMpo7VhPrt5pwW3dXeB2k3EEvKcNBRmzCfcQ7dTkyGzTs658C".parse().unwrap();
352        let public_key = chain_crypto::PublicKey::<Ed25519Bip32>::from_binary(&[
353            0x6a, 0x50, 0x96, 0x89, 0xc6, 0x53, 0x17, 0x58, 0x65, 0x98, 0x5a, 0xd1, 0xe0, 0xeb,
354            0x5f, 0xf9, 0xad, 0xa6, 0x99, 0x7a, 0xa4, 0x03, 0xe6, 0x48, 0x61, 0x4b, 0x3b, 0x78,
355            0xfc, 0xba, 0x9c, 0x27, 0x30, 0x82, 0x28, 0xd9, 0x87, 0x2a, 0xf8, 0xb6, 0x5b, 0x98,
356            0x7f, 0xf2, 0x3e, 0x1a, 0x20, 0xcd, 0x90, 0xd8, 0x34, 0x6c, 0x31, 0xf0, 0xed, 0xb8,
357            0x99, 0x89, 0x52, 0xdc, 0x67, 0x66, 0x55, 0x80,
358        ])
359        .unwrap();
360        assert_same_address(address, public_key);
361    }
362
363    #[test]
364    fn test_vector_2() {
365        let address = "DdzFFzCqrht4it4GYgBp4J39FNnKBsPFejSppARXHCf2gGiTJcwXzpRvgDmxPvKQ8aZZmVqcLUz5L66a8Ja46pfKVtFRaKyn9eKdvpaC".parse().unwrap();
366        let public_key = chain_crypto::PublicKey::<Ed25519Bip32>::from_binary(&[
367            0xff, 0x7b, 0xf1, 0x29, 0x9d, 0xf3, 0xd7, 0x17, 0x98, 0xae, 0xfd, 0xc4, 0xae, 0xa7,
368            0xdb, 0x2f, 0x8d, 0xb7, 0x60, 0x46, 0x56, 0x94, 0x41, 0xea, 0xe5, 0x8b, 0x72, 0x23,
369            0xb6, 0x8b, 0x44, 0x04, 0x82, 0x15, 0xcb, 0xac, 0x94, 0xbc, 0xb7, 0xf2, 0xcf, 0x33,
370            0x6c, 0x6c, 0x18, 0xbc, 0x3e, 0x71, 0x3f, 0xfd, 0x82, 0x67, 0x59, 0x4f, 0xf6, 0x34,
371            0x93, 0x32, 0xce, 0x4f, 0x98, 0x04, 0xa7, 0xff,
372        ])
373        .unwrap();
374        assert_same_address(address, public_key)
375    }
376
377    #[test]
378    fn test_vector_3() {
379        let address = "DdzFFzCqrhsvNQtyViTvEdGxfdc5T1E5RorzFWjYodqjhFDy8fQxfDPccmTc4ePbvkiwvRkR8dtqQ1SHpH53fDSoxD17fo9f6WkRjjAA".parse().unwrap();
380        let public_key = chain_crypto::PublicKey::<Ed25519Bip32>::from_binary(&[
381            0x5c, 0x36, 0x51, 0xe0, 0xeb, 0x9d, 0x6d, 0xc9, 0x64, 0x07, 0x13, 0x7c, 0xcc, 0x1f,
382            0x37, 0x7a, 0x87, 0x94, 0x61, 0x77, 0xa5, 0x2c, 0xa3, 0x77, 0x2c, 0x6b, 0x4b, 0xeb,
383            0x72, 0x39, 0x50, 0xdc, 0x50, 0x22, 0x46, 0x68, 0x21, 0x8b, 0x8b, 0x36, 0x62, 0x02,
384            0xfe, 0x5b, 0x7d, 0x55, 0x6f, 0x50, 0x1c, 0x5c, 0x4e, 0x2d, 0x58, 0xe0, 0x54, 0x67,
385            0xe1, 0xab, 0xc0, 0x44, 0xc6, 0xc1, 0xbf, 0x8e,
386        ])
387        .unwrap();
388        assert_same_address(address, public_key)
389    }
390
391    #[test]
392    fn test_vector_4() {
393        let address = "DdzFFzCqrhsn7ZAhKy8mxkzW6G3wryM7K6bH38VAjE2FesJMxia3UviivMvGz146TP1FpDharxTE6nUgCCnZx2fmtKpmxAosg9Tf5b8y".parse().unwrap();
394        let public_key = chain_crypto::PublicKey::<Ed25519Bip32>::from_binary(&[
395            0xcd, 0x84, 0x2e, 0x01, 0x0d, 0x81, 0xa6, 0xbe, 0x1e, 0x16, 0x9f, 0xd6, 0x35, 0x21,
396            0xdb, 0xb9, 0x5f, 0x42, 0x41, 0xfc, 0x82, 0x3f, 0x45, 0xb1, 0xcf, 0x1a, 0x1c, 0xb4,
397            0xc5, 0x89, 0x57, 0x27, 0x1d, 0x4d, 0x14, 0x2a, 0x22, 0x94, 0xea, 0x5f, 0xa3, 0x16,
398            0xa4, 0xad, 0xbf, 0xcd, 0x59, 0x7a, 0x7c, 0x89, 0x6a, 0x52, 0xa9, 0xa3, 0xa9, 0xce,
399            0x49, 0x64, 0x4a, 0x10, 0x2d, 0x00, 0x71, 0x99,
400        ])
401        .unwrap();
402        assert_same_address(address, public_key)
403    }
404
405    #[test]
406    fn test_vector_5() {
407        let address = "DdzFFzCqrhssTCJf4sv664bdQURovAwzx1hNKkMkNLwMNyaxZFuPSDdZTTRMcoDyXHuCiZhbD4umvMJcWGkvFMMzBoBUW5UBdBbDqXGX".parse().unwrap();
408        let public_key = chain_crypto::PublicKey::<Ed25519Bip32>::from_binary(&[
409            0x5a, 0xac, 0x2d, 0xd0, 0xa8, 0xdc, 0x5d, 0x61, 0x0a, 0x4b, 0x6f, 0xdf, 0x3f, 0x5e,
410            0xf1, 0xb6, 0x4a, 0xcb, 0x76, 0xb1, 0xe8, 0x1f, 0x6a, 0x35, 0x70, 0x31, 0xfa, 0x19,
411            0xd5, 0xe6, 0x56, 0x9d, 0xcc, 0x37, 0xb7, 0xae, 0x6f, 0x39, 0x15, 0x82, 0xfb, 0x05,
412            0x4b, 0x72, 0xba, 0xda, 0x90, 0xab, 0x14, 0x6c, 0xdd, 0x01, 0x42, 0x0e, 0x4b, 0x40,
413            0x18, 0xf1, 0xa0, 0x55, 0x29, 0x82, 0xd2, 0x31,
414        ])
415        .unwrap();
416        assert_same_address(address, public_key)
417    }
418
419    #[test]
420    fn test_vector_6() {
421        let address = "DdzFFzCqrhsfi5fFjJUHYPSnfTYrnMohzh3PrrtrVQgwua33HWPKUdTJXo3o77pSGCmDNrjYaAiZmJddaPW9iHyUDatvU2WhX7MgnNMy".parse().unwrap();
422        let public_key = chain_crypto::PublicKey::<Ed25519Bip32>::from_binary(&[
423            0x2a, 0x6a, 0xd1, 0x51, 0x09, 0x96, 0xff, 0x2d, 0x10, 0x89, 0xcb, 0x8e, 0xd5, 0xf5,
424            0xc0, 0x61, 0xf6, 0xad, 0x0a, 0xfb, 0xb5, 0x3d, 0x95, 0x40, 0xa0, 0xfc, 0x89, 0xef,
425            0xc0, 0xa2, 0x63, 0xb9, 0x6d, 0xac, 0x00, 0xbd, 0x0d, 0x7b, 0xda, 0x7d, 0x16, 0x3a,
426            0x08, 0xdb, 0x20, 0xba, 0x64, 0xb6, 0x33, 0x4d, 0xca, 0x34, 0xea, 0xc8, 0x2c, 0xf7,
427            0xb4, 0x91, 0xc3, 0x5f, 0x5c, 0xae, 0xc7, 0xb0,
428        ])
429        .unwrap();
430        assert_same_address(address, public_key)
431    }
432
433    #[test]
434    fn test_vector_7() {
435        let address = "DdzFFzCqrhsy2zYMDQRCF4Nw34C3P7aT5B7JwHFQ6gLAeoHgVXurCLPCm3AeV1nTa1Nd46uDoNt16cnsPFkb4fpLi1J17AmvphCtGFz2".parse().unwrap();
436        let public_key = chain_crypto::PublicKey::<Ed25519Bip32>::from_binary(&[
437            0x0c, 0xd2, 0x15, 0x54, 0xa0, 0xf9, 0xb8, 0x25, 0x9c, 0x46, 0x88, 0xdd, 0x00, 0xfc,
438            0x01, 0x88, 0x43, 0x50, 0x79, 0x76, 0x4f, 0xa5, 0x50, 0xfb, 0x57, 0x38, 0x2b, 0xff,
439            0x43, 0xe2, 0xd8, 0xd8, 0x27, 0x27, 0x4e, 0x2a, 0x12, 0x9f, 0x86, 0xc3, 0x80, 0x88,
440            0x34, 0x37, 0x4d, 0xfe, 0x3f, 0xda, 0xa6, 0x28, 0x48, 0x30, 0xb8, 0xf6, 0xe4, 0x0d,
441            0x29, 0x93, 0xde, 0xa2, 0xfb, 0x0a, 0xbe, 0x82,
442        ])
443        .unwrap();
444        assert_same_address(address, public_key)
445    }
446
447    #[test]
448    fn test_vector_8() {
449        let address = "DdzFFzCqrht8ygB5pLM4uVbS2x4ek2NTDx6R3DJqP7fUaWEkx8RA9UFR8CHitp2R74XLDP876Pe3KLUByHnrWrKWnffpqPpm14rPCxeP".parse().unwrap();
450        let public_key = chain_crypto::PublicKey::<Ed25519Bip32>::from_binary(&[
451            0x1f, 0x0a, 0xb8, 0x33, 0xfd, 0xb1, 0xfa, 0x49, 0x58, 0xce, 0x74, 0x04, 0x81, 0x84,
452            0x5b, 0x3a, 0x26, 0x6e, 0xfa, 0xab, 0x2d, 0x65, 0xd1, 0x6b, 0xdd, 0x3d, 0xfe, 0x7f,
453            0xcb, 0xe4, 0x46, 0x30, 0x25, 0x9e, 0xd1, 0x91, 0x98, 0x93, 0x03, 0x9d, 0xfd, 0x40,
454            0x02, 0x4a, 0x72, 0x03, 0x45, 0x5b, 0x03, 0xd6, 0xd0, 0x0d, 0x0a, 0x5c, 0xd6, 0xee,
455            0x82, 0xde, 0x2e, 0xce, 0x73, 0x8a, 0xa1, 0xbf,
456        ])
457        .unwrap();
458        assert_same_address(address, public_key)
459    }
460
461    #[test]
462    fn test_vector_9() {
463        let address = "DdzFFzCqrhssTywqjv3dw3EakpEydWQcc3phQzR3YF9NPgQN9Ftkx68FfLLnpJ4vhWo9mAjx5EcpM1wNvorSySrpARZGfk5QugHkVs58".parse().unwrap();
464        let public_key = chain_crypto::PublicKey::<Ed25519Bip32>::from_binary(&[
465            0x16, 0xf7, 0xd2, 0x55, 0x32, 0x6d, 0x77, 0x6e, 0xc1, 0xb5, 0xed, 0xd2, 0x5f, 0x75,
466            0xd3, 0xe3, 0xeb, 0xe0, 0xb9, 0xd4, 0x9c, 0xdd, 0xb2, 0x46, 0xd8, 0x0c, 0xf4, 0x1b,
467            0x25, 0x24, 0x64, 0xb6, 0x24, 0x50, 0xa2, 0x4e, 0xf5, 0x98, 0x7b, 0x4b, 0xd6, 0x5e,
468            0x0d, 0x25, 0x23, 0x43, 0xab, 0xa8, 0xef, 0x77, 0x93, 0x34, 0x79, 0xde, 0xa8, 0xdd,
469            0xe2, 0x9e, 0xec, 0x56, 0xcc, 0x6a, 0xc0, 0x69,
470        ])
471        .unwrap();
472        assert_same_address(address, public_key)
473    }
474
475    #[test]
476    fn test_vector_10() {
477        let address = "DdzFFzCqrhsqTG4t3uq5UBqFrxhxGVM6bvF4q1QcZXqUpizFddEEip7dx5rbife2s9o2fRU3hVKhRp4higog7As8z42s4AMw6Pcu8vL4".parse().unwrap();
478        let public_key = chain_crypto::PublicKey::<Ed25519Bip32>::from_binary(&[
479            0x97, 0xb8, 0x6c, 0x69, 0xd1, 0x2a, 0xf1, 0x64, 0xdc, 0x87, 0xf2, 0x71, 0x26, 0x8f,
480            0x33, 0xbc, 0x4d, 0xee, 0xb0, 0xdf, 0xd3, 0x73, 0xc3, 0xfd, 0x3b, 0xac, 0xd4, 0x47,
481            0x53, 0xa3, 0x1d, 0xe7, 0x8f, 0x10, 0xe5, 0x55, 0x03, 0x7c, 0xd4, 0x00, 0x43, 0x6c,
482            0xcf, 0xd5, 0x38, 0x0d, 0xbb, 0xcd, 0x4d, 0x7c, 0x28, 0x0a, 0xef, 0x9e, 0xc7, 0x57,
483            0x4a, 0xe0, 0xac, 0xac, 0x0c, 0xf7, 0x9e, 0x89,
484        ])
485        .unwrap();
486        assert_same_address(address, public_key)
487    }
488
489    #[test]
490    fn byron_magic_parsing() {
491        // mainnet address w/ protocol magic omitted
492        let addr = ByronAddress::from_base58(
493            "Ae2tdPwUPEZ4YjgvykNpoFeYUxoyhNj2kg8KfKWN2FizsSpLUPv68MpTVDo",
494        )
495        .unwrap();
496        assert_eq!(
497            addr.content.byron_protocol_magic(),
498            NetworkInfo::mainnet().protocol_magic()
499        );
500        assert_eq!(
501            addr.content.network_id().unwrap(),
502            NetworkInfo::mainnet().network_id()
503        );
504
505        // original Byron testnet address
506        let addr = ByronAddress::from_base58(
507            "2cWKMJemoBaipzQe9BArYdo2iPUfJQdZAjm4iCzDA1AfNxJSTgm9FZQTmFCYhKkeYrede",
508        )
509        .unwrap();
510        assert_eq!(
511            addr.content.byron_protocol_magic(),
512            NetworkInfo::testnet().protocol_magic()
513        );
514        assert_eq!(
515            addr.content.network_id().unwrap(),
516            NetworkInfo::testnet().network_id()
517        );
518    }
519
520    #[test]
521    fn round_trip() {
522        // mainnet address
523        let start = "DdzFFzCqrhsqTG4t3uq5UBqFrxhxGVM6bvF4q1QcZXqUpizFddEEip7dx5rbife2s9o2fRU3hVKhRp4higog7As8z42s4AMw6Pcu8vL4";
524        let addr = ByronAddress::from_base58(start).unwrap();
525        let end = addr.content.to_address().to_base58();
526        assert_eq!(start, end);
527
528        // mainnet address w/ protocol magic omitted
529        let start = "Ae2tdPwUPEZ4YjgvykNpoFeYUxoyhNj2kg8KfKWN2FizsSpLUPv68MpTVDo";
530        let addr = ByronAddress::from_base58(start).unwrap();
531        let end = addr.content.to_address().to_base58();
532        assert_eq!(start, end);
533
534        // original Byron testnet address
535        let start = "2cWKMJemoBaipzQe9BArYdo2iPUfJQdZAjm4iCzDA1AfNxJSTgm9FZQTmFCYhKkeYrede";
536        let addr = ByronAddress::from_base58(start).unwrap();
537        let end = addr.content.to_address().to_base58();
538        assert_eq!(start, end);
539
540        // testnet genesis address
541        let start = "37btjrVyb4KEg6anTcJ9E4EAvYtNV9xXL6LNpA15YLhgvm9zJ1D2jwme574HikZ36rKdTwaUmpEicCoL1bDw4CtH5PNcFnTRGQNaFd5ai6Wvo6CZsi";
542        let addr = ByronAddress::from_base58(start).unwrap();
543        let end = addr.content.to_address().to_base58();
544        assert_eq!(start, end);
545    }
546
547    #[test]
548    fn parse_redeem_address() {
549        assert!(ByronAddress::is_valid(
550            "Ae2tdPwUPEZ3MHKkpT5Bpj549vrRH7nBqYjNXnCV8G2Bc2YxNcGHEa8ykDp"
551        ));
552        let byron_addr = ByronAddress::from_base58(
553            "Ae2tdPwUPEZ3MHKkpT5Bpj549vrRH7nBqYjNXnCV8G2Bc2YxNcGHEa8ykDp",
554        )
555        .unwrap();
556        assert_eq!(
557            byron_addr.to_base58(),
558            "Ae2tdPwUPEZ3MHKkpT5Bpj549vrRH7nBqYjNXnCV8G2Bc2YxNcGHEa8ykDp"
559        );
560        let byron_addr2 = ByronAddress::from_cbor_bytes(&byron_addr.to_bytes()).unwrap();
561        assert_eq!(
562            byron_addr2.to_base58(),
563            "Ae2tdPwUPEZ3MHKkpT5Bpj549vrRH7nBqYjNXnCV8G2Bc2YxNcGHEa8ykDp"
564        );
565    }
566}