1#![no_std]
2
3pub mod handlers;
4
5extern crate alloc;
6
7use alloc::{sync::Arc, vec, vec::Vec};
8
9use miden_assembly::{Library, mast::MastForest, utils::Deserializable};
10use miden_core::{EventName, Felt, Word, precompile::PrecompileVerifierRegistry};
11use miden_processor::{EventHandler, HostLibrary};
12use miden_utils_sync::LazyLock;
13
14use crate::handlers::{
15 ecdsa::{ECDSA_VERIFY_EVENT_NAME, EcdsaPrecompile},
16 falcon_div::{FALCON_DIV_EVENT_NAME, handle_falcon_div},
17 keccak256::{KECCAK_HASH_MEMORY_EVENT_NAME, KeccakPrecompile},
18 smt_peek::{SMT_PEEK_EVENT_NAME, handle_smt_peek},
19 sorted_array::{
20 LOWERBOUND_ARRAY_EVENT_NAME, LOWERBOUND_KEY_VALUE_EVENT_NAME, handle_lowerbound_array,
21 handle_lowerbound_key_value,
22 },
23 u64_div::{U64_DIV_EVENT_NAME, handle_u64_div},
24};
25
26#[derive(Clone)]
31pub struct StdLibrary(Library);
32
33impl AsRef<Library> for StdLibrary {
34 fn as_ref(&self) -> &Library {
35 &self.0
36 }
37}
38
39impl From<StdLibrary> for Library {
40 fn from(value: StdLibrary) -> Self {
41 value.0
42 }
43}
44
45impl From<&StdLibrary> for HostLibrary {
46 fn from(stdlib: &StdLibrary) -> Self {
47 Self {
48 mast_forest: stdlib.mast_forest().clone(),
49 handlers: stdlib.handlers(),
50 }
51 }
52}
53
54impl StdLibrary {
55 pub const SERIALIZED: &'static [u8] =
57 include_bytes!(concat!(env!("OUT_DIR"), "/assets/std.masl"));
58
59 pub fn mast_forest(&self) -> &Arc<MastForest> {
61 self.0.mast_forest()
62 }
63
64 pub fn library(&self) -> &Library {
66 &self.0
67 }
68
69 pub fn handlers(&self) -> Vec<(EventName, Arc<dyn EventHandler>)> {
71 vec![
72 (KECCAK_HASH_MEMORY_EVENT_NAME, Arc::new(KeccakPrecompile)),
73 (ECDSA_VERIFY_EVENT_NAME, Arc::new(EcdsaPrecompile)),
74 (SMT_PEEK_EVENT_NAME, Arc::new(handle_smt_peek)),
75 (U64_DIV_EVENT_NAME, Arc::new(handle_u64_div)),
76 (FALCON_DIV_EVENT_NAME, Arc::new(handle_falcon_div)),
77 (LOWERBOUND_ARRAY_EVENT_NAME, Arc::new(handle_lowerbound_array)),
78 (LOWERBOUND_KEY_VALUE_EVENT_NAME, Arc::new(handle_lowerbound_key_value)),
79 ]
80 }
81
82 pub fn verifier_registry(&self) -> PrecompileVerifierRegistry {
85 PrecompileVerifierRegistry::new()
86 .with_verifier(&KECCAK_HASH_MEMORY_EVENT_NAME, Arc::new(KeccakPrecompile))
87 .with_verifier(&ECDSA_VERIFY_EVENT_NAME, Arc::new(EcdsaPrecompile))
88 }
89}
90
91impl Default for StdLibrary {
92 fn default() -> Self {
93 static STDLIB: LazyLock<StdLibrary> = LazyLock::new(|| {
94 let contents =
95 Library::read_from_bytes(StdLibrary::SERIALIZED).expect("failed to read std masl!");
96 StdLibrary(contents)
97 });
98 STDLIB.clone()
99 }
100}
101
102#[cfg(feature = "std")]
120pub fn falcon_sign(sk: &[Felt], msg: Word) -> Option<Vec<Felt>> {
121 use alloc::vec;
122
123 use miden_core::{
124 Felt,
125 crypto::{
126 dsa::rpo_falcon512::{Polynomial, SecretKey},
127 hash::Rpo256,
128 },
129 utils::Deserializable,
130 };
131
132 let mut sk_bytes = Vec::with_capacity(sk.len());
134 for element in sk {
135 let value = element.as_int();
136 if value > u8::MAX as u64 {
137 return None;
138 }
139 sk_bytes.push(value as u8);
140 }
141
142 let sk = SecretKey::read_from_bytes(&sk_bytes).ok()?;
143
144 let sig = sk.sign(msg);
146
147 let nonce = sig.nonce();
151
152 let s2 = sig.sig_poly();
154
155 let h = sk.public_key();
158
159 let pi = Polynomial::mul_modulo_p(&h, s2);
163
164 let mut polynomials: Vec<Felt> =
170 h.coefficients.iter().map(|a| Felt::from(a.value() as u32)).collect();
171 polynomials.extend(s2.coefficients.iter().map(|a| Felt::from(a.value() as u32)));
172 polynomials.extend(pi.iter().map(|a| Felt::new(*a)));
173
174 let digest_polynomials = Rpo256::hash_elements(&polynomials);
175 let challenge = (digest_polynomials[0], digest_polynomials[1]);
176
177 let mut result: Vec<Felt> = vec![challenge.0, challenge.1];
178 result.extend_from_slice(&polynomials);
179 result.extend_from_slice(&nonce.to_elements());
180
181 result.reverse();
182 Some(result)
183}
184
185#[cfg(not(feature = "std"))]
186pub fn falcon_sign(_pk_sk: &[Felt], _msg: Word) -> Option<Vec<Felt>> {
187 None
188}
189
190#[cfg(test)]
194mod tests {
195 use miden_assembly::LibraryPath;
196
197 use super::*;
198
199 #[test]
200 fn test_compile() {
201 let path = "std::math::u64::overflowing_add".parse::<LibraryPath>().unwrap();
202 let stdlib = StdLibrary::default();
203 let exists = stdlib.0.module_infos().any(|module| {
204 module
205 .procedures()
206 .any(|(_, proc)| module.path().clone().append(&proc.name).unwrap() == path)
207 });
208
209 assert!(exists);
210 }
211}