Skip to content

Commit

Permalink
feat: use hash cache
Browse files Browse the repository at this point in the history
  • Loading branch information
wemeetagain committed Feb 19, 2024
1 parent 6220d32 commit 844e12b
Show file tree
Hide file tree
Showing 15 changed files with 956 additions and 271 deletions.
243 changes: 243 additions & 0 deletions packages/as-sha256/src/hashCache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
import { HashObject } from "./hashObject";

export const HASH_SIZE = 32;
export const CACHE_HASH_SIZE = 32768;
export const CACHE_BYTE_SIZE = CACHE_HASH_SIZE * HASH_SIZE;

export type HashCache = {
cache: Uint8Array;
used: Set<number>;
next: number;
};

/**
* A unique identifier for a hash in a cache.
*
*
* The `cacheIndex` is the index of the cache in the `hashCaches` array.
* The `hashIndex` is the index of the hash in the cache.
*/
export type HashId = number;

function toHashId(cacheIndex: number, hashIndex: number): HashId {
return (cacheIndex << 16) | hashIndex;
}

function fromHashId(id: HashId): [number, number] {
return [id >> 16, id & 0xffff];
}

function getCacheIndex(id: HashId): number {
return id >> 16;
}

function getHashIndex(id: HashId): number {
return id & 0xffff;
}

const hashCaches: HashCache[] = [];

export function allocHashCache(): HashCache {
const cache = new Uint8Array(CACHE_BYTE_SIZE);
const used = new Set<number>();
const next = 0;
const out = {cache, used, next};
hashCaches.push(out);
return out;
}

export function getHash(id: HashId): Uint8Array {
const [cacheIndex, hashIndex] = fromHashId(id);
const cache = hashCaches[cacheIndex];
const offset = hashIndex * HASH_SIZE;
return cache.cache.subarray(offset, offset + HASH_SIZE);
}

export function getCache(id: HashId): HashCache {
return hashCaches[getCacheIndex(id)];
}

export function getCacheOffset(id: HashId): number {
return getHashIndex(id) * HASH_SIZE;
}

export function incrementNext(cache: HashCache): number {
const out = cache.next;
cache.used.add(out);
// eslint-disable-next-line no-empty
while (cache.used.has(cache.next++)) {}
return out;
}

export function newHashId(cacheIndex: number, cache: HashCache): HashId {
const hashIndex = incrementNext(cache);
return toHashId(cacheIndex, hashIndex);
}

export function allocHashId(): HashId {
const cachesLength = hashCaches.length;
for (let i = 0; i < cachesLength; i++) {
const cache = hashCaches[i];
if (cache.next < CACHE_HASH_SIZE) {
return newHashId(i, cache);
}
}
const cache = allocHashCache();
return newHashId(cachesLength, cache);
}

export function freeHashId(id: HashId): void {
const [cacheIndex, hashIndex] = fromHashId(id);
hashCaches[cacheIndex].used.delete(hashIndex);
if (hashCaches[cacheIndex].next > hashIndex) {
hashCaches[cacheIndex].next = hashIndex;
}
}

export function cloneHashId(source: HashId, target: HashId): void {
const {cache: cacheSource} = getCache(source);
let offsetSource = getCacheOffset(source);
const {cache: cacheTarget} = getCache(target);
let offsetTarget = getCacheOffset(target);

cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
cacheTarget[offsetTarget++] = cacheSource[offsetSource++];
}

export function getHashObject(id: HashId): HashObject {
const {cache} = getCache(id);
let offset = getCacheOffset(id);

return {
h0: cache[offset++] + (cache[offset++] << 8) + (cache[offset++] << 16) + (cache[offset++] << 24),
h1: cache[offset++] + (cache[offset++] << 8) + (cache[offset++] << 16) + (cache[offset++] << 24),
h2: cache[offset++] + (cache[offset++] << 8) + (cache[offset++] << 16) + (cache[offset++] << 24),
h3: cache[offset++] + (cache[offset++] << 8) + (cache[offset++] << 16) + (cache[offset++] << 24),
h4: cache[offset++] + (cache[offset++] << 8) + (cache[offset++] << 16) + (cache[offset++] << 24),
h5: cache[offset++] + (cache[offset++] << 8) + (cache[offset++] << 16) + (cache[offset++] << 24),
h6: cache[offset++] + (cache[offset++] << 8) + (cache[offset++] << 16) + (cache[offset++] << 24),
h7: cache[offset++] + (cache[offset++] << 8) + (cache[offset++] << 16) + (cache[offset++] << 24),
};
}

