Skip to content

Commit

Permalink
finally finished serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
Samuel Schlesinger authored and Samuel Schlesinger committed Apr 21, 2023
1 parent 9c0f0c8 commit 5fbb0a5
Show file tree
Hide file tree
Showing 3 changed files with 183 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "blake3-lamport-signatures"
version = "0.3.4"
version = "0.3.5"
edition = "2021"
description = "Lamport Signatures using the Blake 3 Cryptographic Hash Function"
license = "MIT"
Expand Down
62 changes: 62 additions & 0 deletions src/merkle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ pub mod internal;
use crate::lamport;
use crate::merkle::internal::*;

pub use crate::merkle::internal::ProofDecodingError;

/// A public key is the Merkle root of the tree in your [`PrivateKey`].
pub struct PublicKey(Commitment);

Expand Down Expand Up @@ -67,8 +69,64 @@ impl From<(Vec<lamport::PrivateKey>, usize)> for PrivateKey {

/// A signature consists of a lamport signature and a merkle proof of the
/// public key used.
#[derive(Debug, Eq, PartialEq)]
pub struct Signature(lamport::Signature, lamport::PublicKey, Proof);

#[derive(Debug)]
pub enum SignatureDecodingError {
NotEnoughInput(usize),
MerkleProofDecodingError(ProofDecodingError),
}

impl From<&Signature> for Vec<u8> {
fn from(sig: &Signature) -> Self {
let mut output = Vec::new();
let lamport_sig_bytes: [u8; 8192] = sig.0.clone().into();
output.extend(lamport_sig_bytes.into_iter());

let lamport_pub_key_bytes: [u8; 16384] = (&sig.1).into();
output.extend(lamport_pub_key_bytes.into_iter());

let proof_bytes: Vec<u8> = (&sig.2).into();
output.extend(proof_bytes.into_iter());

output
}
}

impl TryFrom<&[u8]> for Signature {
type Error = SignatureDecodingError;
fn try_from(signature_bytes: &[u8]) -> Result<Self, Self::Error> {
let mut i = 0;
let next_byte = |i: &mut usize| {
if let Some(b) = signature_bytes.get(*i) {
*i += 1;
Ok(*b)
} else {
Err(SignatureDecodingError::NotEnoughInput(
signature_bytes.len(),
))
}
};
let mut lamport_signature_bytes = [0u8; 8192];
for j in 0..8192 {
lamport_signature_bytes[j] = next_byte(&mut i)?;
}
let lamport_signature = lamport::Signature::from(lamport_signature_bytes);

let mut lamport_public_key_bytes = [0u8; 16384];
for j in 0..16384 {
lamport_public_key_bytes[j] = next_byte(&mut i)?;
}
let lamport_public_key = lamport::PublicKey::from(&lamport_public_key_bytes);

let proof = Proof::try_from(&signature_bytes[i..])
.map_err(|e| SignatureDecodingError::MerkleProofDecodingError(e))?;

Ok(Signature(lamport_signature, lamport_public_key, proof))
}
}

impl PrivateKey {
pub fn inner_keys(&self) -> &Vec<lamport::PrivateKey> {
&self.0
Expand Down Expand Up @@ -131,6 +189,10 @@ mod tests {
let mut private_key = PrivateKey::generate(1).unwrap();
let public_key = private_key.public_key();
let signature = private_key.sign(&s.as_bytes()).unwrap();
let signature_bytes: Vec<u8> = (&signature).into();
let signature_bytes_ref: &[u8] = &signature_bytes;
let signature_2: Signature = signature_bytes_ref.try_into().unwrap();
assert_eq!(signature, signature_2);
assert!(public_key.verify(s.as_bytes(), &signature));

}
Expand Down
120 changes: 120 additions & 0 deletions src/merkle/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,128 @@ impl Commitment {
/// A from 1 and 2. We reveal ancillary commitments to other data,
/// such as 2 and B, but those commitments are zero-knowledge unless
/// you can find collisions for the [`blake3::hash`] function.
#[derive(Debug, Eq, PartialEq)]
pub(crate) struct Proof {
item: Vec<u8>,
index: u64,
frontier: Vec<ProofNode>,
}

#[derive(Debug)]
pub enum ProofDecodingError {
NotEnoughInput(usize),
InvalidProofNodeType(u8),
}

impl TryFrom<&[u8]> for Proof {
type Error = ProofDecodingError;

fn try_from(encoded: &[u8]) -> Result<Self, Self::Error> {
if encoded.len() < 8 {
return Err(ProofDecodingError::NotEnoughInput(encoded.len()));
}

let mut i = 0;
let next_byte = |i: &mut usize| {
if let Some(&b) = encoded.get(*i) {
*i += 1;
Ok(b)
} else {
Err(ProofDecodingError::NotEnoughInput(encoded.len()))
}
};

let next_u64 = |mut i: &mut usize| {
let mut u64_bytes = [0u8; 8];
for j in 0..8 {
u64_bytes[j] = next_byte(&mut i)?;
}
Ok(u64::from_be_bytes(u64_bytes))
};

let next_n_bytes = |mut i: &mut usize, n: u64| {
let mut v = Vec::new();
for _ in 0..n {
v.push(next_byte(&mut i)?);
}
Ok(v)
};

let next_hash = |mut i: &mut usize| {
let mut hash_bytes = [0u8; 32];
for j in 0..32 {
hash_bytes[j] = next_byte(&mut i)?;
}
Ok(Hash::from(hash_bytes))
};

let next_frontier_node = |mut i: &mut usize| {
let tag = next_byte(&mut i)?;
match tag {
0 => Ok(ProofNode::NodeWithoutSibling),
1 => Ok(ProofNode::LeftChildWithSibling(next_hash(&mut i)?)),
2 => Ok(ProofNode::RightChildWithSibling(next_hash(&mut i)?)),
b => Err(ProofDecodingError::InvalidProofNodeType(b)),
}
};

let length = next_u64(&mut i)?;
let item: Vec<u8> = next_n_bytes(&mut i, length)?;

let index = next_u64(&mut i)?;
let length = next_u64(&mut i)?;

let mut frontier: Vec<ProofNode> = Vec::new();
for _ in 0..length {
frontier.push(next_frontier_node(&mut i)?);
}

Ok(Proof {
item,
index,
frontier,
})
}
}

impl From<&Proof> for Vec<u8> {
fn from(pf: &Proof) -> Self {
fn encode_proof_node(pf_node: &ProofNode, output: &mut Vec<u8>) {
match pf_node {
ProofNode::NodeWithoutSibling => {
output.push(0);
}
ProofNode::LeftChildWithSibling(hash) => {
let bytes: [u8; 32] = hash.clone().into();
output.push(1);
for i in 0..32 {
output.push(bytes[i]);
}
}
ProofNode::RightChildWithSibling(hash) => {
let bytes: [u8; 32] = hash.clone().into();
output.push(2);
for i in 0..32 {
output.push(bytes[i]);
}
}
}
}

let mut output = Vec::new();
output.extend((pf.item.len() as u64).to_be_bytes().iter().copied());
output.extend(pf.item.iter().copied());
output.extend((pf.index as u64).to_be_bytes().iter().copied());
output.extend((pf.frontier.len() as u64).to_be_bytes().iter().copied());

for node in pf.frontier.iter() {
encode_proof_node(node, &mut output);
}

output
}
}

#[derive(PartialEq, Eq, Debug)]
enum ProofNode {
NodeWithoutSibling,
Expand Down Expand Up @@ -243,6 +359,10 @@ fn test_tree() {
fn test_prove(v: &Vec<&[u8]>) {
let tree = Tree::new(&mut v.clone().into_iter());
let mut proof = tree.prove(v[0].into(), 0).unwrap();
let v: Vec<u8> = (&proof).into();
let v_ref: &[u8] = &v;
let proof_2: Proof = v_ref.try_into().unwrap();
assert_eq!(proof, proof_2);
let commitment = tree.commitment();
assert!(commitment.verify(&proof));
if modify_frontier(&mut proof.frontier) {
Expand Down

0 comments on commit 5fbb0a5

Please sign in to comment.