Browse Source

Merge pull request #50 from 0xPolygonMiden/next

Tracking PR for release v0.1.1
al-gkr-basic-workflow v0.1.1
grjte 2 years ago
committed by GitHub
parent
commit
398af59045
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 72 additions and 7 deletions
  1. +13
    -0
      CHANGELOG.md
  2. +1
    -1
      Cargo.toml
  3. +22
    -0
      src/hash/rpo/mod.rs
  4. +29
    -1
      src/hash/rpo/tests.rs
  5. +2
    -0
      src/lib.rs
  6. +1
    -1
      src/merkle/merkle_path_set.rs
  7. +1
    -1
      src/merkle/merkle_tree.rs
  8. +3
    -3
      src/merkle/simple_smt/mod.rs

+ 13
- 0
CHANGELOG.md

@ -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.

+ 1
- 1
Cargo.toml

@ -1,6 +1,6 @@
[package] [package]
name = "miden-crypto" name = "miden-crypto"
version = "0.1.0"
version = "0.1.1"
description="Miden Cryptographic primitives" description="Miden Cryptographic primitives"
authors = ["miden contributors"] authors = ["miden contributors"]
readme="README.md" readme="README.md"

+ 22
- 0
src/hash/rpo/mod.rs

@ -294,6 +294,28 @@ impl Rpo256 {
<Self as ElementHasher>::hash_elements(elements) <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 // RESCUE PERMUTATION
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------

+ 29
- 1
src/hash/rpo/tests.rs

@ -1,5 +1,6 @@
use super::{ 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 core::convert::TryInto;
use rand_utils::rand_value; use rand_utils::rand_value;
@ -51,6 +52,33 @@ fn hash_elements_vs_merge() {
assert_eq!(m_result, h_result); 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] #[test]
fn hash_elements_vs_merge_with_int() { fn hash_elements_vs_merge_with_int() {
let tmp = [Felt::new(rand_value()); 4]; let tmp = [Felt::new(rand_value()); 4];

+ 2
- 0
src/lib.rs

@ -10,6 +10,8 @@ pub mod merkle;
// RE-EXPORTS // RE-EXPORTS
// ================================================================================================ // ================================================================================================
pub use winter_crypto::{RandomCoin, RandomCoinError};
pub use winter_math::{fields::f64::BaseElement as Felt, FieldElement, StarkField}; pub use winter_math::{fields::f64::BaseElement as Felt, FieldElement, StarkField};
pub mod utils { pub mod utils {

+ 1
- 1
src/merkle/merkle_path_set.rs

@ -4,7 +4,7 @@ use super::{BTreeMap, MerkleError, Rpo256, Vec, Word, ZERO};
// ================================================================================================ // ================================================================================================
/// A set of Merkle paths. /// A set of Merkle paths.
#[derive(Clone, Debug)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MerklePathSet { pub struct MerklePathSet {
root: Word, root: Word,
total_depth: u32, total_depth: u32,

+ 1
- 1
src/merkle/merkle_tree.rs

@ -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). /// 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 { pub struct MerkleTree {
nodes: Vec<Word>, nodes: Vec<Word>,
} }

+ 3
- 3
src/merkle/simple_smt/mod.rs

@ -9,7 +9,7 @@ mod tests;
/// A sparse Merkle tree with 63-bit keys and 4-element leaf values, without compaction. /// 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`. /// 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. /// The root of the tree is recomputed on each new leaf update.
#[derive(Clone, Debug)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SimpleSmt { pub struct SimpleSmt {
root: Word, root: Word,
depth: u32, depth: u32,
@ -186,7 +186,7 @@ impl SimpleSmt {
/// Leaves and branch nodes are stored separately in B-tree maps, indexed by key and (key, depth) /// 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 /// 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. /// 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 { struct Store {
branches: BTreeMap<(u64, u32), BranchNode>, branches: BTreeMap<(u64, u32), BranchNode>,
leaves: BTreeMap<u64, Word>, leaves: BTreeMap<u64, Word>,
@ -194,7 +194,7 @@ struct Store {
depth: u32, depth: u32,
} }
#[derive(Clone, Debug, Default)]
#[derive(Debug, Default, Clone, PartialEq, Eq)]
struct BranchNode { struct BranchNode {
left: RpoDigest, left: RpoDigest,
right: RpoDigest, right: RpoDigest,

Loading…
Cancel
Save