keri_core/prefix/
mod.rs

1use crate::{
2    database::redb::rkyv_adapter::said_wrapper::SaidValue,
3    event::sections::key_config::SignatureError,
4};
5
6use self::error::Error;
7use cesrox::primitives::codes::PrimitiveCode;
8pub use cesrox::primitives::CesrPrimitive;
9use core::str::FromStr;
10use said::SelfAddressingIdentifier;
11use serde::{Deserialize, Deserializer, Serialize, Serializer};
12use std::fmt::Display;
13
14pub mod attached_signature;
15pub mod basic;
16pub mod cesr_adapter;
17pub mod error;
18pub mod seed;
19pub mod self_signing;
20
21pub use attached_signature::IndexedSignature;
22pub use basic::BasicPrefix;
23pub use seed::SeedPrefix;
24pub use self_signing::SelfSigningPrefix;
25
26#[derive(Debug, PartialEq, Clone, Eq, Hash, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
27#[rkyv(derive(Debug))]
28pub enum IdentifierPrefix {
29    Basic(BasicPrefix),
30    SelfAddressing(SaidValue),
31    SelfSigning(SelfSigningPrefix),
32}
33
34impl IdentifierPrefix {
35    pub fn self_addressing(said: SelfAddressingIdentifier) -> Self {
36        IdentifierPrefix::SelfAddressing(said.into())
37    }
38
39    pub fn basic(bp: BasicPrefix) -> Self {
40        IdentifierPrefix::Basic(bp)
41    }
42
43    pub fn self_signing(self_signing: SelfSigningPrefix) -> Self {
44        IdentifierPrefix::SelfSigning(self_signing)
45    }
46}
47
48impl Display for IdentifierPrefix {
49    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50        write!(f, "{}", self.to_str())
51    }
52}
53
54impl FromStr for IdentifierPrefix {
55    type Err = Error;
56    fn from_str(s: &str) -> Result<Self, Self::Err> {
57        match BasicPrefix::from_str(s) {
58            Ok(bp) => Ok(Self::Basic(bp)),
59            Err(_) => match SelfAddressingIdentifier::from_str(s) {
60                Ok(sa) => Ok(Self::SelfAddressing(sa.into())),
61                Err(_) => Ok(Self::SelfSigning(SelfSigningPrefix::from_str(s)?)),
62            },
63        }
64    }
65}
66
67impl CesrPrimitive for IdentifierPrefix {
68    fn derivative(&self) -> Vec<u8> {
69        match self {
70            Self::Basic(bp) => bp.derivative(),
71            Self::SelfAddressing(sap) => sap.said.derivative(),
72            Self::SelfSigning(ssp) => ssp.derivative(),
73        }
74    }
75    fn derivation_code(&self) -> PrimitiveCode {
76        match self {
77            Self::Basic(bp) => bp.derivation_code(),
78            Self::SelfAddressing(sap) => sap.said.derivation_code(),
79            Self::SelfSigning(ssp) => ssp.derivation_code(),
80        }
81    }
82}
83
84/// Serde compatible Serialize
85impl Serialize for IdentifierPrefix {
86    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
87    where
88        S: Serializer,
89    {
90        serializer.serialize_str(&self.to_str())
91    }
92}
93
94/// Serde compatible Deserialize
95impl<'de> Deserialize<'de> for IdentifierPrefix {
96    fn deserialize<D>(deserializer: D) -> Result<IdentifierPrefix, D::Error>
97    where
98        D: Deserializer<'de>,
99    {
100        let s = String::deserialize(deserializer)?;
101
102        IdentifierPrefix::from_str(&s).map_err(serde::de::Error::custom)
103    }
104}
105
106impl Default for IdentifierPrefix {
107    fn default() -> Self {
108        IdentifierPrefix::SelfAddressing(SelfAddressingIdentifier::default().into())
109    }
110}
111
112/// Verify
113///
114/// Uses a public key to verify a signature against some data, with
115/// the key and signature represented by Basic and Self-Signing Prefixes
116pub fn verify(
117    data: &[u8],
118    key: &BasicPrefix,
119    signature: &SelfSigningPrefix,
120) -> Result<bool, SignatureError> {
121    match key {
122        BasicPrefix::Ed25519(pk) | BasicPrefix::Ed25519NT(pk) => match signature {
123            SelfSigningPrefix::Ed25519Sha512(signature) => {
124                Ok(pk.verify_ed(data.as_ref(), signature))
125            }
126            _ => Err(SignatureError::WrongSignatureTypeError),
127        },
128        BasicPrefix::ECDSAsecp256k1(key) | BasicPrefix::ECDSAsecp256k1NT(key) => match signature {
129            SelfSigningPrefix::ECDSAsecp256k1Sha256(signature) => {
130                Ok(key.verify_ecdsa(data.as_ref(), signature))
131            }
132            _ => Err(SignatureError::WrongSignatureTypeError),
133        },
134        _ => Err(SignatureError::WrongKeyTypeError),
135    }
136}
137
138/// Derive
139///
140/// Derives the Basic Prefix corrosponding to the given Seed Prefix
141pub fn derive(seed: &SeedPrefix, transferable: bool) -> Result<BasicPrefix, Error> {
142    let (pk, _) = seed.derive_key_pair()?;
143    Ok(match seed {
144        SeedPrefix::RandomSeed256Ed25519(_) if transferable => BasicPrefix::Ed25519(pk),
145        SeedPrefix::RandomSeed256Ed25519(_) if !transferable => BasicPrefix::Ed25519NT(pk),
146        SeedPrefix::RandomSeed256ECDSAsecp256k1(_) if transferable => {
147            BasicPrefix::ECDSAsecp256k1(pk)
148        }
149        SeedPrefix::RandomSeed256ECDSAsecp256k1(_) if !transferable => {
150            BasicPrefix::ECDSAsecp256k1NT(pk)
151        }
152        _ => return Err(Error::WrongSeedTypeError),
153    })
154}
155
156#[cfg(test)]
157mod tests {
158    use super::*;
159    use crate::keys::{PrivateKey, PublicKey};
160    use ed25519_dalek::SigningKey;
161    use rand::rngs::OsRng;
162    use said::derivation::{HashFunction, HashFunctionCode};
163
164    #[test]
165    fn simple_deserialize() -> Result<(), Error> {
166        let pref: IdentifierPrefix = "BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA".parse()?;
167
168        assert_eq!(pref.derivation_code().to_str(), "B");
169
170        assert_eq!(pref.derivative().len(), 32);
171
172        assert_eq!(pref.derivative().to_vec(), vec![0u8; 32]);
173
174        Ok(())
175    }
176
177    #[test]
178    fn length() -> Result<(), Error> {
179        // correct
180        assert!(IdentifierPrefix::from_str("BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA").is_ok());
181        assert!(IdentifierPrefix::from_str("CBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA").is_ok());
182
183        // too short
184        assert!(!IdentifierPrefix::from_str("BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA").is_ok());
185
186        // too long
187        assert!(
188            !IdentifierPrefix::from_str("BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA").is_ok()
189        );
190
191        // not a real prefix
192        assert!(
193            !IdentifierPrefix::from_str("ZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA").is_ok()
194        );
195
196        // not base 64 URL
197        assert!(
198            !IdentifierPrefix::from_str("BAAAAAAAAAAAAAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAA").is_ok()
199        );
200
201        Ok(())
202    }
203
204    #[test]
205    fn simple_serialize() -> Result<(), Error> {
206        let pref = BasicPrefix::Ed25519NT(PublicKey::new(
207            ed25519_dalek::VerifyingKey::from_bytes(&[0; 32])
208                .unwrap()
209                .to_bytes()
210                .to_vec(),
211        ));
212
213        assert_eq!(
214            pref.to_str(),
215            "BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
216        );
217
218        Ok(())
219    }
220
221    #[test]
222    fn verify() -> Result<(), Error> {
223        let data_string = "hello there";
224
225        let kp = SigningKey::generate(&mut OsRng);
226        let pub_key = PublicKey::new(kp.verifying_key().to_bytes().to_vec());
227        let priv_key = PrivateKey::new(kp.to_bytes().to_vec());
228
229        let key_prefix = BasicPrefix::Ed25519NT(pub_key);
230
231        let sig = priv_key.sign_ed(&data_string.as_bytes()).unwrap();
232        let sig_prefix = SelfSigningPrefix::Ed25519Sha512(sig);
233
234        let check = key_prefix.verify(&data_string.as_bytes(), &sig_prefix);
235        assert!(check.is_ok());
236        assert!(check.unwrap());
237
238        Ok(())
239    }
240
241    #[test]
242    fn prefix_deserialization() -> Result<(), Error> {
243        /// Helper function that checks whether all codes fulfill the condition
244        /// given by predicate `pred`.
245        fn all_codes<F>(codes: Vec<(&str, usize)>, pred: F) -> Result<(), Error>
246        where
247            F: Fn(IdentifierPrefix) -> bool,
248        {
249            for (code, length) in codes {
250                let pref: IdentifierPrefix =
251                    [code.to_string(), "A".repeat(length)].join("").parse()?;
252                assert!(pred(pref.clone()));
253                assert_eq!(pref.derivation_code().to_str(), code);
254            }
255            Ok(())
256        }
257
258        // All codes that are mapped to `BasicPrefix`.
259        let basic_codes = vec!["B", "C", "D", "L", "1AAA", "1AAB", "1AAC", "1AAD"].into_iter();
260        // Allowed string lengths for respective basic codes.
261        let allowed_lengths = vec![43, 43, 43, 75, 44, 44, 76, 76].into_iter();
262        let is_basic = |identifier| matches!(&identifier, IdentifierPrefix::Basic(_));
263        all_codes(basic_codes.zip(allowed_lengths).collect(), is_basic)?;
264
265        // All codes that are mapped to `SelfAddressingIdentifier`.
266        let self_adressing_codes =
267            vec!["E", "F", "G", "H", "I", "0D", "0E", "0F", "0G"].into_iter();
268        // Allowed string lengths for respective self addressing codes.
269        let allowed_lengths = vec![43, 43, 43, 43, 43, 86, 86, 86, 86].into_iter();
270        let is_self_addresing =
271            |identifier| matches!(&identifier, IdentifierPrefix::SelfAddressing(_));
272        all_codes(
273            self_adressing_codes.zip(allowed_lengths).collect(),
274            is_self_addresing,
275        )?;
276
277        // All codes that are mapped to `SelfSigningPrefix`.
278        let is_self_signing = |identifier| matches!(&identifier, IdentifierPrefix::SelfSigning(_));
279        // Allowed string lengths for respective self signing codes.
280        let self_signing_codes = vec!["0B", "0C", "1AAE"].into_iter();
281        let allowed_lengths = vec![86, 86, 152].into_iter();
282        all_codes(
283            self_signing_codes.zip(allowed_lengths).collect(),
284            is_self_signing,
285        )?;
286
287        Ok(())
288    }
289
290    #[test]
291    fn prefix_serialization() -> Result<(), Error> {
292        // The lengths of respective vectors are choosen according to [0, Section 14.2]
293        // [0]: https://github.com/SmithSamuelM/Papers/raw/master/whitepapers/KERI_WP_2.x.web.pdf
294
295        // Test BasicPrefix serialization.
296        assert_eq!(
297            BasicPrefix::Ed25519NT(PublicKey::new(
298                ed25519_dalek::VerifyingKey::from_bytes(&[0; 32])
299                    .unwrap()
300                    .to_bytes()
301                    .to_vec()
302            ))
303            .to_str(),
304            ["B".to_string(), "A".repeat(43)].join("")
305        );
306        assert_eq!(
307            BasicPrefix::X25519(PublicKey::new(
308                ed25519_dalek::VerifyingKey::from_bytes(&[0; 32])
309                    .unwrap()
310                    .to_bytes()
311                    .to_vec()
312            ))
313            .to_str(),
314            ["C".to_string(), "A".repeat(43)].join("")
315        );
316        assert_eq!(
317            BasicPrefix::Ed25519(PublicKey::new(
318                ed25519_dalek::VerifyingKey::from_bytes(&[0; 32])
319                    .unwrap()
320                    .to_bytes()
321                    .to_vec()
322            ))
323            .to_str(),
324            ["D".to_string(), "A".repeat(43)].join("")
325        );
326        assert_eq!(
327            BasicPrefix::X448(PublicKey::new([0; 56].to_vec())).to_str(),
328            ["L".to_string(), "A".repeat(75)].join("")
329        );
330        assert_eq!(
331            BasicPrefix::ECDSAsecp256k1NT(PublicKey::new([0; 33].to_vec())).to_str(),
332            ["1AAA".to_string(), "A".repeat(44)].join("")
333        );
334        assert_eq!(
335            BasicPrefix::ECDSAsecp256k1(PublicKey::new([0; 33].to_vec())).to_str(),
336            ["1AAB".to_string(), "A".repeat(44)].join("")
337        );
338        assert_eq!(
339            BasicPrefix::Ed448NT(PublicKey::new([0; 57].to_vec())).to_str(),
340            ["1AAC".to_string(), "A".repeat(76)].join("")
341        );
342        assert_eq!(
343            BasicPrefix::Ed448(PublicKey::new([0; 57].to_vec())).to_str(),
344            ["1AAD".to_string(), "A".repeat(76)].join("")
345        );
346
347        // Test SelfAddressingIdentifier serialization.
348        assert_eq!(
349            SelfAddressingIdentifier::new(HashFunctionCode::Blake3_256.into(), vec![0; 32])
350                .to_str(),
351            ["E".to_string(), "A".repeat(43)].join("")
352        );
353        assert_eq!(
354            SelfAddressingIdentifier::new(HashFunctionCode::Blake2B256(vec!()).into(), vec![0; 32])
355                .to_str(),
356            ["F".to_string(), "A".repeat(43)].join("")
357        );
358        assert_eq!(
359            SelfAddressingIdentifier::new(HashFunctionCode::Blake2S256(vec!()).into(), vec![0; 32])
360                .to_str(),
361            ["G".to_string(), "A".repeat(43)].join("")
362        );
363        assert_eq!(
364            SelfAddressingIdentifier::new(HashFunctionCode::SHA3_256.into(), vec![0; 32]).to_str(),
365            ["H".to_string(), "A".repeat(43)].join("")
366        );
367        assert_eq!(
368            SelfAddressingIdentifier::new(HashFunctionCode::SHA2_256.into(), vec![0; 32]).to_str(),
369            ["I".to_string(), "A".repeat(43)].join("")
370        );
371        assert_eq!(
372            SelfAddressingIdentifier::new(HashFunctionCode::Blake3_512.into(), vec![0; 64])
373                .to_str(),
374            ["0D".to_string(), "A".repeat(86)].join("")
375        );
376        assert_eq!(
377            SelfAddressingIdentifier::new(HashFunctionCode::SHA3_512.into(), vec![0; 64]).to_str(),
378            ["0E".to_string(), "A".repeat(86)].join("")
379        );
380        assert_eq!(
381            SelfAddressingIdentifier::new(HashFunctionCode::Blake2B512.into(), vec![0; 64])
382                .to_str(),
383            ["0F".to_string(), "A".repeat(86)].join("")
384        );
385        assert_eq!(
386            SelfAddressingIdentifier::new(HashFunctionCode::SHA2_512.into(), vec![0; 64]).to_str(),
387            ["0G".to_string(), "A".repeat(86)].join("")
388        );
389
390        // Test SelfSigningPrefix serialization.
391        assert_eq!(
392            SelfSigningPrefix::ECDSAsecp256k1Sha256(vec![0; 64]).to_str(),
393            ["0C".to_string(), "A".repeat(86)].join("")
394        );
395        assert_eq!(
396            SelfSigningPrefix::Ed25519Sha512(vec![0; 64]).to_str(),
397            ["0B".to_string(), "A".repeat(86)].join("")
398        );
399        assert_eq!(
400            SelfSigningPrefix::Ed448(vec![0; 114]).to_str(),
401            ["1AAE".to_string(), "A".repeat(152)].join("")
402        );
403
404        Ok(())
405    }
406
407    #[test]
408    pub fn test_identifier_encoding() {
409        use crate::keys::PublicKey;
410        use sodiumoxide::hex;
411        let pub_key = "694e894769e6c3267e8b477c2590284cd647dd42ef6007d254fce1cd2e9be423";
412        let key = hex::decode(pub_key).unwrap();
413        let bp = BasicPrefix::Ed25519NT(PublicKey::new(key));
414        let hash_function: HashFunction = HashFunctionCode::Blake3_256.into();
415        let expected_identifier = "BGlOiUdp5sMmfotHfCWQKEzWR91C72AH0lT84c0um-Qj";
416        assert_eq!(bp.to_str(), expected_identifier);
417
418        // Prefixes from keripy/tests/core/test_coring:test_diger
419        let to_digest = "abcdefghijklmnopqrstuvwxyz0123456789";
420        let dig = hash_function.derive(to_digest.as_bytes());
421        dig.verify_binding(to_digest.as_bytes());
422        assert_eq!(dig.to_str(), "ELC5L3iBVD77d_MYbYGGCUQgqQBju1o4x1Ud-z2sL-ux");
423
424        // Digest from: keripy/tests/core/test_coring:test_nexter
425        let to_digest = "BDjXHlcskwOzNj8rYbV8IQ6ox2TW_KkbA1K3-n0EU0un";
426        let dig = hash_function.derive(to_digest.as_bytes());
427        assert_eq!(dig.to_str(), "EP9XvFnpQP4vnaTNDNAMU2T7nxDPe1EZLUaiABcLRfS4");
428
429        // Prefixes from keripy/tests/core/test_coring:test_matter
430        let self_signing_b64 =
431        "mdI8OSQkMJ9r-xigjEByEjIua7LHH3AOJ22PQKqljMhuhcgh9nGRcKnsz5KvKd7K_H9-1298F4Id1DxvIoEmCQ==";
432        let self_signing_raw = base64::decode_config(self_signing_b64, base64::URL_SAFE).unwrap();
433
434        let ssp = SelfSigningPrefix::Ed25519Sha512(self_signing_raw);
435        assert_eq!(
436        ssp.to_str(),
437        "0BCZ0jw5JCQwn2v7GKCMQHISMi5rsscfcA4nbY9AqqWMyG6FyCH2cZFwqezPkq8p3sr8f37Xb3wXgh3UPG8igSYJ"
438    );
439    }
440}