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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use std::collections::hash_map;
use std::sync::Arc;

use anyhow::Result;
use everscale_crypto::ed25519;

use crate::utils::*;

/// Tagged keystore for ADNL keys
#[derive(Default)]
pub struct Keystore {
    keys: FxHashMap<AdnlNodeIdShort, Arc<StoredAdnlNodeKey>>,
    tags: FxHashMap<usize, AdnlNodeIdShort>,
}

impl Keystore {
    pub fn builder() -> KeystoreBuilder {
        KeystoreBuilder::default()
    }

    pub fn key_by_id(
        &self,
        id: &AdnlNodeIdShort,
    ) -> Result<&Arc<StoredAdnlNodeKey>, KeystoreError> {
        if let Some(key) = self.keys.get(id) {
            Ok(key)
        } else {
            Err(KeystoreError::KeyIdNotFound(*id))
        }
    }

    pub fn key_by_tag(&self, tag: usize) -> Result<&Arc<StoredAdnlNodeKey>, KeystoreError> {
        if let Some(id) = self.tags.get(&tag) {
            self.key_by_id(id)
        } else {
            Err(KeystoreError::KeyTagNotFound(tag))
        }
    }

    #[inline(always)]
    pub fn keys(&self) -> &FxHashMap<AdnlNodeIdShort, Arc<StoredAdnlNodeKey>> {
        &self.keys
    }

    pub fn add_key(&mut self, key: [u8; 32], tag: usize) -> Result<AdnlNodeIdShort, KeystoreError> {
        let secret_key = ed25519::SecretKey::from_bytes(key);
        let (full_id, short_id) = secret_key.compute_node_ids();

        match self.tags.entry(tag) {
            hash_map::Entry::Vacant(entry) => {
                entry.insert(short_id);
                match self.keys.entry(short_id) {
                    hash_map::Entry::Vacant(entry) => {
                        entry.insert(Arc::new(StoredAdnlNodeKey::from_id_and_private_key(
                            short_id,
                            full_id,
                            &secret_key,
                        )));
                        Ok(short_id)
                    }
                    hash_map::Entry::Occupied(_) => Err(KeystoreError::DuplicatedKey(tag)),
                }
            }
            hash_map::Entry::Occupied(entry) => {
                if entry.get() == &short_id {
                    Ok(short_id)
                } else {
                    Err(KeystoreError::DuplicatedKeyTag(tag))
                }
            }
        }
    }
}

#[derive(Default)]
pub struct KeystoreBuilder {
    keystore: Keystore,
}

impl KeystoreBuilder {
    pub fn build(self) -> Keystore {
        self.keystore
    }

    pub fn with_tagged_key(mut self, key: [u8; 32], tag: usize) -> Result<Self, KeystoreError> {
        self.keystore.add_key(key, tag)?;
        Ok(self)
    }

    /// Creates new keystore from tagged secret keys
    pub fn with_tagged_keys<I>(mut self, keys: I) -> Result<Self, KeystoreError>
    where
        I: IntoIterator<Item = ([u8; 32], usize)>,
    {
        for (key, tag) in keys {
            self.keystore.add_key(key, tag)?;
        }
        Ok(self)
    }
}

#[derive(thiserror::Error, Debug)]
pub enum KeystoreError {
    #[error("Duplicated key tag {0}")]
    DuplicatedKeyTag(usize),
    #[error("Duplicated secret key {0}")]
    DuplicatedKey(usize),
    #[error("Key is not found: {0}")]
    KeyIdNotFound(AdnlNodeIdShort),
    #[error("Key tag not found: {0}")]
    KeyTagNotFound(usize),
    #[error("Unexpected key")]
    UnexpectedKey,
}