mirror of
https://github.com/logos-messaging/js-waku.git
synced 2026-01-04 23:03:07 +00:00
feat: upgrade zerokit
This commit is contained in:
parent
94a1eb4dd6
commit
bdbe6181e2
17
package-lock.json
generated
17
package-lock.json
generated
@ -7138,15 +7138,10 @@
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@waku/zerokit-rln-wasm": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@waku/zerokit-rln-wasm/-/zerokit-rln-wasm-0.2.1.tgz",
|
||||
"integrity": "sha512-2Xp7e92y4qZpsiTPGBSVr4gVJ9mJTLaudlo0DQxNpxJUBtoJKpxdH5xDCQDiorbkWZC2j9EId+ohhxHO/xC1QQ==",
|
||||
"license": "MIT or Apache2"
|
||||
},
|
||||
"node_modules/@waku/zerokit-rln-wasm-utils": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@waku/zerokit-rln-wasm-utils/-/zerokit-rln-wasm-utils-0.1.0.tgz",
|
||||
"integrity": "sha512-3ccyg9+CtRXFJfWaxI/kx8Aec5B2S9YUmZAVhPRdN1EG6iQYG2hgvAurx8ZF9/zOppdrhzzyvCgDPg5kRUlOfQ=="
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@waku/zerokit-rln-wasm/-/zerokit-rln-wasm-1.0.0.tgz",
|
||||
"integrity": "sha512-kRAeUePAY3++i5XXniCx+tqDH+3rdfPKED/lFRrbQ8ZiNWpu059fKxtPQqqvd8jNZQUOWDc7HRTpq2TVbWd8yQ==",
|
||||
"license": "MIT OR Apache-2.0"
|
||||
},
|
||||
"node_modules/@webassemblyjs/ast": {
|
||||
"version": "1.14.1",
|
||||
@ -34727,8 +34722,7 @@
|
||||
"@wagmi/core": "^2.22.1",
|
||||
"@waku/core": "^0.0.40",
|
||||
"@waku/utils": "^0.0.27",
|
||||
"@waku/zerokit-rln-wasm": "^0.2.1",
|
||||
"@waku/zerokit-rln-wasm-utils": "^0.1.0",
|
||||
"@waku/zerokit-rln-wasm": "^1.0.0",
|
||||
"chai": "^5.1.2",
|
||||
"chai-as-promised": "^8.0.1",
|
||||
"chai-spies": "^1.1.0",
|
||||
@ -34752,6 +34746,7 @@
|
||||
"@waku/build-utils": "^1.0.0",
|
||||
"@waku/message-encryption": "^0.0.37",
|
||||
"@waku/sdk": "^0.0.36",
|
||||
"@waku/tests": "*",
|
||||
"deep-equal-in-any-order": "^2.0.6",
|
||||
"fast-check": "^3.23.2",
|
||||
"rollup-plugin-copy": "^3.5.0"
|
||||
|
||||
@ -26,7 +26,7 @@ module.exports = function (config) {
|
||||
nocache: true
|
||||
},
|
||||
{
|
||||
pattern: "src/resources/**/*.zkey",
|
||||
pattern: "src/resources/**/*.arkzkey",
|
||||
included: false,
|
||||
served: true,
|
||||
watched: false,
|
||||
@ -39,14 +39,6 @@ module.exports = function (config) {
|
||||
watched: false,
|
||||
type: "wasm",
|
||||
nocache: true
|
||||
},
|
||||
{
|
||||
pattern: "../../node_modules/@waku/zerokit-rln-wasm-utils/*.wasm",
|
||||
included: false,
|
||||
served: true,
|
||||
watched: false,
|
||||
type: "wasm",
|
||||
nocache: true
|
||||
}
|
||||
],
|
||||
|
||||
@ -68,7 +60,7 @@ module.exports = function (config) {
|
||||
|
||||
mime: {
|
||||
"application/wasm": ["wasm"],
|
||||
"application/octet-stream": ["zkey"]
|
||||
"application/octet-stream": ["arkzkey"]
|
||||
},
|
||||
|
||||
customHeaders: [
|
||||
@ -78,7 +70,7 @@ module.exports = function (config) {
|
||||
value: "application/wasm"
|
||||
},
|
||||
{
|
||||
match: ".*\\.zkey$",
|
||||
match: ".*\\.arkzkey$",
|
||||
name: "Content-Type",
|
||||
value: "application/octet-stream"
|
||||
}
|
||||
@ -91,16 +83,10 @@ module.exports = function (config) {
|
||||
__dirname,
|
||||
"../../node_modules/@waku/zerokit-rln-wasm/rln_wasm_bg.wasm"
|
||||
),
|
||||
"/base/rln_wasm_utils_bg.wasm":
|
||||
"/absolute" +
|
||||
path.resolve(
|
||||
__dirname,
|
||||
"../../node_modules/@waku/zerokit-rln-wasm-utils/rln_wasm_utils_bg.wasm"
|
||||
),
|
||||
"/base/rln.wasm":
|
||||
"/absolute" + path.resolve(__dirname, "src/resources/rln.wasm"),
|
||||
"/base/rln_final.zkey":
|
||||
"/absolute" + path.resolve(__dirname, "src/resources/rln_final.zkey")
|
||||
"/base/rln_final.arkzkey":
|
||||
"/absolute" + path.resolve(__dirname, "src/resources/rln_final.arkzkey")
|
||||
},
|
||||
|
||||
webpack: {
|
||||
@ -131,7 +117,7 @@ module.exports = function (config) {
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.zkey$/,
|
||||
test: /\.arkzkey$/,
|
||||
type: "asset/resource",
|
||||
generator: {
|
||||
filename: "[name][ext]"
|
||||
|
||||
@ -33,7 +33,7 @@ module.exports = function (config) {
|
||||
nocache: true
|
||||
},
|
||||
{
|
||||
pattern: "src/resources/**/*.zkey",
|
||||
pattern: "src/resources/**/*.arkzkey",
|
||||
included: false,
|
||||
served: true,
|
||||
watched: false,
|
||||
@ -47,14 +47,6 @@ module.exports = function (config) {
|
||||
type: "wasm",
|
||||
nocache: true
|
||||
},
|
||||
{
|
||||
pattern: "../../node_modules/@waku/zerokit-rln-wasm-utils/*.wasm",
|
||||
included: false,
|
||||
served: true,
|
||||
watched: false,
|
||||
type: "wasm",
|
||||
nocache: true
|
||||
},
|
||||
{
|
||||
// Fleet info is written by the integration test runner
|
||||
pattern: "fleet-info.json",
|
||||
@ -83,7 +75,7 @@ module.exports = function (config) {
|
||||
|
||||
mime: {
|
||||
"application/wasm": ["wasm"],
|
||||
"application/octet-stream": ["zkey"]
|
||||
"application/octet-stream": ["arkzkey"]
|
||||
},
|
||||
|
||||
customHeaders: [
|
||||
@ -93,7 +85,7 @@ module.exports = function (config) {
|
||||
value: "application/wasm"
|
||||
},
|
||||
{
|
||||
match: ".*\\.zkey$",
|
||||
match: ".*\\.arkzkey$",
|
||||
name: "Content-Type",
|
||||
value: "application/octet-stream"
|
||||
}
|
||||
@ -106,16 +98,10 @@ module.exports = function (config) {
|
||||
__dirname,
|
||||
"../../node_modules/@waku/zerokit-rln-wasm/rln_wasm_bg.wasm"
|
||||
),
|
||||
"/base/rln_wasm_utils_bg.wasm":
|
||||
"/absolute" +
|
||||
path.resolve(
|
||||
__dirname,
|
||||
"../../node_modules/@waku/zerokit-rln-wasm-utils/rln_wasm_utils_bg.wasm"
|
||||
),
|
||||
"/base/rln.wasm":
|
||||
"/absolute" + path.resolve(__dirname, "src/resources/rln.wasm"),
|
||||
"/base/rln_final.zkey":
|
||||
"/absolute" + path.resolve(__dirname, "src/resources/rln_final.zkey")
|
||||
"/base/rln_final.arkzkey":
|
||||
"/absolute" + path.resolve(__dirname, "src/resources/rln_final.arkzkey")
|
||||
},
|
||||
|
||||
webpack: {
|
||||
@ -146,7 +132,7 @@ module.exports = function (config) {
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.zkey$/,
|
||||
test: /\.arkzkey$/,
|
||||
type: "asset/resource",
|
||||
generator: {
|
||||
filename: "[name][ext]"
|
||||
|
||||
@ -85,8 +85,7 @@
|
||||
"@wagmi/core": "^2.22.1",
|
||||
"@waku/core": "^0.0.40",
|
||||
"@waku/utils": "^0.0.27",
|
||||
"@waku/zerokit-rln-wasm": "^0.2.1",
|
||||
"@waku/zerokit-rln-wasm-utils": "^0.1.0",
|
||||
"@waku/zerokit-rln-wasm": "^1.0.0",
|
||||
"chai": "^5.1.2",
|
||||
"chai-as-promised": "^8.0.1",
|
||||
"chai-spies": "^1.1.0",
|
||||
|
||||
@ -84,7 +84,7 @@ export class RLNEncoder implements IEncoder {
|
||||
0 // TODO: need to track messages sent per epoch
|
||||
);
|
||||
|
||||
return new Proof(proof, epoch, rlnIdentifier);
|
||||
return new Proof(proof.toBytesLE(), epoch, rlnIdentifier);
|
||||
}
|
||||
|
||||
public get pubsubTopic(): string {
|
||||
|
||||
@ -3,6 +3,7 @@ import { publicActions } from "viem";
|
||||
|
||||
import { RLN_CONTRACT } from "./contract/constants.js";
|
||||
import { RLNBaseContract } from "./contract/rln_base_contract.js";
|
||||
import { IdentityCredential } from "./identity.js";
|
||||
import { Keystore } from "./keystore/index.js";
|
||||
import type {
|
||||
DecryptedCredentials,
|
||||
@ -111,9 +112,10 @@ export class RLNCredentialsManager {
|
||||
|
||||
if ("signature" in options) {
|
||||
log.info("Using Zerokit to generate identity");
|
||||
identity = this.zerokit.generateSeededIdentityCredential(
|
||||
const extendedIdentity = this.zerokit.generateSeededIdentityCredential(
|
||||
options.signature
|
||||
);
|
||||
identity = IdentityCredential.fromBytes(extendedIdentity.toBytesLE());
|
||||
}
|
||||
|
||||
if (!identity) {
|
||||
|
||||
@ -133,7 +133,7 @@ describe("RLN Proof Unit Tests", function () {
|
||||
);
|
||||
|
||||
// Parse proof bytes into Proof class
|
||||
const parsedProof = new Proof(proof, epoch, rlnIdentifier);
|
||||
const parsedProof = new Proof(proof.toBytesLE(), epoch, rlnIdentifier);
|
||||
|
||||
// Verify all fields have correct lengths according to Nim format:
|
||||
// proof<128> | root<32> | external_nullifier<32> | share_x<32> | share_y<32> | nullifier<32>
|
||||
@ -154,7 +154,7 @@ describe("RLN Proof Unit Tests", function () {
|
||||
// Verify round-trip: proofToBytes should reconstruct original bytes
|
||||
const reconstructedBytes = proofToBytes(parsedProof);
|
||||
expect(reconstructedBytes).to.deep.equal(
|
||||
proof,
|
||||
proof.toBytesLE(),
|
||||
"Reconstructed bytes should match original"
|
||||
);
|
||||
|
||||
|
||||
BIN
packages/rln/src/resources/rln_final.arkzkey
Normal file
BIN
packages/rln/src/resources/rln_final.arkzkey
Normal file
Binary file not shown.
Binary file not shown.
@ -1,6 +1,5 @@
|
||||
import { Logger } from "@waku/utils";
|
||||
import init, * as zerokitRLN from "@waku/zerokit-rln-wasm";
|
||||
import initUtils from "@waku/zerokit-rln-wasm-utils";
|
||||
import init, { WasmRLN } from "@waku/zerokit-rln-wasm";
|
||||
|
||||
import { DEFAULT_RATE_LIMIT } from "./contract/constants.js";
|
||||
import { RLNCredentialsManager } from "./credentials_manager.js";
|
||||
@ -17,14 +16,12 @@ export class RLNInstance extends RLNCredentialsManager {
|
||||
*/
|
||||
public static async create(): Promise<RLNInstance> {
|
||||
try {
|
||||
await initUtils();
|
||||
await init();
|
||||
zerokitRLN.initPanicHook();
|
||||
|
||||
const witnessCalculator = await RLNInstance.loadWitnessCalculator();
|
||||
const zkey = await RLNInstance.loadZkey();
|
||||
|
||||
const zkRLN = zerokitRLN.newRLN(zkey);
|
||||
const zkRLN = new WasmRLN(zkey);
|
||||
const zerokit = new Zerokit(zkRLN, witnessCalculator, DEFAULT_RATE_LIMIT);
|
||||
|
||||
return new RLNInstance(zerokit);
|
||||
@ -63,7 +60,7 @@ export class RLNInstance extends RLNCredentialsManager {
|
||||
|
||||
public static async loadZkey(): Promise<Uint8Array> {
|
||||
try {
|
||||
const url = new URL("./resources/rln_final.zkey", import.meta.url);
|
||||
const url = new URL("./resources/rln_final.arkzkey", import.meta.url);
|
||||
const response = await fetch(url);
|
||||
|
||||
if (!response.ok) {
|
||||
|
||||
@ -1,18 +0,0 @@
|
||||
import { hash, poseidonHash as poseidon } from "@waku/zerokit-rln-wasm-utils";
|
||||
|
||||
import { BytesUtils } from "./bytes.js";
|
||||
|
||||
export function poseidonHash(...input: Array<Uint8Array>): Uint8Array {
|
||||
const inputLen = BytesUtils.writeUIntLE(
|
||||
new Uint8Array(8),
|
||||
input.length,
|
||||
0,
|
||||
8
|
||||
);
|
||||
const lenPrefixedData = BytesUtils.concatenate(inputLen, ...input);
|
||||
return poseidon(lenPrefixedData, true);
|
||||
}
|
||||
|
||||
export function sha256(input: Uint8Array): Uint8Array {
|
||||
return hash(input, true);
|
||||
}
|
||||
@ -1,6 +1,5 @@
|
||||
export { createViemClientFromWindow, RpcClient } from "./rpcClient.js";
|
||||
export { BytesUtils } from "./bytes.js";
|
||||
export { sha256, poseidonHash } from "./hash.js";
|
||||
export {
|
||||
dateToEpoch,
|
||||
epochIntToBytes,
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { Hasher, WasmFr } from "@waku/zerokit-rln-wasm";
|
||||
|
||||
import { BytesUtils } from "./bytes.js";
|
||||
import { poseidonHash } from "./hash.js";
|
||||
|
||||
/**
|
||||
* The fixed depth of the Merkle tree used in the RLN contract
|
||||
@ -26,23 +27,27 @@ export function reconstructMerkleRoot(
|
||||
);
|
||||
}
|
||||
|
||||
let currentValue = BytesUtils.bytes32FromBigInt(leafValue);
|
||||
let currentValue = WasmFr.fromBytesLE(
|
||||
BytesUtils.bytes32FromBigInt(leafValue)
|
||||
);
|
||||
|
||||
for (let level = 0; level < MERKLE_TREE_DEPTH; level++) {
|
||||
const bit = (leafIndex >> BigInt(level)) & 1n;
|
||||
|
||||
const proofBytes = BytesUtils.bytes32FromBigInt(proof[level]);
|
||||
const proofFr = WasmFr.fromBytesLE(
|
||||
BytesUtils.bytes32FromBigInt(proof[level])
|
||||
);
|
||||
|
||||
if (bit === 0n) {
|
||||
// Current node is a left child: hash(current, proof[level])
|
||||
currentValue = poseidonHash(currentValue, proofBytes);
|
||||
currentValue = Hasher.poseidonHashPair(currentValue, proofFr);
|
||||
} else {
|
||||
// Current node is a right child: hash(proof[level], current)
|
||||
currentValue = poseidonHash(proofBytes, currentValue);
|
||||
currentValue = Hasher.poseidonHashPair(proofFr, currentValue);
|
||||
}
|
||||
}
|
||||
|
||||
return BytesUtils.toBigInt(currentValue, "little");
|
||||
return BytesUtils.toBigInt(currentValue.toBytesLE(), "little");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -60,8 +65,11 @@ export function calculateRateCommitment(
|
||||
const idBytes = BytesUtils.bytes32FromBigInt(idCommitment);
|
||||
const rateLimitBytes = BytesUtils.bytes32FromBigInt(rateLimit);
|
||||
|
||||
const hashResult = poseidonHash(idBytes, rateLimitBytes);
|
||||
return BytesUtils.toBigInt(hashResult, "little");
|
||||
const hashResult = Hasher.poseidonHashPair(
|
||||
WasmFr.fromBytesLE(idBytes),
|
||||
WasmFr.fromBytesLE(rateLimitBytes)
|
||||
);
|
||||
return BytesUtils.toBigInt(hashResult.toBytesLE(), "little");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -10,17 +10,29 @@ describe("@waku/rln", () => {
|
||||
const memKeys1 = rlnInstance.zerokit.generateSeededIdentityCredential(seed);
|
||||
const memKeys2 = rlnInstance.zerokit.generateSeededIdentityCredential(seed);
|
||||
|
||||
memKeys1.IDCommitment.forEach((element, index) => {
|
||||
expect(element).to.equal(memKeys2.IDCommitment[index]);
|
||||
});
|
||||
memKeys1.IDNullifier.forEach((element, index) => {
|
||||
expect(element).to.equal(memKeys2.IDNullifier[index]);
|
||||
});
|
||||
memKeys1.IDSecretHash.forEach((element, index) => {
|
||||
expect(element).to.equal(memKeys2.IDSecretHash[index]);
|
||||
});
|
||||
memKeys1.IDTrapdoor.forEach((element, index) => {
|
||||
expect(element).to.equal(memKeys2.IDTrapdoor[index]);
|
||||
});
|
||||
memKeys1
|
||||
.getCommitment()
|
||||
.toBytesLE()
|
||||
.forEach((element, index) => {
|
||||
expect(element).to.equal(memKeys2.getCommitment().toBytesLE()[index]);
|
||||
});
|
||||
memKeys1
|
||||
.getNullifier()
|
||||
.toBytesLE()
|
||||
.forEach((element, index) => {
|
||||
expect(element).to.equal(memKeys2.getNullifier().toBytesLE()[index]);
|
||||
});
|
||||
memKeys1
|
||||
.getSecretHash()
|
||||
.toBytesLE()
|
||||
.forEach((element, index) => {
|
||||
expect(element).to.equal(memKeys2.getSecretHash().toBytesLE()[index]);
|
||||
});
|
||||
memKeys1
|
||||
.getTrapdoor()
|
||||
.toBytesLE()
|
||||
.forEach((element, index) => {
|
||||
expect(element).to.equal(memKeys2.getTrapdoor().toBytesLE()[index]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,17 +1,21 @@
|
||||
import * as zerokitRLN from "@waku/zerokit-rln-wasm";
|
||||
import { generateSeededExtendedMembershipKey } from "@waku/zerokit-rln-wasm-utils";
|
||||
import {
|
||||
ExtendedIdentity,
|
||||
Hasher,
|
||||
VecWasmFr,
|
||||
WasmFr,
|
||||
WasmRLN,
|
||||
WasmRLNProof,
|
||||
WasmRLNWitnessInput
|
||||
} from "@waku/zerokit-rln-wasm";
|
||||
|
||||
import { DEFAULT_RATE_LIMIT, RATE_LIMIT_PARAMS } from "./contract/constants.js";
|
||||
import { IdentityCredential } from "./identity.js";
|
||||
import { WitnessCalculator } from "./resources/witness_calculator";
|
||||
import { BytesUtils } from "./utils/bytes.js";
|
||||
import { dateToEpochBytes } from "./utils/epoch.js";
|
||||
import { poseidonHash, sha256 } from "./utils/hash.js";
|
||||
import { MERKLE_TREE_DEPTH } from "./utils/merkle.js";
|
||||
|
||||
export class Zerokit {
|
||||
public constructor(
|
||||
private readonly zkRLN: number,
|
||||
private readonly zkRLN: WasmRLN,
|
||||
private readonly witnessCalculator: WitnessCalculator,
|
||||
public readonly rateLimit: number = DEFAULT_RATE_LIMIT,
|
||||
public readonly rlnIdentifier: Uint8Array = (() => {
|
||||
@ -22,63 +26,14 @@ export class Zerokit {
|
||||
})()
|
||||
) {}
|
||||
|
||||
public get getZkRLN(): number {
|
||||
return this.zkRLN;
|
||||
}
|
||||
|
||||
public get getWitnessCalculator(): WitnessCalculator {
|
||||
return this.witnessCalculator;
|
||||
}
|
||||
|
||||
public generateSeededIdentityCredential(seed: string): IdentityCredential {
|
||||
public generateSeededIdentityCredential(seed: string): ExtendedIdentity {
|
||||
const stringEncoder = new TextEncoder();
|
||||
const seedBytes = stringEncoder.encode(seed);
|
||||
const memKeys = generateSeededExtendedMembershipKey(seedBytes, true);
|
||||
return IdentityCredential.fromBytes(memKeys);
|
||||
}
|
||||
|
||||
private async serializeWitness(
|
||||
idSecretHash: Uint8Array,
|
||||
pathElements: Uint8Array[],
|
||||
identityPathIndex: Uint8Array[],
|
||||
msg: Uint8Array,
|
||||
epoch: Uint8Array,
|
||||
rateLimit: number,
|
||||
messageId: number // number of message sent by the user in this epoch
|
||||
): Promise<Uint8Array> {
|
||||
const externalNullifier = poseidonHash(
|
||||
sha256(epoch),
|
||||
sha256(this.rlnIdentifier)
|
||||
);
|
||||
const pathElementsBytes = new Uint8Array(8 + pathElements.length * 32);
|
||||
BytesUtils.writeUIntLE(pathElementsBytes, pathElements.length, 0, 8);
|
||||
for (let i = 0; i < pathElements.length; i++) {
|
||||
// We assume that the path elements are already in little-endian format
|
||||
pathElementsBytes.set(pathElements[i], 8 + i * 32);
|
||||
}
|
||||
const identityPathIndexBytes = new Uint8Array(
|
||||
8 + identityPathIndex.length * 1
|
||||
);
|
||||
BytesUtils.writeUIntLE(
|
||||
identityPathIndexBytes,
|
||||
identityPathIndex.length,
|
||||
0,
|
||||
8
|
||||
);
|
||||
for (let i = 0; i < identityPathIndex.length; i++) {
|
||||
// We assume that each identity path index is already in little-endian format
|
||||
identityPathIndexBytes.set(identityPathIndex[i], 8 + i * 1);
|
||||
}
|
||||
const x = sha256(msg);
|
||||
return BytesUtils.concatenate(
|
||||
idSecretHash,
|
||||
BytesUtils.writeUIntLE(new Uint8Array(32), rateLimit, 0, 32),
|
||||
BytesUtils.writeUIntLE(new Uint8Array(32), messageId, 0, 32),
|
||||
pathElementsBytes,
|
||||
identityPathIndexBytes,
|
||||
x,
|
||||
externalNullifier
|
||||
);
|
||||
return ExtendedIdentity.generateSeeded(seedBytes);
|
||||
}
|
||||
|
||||
public async generateRLNProof(
|
||||
@ -90,7 +45,7 @@ export class Zerokit {
|
||||
rateLimit: number,
|
||||
messageId: number // number of message sent by the user in this epoch
|
||||
): Promise<{
|
||||
proof: Uint8Array;
|
||||
proof: WasmRLNProof;
|
||||
epoch: Uint8Array;
|
||||
rlnIdentifier: Uint8Array;
|
||||
}> {
|
||||
@ -120,26 +75,37 @@ export class Zerokit {
|
||||
`messageId must be an integer between 0 and ${rateLimit - 1}, got ${messageId}`
|
||||
);
|
||||
}
|
||||
|
||||
const serializedWitness = await this.serializeWitness(
|
||||
idSecretHash,
|
||||
pathElements,
|
||||
identityPathIndex,
|
||||
msg,
|
||||
epoch,
|
||||
rateLimit,
|
||||
messageId
|
||||
const pathElementsVec = new VecWasmFr();
|
||||
for (const element of pathElements) {
|
||||
pathElementsVec.push(WasmFr.fromBytesLE(element));
|
||||
}
|
||||
const identityPathIndexBytes = new Uint8Array(identityPathIndex.length);
|
||||
for (let i = 0; i < identityPathIndex.length; i++) {
|
||||
// We assume that each identity path index is already in little-endian format
|
||||
identityPathIndexBytes.set(identityPathIndex[i], i);
|
||||
}
|
||||
const x = Hasher.hashToFieldLE(msg);
|
||||
const externalNullifier = Hasher.poseidonHashPair(
|
||||
Hasher.hashToFieldLE(epoch),
|
||||
Hasher.hashToFieldLE(this.rlnIdentifier)
|
||||
);
|
||||
const witnessJson: Record<string, unknown> = zerokitRLN.rlnWitnessToJson(
|
||||
this.zkRLN,
|
||||
serializedWitness
|
||||
) as Record<string, unknown>;
|
||||
const witness = new WasmRLNWitnessInput(
|
||||
WasmFr.fromBytesLE(idSecretHash),
|
||||
WasmFr.fromUint(rateLimit),
|
||||
WasmFr.fromUint(messageId),
|
||||
pathElementsVec,
|
||||
identityPathIndexBytes,
|
||||
x,
|
||||
externalNullifier
|
||||
);
|
||||
|
||||
const calculatedWitness: bigint[] =
|
||||
await this.witnessCalculator.calculateWitness(witnessJson);
|
||||
const proof = zerokitRLN.generateRLNProofWithWitness(
|
||||
this.zkRLN,
|
||||
await this.witnessCalculator.calculateWitness(
|
||||
witness.toBigIntJson() as Record<string, unknown>
|
||||
);
|
||||
const proof = this.zkRLN.generateRLNProofWithWitness(
|
||||
calculatedWitness,
|
||||
serializedWitness
|
||||
witness
|
||||
);
|
||||
return {
|
||||
proof,
|
||||
@ -151,21 +117,21 @@ export class Zerokit {
|
||||
public verifyRLNProof(
|
||||
signalLength: Uint8Array,
|
||||
signal: Uint8Array,
|
||||
proof: Uint8Array,
|
||||
proof: WasmRLNProof,
|
||||
roots: Uint8Array[]
|
||||
): boolean {
|
||||
if (signalLength.length !== 8)
|
||||
throw new Error("signalLength must be 8 bytes");
|
||||
if (proof.length !== 288) throw new Error("proof must be 288 bytes");
|
||||
if (roots.length == 0) throw new Error("roots array is empty");
|
||||
if (roots.find((root) => root.length !== 32)) {
|
||||
throw new Error("All roots must be 32 bytes");
|
||||
}
|
||||
|
||||
return zerokitRLN.verifyWithRoots(
|
||||
this.zkRLN,
|
||||
BytesUtils.concatenate(proof, signalLength, signal),
|
||||
BytesUtils.concatenate(...roots)
|
||||
);
|
||||
const rootsVec = new VecWasmFr();
|
||||
for (const root of roots) {
|
||||
rootsVec.push(WasmFr.fromBytesLE(root));
|
||||
}
|
||||
const x = Hasher.hashToFieldLE(signal);
|
||||
return this.zkRLN.verifyWithRoots(proof, rootsVec, x);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user