fix: idCommitmentBigInt must always be less than the contract Q (#2394)

* chore: idCommitmentBigInt validates against contract Q

* chore: fix linting

* chore: add log

* chore: rename Q and make sync

* fix: test

* chore: remove stubbed contract test

* chore: hardcode default constant for Q

* use non deprecated sha256

* chore: use full 32 bytes for bigint

* chore: all storage in LE, but smart contract interactions in BE

* chore: remove references to idCOmmitmentBigInt in Identity

* chore: don't fetch Q from contract

* chore: ByteUtils as a class

* chore: store Identity in BE, convert during Keystore

* chore: add IDCommitmentBigInt part of Identity

* chore: minor improvements

* chore: switch idTrapdoor to LE

* chore: add logs

* chore: rename `DEFAULT_Q` to `RLN_Q`

* chore: rm spec test

* chore: improve modulo logging

* fix(tests): add IDCommitmentBigInt
This commit is contained in:
Danish Arora 2025-07-14 16:35:34 +05:30 committed by GitHub
parent 5d8cfff7eb
commit 9b0c5e8311
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 303 additions and 183 deletions

View File

@ -25,4 +25,13 @@ export const RATE_LIMIT_PARAMS = {
EPOCH_LENGTH: 600 // Epoch length in seconds (10 minutes)
} as const;
/**
* Default Q value for the RLN contract
* This is the upper bound for the ID commitment
* @see https://github.com/waku-org/specs/blob/master/standards/core/rln-contract.md#implementation-suggestions
*/
export const RLN_Q = BigInt(
"21888242871839275222246405745257275088548364400416034343698204186575808495617"
);
export const DEFAULT_RATE_LIMIT = RATE_LIMIT_PARAMS.MAX_RATE;

View File

@ -3,6 +3,7 @@ import { ethers } from "ethers";
import { IdentityCredential } from "../identity.js";
import { DecryptedCredentials } from "../keystore/types.js";
import { BytesUtils } from "../utils/bytes.js";
import { RLN_ABI } from "./abi.js";
import { DEFAULT_RATE_LIMIT, RATE_LIMIT_PARAMS } from "./constants.js";
@ -490,7 +491,6 @@ export class RLNBaseContract {
log.error(`Error in withdraw: ${(error as Error).message}`);
}
}
public async registerWithIdentity(
identity: IdentityCredential
): Promise<DecryptedCredentials | undefined> {
@ -529,7 +529,9 @@ export class RLNBaseContract {
identity.IDCommitmentBigInt,
this.rateLimit,
[],
{ gasLimit }
{
gasLimit
}
);
const txRegisterReceipt = await txRegisterResponse.wait();
@ -626,7 +628,7 @@ export class RLNBaseContract {
permit.v,
permit.r,
permit.s,
identity.IDCommitmentBigInt,
BytesUtils.buildBigIntFromUint8ArrayBE(identity.IDCommitment),
this.rateLimit,
idCommitmentsToErase.map((id) => ethers.BigNumber.from(id))
);

View File

@ -4,13 +4,13 @@ import chaiAsPromised from "chai-as-promised";
import * as ethers from "ethers";
import sinon, { SinonSandbox } from "sinon";
import { createTestRLNInstance, initializeRLNContract } from "./test-setup.js";
import { createTestRLNInstance, initializeRLNContract } from "./test_setup.js";
import {
createMockRegistryContract,
createRegisterStub,
mockRLNRegisteredEvent,
verifyRegistration
} from "./test-utils.js";
} from "./test_utils.js";
use(chaiAsPromised);

View File

@ -4,7 +4,7 @@ import { ethers } from "ethers";
import type { RLNInstance } from "../rln.js";
import { MerkleRootTracker } from "../root_tracker.js";
import { zeroPadLE } from "../utils/bytes.js";
import { BytesUtils } from "../utils/bytes.js";
import { RLNBaseContract } from "./rln_base_contract.js";
import { RLNContractInitOptions } from "./types.js";
@ -110,7 +110,10 @@ export class RLNContract extends RLNBaseContract {
index = ethers.BigNumber.from(index);
}
const idCommitment = zeroPadLE(hexToBytes(_idCommitment), 32);
const idCommitment = BytesUtils.zeroPadLE(
hexToBytes(_idCommitment),
32
);
rlnInstance.zerokit.insertMember(idCommitment);
const numericIndex = index.toNumber();

