keri_core/prefix/
seed.rs

1use std::str::FromStr;
2
3use super::error::Error;
4use super::CesrPrimitive;
5use crate::keys::{KeysError, PrivateKey, PublicKey};
6use cesrox::{
7    conversion::from_text_to_bytes,
8    derivation_code::DerivationCode,
9    primitives::codes::{seed::SeedCode, PrimitiveCode},
10};
11use k256::ecdsa::{SigningKey, VerifyingKey};
12use serde::{Deserialize, Deserializer, Serialize, Serializer};
13
14#[derive(Debug, PartialEq, Clone)]
15pub enum SeedPrefix {
16    RandomSeed128(Vec<u8>),
17    RandomSeed256Ed25519(Vec<u8>),
18    RandomSeed256ECDSAsecp256k1(Vec<u8>),
19    RandomSeed448(Vec<u8>),
20}
21
22impl SeedPrefix {
23    pub fn new(code: SeedCode, value: Vec<u8>) -> Self {
24        match code {
25            SeedCode::RandomSeed128 => Self::RandomSeed128(value),
26            SeedCode::RandomSeed256Ed25519 => Self::RandomSeed256Ed25519(value),
27            SeedCode::RandomSeed256ECDSAsecp256k1 => Self::RandomSeed256ECDSAsecp256k1(value),
28            SeedCode::RandomSeed448 => Self::RandomSeed448(value),
29        }
30    }
31
32    pub fn derive_key_pair(&self) -> Result<(PublicKey, PrivateKey), Error> {
33        match self {
34            Self::RandomSeed256Ed25519(seed) => {
35                let key: &[u8; 32] = match seed.as_slice().try_into() {
36                    Ok(arr) => arr,
37                    Err(_) => return Err(KeysError::Ed25519DalekKeyError.into()),
38                };
39                let secret = ed25519_dalek::SigningKey::from_bytes(key);
40                let vk = PublicKey::new(secret.verifying_key().to_bytes().to_vec());
41                let sk = PrivateKey::new(secret.to_bytes().to_vec());
42                Ok((vk, sk))
43            }
44            Self::RandomSeed256ECDSAsecp256k1(seed) => {
45                let sk = SigningKey::from_bytes(seed).map_err(|_e| KeysError::EcdsaError)?;
46                Ok((
47                    PublicKey::new(VerifyingKey::from(&sk).to_bytes().to_vec()),
48                    PrivateKey::new(sk.to_bytes().to_vec()),
49                ))
50            }
51            _ => Err(Error::WrongSeedTypeError),
52        }
53    }
54}
55
56impl FromStr for SeedPrefix {
57    type Err = Error;
58
59    fn from_str(s: &str) -> Result<Self, Self::Err> {
60        let code = SeedCode::from_str(s)?;
61
62        if s.len() == code.full_size() {
63            let k_vec =
64                from_text_to_bytes(s[code.code_size()..].as_bytes())?[code.code_size()..].to_vec();
65            Ok(Self::new(code, k_vec))
66        } else {
67            Err(Error::IncorrectLengthError(s.into()))
68        }
69    }
70}
71
72impl CesrPrimitive for SeedPrefix {
73    fn derivative(&self) -> Vec<u8> {
74        match self {
75            Self::RandomSeed256Ed25519(seed) => seed.to_owned(),
76            Self::RandomSeed256ECDSAsecp256k1(seed) => seed.to_owned(),
77            Self::RandomSeed448(seed) => seed.to_owned(),
78            Self::RandomSeed128(seed) => seed.to_owned(),
79        }
80    }
81    fn derivation_code(&self) -> PrimitiveCode {
82        match self {
83            Self::RandomSeed256Ed25519(_) => PrimitiveCode::Seed(SeedCode::RandomSeed256Ed25519),
84            Self::RandomSeed256ECDSAsecp256k1(_) => {
85                PrimitiveCode::Seed(SeedCode::RandomSeed256ECDSAsecp256k1)
86            }
87            Self::RandomSeed448(_) => PrimitiveCode::Seed(SeedCode::RandomSeed448),
88            Self::RandomSeed128(_) => PrimitiveCode::Seed(SeedCode::RandomSeed448),
89        }
90    }
91}
92
93/// Serde compatible Serialize
94impl Serialize for SeedPrefix {
95    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
96    where
97        S: Serializer,
98    {
99        serializer.serialize_str(&self.to_str())
100    }
101}
102
103/// Serde compatible Deserialize
104impl<'de> Deserialize<'de> for SeedPrefix {
105    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
106    where
107        D: Deserializer<'de>,
108    {
109        let s = String::deserialize(deserializer)?;
110
111        SeedPrefix::from_str(&s).map_err(serde::de::Error::custom)
112    }
113}
114
115#[test]
116fn test_derive_keypair() -> Result<(), Error> {
117    use crate::prefix::basic::BasicPrefix;
118    use base64::URL_SAFE;
119
120    // taken from KERIPY: tests/core/test_eventing.py#1512
121    let seeds = vec![
122        "AK8F6AAiYDpXlWdj2O5F5-6wNCCNJh2A4XOlqwR_HwwH",
123        "AOs8-zNPPh0EhavdrCfCiTk9nGeO8e6VxUCzwdKXJAd0",
124        "AHMBU5PsIJN2U9m7j0SGyvs8YD8fkym2noELzxIrzfdG",
125        "AJZ7ZLd7unQ4IkMUwE69NXcvDO9rrmmRH_Xk3TPu9BpP",
126        "ANfkMQ5LKPfjEdQPK2c_zWsOn4GgLWsnWvIa25EVVbtR",
127        "ACrmDHtPQjnM8H9pyKA-QBNdfZ-xixTlRZTS8WXCrrMH",
128        "AMRXyU3ErhBNdRSDX1zKlrbZGRp1GfCmkRIa58gF07I8",
129        "AC6vsNVCpHa6acGcxk7c-D1mBHlptPrAx8zr-bKvesSW",
130    ];
131
132    let expected_pubkeys = vec![
133        "SuhyBcPZEZLK-fcw5tzHn2N46wRCG_ZOoeKtWTOunRA=",
134        "VcuJOOJF1IE8svqEtrSuyQjGTd2HhfAkt9y2QkUtFJI=",
135        "T1iAhBWCkvChxNWsby2J0pJyxBIxbAtbLA0Ljx-Grh8=",
136        "KPE5eeJRzkRTMOoRGVd2m18o8fLqM2j9kaxLhV3x8AQ=",
137        "1kcBE7h0ImWW6_Sp7MQxGYSshZZz6XM7OiUE5DXm0dU=",
138        "4JDgo3WNSUpt-NG14Ni31_GCmrU0r38yo7kgDuyGkQM=",
139        "VjWcaNX2gCkHOjk6rkmqPBCxkRCqwIJ-3OjdYmMwxf4=",
140        "T1nEDepd6CSAMCE7NY_jlLdG6_mKUlKS_mW-2HJY1hg=",
141    ];
142    let expected_basic_prefix = vec![
143        "DErocgXD2RGSyvn3MObcx59jeOsEQhv2TqHirVkzrp0Q",
144        "DFXLiTjiRdSBPLL6hLa0rskIxk3dh4XwJLfctkJFLRSS",
145        "DE9YgIQVgpLwocTVrG8tidKScsQSMWwLWywNC48fhq4f",
146        "DCjxOXniUc5EUzDqERlXdptfKPHy6jNo_ZGsS4Vd8fAE",
147        "DNZHARO4dCJlluv0qezEMRmErIWWc-lzOzolBOQ15tHV",
148        "DOCQ4KN1jUlKbfjRteDYt9fxgpq1NK9_MqO5IA7shpED",
149        "DFY1nGjV9oApBzo5Oq5JqjwQsZEQqsCCftzo3WJjMMX-",
150        "DE9ZxA3qXegkgDAhOzWP45S3Ruv5ilJSkv5lvthyWNYY",
151    ];
152
153    for (seed_str, (expected_pk, expected_bp)) in seeds
154        .iter()
155        .zip(expected_pubkeys.iter().zip(expected_basic_prefix.iter()))
156    {
157        let seed: SeedPrefix = seed_str.parse()?;
158        let (pub_key, _priv_key) = seed.derive_key_pair()?;
159        let b64_pubkey = base64::encode_config(pub_key.key(), URL_SAFE);
160        let bp = BasicPrefix::Ed25519(pub_key);
161        assert_eq!(&bp.to_str(), expected_bp);
162        assert_eq!(&b64_pubkey, expected_pk);
163    }
164
165    Ok(())
166}
167
168#[test]
169fn test_derive_from_seed() {
170    use cesrox::primitives::codes::seed::SeedCode;
171    use rand::rngs::OsRng;
172    let ed_keypair = ed25519_dalek::SigningKey::generate(&mut OsRng);
173
174    let sp = SeedPrefix::new(
175        SeedCode::RandomSeed256Ed25519,
176        ed_keypair.as_bytes().to_vec(),
177    );
178
179    let (derived_pub_key, derived_priv_key) = sp.derive_key_pair().unwrap();
180    assert_eq!(derived_pub_key.key(), ed_keypair.verifying_key().to_bytes());
181    assert_eq!(derived_priv_key.key(), ed_keypair.to_bytes());
182}