Skip to content

Commit

Permalink
extract blake3-hasher crate
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinheavey committed Jan 16, 2025
1 parent f76c121 commit c2dbbd1
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 44 deletions.
18 changes: 18 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ members = [
"sdk/account-info",
"sdk/atomic-u64",
"sdk/bincode",
"sdk/blake3-hasher",
"sdk/borsh",
"sdk/cargo-build-sbf",
"sdk/cargo-test-sbf",
Expand Down Expand Up @@ -449,6 +450,7 @@ solana-banks-interface = { path = "banks-interface", version = "=2.2.0" }
solana-banks-server = { path = "banks-server", version = "=2.2.0" }
solana-bench-tps = { path = "bench-tps", version = "=2.2.0" }
solana-bincode = { path = "sdk/bincode", version = "=2.2.0" }
solana-blake3-hasher = { path = "sdk/blake3-hasher" }
solana-bloom = { path = "bloom", version = "=2.2.0" }
solana-bn254 = { path = "curves/bn254", version = "=2.2.0" }
solana-borsh = { path = "sdk/borsh", version = "=2.2.0" }
Expand Down
13 changes: 12 additions & 1 deletion programs/sbf/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

53 changes: 53 additions & 0 deletions sdk/blake3-hasher/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
[package]
name = "solana-blake3-hasher"
description = "Solana BLAKE3 hashing"
documentation = "https://docs.rs/solana-blake3-hasher"
version = { workspace = true }
authors = { workspace = true }
repository = { workspace = true }
homepage = { workspace = true }
license = { workspace = true }
edition = { workspace = true }

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
all-features = true
rustdoc-args = ["--cfg=docsrs"]

[dependencies]
borsh = { workspace = true, optional = true }
serde = { workspace = true, optional = true }
serde_derive = { workspace = true, optional = true }
solana-frozen-abi = { workspace = true, optional = true, features = [
"frozen-abi",
] }
solana-frozen-abi-macro = { workspace = true, optional = true, features = [
"frozen-abi",
] }
solana-hash = { workspace = true }
solana-sanitize = { workspace = true }

[target.'cfg(not(target_os = "solana"))'.dependencies]
blake3 = { workspace = true }

[target.'cfg(target_os = "solana")'.dependencies]
# blake3 should be removed in the next breaking release,
# as there's no reason to use the crate instead of the syscall
# onchain
blake3 = { workspace = true, optional = true }
solana-define-syscall = { workspace = true }

[dev-dependencies]
bs58 = { workspace = true, features = ["std"] }
solana-blake3-hasher = { path = ".", features = ["dev-context-only-utils"] }

[features]
borsh = ["dep:borsh", "std"]
dev-context-only-utils = ["std"]
frozen-abi = ["dep:solana-frozen-abi", "dep:solana-frozen-abi-macro", "std"]
serde = ["dep:serde", "dep:serde_derive"]
blake3 = ["dep:blake3"]
std = ["solana-hash/std"]

[lints]
workspace = true
88 changes: 47 additions & 41 deletions sdk/program/src/blake3.rs → sdk/blake3-hasher/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,49 @@
//! Hashing with the [blake3] hash function.
//!
//! [blake3]: https://github.com/BLAKE3-team/BLAKE3
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![cfg_attr(feature = "frozen-abi", feature(min_specialization))]
#![no_std]
#[cfg(feature = "std")]
extern crate std;

pub use solana_hash::{ParseHashError, HASH_BYTES, MAX_BASE58_LEN};
#[cfg(feature = "borsh")]
use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
use {
borsh::{BorshDeserialize, BorshSchema, BorshSerialize},
std::string::ToString,
};
use {
core::{fmt, str::FromStr},
solana_sanitize::Sanitize,
std::{convert::TryFrom, fmt, str::FromStr},
thiserror::Error,
};

/// Size of a hash in bytes.
pub const HASH_BYTES: usize = 32;
/// Maximum string length of a base58 encoded hash.
const MAX_BASE58_LEN: usize = 44;

/// A blake3 hash.
#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
// TODO: replace this with `solana_hash::Hash` in the
// next breaking change.
// It's a breaking change because the field is public
// here and private in `solana_hash`, and making
// it public in `solana_hash` would break wasm-bindgen
#[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))]
#[cfg_attr(
feature = "borsh",
derive(BorshSerialize, BorshDeserialize, BorshSchema),
borsh(crate = "borsh")
)]
#[derive(Serialize, Deserialize, Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[cfg_attr(
feature = "serde",
derive(serde_derive::Deserialize, serde_derive::Serialize)
)]
#[derive(Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[repr(transparent)]
pub struct Hash(pub [u8; HASH_BYTES]);

#[cfg(any(feature = "blake3", not(target_os = "solana")))]
#[derive(Clone, Default)]
pub struct Hasher {
hasher: blake3::Hasher,
}

