@waku/rln 0.1.6-b4748fd.0 → 0.1.6-b58de3a.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/_virtual/utils.js +2 -2
- package/bundle/_virtual/utils2.js +2 -2
- package/bundle/node_modules/@chainsafe/bls-keystore/node_modules/@noble/hashes/_sha2.js +1 -1
- package/bundle/node_modules/@chainsafe/bls-keystore/node_modules/@noble/hashes/hmac.js +1 -1
- package/bundle/node_modules/@chainsafe/bls-keystore/node_modules/@noble/hashes/pbkdf2.js +1 -1
- package/bundle/node_modules/@chainsafe/bls-keystore/node_modules/@noble/hashes/scrypt.js +1 -1
- package/bundle/node_modules/@chainsafe/bls-keystore/node_modules/@noble/hashes/sha256.js +1 -1
- package/bundle/node_modules/@chainsafe/bls-keystore/node_modules/@noble/hashes/sha512.js +1 -1
- package/bundle/node_modules/@chainsafe/bls-keystore/node_modules/@noble/hashes/utils.js +1 -1
- package/bundle/node_modules/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/random.js +1 -1
- package/bundle/node_modules/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/utils.js +2 -2
- package/bundle/packages/rln/dist/contract/rln_base_contract.js +4 -24
- package/bundle/packages/rln/dist/credentials_manager.js +16 -13
- package/bundle/packages/rln/dist/identity.js +8 -5
- package/bundle/packages/rln/dist/keystore/keystore.js +10 -8
- package/bundle/packages/rln/dist/utils/bytes.js +10 -14
- package/dist/.tsbuildinfo +1 -1
- package/dist/contract/rln_base_contract.d.ts +0 -1
- package/dist/contract/rln_base_contract.js +4 -24
- package/dist/contract/rln_base_contract.js.map +1 -1
- package/dist/contract/test-utils.d.ts +39 -0
- package/dist/contract/test-utils.js +118 -0
- package/dist/contract/test-utils.js.map +1 -0
- package/dist/credentials_manager.js +16 -13
- package/dist/credentials_manager.js.map +1 -1
- package/dist/identity.d.ts +2 -4
- package/dist/identity.js +6 -5
- package/dist/identity.js.map +1 -1
- package/dist/keystore/keystore.js +10 -8
- package/dist/keystore/keystore.js.map +1 -1
- package/dist/utils/bytes.d.ts +1 -2
- package/dist/utils/bytes.js +9 -13
- 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 +11 -37
- package/src/contract/test-utils.ts +179 -0
- package/src/credentials_manager.ts +27 -20
- package/src/identity.ts +7 -5
- package/src/keystore/keystore.ts +33 -17
- package/src/utils/bytes.ts +19 -21
- package/src/utils/index.ts +1 -1
package/package.json
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"name":"@waku/rln","version":"0.1.6-
|
1
|
+
{"name":"@waku/rln","version":"0.1.6-b58de3a.0","description":"RLN (Rate Limiting Nullifier) implementation for Waku","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"type":"module","homepage":"https://github.com/waku-org/js-waku/tree/master/packages/rln#readme","repository":{"type":"git","url":"https://github.com/waku-org/js-waku.git"},"bugs":{"url":"https://github.com/waku-org/js-waku/issues"},"license":"MIT OR Apache-2.0","keywords":["waku","rln","rate-limiting","privacy","web3"],"scripts":{"build":"run-s build:**","build:copy":"mkdir -p dist/resources && cp -r src/resources/* dist/resources/","build:esm":"tsc","build:bundle":"rollup --config rollup.config.js","fix":"run-s fix:*","fix:lint":"eslint src *.js --fix","check":"run-s check:*","check:tsc":"tsc -p tsconfig.dev.json","check:lint":"eslint \"src/!(resources)/**/*.{ts,js}\" *.js","check:spelling":"cspell \"{README.md,src/**/*.ts}\"","test":"NODE_ENV=test run-s test:*","test:browser":"karma start karma.conf.cjs","watch:build":"tsc -p tsconfig.json -w","watch:test":"mocha --watch","prepublish":"npm run build","reset-hard":"git clean -dfx -e .idea && git reset --hard && npm i && npm run build"},"engines":{"node":">=20"},"devDependencies":{"@rollup/plugin-commonjs":"^25.0.7","@rollup/plugin-json":"^6.0.0","@rollup/plugin-node-resolve":"^15.2.3","@types/chai":"^5.0.1","@types/chai-spies":"^1.0.6","@waku/interfaces":"0.0.31-b58de3a.0","@types/deep-equal-in-any-order":"^1.0.4","@types/lodash":"^4.17.15","@types/sinon":"^17.0.3","@waku/build-utils":"^1.0.0","@waku/message-encryption":"0.0.34-b58de3a.0","deep-equal-in-any-order":"^2.0.6","fast-check":"^3.23.2","rollup-plugin-copy":"^3.5.0"},"files":["dist","bundle","src/**/*.ts","!**/*.spec.*","!**/*.json","CHANGELOG.md","LICENSE","README.md"],"dependencies":{"@chainsafe/bls-keystore":"3.0.0","@waku/core":"0.0.36-b58de3a.0","@waku/utils":"0.0.24-b58de3a.0","@noble/hashes":"^1.2.0","@waku/zerokit-rln-wasm":"^0.0.13","ethereum-cryptography":"^3.1.0","ethers":"^5.7.2","lodash":"^4.17.21","uuid":"^11.0.5","chai":"^5.1.2","chai-as-promised":"^8.0.1","chai-spies":"^1.1.0","chai-subset":"^1.6.0","sinon":"^19.0.2"}}
|
@@ -3,7 +3,6 @@ import { ethers } from "ethers";
|
|
3
3
|
|
4
4
|
import { IdentityCredential } from "../identity.js";
|
5
5
|
import { DecryptedCredentials } from "../keystore/types.js";
|
6
|
-
import { buildBigIntFromUint8ArrayBE } from "../utils/bytes.js";
|
7
6
|
|
8
7
|
import { RLN_ABI } from "./abi.js";
|
9
8
|
import {
|
@@ -506,32 +505,6 @@ export class RLNBaseContract {
|
|
506
505
|
}
|
507
506
|
}
|
508
507
|
|
509
|
-
private getIdCommitmentBigInt(bytes: Uint8Array): bigint {
|
510
|
-
let idCommitmentBigIntBE = buildBigIntFromUint8ArrayBE(bytes);
|
511
|
-
log.info("1");
|
512
|
-
|
513
|
-
if (!this.contract) {
|
514
|
-
throw Error("RLN contract is not initialized");
|
515
|
-
}
|
516
|
-
|
517
|
-
const idCommitmentBigIntLimit = this.contract.idCommitmentBigIntLimit;
|
518
|
-
|
519
|
-
log.info("idCommitmentBigIntBE: ", idCommitmentBigIntBE);
|
520
|
-
log.info("idCommitmentBigIntLimit: ", idCommitmentBigIntLimit);
|
521
|
-
log.info(
|
522
|
-
"idCommitmentBigIntBE >= idCommitmentBigIntLimit: ",
|
523
|
-
idCommitmentBigIntBE >= idCommitmentBigIntLimit
|
524
|
-
);
|
525
|
-
|
526
|
-
if (idCommitmentBigIntBE >= idCommitmentBigIntLimit) {
|
527
|
-
log.warn(
|
528
|
-
`ID commitment is greater than Q, reducing it by Q(idCommitmentBigIntLimit): ${idCommitmentBigIntBE} % ${idCommitmentBigIntLimit}`
|
529
|
-
);
|
530
|
-
idCommitmentBigIntBE = idCommitmentBigIntBE % idCommitmentBigIntLimit;
|
531
|
-
}
|
532
|
-
return idCommitmentBigIntBE;
|
533
|
-
}
|
534
|
-
|
535
508
|
public async registerWithIdentity(
|
536
509
|
identity: IdentityCredential
|
537
510
|
): Promise<DecryptedCredentials | undefined> {
|
@@ -540,12 +513,10 @@ export class RLNBaseContract {
|
|
540
513
|
`Registering identity with rate limit: ${this.rateLimit} messages/epoch`
|
541
514
|
);
|
542
515
|
|
543
|
-
const idCommitmentBigInt = this.getIdCommitmentBigInt(
|
544
|
-
identity.IDCommitment
|
545
|
-
);
|
546
|
-
|
547
516
|
// Check if the ID commitment is already registered
|
548
|
-
const existingIndex = await this.getMemberIndex(
|
517
|
+
const existingIndex = await this.getMemberIndex(
|
518
|
+
identity.IDCommitmentBigInt
|
519
|
+
);
|
549
520
|
if (existingIndex) {
|
550
521
|
throw new Error(
|
551
522
|
`ID commitment is already registered with index ${existingIndex}`
|
@@ -561,16 +532,19 @@ export class RLNBaseContract {
|
|
561
532
|
}
|
562
533
|
|
563
534
|
const estimatedGas = await this.contract.estimateGas.register(
|
564
|
-
|
535
|
+
identity.IDCommitmentBigInt,
|
565
536
|
this.rateLimit,
|
566
537
|
[]
|
567
538
|
);
|
568
539
|
const gasLimit = estimatedGas.add(10000);
|
569
540
|
|
570
541
|
const txRegisterResponse: ethers.ContractTransaction =
|
571
|
-
await this.contract.register(
|
572
|
-
|
573
|
-
|
542
|
+
await this.contract.register(
|
543
|
+
identity.IDCommitmentBigInt,
|
544
|
+
this.rateLimit,
|
545
|
+
[],
|
546
|
+
{ gasLimit }
|
547
|
+
);
|
574
548
|
|
575
549
|
const txRegisterReceipt = await txRegisterResponse.wait();
|
576
550
|
|
@@ -666,7 +640,7 @@ export class RLNBaseContract {
|
|
666
640
|
permit.v,
|
667
641
|
permit.r,
|
668
642
|
permit.s,
|
669
|
-
|
643
|
+
identity.IDCommitmentBigInt,
|
670
644
|
this.rateLimit,
|
671
645
|
idCommitmentsToErase.map((id) => ethers.BigNumber.from(id))
|
672
646
|
);
|
@@ -0,0 +1,179 @@
|
|
1
|
+
import { hexToBytes } from "@waku/utils/bytes";
|
2
|
+
import { expect } from "chai";
|
3
|
+
import * as ethers from "ethers";
|
4
|
+
import sinon from "sinon";
|
5
|
+
|
6
|
+
import type { IdentityCredential } from "../identity.js";
|
7
|
+
|
8
|
+
import { DEFAULT_RATE_LIMIT, LINEA_CONTRACT } from "./constants.js";
|
9
|
+
|
10
|
+
export const mockRateLimits = {
|
11
|
+
minRate: 20,
|
12
|
+
maxRate: 600,
|
13
|
+
maxTotalRate: 1200,
|
14
|
+
currentTotalRate: 500
|
15
|
+
};
|
16
|
+
|
17
|
+
type MockProvider = {
|
18
|
+
getLogs: () => never[];
|
19
|
+
getBlockNumber: () => Promise<number>;
|
20
|
+
getNetwork: () => Promise<{ chainId: number }>;
|
21
|
+
};
|
22
|
+
|
23
|
+
type MockFilters = {
|
24
|
+
MembershipRegistered: () => { address: string };
|
25
|
+
MembershipErased: () => { address: string };
|
26
|
+
MembershipExpired: () => { address: string };
|
27
|
+
};
|
28
|
+
|
29
|
+
export function createMockProvider(): MockProvider {
|
30
|
+
return {
|
31
|
+
getLogs: () => [],
|
32
|
+
getBlockNumber: () => Promise.resolve(1000),
|
33
|
+
getNetwork: () => Promise.resolve({ chainId: 11155111 })
|
34
|
+
};
|
35
|
+
}
|
36
|
+
|
37
|
+
export function createMockFilters(): MockFilters {
|
38
|
+
return {
|
39
|
+
MembershipRegistered: () => ({ address: LINEA_CONTRACT.address }),
|
40
|
+
MembershipErased: () => ({ address: LINEA_CONTRACT.address }),
|
41
|
+
MembershipExpired: () => ({ address: LINEA_CONTRACT.address })
|
42
|
+
};
|
43
|
+
}
|
44
|
+
|
45
|
+
type ContractOverrides = Partial<{
|
46
|
+
filters: Record<string, unknown>;
|
47
|
+
[key: string]: unknown;
|
48
|
+
}>;
|
49
|
+
|
50
|
+
export function createMockRegistryContract(
|
51
|
+
overrides: ContractOverrides = {}
|
52
|
+
): ethers.Contract {
|
53
|
+
const filters = {
|
54
|
+
MembershipRegistered: () => ({ address: LINEA_CONTRACT.address }),
|
55
|
+
MembershipErased: () => ({ address: LINEA_CONTRACT.address }),
|
56
|
+
MembershipExpired: () => ({ address: LINEA_CONTRACT.address })
|
57
|
+
};
|
58
|
+
|
59
|
+
const baseContract = {
|
60
|
+
minMembershipRateLimit: () =>
|
61
|
+
Promise.resolve(ethers.BigNumber.from(mockRateLimits.minRate)),
|
62
|
+
maxMembershipRateLimit: () =>
|
63
|
+
Promise.resolve(ethers.BigNumber.from(mockRateLimits.maxRate)),
|
64
|
+
maxTotalRateLimit: () =>
|
65
|
+
Promise.resolve(ethers.BigNumber.from(mockRateLimits.maxTotalRate)),
|
66
|
+
currentTotalRateLimit: () =>
|
67
|
+
Promise.resolve(ethers.BigNumber.from(mockRateLimits.currentTotalRate)),
|
68
|
+
queryFilter: () => [],
|
69
|
+
provider: createMockProvider(),
|
70
|
+
filters,
|
71
|
+
on: () => ({}),
|
72
|
+
removeAllListeners: () => ({}),
|
73
|
+
register: () => ({
|
74
|
+
wait: () =>
|
75
|
+
Promise.resolve({
|
76
|
+
events: [mockRLNRegisteredEvent()]
|
77
|
+
})
|
78
|
+
}),
|
79
|
+
estimateGas: {
|
80
|
+
register: () => Promise.resolve(ethers.BigNumber.from(100000))
|
81
|
+
},
|
82
|
+
functions: {
|
83
|
+
register: () => Promise.resolve()
|
84
|
+
},
|
85
|
+
getMemberIndex: () => Promise.resolve(null),
|
86
|
+
interface: {
|
87
|
+
getEvent: (eventName: string) => ({
|
88
|
+
name: eventName,
|
89
|
+
format: () => {}
|
90
|
+
})
|
91
|
+
},
|
92
|
+
address: LINEA_CONTRACT.address
|
93
|
+
};
|
94
|
+
|
95
|
+
// Merge overrides while preserving filters
|
96
|
+
const merged = {
|
97
|
+
...baseContract,
|
98
|
+
...overrides,
|
99
|
+
filters: { ...filters, ...(overrides.filters || {}) }
|
100
|
+
};
|
101
|
+
|
102
|
+
return merged as unknown as ethers.Contract;
|
103
|
+
}
|
104
|
+
|
105
|
+
export function mockRLNRegisteredEvent(idCommitment?: string): ethers.Event {
|
106
|
+
return {
|
107
|
+
args: {
|
108
|
+
idCommitment:
|
109
|
+
idCommitment ||
|
110
|
+
"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
|
111
|
+
membershipRateLimit: ethers.BigNumber.from(DEFAULT_RATE_LIMIT),
|
112
|
+
index: ethers.BigNumber.from(1)
|
113
|
+
},
|
114
|
+
event: "MembershipRegistered"
|
115
|
+
} as unknown as ethers.Event;
|
116
|
+
}
|
117
|
+
|
118
|
+
export function formatIdCommitment(idCommitmentBigInt: bigint): string {
|
119
|
+
return "0x" + idCommitmentBigInt.toString(16).padStart(64, "0");
|
120
|
+
}
|
121
|
+
|
122
|
+
export function createRegisterStub(
|
123
|
+
identity: IdentityCredential
|
124
|
+
): sinon.SinonStub {
|
125
|
+
return sinon.stub().callsFake(() => ({
|
126
|
+
wait: () =>
|
127
|
+
Promise.resolve({
|
128
|
+
events: [
|
129
|
+
{
|
130
|
+
event: "MembershipRegistered",
|
131
|
+
args: {
|
132
|
+
idCommitment: formatIdCommitment(identity.IDCommitmentBigInt),
|
133
|
+
membershipRateLimit: ethers.BigNumber.from(DEFAULT_RATE_LIMIT),
|
134
|
+
index: ethers.BigNumber.from(1)
|
135
|
+
}
|
136
|
+
}
|
137
|
+
]
|
138
|
+
})
|
139
|
+
}));
|
140
|
+
}
|
141
|
+
|
142
|
+
export function verifyRegistration(
|
143
|
+
decryptedCredentials: any,
|
144
|
+
identity: IdentityCredential,
|
145
|
+
registerStub: sinon.SinonStub,
|
146
|
+
insertMemberSpy: sinon.SinonStub
|
147
|
+
): void {
|
148
|
+
if (!decryptedCredentials) {
|
149
|
+
throw new Error("Decrypted credentials should not be undefined");
|
150
|
+
}
|
151
|
+
|
152
|
+
// Verify registration call
|
153
|
+
expect(
|
154
|
+
registerStub.calledWith(
|
155
|
+
sinon.match.same(identity.IDCommitmentBigInt),
|
156
|
+
sinon.match.same(DEFAULT_RATE_LIMIT),
|
157
|
+
sinon.match.array,
|
158
|
+
sinon.match.object
|
159
|
+
)
|
160
|
+
).to.be.true;
|
161
|
+
|
162
|
+
// Verify credential properties
|
163
|
+
expect(decryptedCredentials).to.have.property("identity");
|
164
|
+
expect(decryptedCredentials).to.have.property("membership");
|
165
|
+
expect(decryptedCredentials.membership).to.include({
|
166
|
+
address: LINEA_CONTRACT.address,
|
167
|
+
treeIndex: 1
|
168
|
+
});
|
169
|
+
|
170
|
+
// Verify member insertion
|
171
|
+
const expectedIdCommitment = ethers.utils.zeroPad(
|
172
|
+
hexToBytes(formatIdCommitment(identity.IDCommitmentBigInt)),
|
173
|
+
32
|
174
|
+
);
|
175
|
+
expect(insertMemberSpy.callCount).to.equal(1);
|
176
|
+
expect(insertMemberSpy.getCall(0).args[0]).to.deep.equal(
|
177
|
+
expectedIdCommitment
|
178
|
+
);
|
179
|
+
}
|
@@ -13,7 +13,10 @@ import type {
|
|
13
13
|
} from "./keystore/index.js";
|
14
14
|
import { KeystoreEntity, Password } from "./keystore/types.js";
|
15
15
|
import { RegisterMembershipOptions, StartRLNOptions } from "./types.js";
|
16
|
-
import {
|
16
|
+
import {
|
17
|
+
buildBigIntFromUint8ArrayLE,
|
18
|
+
extractMetaMaskSigner
|
19
|
+
} from "./utils/index.js";
|
17
20
|
import { Zerokit } from "./zerokit.js";
|
18
21
|
|
19
22
|
const log = new Logger("waku:credentials");
|
@@ -258,31 +261,35 @@ export class RLNCredentialsManager {
|
|
258
261
|
|
259
262
|
// Generate deterministic values using HMAC-SHA256
|
260
263
|
// We use different context strings for each component to ensure they're different
|
261
|
-
const
|
262
|
-
const
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
);
|
264
|
+
const idTrapdoor = hmac(sha256, seedBytes, encoder.encode("IDTrapdoor"));
|
265
|
+
const idNullifier = hmac(sha256, seedBytes, encoder.encode("IDNullifier"));
|
266
|
+
|
267
|
+
const combinedBytes = new Uint8Array([...idTrapdoor, ...idNullifier]);
|
268
|
+
const idSecretHash = sha256(combinedBytes);
|
267
269
|
|
268
|
-
const
|
269
|
-
const idSecretHashBE = sha256(combinedBytes);
|
270
|
+
const idCommitment = sha256(idSecretHash);
|
270
271
|
|
271
|
-
|
272
|
+
let idCommitmentBigInt = buildBigIntFromUint8ArrayLE(idCommitment);
|
273
|
+
if (!this.contract) {
|
274
|
+
throw Error("RLN contract is not initialized");
|
275
|
+
}
|
272
276
|
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
277
|
+
const idCommitmentBigIntLimit = this.contract.idCommitmentBigIntLimit;
|
278
|
+
|
279
|
+
if (idCommitmentBigInt >= idCommitmentBigIntLimit) {
|
280
|
+
log.warn(
|
281
|
+
`ID commitment is greater than Q, reducing it by Q(idCommitmentBigIntLimit): ${idCommitmentBigInt} % ${idCommitmentBigIntLimit}`
|
282
|
+
);
|
283
|
+
idCommitmentBigInt = idCommitmentBigInt % idCommitmentBigIntLimit;
|
284
|
+
}
|
279
285
|
|
280
286
|
log.info("Successfully generated identity credential");
|
281
287
|
return new IdentityCredential(
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
288
|
+
idTrapdoor,
|
289
|
+
idNullifier,
|
290
|
+
idSecretHash,
|
291
|
+
idCommitment,
|
292
|
+
idCommitmentBigInt
|
286
293
|
);
|
287
294
|
}
|
288
295
|
}
|
package/src/identity.ts
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
+
import { buildBigIntFromUint8ArrayLE } from "./utils/index.js";
|
2
|
+
|
1
3
|
export class IdentityCredential {
|
2
|
-
/**
|
3
|
-
* All variables are in little-endian format
|
4
|
-
*/
|
5
4
|
public constructor(
|
6
5
|
public readonly IDTrapdoor: Uint8Array,
|
7
6
|
public readonly IDNullifier: Uint8Array,
|
8
7
|
public readonly IDSecretHash: Uint8Array,
|
9
|
-
public readonly IDCommitment: Uint8Array
|
8
|
+
public readonly IDCommitment: Uint8Array,
|
9
|
+
public readonly IDCommitmentBigInt: bigint
|
10
10
|
) {}
|
11
11
|
|
12
12
|
public static fromBytes(memKeys: Uint8Array): IdentityCredential {
|
@@ -18,12 +18,14 @@ export class IdentityCredential {
|
|
18
18
|
const idNullifier = memKeys.subarray(32, 64);
|
19
19
|
const idSecretHash = memKeys.subarray(64, 96);
|
20
20
|
const idCommitment = memKeys.subarray(96, 128);
|
21
|
+
const idCommitmentBigInt = buildBigIntFromUint8ArrayLE(idCommitment);
|
21
22
|
|
22
23
|
return new IdentityCredential(
|
23
24
|
idTrapdoor,
|
24
25
|
idNullifier,
|
25
26
|
idSecretHash,
|
26
|
-
idCommitment
|
27
|
+
idCommitment,
|
28
|
+
idCommitmentBigInt
|
27
29
|
);
|
28
30
|
}
|
29
31
|
}
|
package/src/keystore/keystore.ts
CHANGED
@@ -14,6 +14,8 @@ import {
|
|
14
14
|
import _ from "lodash";
|
15
15
|
import { v4 as uuidV4 } from "uuid";
|
16
16
|
|
17
|
+
import { buildBigIntFromUint8ArrayLE } from "../utils/bytes.js";
|
18
|
+
|
17
19
|
import { decryptEipKeystore, keccak256Checksum } from "./cipher.js";
|
18
20
|
import { isCredentialValid, isKeystoreValid } from "./schema_validator.js";
|
19
21
|
import type {
|
@@ -244,29 +246,43 @@ export class Keystore {
|
|
244
246
|
private static fromBytesToIdentity(
|
245
247
|
bytes: Uint8Array
|
246
248
|
): undefined | KeystoreEntity {
|
249
|
+
function fromLittleEndian(bytes: Uint8Array): Uint8Array {
|
250
|
+
return new Uint8Array(bytes).reverse();
|
251
|
+
}
|
247
252
|
try {
|
248
253
|
const str = bytesToUtf8(bytes);
|
249
254
|
const obj = JSON.parse(str);
|
250
255
|
|
251
|
-
|
252
|
-
_.get(obj, "identityCredential.idCommitment", [])
|
253
|
-
);
|
254
|
-
const idTrapdoorLE = Keystore.fromArraylikeToBytes(
|
255
|
-
_.get(obj, "identityCredential.idTrapdoor", [])
|
256
|
-
);
|
257
|
-
const idNullifierLE = Keystore.fromArraylikeToBytes(
|
258
|
-
_.get(obj, "identityCredential.idNullifier", [])
|
259
|
-
);
|
260
|
-
const idSecretHashLE = Keystore.fromArraylikeToBytes(
|
261
|
-
_.get(obj, "identityCredential.idSecretHash", [])
|
262
|
-
);
|
263
|
-
|
256
|
+
// TODO: add runtime validation of nwaku credentials
|
264
257
|
return {
|
265
258
|
identity: {
|
266
|
-
IDCommitment:
|
267
|
-
|
268
|
-
|
269
|
-
|
259
|
+
IDCommitment: fromLittleEndian(
|
260
|
+
Keystore.fromArraylikeToBytes(
|
261
|
+
_.get(obj, "identityCredential.idCommitment", [])
|
262
|
+
)
|
263
|
+
),
|
264
|
+
IDTrapdoor: fromLittleEndian(
|
265
|
+
Keystore.fromArraylikeToBytes(
|
266
|
+
_.get(obj, "identityCredential.idTrapdoor", [])
|
267
|
+
)
|
268
|
+
),
|
269
|
+
IDNullifier: fromLittleEndian(
|
270
|
+
Keystore.fromArraylikeToBytes(
|
271
|
+
_.get(obj, "identityCredential.idNullifier", [])
|
272
|
+
)
|
273
|
+
),
|
274
|
+
IDCommitmentBigInt: buildBigIntFromUint8ArrayLE(
|
275
|
+
fromLittleEndian(
|
276
|
+
Keystore.fromArraylikeToBytes(
|
277
|
+
_.get(obj, "identityCredential.idCommitment", [])
|
278
|
+
)
|
279
|
+
)
|
280
|
+
),
|
281
|
+
IDSecretHash: fromLittleEndian(
|
282
|
+
Keystore.fromArraylikeToBytes(
|
283
|
+
_.get(obj, "identityCredential.idSecretHash", [])
|
284
|
+
)
|
285
|
+
)
|
270
286
|
},
|
271
287
|
membership: {
|
272
288
|
treeIndex: _.get(obj, "treeIndex"),
|
package/src/utils/bytes.ts
CHANGED
@@ -17,13 +17,18 @@ export function concatenate(...input: Uint8Array[]): Uint8Array {
|
|
17
17
|
return result;
|
18
18
|
}
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
20
|
+
// Adapted from https://github.com/feross/buffer
|
21
|
+
function checkInt(
|
22
|
+
buf: Uint8Array,
|
23
|
+
value: number,
|
24
|
+
offset: number,
|
25
|
+
ext: number,
|
26
|
+
max: number,
|
27
|
+
min: number
|
28
|
+
): void {
|
29
|
+
if (value > max || value < min)
|
30
|
+
throw new RangeError('"value" argument is out of bounds');
|
31
|
+
if (offset + ext > buf.length) throw new RangeError("Index out of range");
|
27
32
|
}
|
28
33
|
|
29
34
|
export function writeUIntLE(
|
@@ -51,6 +56,13 @@ export function writeUIntLE(
|
|
51
56
|
return buf;
|
52
57
|
}
|
53
58
|
|
59
|
+
export function buildBigIntFromUint8ArrayLE(bytes: Uint8Array): bigint {
|
60
|
+
return bytes.reduce(
|
61
|
+
(acc, byte, i) => acc + BigInt(byte) * (1n << (8n * BigInt(i))),
|
62
|
+
0n
|
63
|
+
);
|
64
|
+
}
|
65
|
+
|
54
66
|
/**
|
55
67
|
* Fills with zeros to set length
|
56
68
|
* @param array little endian Uint8Array
|
@@ -64,17 +76,3 @@ export function zeroPadLE(array: Uint8Array, length: number): Uint8Array {
|
|
64
76
|
}
|
65
77
|
return result;
|
66
78
|
}
|
67
|
-
|
68
|
-
// Adapted from https://github.com/feross/buffer
|
69
|
-
function checkInt(
|
70
|
-
buf: Uint8Array,
|
71
|
-
value: number,
|
72
|
-
offset: number,
|
73
|
-
ext: number,
|
74
|
-
max: number,
|
75
|
-
min: number
|
76
|
-
): void {
|
77
|
-
if (value > max || value < min)
|
78
|
-
throw new RangeError('"value" argument is out of bounds');
|
79
|
-
if (offset + ext > buf.length) throw new RangeError("Index out of range");
|
80
|
-
}
|
package/src/utils/index.ts
CHANGED