export function setHashObject(id: HashId, obj: HashObject): void {
const {cache} = getCache(id);
let offset = getCacheOffset(id);

cache[offset++] = obj.h0 & 0xff;
cache[offset++] = (obj.h0 >> 8) & 0xff;
cache[offset++] = (obj.h0 >> 16) & 0xff;
cache[offset++] = (obj.h0 >> 24) & 0xff;
cache[offset++] = obj.h1 & 0xff;
cache[offset++] = (obj.h1 >> 8) & 0xff;
cache[offset++] = (obj.h1 >> 16) & 0xff;
cache[offset++] = (obj.h1 >> 24) & 0xff;
cache[offset++] = obj.h2 & 0xff;
cache[offset++] = (obj.h2 >> 8) & 0xff;
cache[offset++] = (obj.h2 >> 16) & 0xff;
cache[offset++] = (obj.h2 >> 24) & 0xff;
cache[offset++] = obj.h3 & 0xff;
cache[offset++] = (obj.h3 >> 8) & 0xff;
cache[offset++] = (obj.h3 >> 16) & 0xff;
cache[offset++] = (obj.h3 >> 24) & 0xff;
cache[offset++] = obj.h4 & 0xff;
cache[offset++] = (obj.h4 >> 8) & 0xff;
cache[offset++] = (obj.h4 >> 16) & 0xff;
cache[offset++] = (obj.h4 >> 24) & 0xff;
cache[offset++] = obj.h5 & 0xff;
cache[offset++] = (obj.h5 >> 8) & 0xff;
cache[offset++] = (obj.h5 >> 16) & 0xff;
cache[offset++] = (obj.h5 >> 24) & 0xff;
cache[offset++] = obj.h6 & 0xff;
cache[offset++] = (obj.h6 >> 8) & 0xff;
cache[offset++] = (obj.h6 >> 16) & 0xff;
cache[offset++] = (obj.h6 >> 24) & 0xff;
cache[offset++] = obj.h7 & 0xff;
cache[offset++] = (obj.h7 >> 8) & 0xff;
cache[offset++] = (obj.h7 >> 16) & 0xff;
cache[offset++] = (obj.h7 >> 24) & 0xff;
}

export function setHashObjectItems(
id: HashId,
h0: number,
h1: number,
h2: number,
h3: number,
h4: number,
h5: number,
h6: number,
h7: number
): void {
const {cache} = getCache(id);
let offset = getCacheOffset(id);

cache[offset++] = h0 & 0xff;
cache[offset++] = (h0 >> 8) & 0xff;
cache[offset++] = (h0 >> 16) & 0xff;
cache[offset++] = (h0 >> 24) & 0xff;
cache[offset++] = h1 & 0xff;
cache[offset++] = (h1 >> 8) & 0xff;
cache[offset++] = (h1 >> 16) & 0xff;
cache[offset++] = (h1 >> 24) & 0xff;
cache[offset++] = h2 & 0xff;
cache[offset++] = (h2 >> 8) & 0xff;
cache[offset++] = (h2 >> 16) & 0xff;
cache[offset++] = (h2 >> 24) & 0xff;
cache[offset++] = h3 & 0xff;
cache[offset++] = (h3 >> 8) & 0xff;
cache[offset++] = (h3 >> 16) & 0xff;
cache[offset++] = (h3 >> 24) & 0xff;
cache[offset++] = h4 & 0xff;
cache[offset++] = (h4 >> 8) & 0xff;
cache[offset++] = (h4 >> 16) & 0xff;
cache[offset++] = (h4 >> 24) & 0xff;
cache[offset++] = h5 & 0xff;
cache[offset++] = (h5 >> 8) & 0xff;
cache[offset++] = (h5 >> 16) & 0xff;
cache[offset++] = (h5 >> 24) & 0xff;
cache[offset++] = h6 & 0xff;
cache[offset++] = (h6 >> 8) & 0xff;
cache[offset++] = (h6 >> 16) & 0xff;
cache[offset++] = (h6 >> 24) & 0xff;
cache[offset++] = h7 & 0xff;
cache[offset++] = (h7 >> 8) & 0xff;
cache[offset++] = (h7 >> 16) & 0xff;
cache[offset++] = (h7 >> 24) & 0xff;
}

