everscale_network/adnl/
keystore.rs

1use std::collections::hash_map;
2use std::sync::Arc;
3
4use anyhow::Result;
5use everscale_crypto::ed25519;
6
7use super::node_id::{ComputeNodeIds, NodeIdFull, NodeIdShort};
8use crate::util::FastHashMap;
9
10/// Tagged keystore for ADNL keys
11#[derive(Default)]
12pub struct Keystore {
13    keys: FastHashMap<NodeIdShort, Arc<Key>>,
14    tags: FastHashMap<usize, NodeIdShort>,
15}
16
17impl Keystore {
18    pub fn builder() -> KeystoreBuilder {
19        KeystoreBuilder::default()
20    }
21
22    /// Searches key by its short id
23    pub fn key_by_id(&self, id: &NodeIdShort) -> Result<&Arc<Key>, KeystoreError> {
24        if let Some(key) = self.keys.get(id) {
25            Ok(key)
26        } else {
27            Err(KeystoreError::KeyIdNotFound(*id))
28        }
29    }
30
31    /// Searches key by its tag
32    pub fn key_by_tag(&self, tag: usize) -> Result<&Arc<Key>, KeystoreError> {
33        if let Some(id) = self.tags.get(&tag) {
34            self.key_by_id(id)
35        } else {
36            Err(KeystoreError::KeyTagNotFound(tag))
37        }
38    }
39
40    /// Returns inner keys table
41    #[inline(always)]
42    pub fn keys(&self) -> &FastHashMap<NodeIdShort, Arc<Key>> {
43        &self.keys
44    }
45
46    /// Adds a new key with the specified tag
47    ///
48    /// NOTE: duplicate keys or tags will cause this method to fail
49    pub fn add_key(&mut self, key: [u8; 32], tag: usize) -> Result<NodeIdShort, KeystoreError> {
50        let secret_key = ed25519::SecretKey::from_bytes(key);
51        let (_, short_id) = secret_key.compute_node_ids();
52
53        match self.tags.entry(tag) {
54            hash_map::Entry::Vacant(entry) => {
55                entry.insert(short_id);
56                match self.keys.entry(short_id) {
57                    hash_map::Entry::Vacant(entry) => {
58                        entry.insert(Arc::new(secret_key.into()));
59                        Ok(short_id)
60                    }
61                    hash_map::Entry::Occupied(_) => Err(KeystoreError::DuplicatedKey(tag)),
62                }
63            }
64            hash_map::Entry::Occupied(entry) => {
65                if entry.get() == &short_id {
66                    Ok(short_id)
67                } else {
68                    Err(KeystoreError::DuplicatedKeyTag(tag))
69                }
70            }
71        }
72    }
73}
74
75#[derive(Default)]
76pub struct KeystoreBuilder {
77    keystore: Keystore,
78}
79
80impl KeystoreBuilder {
81    pub fn build(self) -> Keystore {
82        self.keystore
83    }
84
85    /// Adds a new key with the specified tag
86    ///
87    /// NOTE: duplicate keys or tags will cause this method to fail
88    pub fn with_tagged_key(mut self, key: [u8; 32], tag: usize) -> Result<Self, KeystoreError> {
89        self.keystore.add_key(key, tag)?;
90        Ok(self)
91    }
92
93    /// Creates a new keystore from tagged secret keys
94    pub fn with_tagged_keys<I>(mut self, keys: I) -> Result<Self, KeystoreError>
95    where
96        I: IntoIterator<Item = ([u8; 32], usize)>,
97    {
98        for (key, tag) in keys {
99            self.keystore.add_key(key, tag)?;
100        }
101        Ok(self)
102    }
103}
104
105/// ADNL key with precomputed node IDs
106pub struct Key {
107    short_id: NodeIdShort,
108    full_id: NodeIdFull,
109    secret_key: ed25519::ExpandedSecretKey,
110}
111
112impl Key {
113    /// Constructs new key from the secret key bytes
114    pub fn from_bytes(secret_key: [u8; 32]) -> Self {
115        ed25519::SecretKey::from_bytes(secret_key).into()
116    }
117
118    /// Returns short key id
119    #[inline(always)]
120    pub fn id(&self) -> &NodeIdShort {
121        &self.short_id
122    }
123
124    /// Returns full key id
125    #[inline(always)]
126    pub fn full_id(&self) -> &NodeIdFull {
127        &self.full_id
128    }
129
130    /// Returns inner secret key (as expanded)
131    #[inline(always)]
132    pub fn secret_key(&self) -> &ed25519::ExpandedSecretKey {
133        &self.secret_key
134    }
135
136    /// Signs serializable boxed data
137    #[inline(always)]
138    pub fn sign<T: tl_proto::TlWrite<Repr = tl_proto::Boxed>>(&self, data: T) -> [u8; 64] {
139        self.secret_key.sign(data, self.full_id.public_key())
140    }
141}
142
143impl From<ed25519::SecretKey> for Key {
144    fn from(secret_key: ed25519::SecretKey) -> Self {
145        let (full_id, short_id) = secret_key.compute_node_ids();
146        Self {
147            short_id,
148            full_id,
149            secret_key: ed25519::ExpandedSecretKey::from(&secret_key),
150        }
151    }
152}
153
154#[derive(thiserror::Error, Debug)]
155pub enum KeystoreError {
156    #[error("Duplicated key tag {0}")]
157    DuplicatedKeyTag(usize),
158    #[error("Duplicated secret key {0}")]
159    DuplicatedKey(usize),
160    #[error("Key is not found: {0}")]
161    KeyIdNotFound(NodeIdShort),
162    #[error("Key tag not found: {0}")]
163    KeyTagNotFound(usize),
164    #[error("Unexpected key")]
165    UnexpectedKey,
166}