miden_tx/auth/
tx_authenticator.rs

1use alloc::{collections::BTreeMap, string::ToString, sync::Arc, vec::Vec};
2
3use miden_lib::utils::sync::RwLock;
4use miden_objects::account::{AccountDelta, AuthSecretKey};
5use rand::Rng;
6use vm_processor::{Digest, Felt, Word};
7
8use super::signatures::get_falcon_signature;
9use crate::errors::AuthenticationError;
10
11// TRANSACTION AUTHENTICATOR
12// ================================================================================================
13
14/// Defines an authenticator for transactions.
15///
16/// The main purpose of the authenticator is to generate signatures for a given message against
17/// a key managed by the authenticator. That is, the authenticator maintains a set of public-
18/// private key pairs, and can be requested to generate signatures against any of the managed keys.
19///
20/// The public keys are defined by [Digest]'s which are the hashes of the actual public keys.
21pub trait TransactionAuthenticator {
22    /// Retrieves a signature for a specific message as a list of [Felt].
23    ///
24    /// The request is initiated by the VM as a consequence of the SigToStack advice
25    /// injector.
26    ///
27    /// - `pub_key`: The public key used for signature generation.
28    /// - `message`: The message to sign, usually a commitment to the transaction data.
29    /// - `account_delta`: An informational parameter describing the changes made to the account up
30    ///   to the point of calling `get_signature()`. This allows the authenticator to review any
31    ///   alterations to the account prior to signing. It should not be directly used in the
32    ///   signature computation.
33    fn get_signature(
34        &self,
35        pub_key: Word,
36        message: Word,
37        account_delta: &AccountDelta,
38    ) -> Result<Vec<Felt>, AuthenticationError>;
39}
40
41// BASIC AUTHENTICATOR
42// ================================================================================================
43
44#[derive(Clone, Debug)]
45/// Represents a signer for [AuthSecretKey] keys.
46pub struct BasicAuthenticator<R> {
47    /// pub_key |-> secret_key mapping
48    keys: BTreeMap<Digest, AuthSecretKey>,
49    rng: Arc<RwLock<R>>,
50}
51
52impl<R: Rng> BasicAuthenticator<R> {
53    #[cfg(feature = "std")]
54    pub fn new(keys: &[(Word, AuthSecretKey)]) -> BasicAuthenticator<rand::rngs::StdRng> {
55        use rand::{SeedableRng, rngs::StdRng};
56
57        let rng = StdRng::from_os_rng();
58        BasicAuthenticator::<StdRng>::new_with_rng(keys, rng)
59    }
60
61    pub fn new_with_rng(keys: &[(Word, AuthSecretKey)], rng: R) -> Self {
62        let mut key_map = BTreeMap::new();
63        for (word, secret_key) in keys {
64            key_map.insert(word.into(), secret_key.clone());
65        }
66
67        BasicAuthenticator {
68            keys: key_map,
69            rng: Arc::new(RwLock::new(rng)),
70        }
71    }
72}
73
74impl<R: Rng> TransactionAuthenticator for BasicAuthenticator<R> {
75    /// Gets a signature over a message, given a public key.
76    /// The key should be included in the `keys` map and should be a variant of [AuthSecretKey].
77    ///
78    /// Supported signature schemes:
79    /// - RpoFalcon512
80    ///
81    /// # Errors
82    /// If the public key is not contained in the `keys` map,
83    /// [`AuthenticationError::UnknownPublicKey`] is returned.
84    fn get_signature(
85        &self,
86        pub_key: Word,
87        message: Word,
88        account_delta: &AccountDelta,
89    ) -> Result<Vec<Felt>, AuthenticationError> {
90        let _ = account_delta;
91        let mut rng = self.rng.write();
92
93        match self.keys.get(&pub_key.into()) {
94            Some(key) => match key {
95                AuthSecretKey::RpoFalcon512(falcon_key) => {
96                    get_falcon_signature(falcon_key, message, &mut *rng)
97                },
98            },
99            None => Err(AuthenticationError::UnknownPublicKey(format!(
100                "public key {} is not contained in the authenticator's keys",
101                Digest::from(pub_key)
102            ))),
103        }
104    }
105}
106
107// HELPER FUNCTIONS
108// ================================================================================================
109
110impl TransactionAuthenticator for () {
111    fn get_signature(
112        &self,
113        _pub_key: Word,
114        _message: Word,
115        _account_delta: &AccountDelta,
116    ) -> Result<Vec<Felt>, AuthenticationError> {
117        Err(AuthenticationError::RejectedSignature(
118            "default authenticator cannot provide signatures".to_string(),
119        ))
120    }
121}
122
123#[cfg(test)]
124mod test {
125    use miden_lib::utils::{Deserializable, Serializable};
126    use miden_objects::{account::AuthSecretKey, crypto::dsa::rpo_falcon512::SecretKey};
127
128    #[test]
129    fn serialize_auth_key() {
130        let secret_key = SecretKey::new();
131        let auth_key = AuthSecretKey::RpoFalcon512(secret_key.clone());
132        let serialized = auth_key.to_bytes();
133        let deserialized = AuthSecretKey::read_from_bytes(&serialized).unwrap();
134
135        match deserialized {
136            AuthSecretKey::RpoFalcon512(key) => assert_eq!(secret_key.to_bytes(), key.to_bytes()),
137        }
138    }
139}