export function setHash(id: HashId, hash: Uint8Array): void {
const {cache} = getCache(id);
const offset = getCacheOffset(id);
cache.set(hash, offset);
}
123 changes: 123 additions & 0 deletions packages/as-sha256/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import {newInstance} from "./wasm";
import {HashObject, byteArrayToHashObject, hashObjectToByteArray} from "./hashObject";
import SHA256 from "./sha256";
import { HashId, getCache, getCacheOffset } from "./hashCache";
export * from "./hashCache";

export {HashObject, byteArrayToHashObject, hashObjectToByteArray, SHA256};

const ctx = newInstance();
Expand Down Expand Up @@ -82,6 +85,126 @@ export function digest64HashObjects(obj1: HashObject, obj2: HashObject): HashObj
return byteArrayToHashObject(outputUint8Array);
}

/**
*
*/
export function digest64HashIds(id1: HashId, id2: HashId, out: HashId): void {
const {cache: cache1} = getCache(id1);
let offset1 = getCacheOffset(id1);
const {cache: cache2} = getCache(id2);
let offset2 = getCacheOffset(id2);

// inputUint8Array.set(cache1.subarray(offset1, offset1 + HASH_SIZE));
// inputUint8Array.set(cache2.subarray(offset2, offset2 + HASH_SIZE), HASH_SIZE);
// instead of using inputUint8Array.set, we set each byte individually, without a for loop

inputUint8Array[0] = cache1[offset1++];
inputUint8Array[1] = cache1[offset1++];
inputUint8Array[2] = cache1[offset1++];
inputUint8Array[3] = cache1[offset1++];
inputUint8Array[4] = cache1[offset1++];
inputUint8Array[5] = cache1[offset1++];
inputUint8Array[6] = cache1[offset1++];
inputUint8Array[7] = cache1[offset1++];
inputUint8Array[8] = cache1[offset1++];
inputUint8Array[9] = cache1[offset1++];
inputUint8Array[10] = cache1[offset1++];
inputUint8Array[11] = cache1[offset1++];
inputUint8Array[12] = cache1[offset1++];
inputUint8Array[13] = cache1[offset1++];
inputUint8Array[14] = cache1[offset1++];
inputUint8Array[15] = cache1[offset1++];
inputUint8Array[16] = cache1[offset1++];
inputUint8Array[17] = cache1[offset1++];
inputUint8Array[18] = cache1[offset1++];
inputUint8Array[19] = cache1[offset1++];
inputUint8Array[20] = cache1[offset1++];
inputUint8Array[21] = cache1[offset1++];
inputUint8Array[22] = cache1[offset1++];
inputUint8Array[23] = cache1[offset1++];
inputUint8Array[24] = cache1[offset1++];
inputUint8Array[25] = cache1[offset1++];
inputUint8Array[26] = cache1[offset1++];
inputUint8Array[27] = cache1[offset1++];
inputUint8Array[28] = cache1[offset1++];
inputUint8Array[29] = cache1[offset1++];
inputUint8Array[30] = cache1[offset1++];
inputUint8Array[31] = cache1[offset1++];
inputUint8Array[32] = cache2[offset2++];
inputUint8Array[33] = cache2[offset2++];
inputUint8Array[34] = cache2[offset2++];
inputUint8Array[35] = cache2[offset2++];
inputUint8Array[36] = cache2[offset2++];
inputUint8Array[37] = cache2[offset2++];
inputUint8Array[38] = cache2[offset2++];
inputUint8Array[39] = cache2[offset2++];
inputUint8Array[40] = cache2[offset2++];
inputUint8Array[41] = cache2[offset2++];
inputUint8Array[42] = cache2[offset2++];
inputUint8Array[43] = cache2[offset2++];
inputUint8Array[44] = cache2[offset2++];
inputUint8Array[45] = cache2[offset2++];
inputUint8Array[46] = cache2[offset2++];
inputUint8Array[47] = cache2[offset2++];
inputUint8Array[48] = cache2[offset2++];
inputUint8Array[49] = cache2[offset2++];
inputUint8Array[50] = cache2[offset2++];
inputUint8Array[51] = cache2[offset2++];
inputUint8Array[52] = cache2[offset2++];
inputUint8Array[53] = cache2[offset2++];
inputUint8Array[54] = cache2[offset2++];
inputUint8Array[55] = cache2[offset2++];
inputUint8Array[56] = cache2[offset2++];
inputUint8Array[57] = cache2[offset2++];
inputUint8Array[58] = cache2[offset2++];
inputUint8Array[59] = cache2[offset2++];
inputUint8Array[60] = cache2[offset2++];
inputUint8Array[61] = cache2[offset2++];
inputUint8Array[62] = cache2[offset2++];
inputUint8Array[63] = cache2[offset2++];

ctx.digest64(wasmInputValue, wasmOutputValue);

const {cache: outCache} = getCache(out);
const outOffset = getCacheOffset(out);

// outputCache.set(outputUint8Array, outputOffset);
// instead of using outputCache.set, we set each byte individually, without a for loop

outCache[outOffset] = outputUint8Array[0];
outCache[outOffset + 1] = outputUint8Array[1];
outCache[outOffset + 2] = outputUint8Array[2];
outCache[outOffset + 3] = outputUint8Array[3];
outCache[outOffset + 4] = outputUint8Array[4];
outCache[outOffset + 5] = outputUint8Array[5];
outCache[outOffset + 6] = outputUint8Array[6];
outCache[outOffset + 7] = outputUint8Array[7];
outCache[outOffset + 8] = outputUint8Array[8];
outCache[outOffset + 9] = outputUint8Array[9];
outCache[outOffset + 10] = outputUint8Array[10];
outCache[outOffset + 11] = outputUint8Array[11];
outCache[outOffset + 12] = outputUint8Array[12];
outCache[outOffset + 13] = outputUint8Array[13];
outCache[outOffset + 14] = outputUint8Array[14];
outCache[outOffset + 15] = outputUint8Array[15];
outCache[outOffset + 16] = outputUint8Array[16];
outCache[outOffset + 17] = outputUint8Array[17];
outCache[outOffset + 18] = outputUint8Array[18];
outCache[outOffset + 19] = outputUint8Array[19];
outCache[outOffset + 20] = outputUint8Array[20];
outCache[outOffset + 21] = outputUint8Array[21];
outCache[outOffset + 22] = outputUint8Array[22];
outCache[outOffset + 23] = outputUint8Array[23];
outCache[outOffset + 24] = outputUint8Array[24];
outCache[outOffset + 25] = outputUint8Array[25];
outCache[outOffset + 26] = outputUint8Array[26];
outCache[outOffset + 27] = outputUint8Array[27];
outCache[outOffset + 28] = outputUint8Array[28];
outCache[outOffset + 29] = outputUint8Array[29];
outCache[outOffset + 30] = outputUint8Array[30];
outCache[outOffset + 31] = outputUint8Array[31];
}

function update(data: Uint8Array): void {
const INPUT_LENGTH = ctx.INPUT_LENGTH;
if (data.length > INPUT_LENGTH) {
Expand Down
Loading

0 comments on commit 844e12b

Please sign in to comment.