@waku/rln 0.1.6-16328a3.0 → 0.1.6-27c1236.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/index.js +1 -1
- package/bundle/packages/core/dist/lib/message/version_0.js +1 -4
- package/bundle/packages/rln/dist/contract/constants.js +7 -1
- package/bundle/packages/rln/dist/contract/rln_base_contract.js +10 -3
- package/bundle/packages/rln/dist/credentials_manager.js +13 -8
- package/bundle/packages/rln/dist/identity.js +2 -2
- package/bundle/packages/rln/dist/keystore/keystore.js +19 -11
- package/bundle/packages/rln/dist/message.js +11 -0
- package/bundle/packages/rln/dist/utils/bytes.js +3 -9
- package/dist/.tsbuildinfo +1 -1
- package/dist/contract/constants.d.ts +6 -0
- package/dist/contract/constants.js +6 -0
- package/dist/contract/constants.js.map +1 -1
- package/dist/contract/rln_base_contract.d.ts +5 -0
- package/dist/contract/rln_base_contract.js +10 -3
- package/dist/contract/rln_base_contract.js.map +1 -1
- package/dist/credentials_manager.js +13 -8
- package/dist/credentials_manager.js.map +1 -1
- package/dist/identity.js +2 -2
- package/dist/identity.js.map +1 -1
- package/dist/keystore/keystore.js +19 -11
- package/dist/keystore/keystore.js.map +1 -1
- package/dist/message.d.ts +5 -4
- package/dist/message.js +2 -0
- package/dist/message.js.map +1 -1
- package/dist/utils/bytes.d.ts +1 -6
- package/dist/utils/bytes.js +2 -8
- 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/constants.ts +9 -0
- package/src/contract/rln_base_contract.ts +17 -3
- package/src/credentials_manager.ts +21 -8
- package/src/identity.ts +2 -2
- package/src/keystore/keystore.ts +33 -18
- package/src/message.ts +7 -4
- package/src/utils/bytes.ts +5 -11
- package/src/utils/index.ts +1 -1
package/bundle/index.js
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
export { RLNDecoder, RLNEncoder } from './packages/rln/dist/codec.js';
|
2
2
|
export { RLN_ABI } from './packages/rln/dist/contract/abi.js';
|
3
3
|
export { RLNContract } from './packages/rln/dist/contract/rln_contract.js';
|
4
|
-
export { DEFAULT_RATE_LIMIT, LINEA_CONTRACT, RATE_LIMIT_PARAMS, RATE_LIMIT_TIERS } from './packages/rln/dist/contract/constants.js';
|
4
|
+
export { DEFAULT_Q, DEFAULT_RATE_LIMIT, LINEA_CONTRACT, RATE_LIMIT_PARAMS, RATE_LIMIT_TIERS } from './packages/rln/dist/contract/constants.js';
|
5
5
|
export { MembershipState } from './packages/rln/dist/contract/types.js';
|
6
6
|
export { RLNBaseContract } from './packages/rln/dist/contract/rln_base_contract.js';
|
7
7
|
export { createRLN } from './packages/rln/dist/create.js';
|
@@ -29,9 +29,6 @@ class DecodedMessage {
|
|
29
29
|
get contentTopic() {
|
30
30
|
return this.proto.contentTopic;
|
31
31
|
}
|
32
|
-
get _rawTimestamp() {
|
33
|
-
return this.proto.timestamp;
|
34
|
-
}
|
35
32
|
get timestamp() {
|
36
33
|
// In the case we receive a value that is bigger than JS's max number,
|
37
34
|
// we catch the error and return undefined.
|
@@ -53,7 +50,7 @@ class DecodedMessage {
|
|
53
50
|
get version() {
|
54
51
|
// https://rfc.vac.dev/spec/14/
|
55
52
|
// > If omitted, the value SHOULD be interpreted as version 0.
|
56
|
-
return this.proto.version ??
|
53
|
+
return this.proto.version ?? Version;
|
57
54
|
}
|
58
55
|
get rateLimitProof() {
|
59
56
|
return this.proto.rateLimitProof;
|
@@ -22,6 +22,12 @@ const RATE_LIMIT_PARAMS = {
|
|
22
22
|
MAX_TOTAL_RATE: 160_000, // Maximum total rate limit across all memberships
|
23
23
|
EPOCH_LENGTH: 600 // Epoch length in seconds (10 minutes)
|
24
24
|
};
|
25
|
+
/**
|
26
|
+
* Default Q value for the RLN contract
|
27
|
+
* This is the upper bound for the ID commitment
|
28
|
+
* @see https://github.com/waku-org/specs/blob/master/standards/core/rln-contract.md#implementation-suggestions
|
29
|
+
*/
|
30
|
+
const DEFAULT_Q = BigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
25
31
|
const DEFAULT_RATE_LIMIT = RATE_LIMIT_PARAMS.MAX_RATE;
|
26
32
|
|
27
|
-
export { DEFAULT_RATE_LIMIT, LINEA_CONTRACT, RATE_LIMIT_PARAMS, RATE_LIMIT_TIERS };
|
33
|
+
export { DEFAULT_Q, DEFAULT_RATE_LIMIT, LINEA_CONTRACT, RATE_LIMIT_PARAMS, RATE_LIMIT_TIERS };
|
@@ -14,7 +14,7 @@ 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
16
|
import { RLN_ABI } from './abi.js';
|
17
|
-
import { DEFAULT_RATE_LIMIT, RATE_LIMIT_PARAMS } from './constants.js';
|
17
|
+
import { DEFAULT_Q, DEFAULT_RATE_LIMIT, RATE_LIMIT_PARAMS } from './constants.js';
|
18
18
|
import { MembershipState } from './types.js';
|
19
19
|
import { Contract } from '../../../../node_modules/@ethersproject/contracts/lib.esm/index.js';
|
20
20
|
import { BigNumber } from '../../../../node_modules/@ethersproject/bignumber/lib.esm/bignumber.js';
|
@@ -26,6 +26,11 @@ class RLNBaseContract {
|
|
26
26
|
rateLimit;
|
27
27
|
minRateLimit;
|
28
28
|
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;
|
29
34
|
_members = new Map();
|
30
35
|
_membersFilter;
|
31
36
|
_membershipErasedFilter;
|
@@ -64,12 +69,14 @@ class RLNBaseContract {
|
|
64
69
|
*/
|
65
70
|
static async create(options) {
|
66
71
|
const instance = new RLNBaseContract(options);
|
67
|
-
const [min, max] = await Promise.all([
|
72
|
+
const [min, max, idCommitmentBigIntLimit] = await Promise.all([
|
68
73
|
instance.contract.minMembershipRateLimit(),
|
69
|
-
instance.contract.maxMembershipRateLimit()
|
74
|
+
instance.contract.maxMembershipRateLimit(),
|
75
|
+
instance.contract.Q()
|
70
76
|
]);
|
71
77
|
instance.minRateLimit = BigNumber.from(min).toNumber();
|
72
78
|
instance.maxRateLimit = BigNumber.from(max).toNumber();
|
79
|
+
instance.idCommitmentBigIntLimit = BigInt(idCommitmentBigIntLimit.toString());
|
73
80
|
instance.validateRateLimit(instance.rateLimit);
|
74
81
|
return instance;
|
75
82
|
}
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { hmac } from '../../../node_modules/@noble/hashes/esm/hmac.js';
|
2
|
-
import { sha256 } from '../../../node_modules/@noble/hashes/esm/
|
2
|
+
import { sha256 } from '../../../node_modules/@noble/hashes/esm/sha2.js';
|
3
3
|
import '../../interfaces/dist/protocols.js';
|
4
4
|
import '../../interfaces/dist/connection_manager.js';
|
5
5
|
import '../../interfaces/dist/health_indicator.js';
|
@@ -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 { buildBigIntFromUint8ArrayLE } from './utils/bytes.js';
|
24
24
|
import './utils/epoch.js';
|
25
25
|
|
26
26
|
const log = new Logger("waku:credentials");
|
@@ -95,7 +95,7 @@ class RLNCredentialsManager {
|
|
95
95
|
}
|
96
96
|
else {
|
97
97
|
log.info("Using local implementation to generate identity");
|
98
|
-
identity = this.generateSeededIdentityCredential(options.signature);
|
98
|
+
identity = await this.generateSeededIdentityCredential(options.signature);
|
99
99
|
}
|
100
100
|
}
|
101
101
|
if (!identity) {
|
@@ -191,7 +191,7 @@ class RLNCredentialsManager {
|
|
191
191
|
* @param seed A string seed to generate the identity from
|
192
192
|
* @returns IdentityCredential
|
193
193
|
*/
|
194
|
-
generateSeededIdentityCredential(seed) {
|
194
|
+
async generateSeededIdentityCredential(seed) {
|
195
195
|
log.info("Generating seeded identity credential");
|
196
196
|
// Convert the seed to bytes
|
197
197
|
const encoder = new TextEncoder();
|
@@ -200,13 +200,18 @@ class RLNCredentialsManager {
|
|
200
200
|
// We use different context strings for each component to ensure they're different
|
201
201
|
const idTrapdoor = hmac(sha256, seedBytes, encoder.encode("IDTrapdoor"));
|
202
202
|
const idNullifier = hmac(sha256, seedBytes, encoder.encode("IDNullifier"));
|
203
|
-
// Generate IDSecretHash as a hash of IDTrapdoor and IDNullifier
|
204
203
|
const combinedBytes = new Uint8Array([...idTrapdoor, ...idNullifier]);
|
205
204
|
const idSecretHash = sha256(combinedBytes);
|
206
|
-
// Generate IDCommitment as a hash of IDSecretHash
|
207
205
|
const idCommitment = sha256(idSecretHash);
|
208
|
-
|
209
|
-
|
206
|
+
let idCommitmentBigInt = buildBigIntFromUint8ArrayLE(idCommitment);
|
207
|
+
if (!this.contract) {
|
208
|
+
throw Error("RLN contract is not initialized");
|
209
|
+
}
|
210
|
+
const idCommitmentBigIntLimit = this.contract.idCommitmentBigIntLimit;
|
211
|
+
if (idCommitmentBigInt >= idCommitmentBigIntLimit) {
|
212
|
+
log.warn(`ID commitment is greater than Q, reducing it by Q(idCommitmentBigIntLimit): ${idCommitmentBigInt} % ${idCommitmentBigIntLimit}`);
|
213
|
+
idCommitmentBigInt = idCommitmentBigInt % idCommitmentBigIntLimit;
|
214
|
+
}
|
210
215
|
log.info("Successfully generated identity credential");
|
211
216
|
return new IdentityCredential(idTrapdoor, idNullifier, idSecretHash, idCommitment, idCommitmentBigInt);
|
212
217
|
}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import {
|
1
|
+
import { buildBigIntFromUint8ArrayLE } from './utils/bytes.js';
|
2
2
|
import './utils/epoch.js';
|
3
3
|
|
4
4
|
class IdentityCredential {
|
@@ -22,7 +22,7 @@ class IdentityCredential {
|
|
22
22
|
const idNullifier = memKeys.subarray(32, 64);
|
23
23
|
const idSecretHash = memKeys.subarray(64, 96);
|
24
24
|
const idCommitment = memKeys.subarray(96, 128);
|
25
|
-
const idCommitmentBigInt =
|
25
|
+
const idCommitmentBigInt = buildBigIntFromUint8ArrayLE(idCommitment);
|
26
26
|
return new IdentityCredential(idTrapdoor, idNullifier, idSecretHash, idCommitment, idCommitmentBigInt);
|
27
27
|
}
|
28
28
|
}
|
@@ -17,7 +17,7 @@ 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 {
|
20
|
+
import { buildBigIntFromUint8ArrayLE } from '../utils/bytes.js';
|
21
21
|
import { keccak256Checksum, decryptEipKeystore } from './cipher.js';
|
22
22
|
import { isKeystoreValid, isCredentialValid } from './schema_validator.js';
|
23
23
|
import { __exports as lib } from '../../../../_virtual/index.js';
|
@@ -161,17 +161,22 @@ class Keystore {
|
|
161
161
|
};
|
162
162
|
}
|
163
163
|
static fromBytesToIdentity(bytes) {
|
164
|
+
function fromLittleEndian(bytes) {
|
165
|
+
return new Uint8Array(bytes).reverse();
|
166
|
+
}
|
164
167
|
try {
|
165
168
|
const str = bytesToUtf8(bytes);
|
166
169
|
const obj = JSON.parse(str);
|
167
|
-
//
|
170
|
+
// Use little-endian bytes directly for BigInt conversion (matches storage and contract expectation)
|
171
|
+
const idCommitmentLE = Keystore.fromArraylikeToBytes(_.get(obj, "identityCredential.idCommitment", []));
|
168
172
|
return {
|
169
173
|
identity: {
|
170
|
-
IDCommitment:
|
171
|
-
IDTrapdoor: Keystore.fromArraylikeToBytes(_.get(obj, "identityCredential.idTrapdoor", [])),
|
172
|
-
IDNullifier: Keystore.fromArraylikeToBytes(_.get(obj, "identityCredential.idNullifier", [])),
|
173
|
-
|
174
|
-
|
174
|
+
IDCommitment: fromLittleEndian(idCommitmentLE),
|
175
|
+
IDTrapdoor: fromLittleEndian(Keystore.fromArraylikeToBytes(_.get(obj, "identityCredential.idTrapdoor", []))),
|
176
|
+
IDNullifier: fromLittleEndian(Keystore.fromArraylikeToBytes(_.get(obj, "identityCredential.idNullifier", []))),
|
177
|
+
// Do NOT reverse for BigInt conversion; use little-endian as stored
|
178
|
+
IDCommitmentBigInt: buildBigIntFromUint8ArrayLE(idCommitmentLE),
|
179
|
+
IDSecretHash: fromLittleEndian(Keystore.fromArraylikeToBytes(_.get(obj, "identityCredential.idSecretHash", [])))
|
175
180
|
},
|
176
181
|
membership: {
|
177
182
|
treeIndex: _.get(obj, "treeIndex"),
|
@@ -208,13 +213,16 @@ class Keystore {
|
|
208
213
|
// follows nwaku implementation
|
209
214
|
// https://github.com/waku-org/nwaku/blob/f05528d4be3d3c876a8b07f9bb7dfaae8aa8ec6e/waku/waku_keystore/protocol_types.nim#L98
|
210
215
|
static fromIdentityToBytes(options) {
|
216
|
+
function toLittleEndian(bytes) {
|
217
|
+
return new Uint8Array(bytes).reverse();
|
218
|
+
}
|
211
219
|
return utf8ToBytes(JSON.stringify({
|
212
220
|
treeIndex: options.membership.treeIndex,
|
213
221
|
identityCredential: {
|
214
|
-
idCommitment: Array.from(options.identity.IDCommitment),
|
215
|
-
idNullifier: Array.from(options.identity.IDNullifier),
|
216
|
-
idSecretHash: Array.from(options.identity.IDSecretHash),
|
217
|
-
idTrapdoor: Array.from(options.identity.IDTrapdoor)
|
222
|
+
idCommitment: Array.from(toLittleEndian(options.identity.IDCommitment)),
|
223
|
+
idNullifier: Array.from(toLittleEndian(options.identity.IDNullifier)),
|
224
|
+
idSecretHash: Array.from(toLittleEndian(options.identity.IDSecretHash)),
|
225
|
+
idTrapdoor: Array.from(toLittleEndian(options.identity.IDTrapdoor))
|
218
226
|
},
|
219
227
|
membershipContract: {
|
220
228
|
chainId: options.membership.chainId,
|
@@ -1,4 +1,14 @@
|
|
1
|
+
import { Version } from '../../core/dist/lib/message/version_0.js';
|
2
|
+
import '../../core/dist/lib/filter/filter.js';
|
3
|
+
import '../../core/dist/lib/light_push/light_push.js';
|
4
|
+
import '../../core/dist/lib/store/store.js';
|
5
|
+
import '../../core/dist/lib/connection_manager/connection_manager.js';
|
6
|
+
import '../../interfaces/dist/protocols.js';
|
7
|
+
import '../../interfaces/dist/connection_manager.js';
|
8
|
+
import '../../interfaces/dist/health_indicator.js';
|
1
9
|
import { utf8ToBytes } from '../../utils/dist/bytes/index.js';
|
10
|
+
import '../../../node_modules/debug/src/browser.js';
|
11
|
+
import '../../core/dist/lib/metadata/metadata.js';
|
2
12
|
import { epochBytesToInt } from './utils/epoch.js';
|
3
13
|
|
4
14
|
function toRLNSignal(contentTopic, msg) {
|
@@ -10,6 +20,7 @@ class RlnMessage {
|
|
10
20
|
msg;
|
11
21
|
rateLimitProof;
|
12
22
|
pubsubTopic = "";
|
23
|
+
version = Version;
|
13
24
|
constructor(rlnInstance, msg, rateLimitProof) {
|
14
25
|
this.rlnInstance = rlnInstance;
|
15
26
|
this.msg = msg;
|
@@ -39,14 +39,8 @@ function writeUIntLE(buf, value, offset, byteLength, noAssert) {
|
|
39
39
|
}
|
40
40
|
return buf;
|
41
41
|
}
|
42
|
-
|
43
|
-
*
|
44
|
-
* @param array: Uint8Array
|
45
|
-
* @returns BigInt
|
46
|
-
*/
|
47
|
-
function buildBigIntFromUint8Array(array, byteOffset = 0) {
|
48
|
-
const dataView = new DataView(array.buffer);
|
49
|
-
return dataView.getBigUint64(byteOffset, true);
|
42
|
+
function buildBigIntFromUint8ArrayLE(bytes) {
|
43
|
+
return bytes.reduce((acc, byte, i) => acc + BigInt(byte) * (1n << (8n * BigInt(i))), 0n);
|
50
44
|
}
|
51
45
|
/**
|
52
46
|
* Fills with zeros to set length
|
@@ -62,4 +56,4 @@ function zeroPadLE(array, length) {
|
|
62
56
|
return result;
|
63
57
|
}
|
64
58
|
|
65
|
-
export {
|
59
|
+
export { buildBigIntFromUint8ArrayLE, concatenate, writeUIntLE, zeroPadLE };
|