Skip to content

Commit

Permalink
Merge pull request #50 from 0xPolygonMiden/next
Browse files Browse the repository at this point in the history
Tracking PR for release v0.1.1
  • Loading branch information
grjte authored Feb 6, 2023
2 parents 3c60484 + cf7011a commit 398af59
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 7 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## 0.1.1 (2023-02-06)

- Introduced `merge_in_domain` for the RPO hash function, to allow using a specified domain value in the second capacity register when hashing two digests together.
- Added a simple sparse Merkle tree implementation.
- Added re-exports of Winterfell RandomCoin and RandomCoinError.

## 0.1.0 (2022-12-02)

- Initial release on crates.io containing the cryptographic primitives used in Miden VM and the Miden Rollup.
- Hash module with the BLAKE3 and Rescue Prime Optimized hash functions.
- BLAKE3 is implemented with 256-bit, 192-bit, or 160-bit output.
- RPO is implemented with 256-bit output.
- Merkle module, with a set of data structures related to Merkle trees, implemented using the RPO hash function.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "miden-crypto"
version = "0.1.0"
version = "0.1.1"
description="Miden Cryptographic primitives"
authors = ["miden contributors"]
readme="README.md"
Expand Down
22 changes: 22 additions & 0 deletions src/hash/rpo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,28 @@ impl Rpo256 {
<Self as ElementHasher>::hash_elements(elements)
}

// DOMAIN IDENTIFIER
// --------------------------------------------------------------------------------------------

/// Returns a hash of two digests and a domain identifier.
pub fn merge_in_domain(values: &[RpoDigest; 2], domain: Felt) -> RpoDigest {
// initialize the state by copying the digest elements into the rate portion of the state
// (8 total elements), and set the capacity elements to 0.
let mut state = [ZERO; STATE_WIDTH];
let it = RpoDigest::digests_as_elements(values.iter());
for (i, v) in it.enumerate() {
state[RATE_RANGE.start + i] = *v;
}

// set the second capacity element to the domain value. The first capacity element is used
// for padding purposes.
state[CAPACITY_RANGE.start + 1] = domain;

// apply the RPO permutation and return the first four elements of the state
Self::apply_permutation(&mut state);
RpoDigest::new(state[DIGEST_RANGE].try_into().unwrap())
}

// RESCUE PERMUTATION
// --------------------------------------------------------------------------------------------

Expand Down
30 changes: 29 additions & 1 deletion src/hash/rpo/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::{
Felt, FieldElement, Hasher, Rpo256, RpoDigest, StarkField, ALPHA, INV_ALPHA, STATE_WIDTH, ZERO,
Felt, FieldElement, Hasher, Rpo256, RpoDigest, StarkField, ALPHA, INV_ALPHA, ONE, STATE_WIDTH,
ZERO,
};
use core::convert::TryInto;
use rand_utils::rand_value;
Expand Down Expand Up @@ -51,6 +52,33 @@ fn hash_elements_vs_merge() {
assert_eq!(m_result, h_result);
}

#[test]
fn merge_vs_merge_in_domain() {
let elements = [Felt::new(rand_value()); 8];

let digests: [RpoDigest; 2] = [
RpoDigest::new(elements[..4].try_into().unwrap()),
RpoDigest::new(elements[4..].try_into().unwrap()),
];
let merge_result = Rpo256::merge(&digests);

// ------------- merge with domain = 0 ----------------------------------------------------------

// set domain to ZERO. This should not change the result.
let domain = ZERO;

let merge_in_domain_result = Rpo256::merge_in_domain(&digests, domain);
assert_eq!(merge_result, merge_in_domain_result);

// ------------- merge with domain = 1 ----------------------------------------------------------

// set domain to ONE. This should change the result.
let domain = ONE;

let merge_in_domain_result = Rpo256::merge_in_domain(&digests, domain);
assert_ne!(merge_result, merge_in_domain_result);
}

#[test]
fn hash_elements_vs_merge_with_int() {
let tmp = [Felt::new(rand_value()); 4];
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ pub mod merkle;
// RE-EXPORTS
// ================================================================================================

pub use winter_crypto::{RandomCoin, RandomCoinError};

pub use winter_math::{fields::f64::BaseElement as Felt, FieldElement, StarkField};

pub mod utils {
Expand Down
2 changes: 1 addition & 1 deletion src/merkle/merkle_path_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use super::{BTreeMap, MerkleError, Rpo256, Vec, Word, ZERO};
// ================================================================================================

/// A set of Merkle paths.
#[derive(Clone, Debug)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MerklePathSet {
root: Word,
total_depth: u32,
Expand Down
2 changes: 1 addition & 1 deletion src/merkle/merkle_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use winter_math::log2;
// ================================================================================================

/// A fully-balanced binary Merkle tree (i.e., a tree where the number of leaves is a power of two).
#[derive(Clone, Debug)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MerkleTree {
nodes: Vec<Word>,
}
Expand Down
6 changes: 3 additions & 3 deletions src/merkle/simple_smt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ mod tests;
/// A sparse Merkle tree with 63-bit keys and 4-element leaf values, without compaction.
/// Manipulation and retrieval of leaves and internal nodes is provided by its internal `Store`.
/// The root of the tree is recomputed on each new leaf update.
#[derive(Clone, Debug)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SimpleSmt {
root: Word,
depth: u32,
Expand Down Expand Up @@ -186,15 +186,15 @@ impl SimpleSmt {
/// Leaves and branch nodes are stored separately in B-tree maps, indexed by key and (key, depth)
/// respectively. Hashes for blank subtrees at each layer are stored in `empty_hashes`, beginning
/// with the root hash of an empty tree, and ending with the zero value of a leaf node.
#[derive(Clone, Debug)]
#[derive(Debug, Clone, PartialEq, Eq)]
struct Store {
branches: BTreeMap<(u64, u32), BranchNode>,
leaves: BTreeMap<u64, Word>,
empty_hashes: Vec<RpoDigest>,
depth: u32,
}

#[derive(Clone, Debug, Default)]
#[derive(Debug, Default, Clone, PartialEq, Eq)]
struct BranchNode {
left: RpoDigest,
right: RpoDigest,
Expand Down

0 comments on commit 398af59

Please sign in to comment.