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
93impl 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
103impl<'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 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}