From 9ea8676d24b65a23b91bf4bcf8c9cf1ae2f3f6d4 Mon Sep 17 00:00:00 2001 From: realaravinth Date: Wed, 8 Dec 2021 13:43:24 +0530 Subject: [PATCH] pow_sha256 serializes the phrase on which the proof is to be computed using the bincode crate, which uses UTF-8 under the hood and also prefixes the length of the string in big endian. This patch introduces changes to implement the same --- jest.config.ts | 4 +++- src/index.ts | 33 ++++++++++++++++++++++++++++----- src/test.ts | 29 ++++++++++++++++++----------- 3 files changed, 49 insertions(+), 17 deletions(-) diff --git a/jest.config.ts b/jest.config.ts index eaabac1..61aa637 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -2,7 +2,6 @@ * For a detailed explanation regarding each configuration property and type check, visit: * https://jestjs.io/docs/en/configuration.html */ - export default { // All imported modules in your tests should be mocked automatically // automock: false, @@ -16,6 +15,8 @@ export default { // Automatically clear mock calls and instances between every test clearMocks: true, + testTimeout: 300000, + // Indicates whether the coverage information should be collected while executing the test collectCoverage: true, @@ -31,6 +32,7 @@ export default { "setupTests.ts", "setUpTests.ts", "jest.setup.ts", + "test-data.ts", ], // Indicates which provider should be used to instrument code for coverage diff --git a/src/index.ts b/src/index.ts index 2fc5244..9c1b456 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,6 +10,29 @@ */ const U128_MAX = 340282366920938463463374607431768211455n; +const encoder = new TextEncoder(); +const decoder = new TextDecoder("utf-8"); + +const length_metadata = (len: number): number[] => { + return [ + (len & 0x00000000000000ff) >> 0, + (len & 0x000000000000ff00) >> 8, + (len & 0x0000000000ff0000) >> 16, + (len & 0x00000000ff000000) >> 24, + (len & 0x000000ff00000000) >> 32, + (len & 0x0000ff000000000) >> 48, + (len & 0x00ff00000000000) >> 56, + Number((BigInt(len) & 0xff0000000000000n) >> BigInt(64)), + ]; +}; + +const serialize = (message: string): Uint8Array => { + const len_encoded = length_metadata(message.length); + const msgUint8 = new Uint8Array( + len_encoded.concat(Array.from(encoder.encode(message))) + ); + return msgUint8; +}; /** * Compute SHA-256 digest of a string @@ -17,8 +40,8 @@ const U128_MAX = 340282366920938463463374607431768211455n; * @returns {number[]} - byte array of the hash **/ export const digest = async (message: string): Promise => { - const msgUint8 = new TextEncoder().encode(message); - msgUint8; + const msgUint8 = encoder.encode(message); + const hashBuffer = await crypto.subtle.digest("SHA-256", msgUint8); const hashArray = Array.from(new Uint8Array(hashBuffer)); return hashArray; @@ -65,11 +88,11 @@ export const generate_work = async ( phrase: string, difficulty: number ): Promise => { - const base = salt + phrase; + const serialized_phrase = decoder.decode(serialize(phrase)); + const base = salt + serialized_phrase; let nonce = 0; let result: BigInt = BigInt(0); - const difficulty_new = U128_MAX - (U128_MAX / BigInt(difficulty)); - console.log(difficulty_new==340275561273600044694105339939619576091n); + const difficulty_new = U128_MAX - U128_MAX / BigInt(difficulty); while (result < difficulty_new) { nonce += 1; const hash = await digest(base + nonce.toString()); diff --git a/src/test.ts b/src/test.ts index 1ed8cb9..2539fa5 100644 --- a/src/test.ts +++ b/src/test.ts @@ -3,20 +3,27 @@ import { DATA, DIFFICULTY, SALT } from "./test-data"; ("use strict"); -it("Everything works", async () => { +test("Proof generation works", async () => { for (let i = 0; i < DATA.length; i++) { const d = DATA[i]; try { - const res = await digest(d.phrase); - expect(res).toStrictEqual(d.hash); - //expect(await w.digest(d.phrase)).toBe(d.hash); - expect(score(d.hash)).toBe(d.difficulty); - //let proof = await generate_work(SALT, d.phrase, DIFFICULTY); - //console.log( - // `saved nonce:${d.pow.nonce} proof result: ${proof.result}proof nonce: ${proof.nonce}` - //); - //expect(proof.nonce).toBe(d.pow.nonce); - //expect(proof.result).toBe(d.pow.result); + const proof = await generate_work(SALT, d.phrase, DIFFICULTY); + expect(proof.nonce).toBe(d.pow.nonce); + expect(proof.result).toBe(`${d.pow.result}`); + } catch (error) { + console.log(`${d.pow.nonce}${error}`); + throw error; + } + } +}); + +test("Digest works", async () => { + for (let i = 0; i < DATA.length; i++) { + const d = DATA[i]; + try { + const res = await digest(d.phrase); + expect(res).toStrictEqual(d.hash); + expect(score(d.hash)).toBe(d.difficulty); } catch (error) { console.log(`${d.pow.nonce}${error}`); throw error;