Skip to content

Commit

Permalink
merkle: new crate extracted from zkvm (stellar#459)
Browse files Browse the repository at this point in the history
  • Loading branch information
oleganza authored Jun 3, 2020
1 parent b499950 commit 45534df
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 23 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

members = [
"readerwriter",
"merkle",
"starsig",
"musig",
"keytree",
Expand Down
2 changes: 2 additions & 0 deletions merkle/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
target
Cargo.lock
15 changes: 15 additions & 0 deletions merkle/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "merkle"
version = "0.1.0"
authors = ["Oleg Andreev <[email protected]>"]
edition = "2018"

[dependencies]
merlin = {version = "2.0"}
subtle = "2"
serde = { version = "1.0", features=["derive"] }
hex = "^0.3"

[dependencies.readerwriter]
path = "../readerwriter"
features = ["merlin"]
78 changes: 57 additions & 21 deletions zkvm/src/merkle.rs → merkle/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
#![deny(missing_docs)]

//! API for operations on merkle binary trees.
use crate::encoding::*;
use crate::errors::VMError;
use core::marker::PhantomData;
use merlin::Transcript;
use readerwriter::*;
use serde::{Deserialize, Serialize};
use std::fmt;
use subtle::ConstantTimeEq;

/// Merkle hash of a node.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct Hash(pub [u8; 32]);
serialize_bytes32!(Hash);

/// MerkleItem defines an item in the Merkle tree.
pub trait MerkleItem: Sized {
Expand Down Expand Up @@ -359,27 +359,10 @@ impl Path {
}
}

// zkvm-specific impl
impl Path {
/// Decodes Path from a byte reader. First 8 bytes is a LE64-encoded position,
/// followed by 4 bytes of LE32-encoded number of neighbours,
/// than the 32-byte neighbour hashes.
pub fn decode(reader: &mut impl Reader) -> Result<Self, VMError> {
let position = reader.read_u64()?;
let n = reader.read_u32()? as usize;
let neighbors = reader.read_vec(n, |r| r.read_u8x32().map(Hash))?;
Ok(Path {
position,
neighbors,
})
}
}

// zkvm-specific impl
impl Encodable for Path {
fn encode(&self, w: &mut impl Writer) -> Result<(), WriteError> {
w.write_u64(b"position", self.position)?;
w.write_size(b"n", self.neighbors.len())?;
w.write_u32(b"n", self.neighbors.len() as u32)?;
for hash in self.neighbors.iter() {
w.write(b"hash", &hash[..])?;
}
Expand All @@ -393,6 +376,18 @@ impl ExactSizeEncodable for Path {
}
}

impl Decodable for Path {
fn decode(reader: &mut impl Reader) -> Result<Self, ReadError> {
let position = reader.read_u64()?;
let n = reader.read_u32()? as usize;
let neighbors = reader.read_vec(n, |r| r.read_u8x32().map(Hash))?;
Ok(Path {
position,
neighbors,
})
}
}

/// Similar to `Path`, but does not contain neighbors - only left/right directions
/// as indicated by the bits in the `position`.
#[derive(Copy, Clone, PartialEq, Debug)]
Expand Down Expand Up @@ -444,6 +439,47 @@ impl DoubleEndedIterator for Directions {
}
}

impl Serialize for Hash {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_bytes(&self.0)
}
}

impl<'de> serde::Deserialize<'de> for Hash {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct BytesVisitor;

impl<'de> serde::de::Visitor<'de> for BytesVisitor {
type Value = Hash;

fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
formatter.write_str("a valid 32-byte string")
}

fn visit_bytes<E>(self, v: &[u8]) -> Result<Hash, E>
where
E: serde::de::Error,
{
if v.len() == 32 {
let mut buf = [0u8; 32];
buf[0..32].copy_from_slice(v);
Ok(Hash(buf))
} else {
Err(serde::de::Error::invalid_length(v.len(), &self))
}
}
}

deserializer.deserialize_bytes(BytesVisitor)
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
3 changes: 3 additions & 0 deletions zkvm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ hex = "^0.3"
path = "../readerwriter"
features = ["merlin"]

[dependencies.merkle]
path = "../merkle"

[dependencies.bulletproofs]
git = "https://github.com/dalek-cryptography/bulletproofs"
branch = "develop"
Expand Down
4 changes: 2 additions & 2 deletions zkvm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#[macro_use]
extern crate failure;
pub extern crate bulletproofs;
pub extern crate merkle;
extern crate serde;

#[macro_use]
Expand All @@ -19,7 +20,6 @@ mod debug;
pub mod encoding;
mod errors;
mod fees;
pub mod merkle;
mod ops;
mod predicate;
mod program;
Expand All @@ -35,7 +35,6 @@ pub use self::constraints::{Commitment, CommitmentWitness, Constraint, Expressio
pub use self::contract::{Anchor, Contract, ContractID, PortableItem};
pub use self::errors::VMError;
pub use self::fees::{fee_flavor, CheckedFee, FeeRate, MAX_FEE};
pub use self::merkle::{Hash, Hasher, MerkleItem, MerkleTree};
pub use self::ops::{Instruction, Opcode};
pub use self::predicate::{Predicate, PredicateTree};
pub use self::program::{Program, ProgramItem};
Expand All @@ -45,5 +44,6 @@ pub use self::transcript::TranscriptProtocol;
pub use self::tx::{Tx, TxEntry, TxHeader, TxID, TxLog, UnsignedTx, VerifiedTx};
pub use self::types::{ClearValue, Item, String, Value, WideValue};
pub use self::verifier::Verifier;
pub use merkle::{Hash, Hasher, MerkleItem, MerkleTree};

pub use musig::{Multikey, Multisignature, Signature, VerificationKey};

0 comments on commit 45534df

Please sign in to comment.