1use curve25519_dalek::edwards::CompressedEdwardsY;
2use curve25519_dalek::traits::IsIdentity;
3use curve25519_dalek::MontgomeryPoint;
4use fi_common::error::Error;
5use sha2::Digest;
6use sha2::Sha512;
7
8pub const MULTIBASE_BASE58BTC_HEADER: &str = "z";
10
11pub fn multibase_decode(header: &[u8; 2], text: &String) -> Result<Vec<u8>, Error> {
12 let value_builder = multibase::decode(&text);
13 let (_, mut value) = match value_builder {
14 Ok(val) => val,
15 Err(error) => {
16 return Err(Error::new(error.to_string().as_str()));
17 }
18 };
19
20 if value[0] == header[0] && value[1] == header[1] {
21 value.remove(0);
22 value.remove(0);
23
24 return Ok(value);
25 }
26
27 Err(Error::new("Multibase value does not have expected header."))
28}
29
30pub fn multibase_encode(header: &[u8; 2], bytes: &mut Vec<u8>) -> String {
31 let mut content_bytes: Vec<u8> = Vec::from(header);
32 content_bytes.append(bytes);
33
34 let encoded_content_bytes = multibase::encode(multibase::Base::Base58Btc, content_bytes);
35
36 return encoded_content_bytes;
37}
38
39pub fn get_key_bytes_from_key_pair_bytes(
40 bytes: &mut Vec<u8>,
41 is_pub_key: bool,
42) -> Result<[u8; 32], Error> {
43 let len = bytes.len();
44 if len < 32 && len != 46 && len != 64 {
45 return Err(Error::new("Key pair byte length is not valid"));
46 }
47
48 while bytes.len() > 32 {
49 if is_pub_key || len != 64 {
50 bytes.remove(0);
51 } else {
52 bytes.remove(bytes.len() - 1);
53 }
54 }
55
56 let bytes_32: [u8; 32] = match (*bytes).clone().try_into() {
57 Ok(val) => val,
58 Err(_error) => {
59 return Err(Error::new("'ed25519_secret_key' length did not match"));
60 }
61 };
62
63 return Ok(bytes_32);
64}
65
66pub fn ed25519_to_x25519_pubkey(ed25519_pubkey_bytes: &[u8; 32]) -> Result<[u8; 32], Error> {
67 let ed25519_point = CompressedEdwardsY(*ed25519_pubkey_bytes);
69
70 let edwards_point = ed25519_point
72 .decompress()
73 .ok_or("Invalid Ed25519 public key")
74 .unwrap();
75
76 if edwards_point.is_identity() {
78 return Err(Error::new(
79 "Invalid Ed25519 public key: point is the identity element",
80 ));
81 }
82
83 let montgomery_point: MontgomeryPoint = edwards_point.to_montgomery();
85
86 Ok(montgomery_point.to_bytes())
88}
89
90pub fn ed25519_to_x25519_privkey(ed25519_privkey_bytes: &[u8; 32]) -> [u8; 32] {
91 let hashed = Sha512::digest(ed25519_privkey_bytes);
93
94 let mut x25519_privkey_bytes: [u8; 32] =
96 hashed[..32].try_into().expect("Slice must be 32 bytes");
97
98 x25519_privkey_bytes[0] &= 248; x25519_privkey_bytes[31] &= 127; x25519_privkey_bytes[31] |= 64; x25519_privkey_bytes
104}