Skip to content

Commit

Permalink
feat: update as-sha256 hasher to use async init
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewkeil committed Jan 5, 2025
1 parent a46a48b commit 62a9576
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 19 deletions.
54 changes: 37 additions & 17 deletions packages/persistent-merkle-tree/src/hasher/as-sha256.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
import {
digest2Bytes32,
digest64HashObjectsInto,
digest64HashObjects,
batchHash4HashObjectInputs,
hashInto,
} from "@chainsafe/as-sha256";
import {HashObject, AssemblyScriptSha256Hasher} from "@chainsafe/as-sha256";
import type {Hasher} from "./types.js";
import {Node} from "../node.js";
import type {HashComputationLevel} from "../hashComputation.js";
import {BLOCK_SIZE, doDigestNLevel, doMerkleizeBlockArray, doMerkleizeBlocksBytes} from "./util.js";

let sha256: undefined | AssemblyScriptSha256Hasher;
/**
* hashInto() function of as-sha256 loop through every 256 bytes
* This is the same to hashInto() function of as-sha256 https://github.com/ChainSafe/ssz/blob/cf3e1f038c8bf7cba1bb27c38540e50b0391d0e6/packages/as-sha256/src/index.ts#L270
Expand All @@ -18,18 +13,43 @@ const buffer = new Uint8Array(4 * BLOCK_SIZE);

export const hasher: Hasher = {
name: "as-sha256",
digest64: digest2Bytes32,
digest64HashObjects: digest64HashObjectsInto,
async initialize() {
sha256 = await AssemblyScriptSha256Hasher.initialize();
},
digest64(a32Bytes: Uint8Array, b32Bytes: Uint8Array): Uint8Array {
if (!sha256) {
throw new Error("Must initialize AssemblyScriptSha256Hasher before use");
}
return sha256.digest2Bytes32(a32Bytes, b32Bytes);
},
digest64HashObjects(left: HashObject, right: HashObject, parent: HashObject): void {
if (!sha256) {
throw new Error("Must initialize AssemblyScriptSha256Hasher before use");
}
return sha256.digest64HashObjectsInto(left, right, parent);
},
merkleizeBlocksBytes(blocksBytes: Uint8Array, padFor: number, output: Uint8Array, offset: number): void {
return doMerkleizeBlocksBytes(blocksBytes, padFor, output, offset, hashInto);
if (!sha256) {
throw new Error("Must initialize AssemblyScriptSha256Hasher before use");
}
return doMerkleizeBlocksBytes(blocksBytes, padFor, output, offset, sha256.hashInto.bind(sha256));
},
merkleizeBlockArray(blocks, blockLimit, padFor, output, offset) {
return doMerkleizeBlockArray(blocks, blockLimit, padFor, output, offset, hashInto, buffer);
if (!sha256) {
throw new Error("Must initialize AssemblyScriptSha256Hasher before use");
}
return doMerkleizeBlockArray(blocks, blockLimit, padFor, output, offset, sha256.hashInto.bind(sha256), buffer);
},
digestNLevel(data: Uint8Array, nLevel: number): Uint8Array {
return doDigestNLevel(data, nLevel, hashInto);
if (!sha256) {
throw new Error("Must initialize AssemblyScriptSha256Hasher before use");
}
return doDigestNLevel(data, nLevel, sha256.hashInto.bind(sha256));
},
executeHashComputations: (hashComputations: HashComputationLevel[]) => {
if (!sha256) {
throw new Error("Must initialize AssemblyScriptSha256Hasher before use");
}
for (let level = hashComputations.length - 1; level >= 0; level--) {
const hcArr = hashComputations[level];
if (!hcArr) {
Expand Down Expand Up @@ -96,7 +116,7 @@ export const hasher: Hasher = {
dest3 !== null
) {
// TODO - batch: find a way not allocate here
const [o0, o1, o2, o3] = batchHash4HashObjectInputs([
const [o0, o1, o2, o3] = sha256.batchHash4HashObjectInputs([
src0_0,
src1_0,
src0_1,
Expand Down Expand Up @@ -137,16 +157,16 @@ export const hasher: Hasher = {

// remaining
if (src0_0 !== null && src1_0 !== null && dest0 !== null) {
dest0.applyHash(digest64HashObjects(src0_0, src1_0));
dest0.applyHash(sha256.digest64HashObjects(src0_0, src1_0));
}
if (src0_1 !== null && src1_1 !== null && dest1 !== null) {
dest1.applyHash(digest64HashObjects(src0_1, src1_1));
dest1.applyHash(sha256.digest64HashObjects(src0_1, src1_1));
}
if (src0_2 !== null && src1_2 !== null && dest2 !== null) {
dest2.applyHash(digest64HashObjects(src0_2, src1_2));
dest2.applyHash(sha256.digest64HashObjects(src0_2, src1_2));
}
if (src0_3 !== null && src1_3 !== null && dest3 !== null) {
dest3.applyHash(digest64HashObjects(src0_3, src1_3));
dest3.applyHash(sha256.digest64HashObjects(src0_3, src1_3));
}
}
},
Expand Down
5 changes: 4 additions & 1 deletion packages/persistent-merkle-tree/src/hasher/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ export let hasher: Hasher = nobleHasher;
*
* WARNING: This function is intended for power users and must be executed before any other SSZ code is imported
*/
export function setHasher(newHasher: Hasher): void {
export async function setHasher(newHasher: Hasher): Promise<void> {
if (typeof newHasher.initialize === "function") {
await newHasher.initialize();
}
hasher = newHasher;
}

Expand Down
2 changes: 2 additions & 0 deletions packages/persistent-merkle-tree/src/hasher/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export type {HashObject};
export type Hasher = {
// name of the hashing library
name: string;
// as-sha256 has an async initialization. must run this to detect correct bindings
initialize?: () => Promise<void>;
/**
* Hash two 32-byte Uint8Arrays
*/
Expand Down
2 changes: 1 addition & 1 deletion setHasher.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
// Used to run benchmarks with with visibility into hashtree performance, useful for Lodestar
import {setHasher} from "@chainsafe/persistent-merkle-tree/lib/hasher/index.js";
import {hasher} from "@chainsafe/persistent-merkle-tree/lib/hasher/hashtree.js";
setHasher(hasher);
await setHasher(hasher);

export {};

0 comments on commit 62a9576

Please sign in to comment.