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::{EventId, Felt, Word};
11use miden_processor::{EventHandler, HostLibrary};
12use miden_utils_sync::LazyLock;
13
14use crate::handlers::{
15 falcon_div::{FALCON_DIV_EVENT_ID, handle_falcon_div},
16 keccak256::{KECCAK_HASH_MEMORY_EVENT_ID, handle_keccak_hash_memory},
17 smt_peek::{SMT_PEEK_EVENT_ID, handle_smt_peek},
18 sorted_array::{
19 LOWERBOUND_ARRAY_EVENT_ID, LOWERBOUND_KEY_VALUE_EVENT_ID, handle_lowerbound_array,
20 handle_lowerbound_key_value,
21 },
22 u64_div::{U64_DIV_EVENT_ID, handle_u64_div},
23};
24
25#[derive(Clone)]
30pub struct StdLibrary(Library);
31
32impl AsRef<Library> for StdLibrary {
33 fn as_ref(&self) -> &Library {
34 &self.0
35 }
36}
37
38impl From<StdLibrary> for Library {
39 fn from(value: StdLibrary) -> Self {
40 value.0
41 }
42}
43
44impl From<&StdLibrary> for HostLibrary {
45 fn from(stdlib: &StdLibrary) -> Self {
46 Self {
47 mast_forest: stdlib.mast_forest().clone(),
48 handlers: stdlib.handlers(),
49 }
50 }
51}
52
53impl StdLibrary {
54 pub const SERIALIZED: &'static [u8] =
56 include_bytes!(concat!(env!("OUT_DIR"), "/assets/std.masl"));
57
58 pub fn mast_forest(&self) -> &Arc<MastForest> {
60 self.0.mast_forest()
61 }
62
63 pub fn library(&self) -> &Library {
65 &self.0
66 }
67
68 pub fn handlers(&self) -> Vec<(EventId, Arc<dyn EventHandler>)> {
70 vec![
71 (KECCAK_HASH_MEMORY_EVENT_ID, Arc::new(handle_keccak_hash_memory)),
72 (SMT_PEEK_EVENT_ID, Arc::new(handle_smt_peek)),
73 (U64_DIV_EVENT_ID, Arc::new(handle_u64_div)),
74 (FALCON_DIV_EVENT_ID, Arc::new(handle_falcon_div)),
75 (LOWERBOUND_ARRAY_EVENT_ID, Arc::new(handle_lowerbound_array)),
76 (LOWERBOUND_KEY_VALUE_EVENT_ID, Arc::new(handle_lowerbound_key_value)),
77 ]
78 }
79}
80
81impl Default for StdLibrary {
82 fn default() -> Self {
83 static STDLIB: LazyLock<StdLibrary> = LazyLock::new(|| {
84 let contents =
85 Library::read_from_bytes(StdLibrary::SERIALIZED).expect("failed to read std masl!");
86 StdLibrary(contents)
87 });
88 STDLIB.clone()
89 }
90}
91
92#[cfg(feature = "std")]
110pub fn falcon_sign(sk: &[Felt], msg: Word) -> Option<Vec<Felt>> {
111 use alloc::vec;
112
113 use miden_core::{
114 Felt,
115 crypto::{
116 dsa::rpo_falcon512::{Polynomial, SecretKey},
117 hash::Rpo256,
118 },
119 utils::Deserializable,
120 };
121
122 let mut sk_bytes = Vec::with_capacity(sk.len());
124 for element in sk {
125 let value = element.as_int();
126 if value > u8::MAX as u64 {
127 return None;
128 }
129 sk_bytes.push(value as u8);
130 }
131
132 let sk = SecretKey::read_from_bytes(&sk_bytes).ok()?;
133
134 let sig = sk.sign(msg);
136
137 let nonce = sig.nonce();
141
142 let s2 = sig.sig_poly();
144
145 let h = sk.public_key();
148
149 let pi = Polynomial::mul_modulo_p(&h, s2);
153
154 let mut polynomials: Vec<Felt> =
160 h.coefficients.iter().map(|a| Felt::from(a.value() as u32)).collect();
161 polynomials.extend(s2.coefficients.iter().map(|a| Felt::from(a.value() as u32)));
162 polynomials.extend(pi.iter().map(|a| Felt::new(*a)));
163
164 let digest_polynomials = Rpo256::hash_elements(&polynomials);
165 let challenge = (digest_polynomials[0], digest_polynomials[1]);
166
167 let mut result: Vec<Felt> = vec![challenge.0, challenge.1];
168 result.extend_from_slice(&polynomials);
169 result.extend_from_slice(&nonce.to_elements());
170
171 result.reverse();
172 Some(result)
173}
174
175#[cfg(not(feature = "std"))]
176pub fn falcon_sign(_pk_sk: &[Felt], _msg: Word) -> Option<Vec<Felt>> {
177 None
178}
179
180#[cfg(test)]
184mod tests {
185 use miden_assembly::LibraryPath;
186
187 use super::*;
188
189 #[test]
190 fn test_compile() {
191 let path = "std::math::u64::overflowing_add".parse::<LibraryPath>().unwrap();
192 let stdlib = StdLibrary::default();
193 let exists = stdlib.0.module_infos().any(|module| {
194 module
195 .procedures()
196 .any(|(_, proc)| module.path().clone().append(&proc.name).unwrap() == path)
197 });
198
199 assert!(exists);
200 }
201}