Skip to main content

miden_crypto/
lib.rs

1#![no_std]
2
3#[macro_use]
4extern crate alloc;
5#[cfg(feature = "std")]
6extern crate std;
7
8pub mod aead;
9pub mod dsa;
10pub mod ecdh;
11pub mod hash;
12pub mod ies;
13pub mod merkle;
14pub mod rand;
15pub mod utils;
16
17// RE-EXPORTS
18// ================================================================================================
19pub use miden_field::{Felt, LexicographicWord, Word, WordError, word};
20
21pub mod field {
22    //! Traits and utilities for working with the Goldilocks finite field (i.e.,
23    //! [Felt](super::Felt)).
24
25    pub use miden_field::{
26        BasedVectorSpace, BinomialExtensionField, BinomiallyExtendable,
27        BinomiallyExtendableAlgebra, ExtensionField, Field, HasTwoAdicBinomialExtension,
28        InjectiveMonomial, Packable, PermutationMonomial, PrimeCharacteristicRing, PrimeField,
29        PrimeField64, QuotientMap, RawDataSerializable, TwoAdicField, batch_multiplicative_inverse,
30    };
31
32    pub use super::batch_inversion::batch_inversion_allow_zeros;
33}
34
35pub mod parallel {
36    //! Conditional parallel iteration primitives.
37    //!
38    //! When the `concurrent` feature is enabled, this module re-exports parallel iterator
39    //! traits from `p3-maybe-rayon` backed by rayon. Without `concurrent`, these traits
40    //! fall back to sequential iteration.
41    pub use p3_maybe_rayon::prelude::*;
42}
43
44pub mod stark {
45    //! Foundational components for the STARK proving system based on Plonky3.
46    //!
47    //! This module contains components needed to build a STARK prover/verifier and define
48    //! Algebraic Intermediate Representation (AIR) for the Miden VM and other components.
49    //! It primarily consists of re-exports from the Plonky3 project with some Miden-specific
50    //! adaptations.
51    pub use p3_miden_prover::{
52        Commitments, Domain, Entry, OpenedValues, PackedChallenge, PackedVal, PcsError, Proof,
53        ProverConstraintFolder, StarkConfig, StarkGenericConfig, SymbolicAirBuilder,
54        SymbolicExpression, SymbolicVariable, Val, VerificationError, VerifierConstraintFolder,
55        generate_logup_trace, get_log_quotient_degree, get_max_constraint_degree,
56        get_symbolic_constraints, prove, quotient_values, recompose_quotient_from_chunks, verify,
57        verify_constraints,
58    };
59
60    pub mod air {
61        pub use p3_air::{
62            Air, AirBuilder, AirBuilderWithPublicValues, BaseAir, BaseAirWithPublicValues,
63            ExtensionBuilder, FilteredAirBuilder, PairBuilder, PairCol, PermutationAirBuilder,
64            VirtualPairCol,
65        };
66        pub use p3_miden_air::{
67            BaseAirWithAuxTrace, FilteredMidenAirBuilder, MidenAir, MidenAirBuilder,
68        };
69    }
70
71    pub mod challenger {
72        pub use p3_challenger::{HashChallenger, SerializingChallenger64};
73    }
74
75    pub mod commit {
76        pub use p3_commit::ExtensionMmcs;
77        pub use p3_merkle_tree::MerkleTreeMmcs;
78    }
79
80    pub mod dft {
81        pub use p3_dft::Radix2DitParallel;
82    }
83
84    pub mod matrix {
85        pub use p3_matrix::{Matrix, dense::RowMajorMatrix};
86    }
87
88    pub mod pcs {
89        pub use p3_miden_fri::{FriParameters, TwoAdicFriPcs};
90    }
91
92    pub mod symmetric {
93        pub use p3_symmetric::{
94            CompressionFunctionFromHasher, PaddingFreeSponge, SerializingHasher,
95        };
96    }
97}
98
99// TYPE ALIASES
100// ================================================================================================
101
102/// An alias for a key-value map.
103///
104/// By default, this is an alias for the [`alloc::collections::BTreeMap`], however, when the
105/// `hashmaps` feature is enabled, this is an alias for the `hashbrown`'s `HashMap`.
106#[cfg(feature = "hashmaps")]
107pub type Map<K, V> = hashbrown::HashMap<K, V>;
108
109#[cfg(feature = "hashmaps")]
110pub use hashbrown::hash_map::Entry as MapEntry;
111
112/// An alias for a key-value map.
113///
114/// By default, this is an alias for the [`alloc::collections::BTreeMap`], however, when the
115/// `hashmaps` feature is enabled, this is an alias for the `hashbrown`'s `HashMap`.
116#[cfg(not(feature = "hashmaps"))]
117pub type Map<K, V> = alloc::collections::BTreeMap<K, V>;
118
119#[cfg(not(feature = "hashmaps"))]
120pub use alloc::collections::btree_map::Entry as MapEntry;
121
122/// An alias for a simple set.
123///
124/// By default, this is an alias for the [`alloc::collections::BTreeSet`]. However, when the
125/// `hashmaps` feature is enabled, this becomes an alias for hashbrown's HashSet.
126#[cfg(feature = "hashmaps")]
127pub type Set<V> = hashbrown::HashSet<V>;
128
129/// An alias for a simple set.
130///
131/// By default, this is an alias for the [`alloc::collections::BTreeSet`]. However, when the
132/// `hashmaps` feature is enabled, this becomes an alias for hashbrown's HashSet.
133#[cfg(not(feature = "hashmaps"))]
134pub type Set<V> = alloc::collections::BTreeSet<V>;
135
136// CONSTANTS
137// ================================================================================================
138
139/// Number of field elements in a word.
140pub const WORD_SIZE: usize = word::WORD_SIZE_FELTS;
141
142/// Field element representing ZERO in the Miden base filed.
143pub const ZERO: Felt = Felt::ZERO;
144
145/// Field element representing ONE in the Miden base filed.
146pub const ONE: Felt = Felt::ONE;
147
148/// Array of field elements representing word of ZEROs in the Miden base field.
149pub const EMPTY_WORD: Word = Word::new([ZERO; WORD_SIZE]);
150
151// TRAITS
152// ================================================================================================
153
154/// Defines how to compute a commitment to an object represented as a sequence of field elements.
155pub trait SequentialCommit {
156    /// A type of the commitment which must be derivable from [Word].
157    type Commitment: From<Word>;
158
159    /// Computes the commitment to the object.
160    ///
161    /// The default implementation of this function uses Poseidon2 hash function to hash the
162    /// sequence of elements returned from [Self::to_elements()].
163    fn to_commitment(&self) -> Self::Commitment {
164        hash::poseidon2::Poseidon2::hash_elements(&self.to_elements()).into()
165    }
166
167    /// Returns a representation of the object as a sequence of fields elements.
168    fn to_elements(&self) -> alloc::vec::Vec<Felt>;
169}
170
171// BATCH INVERSION
172// ================================================================================================
173
174mod batch_inversion {
175
176    use alloc::vec::Vec;
177
178    use p3_maybe_rayon::prelude::*;
179
180    use super::{Felt, ONE, ZERO, field::Field};
181
182    /// Parallel batch inversion using Montgomery's trick, with zeros left unchanged.
183    ///
184    /// Processes chunks in parallel using rayon, each chunk using Montgomery's trick.
185    pub fn batch_inversion_allow_zeros(values: &mut [Felt]) {
186        const CHUNK_SIZE: usize = 1024;
187
188        // We need to work with a copy since we're modifying in place
189        let input: Vec<Felt> = values.to_vec();
190
191        input.par_chunks(CHUNK_SIZE).zip(values.par_chunks_mut(CHUNK_SIZE)).for_each(
192            |(input_chunk, output_chunk)| {
193                batch_inversion_helper(input_chunk, output_chunk);
194            },
195        );
196    }
197
198    /// Montgomery's trick for batch inversion, handling zeros.
199    fn batch_inversion_helper(values: &[Felt], result: &mut [Felt]) {
200        debug_assert_eq!(values.len(), result.len());
201
202        if values.is_empty() {
203            return;
204        }
205
206        // Forward pass: compute cumulative products, skipping zeros
207        let mut last = ONE;
208        for (result, &value) in result.iter_mut().zip(values.iter()) {
209            *result = last;
210            if value != ZERO {
211                last *= value;
212            }
213        }
214
215        // Invert the final cumulative product
216        last = last.inverse();
217
218        // Backward pass: compute individual inverses
219        for i in (0..values.len()).rev() {
220            if values[i] == ZERO {
221                result[i] = ZERO;
222            } else {
223                result[i] *= last;
224                last *= values[i];
225            }
226        }
227    }
228
229    #[cfg(test)]
230    mod tests {
231        use super::*;
232
233        #[test]
234        fn test_batch_inversion_allow_zeros() {
235            let mut column = Vec::from([Felt::new(2), ZERO, Felt::new(4), Felt::new(5)]);
236            batch_inversion_allow_zeros(&mut column);
237
238            assert_eq!(column[0], Felt::new(2).inverse());
239            assert_eq!(column[1], ZERO);
240            assert_eq!(column[2], Felt::new(4).inverse());
241            assert_eq!(column[3], Felt::new(5).inverse());
242        }
243    }
244}
245
246// TESTS
247// ================================================================================================
248
249#[cfg(test)]
250mod tests {
251
252    #[test]
253    #[should_panic]
254    fn debug_assert_is_checked() {
255        // enforce the release checks to always have `RUSTFLAGS="-C debug-assertions"`.
256        //
257        // some upstream tests are performed with `debug_assert`, and we want to assert its
258        // correctness downstream.
259        //
260        // for reference, check
261        // https://github.com/0xMiden/miden-vm/issues/433
262        debug_assert!(false);
263    }
264
265    #[test]
266    #[should_panic]
267    #[allow(arithmetic_overflow)]
268    fn overflow_panics_for_test() {
269        // overflows might be disabled if tests are performed in release mode. these are critical,
270        // mandatory checks as overflows might be attack vectors.
271        //
272        // to enable overflow checks in release mode, ensure `RUSTFLAGS="-C overflow-checks"`
273        let a = 1_u64;
274        let b = 64;
275        assert_ne!(a << b, 0);
276    }
277}