View File

@ -83,4 +83,4 @@ export const TEST_DATA = {
),
mockSignature:
"0xdeb8a6b00a8e404deb1f52d3aa72ed7f60a2ff4484c737eedaef18a0aacb2dfb4d5d74ac39bb71fa358cf2eb390565a35b026cc6272f2010d4351e17670311c21c"
} as const;
};

View File

@ -1,9 +1,9 @@
import { hmac } from "@noble/hashes/hmac";
import { sha256 } from "@noble/hashes/sha256";
import { sha256 } from "@noble/hashes/sha2";
import { Logger } from "@waku/utils";
import { ethers } from "ethers";
import { LINEA_CONTRACT } from "./contract/constants.js";
import { LINEA_CONTRACT, RLN_Q } from "./contract/constants.js";
import { RLNBaseContract } from "./contract/rln_base_contract.js";
import { IdentityCredential } from "./identity.js";
import { Keystore } from "./keystore/index.js";
@ -13,10 +13,8 @@ import type {
} from "./keystore/index.js";
import { KeystoreEntity, Password } from "./keystore/types.js";
import { RegisterMembershipOptions, StartRLNOptions } from "./types.js";
import {
buildBigIntFromUint8Array,
extractMetaMaskSigner
} from "./utils/index.js";
import { BytesUtils } from "./utils/bytes.js";
import { extractMetaMaskSigner } from "./utils/index.js";
import { Zerokit } from "./zerokit.js";
const log = new Logger("waku:credentials");
@ -116,7 +114,9 @@ export class RLNCredentialsManager {
);
} else {
log.info("Using local implementation to generate identity");
identity = this.generateSeededIdentityCredential(options.signature);
identity = await this.generateSeededIdentityCredential(
options.signature
);
}
}
@ -249,7 +249,9 @@ export class RLNCredentialsManager {
* @param seed A string seed to generate the identity from
* @returns IdentityCredential
*/
private generateSeededIdentityCredential(seed: string): IdentityCredential {
private async generateSeededIdentityCredential(
seed: string
): Promise<IdentityCredential> {
log.info("Generating seeded identity credential");
// Convert the seed to bytes
const encoder = new TextEncoder();
@ -257,26 +259,38 @@ export class RLNCredentialsManager {
// Generate deterministic values using HMAC-SHA256
// We use different context strings for each component to ensure they're different
const idTrapdoor = hmac(sha256, seedBytes, encoder.encode("IDTrapdoor"));
const idNullifier = hmac(sha256, seedBytes, encoder.encode("IDNullifier"));
const idTrapdoorBE = hmac(sha256, seedBytes, encoder.encode("IDTrapdoor"));
const idNullifierBE = hmac(
sha256,
seedBytes,
encoder.encode("IDNullifier")
);
// Generate IDSecretHash as a hash of IDTrapdoor and IDNullifier
const combinedBytes = new Uint8Array([...idTrapdoor, ...idNullifier]);
const idSecretHash = sha256(combinedBytes);
const combinedBytes = new Uint8Array([...idTrapdoorBE, ...idNullifierBE]);
const idSecretHashBE = sha256(combinedBytes);
// Generate IDCommitment as a hash of IDSecretHash
const idCommitment = sha256(idSecretHash);
const idCommitmentRawBE = sha256(idSecretHashBE);
const idCommitmentBE = this.reduceIdCommitment(idCommitmentRawBE);
// Convert IDCommitment to BigInt
const idCommitmentBigInt = buildBigIntFromUint8Array(idCommitment);
log.info("Successfully generated identity credential");
log.info(
"Successfully generated identity credential, storing in Big Endian format"
);
return new IdentityCredential(
idTrapdoor,
idNullifier,
idSecretHash,
idCommitment,
idCommitmentBigInt
idTrapdoorBE,
idNullifierBE,
idSecretHashBE,
idCommitmentBE
);
}
/**
* Helper: take 32-byte BE, reduce mod Q, return 32-byte BE
*/
private reduceIdCommitment(
bytesBE: Uint8Array,
limit: bigint = RLN_Q
): Uint8Array {
const nBE = BytesUtils.buildBigIntFromUint8ArrayBE(bytesBE);
return BytesUtils.bigIntToUint8Array32BE(nBE % limit);
}
}

View File

@ -1,13 +1,19 @@
import { buildBigIntFromUint8Array } from "./utils/index.js";
import { BytesUtils } from "./utils/bytes.js";
export class IdentityCredential {
public IDCommitmentBigInt: bigint;
/**
* All variables are in little-endian format
*/
public constructor(
public readonly IDTrapdoor: Uint8Array,
public readonly IDNullifier: Uint8Array,
public readonly IDSecretHash: Uint8Array,
public readonly IDCommitment: Uint8Array,
public readonly IDCommitmentBigInt: bigint
) {}
public readonly IDCommitment: Uint8Array
) {
this.IDCommitmentBigInt =
BytesUtils.buildBigIntFromUint8ArrayBE(IDCommitment);
}
public static fromBytes(memKeys: Uint8Array): IdentityCredential {
if (memKeys.length < 128) {
@ -18,14 +24,12 @@ export class IdentityCredential {
const idNullifier = memKeys.subarray(32, 64);
const idSecretHash = memKeys.subarray(64, 96);
const idCommitment = memKeys.subarray(96, 128);
const idCommitmentBigInt = buildBigIntFromUint8Array(idCommitment, 32);
return new IdentityCredential(
idTrapdoor,
idNullifier,
idSecretHash,
idCommitment,
idCommitmentBigInt
idCommitment
);
}
}

View File

@ -8,7 +8,7 @@ use(deepEqualInAnyOrder);
use(chaiAsPromised);
import { IdentityCredential } from "../identity.js";
import { buildBigIntFromUint8Array } from "../utils/bytes.js";
import { BytesUtils } from "../utils/bytes.js";
import { Keystore } from "./keystore.js";
import type { KeystoreMembershipInfo } from "./types.js";
@ -219,15 +219,12 @@ describe("Keystore", () => {
IDCommitment: new Uint8Array([
112, 216, 27, 89, 188, 135, 203, 19, 168, 211, 117, 13, 231, 135, 229,
58, 94, 20, 246, 8, 33, 65, 238, 37, 112, 97, 65, 241, 255, 93, 171, 15
]),
IDCommitmentBigInt: buildBigIntFromUint8Array(
new Uint8Array([
112, 216, 27, 89, 188, 135, 203, 19, 168, 211, 117, 13, 231, 135, 229,
58, 94, 20, 246, 8, 33, 65, 238, 37, 112, 97, 65, 241, 255, 93, 171,
15
])
)
])
} as unknown as IdentityCredential;
// Add the missing property for test correctness
identity.IDCommitmentBigInt = BytesUtils.buildBigIntFromUint8ArrayBE(
identity.IDCommitment
);
const membership = {
chainId: "0xAA36A7",
treeIndex: 8,
@ -279,6 +276,9 @@ describe("Keystore", () => {
58, 94, 20, 246, 8, 33, 65, 238, 37, 112, 97, 65, 241, 255, 93, 171, 15
]
} as unknown as IdentityCredential;
identity.IDCommitmentBigInt = BytesUtils.buildBigIntFromUint8ArrayBE(
identity.IDCommitment
);
const membership = {
chainId: "0xAA36A7",
treeIndex: 8,

View File

@ -14,7 +14,7 @@ import {
import _ from "lodash";
import { v4 as uuidV4 } from "uuid";
import { buildBigIntFromUint8Array } from "../utils/bytes.js";
import { BytesUtils } from "../utils/bytes.js";
import { decryptEipKeystore, keccak256Checksum } from "./cipher.js";
import { isCredentialValid, isKeystoreValid } from "./schema_validator.js";
@ -250,26 +250,35 @@ export class Keystore {
const str = bytesToUtf8(bytes);
const obj = JSON.parse(str);
// TODO: add runtime validation of nwaku credentials
// Little Endian
const idCommitmentLE = Keystore.fromArraylikeToBytes(
_.get(obj, "identityCredential.idCommitment", [])
);
const idTrapdoorLE = Keystore.fromArraylikeToBytes(
_.get(obj, "identityCredential.idTrapdoor", [])
);
const idNullifierLE = Keystore.fromArraylikeToBytes(
_.get(obj, "identityCredential.idNullifier", [])
);
const idSecretHashLE = Keystore.fromArraylikeToBytes(
_.get(obj, "identityCredential.idSecretHash", [])
);
// Big Endian
const idCommitmentBE = BytesUtils.switchEndianness(idCommitmentLE);
const idTrapdoorBE = BytesUtils.switchEndianness(idTrapdoorLE);
const idNullifierBE = BytesUtils.switchEndianness(idNullifierLE);
const idSecretHashBE = BytesUtils.switchEndianness(idSecretHashLE);
const idCommitmentBigInt =
BytesUtils.buildBigIntFromUint8ArrayBE(idCommitmentBE);
return {
identity: {
IDCommitment: Keystore.fromArraylikeToBytes(
_.get(obj, "identityCredential.idCommitment", [])
),
IDTrapdoor: Keystore.fromArraylikeToBytes(
_.get(obj, "identityCredential.idTrapdoor", [])
),
IDNullifier: Keystore.fromArraylikeToBytes(
_.get(obj, "identityCredential.idNullifier", [])
),
IDCommitmentBigInt: buildBigIntFromUint8Array(
Keystore.fromArraylikeToBytes(
_.get(obj, "identityCredential.idCommitment", [])
)
),
IDSecretHash: Keystore.fromArraylikeToBytes(
_.get(obj, "identityCredential.idSecretHash", [])
)
IDCommitment: idCommitmentBE,
IDTrapdoor: idTrapdoorBE,
IDNullifier: idNullifierBE,
IDSecretHash: idSecretHashBE,
IDCommitmentBigInt: idCommitmentBigInt
},
membership: {
treeIndex: _.get(obj, "treeIndex"),
@ -320,15 +329,35 @@ export class Keystore {
// follows nwaku implementation
// https://github.com/waku-org/nwaku/blob/f05528d4be3d3c876a8b07f9bb7dfaae8aa8ec6e/waku/waku_keystore/protocol_types.nim#L98
// IdentityCredential is stored in Big Endian format => switch to Little Endian
private static fromIdentityToBytes(options: KeystoreEntity): Uint8Array {
const { IDCommitment, IDNullifier, IDSecretHash, IDTrapdoor } =
options.identity;
const idCommitmentLE = BytesUtils.switchEndianness(IDCommitment);
const idNullifierLE = BytesUtils.switchEndianness(IDNullifier);
const idSecretHashLE = BytesUtils.switchEndianness(IDSecretHash);
const idTrapdoorLE = BytesUtils.switchEndianness(IDTrapdoor);
// eslint-disable-next-line no-console
console.log({
idCommitmentBE: IDCommitment,
idCommitmentLE,
idNullifierBE: IDNullifier,
idNullifierLE,
idSecretHashBE: IDSecretHash,
idSecretHashLE,
idTrapdoorBE: IDTrapdoor,
idTrapdoorLE
});
return utf8ToBytes(
JSON.stringify({
treeIndex: options.membership.treeIndex,
identityCredential: {
idCommitment: Array.from(options.identity.IDCommitment),
idNullifier: Array.from(options.identity.IDNullifier),
idSecretHash: Array.from(options.identity.IDSecretHash),
idTrapdoor: Array.from(options.identity.IDTrapdoor)
idCommitment: Array.from(idCommitmentLE),
idNullifier: Array.from(idNullifierLE),
idSecretHash: Array.from(idSecretHashLE),
idTrapdoor: Array.from(idTrapdoorLE)
},
membershipContract: {
chainId: options.membership.chainId,

View File

@ -1,6 +1,6 @@
import type { IRateLimitProof } from "@waku/interfaces";
import { concatenate, poseidonHash } from "./utils/index.js";
import { BytesUtils, poseidonHash } from "./utils/index.js";
const proofOffset = 128;
const rootOffset = proofOffset + 32;
@ -57,7 +57,7 @@ export class Proof implements IRateLimitProof {
}
export function proofToBytes(p: IRateLimitProof): Uint8Array {
return concatenate(
return BytesUtils.concatenate(
p.proof,
p.merkleRoot,
p.epoch,

View File

@ -1,84 +1,130 @@
/**
* Concatenate Uint8Arrays
* @param input
* @returns concatenation of all Uint8Array received as input
*/
export function concatenate(...input: Uint8Array[]): Uint8Array {
let totalLength = 0;
for (const arr of input) {
totalLength += arr.length;
}
const result = new Uint8Array(totalLength);
let offset = 0;
for (const arr of input) {
result.set(arr, offset);
offset += arr.length;
}
return result;
}
// Adapted from https://github.com/feross/buffer
function checkInt(
buf: Uint8Array,
value: number,
offset: number,
ext: number,
max: number,
min: number
): void {
if (value > max || value < min)
throw new RangeError('"value" argument is out of bounds');
if (offset + ext > buf.length) throw new RangeError("Index out of range");
}
export function writeUIntLE(
buf: Uint8Array,
value: number,
offset: number,
byteLength: number,
noAssert?: boolean
): Uint8Array {
value = +value;
offset = offset >>> 0;
byteLength = byteLength >>> 0;
if (!noAssert) {
const maxBytes = Math.pow(2, 8 * byteLength) - 1;
checkInt(buf, value, offset, byteLength, maxBytes, 0);
export class BytesUtils {
/**
* Switches endianness of a byte array
*/
public static switchEndianness(bytes: Uint8Array): Uint8Array {
return new Uint8Array([...bytes].reverse());
}
let mul = 1;
let i = 0;
buf[offset] = value & 0xff;
while (++i < byteLength && (mul *= 0x100)) {
buf[offset + i] = (value / mul) & 0xff;
/**
* Builds a BigInt from a big-endian Uint8Array
* @param bytes The big-endian bytes to convert
* @returns The resulting BigInt in big-endian format
*/
public static buildBigIntFromUint8ArrayBE(bytes: Uint8Array): bigint {
let result = 0n;
for (let i = 0; i < bytes.length; i++) {
result = (result << 8n) + BigInt(bytes[i]);
}
return result;
}
return buf;
}
/**
* Switches endianness of a bigint value
* @param value The bigint value to switch endianness for
* @returns The bigint value with reversed endianness
*/
public static switchEndiannessBigInt(value: bigint): bigint {
// Convert bigint to byte array
const bytes = [];
let tempValue = value;
while (tempValue > 0n) {
bytes.push(Number(tempValue & 0xffn));
tempValue >>= 8n;
}
/**
* Transforms Uint8Array into BigInt
* @param array: Uint8Array
* @returns BigInt
*/
export function buildBigIntFromUint8Array(
array: Uint8Array,
byteOffset: number = 0
): bigint {
const dataView = new DataView(array.buffer);
return dataView.getBigUint64(byteOffset, true);
}
/**
* Fills with zeros to set length
* @param array little endian Uint8Array
* @param length amount to pad
* @returns little endian Uint8Array padded with zeros to set length
*/
export function zeroPadLE(array: Uint8Array, length: number): Uint8Array {
const result = new Uint8Array(length);
for (let i = 0; i < length; i++) {
result[i] = array[i] || 0;
// Reverse bytes and convert back to bigint
return bytes
.reverse()
.reduce((acc, byte) => (acc << 8n) + BigInt(byte), 0n);
}
/**
* Converts a big-endian bigint to a 32-byte big-endian Uint8Array
* @param value The big-endian bigint to convert
* @returns A 32-byte big-endian Uint8Array
*/
public static bigIntToUint8Array32BE(value: bigint): Uint8Array {
const bytes = new Uint8Array(32);
for (let i = 31; i >= 0; i--) {
bytes[i] = Number(value & 0xffn);
value >>= 8n;
}
return bytes;
}
/**
* Writes an unsigned integer to a buffer in little-endian format
*/
public static writeUIntLE(
buf: Uint8Array,
value: number,
offset: number,
byteLength: number,
noAssert?: boolean
): Uint8Array {
value = +value;
offset = offset >>> 0;
byteLength = byteLength >>> 0;
if (!noAssert) {
const maxBytes = Math.pow(2, 8 * byteLength) - 1;
BytesUtils.checkInt(buf, value, offset, byteLength, maxBytes, 0);
}
let mul = 1;
let i = 0;
buf[offset] = value & 0xff;
while (++i < byteLength && (mul *= 0x100)) {
buf[offset + i] = (value / mul) & 0xff;
}
return buf;
}
/**
* Fills with zeros to set length
* @param array little endian Uint8Array
* @param length amount to pad
* @returns little endian Uint8Array padded with zeros to set length
*/
public static zeroPadLE(array: Uint8Array, length: number): Uint8Array {
const result = new Uint8Array(length);
for (let i = 0; i < length; i++) {
result[i] = array[i] || 0;
}
return result;
}
// Adapted from https://github.com/feross/buffer
public static checkInt(
buf: Uint8Array,
value: number,
offset: number,
ext: number,
max: number,
min: number
): void {
if (value > max || value < min)
throw new RangeError('"value" argument is out of bounds');
if (offset + ext > buf.length) throw new RangeError("Index out of range");
}
/**
* Concatenate Uint8Arrays
* @param input
* @returns concatenation of all Uint8Array received as input
*/
public static concatenate(...input: Uint8Array[]): Uint8Array {
let totalLength = 0;
for (const arr of input) {
totalLength += arr.length;
}
const result = new Uint8Array(totalLength);
let offset = 0;
for (const arr of input) {
result.set(arr, offset);
offset += arr.length;
}
return result;
}
return result;
}

View File

@ -1,15 +1,25 @@
import * as zerokitRLN from "@waku/zerokit-rln-wasm";
import { concatenate, writeUIntLE } from "./bytes.js";
import { BytesUtils } from "./bytes.js";
export function poseidonHash(...input: Array<Uint8Array>): Uint8Array {
const inputLen = writeUIntLE(new Uint8Array(8), input.length, 0, 8);
const lenPrefixedData = concatenate(inputLen, ...input);
const inputLen = BytesUtils.writeUIntLE(
new Uint8Array(8),
input.length,
0,
8
);
const lenPrefixedData = BytesUtils.concatenate(inputLen, ...input);
return zerokitRLN.poseidonHash(lenPrefixedData);
}
export function sha256(input: Uint8Array): Uint8Array {
const inputLen = writeUIntLE(new Uint8Array(8), input.length, 0, 8);
const lenPrefixedData = concatenate(inputLen, input);
const inputLen = BytesUtils.writeUIntLE(
new Uint8Array(8),
input.length,
0,
8
);
const lenPrefixedData = BytesUtils.concatenate(inputLen, input);
return zerokitRLN.hash(lenPrefixedData);
}

View File

@ -1,9 +1,4 @@
export { extractMetaMaskSigner } from "./metamask.js";
export {
concatenate,
writeUIntLE,
buildBigIntFromUint8Array,
zeroPadLE
} from "./bytes.js";
export { BytesUtils } from "./bytes.js";
export { sha256, poseidonHash } from "./hash.js";
export { dateToEpoch, epochIntToBytes, epochBytesToInt } from "./epoch.js";

View File

@ -5,12 +5,7 @@ import { DEFAULT_RATE_LIMIT, RATE_LIMIT_PARAMS } from "./contract/constants.js";
import { IdentityCredential } from "./identity.js";
import { Proof, proofToBytes } from "./proof.js";
import { WitnessCalculator } from "./resources/witness_calculator";
import {
concatenate,
dateToEpoch,
epochIntToBytes,
writeUIntLE
} from "./utils/index.js";
import { BytesUtils, dateToEpoch, epochIntToBytes } from "./utils/index.js";
export class Zerokit {
public constructor(
@ -57,13 +52,16 @@ export class Zerokit {
): void {
// serializes a seq of IDCommitments to a byte seq
// the order of serialization is |id_commitment_len<8>|id_commitment<var>|
const idCommitmentLen = writeUIntLE(
const idCommitmentLen = BytesUtils.writeUIntLE(
new Uint8Array(8),
idCommitments.length,
0,
8
);
const idCommitmentBytes = concatenate(idCommitmentLen, ...idCommitments);
const idCommitmentBytes = BytesUtils.concatenate(
idCommitmentLen,
...idCommitments
);
zerokitRLN.setLeavesFrom(this.zkRLN, index, idCommitmentBytes);
}
@ -83,9 +81,19 @@ export class Zerokit {
rateLimit?: number
): Uint8Array {
// calculate message length
const msgLen = writeUIntLE(new Uint8Array(8), uint8Msg.length, 0, 8);
const memIndexBytes = writeUIntLE(new Uint8Array(8), memIndex, 0, 8);
const rateLimitBytes = writeUIntLE(
const msgLen = BytesUtils.writeUIntLE(
new Uint8Array(8),
uint8Msg.length,
0,
8
);
const memIndexBytes = BytesUtils.writeUIntLE(
new Uint8Array(8),
memIndex,
0,
8
);
const rateLimitBytes = BytesUtils.writeUIntLE(
new Uint8Array(8),
rateLimit ?? this.rateLimit,
0,
@ -93,7 +101,7 @@ export class Zerokit {
);
// [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> | rate_limit<8> ]
return concatenate(
return BytesUtils.concatenate(
idKey,
memIndexBytes,
epoch,
@ -169,8 +177,8 @@ export class Zerokit {
}
// calculate message length
const msgLen = writeUIntLE(new Uint8Array(8), msg.length, 0, 8);
const rateLimitBytes = writeUIntLE(
const msgLen = BytesUtils.writeUIntLE(new Uint8Array(8), msg.length, 0, 8);
const rateLimitBytes = BytesUtils.writeUIntLE(
new Uint8Array(8),
rateLimit ?? this.rateLimit,
0,
@ -179,7 +187,7 @@ export class Zerokit {
return zerokitRLN.verifyRLNProof(
this.zkRLN,
concatenate(pBytes, msgLen, msg, rateLimitBytes)
BytesUtils.concatenate(pBytes, msgLen, msg, rateLimitBytes)
);
}
@ -196,19 +204,19 @@ export class Zerokit {
pBytes = proofToBytes(proof);
}
// calculate message length
const msgLen = writeUIntLE(new Uint8Array(8), msg.length, 0, 8);
const rateLimitBytes = writeUIntLE(
const msgLen = BytesUtils.writeUIntLE(new Uint8Array(8), msg.length, 0, 8);
const rateLimitBytes = BytesUtils.writeUIntLE(
new Uint8Array(8),
rateLimit ?? this.rateLimit,
0,
8
);
const rootsBytes = concatenate(...roots);
const rootsBytes = BytesUtils.concatenate(...roots);
return zerokitRLN.verifyWithRoots(
this.zkRLN,
concatenate(pBytes, msgLen, msg, rateLimitBytes),
BytesUtils.concatenate(pBytes, msgLen, msg, rateLimitBytes),
rootsBytes
);
}
@ -226,8 +234,8 @@ export class Zerokit {
}
// calculate message length
const msgLen = writeUIntLE(new Uint8Array(8), msg.length, 0, 8);
const rateLimitBytes = writeUIntLE(
const msgLen = BytesUtils.writeUIntLE(new Uint8Array(8), msg.length, 0, 8);
const rateLimitBytes = BytesUtils.writeUIntLE(
new Uint8Array(8),
rateLimit ?? this.rateLimit,
0,
@ -236,7 +244,7 @@ export class Zerokit {
return zerokitRLN.verifyWithRoots(
this.zkRLN,
concatenate(pBytes, msgLen, msg, rateLimitBytes),
BytesUtils.concatenate(pBytes, msgLen, msg, rateLimitBytes),
new Uint8Array()
);
}