1#![no_std]
2
3extern crate alloc;
4
5use alloc::{sync::Arc, vec, vec::Vec};
6
7use miden_assembly::{Library, mast::MastForest, utils::Deserializable};
8use miden_core::{Felt, Word};
9use miden_processor::HostLibrary;
10use miden_utils_sync::LazyLock;
11
12#[derive(Clone)]
17pub struct StdLibrary(Library);
18
19impl AsRef<Library> for StdLibrary {
20 fn as_ref(&self) -> &Library {
21 &self.0
22 }
23}
24
25impl From<StdLibrary> for Library {
26 fn from(value: StdLibrary) -> Self {
27 value.0
28 }
29}
30
31impl From<&StdLibrary> for HostLibrary {
32 fn from(stdlib: &StdLibrary) -> Self {
33 Self {
34 mast_forest: stdlib.mast_forest().clone(),
35 handlers: vec![],
36 }
37 }
38}
39
40impl StdLibrary {
41 pub const SERIALIZED: &'static [u8] =
43 include_bytes!(concat!(env!("OUT_DIR"), "/assets/std.masl"));
44
45 pub fn mast_forest(&self) -> &Arc<MastForest> {
47 self.0.mast_forest()
48 }
49}
50
51impl Default for StdLibrary {
52 fn default() -> Self {
53 static STDLIB: LazyLock<StdLibrary> = LazyLock::new(|| {
54 let contents =
55 Library::read_from_bytes(StdLibrary::SERIALIZED).expect("failed to read std masl!");
56 StdLibrary(contents)
57 });
58 STDLIB.clone()
59 }
60}
61
62#[cfg(feature = "std")]
80pub fn falcon_sign(sk: &[Felt], msg: Word) -> Option<Vec<Felt>> {
81 use alloc::vec;
82
83 use miden_core::{
84 Felt,
85 crypto::{
86 dsa::rpo_falcon512::{Polynomial, SecretKey},
87 hash::Rpo256,
88 },
89 utils::Deserializable,
90 };
91
92 let mut sk_bytes = Vec::with_capacity(sk.len());
94 for element in sk {
95 let value = element.as_int();
96 if value > u8::MAX as u64 {
97 return None;
98 }
99 sk_bytes.push(value as u8);
100 }
101
102 let sk = SecretKey::read_from_bytes(&sk_bytes).ok()?;
103
104 let sig = sk.sign(msg);
106
107 let nonce = sig.nonce();
111
112 let s2 = sig.sig_poly();
114
115 let h = sk.compute_pub_key_poly().0;
118
119 let pi = Polynomial::mul_modulo_p(&h, s2);
123
124 let mut polynomials: Vec<Felt> =
130 h.coefficients.iter().map(|a| Felt::from(a.value() as u32)).collect();
131 polynomials.extend(s2.coefficients.iter().map(|a| Felt::from(a.value() as u32)));
132 polynomials.extend(pi.iter().map(|a| Felt::new(*a)));
133
134 let digest_polynomials = Rpo256::hash_elements(&polynomials);
135 let challenge = (digest_polynomials[0], digest_polynomials[1]);
136
137 let mut result: Vec<Felt> = vec![challenge.0, challenge.1];
138 result.extend_from_slice(&polynomials);
139 result.extend_from_slice(&nonce.to_elements());
140
141 result.reverse();
142 Some(result)
143}
144
145#[cfg(not(feature = "std"))]
146pub fn falcon_sign(_pk_sk: &[Felt], _msg: Word) -> Option<Vec<Felt>> {
147 None
148}
149
150#[cfg(test)]
154mod tests {
155 use miden_assembly::LibraryPath;
156
157 use super::*;
158
159 #[test]
160 fn test_compile() {
161 let path = "std::math::u64::overflowing_add".parse::<LibraryPath>().unwrap();
162 let stdlib = StdLibrary::default();
163 let exists = stdlib.0.module_infos().any(|module| {
164 module
165 .procedures()
166 .any(|(_, proc)| module.path().clone().append(&proc.name).unwrap() == path)
167 });
168
169 assert!(exists);
170 }
171}