noosphere_core/authority/
key_material.rs

1use crate::data::Mnemonic;
2use anyhow::{anyhow, Result};
3use bip39::{Language, Mnemonic as BipMnemonic};
4use ed25519_zebra::{SigningKey as Ed25519PrivateKey, VerificationKey as Ed25519PublicKey};
5use ucan::crypto::did::KeyConstructorSlice;
6use ucan_key_support::{
7    ed25519::{bytes_to_ed25519_key, Ed25519KeyMaterial, ED25519_MAGIC_BYTES},
8    rsa::{bytes_to_rsa_key, RSA_MAGIC_BYTES},
9};
10
11/// A common set of DID Key formats that are supported by this crate
12// TODO: Conditional web crypto support
13pub const SUPPORTED_KEYS: &KeyConstructorSlice = &[
14    (ED25519_MAGIC_BYTES, bytes_to_ed25519_key),
15    (RSA_MAGIC_BYTES, bytes_to_rsa_key),
16];
17
18/// Produce a unique [Ed25519KeyMaterial] for general purpose use cases
19pub fn generate_ed25519_key() -> Ed25519KeyMaterial {
20    let private_key = Ed25519PrivateKey::new(rand::thread_rng());
21    let public_key = Ed25519PublicKey::from(&private_key);
22    Ed25519KeyMaterial(public_key, Some(private_key))
23}
24
25/// Restore an [Ed25519KeyMaterial] from a [Mnemonic]
26pub fn restore_ed25519_key(mnemonic: &str) -> Result<Ed25519KeyMaterial> {
27    let mnemonic = BipMnemonic::from_phrase(mnemonic, Language::English)?;
28    let private_key = Ed25519PrivateKey::try_from(mnemonic.entropy())?;
29    let public_key = Ed25519PublicKey::from(&private_key);
30
31    Ok(Ed25519KeyMaterial(public_key, Some(private_key)))
32}
33
34/// Produce a [Mnemonic] for a given [Ed25519KeyMaterial]; note that the private
35/// part of the key must be available in the [Ed25519KeyMaterial] in order to
36/// produce the mnemonic.
37pub fn ed25519_key_to_mnemonic(key_material: &Ed25519KeyMaterial) -> Result<Mnemonic> {
38    let private_key = &key_material.1.ok_or_else(|| {
39        anyhow!(
40            "A mnemonic can only be generated for the key material if a private key is configured"
41        )
42    })?;
43    let mnemonic = BipMnemonic::from_entropy(private_key.as_ref(), Language::English)?;
44    Ok(Mnemonic(mnemonic.into_phrase()))
45}
46
47const ED25519_KEYPAIR_LENGTH: usize = 64;
48const ED25519_KEY_LENGTH: usize = 32;
49
50/// For a given [Ed25519KeyMaterial] produce a serialized byte array of the
51/// key that is suitable for persisting to secure storage.
52pub fn ed25519_key_to_bytes(
53    key_material: &Ed25519KeyMaterial,
54) -> Result<[u8; ED25519_KEYPAIR_LENGTH]> {
55    let public_key = key_material.0;
56    let private_key: Ed25519PrivateKey = key_material
57        .1
58        .ok_or_else(|| anyhow!("Private key required in order to deserialize."))?;
59
60    let mut bytes: [u8; ED25519_KEYPAIR_LENGTH] = [0u8; ED25519_KEYPAIR_LENGTH];
61    bytes[..ED25519_KEY_LENGTH].copy_from_slice(private_key.as_ref());
62    bytes[ED25519_KEY_LENGTH..].copy_from_slice(public_key.as_ref());
63    Ok(bytes)
64}