mirror of
https://github.com/UneBaguette/blake3.wasm.git
synced 2026-08-21 00:00:15 +02:00
feat: add new_derive_key, finalize_and_reset, doc comments, official test vectors, Makefile
This commit is contained in:
@@ -25,7 +25,7 @@ jobs:
|
|||||||
run: wasm-pack test --node
|
run: wasm-pack test --node
|
||||||
|
|
||||||
- name: Build package
|
- name: Build package
|
||||||
run: bash build.sh
|
run: make
|
||||||
|
|
||||||
- name: Publish to npm
|
- name: Publish to npm
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
Generated
+8
-1
@@ -47,9 +47,10 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "blake3-wasm-rs"
|
name = "blake3-wasm-rs"
|
||||||
version = "0.1.2"
|
version = "0.1.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"blake3",
|
"blake3",
|
||||||
|
"hex",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-test",
|
"wasm-bindgen-test",
|
||||||
]
|
]
|
||||||
@@ -127,6 +128,12 @@ dependencies = [
|
|||||||
"slab",
|
"slab",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.18"
|
version = "1.0.18"
|
||||||
|
|||||||
+2
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "blake3-wasm-rs"
|
name = "blake3-wasm-rs"
|
||||||
version = "0.1.2"
|
version = "0.1.3"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["UneBaguette <[email protected]>"]
|
authors = ["UneBaguette <[email protected]>"]
|
||||||
@@ -19,3 +19,4 @@ wasm-bindgen = "0.2"
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
wasm-bindgen-test = "0.3"
|
wasm-bindgen-test = "0.3"
|
||||||
|
hex = "0.4"
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
ROOT := pkg
|
||||||
|
CRATE := blake3_wasm_rs
|
||||||
|
VERSION := 0.3.0
|
||||||
|
|
||||||
|
.PHONY: all clean build bundler node web node-esm package verify
|
||||||
|
|
||||||
|
all: clean build package
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(ROOT)
|
||||||
|
|
||||||
|
build: bundler node web node-esm
|
||||||
|
|
||||||
|
bundler:
|
||||||
|
@echo "Building bundler target..."
|
||||||
|
wasm-pack build --target bundler -d $(ROOT)/bundler
|
||||||
|
|
||||||
|
node:
|
||||||
|
@echo "Building nodejs target..."
|
||||||
|
wasm-pack build --target nodejs -d $(ROOT)/node
|
||||||
|
|
||||||
|
web:
|
||||||
|
@echo "Building web target..."
|
||||||
|
wasm-pack build --target web -d $(ROOT)/web
|
||||||
|
|
||||||
|
node-esm: node
|
||||||
|
@echo "Generating node-esm wrapper..."
|
||||||
|
@mkdir -p $(ROOT)/node-esm
|
||||||
|
@node -e "\
|
||||||
|
const fs = require('fs'); \
|
||||||
|
const dts = fs.readFileSync('$(ROOT)/node/$(CRATE).d.ts', 'utf8'); \
|
||||||
|
const fns = [...dts.matchAll(/export function (\w+)/g)].map(m => m[1]); \
|
||||||
|
const cls = [...dts.matchAll(/export class (\w+)/g)].map(m => m[1]); \
|
||||||
|
const lines = [ \
|
||||||
|
\"import { createRequire } from 'module';\", \
|
||||||
|
\"const require = createRequire(import.meta.url);\", \
|
||||||
|
\"const mod = require('../node/$(CRATE).js');\", \
|
||||||
|
\"export default mod;\", \
|
||||||
|
...fns.map(n => 'export const ' + n + ' = mod.' + n + ';'), \
|
||||||
|
...cls.map(n => 'export const ' + n + ' = mod.' + n + ';'), \
|
||||||
|
]; \
|
||||||
|
fs.writeFileSync('$(ROOT)/node-esm/index.mjs', lines.join('\n') + '\n'); \
|
||||||
|
"
|
||||||
|
|
||||||
|
|
||||||
|
package: build
|
||||||
|
@cp README.md $(ROOT)/README.md
|
||||||
|
@rm -f $(ROOT)/bundler/package.json $(ROOT)/node/package.json $(ROOT)/web/package.json
|
||||||
|
@rm -f $(ROOT)/bundler/.gitignore $(ROOT)/node/.gitignore $(ROOT)/web/.gitignore
|
||||||
|
@node -e "\
|
||||||
|
const pkg = { \
|
||||||
|
name: 'blake3-wasm-rs', \
|
||||||
|
version: '$(VERSION)', \
|
||||||
|
description: 'BLAKE3 hashing via Rust/WASM - works in Node.js (CJS + ESM), browsers, and bundlers', \
|
||||||
|
license: 'MIT', \
|
||||||
|
repository: { \
|
||||||
|
type: 'git', \
|
||||||
|
url: 'https://github.com/UneBaguette/blake3.wasm', \
|
||||||
|
}, \
|
||||||
|
exports: { \
|
||||||
|
'.': { \
|
||||||
|
node: { \
|
||||||
|
require: './node/$(CRATE).js', \
|
||||||
|
import: './node-esm/index.mjs', \
|
||||||
|
}, \
|
||||||
|
import: './bundler/$(CRATE).js', \
|
||||||
|
default: './web/$(CRATE).js', \
|
||||||
|
}, \
|
||||||
|
}, \
|
||||||
|
types: './bundler/$(CRATE).d.ts', \
|
||||||
|
files: ['node/', 'node-esm/', 'bundler/', 'web/', 'README.md'], \
|
||||||
|
keywords: ['blake3', 'wasm', 'hash', 'cryptography', 'wasm-bindgen'], \
|
||||||
|
}; \
|
||||||
|
require('fs').writeFileSync('$(ROOT)/package.json', JSON.stringify(pkg, null, 2) + '\n'); \
|
||||||
|
"
|
||||||
|
@echo ""
|
||||||
|
@echo "Done! Package ready in $(ROOT)/"
|
||||||
|
@echo " node (CJS): $(ROOT)/node/"
|
||||||
|
@echo " node (ESM): $(ROOT)/node-esm/"
|
||||||
|
@echo " bundler: $(ROOT)/bundler/"
|
||||||
|
@echo " web: $(ROOT)/web/"
|
||||||
|
|
||||||
|
verify: package
|
||||||
|
cd $(ROOT) && npm pack --dry-run
|
||||||
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
ROOT="pkg"
|
|
||||||
rm -rf "$ROOT"
|
|
||||||
|
|
||||||
echo "Building bundler target..."
|
|
||||||
wasm-pack build --target bundler -d "$ROOT/bundler"
|
|
||||||
|
|
||||||
echo "Building nodejs target..."
|
|
||||||
wasm-pack build --target nodejs -d "$ROOT/node"
|
|
||||||
|
|
||||||
echo "Building web target..."
|
|
||||||
wasm-pack build --target web -d "$ROOT/web"
|
|
||||||
|
|
||||||
# Generate node-esm wrapper from the nodejs build exports
|
|
||||||
echo "Generating node-esm wrapper..."
|
|
||||||
mkdir -p "$ROOT/node-esm"
|
|
||||||
|
|
||||||
cp README.md "$ROOT/README.md"
|
|
||||||
|
|
||||||
# Extract export names from the nodejs .js file
|
|
||||||
EXPORTS=$(grep -oP '(?<=module\.exports\.)\w+' "$ROOT/node/blake3_wasm_rs.js" | sort -u || true)
|
|
||||||
|
|
||||||
# Fallback: parse from .d.ts if module.exports pattern not found
|
|
||||||
if [ -z "$EXPORTS" ]; then
|
|
||||||
EXPORTS=$(grep -oP '(?<=export function )\w+' "$ROOT/node/blake3_wasm_rs.d.ts" | sort -u || true)
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Also check for exported classes
|
|
||||||
CLASSES=$(grep -oP '(?<=export class )\w+' "$ROOT/node/blake3_wasm_rs.d.ts" | sort -u || true)
|
|
||||||
|
|
||||||
{
|
|
||||||
echo "import { createRequire } from 'module';"
|
|
||||||
echo "const require = createRequire(import.meta.url);"
|
|
||||||
echo "const mod = require('../node/blake3_wasm_rs.js');"
|
|
||||||
echo "export default mod;"
|
|
||||||
|
|
||||||
for name in $EXPORTS; do
|
|
||||||
echo "export const $name = mod.$name;"
|
|
||||||
done
|
|
||||||
|
|
||||||
for name in $CLASSES; do
|
|
||||||
echo "export const $name = mod.$name;"
|
|
||||||
done
|
|
||||||
} > "$ROOT/node-esm/index.mjs"
|
|
||||||
|
|
||||||
# Clean up wasm-pack generated package.json in each subfolder
|
|
||||||
rm -f "$ROOT/bundler/package.json" "$ROOT/node/package.json" "$ROOT/web/package.json"
|
|
||||||
rm -f "$ROOT/bundler/.gitignore" "$ROOT/node/.gitignore" "$ROOT/web/.gitignore"
|
|
||||||
|
|
||||||
# Generate root package.json
|
|
||||||
cat > "$ROOT/package.json" << 'EOF'
|
|
||||||
{
|
|
||||||
"name": "blake3-wasm-rs",
|
|
||||||
"version": "0.2.2",
|
|
||||||
"description": "BLAKE3 hashing via Rust/WASM - works in Node.js (CJS + ESM), browsers, and bundlers",
|
|
||||||
"license": "MIT",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/UneBaguette/blake3.wasm"
|
|
||||||
},
|
|
||||||
"exports": {
|
|
||||||
".": {
|
|
||||||
"node": {
|
|
||||||
"require": "./node/blake3_wasm_rs.js",
|
|
||||||
"import": "./node-esm/index.mjs"
|
|
||||||
},
|
|
||||||
"import": "./bundler/blake3_wasm_rs.js",
|
|
||||||
"default": "./web/blake3_wasm_rs.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"types": "./bundler/blake3_wasm_rs.d.ts",
|
|
||||||
"files": [
|
|
||||||
"node/",
|
|
||||||
"node-esm/",
|
|
||||||
"bundler/",
|
|
||||||
"web/",
|
|
||||||
"README.md"
|
|
||||||
],
|
|
||||||
"keywords": [
|
|
||||||
"blake3",
|
|
||||||
"wasm",
|
|
||||||
"hash",
|
|
||||||
"cryptography",
|
|
||||||
"wasm-bindgen"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "Done! Package ready in $ROOT/"
|
|
||||||
echo " node (CJS): $ROOT/node/"
|
|
||||||
echo " node (ESM): $ROOT/node-esm/"
|
|
||||||
echo " bundler: $ROOT/bundler/"
|
|
||||||
echo " web: $ROOT/web/"
|
|
||||||
echo ""
|
|
||||||
echo "Verify with: cd $ROOT && npm pack --dry-run"
|
|
||||||
+136
@@ -1,10 +1,13 @@
|
|||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
/// Hash data and return a 32-byte BLAKE3 digest.
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn hash(value: &[u8]) -> Vec<u8> {
|
pub fn hash(value: &[u8]) -> Vec<u8> {
|
||||||
blake3::hash(value).as_bytes().to_vec()
|
blake3::hash(value).as_bytes().to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Hash data with variable-length output (XOF mode).
|
||||||
|
/// Returns `out_len` bytes of BLAKE3 extended output.
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn hash_xof(data: &[u8], out_len: usize) -> Vec<u8> {
|
pub fn hash_xof(data: &[u8], out_len: usize) -> Vec<u8> {
|
||||||
let mut out = vec![0u8; out_len];
|
let mut out = vec![0u8; out_len];
|
||||||
@@ -15,50 +18,88 @@ pub fn hash_xof(data: &[u8], out_len: usize) -> Vec<u8> {
|
|||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compute a keyed BLAKE3 hash (MAC). Key must be exactly 32 bytes.
|
||||||
|
/// Throws if the key length is wrong.
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn keyed_hash(data: &[u8], key: &[u8]) -> Result<Vec<u8>, JsError> {
|
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(|_| JsError::new("key must be exactly 32 bytes"))?;
|
||||||
|
|
||||||
Ok(blake3::keyed_hash(key, data).as_bytes().to_vec())
|
Ok(blake3::keyed_hash(key, data).as_bytes().to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Derive a 32-byte key from a context string and key material.
|
||||||
|
/// Context should be a hardcoded, globally unique, application-specific string.
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn derive_key(context: &str, key_material: &[u8]) -> Vec<u8> {
|
pub fn derive_key(context: &str, key_material: &[u8]) -> Vec<u8> {
|
||||||
blake3::derive_key(context, key_material).to_vec()
|
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]
|
#[wasm_bindgen]
|
||||||
pub struct Hasher(blake3::Hasher);
|
pub struct Hasher(blake3::Hasher);
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
impl Hasher {
|
impl Hasher {
|
||||||
|
/// Create a new hasher for unkeyed hashing.
|
||||||
#[wasm_bindgen(constructor)]
|
#[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.
|
||||||
|
/// Throws if the key length is wrong.
|
||||||
pub fn new_keyed(key: &[u8]) -> Result<Hasher, JsError> {
|
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(|_| JsError::new("key must be exactly 32 bytes"))?;
|
||||||
|
|
||||||
Ok(Hasher(blake3::Hasher::new_keyed(key)))
|
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()`.
|
||||||
|
pub fn new_derive_key(context: &str) -> Hasher {
|
||||||
|
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]) {
|
pub fn update(&mut self, data: &[u8]) {
|
||||||
self.0.update(data);
|
self.0.update(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the 32-byte hash digest. Non-destructive. Can be called multiple times.
|
||||||
pub fn finalize(&self) -> Vec<u8> {
|
pub fn finalize(&self) -> Vec<u8> {
|
||||||
self.0.finalize().as_bytes().to_vec()
|
self.0.finalize().as_bytes().to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return `out_len` bytes of extended output (XOF mode). Non-destructive.
|
||||||
pub fn finalize_xof(&self, out_len: usize) -> Vec<u8> {
|
pub fn finalize_xof(&self, out_len: usize) -> Vec<u8> {
|
||||||
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);
|
||||||
|
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Finalize the hash and reset the hasher in one call.
|
||||||
|
/// Useful for hashing multiple inputs sequentially without creating new instances.
|
||||||
|
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) {
|
pub fn reset(&mut self) {
|
||||||
self.0.reset();
|
self.0.reset();
|
||||||
}
|
}
|
||||||
@@ -112,6 +153,54 @@ mod tests {
|
|||||||
assert_eq!(h.finalize(), oneshot);
|
assert_eq!(h.finalize(), oneshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hasher_derive_key() {
|
||||||
|
let oneshot = derive_key("my-ctx", b"material");
|
||||||
|
let mut h = Hasher::new_derive_key("my-ctx");
|
||||||
|
h.update(b"material");
|
||||||
|
assert_eq!(h.finalize(), oneshot);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hasher_finalize_and_reset() {
|
||||||
|
let mut h = Hasher::new();
|
||||||
|
h.update(b"hello");
|
||||||
|
let first = h.finalize_and_reset();
|
||||||
|
assert_eq!(first, hash(b"hello"));
|
||||||
|
|
||||||
|
// After reset, hashing different data should produce different output
|
||||||
|
h.update(b"world");
|
||||||
|
let second = h.finalize();
|
||||||
|
assert_eq!(second, hash(b"world"));
|
||||||
|
assert_ne!(first, second);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_keyed_hash_matches_streaming() {
|
||||||
|
let key = [42u8; 32];
|
||||||
|
let oneshot = keyed_hash(b"hello world", &key).unwrap();
|
||||||
|
let mut h = Hasher::new_keyed(&key).unwrap();
|
||||||
|
h.update(b"hello ");
|
||||||
|
h.update(b"world");
|
||||||
|
assert_eq!(h.finalize(), oneshot);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hasher_finalize_xof() {
|
||||||
|
let oneshot = hash_xof(b"hello", 64);
|
||||||
|
let mut h = Hasher::new();
|
||||||
|
h.update(b"hello");
|
||||||
|
assert_eq!(h.finalize_xof(64), oneshot);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hasher_finalize_xof_prefix_matches_hash() {
|
||||||
|
// First 32 bytes of XOF output should equal the standard hash
|
||||||
|
let standard = hash(b"test data");
|
||||||
|
let xof = hash_xof(b"test data", 64);
|
||||||
|
assert_eq!(&xof[..32], standard.as_slice());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_hasher_reset() {
|
fn test_hasher_reset() {
|
||||||
let mut h = Hasher::new();
|
let mut h = Hasher::new();
|
||||||
@@ -127,6 +216,53 @@ mod tests {
|
|||||||
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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BLAKE3 official test vectors (from BLAKE3 spec)
|
||||||
|
// Reference: https://github.com/BLAKE3-team/BLAKE3/blob/master/test_vectors/test_vectors.json
|
||||||
|
// Input: 0x00..0xfa repeating pattern, first N bytes
|
||||||
|
|
||||||
|
fn test_input(len: usize) -> Vec<u8> {
|
||||||
|
(0..len).map(|i| (i % 251) as u8).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_vector_empty() {
|
||||||
|
let out = hash(&[]);
|
||||||
|
let expected =
|
||||||
|
hex::decode("af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262")
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(out, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_vector_1_byte() {
|
||||||
|
let input = test_input(1);
|
||||||
|
let out = hash(&input);
|
||||||
|
let expected =
|
||||||
|
hex::decode("2d3adedff11b61f14c886e35afa036736dcd87a74d27b5c1510225d0f592e213")
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(out, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_vector_1025_bytes() {
|
||||||
|
let input = test_input(1025);
|
||||||
|
let out = hash(&input);
|
||||||
|
let expected =
|
||||||
|
hex::decode("d00278ae47eb27b34faecf67b4fe263f82d5412916c1ffd97c8cb7fb814b8444")
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(out, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_vector_keyed_empty() {
|
||||||
|
let key = b"whats the Elvish word for friend";
|
||||||
|
let out = keyed_hash(&[], key).unwrap();
|
||||||
|
let expected =
|
||||||
|
hex::decode("92b2b75604ed3c761f9d6f62392c8a9227ad0ea3f09573e783f1498a4ed60d26")
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(out, expected);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(target_arch = "wasm32", test))]
|
#[cfg(all(target_arch = "wasm32", test))]
|
||||||
|
|||||||
Reference in New Issue
Block a user