-
Notifications
You must be signed in to change notification settings - Fork 208
hash!: Unify all hash types, introduce "offchain" feature #236
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
b833114
31bca93
b48fd48
42e1a58
a1bc7d0
228cb11
c7e9f72
5a4c256
852d179
1e1e76a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,48 +2,17 @@ | |
| //! | ||
| //! [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}, | ||
| std::string::ToString, | ||
| }; | ||
| use { | ||
| core::{fmt, str::FromStr}, | ||
| solana_sanitize::Sanitize, | ||
| }; | ||
| pub use solana_hash::{Hash, ParseHashError, HASH_BYTES, MAX_BASE58_LEN}; | ||
|
|
||
| // 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") | ||
| )] | ||
| #[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)] | ||
| #[cfg(all(feature = "blake3", not(target_os = "solana")))] | ||
| pub struct Hasher { | ||
| hasher: blake3::Hasher, | ||
| } | ||
|
|
||
| #[cfg(any(feature = "blake3", not(target_os = "solana")))] | ||
| #[cfg(all(feature = "blake3", not(target_os = "solana")))] | ||
| impl Hasher { | ||
| pub fn hash(&mut self, val: &[u8]) { | ||
| self.hasher.update(val); | ||
|
|
@@ -54,65 +23,7 @@ impl Hasher { | |
| } | ||
| } | ||
| pub fn result(self) -> Hash { | ||
| Hash(*self.hasher.finalize().as_bytes()) | ||
| } | ||
| } | ||
|
|
||
| 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 { | ||
| fn as_ref(&self) -> &[u8] { | ||
| &self.0[..] | ||
| } | ||
| } | ||
|
|
||
| impl fmt::Debug for Hash { | ||
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
| 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 { | ||
| let converted: solana_hash::Hash = (*self).into(); | ||
| fmt::Display::fmt(&converted, f) | ||
| } | ||
| } | ||
|
|
||
| impl FromStr for Hash { | ||
| type Err = ParseHashError; | ||
|
|
||
| fn from_str(s: &str) -> Result<Self, Self::Err> { | ||
| let unconverted = solana_hash::Hash::from_str(s)?; | ||
| Ok(unconverted.into()) | ||
| } | ||
| } | ||
|
|
||
| impl Hash { | ||
| pub const fn new_from_array(hash_array: [u8; HASH_BYTES]) -> Self { | ||
| Self(hash_array) | ||
| } | ||
|
|
||
| /// unique Hash for tests and benchmarks. | ||
| pub fn new_unique() -> Self { | ||
| Self::from(solana_hash::Hash::new_unique()) | ||
| } | ||
|
|
||
| pub fn to_bytes(self) -> [u8; HASH_BYTES] { | ||
| self.0 | ||
| Hash::new_from_array(*self.hasher.finalize().as_bytes()) | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -122,9 +33,17 @@ pub fn hashv(vals: &[&[u8]]) -> Hash { | |
| // not supported | ||
| #[cfg(not(target_os = "solana"))] | ||
| { | ||
| let mut hasher = Hasher::default(); | ||
| hasher.hashv(vals); | ||
| hasher.result() | ||
| #[cfg(feature = "blake3")] | ||
| { | ||
| let mut hasher = Hasher::default(); | ||
| hasher.hashv(vals); | ||
| hasher.result() | ||
| } | ||
| #[cfg(not(feature = "blake3"))] | ||
| { | ||
| core::hint::black_box(vals); | ||
| panic!("hashv is only available on target `solana` or with the `blake3` feature enabled on this crate") | ||
| } | ||
| } | ||
| // Call via a system call to perform the calculation | ||
| #[cfg(target_os = "solana")] | ||
|
|
@@ -146,71 +65,20 @@ 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(); | ||
| hash_data.extend_from_slice(val); | ||
| hash(&hash_data) | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| #[cfg(feature = "blake3")] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems that the feature is enabled on the dev-dependencies, so we probably don't need this. I might have missed that on my first review. Not sure if the idea is to have this pattern, but it can get a bit verbose for crates that have many features. |
||
| mod tests { | ||
| use super::*; | ||
|
|
||
| #[test] | ||
| fn test_new_unique() { | ||
| assert!(Hash::new_unique() != Hash::new_unique()); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_hash_fromstr() { | ||
| let hash = hash(&[1u8]); | ||
|
|
||
| let mut hash_base58_str = bs58::encode(hash).into_string(); | ||
|
|
||
| assert_eq!(hash_base58_str.parse::<Hash>(), Ok(hash)); | ||
|
|
||
| hash_base58_str.push_str(&bs58::encode(hash.0).into_string()); | ||
| assert_eq!( | ||
| hash_base58_str.parse::<Hash>(), | ||
| Err(ParseHashError::WrongSize) | ||
| ); | ||
|
|
||
| hash_base58_str.truncate(hash_base58_str.len() / 2); | ||
| assert_eq!(hash_base58_str.parse::<Hash>(), Ok(hash)); | ||
|
|
||
| hash_base58_str.truncate(hash_base58_str.len() / 2); | ||
| assert_eq!( | ||
| hash_base58_str.parse::<Hash>(), | ||
| Err(ParseHashError::WrongSize) | ||
| ); | ||
|
|
||
| let input_too_big = bs58::encode(&[0xffu8; HASH_BYTES + 1]).into_string(); | ||
| assert!(input_too_big.len() > MAX_BASE58_LEN); | ||
| assert_eq!( | ||
| input_too_big.parse::<Hash>(), | ||
| Err(ParseHashError::WrongSize) | ||
| ); | ||
|
|
||
| let mut hash_base58_str = bs58::encode(hash.0).into_string(); | ||
| assert_eq!(hash_base58_str.parse::<Hash>(), Ok(hash)); | ||
|
|
||
| // throw some non-base58 stuff in there | ||
| hash_base58_str.replace_range(..1, "I"); | ||
| assert_eq!( | ||
| hash_base58_str.parse::<Hash>(), | ||
| Err(ParseHashError::Invalid) | ||
| ); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_extend_and_hash() { | ||
| fn test_hashv() { | ||
| let val = "gHiljKpq"; | ||
| let val_hash = hash(val.as_bytes()); | ||
|
|
||
| let ext = "lM890t"; | ||
| let hash_ext = [&val_hash.0, ext.as_bytes()].concat(); | ||
| let ext_hash = extend_and_hash(&val_hash, ext.as_bytes()); | ||
| let ext_hash = hashv(&[&val_hash.to_bytes(), ext.as_bytes()]); | ||
|
febo marked this conversation as resolved.
|
||
|
|
||
| let hash_ext = [&val_hash.to_bytes(), ext.as_bytes()].concat(); | ||
| assert!(ext_hash == hash(&hash_ext)); | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.