Merge pull request #16 from mCaptcha/feat-incremental
feat: incremental proof of work computing fn
This commit is contained in:
commit
b0111bde6e
2 changed files with 77 additions and 4 deletions
49
src/index.ts
49
src/index.ts
|
@ -4,7 +4,7 @@
|
||||||
* Copyright © 2021 Aravinth Manivnanan <realaravinth@batsense.net>.
|
* Copyright © 2021 Aravinth Manivnanan <realaravinth@batsense.net>.
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by Apache 2.0 or MIT license.
|
* Use of this source code is governed by Apache 2.0 or MIT license.
|
||||||
* You shoud have received a copy of MIT and Apache 2.0 along with
|
* You should have received a copy of MIT and Apache 2.0 along with
|
||||||
* this program. If not, see <https://spdx.org/licenses/MIT.html> for
|
* this program. If not, see <https://spdx.org/licenses/MIT.html> for
|
||||||
* MIT or <http://www.apache.org/licenses/LICENSE-2.0> for Apache.
|
* MIT or <http://www.apache.org/licenses/LICENSE-2.0> for Apache.
|
||||||
*/
|
*/
|
||||||
|
@ -51,7 +51,7 @@ export const digest = async (message: string): Promise<number[]> => {
|
||||||
* Calculate difficulty of a hash
|
* Calculate difficulty of a hash
|
||||||
*
|
*
|
||||||
* @param {number[]} hash - hash for which difficulty should be calculated
|
* @param {number[]} hash - hash for which difficulty should be calculated
|
||||||
* @returns {BigInt} - diffuclty of the given hash
|
* @returns {BigInt} - difficulty of the given hash
|
||||||
*/
|
*/
|
||||||
export const score = (hash: number[]): BigInt => {
|
export const score = (hash: number[]): BigInt => {
|
||||||
let sum = BigInt(0);
|
let sum = BigInt(0);
|
||||||
|
@ -75,7 +75,7 @@ export type WasmWork = {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate Proof-of-Work(PoW) according to the algorithim used in mCaptcha
|
* Generate Proof-of-Work(PoW) according to the algorithm used in mCaptcha
|
||||||
*
|
*
|
||||||
* @param {string} salt - salt used in PoW computation. Will be provided in PoW requirement
|
* @param {string} salt - salt used in PoW computation. Will be provided in PoW requirement
|
||||||
* @param {string} phrase - challenge phrase used in PoW computation. Will be provided in PoW requirement
|
* @param {string} phrase - challenge phrase used in PoW computation. Will be provided in PoW requirement
|
||||||
|
@ -105,3 +105,46 @@ export const generate_work = async (
|
||||||
};
|
};
|
||||||
return work;
|
return work;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate Proof-of-Work(PoW) according to the algorithm used in mCaptcha incrementally
|
||||||
|
*
|
||||||
|
* @param {string} salt - salt used in PoW computation. Will be provided in PoW requirement
|
||||||
|
* @param {string} phrase - challenge phrase used in PoW computation. Will be provided in PoW requirement
|
||||||
|
* @param {number} difficulty - target difficulty for which PoW should be generated. Will be provided in PoW requirement
|
||||||
|
* @param {number} step - notify progress with nonce after 'n' number of steps
|
||||||
|
* @param {(nonce: number) => void} fn - callback function to notify progress
|
||||||
|
*
|
||||||
|
* @returns {Promise<WasmWork>} - proof-of-work
|
||||||
|
**/
|
||||||
|
export const stepped_generate_work = async (
|
||||||
|
salt: string,
|
||||||
|
phrase: string,
|
||||||
|
difficulty: number,
|
||||||
|
step: number,
|
||||||
|
fn: (nonce: number) => void,
|
||||||
|
): Promise<WasmWork> => {
|
||||||
|
const serialized_phrase = decoder.decode(serialize(phrase));
|
||||||
|
const base = salt + serialized_phrase;
|
||||||
|
let nonce = 0;
|
||||||
|
let result: BigInt = BigInt(0);
|
||||||
|
const difficulty_new: BigInt = U128_MAX - U128_MAX / BigInt(difficulty);
|
||||||
|
let count = 0;
|
||||||
|
while (result < difficulty_new) {
|
||||||
|
if (count < step) {
|
||||||
|
nonce += 1;
|
||||||
|
const hash = await digest(base + nonce.toString());
|
||||||
|
result = score(hash);
|
||||||
|
count+=1;
|
||||||
|
} else {
|
||||||
|
fn(nonce);
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const work: WasmWork = {
|
||||||
|
result: result.toString(),
|
||||||
|
nonce,
|
||||||
|
};
|
||||||
|
return work;
|
||||||
|
};
|
||||||
|
|
32
src/test.ts
32
src/test.ts
|
@ -1,4 +1,4 @@
|
||||||
import { digest, score, generate_work } from "./index";
|
import { digest, score, generate_work, stepped_generate_work } from "./index";
|
||||||
import { DATA, DIFFICULTY, SALT } from "./test-data";
|
import { DATA, DIFFICULTY, SALT } from "./test-data";
|
||||||
|
|
||||||
("use strict");
|
("use strict");
|
||||||
|
@ -30,3 +30,33 @@ test("Digest works", async () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("Incremental proof generation works", async () => {
|
||||||
|
for (let i = 0; i < DATA.length; i++) {
|
||||||
|
const d = DATA[i];
|
||||||
|
let last_nonce = 0;
|
||||||
|
const step = 1000;
|
||||||
|
let fnExecuted = false;
|
||||||
|
const fn = (n: number): void => {
|
||||||
|
expect(last_nonce + step).toBe(n);
|
||||||
|
last_nonce = n;
|
||||||
|
fnExecuted = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const proof = await stepped_generate_work(
|
||||||
|
SALT,
|
||||||
|
d.phrase,
|
||||||
|
DIFFICULTY,
|
||||||
|
1000,
|
||||||
|
fn
|
||||||
|
);
|
||||||
|
expect(proof.nonce).toBe(d.pow.nonce);
|
||||||
|
expect(proof.result).toBe(`${d.pow.result}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(`${d.pow.nonce}${error}`);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
expect(fnExecuted).toBeTruthy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
Loading…
Reference in a new issue