miden_tx/auth/
tx_authenticator.rs1use alloc::boxed::Box;
2use alloc::collections::BTreeMap;
3use alloc::string::ToString;
4use alloc::sync::Arc;
5use alloc::vec::Vec;
6
7use miden_objects::account::AuthSecretKey;
8use miden_objects::crypto::SequentialCommit;
9use miden_objects::transaction::TransactionSummary;
10use miden_objects::{Felt, Hasher, Word};
11use miden_processor::FutureMaybeSend;
12use rand::Rng;
13use tokio::sync::RwLock;
14
15use super::signatures::get_falcon_signature;
16use crate::errors::AuthenticationError;
17
18#[derive(Debug, Clone)]
31pub enum SigningInputs {
32 TransactionSummary(Box<TransactionSummary>),
33 Arbitrary(Vec<Felt>),
34 Blind(Word),
35}
36
37impl SequentialCommit for SigningInputs {
38 type Commitment = Word;
39
40 fn to_elements(&self) -> Vec<Felt> {
41 match self {
42 SigningInputs::TransactionSummary(tx_summary) => tx_summary.as_ref().to_elements(),
43 SigningInputs::Arbitrary(elements) => elements.clone(),
44 SigningInputs::Blind(word) => word.as_elements().to_vec(),
45 }
46 }
47
48 fn to_commitment(&self) -> Self::Commitment {
49 match self {
50 SigningInputs::TransactionSummary(tx_summary) => tx_summary.as_ref().to_commitment(),
52 SigningInputs::Arbitrary(elements) => Hasher::hash_elements(elements),
54 SigningInputs::Blind(word) => *word,
56 }
57 }
58}
59
60impl SigningInputs {
62 pub fn to_commitment(&self) -> Word {
64 <Self as SequentialCommit>::to_commitment(self)
65 }
66
67 pub fn to_elements(&self) -> Vec<Felt> {
69 <Self as SequentialCommit>::to_elements(self)
70 }
71}
72
73pub trait TransactionAuthenticator {
84 fn get_signature(
96 &self,
97 pub_key: Word,
98 signing_inputs: &SigningInputs,
99 ) -> impl FutureMaybeSend<Result<Vec<Felt>, AuthenticationError>>;
100}
101
102#[derive(Debug, Clone, Copy)]
107pub struct UnreachableAuth {
108 _protect: core::marker::PhantomData<u8>,
110}
111
112impl TransactionAuthenticator for UnreachableAuth {
113 #[allow(clippy::manual_async_fn)]
114 fn get_signature(
115 &self,
116 _pub_key: Word,
117 _signing_inputs: &SigningInputs,
118 ) -> impl FutureMaybeSend<Result<Vec<Felt>, AuthenticationError>> {
119 async { unreachable!("Type `UnreachableAuth` must not be instantiated") }
120 }
121}
122
123#[derive(Clone, Debug)]
128pub struct BasicAuthenticator<R> {
129 keys: BTreeMap<Word, AuthSecretKey>,
131 rng: Arc<RwLock<R>>,
132}
133
134impl<R: Rng> BasicAuthenticator<R> {
135 #[cfg(feature = "std")]
136 pub fn new(keys: &[(Word, AuthSecretKey)]) -> BasicAuthenticator<rand::rngs::StdRng> {
137 use rand::SeedableRng;
138 use rand::rngs::StdRng;
139
140 let rng = StdRng::from_os_rng();
141 BasicAuthenticator::<StdRng>::new_with_rng(keys, rng)
142 }
143
144 pub fn new_with_rng(keys: &[(Word, AuthSecretKey)], rng: R) -> Self {
145 let mut key_map = BTreeMap::new();
146 for (word, secret_key) in keys {
147 key_map.insert(*word, secret_key.clone());
148 }
149
150 BasicAuthenticator {
151 keys: key_map,
152 rng: Arc::new(RwLock::new(rng)),
153 }
154 }
155
156 pub fn keys(&self) -> &BTreeMap<Word, AuthSecretKey> {
159 &self.keys
160 }
161}
162
163impl<R: Rng + Send + Sync> TransactionAuthenticator for BasicAuthenticator<R> {
164 fn get_signature(
174 &self,
175 pub_key: Word,
176 signing_inputs: &SigningInputs,
177 ) -> impl FutureMaybeSend<Result<Vec<Felt>, AuthenticationError>> {
178 let message = signing_inputs.to_commitment();
179
180 async move {
181 let mut rng = self.rng.write().await;
182 match self.keys.get(&pub_key) {
183 Some(key) => match key {
184 AuthSecretKey::RpoFalcon512(falcon_key) => {
185 get_falcon_signature(falcon_key, message, &mut *rng)
186 },
187 },
188 None => Err(AuthenticationError::UnknownPublicKey(format!(
189 "public key {pub_key} is not contained in the authenticator's keys",
190 ))),
191 }
192 }
193 }
194}
195
196impl TransactionAuthenticator for () {
200 #[allow(clippy::manual_async_fn)]
201 fn get_signature(
202 &self,
203 _pub_key: Word,
204 _signing_inputs: &SigningInputs,
205 ) -> impl FutureMaybeSend<Result<Vec<Felt>, AuthenticationError>> {
206 async {
207 Err(AuthenticationError::RejectedSignature(
208 "default authenticator cannot provide signatures".to_string(),
209 ))
210 }
211 }
212}
213
214#[cfg(test)]
215mod test {
216 use miden_lib::utils::{Deserializable, Serializable};
217 use miden_objects::account::AuthSecretKey;
218 use miden_objects::crypto::dsa::rpo_falcon512::SecretKey;
219
220 #[test]
221 fn serialize_auth_key() {
222 let secret_key = SecretKey::new();
223 let auth_key = AuthSecretKey::RpoFalcon512(secret_key.clone());
224 let serialized = auth_key.to_bytes();
225 let deserialized = AuthSecretKey::read_from_bytes(&serialized).unwrap();
226
227 match deserialized {
228 AuthSecretKey::RpoFalcon512(key) => assert_eq!(secret_key.to_bytes(), key.to_bytes()),
229 }
230 }
231}