From 8354e02808bec5d1ec5daff3e39aafc3b2ef5364 Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Wed, 5 Jun 2024 15:06:41 -0600 Subject: [PATCH 1/3] Update crates --- Cargo.toml | 5 +++-- src/decoding.rs | 2 +- src/encoding.rs | 2 +- src/error.rs | 14 +++++++++++--- src/file.rs | 18 +++++++++--------- src/utils.rs | 16 ++++++++++------ tests/codec.rs | 3 ++- tests/format.rs | 3 ++- 8 files changed, 39 insertions(+), 24 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e14df19..1572a9d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ include = ["src/**/*", "LICENSE", "README.md"] [dependencies] bao = "0.12.1" -bech32 = "0.9.1" +bech32 = "0.11.0" bitmask-enum = "2.1.0" bytes = "1.4.0" ecies = { version = "0.2.6", default-features = false, features = [ @@ -23,7 +23,7 @@ libsecp256k1 = { version = "0.7.1", features = ["std"] } log = "0.4.19" nom = "7.1.3" pretty_env_logger = "0.5.0" -secp256k1 = { version = "0.28.0", features = [ +secp256k1 = { version = "0.29.0", features = [ "global-context", "rand-std", "serde", @@ -33,6 +33,7 @@ snap = "1.1.0" thiserror = "1.0" zfec-rs = "0.1.0" once_cell = "1.19.0" +libsecp256k1-core = "0.3.0" [dev-dependencies] anyhow = "1.0.71" diff --git a/src/decoding.rs b/src/decoding.rs index 1084bd7..9c089ca 100644 --- a/src/decoding.rs +++ b/src/decoding.rs @@ -84,7 +84,7 @@ pub fn decode( padding: u32, format: u8, ) -> Result, CarbonadoError> { - let format = Format::try_from(format)?; + let format = Format::from(format); let verified = if format.contains(Format::Bao) { bao(input, hash)? diff --git a/src/encoding.rs b/src/encoding.rs index b0fbf2e..31c0f99 100644 --- a/src/encoding.rs +++ b/src/encoding.rs @@ -85,7 +85,7 @@ pub fn zfec(input: &[u8]) -> Result<(Vec, u32, u32), CarbonadoError> { /// `snap -> ecies -> zfec -> bao` pub fn encode(pubkey: &[u8], input: &[u8], format: u8) -> Result { let input_len = input.len() as u32; - let format = Format::try_from(format)?; + let format = Format::from(format); let compressed; let encrypted; diff --git a/src/error.rs b/src/error.rs index a0e962d..1c37535 100644 --- a/src/error.rs +++ b/src/error.rs @@ -18,9 +18,17 @@ pub enum CarbonadoError { #[error(transparent)] HexDecodeError(#[from] hex::FromHexError), - /// Bech32 error + /// Bech32 encode error #[error(transparent)] - Bech32Error(#[from] bech32::Error), + Bech32EncodeError(#[from] bech32::EncodeError), + + /// Bech32 decode error + #[error(transparent)] + Bech32DecodeError(#[from] bech32::DecodeError), + + /// Bech32 human readable part error + #[error(transparent)] + InvalidHrp(#[from] bech32::primitives::hrp::Error), /// snap error #[error(transparent)] @@ -32,7 +40,7 @@ pub enum CarbonadoError { /// ecies error #[error(transparent)] - EciesError(#[from] ecies::SecpError), + EciesError(#[from] libsecp256k1_core::Error), /// bao decode error #[error(transparent)] diff --git a/src/file.rs b/src/file.rs index 2160d5a..19045ac 100644 --- a/src/file.rs +++ b/src/file.rs @@ -80,9 +80,9 @@ impl TryFrom<&File> for Header { // Verify hash against signature signature.verify(&Message::from_digest_slice(&hash)?, &pubkey)?; - let hash = bao::Hash::try_from(hash)?; + let hash = bao::Hash::from(hash); - let format = Format::try_from(format[0])?; + let format = Format::from(format[0]); let chunk_index = u8::from_le_bytes(chunk_index); let encoded_len = u32::from_le_bytes(encoded_len); let padding_len = u32::from_le_bytes(padding_len); @@ -135,9 +135,9 @@ impl TryFrom<&[u8]> for Header { signature.verify(&Message::from_digest_slice(hash)?, &pubkey)?; let hash: [u8; 32] = hash[0..32].try_into()?; - let hash = bao::Hash::try_from(hash)?; + let hash = bao::Hash::from(hash); - let format = Format::try_from(format)?; + let format = Format::from(format); Ok(Header { pubkey, @@ -183,9 +183,9 @@ impl TryFrom for Header { signature.verify(&Message::from_digest_slice(hash)?, &pubkey)?; let hash: [u8; 32] = hash[0..32].try_into()?; - let hash = bao::Hash::try_from(hash)?; + let hash = bao::Hash::from(hash); - let format = Format::try_from(format)?; + let format = Format::from(format); Ok(Header { pubkey, @@ -231,9 +231,9 @@ impl TryFrom<&Bytes> for Header { signature.verify(&Message::from_digest_slice(hash)?, &pubkey)?; let hash: [u8; 32] = hash[0..32].try_into()?; - let hash = bao::Hash::try_from(hash)?; + let hash = bao::Hash::from(hash); - let format = Format::try_from(format)?; + let format = Format::from(format); Ok(Header { pubkey, @@ -416,7 +416,7 @@ pub fn encode( let Encoded(mut encoded, hash, encode_info) = encoding::encode(&pubkey, input, level)?; - let format = Format::try_from(level)?; + let format = Format::from(level); let header = Header::new( sk, &pubkey, diff --git a/src/utils.rs b/src/utils.rs index 99f93cf..b8ca730 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,7 +1,7 @@ use std::sync::Once; use bao::Hash; -use bech32::{decode, encode, FromBase32, ToBase32, Variant}; +use bech32::{decode, encode_to_fmt, Bech32m, Hrp}; use log::trace; use crate::{ @@ -54,12 +54,16 @@ pub fn calc_padding_len(input_len: usize) -> (u32, u32) { } /// Helper for encoding data to bech32m. -pub fn bech32m_encode(hrp: &str, bytes: &[u8]) -> Result { - Ok(encode(hrp, bytes.to_base32(), Variant::Bech32m)?) +pub fn bech32m_encode(hrp_str: &str, bytes: &[u8]) -> Result { + let hrp = Hrp::parse(hrp_str).map_err(CarbonadoError::InvalidHrp)?; + let mut buf = String::new(); + encode_to_fmt::(&mut buf, hrp, bytes)?; + Ok(buf) } /// Helper for decoding bech32-encoded data. -pub fn bech32_decode(bech32_str: &str) -> Result<(String, Vec, Variant), CarbonadoError> { - let (hrp, words, variant) = decode(bech32_str)?; - Ok((hrp, Vec::::from_base32(&words)?, variant)) +pub fn bech32_decode(bech32_str: &str) -> Result<(String, Vec), CarbonadoError> { + let (hrp, data) = decode(bech32_str).map_err(CarbonadoError::Bech32DecodeError)?; + let hrp_str = hrp.to_string(); + Ok((hrp_str, data)) } diff --git a/tests/codec.rs b/tests/codec.rs index fcf5549..67126f2 100644 --- a/tests/codec.rs +++ b/tests/codec.rs @@ -101,7 +101,7 @@ fn codec(path: &str) -> Result<()> { assert_eq!(decoded, input, "Decoded output is same as encoded input"); let carbonado_level = 15; - let format = Format::try_from(carbonado_level)?; + let format = Format::from(carbonado_level); let header = Header::new( &sk.secret_bytes(), &pk.serialize(), @@ -121,6 +121,7 @@ fn codec(path: &str) -> Result<()> { .read(true) .write(true) .create(true) + .truncate(true) .open(&file_path)?; file.write_all(&header_bytes)?; file.write_all(&encoded)?; diff --git a/tests/format.rs b/tests/format.rs index 08f80cd..1b9d907 100644 --- a/tests/format.rs +++ b/tests/format.rs @@ -19,7 +19,7 @@ fn format() -> Result<()> { let input = "Hello world!".as_bytes(); let carbonado_level = 15; - let format = Format::try_from(carbonado_level)?; + let format = Format::from(carbonado_level); let (file_sk, file_pk) = generate_keypair(&mut thread_rng()); let (node_sk, node_pk) = generate_keypair(&mut thread_rng()); @@ -63,6 +63,7 @@ fn format() -> Result<()> { .read(true) .write(true) .create(true) + .truncate(true) .open(file_path)?; file.write_all(&header_bytes)?; file.write_all(&encoded)?; From 861fa4cdc43fecea2afecf308398197e6d218559 Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Wed, 5 Jun 2024 15:12:53 -0600 Subject: [PATCH 2/3] Add BaoHasher utility --- src/utils.rs | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 2 deletions(-) diff --git a/src/utils.rs b/src/utils.rs index b8ca730..85e3292 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,6 +1,10 @@ -use std::sync::Once; +use std::{ + fmt, + io::{Cursor, Write}, + sync::{Arc, Once, RwLock}, +}; -use bao::Hash; +use bao::{encode::Encoder, Hash}; use bech32::{decode, encode_to_fmt, Bech32m, Hrp}; use log::trace; @@ -67,3 +71,71 @@ pub fn bech32_decode(bech32_str: &str) -> Result<(String, Vec), CarbonadoErr let hrp_str = hrp.to_string(); Ok((hrp_str, data)) } + +#[derive(Clone, Debug)] +pub struct BaoHash(pub bao::Hash); + +impl BaoHash { + pub fn to_bytes(&self) -> Vec { + let Self(hash) = self; + + hash.as_bytes().to_vec() + } +} + +impl fmt::Display for BaoHash { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let Self(hash) = self; + + f.write_str(&hash.to_string()) + } +} + +impl From<&[u8]> for BaoHash { + fn from(value: &[u8]) -> Self { + let mut hash = [0_u8; 32]; + hash.copy_from_slice(&value[0..32]); + Self(bao::Hash::from(hash)) + } +} + +impl From for BaoHash { + fn from(hash: bao::Hash) -> Self { + Self(hash) + } +} + +/// A threadsafe bao hasher similar to that provided by blake3 +pub struct BaoHasher { + encoder: Arc>>>>, +} + +impl BaoHasher { + pub fn new() -> Arc { + let data = Vec::new(); + let cursor = Cursor::new(data.clone()); + let encoder = Encoder::new(cursor); + + let bao_hasher = Self { + encoder: Arc::new(RwLock::new(encoder)), + }; + + Arc::new(bao_hasher) + } + + pub fn update(&self, buf: &[u8]) { + let mut encoder = self.encoder.write().expect("encoder write lock"); + encoder.write_all(buf).expect("write to encoder"); + } + + pub fn finalize(&self) -> BaoHash { + let mut encoder = self.encoder.write().expect("encoder read lock"); + BaoHash::from(encoder.finalize().expect("finalize bao hash")) + } + + pub fn read_all(&self) -> Vec { + let encoder = self.encoder.write().expect("encoder read lock"); + let data = encoder.clone().into_inner(); + data.into_inner().to_vec() + } +} From 621c61d826d2b1b7b0ab72aa8874b8e2a371857f Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Wed, 5 Jun 2024 15:15:09 -0600 Subject: [PATCH 3/3] Bump version to 0.4.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1572a9d..1329b95 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "carbonado" -version = "0.3.6" +version = "0.4.0" edition = "2021" license = "MIT" description = "An apocalypse-resistant data storage format for the truly paranoid."