diff --git a/package.json b/package.json index dd394ca7..e5d1d3ce 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "mocha": "^8.3.2", "nyc": "^15.0.0", "prettier": "^2.2.1", + "ts-loader": "^9.2.8", "ts-node": "^9.1.1", "typescript": "~4.2.3", "webpack": "^5.43.0", diff --git a/packages/as-sha256/.babel-register b/packages/as-sha256/.babel-register deleted file mode 100644 index 9414c15a..00000000 --- a/packages/as-sha256/.babel-register +++ /dev/null @@ -1 +0,0 @@ -require('@babel/register') \ No newline at end of file diff --git a/packages/as-sha256/.babelrc b/packages/as-sha256/.babelrc deleted file mode 100644 index 49d205e3..00000000 --- a/packages/as-sha256/.babelrc +++ /dev/null @@ -1,24 +0,0 @@ -{ - "presets": [ - [ - "@babel/env", - { - "targets": { - "node": "8", - "browsers": ">1%, not ie 11" - }, - "exclude": [ - "transform-regenerator" - ] - } - ] - ], - "plugins": [ - ["@chainsafe/babel-plugin-inline-binary-import", { - "extensions": [ - ".wasm" - ] - }] - ] -} - diff --git a/packages/as-sha256/.prettierrc.js b/packages/as-sha256/.prettierrc.js new file mode 100644 index 00000000..ee8eee2a --- /dev/null +++ b/packages/as-sha256/.prettierrc.js @@ -0,0 +1,11 @@ +module.exports = { + printWidth: 120, + tabWidth: 2, + useTabs: false, + semi: true, + singleQuote: false, + quoteProps: "as-needed", + trailingComma: "es5", + bracketSpacing: false, + arrowParens: "always", +}; diff --git a/packages/as-sha256/README.md b/packages/as-sha256/README.md index 06162584..08928ce9 100644 --- a/packages/as-sha256/README.md +++ b/packages/as-sha256/README.md @@ -10,7 +10,7 @@ AssemblyScript implementation of SHA256. `yarn add @chainsafe/as-sha256` ```typescript -import SHA256 from "@chainsafe/as-sha256"; +import {digest, digest64, SHA256} from "@chainsafe/as-sha256"; let hash: Uint8Array; @@ -20,10 +20,10 @@ const sha256 = new SHA256(); hash = sha256.init().update(Buffer.from("Hello world")).final(); // or use a one-pass interface -hash = SHA256.digest(Buffer.from("Hello world")); +hash = digest(Buffer.from("Hello world")); // or use a faster one-pass interface for hashing (only) 64 bytes -hash = SHA256.digest64(Buffer.from("abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh")); +hash = digest64(Buffer.from("abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh")); ``` ### License diff --git a/packages/as-sha256/assembly/__tests__/as-pect.d.ts b/packages/as-sha256/assembly/__tests__/as-pect.d.ts index 0a5912a6..f85eb205 100644 --- a/packages/as-sha256/assembly/__tests__/as-pect.d.ts +++ b/packages/as-sha256/assembly/__tests__/as-pect.d.ts @@ -92,7 +92,6 @@ declare function test(description: string, callback: () => void): void; */ declare function throws(description: string, callback: () => void, message?: string): void; - /** * This function creates a test that is expected to fail. This is useful to verify if a given * behavior is expected to throw. @@ -257,7 +256,6 @@ declare function log(value: T | null): void; */ // @ts-ignore declare class Expectation { - /** * Create a new expectation. * @@ -534,7 +532,7 @@ declare class Expectation { * expect([1, 2, 3]).toContain(3); * ``` */ - // @ts-ignore: expected value should be known at compile time + // @ts-ignore: expected value should be known at compile time toContain(expected: valueof, message?: string): void; /** @@ -668,9 +666,9 @@ declare class Performance { public static reportVariance(value: bool): void; } /** - * Assemblyscript uses reference counting to perform garbage collection. This means when you + * Assemblyscript uses reference counting to perform garbage collection. This means when you * allocate a managed object and return it, it's reference count is one. If another variable aliases - * it then the reference count goes up. This static class contains a few convenience methods for + * it then the reference count goes up. This static class contains a few convenience methods for * developers to test the current number of blocks allocated on the heap to make sure you aren't leaking * references, e.i. keeping references to objects you expect to be collected. */ @@ -809,7 +807,6 @@ declare class RTrace { public static activeTestBlocks(): usize[]; } - /** * This class is static and contains private global values that contain metadata about the Actual * value. @@ -835,7 +832,6 @@ declare class Actual { public static clear(): void; } - /** * This class is static and contains private global values that contain metadata about the Expected * value. diff --git a/packages/as-sha256/assembly/__tests__/example.spec.ts b/packages/as-sha256/assembly/__tests__/example.spec.ts index 635e1d60..c2bc042c 100644 --- a/packages/as-sha256/assembly/__tests__/example.spec.ts +++ b/packages/as-sha256/assembly/__tests__/example.spec.ts @@ -1,4 +1,4 @@ -import { init, update, final, digest64 } from '..'; +import {init, update, final, digest64} from ".."; export function toHexString(bin: Uint8Array): string { let bin_len = bin.length; @@ -7,8 +7,7 @@ export function toHexString(bin: Uint8Array): string { let bin_i = bin[i] as u32; let c = bin_i & 0xf; let b = bin_i >> 4; - let x: u32 = ((87 + c + (((c - 10) >> 8) & ~38)) << 8) | - (87 + b + (((b - 10) >> 8) & ~38)); + let x: u32 = ((87 + c + (((c - 10) >> 8) & ~38)) << 8) | (87 + b + (((b - 10) >> 8) & ~38)); hex += String.fromCharCode(x as u8); x >>= 8; hex += String.fromCharCode(x as u8); @@ -26,49 +25,57 @@ function hash(data: Uint8Array): Uint8Array { function hash64(data: Uint8Array): Uint8Array { const output = new Uint8Array(32); - digest64(changetype(data.buffer),changetype(output.buffer)); + digest64(changetype(data.buffer), changetype(output.buffer)); return output; } describe("example", () => { it("Hash: empty array", () => { let preImgArrayBuffer = new Uint8Array(0); - expect(toHexString(hash(preImgArrayBuffer))).toBe("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + expect(toHexString(hash(preImgArrayBuffer))).toBe( + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + ); }); it("Hash: abc", () => { let preImgString = "abc"; let preImgArrayBuffer = Uint8Array.wrap(String.UTF8.encode(preImgString)); - expect(toHexString(hash(preImgArrayBuffer))).toBe("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"); + expect(toHexString(hash(preImgArrayBuffer))).toBe( + "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" + ); }); it("Hash: lorem ipsum", () => { - let preImgString = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."; + let preImgString = + "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."; let preImgArrayBuffer = Uint8Array.wrap(String.UTF8.encode(preImgString)); - expect(toHexString(hash(preImgArrayBuffer))).toBe("7321348c8894678447b54c888fdbc4e4b825bf4d1eb0cfb27874286a23ea9fd2"); + expect(toHexString(hash(preImgArrayBuffer))).toBe( + "7321348c8894678447b54c888fdbc4e4b825bf4d1eb0cfb27874286a23ea9fd2" + ); }); it("Hash: abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", () => { let preImgString = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; let preImgArrayBuffer = Uint8Array.wrap(String.UTF8.encode(preImgString)); - expect(toHexString(hash(preImgArrayBuffer))).toBe("248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"); + expect(toHexString(hash(preImgArrayBuffer))).toBe( + "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1" + ); }); it("Hash64: gajindergajindergajindergajindergajindergajindergajindergajinder", () => { let preImgString = "gajindergajindergajindergajindergajindergajindergajindergajinder"; let preImgArrayBuffer = Uint8Array.wrap(String.UTF8.encode(preImgString)); - expect(toHexString(hash64(preImgArrayBuffer))).toBe("be39380ff1d0261e6f37dafe4278b662ef611f1cb2f7c0a18348b2d7eb14cf6e"); + expect(toHexString(hash64(preImgArrayBuffer))).toBe( + "be39380ff1d0261e6f37dafe4278b662ef611f1cb2f7c0a18348b2d7eb14cf6e" + ); }); it("CompareHash64: harkamalharkamalharkamalharkamalharkamalharkamalharkamalharkamal", () => { let preImgString = "harkamalharkamalharkamalharkamalharkamalharkamalharkamalharkamal"; let preImgArrayBuffer = Uint8Array.wrap(String.UTF8.encode(preImgString)); - const normalHash=toHexString(hash(preImgArrayBuffer)); - const fastHash64=toHexString(hash64(preImgArrayBuffer)); + const normalHash = toHexString(hash(preImgArrayBuffer)); + const fastHash64 = toHexString(hash64(preImgArrayBuffer)); expect(fastHash64).toBe(normalHash); - }); - }); - diff --git a/packages/as-sha256/assembly/tsconfig.json b/packages/as-sha256/assembly/tsconfig.json index c614e5c8..31e4eac9 100644 --- a/packages/as-sha256/assembly/tsconfig.json +++ b/packages/as-sha256/assembly/tsconfig.json @@ -1,6 +1,4 @@ { "extends": "../node_modules/assemblyscript/std/assembly.json", - "include": [ - "./**/*.ts" - ] -} \ No newline at end of file + "include": ["./**/*.ts"] +} diff --git a/packages/as-sha256/examples/browser-example.html b/packages/as-sha256/examples/browser-example.html deleted file mode 100644 index 015db398..00000000 --- a/packages/as-sha256/examples/browser-example.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - title - - - - - - diff --git a/packages/as-sha256/examples/run-wasm.js b/packages/as-sha256/examples/run-wasm.js deleted file mode 100644 index ac937fa1..00000000 --- a/packages/as-sha256/examples/run-wasm.js +++ /dev/null @@ -1,50 +0,0 @@ -const crypto = require('crypto'); -const wasm = require('../src/wasm.js'); -const sha = require('../lib/index.js'); - -const toHexString = byteArray => byteArray.reduce((acc, val) => (acc + ('0' + val.toString(16)).slice(-2)), ''); - -const emptyMessage = new Uint8Array(0); - -const testString = 'testi'; -const Message = new Uint8Array(Buffer.from(testString)); - -const aMessage = new Uint8Array([97,98,99]); -const randomMessage2048 = new Uint8Array(crypto.randomBytes(2048)); -const randomMessage16384 = new Uint8Array(crypto.randomBytes(16384)); - -const message = wasm.__retain(wasm.__allocArray(wasm.UINT8ARRAY_ID, Message)); -const amessage = wasm.__retain(wasm.__allocArray(wasm.UINT8ARRAY_ID, aMessage)); -const emptymessage = wasm.__retain(wasm.__allocArray(wasm.UINT8ARRAY_ID, emptyMessage)); -const randomessage2048 = wasm.__retain(wasm.__allocArray(wasm.UINT8ARRAY_ID, randomMessage2048)); -const randomessage16384 = wasm.__retain(wasm.__allocArray(wasm.UINT8ARRAY_ID, randomMessage16384)); - - -console.time('as (wasm)'); - const messageOut = wasm.hash(message); - const amessageOut = wasm.hash(amessage); - const emptymessageOut = wasm.hash(emptymessage); - for (let i = 0; i < 1000; i++) { - wasm.hash(randomessage2048); - } - for (let i = 0; i < 100; i++) { - wasm.hash(randomessage16384); - } -console.timeEnd('as (wasm)'); - -console.log(toHexString(wasm.__getUint8Array(messageOut)), '26e19f2b4dd93a3a7c49c3e785ec8932550af6aa6bea13078672a8c81508f18e'); -console.log(toHexString(wasm.__getUint8Array(amessageOut)), 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad'); -console.log(toHexString(wasm.__getUint8Array(emptymessageOut)), 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'); - -const h = sha.default(testString); -console.log(toHexString(h), '26e19f2b4dd93a3a7c49c3e785ec8932550af6aa6bea13078672a8c81508f18e'); - -wasm.__release(messageOut); -wasm.__release(amessageOut); -wasm.__release(emptymessageOut); - -wasm.__release(message); -wasm.__release(amessage); -wasm.__release(emptymessage); -wasm.__release(randomessage2048); -wasm.__release(randomessage16384); \ No newline at end of file diff --git a/packages/as-sha256/karma.config.js b/packages/as-sha256/karma.config.js index d615a558..3e6902da 100644 --- a/packages/as-sha256/karma.config.js +++ b/packages/as-sha256/karma.config.js @@ -2,19 +2,19 @@ module.exports = function (config) { config.set({ frameworks: ['mocha', 'chai'], files: [ - 'test/index.spec.js' + 'test/unit/index.test.ts' ], preprocessors: { - 'test/index.spec.js': ['webpack'] + 'test/unit/index.test.ts': ['webpack'] }, webpack: { mode: "production", module: { rules: [ { - test: /\.js?$/, + test: /\.ts?$/, exclude: /node_modules/, - loader: 'babel-loader', + loader: 'ts-loader', }, ] }, diff --git a/packages/as-sha256/package.json b/packages/as-sha256/package.json index 798b6d5c..f0fbd15e 100644 --- a/packages/as-sha256/package.json +++ b/packages/as-sha256/package.json @@ -1,51 +1,49 @@ { - "name": "@chainsafe/as-sha256", - "version": "0.2.4", - "description": "An AssemblyScript implementation of SHA256", - "author": "ChainSafe Systems", - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/ChainSafe/as-sha256/issues" - }, - "homepage": "https://github.com/ChainSafe/as-sha256#readme", - "repository": { - "type": "git", - "url": "git+https://github.com/chainsafe/as-sha256.git" - }, - "main": "lib/index.js", - "types": "lib/index.d.ts", - "files": [ - "lib", - "build" - ], - "scripts": { - "prebuild": "rm -rf ./dist", - "prepublish": "yarn build", - "build": "yarn asbuild:untouched && yarn asbuild:optimized && yarn build:lib", - "asbuild:untouched": "asc assembly/index.ts -b build/untouched.wasm -t build/untouched.wat --runtime none --validate --debug", - "asbuild:optimized": "asc assembly/index.ts -b build/optimized.wasm -t build/optimized.wat --runtime none --validate -O3z --noAssert", - "build:lib": "babel src -d lib --copy-files", - "build:web": "webpack --mode production --entry ./index.js --output ./dist/as-sha256.min.js", - "test": "yarn run test:as-ci && yarn run test:unit", - "test:unit": "yarn run test:unit:node && yarn run test:unit:browser", - "test:unit:node": "mocha -r .babel-register test/*.spec.js", - "test:unit:browser": "karma start --single-run --browsers ChromeHeadless,FirefoxHeadless karma.config.js", - "benchmark": "node ./node_modules/.bin/benchmark 'test/benchmark.test.js'", - "benchmark:local": "yarn benchmark --local", - "test:ci": "yarn test:as-ci", - "test:as": "asp --nortrace --verbose", - "test:as-ci": "asp --nortrace 2> /dev/null" - }, - "dependencies": { - "@assemblyscript/loader": "^0.9.2", - "buffer": "^5.4.3" - }, - "devDependencies": { - "@as-pect/assembly": "2.8.1", - "@as-pect/cli": "2.8.1", - "@as-pect/core": "2.8.1", - "@chainsafe/babel-plugin-inline-binary-import": "^1.0.3", - "assemblyscript": "0.9.2", - "benchmark": "^2.1.4" - } + "name": "@chainsafe/as-sha256", + "version": "0.2.4", + "description": "An AssemblyScript implementation of SHA256", + "author": "ChainSafe Systems", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/ChainSafe/as-sha256/issues" + }, + "homepage": "https://github.com/ChainSafe/as-sha256#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/chainsafe/as-sha256.git" + }, + "main": "lib/index.js", + "types": "lib/index.d.ts", + "files": [ + "lib", + "build" + ], + "scripts": { + "prebuild": "rm -rf ./dist && node -r ts-node/register ./scripts/codegen.ts", + "prepublish": "yarn build", + "build": "yarn asbuild:untouched && yarn asbuild:optimized && yarn build:lib", + "asbuild:untouched": "asc assembly/index.ts -b build/untouched.wasm -t build/untouched.wat --runtime none --validate --debug", + "asbuild:optimized": "asc assembly/index.ts -b build/optimized.wasm -t build/optimized.wat --runtime none --validate -O3z --noAssert", + "build:lib": "tsc -p tsconfig.build.json", + "build:web": "webpack --mode production --entry ./index.js --output ./dist/as-sha256.min.js", + "test": "yarn run test:as-ci && yarn run test:unit", + "test:unit": "yarn run test:unit:node && yarn run test:unit:browser", + "test:unit:node": "mocha -r ts-node/register test/unit/*.test.ts", + "test:unit:browser": "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:local": "yarn benchmark --local", + "test:ci": "yarn test:as-ci", + "test:as": "asp --nortrace --verbose", + "test:as-ci": "asp --nortrace 2> /dev/null" + }, + "dependencies": { + }, + "devDependencies": { + "@as-pect/assembly": "2.8.1", + "@as-pect/cli": "2.8.1", + "@as-pect/core": "2.8.1", + "@chainsafe/babel-plugin-inline-binary-import": "^1.0.3", + "assemblyscript": "0.9.2", + "benchmark": "^2.1.4" + } } diff --git a/packages/as-sha256/scripts/codegen.ts b/packages/as-sha256/scripts/codegen.ts new file mode 100644 index 00000000..d15b813a --- /dev/null +++ b/packages/as-sha256/scripts/codegen.ts @@ -0,0 +1,19 @@ +// Since wasm binary data cannot be statically imported into javascript, +// we preprocess the binary data into valid javascript code, a single exportable object. +// which can be statically imported. + +import fs from "fs"; + +const INPUT = "build/optimized.wasm"; +const OUTPUT = "src/wasmCode.ts"; + +const wasmBinary = Uint8Array.from(fs.readFileSync(INPUT)); + +const outputString = `// This file was autogenerated by scripts/codegen.ts +// DO NOT modify this file by hand! + +// eslint-disable-next-line prettier/prettier +export const wasmCode = Uint8Array.from([${wasmBinary.toString()}]); +`; + +fs.writeFileSync(OUTPUT, outputString); diff --git a/packages/as-sha256/src/index.js b/packages/as-sha256/src/hashObject.ts similarity index 51% rename from packages/as-sha256/src/index.js rename to packages/as-sha256/src/hashObject.ts index ef883f4e..18645a82 100644 --- a/packages/as-sha256/src/index.js +++ b/packages/as-sha256/src/hashObject.ts @@ -1,106 +1,24 @@ -import {newInstance} from "./wasm"; - -export default class SHA256 { - constructor() { - this.ctx = newInstance(); - this.wasmInputValue = this.ctx.input.value; - this.wasmOutputValue = this.ctx.output.value; - this.uint8InputArray = new Uint8Array(this.ctx.memory.buffer, this.wasmInputValue, this.ctx.INPUT_LENGTH); - this.uint8OutputArray = new Uint8Array(this.ctx.memory.buffer, this.wasmOutputValue, 32); - this.uint32InputArray = new Uint32Array(this.ctx.memory.buffer, this.wasmInputValue, this.ctx.INPUT_LENGTH); - // extracting numbers from Uint32Array causes more memory - // this.uint32OutputArray = new Uint32Array(this.ctx.memory.buffer, this.wasmOutputValue, 32); - } - init() { - this.ctx.init(); - return this; - } - update(data) { - const INPUT_LENGTH = this.ctx.INPUT_LENGTH; - if (data.length > INPUT_LENGTH) { - for (let i = 0; i < data.length; i += INPUT_LENGTH) { - const sliced = data.slice(i, i + INPUT_LENGTH); - this.uint8InputArray.set(sliced); - this.ctx.update(this.wasmInputValue, sliced.length); - } - } else { - this.uint8InputArray.set(data); - this.ctx.update(this.wasmInputValue, data.length); - } - return this; - } - final() { - this.ctx.final(this.wasmOutputValue); - const output = new Uint8Array(32); - output.set(this.uint8OutputArray); - return output; - } - - static digest(data) { - if (data.length === 64) { - return SHA256.digest64(data); - } - if (data.length <= staticInstance.ctx.INPUT_LENGTH) { - staticInstance.uint8InputArray.set(data); - staticInstance.ctx.digest(data.length); - const output = new Uint8Array(32); - output.set(staticInstance.uint8OutputArray); - return output; - } - return staticInstance.init().update(data).final(); - } - - static digest64(data) { - if (data.length === 64) { - staticInstance.uint8InputArray.set(data); - staticInstance.ctx.digest64(staticInstance.wasmInputValue, staticInstance.wasmOutputValue); - const output = new Uint8Array(32); - output.set(staticInstance.uint8OutputArray); - return output; - } - throw new Error("InvalidLengthForDigest64"); - } - - /** - * Digest 2 objects, each has 8 properties from h0 to h7. - * The performance is a little bit better than digest64 due to the use of Uint32Array - * and the memory is a little bit better than digest64 due to no temporary Uint8Array. - * @returns - */ - static digestTwoHashObjects(obj1, obj2) { - // TODO: expect obj1 and obj2 as HashObject - staticInstance.uint32InputArray[0] = obj1.h0; - staticInstance.uint32InputArray[1] = obj1.h1; - staticInstance.uint32InputArray[2] = obj1.h2; - staticInstance.uint32InputArray[3] = obj1.h3; - staticInstance.uint32InputArray[4] = obj1.h4; - staticInstance.uint32InputArray[5] = obj1.h5; - staticInstance.uint32InputArray[6] = obj1.h6; - staticInstance.uint32InputArray[7] = obj1.h7; - staticInstance.uint32InputArray[8] = obj2.h0; - staticInstance.uint32InputArray[9] = obj2.h1; - staticInstance.uint32InputArray[10] = obj2.h2; - staticInstance.uint32InputArray[11] = obj2.h3; - staticInstance.uint32InputArray[12] = obj2.h4; - staticInstance.uint32InputArray[13] = obj2.h5; - staticInstance.uint32InputArray[14] = obj2.h6; - staticInstance.uint32InputArray[15] = obj2.h7; - - staticInstance.ctx.digest64(staticInstance.wasmInputValue, staticInstance.wasmOutputValue); - - // extracting numbers from Uint32Array causes more memory - return byteArrayToHashObject(staticInstance.uint8OutputArray); - } +/** + * This is a hash representation with 8 numbers, each 4 bytes. + * That makes it 32 bytes, the same to Uint8Array(32). + */ +export interface HashObject { + h0: number; + h1: number; + h2: number; + h3: number; + h4: number; + h5: number; + h6: number; + h7: number; } -const staticInstance = new SHA256(); - /** * Pass 8 numbers in an object and set that to inputArray. * This function contains multiple same procedures but we intentionally * do it step by step to improve performance a bit. **/ -export function hashObjectToByteArray(obj, byteArr, offset) { +export function hashObjectToByteArray(obj: HashObject, byteArr: Uint8Array, offset: number): void { let tmp = obj.h0; byteArr[0 + offset] = tmp & 0xff; tmp = tmp >> 8; @@ -180,7 +98,7 @@ export function hashObjectToByteArray(obj, byteArr, offset) { * This function contains multiple same procedures but we intentionally * do it step by step to improve performance a bit. **/ -export function byteArrayToHashObject(byteArr) { +export function byteArrayToHashObject(byteArr: Uint8Array): HashObject { let tmp = 0; tmp |= byteArr[3] & 0xff; tmp = tmp << 8; diff --git a/packages/as-sha256/src/index.ts b/packages/as-sha256/src/index.ts new file mode 100644 index 00000000..f99811b6 --- /dev/null +++ b/packages/as-sha256/src/index.ts @@ -0,0 +1,92 @@ +import {newInstance} from "./wasm"; +import {HashObject, byteArrayToHashObject, hashObjectToByteArray} from "./hashObject"; +import SHA256 from "./sha256"; +export {HashObject, byteArrayToHashObject, hashObjectToByteArray, SHA256}; + +const ctx = newInstance(); +const wasmInputValue = ctx.input.value; +const wasmOutputValue = ctx.output.value; +const inputUint8Array = new Uint8Array(ctx.memory.buffer, wasmInputValue, ctx.INPUT_LENGTH); +const outputUint8Array = new Uint8Array(ctx.memory.buffer, wasmOutputValue, 32); +const inputUint32Array = new Uint32Array(ctx.memory.buffer, wasmInputValue, ctx.INPUT_LENGTH); + +export function digest(data: Uint8Array): Uint8Array { + if (data.length === 64) { + return digest64(data); + } + + if (data.length <= ctx.INPUT_LENGTH) { + inputUint8Array.set(data); + ctx.digest(data.length); + const output = new Uint8Array(32); + output.set(outputUint8Array); + return output; + } + + ctx.init(); + update(data); + return final(); +} + +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; + } + throw new Error("InvalidLengthForDigest64"); +} + +/** + * Digest 2 objects, each has 8 properties from h0 to h7. + * The performance is a little bit better than digest64 due to the use of Uint32Array + * and the memory is a little bit better than digest64 due to no temporary Uint8Array. + * @returns + */ +export function digest64HashObjects(obj1: HashObject, obj2: HashObject): HashObject { + // TODO: expect obj1 and obj2 as HashObject + inputUint32Array[0] = obj1.h0; + inputUint32Array[1] = obj1.h1; + inputUint32Array[2] = obj1.h2; + inputUint32Array[3] = obj1.h3; + inputUint32Array[4] = obj1.h4; + inputUint32Array[5] = obj1.h5; + inputUint32Array[6] = obj1.h6; + inputUint32Array[7] = obj1.h7; + inputUint32Array[8] = obj2.h0; + inputUint32Array[9] = obj2.h1; + inputUint32Array[10] = obj2.h2; + inputUint32Array[11] = obj2.h3; + inputUint32Array[12] = obj2.h4; + inputUint32Array[13] = obj2.h5; + inputUint32Array[14] = obj2.h6; + inputUint32Array[15] = obj2.h7; + + ctx.digest64(wasmInputValue, wasmOutputValue); + + // extracting numbers from Uint32Array causes more memory + return byteArrayToHashObject(outputUint8Array); +} + +function update(data: Uint8Array): void { + const INPUT_LENGTH = ctx.INPUT_LENGTH; + if (data.length > INPUT_LENGTH) { + for (let i = 0; i < data.length; i += INPUT_LENGTH) { + const sliced = data.slice(i, i + INPUT_LENGTH); + inputUint8Array.set(sliced); + ctx.update(wasmInputValue, sliced.length); + } + } else { + inputUint8Array.set(data); + ctx.update(wasmInputValue, data.length); + } +} + +function final(): Uint8Array { + ctx.final(wasmOutputValue); + const output = new Uint8Array(32); + output.set(outputUint8Array); + return output; +} diff --git a/packages/as-sha256/src/sha256.ts b/packages/as-sha256/src/sha256.ts new file mode 100644 index 00000000..a06e8369 --- /dev/null +++ b/packages/as-sha256/src/sha256.ts @@ -0,0 +1,47 @@ +import {newInstance, WasmContext} from "./wasm"; + +/** + * Class based SHA256 + */ +export default class SHA256 { + ctx: WasmContext; + private wasmInputValue: number; + private wasmOutputValue: number; + private uint8InputArray: Uint8Array; + private uint8OutputArray: Uint8Array; + + constructor() { + this.ctx = newInstance(); + this.wasmInputValue = this.ctx.input.value; + this.wasmOutputValue = this.ctx.output.value; + this.uint8InputArray = new Uint8Array(this.ctx.memory.buffer, this.wasmInputValue, this.ctx.INPUT_LENGTH); + this.uint8OutputArray = new Uint8Array(this.ctx.memory.buffer, this.wasmOutputValue, 32); + } + + init(): this { + this.ctx.init(); + return this; + } + + update(data: Uint8Array): this { + const INPUT_LENGTH = this.ctx.INPUT_LENGTH; + if (data.length > INPUT_LENGTH) { + for (let i = 0; i < data.length; i += INPUT_LENGTH) { + const sliced = data.slice(i, i + INPUT_LENGTH); + this.uint8InputArray.set(sliced); + this.ctx.update(this.wasmInputValue, sliced.length); + } + } else { + this.uint8InputArray.set(data); + this.ctx.update(this.wasmInputValue, data.length); + } + return this; + } + + final(): Uint8Array { + this.ctx.final(this.wasmOutputValue); + const output = new Uint8Array(32); + output.set(this.uint8OutputArray); + return output; + } +} diff --git a/packages/as-sha256/src/wasm.js b/packages/as-sha256/src/wasm.js deleted file mode 100644 index cfb94cd6..00000000 --- a/packages/as-sha256/src/wasm.js +++ /dev/null @@ -1,9 +0,0 @@ -import loader from "@assemblyscript/loader"; -import wasmCode from "../build/optimized.wasm"; -import {Buffer} from "buffer"; - -const module = new WebAssembly.Module(Buffer.from(wasmCode, 'binary')); - -export function newInstance() { - return loader.instantiateSync(module); -} diff --git a/packages/as-sha256/src/wasm.ts b/packages/as-sha256/src/wasm.ts new file mode 100644 index 00000000..e76abe5c --- /dev/null +++ b/packages/as-sha256/src/wasm.ts @@ -0,0 +1,36 @@ +import {wasmCode} from "./wasmCode"; + +const _module = new WebAssembly.Module(wasmCode); + +export interface WasmContext { + readonly INPUT_LENGTH: number; + memory: { + buffer: ArrayBuffer; + }; + input: { + value: number; + }; + output: { + value: number; + }; + + init(): void; + update(dataPtr: number, dataLength: number): void; + final(outPtr: number): void; + + digest(length: number): void; + digest64(inPtr: number, outPtr: number): void; +} + +const importObj = { + env: { + // modified from https://github.com/AssemblyScript/assemblyscript/blob/v0.9.2/lib/loader/index.js#L70 + abort: function (msg: number, file: number, line: number, col: number) { + throw Error(`abort: ${msg}:${file}:${line}:${col}`); + }, + }, +}; + +export function newInstance(): WasmContext { + return new WebAssembly.Instance(_module, importObj).exports as unknown as WasmContext; +} diff --git a/packages/as-sha256/src/wasmCode.ts b/packages/as-sha256/src/wasmCode.ts new file mode 100644 index 00000000..102d56e6 --- /dev/null +++ b/packages/as-sha256/src/wasmCode.ts @@ -0,0 +1,5 @@ +// This file was autogenerated by scripts/codegen.ts +// DO NOT modify this file by hand! + +// eslint-disable-next-line prettier/prettier +export const wasmCode = Uint8Array.from([0,97,115,109,1,0,0,0,1,31,6,96,1,127,0,96,2,127,127,0,96,0,0,96,1,127,1,127,96,3,127,127,127,0,96,4,127,127,127,127,0,2,13,1,3,101,110,118,5,97,98,111,114,116,0,5,3,16,15,0,3,1,3,2,2,4,1,1,3,0,0,0,1,2,5,3,1,0,1,6,172,1,34,127,0,65,128,4,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,127,1,65,0,11,7,86,9,6,109,101,109,111,114,121,2,0,12,73,78,80,85,84,95,76,69,78,71,84,72,3,0,5,105,110,112,117,116,3,28,6,111,117,116,112,117,116,3,30,4,105,110,105,116,0,6,6,117,112,100,97,116,101,0,9,5,102,105,110,97,108,0,11,6,100,105,103,101,115,116,0,12,8,100,105,103,101,115,116,54,52,0,14,8,1,15,10,202,14,15,70,1,2,127,32,0,63,0,34,2,65,16,116,34,1,75,4,64,32,2,32,0,32,1,107,65,255,255,3,106,65,128,128,124,113,65,16,118,34,1,32,2,32,1,74,27,64,0,65,0,72,4,64,32,1,64,0,65,0,72,4,64,0,11,11,11,32,0,36,23,11,82,1,3,127,32,0,65,240,255,255,255,3,75,4,64,0,11,35,23,65,16,106,34,2,32,0,65,15,106,65,112,113,34,1,65,16,32,1,65,16,75,27,34,3,106,16,1,32,2,65,16,107,34,1,32,3,54,2,0,32,1,65,1,54,2,4,32,1,65,0,54,2,8,32,1,32,0,54,2,12,32,2,11,37,1,1,127,3,64,32,1,4,64,32,0,34,2,65,1,106,33,0,32,2,65,0,58,0,0,32,1,65,1,107,33,1,12,1,11,11,11,41,1,1,127,32,0,65,240,255,255,255,3,75,4,64,65,128,5,65,176,5,65,54,65,42,16,0,0,11,32,0,16,2,34,1,32,0,16,3,32,1,11,71,0,65,180,2,40,2,0,36,1,65,228,4,40,2,0,36,2,65,224,5,36,22,65,224,5,36,23,65,192,0,16,4,36,24,35,24,36,25,65,128,2,16,4,36,26,35,26,36,27,65,128,4,16,4,36,28,35,28,36,29,65,32,16,4,36,30,35,30,36,31,11,74,0,65,231,204,167,208,6,36,3,65,133,221,158,219,123,36,4,65,242,230,187,227,3,36,5,65,186,234,191,170,122,36,6,65,255,164,185,136,5,36,7,65,140,209,149,216,121,36,8,65,171,179,143,252,1,36,9,65,153,154,131,223,5,36,10,65,0,36,32,65,0,36,33,11,103,1,2,127,2,64,32,2,33,3,32,0,32,1,70,13,0,32,0,32,1,73,4,64,3,64,32,3,4,64,32,0,34,2,65,1,106,33,0,32,1,34,4,65,1,106,33,1,32,2,32,4,45,0,0,58,0,0,32,3,65,1,107,33,3,12,1,11,11,5,3,64,32,3,4,64,32,3,65,1,107,34,3,32,0,106,32,1,32,3,106,45,0,0,58,0,0,12,1,11,11,11,11,11,231,3,1,1,127,35,3,36,11,35,4,36,12,35,5,36,13,35,6,36,14,35,7,36,15,35,8,36,16,35,9,36,17,35,10,36,18,65,0,36,19,3,64,35,19,65,16,73,4,64,32,0,35,19,65,2,116,106,32,1,35,19,65,2,116,34,2,106,45,0,0,65,24,116,32,1,32,2,65,1,106,106,45,0,0,65,16,116,114,32,1,32,2,65,2,106,106,45,0,0,65,8,116,114,32,1,32,2,65,3,106,106,45,0,0,114,54,2,0,35,19,65,1,106,36,19,12,1,11,11,65,16,36,19,3,64,35,19,65,192,0,73,4,64,32,0,35,19,65,2,116,106,32,0,35,19,65,16,107,65,2,116,106,40,2,0,32,0,35,19,65,7,107,65,2,116,106,40,2,0,32,0,35,19,65,2,107,65,2,116,106,40,2,0,34,1,65,17,120,32,1,65,19,120,115,32,1,65,10,118,115,106,32,0,35,19,65,15,107,65,2,116,106,40,2,0,34,1,65,7,120,32,1,65,18,120,115,32,1,65,3,118,115,106,106,54,2,0,35,19,65,1,106,36,19,12,1,11,11,65,0,36,19,3,64,35,19,65,192,0,73,4,64,32,0,35,19,65,2,116,106,40,2,0,35,1,35,19,65,2,116,106,40,2,0,35,18,35,15,34,1,65,6,120,32,1,65,11,120,115,32,1,65,25,120,115,106,35,15,34,1,35,16,113,35,17,32,1,65,127,115,113,115,106,106,106,36,20,35,11,34,1,65,2,120,32,1,65,13,120,115,32,1,65,22,120,115,35,11,34,1,35,12,34,2,113,32,1,35,13,34,1,113,115,32,1,32,2,113,115,106,36,21,35,17,36,18,35,16,36,17,35,15,36,16,35,14,35,20,106,36,15,35,13,36,14,35,12,36,13,35,11,36,12,35,20,35,21,106,36,11,35,19,65,1,106,36,19,12,1,11,11,35,3,35,11,106,36,3,35,4,35,12,106,36,4,35,5,35,13,106,36,5,35,6,35,14,106,36,6,35,7,35,15,106,36,7,35,8,35,16,106,36,8,35,9,35,17,106,36,9,35,10,35,18,106,36,10,11,177,1,1,2,127,32,1,35,33,106,36,33,35,32,4,64,65,192,0,35,32,107,32,1,76,4,64,35,25,35,32,106,32,0,65,192,0,35,32,107,16,7,35,32,65,192,0,35,32,107,106,36,32,65,192,0,35,32,107,33,2,32,1,65,192,0,35,32,107,107,33,1,35,27,35,25,16,8,65,0,36,32,5,35,25,35,32,106,32,0,32,1,16,7,32,1,35,32,106,36,32,15,11,11,3,64,32,3,32,1,65,192,0,109,72,4,64,35,27,32,0,32,2,106,16,8,32,3,65,1,106,33,3,32,2,65,64,107,33,2,12,1,11,11,32,1,65,63,113,4,64,35,25,35,32,106,32,0,32,2,106,32,1,65,63,113,34,0,16,7,32,0,35,32,106,36,32,11,11,25,0,32,0,65,128,254,131,120,113,65,8,119,32,0,65,255,129,252,7,113,65,8,120,114,11,173,2,1,2,127,35,33,65,63,113,65,63,72,4,64,35,25,35,32,106,65,128,1,58,0,0,35,32,65,1,106,36,32,11,35,33,65,63,113,65,56,78,4,64,35,25,35,32,106,34,1,65,192,0,35,32,107,106,33,2,3,64,32,1,32,2,73,4,64,32,1,65,0,58,0,0,32,1,65,1,106,33,1,12,1,11,11,35,27,35,25,16,8,65,0,36,32,11,35,33,65,63,113,65,63,78,4,64,35,25,35,32,106,65,128,1,58,0,0,35,32,65,1,106,36,32,11,35,25,35,32,106,34,1,65,56,35,32,107,106,33,2,3,64,32,1,32,2,73,4,64,32,1,65,0,58,0,0,32,1,65,1,106,33,1,12,1,11,11,35,25,65,56,106,35,33,65,128,128,128,128,2,109,16,10,54,2,0,35,25,65,60,106,35,33,65,3,116,16,10,54,2,0,35,27,35,25,16,8,32,0,35,3,16,10,54,2,0,32,0,65,4,106,35,4,16,10,54,2,0,32,0,65,8,106,35,5,16,10,54,2,0,32,0,65,12,106,35,6,16,10,54,2,0,32,0,65,16,106,35,7,16,10,54,2,0,32,0,65,20,106,35,8,16,10,54,2,0,32,0,65,24,106,35,9,16,10,54,2,0,32,0,65,28,106,35,10,16,10,54,2,0,11,14,0,16,6,35,29,32,0,16,9,35,31,16,11,11,253,1,1,2,127,35,3,36,11,35,4,36,12,35,5,36,13,35,6,36,14,35,7,36,15,35,8,36,16,35,9,36,17,35,10,36,18,65,0,36,19,3,64,35,19,65,192,0,73,4,64,32,0,35,19,65,2,116,106,40,2,0,35,18,35,15,34,1,65,6,120,32,1,65,11,120,115,32,1,65,25,120,115,106,35,15,34,1,35,16,113,35,17,32,1,65,127,115,113,115,106,106,36,20,35,11,34,1,65,2,120,32,1,65,13,120,115,32,1,65,22,120,115,35,11,34,1,35,12,34,2,113,32,1,35,13,34,1,113,115,32,1,32,2,113,115,106,36,21,35,17,36,18,35,16,36,17,35,15,36,16,35,14,35,20,106,36,15,35,13,36,14,35,12,36,13,35,11,36,12,35,20,35,21,106,36,11,35,19,65,1,106,36,19,12,1,11,11,35,3,35,11,106,36,3,35,4,35,12,106,36,4,35,5,35,13,106,36,5,35,6,35,14,106,36,6,35,7,35,15,106,36,7,35,8,35,16,106,36,8,35,9,35,17,106,36,9,35,10,35,18,106,36,10,11,107,0,16,6,35,27,32,0,16,8,35,2,16,13,32,1,35,3,16,10,54,2,0,32,1,65,4,106,35,4,16,10,54,2,0,32,1,65,8,106,35,5,16,10,54,2,0,32,1,65,12,106,35,6,16,10,54,2,0,32,1,65,16,106,35,7,16,10,54,2,0,32,1,65,20,106,35,8,16,10,54,2,0,32,1,65,24,106,35,9,16,10,54,2,0,32,1,65,28,106,35,10,16,10,54,2,0,11,4,0,16,5,11,11,222,5,6,0,65,17,11,143,2,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,152,47,138,66,145,68,55,113,207,251,192,181,165,219,181,233,91,194,86,57,241,17,241,89,164,130,63,146,213,94,28,171,152,170,7,216,1,91,131,18,190,133,49,36,195,125,12,85,116,93,190,114,254,177,222,128,167,6,220,155,116,241,155,193,193,105,155,228,134,71,190,239,198,157,193,15,204,161,12,36,111,44,233,45,170,132,116,74,220,169,176,92,218,136,249,118,82,81,62,152,109,198,49,168,200,39,3,176,199,127,89,191,243,11,224,198,71,145,167,213,81,99,202,6,103,41,41,20,133,10,183,39,56,33,27,46,252,109,44,77,19,13,56,83,84,115,10,101,187,10,106,118,46,201,194,129,133,44,114,146,161,232,191,162,75,102,26,168,112,139,75,194,163,81,108,199,25,232,146,209,36,6,153,214,133,53,14,244,112,160,106,16,22,193,164,25,8,108,55,30,76,119,72,39,181,188,176,52,179,12,28,57,74,170,216,78,79,202,156,91,243,111,46,104,238,130,143,116,111,99,165,120,20,120,200,132,8,2,199,140,250,255,190,144,235,108,80,164,247,163,249,190,242,120,113,198,0,65,160,2,11,29,16,0,0,0,1,0,0,0,3,0,0,0,16,0,0,0,32,0,0,0,32,0,0,0,0,1,0,0,64,0,65,193,2,11,143,2,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,152,47,138,194,145,68,55,113,207,251,192,181,165,219,181,233,91,194,86,57,241,17,241,89,164,130,63,146,213,94,28,171,152,170,7,216,1,91,131,18,190,133,49,36,195,125,12,85,116,93,190,114,254,177,222,128,167,6,220,155,116,243,155,193,193,105,155,100,134,71,254,240,198,237,225,15,84,242,12,36,111,52,233,79,190,132,201,108,30,65,185,97,250,136,249,22,82,81,198,242,109,90,142,168,101,252,25,176,199,158,217,185,195,49,18,154,160,234,14,231,43,35,177,253,176,62,53,199,213,186,105,48,95,109,151,203,143,17,15,90,253,238,30,220,137,182,53,10,4,122,11,222,157,202,244,88,22,91,93,225,134,62,127,0,128,137,8,55,50,234,7,165,55,149,171,111,16,97,64,23,241,214,140,13,109,59,170,205,55,190,187,192,218,59,97,131,99,163,72,219,49,233,2,11,167,92,209,111,202,250,26,82,49,132,51,49,149,26,212,110,144,120,67,109,242,145,156,195,189,171,204,158,230,160,201,181,60,182,47,83,198,65,199,210,163,126,35,7,104,75,149,164,118,29,25,76,0,65,208,4,11,29,16,0,0,0,1,0,0,0,3,0,0,0,16,0,0,0,80,1,0,0,80,1,0,0,0,1,0,0,64,0,65,240,4,11,43,28,0,0,0,1,0,0,0,1,0,0,0,28,0,0,0,73,0,110,0,118,0,97,0,108,0,105,0,100,0,32,0,108,0,101,0,110,0,103,0,116,0,104,0,65,160,5,11,53,38,0,0,0,1,0,0,0,1,0,0,0,38,0,0,0,126,0,108,0,105,0,98,0,47,0,97,0,114,0,114,0,97,0,121,0,98,0,117,0,102,0,102,0,101,0,114,0,46,0,116,0,115]); diff --git a/packages/as-sha256/test/index.spec.js b/packages/as-sha256/test/index.spec.js deleted file mode 100644 index 48adf764..00000000 --- a/packages/as-sha256/test/index.spec.js +++ /dev/null @@ -1,107 +0,0 @@ -const {Buffer} = require("buffer"); -const sha256 = require("../src"); -const {expect} = require("chai"); - -describe("sha256", function () { - - describe("digest function", function () { - - it('abc', function () { - const input = Buffer.from("abc", "utf8"); - expect(Buffer.from(sha256.default.digest(input)).toString("hex")).to.be.equal("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"); - }); - - it('empty string', function () { - const input = Buffer.from("", "utf8"); - expect(Buffer.from(sha256.default.digest(input)).toString("hex")).to.be.equal("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") - }); - - it('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq', function () { - const input = Buffer.from("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "utf8"); - expect(Buffer.from(sha256.default.digest(input)).toString("hex")).to.be.equal("248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1") - }); - - it('abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu', function () { - const input = Buffer.from("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", "utf8"); - expect(Buffer.from(sha256.default.digest(input)).toString("hex")).to.be.equal("cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1") - }); - - it('gajindergajindergajindergajindergajindergajindergajindergajinder', function () { - const input1 = "gajindergajindergajindergajinder"; - const input2 = "gajindergajindergajindergajinder"; - const input = Buffer.from(input1 + input2, "utf8"); - const output = sha256.default.digest64(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 - ]); - expect(output).to.be.deep.equal(expectedOutput, "incorrect digest64 result"); - expect(Buffer.from(output).toString("hex")).to.be.equal("be39380ff1d0261e6f37dafe4278b662ef611f1cb2f7c0a18348b2d7eb14cf6e") - // digestTwoHashObjects should be the same to digest64 - const buffer1 = Buffer.from(input1, "utf-8"); - const buffer2 = Buffer.from(input2, "utf-8"); - const obj1 = sha256.byteArrayToHashObject(buffer1); - const obj2 = sha256.byteArrayToHashObject(buffer2); - const obj = sha256.default.digestTwoHashObjects(obj1, obj2); - const output2 = new Uint8Array(32); - sha256.hashObjectToByteArray(obj, output2, 0); - for (let i = 0; i < 32; i++) { - expect(output2[i]).to.be.equal(output[i], "failed at index" + i); - } - expect(output2).to.be.deep.equal(expectedOutput, "incorrect digestTwoHashObjects result"); - }); - - it('harkamalharkamalharkamalharkamalharkamalharkamalharkamalharkamal', function () { - const input = Buffer.from("harkamalharkamalharkamalharkamalharkamalharkamalharkamalharkamal", "utf8"); - const output = Buffer.from(sha256.default.digest(input)).toString("hex"); - const output64 = Buffer.from(sha256.default.digest64(input)).toString("hex") - expect(output).to.be.equal(output64) - }); - - it('1024 digest test', function () { - let input = "12345678"; - input=`${input}${input}${input}${input}${input}${input}${input}${input}`;//64 length - input=`${input}${input}${input}${input}${input}${input}${input}${input}`;//512 length - input=`${input}${input}`;//1024 length - input=Buffer.from(input,"utf8"); - expect(input.length).to.be.equal(1024) - - const output = Buffer.from(sha256.default.digest(input)).toString("hex"); - expect(output).to.be.equal("54c7cb8a82d68145fd5f5da4103f5a66f422dbea23d9fc9f40f59b1dcf5403a9"); - }); - }) - -}); - -describe("sha256.hashObjectToByteArray and sha256.byteArrayToHashObject", function () { - const tcs = [ - 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, - ]), - new Uint8Array([ - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - ]), - new Uint8Array([ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - ]), - ]; - for (const [i, byteArr] of tcs.entries()) { - it("test case " + i, function () { - const obj = sha256.byteArrayToHashObject(byteArr); - const newByteArr = new Uint8Array(32); - sha256.hashObjectToByteArray(obj, newByteArr, 0); - expect(newByteArr).to.be.deep.equal(byteArr, "failed test case" + i); - }); - } -}); diff --git a/packages/as-sha256/test/benchmark.test.js b/packages/as-sha256/test/perf/index.test.ts similarity index 76% rename from packages/as-sha256/test/benchmark.test.js rename to packages/as-sha256/test/perf/index.test.ts index 84c9acb3..b772165c 100644 --- a/packages/as-sha256/test/benchmark.test.js +++ b/packages/as-sha256/test/perf/index.test.ts @@ -1,5 +1,5 @@ -const {itBench, setBenchOpts} = require("@dapplion/benchmark"); -const sha256 = require("../lib/index"); +import {itBench} from "@dapplion/benchmark"; +import * as sha256 from "../../src"; // Aug 10 2021 // digestTwoHashObjects vs digest64 vs digest @@ -7,12 +7,6 @@ const sha256 = require("../lib/index"); // ✓ digest64 50023 times 18.21352 ops/s 54.90425 ms/op - 1093 runs 60.0 s // ✓ digest 50023 times 10.60461 ops/s 94.29865 ms/op - 637 runs 60.1 s describe("digestTwoHashObjects vs digest64 vs digest", () => { - setBenchOpts({ - maxMs: 100 * 1000, - minMs: 60 * 1000, - runs: 512, - }); - const input = Buffer.from("gajindergajindergajindergajindergajindergajindergajindergajinder", "utf8"); const input1 = "gajindergajindergajindergajinder"; const input2 = "gajindergajindergajindergajinder"; @@ -23,32 +17,26 @@ describe("digestTwoHashObjects vs digest64 vs digest", () => { // total number of time running hash for 200000 balances const iterations = 50023; itBench(`digestTwoHashObjects ${iterations} times`, () => { - for (let j = 0; j < iterations; j++) sha256.default.digestTwoHashObjects(obj1, obj2); + for (let j = 0; j < iterations; j++) sha256.digest64HashObjects(obj1, obj2); }); itBench(`digest64 ${iterations} times`, () => { - for (let j = 0; j < iterations; j++) sha256.default.digest64(input); + for (let j = 0; j < iterations; j++) sha256.digest64(input); }); itBench(`digest ${iterations} times`, () => { - for (let j = 0; j < iterations; j++) sha256.default.digest(input); + for (let j = 0; j < iterations; j++) sha256.digest(input); }); - }); describe("digest different Buffers", () => { - const randomBuffer = (length) => Buffer.from(Array.from({length}, () => Math.round(Math.random() * 255))); - - setBenchOpts({ - maxMs: 10 * 1000, - minMs: 5 * 1000, - runs: 512, - }); + const randomBuffer = (length: number): Uint8Array => + Buffer.from(Array.from({length}, () => Math.round(Math.random() * 255))); for (const length of [32, 64, 128, 256, 512, 1024]) { const buffer = randomBuffer(length); itBench(`input length ${length}`, () => { - sha256.default.digest(buffer); + sha256.digest(buffer); }); } }); @@ -61,20 +49,15 @@ describe("digest different Buffers", () => { * digest 1000000 times 0.8279731 ops/s 1.207769 s/op - 82 runs 100 s * => we are at 8279731 hashes/sec */ - describe("hash - compare to java", () => { +describe("hash - compare to java", () => { // java statistic for same test: https://gist.github.com/scoroberts/a60d61a2cc3afba1e8813b338ecd1501 - setBenchOpts({ - maxMs: 100 * 1000, - minMs: 60 * 1000, - runs: 512, - }); const iterations = 1000000; const input = Buffer.from("lwkjt23uy45pojsdf;lnwo45y23po5i;lknwe;lknasdflnqw3uo5", "utf8"); itBench(`digest ${iterations} times`, () => { - for (let i=0; i { // ✓ hashObjectToByteArray 50023 times 685.6641 ops/s 1.458440 ms/op - 41081 runs 60.0 s // ✓ byteArrayToHashObject 50023 times 580.6237 ops/s 1.722286 ms/op - 34771 runs 60.0 s describe("utils", () => { - setBenchOpts({ - maxMs: 100 * 1000, - minMs: 60 * 1000, - runs: 512, - }); - const input1 = "gajindergajindergajindergajinder"; const buffer1 = Buffer.from(input1, "utf-8"); const obj1 = sha256.byteArrayToHashObject(buffer1); diff --git a/packages/as-sha256/test/unit/index.test.ts b/packages/as-sha256/test/unit/index.test.ts new file mode 100644 index 00000000..4c31d5c2 --- /dev/null +++ b/packages/as-sha256/test/unit/index.test.ts @@ -0,0 +1,103 @@ +import {Buffer} from "buffer"; +import * as sha256 from "../../src"; +import {expect} from "chai"; + +describe("sha256", function () { + describe("digest function", function () { + it("abc", function () { + const input = Buffer.from("abc", "utf8"); + expect(Buffer.from(sha256.digest(input)).toString("hex")).to.be.equal( + "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" + ); + }); + + it("empty string", function () { + const input = Buffer.from("", "utf8"); + expect(Buffer.from(sha256.digest(input)).toString("hex")).to.be.equal( + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + ); + }); + + it("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", function () { + const input = Buffer.from("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "utf8"); + expect(Buffer.from(sha256.digest(input)).toString("hex")).to.be.equal( + "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1" + ); + }); + + it("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", function () { + const input = Buffer.from( + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", + "utf8" + ); + expect(Buffer.from(sha256.digest(input)).toString("hex")).to.be.equal( + "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1" + ); + }); + + it("gajindergajindergajindergajindergajindergajindergajindergajinder", function () { + const input1 = "gajindergajindergajindergajinder"; + const input2 = "gajindergajindergajindergajinder"; + const input = Buffer.from(input1 + input2, "utf8"); + const output = sha256.digest64(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, + ]); + expect(output).to.be.deep.equal(expectedOutput, "incorrect digest64 result"); + expect(Buffer.from(output).toString("hex")).to.be.equal( + "be39380ff1d0261e6f37dafe4278b662ef611f1cb2f7c0a18348b2d7eb14cf6e" + ); + // digestTwoHashObjects should be the same to digest64 + const buffer1 = Buffer.from(input1, "utf-8"); + const buffer2 = Buffer.from(input2, "utf-8"); + const obj1 = sha256.byteArrayToHashObject(buffer1); + const obj2 = sha256.byteArrayToHashObject(buffer2); + const obj = sha256.digest64HashObjects(obj1, obj2); + const output2 = new Uint8Array(32); + sha256.hashObjectToByteArray(obj, output2, 0); + for (let i = 0; i < 32; i++) { + expect(output2[i]).to.be.equal(output[i], "failed at index" + i); + } + expect(output2).to.be.deep.equal(expectedOutput, "incorrect digestTwoHashObjects result"); + }); + + it("harkamalharkamalharkamalharkamalharkamalharkamalharkamalharkamal", function () { + const input = Buffer.from("harkamalharkamalharkamalharkamalharkamalharkamalharkamalharkamal", "utf8"); + const output = Buffer.from(sha256.digest(input)).toString("hex"); + const output64 = Buffer.from(sha256.digest64(input)).toString("hex"); + expect(output).to.be.equal(output64); + }); + + it("1024 digest test", function () { + const inputStr = "12345678".repeat(128); + const input = Buffer.from(inputStr, "utf8"); + expect(input.length).to.be.equal(1024); + + const output = Buffer.from(sha256.digest(input)).toString("hex"); + expect(output).to.be.equal("54c7cb8a82d68145fd5f5da4103f5a66f422dbea23d9fc9f40f59b1dcf5403a9"); + }); + }); +}); + +describe("sha256.hashObjectToByteArray and sha256.byteArrayToHashObject", function () { + const tcs = [ + 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, + ]), + new Uint8Array([ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, + ]), + new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + ]; + for (const [i, byteArr] of tcs.entries()) { + it("test case " + i, function () { + const obj = sha256.byteArrayToHashObject(byteArr); + const newByteArr = new Uint8Array(32); + sha256.hashObjectToByteArray(obj, newByteArr, 0); + expect(newByteArr).to.be.deep.equal(byteArr, "failed test case" + i); + }); + } +}); diff --git a/packages/as-sha256/tsconfig.build.json b/packages/as-sha256/tsconfig.build.json new file mode 100644 index 00000000..bd4bfc9e --- /dev/null +++ b/packages/as-sha256/tsconfig.build.json @@ -0,0 +1,28 @@ +{ + "include": ["src"], + "compilerOptions": { + "typeRoots": ["../../node_modules/@types", "./node_modules/@types", "./types"], + + "outDir": "lib", + "target": "esnext", + "module": "commonjs", + "pretty": true, + + "strict": true, + "sourceMap": true, + "alwaysStrict": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "strictBindCallApply": true, + "strictPropertyInitialization": true, + "noImplicitAny": true, + "noImplicitThis": true, + "noImplicitReturns": true, + + "esModuleInterop": true, + "declaration": true, + "declarationMap": true, + "incremental": false, + "preserveWatchOutput": true + } +} diff --git a/packages/as-sha256/tsconfig.json b/packages/as-sha256/tsconfig.json new file mode 100644 index 00000000..32952636 --- /dev/null +++ b/packages/as-sha256/tsconfig.json @@ -0,0 +1,7 @@ +{ + "include": ["src", "test"], + "extends": "./tsconfig.build.json", + "compilerOptions": { + "incremental": true + } +} diff --git a/packages/persistent-merkle-tree/src/hash.ts b/packages/persistent-merkle-tree/src/hash.ts index 1d17f29d..4952a9ea 100644 --- a/packages/persistent-merkle-tree/src/hash.ts +++ b/packages/persistent-merkle-tree/src/hash.ts @@ -1,4 +1,10 @@ -import SHA256, {byteArrayToHashObject, HashObject, hashObjectToByteArray} from "@chainsafe/as-sha256"; +import { + byteArrayToHashObject, + digest64, + digest64HashObjects, + HashObject, + hashObjectToByteArray, +} from "@chainsafe/as-sha256"; const input = new Uint8Array(64); @@ -8,14 +14,14 @@ const input = new Uint8Array(64); export function hash(a: Uint8Array, b: Uint8Array): Uint8Array { input.set(a, 0); input.set(b, 32); - return SHA256.digest64(input); + return digest64(input); } /** * Hash 2 objects, each store 8 numbers (equivalent to Uint8Array(32)) */ export function hashTwoObjects(a: HashObject, b: HashObject): HashObject { - return SHA256.digestTwoHashObjects(a, b); + return digest64HashObjects(a, b); } export function hashObjectToUint8Array(obj: HashObject): Uint8Array { diff --git a/packages/ssz/src/util/hash.ts b/packages/ssz/src/util/hash.ts index 3b619245..d455acf0 100644 --- a/packages/ssz/src/util/hash.ts +++ b/packages/ssz/src/util/hash.ts @@ -1,11 +1,11 @@ /** @module ssz */ -import SHA256, {HashObject} from "@chainsafe/as-sha256"; +import {digest, HashObject} from "@chainsafe/as-sha256"; /** * Hash used for hashTreeRoot */ export function hash(...inputs: Uint8Array[]): Uint8Array { - return SHA256.digest(Buffer.concat(inputs)); + return digest(Buffer.concat(inputs)); } /** diff --git a/tsconfig.build.json b/tsconfig.build.json index 766c32a9..189eef8e 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -3,7 +3,7 @@ "target": "es2019", "module": "commonjs", "pretty": true, - "lib": ["es2020", "esnext.bigint", "es2020.string", "es2020.symbol.wellknown"], + "lib": ["dom", "es2020", "esnext.bigint", "es2020.string", "es2020.symbol.wellknown"], "strict": true, "sourceMap": true, diff --git a/tsconfig.json b/tsconfig.json index 4f9b24d7..c5737365 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,6 +3,5 @@ "compilerOptions": { "emitDeclarationOnly": false, "incremental": false, - "noEmit": true } } diff --git a/yarn.lock b/yarn.lock index 4b4e3873..0fb65bb0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -85,11 +85,6 @@ optionalDependencies: csv-stringify "^5.3.6" -"@assemblyscript/loader@^0.9.2": - version "0.9.4" - resolved "https://registry.yarnpkg.com/@assemblyscript/loader/-/loader-0.9.4.tgz#a483c54c1253656bb33babd464e3154a173e1577" - integrity sha512-HazVq9zwTVwGmqdwYzu7WyQ6FQVZ7SwET0KKQuKm55jD0IfUpZgN0OPIiZG3zV1iSrVYcN0bdwLRXI/VNCYsUA== - "@azure/abort-controller@^1.0.0": version "1.0.4" resolved "https://registry.yarnpkg.com/@azure/abort-controller/-/abort-controller-1.0.4.tgz#fd3c4d46c8ed67aace42498c8e2270960250eafd" @@ -3802,14 +3797,6 @@ buffer@4.9.2, buffer@^4.3.0: ieee754 "^1.1.4" isarray "^1.0.0" -buffer@^5.4.3: - version "5.7.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" - integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.1.13" - buffer@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" @@ -4059,7 +4046,7 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^4.0.0, chalk@^4.1.2: +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -5373,6 +5360,14 @@ enhanced-resolve@^4.5.0: memory-fs "^0.5.0" tapable "^1.0.0" +enhanced-resolve@^5.0.0: + version "5.9.2" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz#0224dcd6a43389ebfb2d55efee517e5466772dd9" + integrity sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + enhanced-resolve@^5.8.0: version "5.8.2" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.8.2.tgz#15ddc779345cbb73e97c611cd00c01c1e7bf4d8b" @@ -6970,7 +6965,7 @@ ieee754@1.1.13: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== -ieee754@^1.1.13, ieee754@^1.1.4, ieee754@^1.2.1: +ieee754@^1.1.4, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -8356,7 +8351,7 @@ micromatch@^3.1.10, micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" -micromatch@^4.0.4: +micromatch@^4.0.0, micromatch@^4.0.4: version "4.0.4" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== @@ -11897,6 +11892,16 @@ triple-beam@^1.2.0, triple-beam@^1.3.0: dependencies: glob "^7.1.2" +ts-loader@^9.2.8: + version "9.2.8" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.2.8.tgz#e89aa32fa829c5cad0a1d023d6b3adecd51d5a48" + integrity sha512-gxSak7IHUuRtwKf3FIPSW1VpZcqF9+MBrHOvBp9cjHh+525SjtCIJKVGjRKIAfxBwDGDGCFF00rTfzB1quxdSw== + dependencies: + chalk "^4.1.0" + enhanced-resolve "^5.0.0" + micromatch "^4.0.0" + semver "^7.3.4" + ts-node@^9.1.1: version "9.1.1" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-9.1.1.tgz#51a9a450a3e959401bda5f004a72d54b936d376d"