Skip to content

Commit

Permalink
chore: documentation and benchmark in CI
Browse files Browse the repository at this point in the history
  • Loading branch information
twoeths committed Apr 15, 2024
1 parent d5e5495 commit 432f30d
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 36 deletions.
2 changes: 1 addition & 1 deletion packages/as-sha256/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"test:unit": "yarn run test:unit:node && yarn run test:unit:browser",
"test:unit:node": "run -T mocha -r ts-node/register test/unit/*.test.ts",
"test:unit:browser": "run -T karma start --single-run --browsers ChromeHeadless,FirefoxHeadless karma.config.js",
"benchmark": "node -r ts-node/register ./node_modules/.bin/benchmark 'test/perf/index.test.ts'",
"benchmark": "node -r ts-node/register ./node_modules/.bin/benchmark 'test/perf/*.test.ts'",
"benchmark:local": "yarn benchmark --local",
"test:ci": "yarn test:as-ci"
},
Expand Down
56 changes: 30 additions & 26 deletions packages/as-sha256/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ export function digest(data: Uint8Array): Uint8Array {
if (data.length <= ctx.INPUT_LENGTH) {
inputUint8Array.set(data);
ctx.digest(data.length);
const output = new Uint8Array(32);
output.set(outputUint8Array);
return output;
return outputUint8Array.slice(0, 32);
}

ctx.init();
Expand All @@ -32,9 +30,7 @@ export function digest64(data: Uint8Array): Uint8Array {
if (data.length === 64) {
inputUint8Array.set(data);
ctx.digest64(wasmInputValue, wasmOutputValue);
const output = new Uint8Array(32);
output.set(outputUint8Array);
return output;
return outputUint8Array.slice(0, 32);
}
throw new Error("InvalidLengthForDigest64");
}
Expand All @@ -44,9 +40,7 @@ export function digest2Bytes32(bytes1: Uint8Array, bytes2: Uint8Array): Uint8Arr
inputUint8Array.set(bytes1);
inputUint8Array.set(bytes2, 32);
ctx.digest64(wasmInputValue, wasmOutputValue);
const output = new Uint8Array(32);
output.set(outputUint8Array);
return output;
return outputUint8Array.slice(0, 32);
}
throw new Error("InvalidLengthForDigest64");
}
Expand Down Expand Up @@ -83,22 +77,30 @@ export function digest64HashObjects(obj1: HashObject, obj2: HashObject): HashObj
}