#[cfg(any(feature = "blake3", not(target_os = "solana")))]
impl Hasher {
pub fn hash(&mut self, val: &[u8]) {
self.hasher.update(val);
Expand All @@ -45,6 +58,18 @@ impl Hasher {
}
}

impl From<solana_hash::Hash> for Hash {
fn from(val: solana_hash::Hash) -> Self {
Self(val.to_bytes())
}
}

impl From<Hash> for solana_hash::Hash {
fn from(val: Hash) -> Self {
Self::new_from_array(val.0)
}
}

impl Sanitize for Hash {}

impl AsRef<[u8]> for Hash {
Expand All @@ -55,46 +80,32 @@ impl AsRef<[u8]> for Hash {

impl fmt::Debug for Hash {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", bs58::encode(self.0).into_string())
let converted: solana_hash::Hash = (*self).into();
fmt::Debug::fmt(&converted, f)
}
}

impl fmt::Display for Hash {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", bs58::encode(self.0).into_string())
let converted: solana_hash::Hash = (*self).into();
fmt::Display::fmt(&converted, f)
}
}

#[derive(Debug, Clone, PartialEq, Eq, Error)]
pub enum ParseHashError {
#[error("string decoded to wrong size for hash")]
WrongSize,
#[error("failed to decoded string to hash")]
Invalid,
}

impl FromStr for Hash {
type Err = ParseHashError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.len() > MAX_BASE58_LEN {
return Err(ParseHashError::WrongSize);
}
bs58::decode(s)
.into_vec()
.map_err(|_| ParseHashError::Invalid)
.and_then(|bytes| {
<[u8; HASH_BYTES]>::try_from(bytes)
.map(Hash::new_from_array)
.map_err(|_| ParseHashError::WrongSize)
})
let unconverted = solana_hash::Hash::from_str(s)?;
Ok(unconverted.into())
}
}

impl Hash {
#[deprecated(since = "2.2.0", note = "Use 'Hash::new_from_array' instead")]
pub fn new(hash_slice: &[u8]) -> Self {
Hash(<[u8; HASH_BYTES]>::try_from(hash_slice).unwrap())
#[allow(deprecated)]
Self::from(solana_hash::Hash::new(hash_slice))
}

pub const fn new_from_array(hash_array: [u8; HASH_BYTES]) -> Self {
Expand All @@ -103,13 +114,7 @@ impl Hash {

/// unique Hash for tests and benchmarks.
pub fn new_unique() -> Self {
use solana_atomic_u64::AtomicU64;
static I: AtomicU64 = AtomicU64::new(1);

let mut b = [0u8; HASH_BYTES];
let i = I.fetch_add(1);
b[0..8].copy_from_slice(&i.to_le_bytes());
Self::new_from_array(b)
Self::from(solana_hash::Hash::new_unique())
}

pub fn to_bytes(self) -> [u8; HASH_BYTES] {
Expand All @@ -132,7 +137,7 @@ pub fn hashv(vals: &[&[u8]]) -> Hash {
{
let mut hash_result = [0; HASH_BYTES];
unsafe {
crate::syscalls::sol_blake3(
solana_define_syscall::definitions::sol_blake3(
vals as *const _ as *const u8,
vals.len() as u64,
&mut hash_result as *mut _ as *mut u8,
Expand All @@ -147,6 +152,7 @@ pub fn hash(val: &[u8]) -> Hash {
hashv(&[val])
}

#[cfg(feature = "std")]
/// Return the hash of the given hash extended with the given value.
pub fn extend_and_hash(id: &Hash, val: &[u8]) -> Hash {
let mut hash_data = id.as_ref().to_vec();
Expand Down
1 change: 1 addition & 0 deletions sdk/program/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ serde_derive = { workspace = true }
solana-account-info = { workspace = true, features = ["bincode"] }
solana-atomic-u64 = { workspace = true }
solana-bincode = { workspace = true }
solana-blake3-hasher = { workspace = true, features = ["blake3"] }
solana-borsh = { workspace = true, optional = true }
solana-clock = { workspace = true, features = ["serde", "sysvar"] }
solana-cpi = { workspace = true }
Expand Down
3 changes: 2 additions & 1 deletion sdk/program/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,6 @@ extern crate self as solana_program;

pub mod address_lookup_table;
pub mod big_mod_exp;
pub mod blake3;
pub mod bpf_loader;
pub mod bpf_loader_deprecated;
pub mod bpf_loader_upgradeable;
Expand Down Expand Up @@ -506,6 +505,8 @@ pub mod sysvar;
pub mod vote;
pub mod wasm;

#[deprecated(since = "2.2.0", note = "Use `solana-blake3-hasher` crate instead")]
pub use solana_blake3_hasher as blake3;
#[cfg(feature = "borsh")]
#[deprecated(since = "2.1.0", note = "Use `solana-borsh` crate instead")]
pub use solana_borsh::deprecated as borsh;
Expand Down
13 changes: 12 additions & 1 deletion svm/examples/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit c2dbbd1

Please sign in to comment.