1use mina_signer::{pubkey::*, BaseField};
2use o1_utils::field_helpers::FieldHelpers;
3use sha2::{Digest, Sha256};
4const MINA_ADDRESS_RAW_LEN: usize = 40;
5
6pub 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}