mina_tree/util/
pubkey.rs

1use mina_signer::{pubkey::*, BaseField};
2use o1_utils::field_helpers::FieldHelpers;
3use sha2::{Digest, Sha256};
4const MINA_ADDRESS_RAW_LEN: usize = 40;
5
6// Needed because of two invalid keys in mina's mainnet genesis ledger that we
7// must parse even if invalid to be able to reconstruct the genesis ledger.
8pub fn compressed_pubkey_from_address_maybe_with_error(address: &str) -> Result<CompressedPubKey> {
9    if address.len() != MINA_ADDRESS_LEN {
10        return Err(PubKeyError::AddressLength);
11    }
12
13    let bytes = bs58::decode(address)
14        .into_vec()
15        .map_err(|_| PubKeyError::AddressBase58)?;
16
17    if bytes.len() != MINA_ADDRESS_RAW_LEN {
18        return Err(PubKeyError::AddressRawByteLength);
19    }
20
21    let (raw, checksum) = (&bytes[..bytes.len() - 4], &bytes[bytes.len() - 4..]);
22    let hash = Sha256::digest(&Sha256::digest(raw)[..]);
23    if checksum != &hash[..4] {
24        return Err(PubKeyError::AddressChecksum);
25    }
26
27    let (version, x_bytes, y_parity) = (
28        &raw[..3],
29        &raw[3..bytes.len() - 5],
30        raw[bytes.len() - 5] == 0x01,
31    );
32    if version != [0xcb, 0x01, 0x01] {
33        return Err(PubKeyError::AddressVersion);
34    }
35
36    let x = BaseField::from_bytes(x_bytes).map_err(|_| PubKeyError::XCoordinateBytes)?;
37
38    Ok(CompressedPubKey {
39        x,
40        is_odd: y_parity,
41    })
42}
43
44#[test]
45fn compressed_from_invalid_address() {
46    let address = "B62qpyhbvLobnd4Mb52vP7LPFAasb2S6Qphq8h5VV8Sq1m7VNK1VZcW";
47    let pk =
48        compressed_pubkey_from_address_maybe_with_error(address).expect("failed to create pubkey");
49    assert_eq!(pk.into_address(), address);
50
51    let address = "B62qqdcf6K9HyBSaxqH5JVFJkc1SUEe1VzDc5kYZFQZXWSQyGHoino1";
52    let pk =
53        compressed_pubkey_from_address_maybe_with_error(address).expect("failed to create pubkey");
54    assert_eq!(pk.into_address(), address);
55}