/**
* Hash 4 inputs, each 64 bytes
* @param i0 64 byte Uint8Array
* @param i1
* @param i2
* @param i3
* Hash 4 Uint8Array objects in parallel, each 64 length as below
* Inputs: 0 1 2 3 4 5 6 7
* \ / \ / \ / \ /
* Outputs: 0 1 2 3
*/
export function hash4Inputs(i0: Uint8Array, i1: Uint8Array, i2: Uint8Array, i3: Uint8Array): Uint8Array[] {
if (i0.length !== 64 || i1.length !== 64 || i2.length !== 64 || i3.length !== 64) {
throw new Error("Input length must be 64");
export function hash4Input64s(inputs: Uint8Array[]): Uint8Array[] {
if (inputs.length !== 4) {
throw new Error("Input length must be 4");
}
for (let i = 0; i < 4; i++) {
const input = inputs[i];
if (input == null) {
throw new Error(`Input ${i} is null or undefined`);
}
if (input.length !== 64) {
throw new Error(`Invalid length ${input.length} at input ${i}`);
}
}

// set up input buffer for v128
inputUint8Array.set(i0, 0);
inputUint8Array.set(i1, 64);
inputUint8Array.set(i2, 128);
inputUint8Array.set(i3, 192);
inputUint8Array.set(inputs[0], 0);
inputUint8Array.set(inputs[1], 64);
inputUint8Array.set(inputs[2], 128);
inputUint8Array.set(inputs[3], 192);

ctx.hash4Inputs(wasmOutputValue);

Expand All @@ -111,8 +113,12 @@ export function hash4Inputs(i0: Uint8Array, i1: Uint8Array, i2: Uint8Array, i3:
}

/**
* Hash 8 HashObjects:
* input${i} has h0 to h7, each 4 bytes which make it 32 bytes
* Hash 8 HashObjects in parallel:
* - input${i} has h0 to h7, each 4 bytes which make it 32 bytes
*
* Inputs h0 h1 h2 h3 h4 h5 h6 h7
* \ / \ / \ / \ /
* Outputs o0 o1 o2 o3
*/
export function hash8HashObjects(inputs: HashObject[]): HashObject[] {
if (inputs.length !== 8) {
Expand Down Expand Up @@ -243,7 +249,5 @@ function update(data: Uint8Array): void {

function final(): Uint8Array {
ctx.final(wasmOutputValue);
const output = new Uint8Array(32);
output.set(outputUint8Array);
return output;
return outputUint8Array.slice(0, 32);
}
25 changes: 18 additions & 7 deletions packages/as-sha256/test/perf/simd.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ import { itBench, setBenchOpts } from "@dapplion/benchmark";
import * as sha256 from "../../src";
import {byteArrayToHashObject} from "../../src/hashObject";

/**
* Mac M1 Apr 2024
*
digest64 vs hash4Inputs vs hash8HashObjects
✓ digest64 200092 times 6.816078 ops/s 146.7119 ms/op - 66 runs 10.3 s
✓ hash 200092 times using hash4Input64s 8.093460 ops/s 123.5566 ms/op - 78 runs 10.2 s
✓ hash 200092 times using hash8HashObjects 8.141334 ops/s 122.8300 ms/op - 78 runs 10.2 s
*/
describe("digest64 vs hash4Inputs vs hash8HashObjects", function () {
this.timeout(0);

Expand All @@ -12,20 +20,23 @@ describe("digest64 vs hash4Inputs vs hash8HashObjects", function () {
const input = Buffer.from("gajindergajindergajindergajindergajindergajindergajindergajinder", "utf8");
// total number of time running hash for 200000 balances
const iterations = 50023;
itBench(`digest64 ${iterations} times`, () => {
for (let j = 0; j < iterations; j++) sha256.digest64(input);
itBench(`digest64 ${iterations * 4} times`, () => {
for (let j = 0; j < iterations * 4; j++) sha256.digest64(input);
});

// hash4Inputs do 4 sha256 in parallel
const iterations2 = Math.floor(iterations / 4);
itBench(`hash ${iterations * 4} times using hash4Inputs`, () => {
for (let j = 0; j < iterations; j++) sha256.hash4Inputs(input, input, input, input);
itBench(`hash ${iterations * 4} times using hash4Input64s`, () => {
for (let j = 0; j < iterations; j++) {
sha256.hash4Input64s([input, input, input, input]);
}
});

const hashObject = byteArrayToHashObject(Buffer.from("gajindergajindergajindergajinder", "utf8"));
const hashInputs = Array.from({length: 8}, () => hashObject);
// hash8HashObjects do 4 sha256 in parallel
itBench(`hash ${iterations * 4} times using hash8HashObjects`, () => {
for (let j = 0; j < iterations; j++) sha256.hash8HashObjects(hashInputs);
for (let j = 0; j < iterations; j++) {
sha256.hash8HashObjects(hashInputs);
}
});
});
});
4 changes: 2 additions & 2 deletions packages/as-sha256/test/unit/simd.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ describe("Test SIMD implementation of as-sha256", () => {
const input1 = "gajindergajindergajindergajinder";
const input2 = "gajindergajindergajindergajinder";
const input = Buffer.from(input1 + input2, "utf8");
const outputs = sha256.hash4Inputs(input, input, input, input);
const outputs = sha256.hash4Input64s([input, input, input, input]);
const expectedOutput = new Uint8Array([
190, 57, 56, 15, 241, 208, 38, 30, 111, 55, 218, 254, 66, 120, 182, 98, 239, 97, 31, 28, 178, 247, 192, 161,
131, 72, 178, 215, 235, 20, 207, 110,
Expand All @@ -21,7 +21,7 @@ describe("Test SIMD implementation of as-sha256", () => {
it("testHash4Inputs 1000 times", () => {
for (let i = 0; i < 1000; i++) {
const input = crypto.randomBytes(64);
const outputs = sha256.hash4Inputs(input, input, input, input);
const outputs = sha256.hash4Input64s([input, input, input, input]);
const expectedOutput = sha256.digest64(input);
expect(outputs[0]).to.be.deep.equal(expectedOutput);
expect(outputs[1]).to.be.deep.equal(expectedOutput);
Expand Down

0 comments on commit 432f30d

Please sign in to comment.