@waku/rln 0.1.8-e224c05.0 → 0.1.8-e800af3.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/index.js +6 -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/@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/@noble/hashes/esm/hmac.js +88 -0
- package/bundle/node_modules/@noble/hashes/esm/sha3.js +1 -1
- package/bundle/node_modules/@noble/hashes/esm/utils.js +8 -1
- package/bundle/node_modules/@waku/zerokit-rln-wasm/rln_wasm.js +517 -255
- package/bundle/node_modules/it-length-prefixed/dist/src/decode.js +6 -0
- package/bundle/node_modules/multiformats/dist/src/bases/base10.js +3 -1
- package/bundle/node_modules/multiformats/dist/src/bases/base16.js +4 -2
- package/bundle/node_modules/multiformats/dist/src/bases/base2.js +3 -1
- package/bundle/node_modules/multiformats/dist/src/bases/base256emoji.js +3 -1
- package/bundle/node_modules/multiformats/dist/src/bases/base32.js +11 -9
- package/bundle/node_modules/multiformats/dist/src/bases/base36.js +4 -2
- package/bundle/node_modules/multiformats/dist/src/bases/base58.js +4 -2
- package/bundle/node_modules/multiformats/dist/src/bases/base64.js +6 -4
- package/bundle/node_modules/multiformats/dist/src/bases/base8.js +3 -1
- package/bundle/node_modules/multiformats/dist/src/bases/identity.js +3 -1
- package/bundle/node_modules/multiformats/dist/src/basics.js +15 -0
- package/bundle/node_modules/multiformats/dist/src/bytes.js +15 -1
- 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/protons-runtime/dist/src/codec.js +20 -0
- package/bundle/node_modules/protons-runtime/dist/src/codecs/enum.js +24 -0
- package/bundle/node_modules/protons-runtime/dist/src/codecs/message.js +7 -0
- package/bundle/node_modules/protons-runtime/dist/src/decode.js +8 -0
- package/bundle/node_modules/protons-runtime/dist/src/encode.js +11 -0
- package/bundle/node_modules/protons-runtime/dist/src/index.js +30 -0
- package/bundle/node_modules/protons-runtime/dist/src/utils/float.js +54 -0
- package/bundle/node_modules/protons-runtime/dist/src/utils/longbits.js +175 -0
- package/bundle/node_modules/protons-runtime/dist/src/utils/pool.js +28 -0
- package/bundle/node_modules/protons-runtime/dist/src/utils/reader.js +367 -0
- package/bundle/node_modules/protons-runtime/dist/src/utils/utf8.js +99 -0
- package/bundle/node_modules/protons-runtime/dist/src/utils/writer.js +438 -0
- package/bundle/node_modules/uint8-varint/dist/src/index.js +124 -0
- package/bundle/node_modules/uint8arrays/dist/src/alloc.js +17 -0
- package/bundle/node_modules/uint8arrays/dist/src/concat.js +20 -0
- package/bundle/node_modules/uint8arrays/dist/src/from-string.js +19 -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/node_modules/uint8arrays/dist/src/util/bases.js +49 -0
- package/bundle/packages/core/dist/lib/connection_manager/connection_limiter.js +18 -0
- package/bundle/packages/core/dist/lib/connection_manager/connection_manager.js +24 -0
- package/bundle/packages/core/dist/lib/connection_manager/dialer.js +14 -0
- package/bundle/packages/core/dist/lib/connection_manager/discovery_dialer.js +14 -0
- package/bundle/packages/core/dist/lib/connection_manager/keep_alive_manager.js +15 -0
- package/bundle/packages/core/dist/lib/connection_manager/shard_reader.js +14 -0
- package/bundle/packages/core/dist/lib/filter/filter.js +28 -0
- package/bundle/packages/core/dist/lib/light_push/light_push.js +28 -0
- package/bundle/packages/core/dist/lib/message/version_0.js +172 -0
- package/bundle/packages/core/dist/lib/metadata/metadata.js +28 -0
- package/bundle/packages/core/dist/lib/store/store.js +24 -0
- package/bundle/packages/interfaces/dist/connection_manager.js +9 -0
- package/bundle/packages/interfaces/dist/health_status.js +17 -0
- package/bundle/packages/interfaces/dist/protocols.js +92 -0
- package/bundle/packages/interfaces/dist/waku.js +7 -0
- package/bundle/packages/proto/dist/generated/filter.js +447 -0
- package/bundle/packages/proto/dist/generated/filter_v2.js +426 -0
- package/bundle/packages/proto/dist/generated/light_push.js +550 -0
- package/bundle/packages/proto/dist/generated/message.js +215 -0
- package/bundle/packages/proto/dist/generated/metadata.js +132 -0
- package/bundle/packages/proto/dist/generated/peer_exchange.js +211 -0
- package/bundle/packages/proto/dist/generated/sds_message.js +172 -0
- package/bundle/packages/proto/dist/generated/store_v3.js +492 -0
- package/bundle/packages/proto/dist/generated/topic_only_message.js +63 -0
- package/bundle/packages/rln/dist/codec.js +92 -0
- package/bundle/packages/rln/dist/contract/constants.js +14 -7
- package/bundle/packages/rln/dist/contract/rln_base_contract.js +2 -1
- package/bundle/packages/rln/dist/contract/rln_contract.js +109 -0
- package/bundle/packages/rln/dist/credentials_manager.js +45 -4
- package/bundle/packages/rln/dist/identity.js +2 -1
- package/bundle/packages/rln/dist/keystore/keystore.js +30 -9
- package/bundle/packages/rln/dist/message.js +59 -0
- package/bundle/packages/rln/dist/proof.js +54 -0
- package/bundle/packages/rln/dist/resources/verification_key.js +112 -0
- package/bundle/packages/rln/dist/resources/witness_calculator.js +1 -1
- package/bundle/packages/rln/dist/rln.js +36 -4
- package/bundle/packages/rln/dist/root_tracker.js +76 -0
- package/bundle/packages/rln/dist/utils/bytes.js +70 -31
- package/bundle/packages/rln/dist/utils/epoch.js +23 -1
- package/bundle/packages/rln/dist/utils/hash.js +10 -0
- package/bundle/packages/rln/dist/zerokit.js +99 -2
- package/bundle/packages/utils/dist/bytes/index.js +31 -0
- package/bundle/resources/rln.wasm +0 -0
- package/bundle/resources/rln_final.zkey +0 -0
- package/bundle/resources/verification_key.d.ts +13 -0
- package/bundle/resources/verification_key.js +112 -0
- package/bundle/resources/witness_calculator.d.ts +7 -21
- package/bundle/resources/witness_calculator.js +1 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/codec.d.ts +40 -0
- package/dist/codec.js +79 -0
- package/dist/codec.js.map +1 -0
- package/dist/codec.test-utils.d.ts +37 -0
- package/dist/codec.test-utils.js +61 -0
- package/dist/codec.test-utils.js.map +1 -0
- package/dist/contract/constants.d.ts +10 -3
- package/dist/contract/constants.js +13 -6
- package/dist/contract/constants.js.map +1 -1
- package/dist/contract/index.d.ts +1 -0
- package/dist/contract/index.js +1 -0
- package/dist/contract/index.js.map +1 -1
- package/dist/contract/rln_base_contract.js +2 -1
- package/dist/contract/rln_base_contract.js.map +1 -1
- package/dist/contract/rln_contract.d.ts +17 -0
- package/dist/contract/rln_contract.js +107 -0
- package/dist/contract/rln_contract.js.map +1 -0
- package/dist/contract/test_setup.d.ts +26 -0
- package/dist/contract/test_setup.js +56 -0
- package/dist/contract/test_setup.js.map +1 -0
- 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 +14 -2
- package/dist/credentials_manager.js +45 -4
- package/dist/credentials_manager.js.map +1 -1
- package/dist/identity.js +2 -1
- package/dist/identity.js.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/keystore/keystore.js +30 -9
- package/dist/keystore/keystore.js.map +1 -1
- package/dist/message.d.ts +19 -0
- package/dist/message.js +51 -0
- package/dist/message.js.map +1 -0
- package/dist/proof.d.ts +21 -0
- package/dist/proof.js +50 -0
- package/dist/proof.js.map +1 -0
- package/dist/resources/rln.wasm +0 -0
- package/dist/resources/rln_final.zkey +0 -0
- package/dist/resources/verification_key.d.ts +13 -0
- package/dist/resources/verification_key.js +112 -0
- package/dist/resources/witness_calculator.d.ts +7 -21
- package/dist/resources/witness_calculator.js +1 -1
- package/dist/rln.d.ts +9 -0
- package/dist/rln.js +32 -4
- package/dist/rln.js.map +1 -1
- package/dist/root_tracker.d.ts +10 -0
- package/dist/root_tracker.js +75 -0
- package/dist/root_tracker.js.map +1 -0
- package/dist/utils/bytes.d.ts +31 -9
- package/dist/utils/bytes.js +70 -31
- package/dist/utils/bytes.js.map +1 -1
- package/dist/zerokit.d.ts +11 -0
- package/dist/zerokit.js +97 -1
- package/dist/zerokit.js.map +1 -1
- package/package.json +1 -1
- package/src/codec.test-utils.ts +88 -0
- package/src/codec.ts +138 -0
- package/src/contract/constants.ts +16 -6
- package/src/contract/index.ts +1 -0
- package/src/contract/rln_base_contract.ts +2 -1
- package/src/contract/rln_contract.ts +147 -0
- package/src/contract/test_setup.ts +86 -0
- package/src/contract/test_utils.ts +179 -0
- package/src/credentials_manager.ts +72 -8
- package/src/identity.ts +2 -1
- package/src/index.ts +11 -1
- package/src/keystore/keystore.ts +32 -9
- package/src/message.ts +73 -0
- package/src/proof.ts +69 -0
- package/src/resources/verification_key.d.ts +13 -0
- package/src/resources/witness_calculator.d.ts +7 -21
- package/src/rln.ts +65 -5
- package/src/root_tracker.ts +92 -0
- package/src/utils/bytes.ts +73 -36
- package/src/zerokit.ts +217 -1
|
@@ -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, RLN_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: RLN_CONTRACT.address }),
|
|
40
|
+
MembershipErased: () => ({ address: RLN_CONTRACT.address }),
|
|
41
|
+
MembershipExpired: () => ({ address: RLN_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: RLN_CONTRACT.address }),
|
|
55
|
+
MembershipErased: () => ({ address: RLN_CONTRACT.address }),
|
|
56
|
+
MembershipExpired: () => ({ address: RLN_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: RLN_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: RLN_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,8 +1,11 @@
|
|
|
1
|
+
import { hmac } from "@noble/hashes/hmac";
|
|
2
|
+
import { sha256 } from "@noble/hashes/sha2";
|
|
1
3
|
import { Logger } from "@waku/utils";
|
|
2
4
|
import { ethers } from "ethers";
|
|
3
5
|
|
|
4
|
-
import { RLN_CONTRACT } from "./contract/constants.js";
|
|
6
|
+
import { RLN_CONTRACT, RLN_Q } from "./contract/constants.js";
|
|
5
7
|
import { RLNBaseContract } from "./contract/rln_base_contract.js";
|
|
8
|
+
import { IdentityCredential } from "./identity.js";
|
|
6
9
|
import { Keystore } from "./keystore/index.js";
|
|
7
10
|
import type {
|
|
8
11
|
DecryptedCredentials,
|
|
@@ -10,6 +13,7 @@ import type {
|
|
|
10
13
|
} from "./keystore/index.js";
|
|
11
14
|
import { KeystoreEntity, Password } from "./keystore/types.js";
|
|
12
15
|
import { RegisterMembershipOptions, StartRLNOptions } from "./types.js";
|
|
16
|
+
import { BytesUtils } from "./utils/bytes.js";
|
|
13
17
|
import { extractMetaMaskSigner } from "./utils/index.js";
|
|
14
18
|
import { Zerokit } from "./zerokit.js";
|
|
15
19
|
|
|
@@ -17,6 +21,7 @@ const log = new Logger("waku:credentials");
|
|
|
17
21
|
|
|
18
22
|
/**
|
|
19
23
|
* Manages credentials for RLN
|
|
24
|
+
* This is a lightweight implementation of the RLN contract that doesn't require Zerokit
|
|
20
25
|
* It is used to register membership and generate identity credentials
|
|
21
26
|
*/
|
|
22
27
|
export class RLNCredentialsManager {
|
|
@@ -29,9 +34,9 @@ export class RLNCredentialsManager {
|
|
|
29
34
|
protected keystore = Keystore.create();
|
|
30
35
|
public credentials: undefined | DecryptedCredentials;
|
|
31
36
|
|
|
32
|
-
public zerokit: Zerokit;
|
|
37
|
+
public zerokit: undefined | Zerokit;
|
|
33
38
|
|
|
34
|
-
public constructor(zerokit
|
|
39
|
+
public constructor(zerokit?: Zerokit) {
|
|
35
40
|
log.info("RLNCredentialsManager initialized");
|
|
36
41
|
this.zerokit = zerokit;
|
|
37
42
|
}
|
|
@@ -76,7 +81,7 @@ export class RLNCredentialsManager {
|
|
|
76
81
|
this.contract = await RLNBaseContract.create({
|
|
77
82
|
address: address!,
|
|
78
83
|
signer: signer!,
|
|
79
|
-
rateLimit: rateLimit ?? this.zerokit
|
|
84
|
+
rateLimit: rateLimit ?? this.zerokit?.rateLimit
|
|
80
85
|
});
|
|
81
86
|
|
|
82
87
|
log.info("RLNCredentialsManager successfully started");
|
|
@@ -101,10 +106,18 @@ export class RLNCredentialsManager {
|
|
|
101
106
|
let identity = "identity" in options && options.identity;
|
|
102
107
|
|
|
103
108
|
if ("signature" in options) {
|
|
104
|
-
log.info("
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
109
|
+
log.info("Generating identity from signature");
|
|
110
|
+
if (this.zerokit) {
|
|
111
|
+
log.info("Using Zerokit to generate identity");
|
|
112
|
+
identity = this.zerokit.generateSeededIdentityCredential(
|
|
113
|
+
options.signature
|
|
114
|
+
);
|
|
115
|
+
} else {
|
|
116
|
+
log.info("Using local implementation to generate identity");
|
|
117
|
+
identity = await this.generateSeededIdentityCredential(
|
|
118
|
+
options.signature
|
|
119
|
+
);
|
|
120
|
+
}
|
|
108
121
|
}
|
|
109
122
|
|
|
110
123
|
if (!identity) {
|
|
@@ -229,4 +242,55 @@ export class RLNCredentialsManager {
|
|
|
229
242
|
);
|
|
230
243
|
}
|
|
231
244
|
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Generates an identity credential from a seed string
|
|
248
|
+
* This is a pure implementation that doesn't rely on Zerokit
|
|
249
|
+
* @param seed A string seed to generate the identity from
|
|
250
|
+
* @returns IdentityCredential
|
|
251
|
+
*/
|
|
252
|
+
private async generateSeededIdentityCredential(
|
|
253
|
+
seed: string
|
|
254
|
+
): Promise<IdentityCredential> {
|
|
255
|
+
log.info("Generating seeded identity credential");
|
|
256
|
+
// Convert the seed to bytes
|
|
257
|
+
const encoder = new TextEncoder();
|
|
258
|
+
const seedBytes = encoder.encode(seed);
|
|
259
|
+
|
|
260
|
+
// Generate deterministic values using HMAC-SHA256
|
|
261
|
+
// We use different context strings for each component to ensure they're different
|
|
262
|
+
const idTrapdoorBE = hmac(sha256, seedBytes, encoder.encode("IDTrapdoor"));
|
|
263
|
+
const idNullifierBE = hmac(
|
|
264
|
+
sha256,
|
|
265
|
+
seedBytes,
|
|
266
|
+
encoder.encode("IDNullifier")
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
const combinedBytes = new Uint8Array([...idTrapdoorBE, ...idNullifierBE]);
|
|
270
|
+
const idSecretHashBE = sha256(combinedBytes);
|
|
271
|
+
|
|
272
|
+
const idCommitmentRawBE = sha256(idSecretHashBE);
|
|
273
|
+
const idCommitmentBE = this.reduceIdCommitment(idCommitmentRawBE);
|
|
274
|
+
|
|
275
|
+
log.info(
|
|
276
|
+
"Successfully generated identity credential, storing in Big Endian format"
|
|
277
|
+
);
|
|
278
|
+
return new IdentityCredential(
|
|
279
|
+
idTrapdoorBE,
|
|
280
|
+
idNullifierBE,
|
|
281
|
+
idSecretHashBE,
|
|
282
|
+
idCommitmentBE
|
|
283
|
+
);
|
|
284
|
+
}
|
|
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 = RLN_Q
|
|
292
|
+
): Uint8Array {
|
|
293
|
+
const nBE = BytesUtils.buildBigIntFromUint8ArrayBE(bytesBE);
|
|
294
|
+
return BytesUtils.bigIntToUint8Array32BE(nBE % limit);
|
|
295
|
+
}
|
|
232
296
|
}
|
package/src/identity.ts
CHANGED
|
@@ -11,7 +11,8 @@ export class IdentityCredential {
|
|
|
11
11
|
public readonly IDSecretHash: Uint8Array,
|
|
12
12
|
public readonly IDCommitment: Uint8Array
|
|
13
13
|
) {
|
|
14
|
-
this.IDCommitmentBigInt =
|
|
14
|
+
this.IDCommitmentBigInt =
|
|
15
|
+
BytesUtils.buildBigIntFromUint8ArrayBE(IDCommitment);
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
public static fromBytes(memKeys: Uint8Array): IdentityCredential {
|
package/src/index.ts
CHANGED
|
@@ -1,18 +1,28 @@
|
|
|
1
|
+
import { RLNDecoder, RLNEncoder } from "./codec.js";
|
|
1
2
|
import { RLN_ABI } from "./contract/abi/rln.js";
|
|
2
|
-
import { RLN_CONTRACT } from "./contract/index.js";
|
|
3
|
+
import { RLN_CONTRACT, RLNContract } from "./contract/index.js";
|
|
3
4
|
import { RLNBaseContract } from "./contract/rln_base_contract.js";
|
|
4
5
|
import { createRLN } from "./create.js";
|
|
6
|
+
import { RLNCredentialsManager } from "./credentials_manager.js";
|
|
5
7
|
import { IdentityCredential } from "./identity.js";
|
|
6
8
|
import { Keystore } from "./keystore/index.js";
|
|
9
|
+
import { Proof } from "./proof.js";
|
|
7
10
|
import { RLNInstance } from "./rln.js";
|
|
11
|
+
import { MerkleRootTracker } from "./root_tracker.js";
|
|
8
12
|
import { extractMetaMaskSigner } from "./utils/index.js";
|
|
9
13
|
|
|
10
14
|
export {
|
|
15
|
+
RLNCredentialsManager,
|
|
11
16
|
RLNBaseContract,
|
|
12
17
|
createRLN,
|
|
13
18
|
Keystore,
|
|
14
19
|
RLNInstance,
|
|
15
20
|
IdentityCredential,
|
|
21
|
+
Proof,
|
|
22
|
+
RLNEncoder,
|
|
23
|
+
RLNDecoder,
|
|
24
|
+
MerkleRootTracker,
|
|
25
|
+
RLNContract,
|
|
16
26
|
RLN_CONTRACT,
|
|
17
27
|
extractMetaMaskSigner,
|
|
18
28
|
RLN_ABI
|
package/src/keystore/keystore.ts
CHANGED
|
@@ -264,14 +264,20 @@ export class Keystore {
|
|
|
264
264
|
_.get(obj, "identityCredential.idSecretHash", [])
|
|
265
265
|
);
|
|
266
266
|
|
|
267
|
-
|
|
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);
|
|
268
274
|
|
|
269
275
|
return {
|
|
270
276
|
identity: {
|
|
271
|
-
IDCommitment:
|
|
272
|
-
IDTrapdoor:
|
|
273
|
-
IDNullifier:
|
|
274
|
-
IDSecretHash:
|
|
277
|
+
IDCommitment: idCommitmentBE,
|
|
278
|
+
IDTrapdoor: idTrapdoorBE,
|
|
279
|
+
IDNullifier: idNullifierBE,
|
|
280
|
+
IDSecretHash: idSecretHashBE,
|
|
275
281
|
IDCommitmentBigInt: idCommitmentBigInt
|
|
276
282
|
},
|
|
277
283
|
membership: {
|
|
@@ -323,18 +329,35 @@ export class Keystore {
|
|
|
323
329
|
|
|
324
330
|
// follows nwaku implementation
|
|
325
331
|
// 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
|
|
326
333
|
private static fromIdentityToBytes(options: KeystoreEntity): Uint8Array {
|
|
327
334
|
const { IDCommitment, IDNullifier, IDSecretHash, IDTrapdoor } =
|
|
328
335
|
options.identity;
|
|
336
|
+
const idCommitmentLE = BytesUtils.switchEndianness(IDCommitment);
|
|
337
|
+
const idNullifierLE = BytesUtils.switchEndianness(IDNullifier);
|
|
338
|
+
const idSecretHashLE = BytesUtils.switchEndianness(IDSecretHash);
|
|
339
|
+
const idTrapdoorLE = BytesUtils.switchEndianness(IDTrapdoor);
|
|
340
|
+
|
|
341
|
+
// eslint-disable-next-line no-console
|
|
342
|
+
console.log({
|
|
343
|
+
idCommitmentBE: IDCommitment,
|
|
344
|
+
idCommitmentLE,
|
|
345
|
+
idNullifierBE: IDNullifier,
|
|
346
|
+
idNullifierLE,
|
|
347
|
+
idSecretHashBE: IDSecretHash,
|
|
348
|
+
idSecretHashLE,
|
|
349
|
+
idTrapdoorBE: IDTrapdoor,
|
|
350
|
+
idTrapdoorLE
|
|
351
|
+
});
|
|
329
352
|
|
|
330
353
|
return utf8ToBytes(
|
|
331
354
|
JSON.stringify({
|
|
332
355
|
treeIndex: options.membership.treeIndex,
|
|
333
356
|
identityCredential: {
|
|
334
|
-
idCommitment: Array.from(
|
|
335
|
-
idNullifier: Array.from(
|
|
336
|
-
idSecretHash: Array.from(
|
|
337
|
-
idTrapdoor: Array.from(
|
|
357
|
+
idCommitment: Array.from(idCommitmentLE),
|
|
358
|
+
idNullifier: Array.from(idNullifierLE),
|
|
359
|
+
idSecretHash: Array.from(idSecretHashLE),
|
|
360
|
+
idTrapdoor: Array.from(idTrapdoorLE)
|
|
338
361
|
},
|
|
339
362
|
membershipContract: {
|
|
340
363
|
chainId: options.membership.chainId,
|
package/src/message.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { message } from "@waku/core";
|
|
2
|
+
import type {
|
|
3
|
+
IDecodedMessage,
|
|
4
|
+
IMessage,
|
|
5
|
+
IRateLimitProof,
|
|
6
|
+
IRlnMessage
|
|
7
|
+
} from "@waku/interfaces";
|
|
8
|
+
import * as utils from "@waku/utils/bytes";
|
|
9
|
+
|
|
10
|
+
import { RLNInstance } from "./rln.js";
|
|
11
|
+
import { epochBytesToInt } from "./utils/index.js";
|
|
12
|
+
|
|
13
|
+
export function toRLNSignal(contentTopic: string, msg: IMessage): Uint8Array {
|
|
14
|
+
const contentTopicBytes = utils.utf8ToBytes(contentTopic ?? "");
|
|
15
|
+
return new Uint8Array([...(msg.payload ?? []), ...contentTopicBytes]);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class RlnMessage<T extends IDecodedMessage> implements IRlnMessage {
|
|
19
|
+
public pubsubTopic = "";
|
|
20
|
+
public version = message.version_0.Version;
|
|
21
|
+
|
|
22
|
+
public constructor(
|
|
23
|
+
private rlnInstance: RLNInstance,
|
|
24
|
+
private msg: T,
|
|
25
|
+
public rateLimitProof: IRateLimitProof | undefined
|
|
26
|
+
) {}
|
|
27
|
+
|
|
28
|
+
public verify(roots: Uint8Array[]): boolean | undefined {
|
|
29
|
+
return this.rateLimitProof
|
|
30
|
+
? this.rlnInstance.zerokit.verifyWithRoots(
|
|
31
|
+
this.rateLimitProof,
|
|
32
|
+
toRLNSignal(this.msg.contentTopic, this.msg),
|
|
33
|
+
roots
|
|
34
|
+
) // this.rlnInstance.verifyRLNProof once issue status-im/nwaku#1248 is fixed
|
|
35
|
+
: undefined;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public verifyNoRoot(): boolean | undefined {
|
|
39
|
+
return this.rateLimitProof
|
|
40
|
+
? this.rlnInstance.zerokit.verifyWithNoRoot(
|
|
41
|
+
this.rateLimitProof,
|
|
42
|
+
toRLNSignal(this.msg.contentTopic, this.msg)
|
|
43
|
+
) // this.rlnInstance.verifyRLNProof once issue status-im/nwaku#1248 is fixed
|
|
44
|
+
: undefined;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public get payload(): Uint8Array {
|
|
48
|
+
return this.msg.payload;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public get contentTopic(): string {
|
|
52
|
+
return this.msg.contentTopic;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public get timestamp(): Date | undefined {
|
|
56
|
+
return this.msg.timestamp;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public get ephemeral(): boolean | undefined {
|
|
60
|
+
return this.msg.ephemeral;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public get meta(): Uint8Array | undefined {
|
|
64
|
+
return this.msg.meta;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public get epoch(): number | undefined {
|
|
68
|
+
const bytes = this.rateLimitProof?.epoch;
|
|
69
|
+
if (!bytes) return undefined;
|
|
70
|
+
|
|
71
|
+
return epochBytesToInt(bytes);
|
|
72
|
+
}
|
|
73
|
+
}
|
package/src/proof.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { IRateLimitProof } from "@waku/interfaces";
|
|
2
|
+
|
|
3
|
+
import { BytesUtils, poseidonHash } from "./utils/index.js";
|
|
4
|
+
|
|
5
|
+
const proofOffset = 128;
|
|
6
|
+
const rootOffset = proofOffset + 32;
|
|
7
|
+
const epochOffset = rootOffset + 32;
|
|
8
|
+
const shareXOffset = epochOffset + 32;
|
|
9
|
+
const shareYOffset = shareXOffset + 32;
|
|
10
|
+
const nullifierOffset = shareYOffset + 32;
|
|
11
|
+
const rlnIdentifierOffset = nullifierOffset + 32;
|
|
12
|
+
|
|
13
|
+
class ProofMetadata {
|
|
14
|
+
public constructor(
|
|
15
|
+
public readonly nullifier: Uint8Array,
|
|
16
|
+
public readonly shareX: Uint8Array,
|
|
17
|
+
public readonly shareY: Uint8Array,
|
|
18
|
+
public readonly externalNullifier: Uint8Array
|
|
19
|
+
) {}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class Proof implements IRateLimitProof {
|
|
23
|
+
public readonly proof: Uint8Array;
|
|
24
|
+
public readonly merkleRoot: Uint8Array;
|
|
25
|
+
public readonly epoch: Uint8Array;
|
|
26
|
+
public readonly shareX: Uint8Array;
|
|
27
|
+
public readonly shareY: Uint8Array;
|
|
28
|
+
public readonly nullifier: Uint8Array;
|
|
29
|
+
public readonly rlnIdentifier: Uint8Array;
|
|
30
|
+
|
|
31
|
+
public constructor(proofBytes: Uint8Array) {
|
|
32
|
+
if (proofBytes.length < rlnIdentifierOffset) {
|
|
33
|
+
throw new Error("invalid proof");
|
|
34
|
+
}
|
|
35
|
+
// parse the proof as proof<128> | share_y<32> | nullifier<32> | root<32> | epoch<32> | share_x<32> | rln_identifier<32>
|
|
36
|
+
this.proof = proofBytes.subarray(0, proofOffset);
|
|
37
|
+
this.merkleRoot = proofBytes.subarray(proofOffset, rootOffset);
|
|
38
|
+
this.epoch = proofBytes.subarray(rootOffset, epochOffset);
|
|
39
|
+
this.shareX = proofBytes.subarray(epochOffset, shareXOffset);
|
|
40
|
+
this.shareY = proofBytes.subarray(shareXOffset, shareYOffset);
|
|
41
|
+
this.nullifier = proofBytes.subarray(shareYOffset, nullifierOffset);
|
|
42
|
+
this.rlnIdentifier = proofBytes.subarray(
|
|
43
|
+
nullifierOffset,
|
|
44
|
+
rlnIdentifierOffset
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public extractMetadata(): ProofMetadata {
|
|
49
|
+
const externalNullifier = poseidonHash(this.epoch, this.rlnIdentifier);
|
|
50
|
+
return new ProofMetadata(
|
|
51
|
+
this.nullifier,
|
|
52
|
+
this.shareX,
|
|
53
|
+
this.shareY,
|
|
54
|
+
externalNullifier
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function proofToBytes(p: IRateLimitProof): Uint8Array {
|
|
60
|
+
return BytesUtils.concatenate(
|
|
61
|
+
p.proof,
|
|
62
|
+
p.merkleRoot,
|
|
63
|
+
p.epoch,
|
|
64
|
+
p.shareX,
|
|
65
|
+
p.shareY,
|
|
66
|
+
p.nullifier,
|
|
67
|
+
p.rlnIdentifier
|
|
68
|
+
);
|
|
69
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
declare const verificationKey: {
|
|
2
|
+
protocol: string;
|
|
3
|
+
curve: string;
|
|
4
|
+
nPublic: number;
|
|
5
|
+
vk_alpha_1: string[];
|
|
6
|
+
vk_beta_2: string[][];
|
|
7
|
+
vk_gamma_2: string[][];
|
|
8
|
+
vk_delta_2: string[][];
|
|
9
|
+
vk_alphabeta_12: string[][][];
|
|
10
|
+
IC: string[][];
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default verificationKey;
|
|
@@ -1,25 +1,11 @@
|
|
|
1
|
-
export
|
|
1
|
+
export async function builder(
|
|
2
2
|
code: Uint8Array,
|
|
3
|
-
sanityCheck
|
|
4
|
-
)
|
|
3
|
+
sanityCheck: boolean
|
|
4
|
+
): Promise<WitnessCalculator>;
|
|
5
5
|
|
|
6
6
|
export class WitnessCalculator {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
calculateWitness(
|
|
12
|
-
input: Record<string, unknown>,
|
|
13
|
-
sanityCheck?: boolean
|
|
14
|
-
): Promise<bigint[]>;
|
|
15
|
-
|
|
16
|
-
calculateBinWitness(
|
|
17
|
-
input: Record<string, unknown>,
|
|
18
|
-
sanityCheck?: boolean
|
|
19
|
-
): Promise<Uint8Array>;
|
|
20
|
-
|
|
21
|
-
calculateWTNSBin(
|
|
22
|
-
input: Record<string, unknown>,
|
|
23
|
-
sanityCheck?: boolean
|
|
24
|
-
): Promise<Uint8Array>;
|
|
7
|
+
public calculateWitness(
|
|
8
|
+
input: unknown,
|
|
9
|
+
sanityCheck: boolean
|
|
10
|
+
): Promise<Array<bigint>>;
|
|
25
11
|
}
|