@waku/rln 0.1.6-27c1236.0 → 0.1.6-2ce706d.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundle/packages/rln/dist/contract/rln_base_contract.js +10 -12
- package/bundle/packages/rln/dist/credentials_manager.js +13 -16
- package/bundle/packages/rln/dist/identity.js +37 -7
- package/bundle/packages/rln/dist/keystore/keystore.js +7 -11
- package/bundle/packages/rln/dist/utils/bytes.js +14 -10
- package/dist/.tsbuildinfo +1 -1
- package/dist/contract/rln_base_contract.d.ts +0 -5
- package/dist/contract/rln_base_contract.js +10 -12
- package/dist/contract/rln_base_contract.js.map +1 -1
- package/dist/credentials_manager.js +13 -16
- package/dist/credentials_manager.js.map +1 -1
- package/dist/identity.d.ts +11 -2
- package/dist/identity.js +23 -6
- package/dist/identity.js.map +1 -1
- package/dist/keystore/keystore.js +7 -11
- package/dist/keystore/keystore.js.map +1 -1
- package/dist/utils/bytes.d.ts +2 -1
- package/dist/utils/bytes.js +13 -9
- package/dist/utils/bytes.js.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
- package/src/contract/rln_base_contract.ts +12 -27
- package/src/credentials_manager.ts +20 -27
- package/src/identity.ts +32 -6
- package/src/keystore/keystore.ts +13 -24
- package/src/utils/bytes.ts +21 -19
- package/src/utils/index.ts +1 -1
- package/dist/contract/test-utils.d.ts +0 -39
- package/dist/contract/test-utils.js +0 -118
- package/dist/contract/test-utils.js.map +0 -1
- package/src/contract/test-utils.ts +0 -179
@@ -13,8 +13,9 @@ import '../../../../node_modules/multiformats/dist/src/bases/base8.js';
|
|
13
13
|
import '../../../../node_modules/multiformats/dist/src/bases/identity.js';
|
14
14
|
import '../../../../node_modules/multiformats/dist/src/codecs/json.js';
|
15
15
|
import { Logger } from '../../../utils/dist/logger/index.js';
|
16
|
+
import { IdentityCredential } from '../identity.js';
|
16
17
|
import { RLN_ABI } from './abi.js';
|
17
|
-
import {
|
18
|
+
import { DEFAULT_RATE_LIMIT, RATE_LIMIT_PARAMS } from './constants.js';
|
18
19
|
import { MembershipState } from './types.js';
|
19
20
|
import { Contract } from '../../../../node_modules/@ethersproject/contracts/lib.esm/index.js';
|
20
21
|
import { BigNumber } from '../../../../node_modules/@ethersproject/bignumber/lib.esm/bignumber.js';
|
@@ -26,11 +27,6 @@ class RLNBaseContract {
|
|
26
27
|
rateLimit;
|
27
28
|
minRateLimit;
|
28
29
|
maxRateLimit;
|
29
|
-
/**
|
30
|
-
* Default Q value for the RLN contract.
|
31
|
-
* @see https://github.com/waku-org/waku-rlnv2-contract/blob/b7e9a9b1bc69256a2a3076c1f099b50ce84e7eff/src/WakuRlnV2.sol#L25
|
32
|
-
*/
|
33
|
-
idCommitmentBigIntLimit = DEFAULT_Q;
|
34
30
|
_members = new Map();
|
35
31
|
_membersFilter;
|
36
32
|
_membershipErasedFilter;
|
@@ -69,14 +65,13 @@ class RLNBaseContract {
|
|
69
65
|
*/
|
70
66
|
static async create(options) {
|
71
67
|
const instance = new RLNBaseContract(options);
|
72
|
-
const [min, max
|
68
|
+
const [min, max] = await Promise.all([
|
73
69
|
instance.contract.minMembershipRateLimit(),
|
74
70
|
instance.contract.maxMembershipRateLimit(),
|
75
71
|
instance.contract.Q()
|
76
72
|
]);
|
77
73
|
instance.minRateLimit = BigNumber.from(min).toNumber();
|
78
74
|
instance.maxRateLimit = BigNumber.from(max).toNumber();
|
79
|
-
instance.idCommitmentBigIntLimit = BigInt(idCommitmentBigIntLimit.toString());
|
80
75
|
instance.validateRateLimit(instance.rateLimit);
|
81
76
|
return instance;
|
82
77
|
}
|
@@ -347,8 +342,9 @@ class RLNBaseContract {
|
|
347
342
|
async registerWithIdentity(identity) {
|
348
343
|
try {
|
349
344
|
log.info(`Registering identity with rate limit: ${this.rateLimit} messages/epoch`);
|
345
|
+
const idCommitmentBigInt = IdentityCredential.getIdCommitmentBigInt(identity.IDCommitment);
|
350
346
|
// Check if the ID commitment is already registered
|
351
|
-
const existingIndex = await this.getMemberIndex(
|
347
|
+
const existingIndex = await this.getMemberIndex(idCommitmentBigInt);
|
352
348
|
if (existingIndex) {
|
353
349
|
throw new Error(`ID commitment is already registered with index ${existingIndex}`);
|
354
350
|
}
|
@@ -357,9 +353,11 @@ class RLNBaseContract {
|
|
357
353
|
if (remainingRateLimit < this.rateLimit) {
|
358
354
|
throw new Error(`Not enough remaining rate limit. Requested: ${this.rateLimit}, Available: ${remainingRateLimit}`);
|
359
355
|
}
|
360
|
-
const estimatedGas = await this.contract.estimateGas.register(
|
356
|
+
const estimatedGas = await this.contract.estimateGas.register(idCommitmentBigInt, this.rateLimit, []);
|
361
357
|
const gasLimit = estimatedGas.add(10000);
|
362
|
-
const txRegisterResponse = await this.contract.register(
|
358
|
+
const txRegisterResponse = await this.contract.register(idCommitmentBigInt, this.rateLimit, [], {
|
359
|
+
gasLimit
|
360
|
+
});
|
363
361
|
const txRegisterReceipt = await txRegisterResponse.wait();
|
364
362
|
if (txRegisterReceipt.status === 0) {
|
365
363
|
throw new Error("Transaction failed on-chain");
|
@@ -421,7 +419,7 @@ class RLNBaseContract {
|
|
421
419
|
async registerWithPermitAndErase(identity, permit, idCommitmentsToErase) {
|
422
420
|
try {
|
423
421
|
log.info(`Registering identity with permit and rate limit: ${this.rateLimit} messages/epoch`);
|
424
|
-
const txRegisterResponse = await this.contract.registerWithPermit(permit.owner, permit.deadline, permit.v, permit.r, permit.s, identity.
|
422
|
+
const txRegisterResponse = await this.contract.registerWithPermit(permit.owner, permit.deadline, permit.v, permit.r, permit.s, IdentityCredential.getIdCommitmentBigInt(identity.IDCommitment), this.rateLimit, idCommitmentsToErase.map((id) => BigNumber.from(id)));
|
425
423
|
const txRegisterReceipt = await txRegisterResponse.wait();
|
426
424
|
const memberRegistered = txRegisterReceipt.events?.find((event) => event.event === "MembershipRegistered");
|
427
425
|
if (!memberRegistered || !memberRegistered.args) {
|
@@ -20,7 +20,7 @@ import { RLNBaseContract } from './contract/rln_base_contract.js';
|
|
20
20
|
import { IdentityCredential } from './identity.js';
|
21
21
|
import { Keystore } from './keystore/keystore.js';
|
22
22
|
import { extractMetaMaskSigner } from './utils/metamask.js';
|
23
|
-
import {
|
23
|
+
import { switchEndianness } from './utils/bytes.js';
|
24
24
|
import './utils/epoch.js';
|
25
25
|
|
26
26
|
const log = new Logger("waku:credentials");
|
@@ -198,22 +198,19 @@ class RLNCredentialsManager {
|
|
198
198
|
const seedBytes = encoder.encode(seed);
|
199
199
|
// Generate deterministic values using HMAC-SHA256
|
200
200
|
// We use different context strings for each component to ensure they're different
|
201
|
-
const
|
202
|
-
const
|
203
|
-
const combinedBytes = new Uint8Array([...
|
204
|
-
const
|
205
|
-
const
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
const
|
211
|
-
|
212
|
-
log.warn(`ID commitment is greater than Q, reducing it by Q(idCommitmentBigIntLimit): ${idCommitmentBigInt} % ${idCommitmentBigIntLimit}`);
|
213
|
-
idCommitmentBigInt = idCommitmentBigInt % idCommitmentBigIntLimit;
|
214
|
-
}
|
201
|
+
const idTrapdoorBE = hmac(sha256, seedBytes, encoder.encode("IDTrapdoor"));
|
202
|
+
const idNullifierBE = hmac(sha256, seedBytes, encoder.encode("IDNullifier"));
|
203
|
+
const combinedBytes = new Uint8Array([...idTrapdoorBE, ...idNullifierBE]);
|
204
|
+
const idSecretHashBE = sha256(combinedBytes);
|
205
|
+
const idCommitmentBE = sha256(idSecretHashBE);
|
206
|
+
// All hashing functions return big-endian bytes
|
207
|
+
// We need to switch to little-endian for the identity credential
|
208
|
+
const idTrapdoorLE = switchEndianness(idTrapdoorBE);
|
209
|
+
const idNullifierLE = switchEndianness(idNullifierBE);
|
210
|
+
const idSecretHashLE = switchEndianness(idSecretHashBE);
|
211
|
+
const idCommitmentLE = switchEndianness(idCommitmentBE);
|
215
212
|
log.info("Successfully generated identity credential");
|
216
|
-
return new IdentityCredential(
|
213
|
+
return new IdentityCredential(idTrapdoorLE, idNullifierLE, idSecretHashLE, idCommitmentLE);
|
217
214
|
}
|
218
215
|
}
|
219
216
|
|
@@ -1,18 +1,35 @@
|
|
1
|
-
import
|
2
|
-
import '
|
1
|
+
import '../../interfaces/dist/protocols.js';
|
2
|
+
import '../../interfaces/dist/connection_manager.js';
|
3
|
+
import '../../interfaces/dist/health_indicator.js';
|
4
|
+
import '../../../node_modules/multiformats/dist/src/bases/base10.js';
|
5
|
+
import '../../../node_modules/multiformats/dist/src/bases/base16.js';
|
6
|
+
import '../../../node_modules/multiformats/dist/src/bases/base2.js';
|
7
|
+
import '../../../node_modules/multiformats/dist/src/bases/base256emoji.js';
|
8
|
+
import '../../../node_modules/multiformats/dist/src/bases/base32.js';
|
9
|
+
import '../../../node_modules/multiformats/dist/src/bases/base36.js';
|
10
|
+
import '../../../node_modules/multiformats/dist/src/bases/base58.js';
|
11
|
+
import '../../../node_modules/multiformats/dist/src/bases/base64.js';
|
12
|
+
import '../../../node_modules/multiformats/dist/src/bases/base8.js';
|
13
|
+
import '../../../node_modules/multiformats/dist/src/bases/identity.js';
|
14
|
+
import '../../../node_modules/multiformats/dist/src/codecs/json.js';
|
15
|
+
import { Logger } from '../../utils/dist/logger/index.js';
|
16
|
+
import { DEFAULT_Q } from './contract/constants.js';
|
17
|
+
import { buildBigIntFromUint8ArrayBE } from './utils/bytes.js';
|
3
18
|
|
19
|
+
const log = new Logger("waku:rln:identity");
|
4
20
|
class IdentityCredential {
|
5
21
|
IDTrapdoor;
|
6
22
|
IDNullifier;
|
7
23
|
IDSecretHash;
|
8
24
|
IDCommitment;
|
9
|
-
|
10
|
-
|
25
|
+
/**
|
26
|
+
* All variables are in little-endian format
|
27
|
+
*/
|
28
|
+
constructor(IDTrapdoor, IDNullifier, IDSecretHash, IDCommitment) {
|
11
29
|
this.IDTrapdoor = IDTrapdoor;
|
12
30
|
this.IDNullifier = IDNullifier;
|
13
31
|
this.IDSecretHash = IDSecretHash;
|
14
32
|
this.IDCommitment = IDCommitment;
|
15
|
-
this.IDCommitmentBigInt = IDCommitmentBigInt;
|
16
33
|
}
|
17
34
|
static fromBytes(memKeys) {
|
18
35
|
if (memKeys.length < 128) {
|
@@ -22,8 +39,21 @@ class IdentityCredential {
|
|
22
39
|
const idNullifier = memKeys.subarray(32, 64);
|
23
40
|
const idSecretHash = memKeys.subarray(64, 96);
|
24
41
|
const idCommitment = memKeys.subarray(96, 128);
|
25
|
-
|
26
|
-
|
42
|
+
return new IdentityCredential(idTrapdoor, idNullifier, idSecretHash, idCommitment);
|
43
|
+
}
|
44
|
+
/**
|
45
|
+
* Converts an ID commitment from bytes to a BigInt, normalizing it against a limit if needed
|
46
|
+
* @param bytes The ID commitment bytes to convert
|
47
|
+
* @param limit Optional limit to normalize against (Q value)
|
48
|
+
* @returns The ID commitment as a BigInt
|
49
|
+
*/
|
50
|
+
static getIdCommitmentBigInt(bytes, limit = DEFAULT_Q) {
|
51
|
+
let idCommitmentBigIntBE = buildBigIntFromUint8ArrayBE(bytes);
|
52
|
+
if (limit && idCommitmentBigIntBE >= limit) {
|
53
|
+
log.warn(`ID commitment is greater than Q, reducing it by Q: ${idCommitmentBigIntBE} % ${limit}`);
|
54
|
+
idCommitmentBigIntBE = idCommitmentBigIntBE % limit;
|
55
|
+
}
|
56
|
+
return idCommitmentBigIntBE;
|
27
57
|
}
|
28
58
|
}
|
29
59
|
|
@@ -17,7 +17,6 @@ import { Logger } from '../../../utils/dist/logger/index.js';
|
|
17
17
|
import { sha256 } from '../../../../node_modules/ethereum-cryptography/esm/sha256.js';
|
18
18
|
import { bytesToUtf8 } from '../../../../node_modules/ethereum-cryptography/esm/utils.js';
|
19
19
|
import _ from '../../../../node_modules/lodash/lodash.js';
|
20
|
-
import { buildBigIntFromUint8ArrayLE } from '../utils/bytes.js';
|
21
20
|
import { keccak256Checksum, decryptEipKeystore } from './cipher.js';
|
22
21
|
import { isKeystoreValid, isCredentialValid } from './schema_validator.js';
|
23
22
|
import { __exports as lib } from '../../../../_virtual/index.js';
|
@@ -161,22 +160,19 @@ class Keystore {
|
|
161
160
|
};
|
162
161
|
}
|
163
162
|
static fromBytesToIdentity(bytes) {
|
164
|
-
function fromLittleEndian(bytes) {
|
165
|
-
return new Uint8Array(bytes).reverse();
|
166
|
-
}
|
167
163
|
try {
|
168
164
|
const str = bytesToUtf8(bytes);
|
169
165
|
const obj = JSON.parse(str);
|
170
|
-
// Use little-endian bytes directly for BigInt conversion (matches storage and contract expectation)
|
171
166
|
const idCommitmentLE = Keystore.fromArraylikeToBytes(_.get(obj, "identityCredential.idCommitment", []));
|
167
|
+
const idTrapdoorLE = Keystore.fromArraylikeToBytes(_.get(obj, "identityCredential.idTrapdoor", []));
|
168
|
+
const idNullifierLE = Keystore.fromArraylikeToBytes(_.get(obj, "identityCredential.idNullifier", []));
|
169
|
+
const idSecretHashLE = Keystore.fromArraylikeToBytes(_.get(obj, "identityCredential.idSecretHash", []));
|
172
170
|
return {
|
173
171
|
identity: {
|
174
|
-
IDCommitment:
|
175
|
-
IDTrapdoor:
|
176
|
-
IDNullifier:
|
177
|
-
|
178
|
-
IDCommitmentBigInt: buildBigIntFromUint8ArrayLE(idCommitmentLE),
|
179
|
-
IDSecretHash: fromLittleEndian(Keystore.fromArraylikeToBytes(_.get(obj, "identityCredential.idSecretHash", [])))
|
172
|
+
IDCommitment: idCommitmentLE,
|
173
|
+
IDTrapdoor: idTrapdoorLE,
|
174
|
+
IDNullifier: idNullifierLE,
|
175
|
+
IDSecretHash: idSecretHashLE
|
180
176
|
},
|
181
177
|
membership: {
|
182
178
|
treeIndex: _.get(obj, "treeIndex"),
|
@@ -16,12 +16,12 @@ function concatenate(...input) {
|
|
16
16
|
}
|
17
17
|
return result;
|
18
18
|
}
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
19
|
+
function switchEndianness(bytes) {
|
20
|
+
return new Uint8Array(bytes.reverse());
|
21
|
+
}
|
22
|
+
function buildBigIntFromUint8ArrayBE(bytes) {
|
23
|
+
// Interpret bytes as big-endian
|
24
|
+
return bytes.reduce((acc, byte) => (acc << 8n) + BigInt(byte), 0n);
|
25
25
|
}
|
26
26
|
function writeUIntLE(buf, value, offset, byteLength, noAssert) {
|
27
27
|
value = +value;
|
@@ -39,9 +39,6 @@ function writeUIntLE(buf, value, offset, byteLength, noAssert) {
|
|
39
39
|
}
|
40
40
|
return buf;
|
41
41
|
}
|
42
|
-
function buildBigIntFromUint8ArrayLE(bytes) {
|
43
|
-
return bytes.reduce((acc, byte, i) => acc + BigInt(byte) * (1n << (8n * BigInt(i))), 0n);
|
44
|
-
}
|
45
42
|
/**
|
46
43
|
* Fills with zeros to set length
|
47
44
|
* @param array little endian Uint8Array
|
@@ -55,5 +52,12 @@ function zeroPadLE(array, length) {
|
|
55
52
|
}
|
56
53
|
return result;
|
57
54
|
}
|
55
|
+
// Adapted from https://github.com/feross/buffer
|
56
|
+
function checkInt(buf, value, offset, ext, max, min) {
|
57
|
+
if (value > max || value < min)
|
58
|
+
throw new RangeError('"value" argument is out of bounds');
|
59
|
+
if (offset + ext > buf.length)
|
60
|
+
throw new RangeError("Index out of range");
|
61
|
+
}
|
58
62
|
|
59
|
-
export {
|
63
|
+
export { buildBigIntFromUint8ArrayBE, concatenate, switchEndianness, writeUIntLE, zeroPadLE };
|