diff --git a/Cargo.lock b/Cargo.lock index ba5998f0..0f379517 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3690,8 +3690,6 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexed-merkle-tree" version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1ac76516975752d90a983083c7da0a921df0b57ed4ba89aa3eac0d964a85252" dependencies = [ "cargo-audit", "hex 0.4.3", diff --git a/Cargo.toml b/Cargo.toml index 3cd13398..ae8438aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,7 +52,7 @@ clap = { version = "4.3.2", features = ["derive"] } config = "0.14.0" fs2 = "0.4.3" thiserror = "1.0.50" -indexed-merkle-tree = "0.4.1" +indexed-merkle-tree = "0.5.0" dotenvy = "0.15.7" ahash = "0.8.7" celestia-rpc = "0.2.0" diff --git a/src/da/mod.rs b/src/da/mod.rs index c9692f82..25d98b96 100644 --- a/src/da/mod.rs +++ b/src/da/mod.rs @@ -5,6 +5,7 @@ use crate::{ }; use async_trait::async_trait; use ed25519::Signature; +use indexed_merkle_tree::Hash; use serde::{Deserialize, Serialize}; use std::{self, str::FromStr}; @@ -14,8 +15,8 @@ pub mod mock; #[derive(Serialize, Deserialize, Clone)] pub struct EpochJson { pub height: u64, - pub prev_commitment: String, - pub current_commitment: String, + pub prev_commitment: Hash, + pub current_commitment: Hash, pub proof: Bls12Proof, pub verifying_key: VerifyingKey, pub signature: Option, diff --git a/src/node_types/sequencer.rs b/src/node_types/sequencer.rs index 8ac2e3bd..4a8b8194 100644 --- a/src/node_types/sequencer.rs +++ b/src/node_types/sequencer.rs @@ -4,7 +4,7 @@ use crate::{ }; use async_trait::async_trait; use ed25519_dalek::{Signer, SigningKey}; -use indexed_merkle_tree::{node::Node, sha256_mod, tree::IndexedMerkleTree}; +use indexed_merkle_tree::{node::Node, sha256_mod, tree::IndexedMerkleTree, Hash}; use std::{self, sync::Arc, time::Duration}; use tokio::{ sync::{ @@ -222,7 +222,9 @@ impl Sequencer { let prev_commitment = if epoch > 0 { let prev_epoch = epoch - 1; match self.db.get_commitment(&prev_epoch) { - Ok(commitment) => commitment, + Ok(commitment) => { + Hash::from_hex(commitment.as_str()).map_err(DeimosError::MerkleTree)? + } Err(e) => { return Err(DatabaseError::ReadError(format!( "commitment for prev epoch {:?}: {:?}", @@ -286,13 +288,9 @@ impl Sequencer { .db .get_derived_value(&key.to_string()) .map_err(|e| DatabaseError::ReadError(e.to_string()))?; - Ok(Node::new_leaf( - true, - true, - key.clone(), - value, - Node::TAIL.to_string(), - )) + let hash_key = Hash::from_hex(&key).unwrap(); + let hash_value = Hash::from_hex(&value).unwrap(); + Ok(Node::new_leaf(true, true, hash_key, hash_value, Node::TAIL)) }) .collect(); @@ -335,8 +333,8 @@ impl Sequencer { .iter() .enumerate() // use index .find(|(_, k)| { - // without dereferencing we compare &&string with &string - label.clone().is_some_and(|l| *k == &l) + let k = Hash::from_hex(k).unwrap(); + label.clone().is_some_and(|l| k == l) }) .map(|(k, _)| k) }); @@ -346,9 +344,9 @@ impl Sequencer { nodes.push(Node::new_leaf( false, true, - Node::HEAD.to_string(), - Node::HEAD.to_string(), - Node::TAIL.to_string(), + Node::HEAD, + Node::HEAD, + Node::TAIL, )); } diff --git a/src/storage.rs b/src/storage.rs index e15d1d00..7522c882 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -34,10 +34,10 @@ impl Display for Operation { #[derive(Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct ChainEntry { - pub hash: String, - pub previous_hash: String, + pub hash: Hash, + pub previous_hash: Hash, pub operation: Operation, - pub value: String, + pub value: Hash, } #[derive(Clone, Serialize, Deserialize, Debug)] @@ -99,10 +99,10 @@ pub trait Database: Send + Sync { &self, epoch: &u64, epoch_operation: &u64, - commitment: &str, + commitment: &Hash, proofs: &str, ) -> DeimosResult<()>; - fn add_commitment(&self, epoch: &u64, commitment: &str) -> DeimosResult<()>; + fn add_commitment(&self, epoch: &u64, commitment: &Hash) -> DeimosResult<()>; fn initialize_derived_dict(&self) -> DeimosResult<()>; fn flush_database(&self) -> DeimosResult<()>; } @@ -338,8 +338,10 @@ impl Database for RedisConnections { ) -> DeimosResult<()> { let mut con = self.lock_connection(&self.derived_dict)?; let mut input_con = self.lock_connection(&self.input_order)?; - let hashed_key = sha256_mod(&incoming_entry.id); - con.set::<&String, &String, String>(&hashed_key, &value.hash) + let hashed_key = sha256_mod(&incoming_entry.id.as_bytes()); + // TODO: @distractedm1nd thought about saving the raw bytes of the hash for space effiency but it seems like redis needs at least the key to be a string and for consistency we should probably save then both value as a string wdyt? + // to_string() Method works here because i've implemented the Display trait for Hash in indexed_merkle_tree crate + con.set::<&String, &String, String>(&hashed_key.to_string(), &value.hash.to_string()) .map_err(|_| { DeimosError::Database(DatabaseError::WriteError(format!( "derived dict update for key: {}", @@ -349,7 +351,7 @@ impl Database for RedisConnections { if new { input_con - .rpush::<&'static str, &String, u32>("input_order", &hashed_key) + .rpush::<&'static str, &String, u32>("input_order", &hashed_key.to_string()) .map_err(|_| { DeimosError::Database(DatabaseError::WriteError(format!( "input order update for key: {}", @@ -389,7 +391,7 @@ impl Database for RedisConnections { &self, epoch: &u64, epoch_operation: &u64, - commitment: &str, + commitment: &Hash, proofs: &str, ) -> DeimosResult<()> { let mut con = self.lock_connection(&self.merkle_proofs)?; @@ -403,7 +405,7 @@ impl Database for RedisConnections { }) } - fn add_commitment(&self, epoch: &u64, commitment: &str) -> DeimosResult<()> { + fn add_commitment(&self, epoch: &u64, commitment: &Hash) -> DeimosResult<()> { let mut con = self.lock_connection(&self.commitments)?; con.set::<&String, &String, ()>(&format!("epoch_{}", epoch), &commitment.to_string()) .map_err(|_| { @@ -484,10 +486,10 @@ mod tests { fn create_mock_chain_entry() -> ChainEntry { ChainEntry { - hash: "test_hash".to_string(), - previous_hash: "test_previous_hash".to_string(), + hash: sha256_mod(b"test_hash"), + previous_hash: sha256_mod(b"test_previous_hash"), operation: Operation::Add, - value: "test_value".to_string(), + value: sha256_mod(b"test_value"), } } @@ -644,9 +646,9 @@ mod tests { // check if the returned keys are correct let expected_keys: Vec = vec![ - sha256_mod("test_key1"), - sha256_mod("test_key2"), - sha256_mod("test_key3"), + sha256_mod(b"test_key1").to_string(), + sha256_mod(b"test_key2").to_string(), + sha256_mod(b"test_key3").to_string(), ]; let returned_keys: Vec = keys; @@ -759,7 +761,7 @@ mod tests { } let hashchain = redis_connections.get_hashchain(&incoming_entry.id).unwrap(); - assert_eq!(hashchain[0].hash, "test_hash"); + assert_eq!(hashchain[0].hash, sha256_mod(b"test_hash")); assert_eq!(hashchain.len(), 1); teardown(&redis_connections); diff --git a/src/utils.rs b/src/utils.rs index f5538e80..17ba47b3 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,14 +1,14 @@ use crate::{ error::{DeimosError, DeimosResult, GeneralError, ProofError}, storage::{ChainEntry, Operation}, - zk_snark::{hex_to_scalar, ProofVariantCircuit}, + zk_snark::{hash_to_scalar, ProofVariantCircuit}, }; use base64::{engine::general_purpose::STANDARD as engine, Engine as _}; use bellman::groth16::{self, VerifyingKey}; use bls12_381::{Bls12, Scalar}; use ed25519::Signature; use ed25519_dalek::{Verifier, VerifyingKey as Ed25519VerifyingKey}; -use indexed_merkle_tree::tree::Proof; +use indexed_merkle_tree::{tree::Proof, Hash}; use rand::rngs::OsRng; /// Checks if a given public key in the list of `ChainEntry` objects has been revoked. @@ -22,7 +22,7 @@ use rand::rngs::OsRng; /// /// `true` if the value was not revoked, otherwise `false`. /// TODO(@distractedm1nd): is_revoked > is_not_revoked, for readability -pub fn is_not_revoked(entries: &[ChainEntry], value: String) -> bool { +pub fn is_not_revoked(entries: &[ChainEntry], value: Hash) -> bool { for entry in entries { if entry.value == value && matches!(entry.operation, Operation::Revoke) { return false; @@ -80,8 +80,8 @@ pub fn create_and_verify_snark( } pub fn validate_epoch( - previous_commitment: &str, - current_commitment: &str, + previous_commitment: &Hash, + current_commitment: &Hash, proof: groth16::Proof, verifying_key: VerifyingKey, ) -> Result, DeimosError> { @@ -89,8 +89,8 @@ pub fn validate_epoch( let pvk = groth16::prepare_verifying_key(&verifying_key); let scalars: Result, _> = vec![ - hex_to_scalar(previous_commitment), - hex_to_scalar(current_commitment), + hash_to_scalar(previous_commitment), + hash_to_scalar(current_commitment), ] .into_iter() .collect(); @@ -191,18 +191,16 @@ mod tests { let mut tree = IndexedMerkleTree::new_with_size(8).unwrap(); let prev_commitment = tree.get_commitment().unwrap(); - let ryan = sha256_mod("Ryan"); - let ford = sha256_mod("Ford"); - let sebastian = sha256_mod("Sebastian"); - let pusch = sha256_mod("Pusch"); - let ethan = sha256_mod("Ethan"); - let triple_zero = sha256_mod("000"); + let ryan = sha256_mod(b"Ryan"); + let ford = sha256_mod(b"Ford"); + let sebastian = sha256_mod(b"Sebastian"); + let pusch = sha256_mod(b"Pusch"); + let ethan = sha256_mod(b"Ethan"); + let triple_zero = sha256_mod(b"000"); - let mut ryans_node = Node::new_leaf(true, false, ryan, ford, Node::TAIL.to_string()); - let mut sebastians_node = - Node::new_leaf(true, true, sebastian.clone(), pusch, Node::TAIL.to_string()); - let mut ethans_node = - Node::new_leaf(true, false, ethan, triple_zero, Node::TAIL.to_string()); + let mut ryans_node = Node::new_leaf(true, false, ryan, ford, Node::TAIL); + let mut sebastians_node = Node::new_leaf(true, true, sebastian.clone(), pusch, Node::TAIL); + let mut ethans_node = Node::new_leaf(true, false, ethan, triple_zero, Node::TAIL); let first_insert_proof = tree.insert_node(&mut ryans_node).unwrap(); let second_insert_proof = tree.insert_node(&mut sebastians_node).unwrap(); @@ -212,9 +210,8 @@ mod tests { let second_insert_zk_snark = Proof::Insert(second_insert_proof); let third_insert_zk_snark = Proof::Insert(third_insert_proof); - let updated_seb = sha256_mod("Sebastian"); - sebastians_node = - Node::new_leaf(true, true, sebastian, updated_seb, Node::TAIL.to_string()); + let updated_seb = sha256_mod(b"Sebastian"); + sebastians_node = Node::new_leaf(true, true, sebastian, updated_seb, Node::TAIL); let index = tree.find_node_index(&sebastians_node).unwrap(); let update_proof = tree.update_node(index, sebastians_node).unwrap(); diff --git a/src/webserver.rs b/src/webserver.rs index 024b6fa0..8d2d805c 100644 --- a/src/webserver.rs +++ b/src/webserver.rs @@ -178,7 +178,7 @@ async fn update_entry( .json(format!("Error creating new tree: {}", e)) } }; - let hashed_id = sha256_mod(&incoming_entry.id); + let hashed_id = sha256_mod(incoming_entry.id.as_bytes()); let mut node = match new_tree.find_leaf_by_label(&hashed_id) { Some(n) => n, None => return HttpResponse::InternalServerError().json("Error finding leaf"), diff --git a/src/zk_snark.rs b/src/zk_snark.rs index 66a7a680..eaeb1707 100644 --- a/src/zk_snark.rs +++ b/src/zk_snark.rs @@ -11,6 +11,7 @@ use indexed_merkle_tree::{ node::{LeafNode, Node}, sha256_mod, tree::{InsertProof, MerkleProof, Proof, UpdateProof}, + Hash, }; use serde::{Deserialize, Serialize}; @@ -214,7 +215,7 @@ impl TryFrom for groth16::VerifyingKey { fn unpack_and_process(proof: &MerkleProof) -> Result<(Scalar, &Vec), DeimosError> { if !proof.path.is_empty() { - let root = hex_to_scalar(&proof.root_hash)?; + let root = hash_to_scalar(&proof.root_hash)?; Ok((root, &proof.path)) } else { Err(DeimosError::Proof(ProofError::ProofUnpackError(format!( @@ -234,27 +235,33 @@ mod tests { use indexed_merkle_tree::{node::Node, sha256_mod, tree::IndexedMerkleTree}; use rand::rngs::OsRng; - const EMPTY_HASH: &str = Node::HEAD; - const TAIL: &str = Node::TAIL; - fn head_scalar() -> Scalar { - hex_to_scalar("0000000000000000000000000000000000000000000000000000000000000000").unwrap() + hash_to_scalar(&Node::HEAD).unwrap() } fn small_scalar() -> Scalar { - hex_to_scalar("13ae3ed6fe76d459c9c66fe38ff187593561a1f24d34cb22e06148c77e4cc02b").unwrap() + let small_hash = + Hash::from_hex("13ae3ed6fe76d459c9c66fe38ff187593561a1f24d34cb22e06148c77e4cc02b") + .unwrap(); + hash_to_scalar(&small_hash).unwrap() } fn mid_scalar() -> Scalar { - hex_to_scalar("3d1e830624b2572adc05351a7cbee2d3aa3f6a52b34fa38a260c9c78f96fcd07").unwrap() + let mid_hash = + Hash::from_hex("3d1e830624b2572adc05351a7cbee2d3aa3f6a52b34fa38a260c9c78f96fcd07") + .unwrap(); + hash_to_scalar(&mid_hash).unwrap() } fn big_scalar() -> Scalar { - hex_to_scalar("6714dda957170ad7720bbd2c38004152f34ea5d4350a154b84a259cc62a5dbb4").unwrap() + let big_hash = + Hash::from_hex("6714dda957170ad7720bbd2c38004152f34ea5d4350a154b84a259cc62a5dbb4") + .unwrap(); + hash_to_scalar(&big_hash).unwrap() } fn tail_scalar() -> Scalar { - hex_to_scalar("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000").unwrap() + hash_to_scalar(&Node::TAIL).unwrap() } fn create_scalars() -> (Scalar, Scalar, Scalar, Scalar, Scalar) { @@ -279,20 +286,8 @@ mod tests { } fn build_empty_tree() -> IndexedMerkleTree { - let active_node = Node::new_leaf( - true, - true, - EMPTY_HASH.to_string(), - EMPTY_HASH.to_string(), - TAIL.to_string(), - ); - let inactive_node = Node::new_leaf( - false, - true, - EMPTY_HASH.to_string(), - EMPTY_HASH.to_string(), - TAIL.to_string(), - ); + let active_node = Node::new_leaf(true, true, Node::HEAD, Node::HEAD, Node::TAIL); + let inactive_node = Node::new_leaf(false, true, Node::HEAD, Node::HEAD, Node::TAIL); // build a tree with 4 nodes IndexedMerkleTree::new(vec![ @@ -339,16 +334,16 @@ mod tests { let prev_commitment = tree.get_commitment().unwrap(); // create two nodes to insert - let ryan = sha256_mod("Ryan"); - let ford = sha256_mod("Ford"); - let sebastian = sha256_mod("Sebastian"); - let pusch = sha256_mod("Pusch"); - let ethan = sha256_mod("Ethan"); - let triple_zero = sha256_mod("000"); + let ryan = sha256_mod(b"Ryan"); + let ford = sha256_mod(b"Ford"); + let sebastian = sha256_mod(b"Sebastian"); + let pusch = sha256_mod(b"Pusch"); + let ethan = sha256_mod(b"Ethan"); + let triple_zero = sha256_mod(b"000"); - let mut ryans_node = Node::new_leaf(true, true, ryan, ford, TAIL.to_string()); - let mut sebastians_node = Node::new_leaf(true, true, sebastian, pusch, TAIL.to_string()); - let mut ethans_node = Node::new_leaf(true, true, ethan, triple_zero, TAIL.to_string()); + let mut ryans_node = Node::new_leaf(true, true, ryan, ford, Node::TAIL); + let mut sebastians_node = Node::new_leaf(true, true, sebastian, pusch, Node::TAIL); + let mut ethans_node = Node::new_leaf(true, true, ethan, triple_zero, Node::TAIL); // generate proofs for the two nodes let first_insert_proof = tree.insert_node(&mut ryans_node).unwrap(); @@ -443,20 +438,9 @@ pub struct BatchMerkleProofCircuit { pub proofs: Vec, } -pub fn hex_to_scalar(hex_string: &str) -> Result { - let bytes = hex::decode(hex_string).map_err(|e| { - GeneralError::DecodingError(format!("failed to decode hex string {}: {}", hex_string, e)) - })?; - - if bytes.len() != 32 { - return Err(GeneralError::ParsingError(format!( - "failed to parse hex string to byte array: expected 32 bytes, got {} bytes", - bytes.len() - ))); - } - +pub fn hash_to_scalar(hash: &Hash) -> Result { let mut byte_array = [0u8; 32]; - byte_array.copy_from_slice(&bytes[..32]); + byte_array.copy_from_slice(hash.as_ref()); byte_array.reverse(); // Convert the byte array to an array of four u64 values @@ -474,13 +458,14 @@ pub fn hex_to_scalar(hex_string: &str) -> Result { pub fn recalculate_hash_as_scalar(path: &[Node]) -> Result { let mut current_hash = path[0].get_hash(); for node in path.iter().skip(1) { - if node.is_left_sibling() { - current_hash = sha256_mod(&format!("{}{}", &node.get_hash(), current_hash)); + let combined = if node.is_left_sibling() { + [node.get_hash().as_ref(), current_hash.as_ref()].concat() } else { - current_hash = sha256_mod(&format!("{}{}", current_hash, &node.get_hash())); - } + [current_hash.as_ref(), node.get_hash().as_ref()].concat() + }; + current_hash = sha256_mod(&combined); } - hex_to_scalar(current_hash.as_str()) + hash_to_scalar(¤t_hash) } fn proof_of_update>( @@ -545,9 +530,9 @@ fn proof_of_non_membership>( ) -> Result<(), SynthesisError> { // first we need to make sure, that the label of the missing node lies between the first element of the path - let current_label = hex_to_scalar(&non_membership_path[0].get_label()).unwrap(); - let missing_label = hex_to_scalar(&missing_node.label).unwrap(); - let curret_next = hex_to_scalar(&non_membership_path[0].get_next()).unwrap(); + let current_label = hash_to_scalar(&non_membership_path[0].get_label()).unwrap(); + let missing_label = hash_to_scalar(&missing_node.label).unwrap(); + let curret_next = hash_to_scalar(&non_membership_path[0].get_next()).unwrap(); // circuit check LessThanCircuit::new(current_label, missing_label) @@ -869,8 +854,8 @@ impl UpdateMerkleProofCircuit { // // TODO: are there cases where MissingArgumentError isnt the right type? // let old_root = - // hex_to_scalar(&old_root.ok_or(GeneralError::MissingArgumentError)?.as_str())?; - // let updated_root = hex_to_scalar( + // hash_to_scalar(&old_root.ok_or(GeneralError::MissingArgumentError)?.as_str())?; + // let updated_root = hash_to_scalar( // &updated_root // .ok_or(GeneralError::MissingArgumentError)? // .as_str(), @@ -898,12 +883,12 @@ impl UpdateMerkleProofCircuit { impl BatchMerkleProofCircuit { pub fn new( - old_commitment: &str, - new_commitment: &str, + old_commitment: &Hash, + new_commitment: &Hash, proofs: Vec, ) -> Result { - let parsed_old_commitment = hex_to_scalar(old_commitment).map_err(DeimosError::General)?; - let parsed_new_commitment = hex_to_scalar(new_commitment).map_err(DeimosError::General)?; + let parsed_old_commitment = hash_to_scalar(old_commitment).map_err(DeimosError::General)?; + let parsed_new_commitment = hash_to_scalar(new_commitment).map_err(DeimosError::General)?; let mut proof_circuit_array: Vec = vec![]; for proof in proofs { match proof { @@ -941,11 +926,11 @@ impl HashChainEntryCircuit { hashchain: Vec, ) -> Result { // hash the clear text and parse it to scalar - let hashed_value = sha256_mod(value); - let parsed_value = hex_to_scalar(&hashed_value)?; + let hashed_value = sha256_mod(value.as_bytes()); + let parsed_value = hash_to_scalar(&hashed_value)?; let mut parsed_hashchain: Vec = vec![]; for entry in hashchain { - parsed_hashchain.push(hex_to_scalar(entry.value.as_str())?) + parsed_hashchain.push(hash_to_scalar(&entry.value)?) } Ok(HashChainEntryCircuit { value: parsed_value, @@ -954,7 +939,7 @@ impl HashChainEntryCircuit { } pub fn create_public_parameter(value: &str) -> Result { - let hashed_value = sha256_mod(value); - hex_to_scalar(hashed_value.as_str()) + let hashed_value = sha256_mod(value.as_bytes()); + hash_to_scalar(&hashed_value) } }