mirror of
https://github.com/UneBaguette/blake3.wasm.git
synced 2026-08-26 00:00:25 +02:00
feat!: native-first API refactor, WASM behind feature flag
BREAKING: native functions return [u8; 32] instead of Vec<u8>. BREAKING: WASM bindings require `wasm` feature flag. New Blake3Error type replaces JsError for native consumers.
This commit is contained in:
@@ -30,4 +30,4 @@ jobs:
|
|||||||
run: cargo test
|
run: cargo test
|
||||||
|
|
||||||
- name: WASM tests (Node)
|
- name: WASM tests (Node)
|
||||||
run: wasm-pack test --node
|
run: wasm-pack test --node --features wasm,talc
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ jobs:
|
|||||||
run: cargo test
|
run: cargo test
|
||||||
|
|
||||||
- name: WASM tests (Node)
|
- name: WASM tests (Node)
|
||||||
run: wasm-pack test --node
|
run: wasm-pack test --node --features wasm,talc
|
||||||
|
|
||||||
- name: Build package
|
- name: Build package
|
||||||
run: make
|
run: make
|
||||||
|
|||||||
Generated
+1
-1
@@ -53,7 +53,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "blake3-wasm-rs"
|
name = "blake3-wasm-rs"
|
||||||
version = "0.5.2"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"blake3",
|
"blake3",
|
||||||
"hex",
|
"hex",
|
||||||
|
|||||||
+6
-4
@@ -1,12 +1,12 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "blake3-wasm-rs"
|
name = "blake3-wasm-rs"
|
||||||
version = "0.5.2"
|
version = "0.6.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
authors = ["Thomas <[email protected]>"]
|
authors = ["Thomas <[email protected]>"]
|
||||||
publish = false
|
publish = false
|
||||||
repository = "https://github.com/UneBaguette/blake3.wasm"
|
repository = "https://github.com/UneBaguette/blake3.wasm"
|
||||||
description = "Simple blake3 to wasm project"
|
description = "BLAKE3 hashing with optional WASM bindings"
|
||||||
keywords = ["blake3", "wasm", "hash", "cryptography", "wasm-bindgen"]
|
keywords = ["blake3", "wasm", "hash", "cryptography", "wasm-bindgen"]
|
||||||
categories = ["cryptography", "wasm"]
|
categories = ["cryptography", "wasm"]
|
||||||
|
|
||||||
@@ -14,11 +14,13 @@ categories = ["cryptography", "wasm"]
|
|||||||
crate-type = ["cdylib", "rlib"]
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
default = []
|
||||||
|
wasm = ["dep:wasm-bindgen"]
|
||||||
talc = ["dep:talc"]
|
talc = ["dep:talc"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
blake3 = { version = "1.8", features = ["wasm32_simd"] }
|
blake3 = { version = "1", features = ["wasm32_simd"] }
|
||||||
wasm-bindgen = "=0.2.118"
|
wasm-bindgen = { version = "=0.2.118", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
wasm-bindgen-test = "0.3"
|
wasm-bindgen-test = "0.3"
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ build: build-all node-esm
|
|||||||
|
|
||||||
build-all:
|
build-all:
|
||||||
@echo "Building all target..."
|
@echo "Building all target..."
|
||||||
RUSTFLAGS='-C opt-level=3 -C target-feature=+simd128' $(CARGO) build --target $(WASM_TARGET) --release --features talc
|
RUSTFLAGS='-C opt-level=3 -C target-feature=+simd128' $(CARGO) build --target $(WASM_TARGET) --release --features wasm,talc
|
||||||
@mkdir -p $(ROOT)/bundler $(ROOT)/web $(ROOT)/node
|
@mkdir -p $(ROOT)/bundler $(ROOT)/web $(ROOT)/node
|
||||||
$(WASM_BINDGEN) --target bundler --out-dir $(ROOT)/bundler $(TARGET_DIR)/$(CRATE).wasm
|
$(WASM_BINDGEN) --target bundler --out-dir $(ROOT)/bundler $(TARGET_DIR)/$(CRATE).wasm
|
||||||
$(WASM_BINDGEN) --target web --out-dir $(ROOT)/web $(TARGET_DIR)/$(CRATE).wasm
|
$(WASM_BINDGEN) --target web --out-dir $(ROOT)/web $(TARGET_DIR)/$(CRATE).wasm
|
||||||
@@ -35,9 +35,9 @@ build-all:
|
|||||||
@cp scripts/tpl/index.js.template $(ROOT)/index.js
|
@cp scripts/tpl/index.js.template $(ROOT)/index.js
|
||||||
@cp scripts/tpl/index.d.ts $(ROOT)/index.d.ts
|
@cp scripts/tpl/index.d.ts $(ROOT)/index.d.ts
|
||||||
@cp README.md $(ROOT)/README.md
|
@cp README.md $(ROOT)/README.md
|
||||||
@cp LICENSE-MIT $(PKG_DIR)/LICENSE-MIT
|
@cp LICENSE-MIT $(ROOT)/LICENSE-MIT
|
||||||
@cp LICENSE-APACHE $(PKG_DIR)/LICENSE-APACHE
|
@cp LICENSE-APACHE $(ROOT)/LICENSE-APACHE
|
||||||
@sed -i 's|// @ts-nocheck|// Types|' $(ROOT)/index.d.ts
|
@sed -i 's|// @ts-nocheck||' $(ROOT)/index.d.ts
|
||||||
@node -e "\
|
@node -e "\
|
||||||
const pkg = {\
|
const pkg = {\
|
||||||
name: 'blake3-wasm-rs',\
|
name: 'blake3-wasm-rs',\
|
||||||
|
|||||||
Vendored
-1
@@ -1,6 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
// Copyright 2026 Thomas <[email protected]>
|
// Copyright 2026 Thomas <[email protected]>
|
||||||
//
|
|
||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
|
|
||||||
export { Hasher, deriveKey, hash, hashXof, keyedHash } from './bundler/blake3_wasm_rs';
|
export { Hasher, deriveKey, hash, hashXof, keyedHash } from './bundler/blake3_wasm_rs';
|
||||||
+197
-58
@@ -1,8 +1,6 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
// Copyright 2026 Thomas <[email protected]>
|
// Copyright 2026 Thomas <[email protected]>
|
||||||
|
|
||||||
use wasm_bindgen::prelude::*;
|
|
||||||
|
|
||||||
#[cfg(all(
|
#[cfg(all(
|
||||||
not(target_feature = "atomics"),
|
not(target_feature = "atomics"),
|
||||||
target_family = "wasm",
|
target_family = "wasm",
|
||||||
@@ -13,77 +11,77 @@ static TALC: talc::wasm::WasmDynamicTalc = talc::wasm::new_wasm_dynamic_allocato
|
|||||||
|
|
||||||
const MAX_XOF_LEN: usize = 1 << 16; // 65_536
|
const MAX_XOF_LEN: usize = 1 << 16; // 65_536
|
||||||
|
|
||||||
fn checked_xof_len(out_len: usize) -> Result<usize, JsError> {
|
#[derive(Debug)]
|
||||||
|
pub struct Blake3Error(pub String);
|
||||||
|
|
||||||
|
impl core::fmt::Display for Blake3Error {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
write!(f, "{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for Blake3Error {}
|
||||||
|
|
||||||
|
fn err(msg: &str) -> Blake3Error {
|
||||||
|
Blake3Error(msg.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn checked_xof_len(out_len: usize) -> Result<usize, Blake3Error> {
|
||||||
if out_len == 0 || out_len > MAX_XOF_LEN {
|
if out_len == 0 || out_len > MAX_XOF_LEN {
|
||||||
return Err(JsError::new("out_len must be between 1 and 65536"));
|
return Err(err("out_len must be between 1 and 65536"));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(out_len)
|
Ok(out_len)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Hash data and return a 32-byte BLAKE3 digest.
|
/// Hash data and return a 32-byte BLAKE3 digest.
|
||||||
#[wasm_bindgen]
|
pub fn hash(value: &[u8]) -> [u8; 32] {
|
||||||
pub fn hash(value: &[u8]) -> Vec<u8> {
|
*blake3::hash(value).as_bytes()
|
||||||
blake3::hash(value).as_bytes().to_vec()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Hash data with variable-length output (XOF mode).
|
/// Hash data with variable-length output (XOF mode).
|
||||||
/// Returns `out_len` bytes of BLAKE3 extended output.
|
/// Returns `out_len` bytes of BLAKE3 extended output.
|
||||||
#[wasm_bindgen(js_name = "hashXof")]
|
pub fn hash_xof(data: &[u8], out_len: usize) -> Result<Vec<u8>, Blake3Error> {
|
||||||
pub fn hash_xof(data: &[u8], out_len: usize) -> Result<Vec<u8>, JsError> {
|
|
||||||
let out_len = checked_xof_len(out_len)?;
|
let out_len = checked_xof_len(out_len)?;
|
||||||
let mut out = vec![0u8; out_len];
|
let mut out = vec![0u8; out_len];
|
||||||
let mut reader = blake3::Hasher::new().update(data).finalize_xof();
|
|
||||||
|
|
||||||
reader.fill(&mut out);
|
blake3::Hasher::new()
|
||||||
|
.update(data)
|
||||||
|
.finalize_xof()
|
||||||
|
.fill(&mut out);
|
||||||
|
|
||||||
Ok(out)
|
Ok(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute a keyed BLAKE3 hash (MAC). Key must be exactly 32 bytes.
|
/// Compute a keyed BLAKE3 hash (MAC). Key must be exactly 32 bytes.
|
||||||
/// Throws if the key length is wrong.
|
/// Throws if the key length is wrong.
|
||||||
#[wasm_bindgen(js_name = "keyedHash")]
|
pub fn keyed_hash(data: &[u8], key: &[u8]) -> Result<[u8; 32], Blake3Error> {
|
||||||
pub fn keyed_hash(data: &[u8], key: &[u8]) -> Result<Vec<u8>, JsError> {
|
|
||||||
let key: &[u8; 32] = key
|
let key: &[u8; 32] = key
|
||||||
.try_into()
|
.try_into()
|
||||||
.map_err(|_| JsError::new("key must be exactly 32 bytes"))?;
|
.map_err(|_| err("key must be exactly 32 bytes"))?;
|
||||||
|
|
||||||
Ok(blake3::keyed_hash(key, data).as_bytes().to_vec())
|
Ok(*blake3::keyed_hash(key, data).as_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Derive a 32-byte key from a context string and key material.
|
/// Derive a 32-byte key from a context string and key material.
|
||||||
/// Context should be a hardcoded, globally unique, application-specific string.
|
/// Context should be a hardcoded, globally unique, application-specific string.
|
||||||
#[wasm_bindgen(js_name = "deriveKey")]
|
pub fn derive_key(context: &str, key_material: &[u8]) -> [u8; 32] {
|
||||||
pub fn derive_key(context: &str, key_material: &[u8]) -> Vec<u8> {
|
blake3::derive_key(context, key_material)
|
||||||
blake3::derive_key(context, key_material).to_vec()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Incremental BLAKE3 hasher for streaming data.
|
|
||||||
///
|
|
||||||
/// ```js
|
|
||||||
/// const hasher = new Hasher();
|
|
||||||
/// hasher.update(chunk1);
|
|
||||||
/// hasher.update(chunk2);
|
|
||||||
/// const digest = hasher.finalize(); // 32 bytes
|
|
||||||
/// ```
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub struct Hasher(blake3::Hasher);
|
pub struct Hasher(blake3::Hasher);
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
impl Hasher {
|
impl Hasher {
|
||||||
/// Create a new hasher for unkeyed hashing.
|
/// Create a new hasher for unkeyed hashing.
|
||||||
#[wasm_bindgen(constructor)]
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Hasher(blake3::Hasher::new())
|
Hasher(blake3::Hasher::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a keyed hasher (MAC mode). Key must be exactly 32 bytes.
|
/// Create a keyed hasher (MAC mode). Key must be exactly 32 bytes.
|
||||||
/// Throws if the key length is wrong.
|
/// Throws if the key length is wrong.
|
||||||
#[wasm_bindgen(js_name = "newKeyed")]
|
pub fn new_keyed(key: &[u8]) -> Result<Hasher, Blake3Error> {
|
||||||
pub fn new_keyed(key: &[u8]) -> Result<Hasher, JsError> {
|
|
||||||
let key: &[u8; 32] = key
|
let key: &[u8; 32] = key
|
||||||
.try_into()
|
.try_into()
|
||||||
.map_err(|_| JsError::new("key must be exactly 32 bytes"))?;
|
.map_err(|_| err("key must be exactly 32 bytes"))?;
|
||||||
|
|
||||||
Ok(Hasher(blake3::Hasher::new_keyed(key)))
|
Ok(Hasher(blake3::Hasher::new_keyed(key)))
|
||||||
}
|
}
|
||||||
@@ -91,8 +89,7 @@ impl Hasher {
|
|||||||
/// Create a hasher in derive-key mode.
|
/// Create a hasher in derive-key mode.
|
||||||
/// Context should be a hardcoded, globally unique, application-specific string.
|
/// Context should be a hardcoded, globally unique, application-specific string.
|
||||||
/// Feed key material via `update()`, then call `finalize()`.
|
/// Feed key material via `update()`, then call `finalize()`.
|
||||||
#[wasm_bindgen(js_name = "newDeriveKey")]
|
pub fn new_derive_key(context: &str) -> Self {
|
||||||
pub fn new_derive_key(context: &str) -> Hasher {
|
|
||||||
Hasher(blake3::Hasher::new_derive_key(context))
|
Hasher(blake3::Hasher::new_derive_key(context))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,15 +99,15 @@ impl Hasher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return the 32-byte hash digest. Non-destructive. Can be called multiple times.
|
/// Return the 32-byte hash digest. Non-destructive. Can be called multiple times.
|
||||||
pub fn finalize(&self) -> Vec<u8> {
|
pub fn finalize(&self) -> [u8; 32] {
|
||||||
self.0.finalize().as_bytes().to_vec()
|
*self.0.finalize().as_bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `out_len` bytes of extended output (XOF mode). Non-destructive.
|
/// Return `out_len` bytes of extended output (XOF mode). Non-destructive.
|
||||||
#[wasm_bindgen(js_name = "finalizeXof")]
|
pub fn finalize_xof(&self, out_len: usize) -> Result<Vec<u8>, Blake3Error> {
|
||||||
pub fn finalize_xof(&self, out_len: usize) -> Result<Vec<u8>, JsError> {
|
|
||||||
let out_len = checked_xof_len(out_len)?;
|
let out_len = checked_xof_len(out_len)?;
|
||||||
let mut out = vec![0u8; out_len];
|
let mut out = vec![0u8; out_len];
|
||||||
|
|
||||||
self.0.finalize_xof().fill(&mut out);
|
self.0.finalize_xof().fill(&mut out);
|
||||||
|
|
||||||
Ok(out)
|
Ok(out)
|
||||||
@@ -118,9 +115,9 @@ impl Hasher {
|
|||||||
|
|
||||||
/// Finalize the hash and reset the hasher in one call.
|
/// Finalize the hash and reset the hasher in one call.
|
||||||
/// Useful for hashing multiple inputs sequentially without creating new instances.
|
/// Useful for hashing multiple inputs sequentially without creating new instances.
|
||||||
#[wasm_bindgen(js_name = "finalizeAndReset")]
|
pub fn finalize_and_reset(&mut self) -> [u8; 32] {
|
||||||
pub fn finalize_and_reset(&mut self) -> Vec<u8> {
|
let out = *self.0.finalize().as_bytes();
|
||||||
let out = self.0.finalize().as_bytes().to_vec();
|
|
||||||
self.0.reset();
|
self.0.reset();
|
||||||
|
|
||||||
out
|
out
|
||||||
@@ -132,17 +129,123 @@ impl Hasher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Hasher {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "wasm")]
|
||||||
|
mod wasm {
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn hash(value: &[u8]) -> Vec<u8> {
|
||||||
|
super::hash(value).to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen(js_name = "hashXof")]
|
||||||
|
pub fn hash_xof(data: &[u8], out_len: usize) -> Result<Vec<u8>, JsError> {
|
||||||
|
super::hash_xof(data, out_len).map_err(|e| JsError::new(&e.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen(js_name = "keyedHash")]
|
||||||
|
pub fn keyed_hash(data: &[u8], key: &[u8]) -> Result<Vec<u8>, JsError> {
|
||||||
|
super::keyed_hash(data, key)
|
||||||
|
.map(|h| h.to_vec())
|
||||||
|
.map_err(|e| JsError::new(&e.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen(js_name = "deriveKey")]
|
||||||
|
pub fn derive_key(context: &str, key_material: &[u8]) -> Vec<u8> {
|
||||||
|
super::derive_key(context, key_material).to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Incremental BLAKE3 hasher for streaming data.
|
||||||
|
///
|
||||||
|
/// ```js
|
||||||
|
/// const hasher = new Hasher();
|
||||||
|
/// hasher.update(chunk1);
|
||||||
|
/// hasher.update(chunk2);
|
||||||
|
/// const digest = hasher.finalize(); // 32 bytes
|
||||||
|
/// ```
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub struct Hasher(blake3::Hasher);
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
impl Hasher {
|
||||||
|
/// Create a new hasher for unkeyed hashing.
|
||||||
|
#[wasm_bindgen(constructor)]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Hasher(blake3::Hasher::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a keyed hasher (MAC mode). Key must be exactly 32 bytes.
|
||||||
|
/// Throws if the key length is wrong.
|
||||||
|
#[wasm_bindgen(js_name = "newKeyed")]
|
||||||
|
pub fn new_keyed(key: &[u8]) -> Result<Self, JsError> {
|
||||||
|
let key: &[u8; 32] = key
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| JsError::new("key must be exactly 32 bytes"))?;
|
||||||
|
|
||||||
|
Ok(Hasher(blake3::Hasher::new_keyed(key)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a hasher in derive-key mode.
|
||||||
|
/// Context should be a hardcoded, globally unique, application-specific string.
|
||||||
|
/// Feed key material via `update()`, then call `finalize()`.
|
||||||
|
#[wasm_bindgen(js_name = "newDeriveKey")]
|
||||||
|
pub fn new_derive_key(context: &str) -> Self {
|
||||||
|
Hasher(blake3::Hasher::new_derive_key(context))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Feed data into the hasher. Can be called multiple times for streaming.
|
||||||
|
pub fn update(&mut self, data: &[u8]) {
|
||||||
|
self.0.update(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the 32-byte hash digest. Non-destructive. Can be called multiple times.
|
||||||
|
pub fn finalize(&self) -> Vec<u8> {
|
||||||
|
self.0.finalize().as_bytes().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return `out_len` bytes of extended output (XOF mode). Non-destructive.
|
||||||
|
#[wasm_bindgen(js_name = "finalizeXof")]
|
||||||
|
pub fn finalize_xof(&self, out_len: usize) -> Result<Vec<u8>, JsError> {
|
||||||
|
let len = super::checked_xof_len(out_len).map_err(|e| JsError::new(&e.0))?;
|
||||||
|
let mut out = vec![0u8; len];
|
||||||
|
|
||||||
|
self.0.finalize_xof().fill(&mut out);
|
||||||
|
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finalize the hash and reset the hasher in one call.
|
||||||
|
/// Useful for hashing multiple inputs sequentially without creating new instances.
|
||||||
|
#[wasm_bindgen(js_name = "finalizeAndReset")]
|
||||||
|
pub fn finalize_and_reset(&mut self) -> Vec<u8> {
|
||||||
|
let out = self.0.finalize().as_bytes().to_vec();
|
||||||
|
|
||||||
|
self.0.reset();
|
||||||
|
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reset the hasher to its initial state. Preserves the mode (keyed/derive-key).
|
||||||
|
pub fn reset(&mut self) {
|
||||||
|
self.0.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_hash_deterministic() {
|
fn test_hash_deterministic() {
|
||||||
let a = hash(b"hello");
|
assert_eq!(hash(b"hello"), hash(b"hello"));
|
||||||
let b = hash(b"hello");
|
|
||||||
assert_eq!(a, b);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_hash_length() {
|
fn test_hash_length() {
|
||||||
assert_eq!(hash(b"hello").len(), 32);
|
assert_eq!(hash(b"hello").len(), 32);
|
||||||
@@ -160,6 +263,11 @@ mod tests {
|
|||||||
assert!(keyed_hash(b"hello", &key).is_ok());
|
assert!(keyed_hash(b"hello", &key).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_keyed_hash_bad_key() {
|
||||||
|
assert!(keyed_hash(b"hello", &[0u8; 16]).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_derive_key() {
|
fn test_derive_key() {
|
||||||
let a = derive_key("ctx", b"material");
|
let a = derive_key("ctx", b"material");
|
||||||
@@ -177,6 +285,7 @@ mod tests {
|
|||||||
let mut h = Hasher::new();
|
let mut h = Hasher::new();
|
||||||
h.update(b"hello");
|
h.update(b"hello");
|
||||||
h.update(b"world");
|
h.update(b"world");
|
||||||
|
|
||||||
assert_eq!(h.finalize(), oneshot);
|
assert_eq!(h.finalize(), oneshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,6 +294,7 @@ mod tests {
|
|||||||
let oneshot = derive_key("my-ctx", b"material");
|
let oneshot = derive_key("my-ctx", b"material");
|
||||||
let mut h = Hasher::new_derive_key("my-ctx");
|
let mut h = Hasher::new_derive_key("my-ctx");
|
||||||
h.update(b"material");
|
h.update(b"material");
|
||||||
|
|
||||||
assert_eq!(h.finalize(), oneshot);
|
assert_eq!(h.finalize(), oneshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,6 +319,7 @@ mod tests {
|
|||||||
let mut h = Hasher::new_keyed(&key).unwrap();
|
let mut h = Hasher::new_keyed(&key).unwrap();
|
||||||
h.update(b"hello ");
|
h.update(b"hello ");
|
||||||
h.update(b"world");
|
h.update(b"world");
|
||||||
|
|
||||||
assert_eq!(h.finalize(), oneshot);
|
assert_eq!(h.finalize(), oneshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,6 +328,7 @@ mod tests {
|
|||||||
let oneshot = hash_xof(b"hello", 64).unwrap();
|
let oneshot = hash_xof(b"hello", 64).unwrap();
|
||||||
let mut h = Hasher::new();
|
let mut h = Hasher::new();
|
||||||
h.update(b"hello");
|
h.update(b"hello");
|
||||||
|
|
||||||
assert_eq!(h.finalize_xof(64).unwrap(), oneshot);
|
assert_eq!(h.finalize_xof(64).unwrap(), oneshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,6 +337,7 @@ mod tests {
|
|||||||
// First 32 bytes of XOF output should equal the standard hash
|
// First 32 bytes of XOF output should equal the standard hash
|
||||||
let standard = hash(b"test data");
|
let standard = hash(b"test data");
|
||||||
let xof = hash_xof(b"test data", 64).unwrap();
|
let xof = hash_xof(b"test data", 64).unwrap();
|
||||||
|
|
||||||
assert_eq!(&xof[..32], standard.as_slice());
|
assert_eq!(&xof[..32], standard.as_slice());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,13 +347,30 @@ mod tests {
|
|||||||
h.update(b"junk");
|
h.update(b"junk");
|
||||||
h.reset();
|
h.reset();
|
||||||
h.update(b"hello");
|
h.update(b"hello");
|
||||||
|
|
||||||
assert_eq!(h.finalize(), hash(b"hello"));
|
assert_eq!(h.finalize(), hash(b"hello"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hasher_keyed_bad_key() {
|
||||||
|
assert!(Hasher::new_keyed(&[0u8; 10]).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hash_xof_zero_len() {
|
||||||
|
assert!(hash_xof(b"hello", 0).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hash_xof_over_max() {
|
||||||
|
assert!(hash_xof(b"hello", 65_537).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_hasher_keyed() {
|
fn test_hasher_keyed() {
|
||||||
let key = [1u8; 32];
|
let key = [1u8; 32];
|
||||||
let h = Hasher::new_keyed(&key).unwrap();
|
let h = Hasher::new_keyed(&key).unwrap();
|
||||||
|
|
||||||
assert_ne!(h.finalize(), hash(b"").as_slice());
|
assert_ne!(h.finalize(), hash(b"").as_slice());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,49 +384,58 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_vector_empty() {
|
fn test_vector_empty() {
|
||||||
let out = hash(&[]);
|
|
||||||
let expected =
|
let expected =
|
||||||
hex::decode("af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262")
|
hex::decode("af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(out, expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
assert_eq!(hash(&[]).as_slice(), expected.as_slice());
|
||||||
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_vector_1_byte() {
|
fn test_vector_1_byte() {
|
||||||
let input = test_input(1);
|
|
||||||
let out = hash(&input);
|
|
||||||
let expected =
|
let expected =
|
||||||
hex::decode("2d3adedff11b61f14c886e35afa036736dcd87a74d27b5c1510225d0f592e213")
|
hex::decode("2d3adedff11b61f14c886e35afa036736dcd87a74d27b5c1510225d0f592e213")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(out, expected);
|
|
||||||
|
assert_eq!(hash(&test_input(1)).as_slice(), expected.as_slice());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_vector_1025_bytes() {
|
fn test_vector_1025_bytes() {
|
||||||
let input = test_input(1025);
|
|
||||||
let out = hash(&input);
|
|
||||||
let expected =
|
let expected =
|
||||||
hex::decode("d00278ae47eb27b34faecf67b4fe263f82d5412916c1ffd97c8cb7fb814b8444")
|
hex::decode("d00278ae47eb27b34faecf67b4fe263f82d5412916c1ffd97c8cb7fb814b8444")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(out, expected);
|
|
||||||
|
assert_eq!(hash(&test_input(1025)).as_slice(), expected.as_slice());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_vector_keyed_empty() {
|
fn test_vector_keyed_empty() {
|
||||||
let key = b"whats the Elvish word for friend";
|
let key = b"whats the Elvish word for friend";
|
||||||
let out = keyed_hash(&[], key).unwrap();
|
|
||||||
let expected =
|
let expected =
|
||||||
hex::decode("92b2b75604ed3c761f9d6f62392c8a9227ad0ea3f09573e783f1498a4ed60d26")
|
hex::decode("92b2b75604ed3c761f9d6f62392c8a9227ad0ea3f09573e783f1498a4ed60d26")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(out, expected);
|
|
||||||
|
assert_eq!(
|
||||||
|
keyed_hash(&[], key).unwrap().as_slice(),
|
||||||
|
expected.as_slice()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(target_arch = "wasm32", test))]
|
#[cfg(all(target_arch = "wasm32", test))]
|
||||||
mod wasm_tests {
|
mod wasm_tests {
|
||||||
use super::*;
|
use super::wasm::*;
|
||||||
use wasm_bindgen_test::*;
|
use wasm_bindgen_test::*;
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn test_hash_roundtrip() {
|
||||||
|
let a = hash(b"hello");
|
||||||
|
let b = hash(b"hello");
|
||||||
|
|
||||||
|
assert_eq!(a, b);
|
||||||
|
assert_eq!(a.len(), 32);
|
||||||
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn test_keyed_hash_bad_key() {
|
fn test_keyed_hash_bad_key() {
|
||||||
assert!(keyed_hash(b"hello", &[0u8; 16]).is_err());
|
assert!(keyed_hash(b"hello", &[0u8; 16]).is_err());
|
||||||
|
|||||||
Reference in New Issue
Block a user