@waku/rln 0.1.6-f7c290d.0 → 0.1.6
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/CHANGELOG.md +29 -0
- package/bundle/_virtual/utils.js +2 -2
- package/bundle/_virtual/utils2.js +2 -2
- package/bundle/index.js +1 -1
- 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/node_modules/@chainsafe/is-ip/lib/is-ip.js +12 -0
- package/bundle/node_modules/@chainsafe/is-ip/lib/parse.js +26 -0
- package/bundle/node_modules/@chainsafe/is-ip/lib/parser.js +202 -0
- package/bundle/node_modules/@ethersproject/bignumber/lib.esm/bignumber.js +1 -1
- package/bundle/node_modules/@multiformats/multiaddr/dist/src/constants.js +43 -0
- package/bundle/node_modules/@multiformats/multiaddr/dist/src/errors.js +17 -0
- package/bundle/node_modules/@multiformats/multiaddr/dist/src/registry.js +245 -0
- package/bundle/node_modules/@multiformats/multiaddr/dist/src/utils.js +191 -0
- package/bundle/node_modules/@multiformats/multiaddr/dist/src/validation.js +30 -0
- package/bundle/node_modules/debug/src/browser.js +1 -1
- package/bundle/node_modules/debug/src/common.js +1 -1
- package/bundle/node_modules/lodash/lodash.js +5 -5
- package/bundle/node_modules/multiformats/dist/src/bases/base.js +12 -9
- package/bundle/node_modules/multiformats/dist/src/bytes.js +19 -3
- package/bundle/node_modules/multiformats/dist/src/cid.js +371 -0
- package/bundle/node_modules/multiformats/dist/src/hashes/digest.js +62 -0
- package/bundle/node_modules/multiformats/dist/src/varint.js +15 -0
- package/bundle/node_modules/multiformats/dist/src/vendor/varint.js +78 -0
- package/bundle/node_modules/uint8arrays/dist/src/concat.js +20 -0
- package/bundle/node_modules/uint8arrays/dist/src/to-string.js +19 -0
- package/bundle/node_modules/uint8arrays/dist/src/util/as-uint8array.js +9 -0
- package/bundle/packages/core/dist/lib/connection_manager/connection_manager.js +1 -3
- package/bundle/packages/proto/dist/generated/filter.js +2 -0
- package/bundle/packages/proto/dist/generated/filter_v2.js +2 -0
- package/bundle/packages/proto/dist/generated/light_push.js +2 -0
- package/bundle/packages/proto/dist/generated/message.js +2 -0
- package/bundle/packages/proto/dist/generated/metadata.js +2 -0
- package/bundle/packages/proto/dist/generated/peer_exchange.js +2 -0
- package/bundle/packages/proto/dist/generated/sds_message.js +2 -0
- package/bundle/packages/proto/dist/generated/store_v3.js +2 -0
- package/bundle/packages/proto/dist/generated/topic_only_message.js +2 -0
- package/bundle/packages/rln/dist/contract/constants.js +1 -7
- package/bundle/packages/rln/dist/contract/rln_base_contract.js +2 -5
- package/bundle/packages/rln/dist/contract/rln_contract.js +2 -2
- package/bundle/packages/rln/dist/credentials_manager.js +16 -24
- package/bundle/packages/rln/dist/identity.js +6 -8
- package/bundle/packages/rln/dist/keystore/keystore.js +10 -21
- package/bundle/packages/rln/dist/proof.js +2 -2
- package/bundle/packages/rln/dist/utils/bytes.js +58 -103
- package/bundle/packages/rln/dist/utils/hash.js +3 -3
- package/bundle/packages/rln/dist/zerokit.js +17 -17
- package/dist/.tsbuildinfo +1 -1
- package/dist/codec.test-utils.d.ts +1 -1
- package/dist/contract/constants.d.ts +0 -6
- package/dist/contract/constants.js +0 -6
- package/dist/contract/constants.js.map +1 -1
- package/dist/contract/rln_base_contract.js +2 -5
- package/dist/contract/rln_base_contract.js.map +1 -1
- package/dist/contract/rln_contract.js +2 -2
- package/dist/contract/rln_contract.js.map +1 -1
- package/dist/contract/test-setup.d.ts +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.d.ts +0 -4
- package/dist/credentials_manager.js +16 -25
- package/dist/credentials_manager.js.map +1 -1
- package/dist/identity.d.ts +2 -5
- package/dist/identity.js +5 -8
- package/dist/identity.js.map +1 -1
- package/dist/keystore/credential_validation_generated.d.ts +0 -2
- package/dist/keystore/keystore.js +10 -21
- package/dist/keystore/keystore.js.map +1 -1
- package/dist/keystore/keystore_validation_generated.d.ts +0 -2
- package/dist/proof.js +2 -2
- package/dist/proof.js.map +1 -1
- package/dist/utils/bytes.d.ts +20 -42
- package/dist/utils/bytes.js +57 -102
- package/dist/utils/bytes.js.map +1 -1
- package/dist/utils/hash.js +5 -5
- package/dist/utils/hash.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/dist/zerokit.js +17 -17
- package/dist/zerokit.js.map +1 -1
- package/package.json +93 -1
- package/src/contract/constants.ts +0 -9
- package/src/contract/rln_base_contract.ts +3 -5
- package/src/contract/rln_contract.ts +2 -5
- package/src/contract/test-utils.ts +179 -0
- package/src/credentials_manager.ts +24 -46
- package/src/identity.ts +7 -11
- package/src/keystore/keystore.ts +22 -38
- package/src/proof.ts +2 -2
- package/src/utils/bytes.ts +72 -118
- package/src/utils/hash.ts +5 -15
- package/src/utils/index.ts +6 -1
- package/src/zerokit.ts +22 -30
- package/bundle/node_modules/@multiformats/multiaddr/dist/src/convert.js +0 -15
- package/bundle/node_modules/@multiformats/multiaddr/dist/src/multiaddr.js +0 -21
- package/bundle/node_modules/@multiformats/multiaddr/dist/src/protocols-table.js +0 -92
@@ -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
|
+
}
|
@@ -1,9 +1,9 @@
|
|
1
1
|
import { hmac } from "@noble/hashes/hmac";
|
2
|
-
import { sha256 } from "@noble/hashes/
|
2
|
+
import { sha256 } from "@noble/hashes/sha256";
|
3
3
|
import { Logger } from "@waku/utils";
|
4
4
|
import { ethers } from "ethers";
|
5
5
|
|
6
|
-
import {
|
6
|
+
import { LINEA_CONTRACT } from "./contract/constants.js";
|
7
7
|
import { RLNBaseContract } from "./contract/rln_base_contract.js";
|
8
8
|
import { IdentityCredential } from "./identity.js";
|
9
9
|
import { Keystore } from "./keystore/index.js";
|
@@ -13,8 +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 {
|
17
|
-
|
16
|
+
import {
|
17
|
+
buildBigIntFromUint8Array,
|
18
|
+
extractMetaMaskSigner
|
19
|
+
} from "./utils/index.js";
|
18
20
|
import { Zerokit } from "./zerokit.js";
|
19
21
|
|
20
22
|
const log = new Logger("waku:credentials");
|
@@ -114,9 +116,7 @@ export class RLNCredentialsManager {
|
|
114
116
|
);
|
115
117
|
} else {
|
116
118
|
log.info("Using local implementation to generate identity");
|
117
|
-
identity =
|
118
|
-
options.signature
|
119
|
-
);
|
119
|
+
identity = this.generateSeededIdentityCredential(options.signature);
|
120
120
|
}
|
121
121
|
}
|
122
122
|
|
@@ -249,9 +249,7 @@ export class RLNCredentialsManager {
|
|
249
249
|
* @param seed A string seed to generate the identity from
|
250
250
|
* @returns IdentityCredential
|
251
251
|
*/
|
252
|
-
private
|
253
|
-
seed: string
|
254
|
-
): Promise<IdentityCredential> {
|
252
|
+
private generateSeededIdentityCredential(seed: string): IdentityCredential {
|
255
253
|
log.info("Generating seeded identity credential");
|
256
254
|
// Convert the seed to bytes
|
257
255
|
const encoder = new TextEncoder();
|
@@ -259,46 +257,26 @@ export class RLNCredentialsManager {
|
|
259
257
|
|
260
258
|
// Generate deterministic values using HMAC-SHA256
|
261
259
|
// We use different context strings for each component to ensure they're different
|
262
|
-
const
|
263
|
-
const
|
264
|
-
sha256,
|
265
|
-
seedBytes,
|
266
|
-
encoder.encode("IDNullifier")
|
267
|
-
);
|
260
|
+
const idTrapdoor = hmac(sha256, seedBytes, encoder.encode("IDTrapdoor"));
|
261
|
+
const idNullifier = hmac(sha256, seedBytes, encoder.encode("IDNullifier"));
|
268
262
|
|
269
|
-
|
270
|
-
const
|
263
|
+
// Generate IDSecretHash as a hash of IDTrapdoor and IDNullifier
|
264
|
+
const combinedBytes = new Uint8Array([...idTrapdoor, ...idNullifier]);
|
265
|
+
const idSecretHash = sha256(combinedBytes);
|
271
266
|
|
272
|
-
|
273
|
-
const
|
267
|
+
// Generate IDCommitment as a hash of IDSecretHash
|
268
|
+
const idCommitment = sha256(idSecretHash);
|
274
269
|
|
275
|
-
|
276
|
-
|
277
|
-
|
270
|
+
// Convert IDCommitment to BigInt
|
271
|
+
const idCommitmentBigInt = buildBigIntFromUint8Array(idCommitment);
|
272
|
+
|
273
|
+
log.info("Successfully generated identity credential");
|
278
274
|
return new IdentityCredential(
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
275
|
+
idTrapdoor,
|
276
|
+
idNullifier,
|
277
|
+
idSecretHash,
|
278
|
+
idCommitment,
|
279
|
+
idCommitmentBigInt
|
283
280
|
);
|
284
281
|
}
|
285
|
-
|
286
|
-
/**
|
287
|
-
* Helper: take 32-byte BE, reduce mod Q, return 32-byte BE
|
288
|
-
*/
|
289
|
-
private reduceIdCommitment(
|
290
|
-
bytesBE: Uint8Array,
|
291
|
-
limit: bigint = DEFAULT_Q
|
292
|
-
): Uint8Array {
|
293
|
-
const nBE = BytesUtils.buildBigIntFromUint8ArrayBE(bytesBE);
|
294
|
-
|
295
|
-
if (nBE >= limit) {
|
296
|
-
log.warn(
|
297
|
-
`ID commitment is greater than Q, reducing it by Q: ${nBE} % ${limit}`
|
298
|
-
);
|
299
|
-
return BytesUtils.bigIntToUint8Array32BE(nBE % limit);
|
300
|
-
}
|
301
|
-
|
302
|
-
return bytesBE;
|
303
|
-
}
|
304
282
|
}
|
package/src/identity.ts
CHANGED
@@ -1,19 +1,13 @@
|
|
1
|
-
import {
|
1
|
+
import { buildBigIntFromUint8Array } from "./utils/index.js";
|
2
2
|
|
3
3
|
export class IdentityCredential {
|
4
|
-
public IDCommitmentBigInt: bigint;
|
5
|
-
/**
|
6
|
-
* All variables are in little-endian format
|
7
|
-
*/
|
8
4
|
public constructor(
|
9
5
|
public readonly IDTrapdoor: Uint8Array,
|
10
6
|
public readonly IDNullifier: Uint8Array,
|
11
7
|
public readonly IDSecretHash: Uint8Array,
|
12
|
-
public readonly IDCommitment: Uint8Array
|
13
|
-
|
14
|
-
|
15
|
-
BytesUtils.buildBigIntFromUint8ArrayBE(IDCommitment);
|
16
|
-
}
|
8
|
+
public readonly IDCommitment: Uint8Array,
|
9
|
+
public readonly IDCommitmentBigInt: bigint
|
10
|
+
) {}
|
17
11
|
|
18
12
|
public static fromBytes(memKeys: Uint8Array): IdentityCredential {
|
19
13
|
if (memKeys.length < 128) {
|
@@ -24,12 +18,14 @@ export class IdentityCredential {
|
|
24
18
|
const idNullifier = memKeys.subarray(32, 64);
|
25
19
|
const idSecretHash = memKeys.subarray(64, 96);
|
26
20
|
const idCommitment = memKeys.subarray(96, 128);
|
21
|
+
const idCommitmentBigInt = buildBigIntFromUint8Array(idCommitment, 32);
|
27
22
|
|
28
23
|
return new IdentityCredential(
|
29
24
|
idTrapdoor,
|
30
25
|
idNullifier,
|
31
26
|
idSecretHash,
|
32
|
-
idCommitment
|
27
|
+
idCommitment,
|
28
|
+
idCommitmentBigInt
|
33
29
|
);
|
34
30
|
}
|
35
31
|
}
|
package/src/keystore/keystore.ts
CHANGED
@@ -14,7 +14,7 @@ import {
|
|
14
14
|
import _ from "lodash";
|
15
15
|
import { v4 as uuidV4 } from "uuid";
|
16
16
|
|
17
|
-
import {
|
17
|
+
import { buildBigIntFromUint8Array } from "../utils/bytes.js";
|
18
18
|
|
19
19
|
import { decryptEipKeystore, keccak256Checksum } from "./cipher.js";
|
20
20
|
import { isCredentialValid, isKeystoreValid } from "./schema_validator.js";
|
@@ -250,35 +250,26 @@ export class Keystore {
|
|
250
250
|
const str = bytesToUtf8(bytes);
|
251
251
|
const obj = JSON.parse(str);
|
252
252
|
|
253
|
-
//
|
254
|
-
const idCommitmentLE = Keystore.fromArraylikeToBytes(
|
255
|
-
_.get(obj, "identityCredential.idCommitment", [])
|
256
|
-
);
|
257
|
-
const idTrapdoorLE = Keystore.fromArraylikeToBytes(
|
258
|
-
_.get(obj, "identityCredential.idTrapdoor", [])
|
259
|
-
);
|
260
|
-
const idNullifierLE = Keystore.fromArraylikeToBytes(
|
261
|
-
_.get(obj, "identityCredential.idNullifier", [])
|
262
|
-
);
|
263
|
-
const idSecretHashLE = Keystore.fromArraylikeToBytes(
|
264
|
-
_.get(obj, "identityCredential.idSecretHash", [])
|
265
|
-
);
|
266
|
-
|
267
|
-
// Big Endian
|
268
|
-
const idCommitmentBE = BytesUtils.switchEndianness(idCommitmentLE);
|
269
|
-
const idTrapdoorBE = BytesUtils.switchEndianness(idTrapdoorLE);
|
270
|
-
const idNullifierBE = BytesUtils.switchEndianness(idNullifierLE);
|
271
|
-
const idSecretHashBE = BytesUtils.switchEndianness(idSecretHashLE);
|
272
|
-
const idCommitmentBigInt =
|
273
|
-
BytesUtils.buildBigIntFromUint8ArrayBE(idCommitmentBE);
|
274
|
-
|
253
|
+
// TODO: add runtime validation of nwaku credentials
|
275
254
|
return {
|
276
255
|
identity: {
|
277
|
-
IDCommitment:
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
256
|
+
IDCommitment: Keystore.fromArraylikeToBytes(
|
257
|
+
_.get(obj, "identityCredential.idCommitment", [])
|
258
|
+
),
|
259
|
+
IDTrapdoor: Keystore.fromArraylikeToBytes(
|
260
|
+
_.get(obj, "identityCredential.idTrapdoor", [])
|
261
|
+
),
|
262
|
+
IDNullifier: Keystore.fromArraylikeToBytes(
|
263
|
+
_.get(obj, "identityCredential.idNullifier", [])
|
264
|
+
),
|
265
|
+
IDCommitmentBigInt: buildBigIntFromUint8Array(
|
266
|
+
Keystore.fromArraylikeToBytes(
|
267
|
+
_.get(obj, "identityCredential.idCommitment", [])
|
268
|
+
)
|
269
|
+
),
|
270
|
+
IDSecretHash: Keystore.fromArraylikeToBytes(
|
271
|
+
_.get(obj, "identityCredential.idSecretHash", [])
|
272
|
+
)
|
282
273
|
},
|
283
274
|
membership: {
|
284
275
|
treeIndex: _.get(obj, "treeIndex"),
|
@@ -329,21 +320,14 @@ export class Keystore {
|
|
329
320
|
|
330
321
|
// follows nwaku implementation
|
331
322
|
// https://github.com/waku-org/nwaku/blob/f05528d4be3d3c876a8b07f9bb7dfaae8aa8ec6e/waku/waku_keystore/protocol_types.nim#L98
|
332
|
-
// IdentityCredential is stored in Big Endian format => switch to Little Endian
|
333
323
|
private static fromIdentityToBytes(options: KeystoreEntity): Uint8Array {
|
334
324
|
return utf8ToBytes(
|
335
325
|
JSON.stringify({
|
336
326
|
treeIndex: options.membership.treeIndex,
|
337
327
|
identityCredential: {
|
338
|
-
idCommitment: Array.from(
|
339
|
-
|
340
|
-
),
|
341
|
-
idNullifier: Array.from(
|
342
|
-
BytesUtils.switchEndianness(options.identity.IDNullifier)
|
343
|
-
),
|
344
|
-
idSecretHash: Array.from(
|
345
|
-
BytesUtils.switchEndianness(options.identity.IDSecretHash)
|
346
|
-
),
|
328
|
+
idCommitment: Array.from(options.identity.IDCommitment),
|
329
|
+
idNullifier: Array.from(options.identity.IDNullifier),
|
330
|
+
idSecretHash: Array.from(options.identity.IDSecretHash),
|
347
331
|
idTrapdoor: Array.from(options.identity.IDTrapdoor)
|
348
332
|
},
|
349
333
|
membershipContract: {
|
package/src/proof.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import type { IRateLimitProof } from "@waku/interfaces";
|
2
2
|
|
3
|
-
import {
|
3
|
+
import { concatenate, poseidonHash } from "./utils/index.js";
|
4
4
|
|
5
5
|
const proofOffset = 128;
|
6
6
|
const rootOffset = proofOffset + 32;
|
@@ -57,7 +57,7 @@ export class Proof implements IRateLimitProof {
|
|
57
57
|
}
|
58
58
|
|
59
59
|
export function proofToBytes(p: IRateLimitProof): Uint8Array {
|
60
|
-
return
|
60
|
+
return concatenate(
|
61
61
|
p.proof,
|
62
62
|
p.merkleRoot,
|
63
63
|
p.epoch,
|
package/src/utils/bytes.ts
CHANGED
@@ -1,130 +1,84 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
/**
|
2
|
+
* Concatenate Uint8Arrays
|
3
|
+
* @param input
|
4
|
+
* @returns concatenation of all Uint8Array received as input
|
5
|
+
*/
|
6
|
+
export function concatenate(...input: Uint8Array[]): Uint8Array {
|
7
|
+
let totalLength = 0;
|
8
|
+
for (const arr of input) {
|
9
|
+
totalLength += arr.length;
|
7
10
|
}
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
*/
|
14
|
-
public static buildBigIntFromUint8ArrayBE(bytes: Uint8Array): bigint {
|
15
|
-
let result = 0n;
|
16
|
-
for (let i = 0; i < bytes.length; i++) {
|
17
|
-
result = (result << 8n) + BigInt(bytes[i]);
|
18
|
-
}
|
19
|
-
return result;
|
11
|
+
const result = new Uint8Array(totalLength);
|
12
|
+
let offset = 0;
|
13
|
+
for (const arr of input) {
|
14
|
+
result.set(arr, offset);
|
15
|
+
offset += arr.length;
|
20
16
|
}
|
17
|
+
return result;
|
18
|
+
}
|
21
19
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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");
|
32
|
+
}
|
35
33
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
34
|
+
export function writeUIntLE(
|
35
|
+
buf: Uint8Array,
|
36
|
+
value: number,
|
37
|
+
offset: number,
|
38
|
+
byteLength: number,
|
39
|
+
noAssert?: boolean
|
40
|
+
): Uint8Array {
|
41
|
+
value = +value;
|
42
|
+
offset = offset >>> 0;
|
43
|
+
byteLength = byteLength >>> 0;
|
44
|
+
if (!noAssert) {
|
45
|
+
const maxBytes = Math.pow(2, 8 * byteLength) - 1;
|
46
|
+
checkInt(buf, value, offset, byteLength, maxBytes, 0);
|
40
47
|
}
|
41
48
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
public static bigIntToUint8Array32BE(value: bigint): Uint8Array {
|
48
|
-
const bytes = new Uint8Array(32);
|
49
|
-
for (let i = 31; i >= 0; i--) {
|
50
|
-
bytes[i] = Number(value & 0xffn);
|
51
|
-
value >>= 8n;
|
52
|
-
}
|
53
|
-
return bytes;
|
49
|
+
let mul = 1;
|
50
|
+
let i = 0;
|
51
|
+
buf[offset] = value & 0xff;
|
52
|
+
while (++i < byteLength && (mul *= 0x100)) {
|
53
|
+
buf[offset + i] = (value / mul) & 0xff;
|
54
54
|
}
|
55
55
|
|
56
|
-
|
57
|
-
|
58
|
-
*/
|
59
|
-
public static writeUIntLE(
|
60
|
-
buf: Uint8Array,
|
61
|
-
value: number,
|
62
|
-
offset: number,
|
63
|
-
byteLength: number,
|
64
|
-
noAssert?: boolean
|
65
|
-
): Uint8Array {
|
66
|
-
value = +value;
|
67
|
-
offset = offset >>> 0;
|
68
|
-
byteLength = byteLength >>> 0;
|
69
|
-
if (!noAssert) {
|
70
|
-
const maxBytes = Math.pow(2, 8 * byteLength) - 1;
|
71
|
-
BytesUtils.checkInt(buf, value, offset, byteLength, maxBytes, 0);
|
72
|
-
}
|
73
|
-
|
74
|
-
let mul = 1;
|
75
|
-
let i = 0;
|
76
|
-
buf[offset] = value & 0xff;
|
77
|
-
while (++i < byteLength && (mul *= 0x100)) {
|
78
|
-
buf[offset + i] = (value / mul) & 0xff;
|
79
|
-
}
|
80
|
-
|
81
|
-
return buf;
|
82
|
-
}
|
83
|
-
|
84
|
-
/**
|
85
|
-
* Fills with zeros to set length
|
86
|
-
* @param array little endian Uint8Array
|
87
|
-
* @param length amount to pad
|
88
|
-
* @returns little endian Uint8Array padded with zeros to set length
|
89
|
-
*/
|
90
|
-
public static zeroPadLE(array: Uint8Array, length: number): Uint8Array {
|
91
|
-
const result = new Uint8Array(length);
|
92
|
-
for (let i = 0; i < length; i++) {
|
93
|
-
result[i] = array[i] || 0;
|
94
|
-
}
|
95
|
-
return result;
|
96
|
-
}
|
56
|
+
return buf;
|
57
|
+
}
|
97
58
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
}
|
59
|
+
/**
|
60
|
+
* Transforms Uint8Array into BigInt
|
61
|
+
* @param array: Uint8Array
|
62
|
+
* @returns BigInt
|
63
|
+
*/
|
64
|
+
export function buildBigIntFromUint8Array(
|
65
|
+
array: Uint8Array,
|
66
|
+
byteOffset: number = 0
|
67
|
+
): bigint {
|
68
|
+
const dataView = new DataView(array.buffer);
|
69
|
+
return dataView.getBigUint64(byteOffset, true);
|
70
|
+
}
|
111
71
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
const result = new Uint8Array(totalLength);
|
123
|
-
let offset = 0;
|
124
|
-
for (const arr of input) {
|
125
|
-
result.set(arr, offset);
|
126
|
-
offset += arr.length;
|
127
|
-
}
|
128
|
-
return result;
|
72
|
+
/**
|
73
|
+
* Fills with zeros to set length
|
74
|
+
* @param array little endian Uint8Array
|
75
|
+
* @param length amount to pad
|
76
|
+
* @returns little endian Uint8Array padded with zeros to set length
|
77
|
+
*/
|
78
|
+
export function zeroPadLE(array: Uint8Array, length: number): Uint8Array {
|
79
|
+
const result = new Uint8Array(length);
|
80
|
+
for (let i = 0; i < length; i++) {
|
81
|
+
result[i] = array[i] || 0;
|
129
82
|
}
|
83
|
+
return result;
|
130
84
|
}
|
package/src/utils/hash.ts
CHANGED
@@ -1,25 +1,15 @@
|
|
1
1
|
import * as zerokitRLN from "@waku/zerokit-rln-wasm";
|
2
2
|
|
3
|
-
import {
|
3
|
+
import { concatenate, writeUIntLE } from "./bytes.js";
|
4
4
|
|
5
5
|
export function poseidonHash(...input: Array<Uint8Array>): Uint8Array {
|
6
|
-
const inputLen =
|
7
|
-
|
8
|
-
input.length,
|
9
|
-
0,
|
10
|
-
8
|
11
|
-
);
|
12
|
-
const lenPrefixedData = BytesUtils.concatenate(inputLen, ...input);
|
6
|
+
const inputLen = writeUIntLE(new Uint8Array(8), input.length, 0, 8);
|
7
|
+
const lenPrefixedData = concatenate(inputLen, ...input);
|
13
8
|
return zerokitRLN.poseidonHash(lenPrefixedData);
|
14
9
|
}
|
15
10
|
|
16
11
|
export function sha256(input: Uint8Array): Uint8Array {
|
17
|
-
const inputLen =
|
18
|
-
|
19
|
-
input.length,
|
20
|
-
0,
|
21
|
-
8
|
22
|
-
);
|
23
|
-
const lenPrefixedData = BytesUtils.concatenate(inputLen, input);
|
12
|
+
const inputLen = writeUIntLE(new Uint8Array(8), input.length, 0, 8);
|
13
|
+
const lenPrefixedData = concatenate(inputLen, input);
|
24
14
|
return zerokitRLN.hash(lenPrefixedData);
|
25
15
|
}
|
package/src/utils/index.ts
CHANGED
@@ -1,4 +1,9 @@
|
|
1
1
|
export { extractMetaMaskSigner } from "./metamask.js";
|
2
|
-
export {
|
2
|
+
export {
|
3
|
+
concatenate,
|
4
|
+
writeUIntLE,
|
5
|
+
buildBigIntFromUint8Array,
|
6
|
+
zeroPadLE
|
7
|
+
} from "./bytes.js";
|
3
8
|
export { sha256, poseidonHash } from "./hash.js";
|
4
9
|
export { dateToEpoch, epochIntToBytes, epochBytesToInt } from "./epoch.js";
|