1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
use anyhow::{anyhow, Result};
use bip39::{Language, Mnemonic};
use ed25519_zebra::{SigningKey as Ed25519PrivateKey, VerificationKey as Ed25519PublicKey};
use ucan::crypto::did::KeyConstructorSlice;
use ucan_key_support::{
    ed25519::{bytes_to_ed25519_key, Ed25519KeyMaterial, ED25519_MAGIC_BYTES},
    rsa::{bytes_to_rsa_key, RSA_MAGIC_BYTES},
};

// TODO: Conditional web crypto support
pub const SUPPORTED_KEYS: &KeyConstructorSlice = &[
    (ED25519_MAGIC_BYTES, bytes_to_ed25519_key),
    (RSA_MAGIC_BYTES, bytes_to_rsa_key),
];

pub fn generate_ed25519_key() -> Ed25519KeyMaterial {
    let private_key = Ed25519PrivateKey::new(rand::thread_rng());
    let public_key = Ed25519PublicKey::from(&private_key);
    Ed25519KeyMaterial(public_key, Some(private_key))
}

pub fn restore_ed25519_key(mnemonic: &str) -> Result<Ed25519KeyMaterial> {
    let mnemonic = Mnemonic::from_phrase(mnemonic, Language::English)?;
    let private_key = Ed25519PrivateKey::try_from(mnemonic.entropy())?;
    let public_key = Ed25519PublicKey::try_from(&private_key)?;

    Ok(Ed25519KeyMaterial(public_key, Some(private_key)))
}

pub fn ed25519_key_to_mnemonic(key_material: &Ed25519KeyMaterial) -> Result<String> {
    let private_key = &key_material.1.ok_or_else(|| {
        anyhow!(
            "A mnemonic can only be generated for the key material if a private key is configured"
        )
    })?;
    let mnemonic = Mnemonic::from_entropy(private_key.as_ref(), Language::English)?;
    Ok(mnemonic.into_phrase())
}

pub const ED25519_KEYPAIR_LENGTH: usize = 64;
pub const ED25519_KEY_LENGTH: usize = 32;
pub fn ed25519_key_to_bytes(
    key_material: &Ed25519KeyMaterial,
) -> Result<([u8; ED25519_KEYPAIR_LENGTH])> {
    let public_key = key_material.0;
    let private_key: Ed25519PrivateKey = key_material
        .1
        .ok_or_else(|| anyhow!("Private key required in order to deserialize."))?;

    let mut bytes: [u8; ED25519_KEYPAIR_LENGTH] = [0u8; ED25519_KEYPAIR_LENGTH];
    bytes[..ED25519_KEY_LENGTH].copy_from_slice(private_key.as_ref());
    bytes[ED25519_KEY_LENGTH..].copy_from_slice(public_key.as_ref());
    Ok(bytes)
}