key_resolver/
util.rs

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
8// multibase base58-btc header
9pub 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    // Convert the Ed25519 public key bytes into a CompressedEdwardsY point
68    let ed25519_point = CompressedEdwardsY(*ed25519_pubkey_bytes);
69
70    // Decompress the point to get the Edwards form of the point
71    let edwards_point = ed25519_point
72        .decompress()
73        .ok_or("Invalid Ed25519 public key")
74        .unwrap();
75
76    // Ensure the point is not the identity (neutral element)
77    if edwards_point.is_identity() {
78        return Err(Error::new(
79            "Invalid Ed25519 public key: point is the identity element",
80        ));
81    }
82
83    // Convert the Edwards point to the corresponding Montgomery point
84    let montgomery_point: MontgomeryPoint = edwards_point.to_montgomery();
85
86    // Return the Montgomery point as a byte array, which is the X25519 public key
87    Ok(montgomery_point.to_bytes())
88}
89
90pub fn ed25519_to_x25519_privkey(ed25519_privkey_bytes: &[u8; 32]) -> [u8; 32] {
91    // Step 1: Hash the Ed25519 private key using SHA-512
92    let hashed = Sha512::digest(ed25519_privkey_bytes);
93
94    // Step 2: Use the first 32 bytes of the hash as the X25519 private key
95    let mut x25519_privkey_bytes: [u8; 32] =
96        hashed[..32].try_into().expect("Slice must be 32 bytes");
97
98    // Step 3: Clamp the private key (set necessary bits)
99    x25519_privkey_bytes[0] &= 248; // Clear the 3 least significant bits
100    x25519_privkey_bytes[31] &= 127; // Clear the highest bit
101    x25519_privkey_bytes[31] |= 64; // Set the second highest bit
102
103    x25519_privkey_bytes
104}