diff --git a/CHANGELOG.md b/CHANGELOG.md index a3b6c21..94f419b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ - Standardised CI and Makefile across Miden repos (#323). - Added `Smt::compute_mutations()` and `Smt::apply_mutations()` for validation-checked insertions (#327). +## 0.10.1 (2024-09-13) + +* Added `Serializable` and `Deserializable` implementations for `PartialMmr` and `InOrderIndex` (#329). + + ## 0.10.0 (2024-08-06) - Added more `RpoDigest` and `RpxDigest` conversions (#311). diff --git a/Cargo.lock b/Cargo.lock index e10bdb2..5b80a8a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -518,7 +518,7 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miden-crypto" -version = "0.10.0" +version = "0.10.1" dependencies = [ "blake3", "cc", diff --git a/Cargo.toml b/Cargo.toml index 2616341..d1010f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "miden-crypto" -version = "0.10.0" +version = "0.10.1" description = "Miden Cryptographic primitives" authors = ["miden contributors"] readme = "README.md" license = "MIT" repository = "https://github.com/0xPolygonMiden/crypto" -documentation = "https://docs.rs/miden-crypto/0.10.0" +documentation = "https://docs.rs/miden-crypto/0.10.1" categories = ["cryptography", "no-std"] keywords = ["miden", "crypto", "hash", "merkle"] edition = "2021" diff --git a/src/dsa/rpo_falcon512/keys/secret_key.rs b/src/dsa/rpo_falcon512/keys/secret_key.rs index 920f96f..1cf1d90 100644 --- a/src/dsa/rpo_falcon512/keys/secret_key.rs +++ b/src/dsa/rpo_falcon512/keys/secret_key.rs @@ -28,13 +28,14 @@ const WIDTH_SMALL_POLY_COEFFICIENT: usize = 6; // SECRET KEY // ================================================================================================ -/// The secret key is a quadruple [[g, -f], [G, -F]] of polynomials with integer coefficients. Each -/// polynomial is of degree at most N = 512 and computations with these polynomials is done modulo -/// the monic irreducible polynomial ϕ = x^N + 1. The secret key is a basis for a lattice and has -/// the property of being short with respect to a certain norm and an upper bound appropriate for -/// a given security parameter. The public key on the other hand is another basis for the same -/// lattice and can be described by a single polynomial h with integer coefficients modulo ϕ. -/// The two keys are related by the following relation: +/// The secret key is a quadruple [[g, -f], [G, -F]] of polynomials with integer coefficients. +/// +/// Each polynomial is of degree at most N = 512 and computations with these polynomials are done +/// modulo the monic irreducible polynomial ϕ = x^N + 1. The secret key is a basis for a lattice +/// and has the property of being short with respect to a certain norm and an upper bound +/// appropriate for a given security parameter. The public key on the other hand is another basis +/// for the same lattice and can be described by a single polynomial h with integer coefficients +/// modulo ϕ. The two keys are related by the following relation: /// /// 1. h = g /f [mod ϕ][mod p] /// 2. f.G - g.F = p [mod ϕ] diff --git a/src/dsa/rpo_falcon512/signature.rs b/src/dsa/rpo_falcon512/signature.rs index 2b2441e..79b1900 100644 --- a/src/dsa/rpo_falcon512/signature.rs +++ b/src/dsa/rpo_falcon512/signature.rs @@ -44,7 +44,7 @@ use super::{ /// 2. 40 bytes for the nonce. /// 4. 625 bytes encoding the `s2` polynomial above. /// -/// The total size of the signature is (including the extended public key) is 1563 bytes. +/// The total size of the signature (including the extended public key) is 1563 bytes. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Signature { header: SignatureHeader, diff --git a/src/merkle/mmr/full.rs b/src/merkle/mmr/full.rs index 42aba15..f98d03e 100644 --- a/src/merkle/mmr/full.rs +++ b/src/merkle/mmr/full.rs @@ -7,7 +7,7 @@ //! //! Additionally the structure only supports adding leaves to the right-most tree, the one with the //! least number of leaves. The structure preserves the invariant that each tree has different -//! depths, i.e. as part of adding adding a new element to the forest the trees with same depth are +//! depths, i.e. as part of adding a new element to the forest the trees with same depth are //! merged, creating a new tree with depth d+1, this process is continued until the property is //! reestablished. use alloc::vec::Vec; diff --git a/src/merkle/mmr/inorder.rs b/src/merkle/mmr/inorder.rs index 655f364..37b4884 100644 --- a/src/merkle/mmr/inorder.rs +++ b/src/merkle/mmr/inorder.rs @@ -6,6 +6,8 @@ //! leaves count. use core::num::NonZeroUsize; +use winter_utils::{Deserializable, Serializable}; + // IN-ORDER INDEX // ================================================================================================ @@ -112,6 +114,21 @@ impl InOrderIndex { } } +impl Serializable for InOrderIndex { + fn write_into(&self, target: &mut W) { + target.write_usize(self.idx); + } +} + +impl Deserializable for InOrderIndex { + fn read_from( + source: &mut R, + ) -> Result { + let idx = source.read_usize()?; + Ok(InOrderIndex { idx }) + } +} + // CONVERSIONS FROM IN-ORDER INDEX // ------------------------------------------------------------------------------------------------ @@ -127,6 +144,7 @@ impl From for u64 { #[cfg(test)] mod test { use proptest::prelude::*; + use winter_utils::{Deserializable, Serializable}; use super::InOrderIndex; @@ -162,4 +180,12 @@ mod test { assert_eq!(left.sibling(), right); assert_eq!(left, right.sibling()); } + + #[test] + fn test_inorder_index_serialization() { + let index = InOrderIndex::from_leaf_pos(5); + let bytes = index.to_bytes(); + let index2 = InOrderIndex::read_from_bytes(&bytes).unwrap(); + assert_eq!(index, index2); + } } diff --git a/src/merkle/mmr/partial.rs b/src/merkle/mmr/partial.rs index 3c6f23c..329b3c6 100644 --- a/src/merkle/mmr/partial.rs +++ b/src/merkle/mmr/partial.rs @@ -3,6 +3,8 @@ use alloc::{ vec::Vec, }; +use winter_utils::{Deserializable, Serializable}; + use super::{MmrDelta, MmrProof, Rpo256, RpoDigest}; use crate::merkle::{ mmr::{leaf_to_corresponding_tree, nodes_in_forest}, @@ -184,7 +186,7 @@ impl PartialMmr { pub fn inner_nodes<'a, I: Iterator + 'a>( &'a self, mut leaves: I, - ) -> impl Iterator + '_ { + ) -> impl Iterator + 'a { let stack = if let Some((pos, leaf)) = leaves.next() { let idx = InOrderIndex::from_leaf_pos(pos); vec![(idx, leaf)] @@ -573,6 +575,28 @@ impl<'a, I: Iterator> Iterator for InnerNodeIterator< } } +impl Serializable for PartialMmr { + fn write_into(&self, target: &mut W) { + self.forest.write_into(target); + self.peaks.write_into(target); + self.nodes.write_into(target); + target.write_bool(self.track_latest); + } +} + +impl Deserializable for PartialMmr { + fn read_from( + source: &mut R, + ) -> Result { + let forest = usize::read_from(source)?; + let peaks = Vec::::read_from(source)?; + let nodes = NodeMap::read_from(source)?; + let track_latest = source.read_bool()?; + + Ok(Self { forest, peaks, nodes, track_latest }) + } +} + // UTILS // ================================================================================================ @@ -616,6 +640,8 @@ fn forest_to_rightmost_index(forest: usize) -> InOrderIndex { mod tests { use alloc::{collections::BTreeSet, vec::Vec}; + use winter_utils::{Deserializable, Serializable}; + use super::{ forest_to_rightmost_index, forest_to_root_index, InOrderIndex, MmrPeaks, PartialMmr, RpoDigest, @@ -907,4 +933,16 @@ mod tests { // the openings should be the same assert_eq!(mmr.open(5).unwrap(), partial_mmr.open(5).unwrap().unwrap()); } + + #[test] + fn test_partial_mmr_serialization() { + let mmr = Mmr::from((0..7).map(int_to_node)); + let forest_size = mmr.forest(); + let partial_mmr = PartialMmr::from_peaks(mmr.peaks(forest_size).unwrap()); + + let bytes = partial_mmr.to_bytes(); + let decoded = PartialMmr::read_from_bytes(&bytes).unwrap(); + + assert_eq!(partial_mmr, decoded); + } }