@dorafactory/maci-sdk 0.0.5 → 0.0.7

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.
Files changed (40) hide show
  1. package/dist/index.d.ts +4 -1
  2. package/dist/index.js +326 -10
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.mjs +312 -9
  5. package/dist/index.mjs.map +1 -1
  6. package/dist/libs/circom/circomlib.d.ts +39 -0
  7. package/dist/libs/circom/index.d.ts +10 -0
  8. package/dist/libs/circom/tree.d.ts +23 -0
  9. package/dist/libs/circom/types.d.ts +7 -0
  10. package/dist/libs/contract/contract.d.ts +4 -0
  11. package/dist/libs/contract/utils.d.ts +2 -2
  12. package/dist/libs/contract/vars.d.ts +14 -16
  13. package/dist/libs/indexer/indexer.d.ts +2 -2
  14. package/dist/libs/maci/index.d.ts +0 -0
  15. package/dist/libs/maci/maci.d.ts +62 -0
  16. package/dist/libs/maci/types.d.ts +6 -0
  17. package/dist/libs/oracle-certificate/index.d.ts +1 -0
  18. package/dist/libs/oracle-certificate/oracle-certificate.d.ts +27 -0
  19. package/dist/libs/oracle-certificate/types.d.ts +5 -0
  20. package/dist/libs/query/account.d.ts +1 -1
  21. package/dist/libs/query/index.d.ts +1 -1
  22. package/dist/maci.d.ts +2 -0
  23. package/package.json +11 -7
  24. package/src/index.ts +4 -1
  25. package/src/libs/circom/circomlib.ts +308 -0
  26. package/src/libs/circom/index.ts +85 -0
  27. package/src/libs/circom/types.ts +8 -0
  28. package/src/libs/contract/contract.ts +4 -0
  29. package/src/libs/contract/utils.ts +11 -4
  30. package/src/libs/contract/vars.ts +45 -18
  31. package/src/libs/indexer/indexer.ts +3 -3
  32. package/src/libs/maci/index.ts +0 -0
  33. package/src/libs/maci/maci.ts +284 -0
  34. package/src/libs/maci/types.ts +6 -0
  35. package/src/libs/oracle-certificate/index.ts +1 -0
  36. package/src/libs/oracle-certificate/oracle-certificate.ts +90 -0
  37. package/src/libs/oracle-certificate/types.ts +6 -0
  38. package/src/libs/query/account.ts +1 -1
  39. package/src/libs/query/index.ts +1 -1
  40. package/src/maci.ts +3 -0
@@ -0,0 +1,39 @@
1
+ type MixedData<T> = T | Array<MixedData<T>> | {
2
+ [key: string]: MixedData<T>;
3
+ };
4
+ export type PrivateKey = bigint;
5
+ export type PublicKey = [bigint, bigint];
6
+ export interface Account {
7
+ privKey: PrivateKey;
8
+ pubKey: PublicKey;
9
+ formatedPrivKey: PrivateKey;
10
+ }
11
+ export declare const stringizing: (o: MixedData<bigint>, path?: MixedData<bigint>[]) => MixedData<string>;
12
+ export declare const genKeypair: (pkey?: PrivateKey) => Account;
13
+ export declare const genEcdhSharedKey: (privKey: PrivateKey, pubKey: PublicKey) => PublicKey;
14
+ export declare const genMessageFactory: (stateIdx: number, signPriKey: PrivateKey, signPubKey: PublicKey, coordPubKey: PublicKey) => (encPriKey: PrivateKey, nonce: number, voIdx: number, newVotes: number, isLastCmd: boolean, salt?: bigint) => bigint[];
15
+ export declare const batchGenMessage: (stateIdx: number, account: Account, coordPubKey: PublicKey, plan: [number, number][]) => {
16
+ msg: bigint[];
17
+ encPubkeys: PublicKey;
18
+ }[];
19
+ export declare const privateKeyFromTxt: (txt: string) => Account | undefined;
20
+ export declare const genAddKeyProof: (depth: number, { coordPubKey, oldKey, deactivates, }: {
21
+ coordPubKey: PublicKey;
22
+ oldKey: Account;
23
+ deactivates: bigint[][];
24
+ }) => Promise<{
25
+ inputHash: bigint;
26
+ coordPubKey: PublicKey;
27
+ deactivateRoot: any;
28
+ deactivateIndex: number;
29
+ deactivateLeaf: any;
30
+ c1: bigint[];
31
+ c2: bigint[];
32
+ randomVal: bigint;
33
+ d1: bigint[];
34
+ d2: bigint[];
35
+ deactivateLeafPathElements: any;
36
+ nullifier: any;
37
+ oldPrivateKey: bigint;
38
+ } | null>;
39
+ export {};
@@ -0,0 +1,10 @@
1
+ import { OfflineSigner } from '@cosmjs/proto-signing';
2
+ import { SignResult, CircomParams } from './types';
3
+ export * from './circomlib';
4
+ export declare class Circom {
5
+ private network;
6
+ private chainId;
7
+ constructor({ network }: CircomParams);
8
+ signMessage(signer: OfflineSigner, address: string, message: string): Promise<SignResult>;
9
+ genKeypairFromSign(signer: OfflineSigner, address: string): Promise<import("./circomlib").Account>;
10
+ }
@@ -0,0 +1,23 @@
1
+ export = Tree;
2
+ declare class Tree {
3
+ constructor(degree: any, depth: any, zero: any);
4
+ DEPTH: any;
5
+ HEIGHT: any;
6
+ DEGREE: any;
7
+ LEAVES_COUNT: number;
8
+ LEAVES_IDX_0: number;
9
+ NODES_COUNT: number;
10
+ get root(): any;
11
+ initZero(zero: any): void;
12
+ zeros: any[] | undefined;
13
+ initNodes(): void;
14
+ nodes: any[] | undefined;
15
+ initLeaves(leaves: any): void;
16
+ leaf(leafIdx: any): any;
17
+ leaves(): any[];
18
+ updateLeaf(leafIdx: any, leaf: any): void;
19
+ pathIdxOf(leafIdx: any): number[];
20
+ pathElementOf(leafIdx: any): any[][];
21
+ subTree(length: any): Tree;
22
+ _update(nodeIdx: any): void;
23
+ }
@@ -0,0 +1,7 @@
1
+ export type CircomParams = {
2
+ network: 'mainnet' | 'testnet';
3
+ };
4
+ export type SignResult = {
5
+ signature: string;
6
+ pubkey: Uint8Array;
7
+ };
@@ -1,4 +1,5 @@
1
1
  import { OfflineSigner } from '@cosmjs/proto-signing';
2
+ import { SigningCosmWasmClient } from '@cosmjs/cosmwasm-stargate';
2
3
  import { MaciClient } from './ts/Maci.client';
3
4
  import { AMaciClient } from './ts/AMaci.client';
4
5
  import { RegistryClient } from './ts/Registry.client';
@@ -36,4 +37,7 @@ export declare class Contract {
36
37
  signer: OfflineSigner;
37
38
  contractAddress: string;
38
39
  }): Promise<AMaciClient>;
40
+ contractClient({ signer }: {
41
+ signer: OfflineSigner;
42
+ }): Promise<SigningCosmWasmClient>;
39
43
  }
@@ -17,7 +17,7 @@ export declare function getContractParams(type: MaciRoundType, circuitType: Maci
17
17
  vk_delta_2: string;
18
18
  vk_ic0: string;
19
19
  vk_ic1: string;
20
- } | null;
20
+ } | null | undefined;
21
21
  groth16TallyVkey: {
22
22
  vk_alpha1: string;
23
23
  vk_beta_2: string;
@@ -25,7 +25,7 @@ export declare function getContractParams(type: MaciRoundType, circuitType: Maci
25
25
  vk_delta_2: string;
26
26
  vk_ic0: string;
27
27
  vk_ic1: string;
28
- } | null;
28
+ } | null | undefined;
29
29
  plonkProcessVkey: {
30
30
  n: number;
31
31
  num_inputs: number;
@@ -1,3 +1,11 @@
1
+ type Groth16VkeyType = {
2
+ vk_alpha1: string;
3
+ vk_beta_2: string;
4
+ vk_gamma_2: string;
5
+ vk_delta_2: string;
6
+ vk_ic0: string;
7
+ vk_ic1: string;
8
+ };
1
9
  type CircuitInfoType = {
2
10
  [key: string]: {
3
11
  parameter: {
@@ -7,22 +15,12 @@ type CircuitInfoType = {
7
15
  message_batch_size: string;
8
16
  };
9
17
  groth16: {
10
- process_vkey: {
11
- vk_alpha1: string;
12
- vk_beta_2: string;
13
- vk_gamma_2: string;
14
- vk_delta_2: string;
15
- vk_ic0: string;
16
- vk_ic1: string;
17
- };
18
- tally_vkey: {
19
- vk_alpha1: string;
20
- vk_beta_2: string;
21
- vk_gamma_2: string;
22
- vk_delta_2: string;
23
- vk_ic0: string;
24
- vk_ic1: string;
25
- };
18
+ process_vkey?: Groth16VkeyType;
19
+ tally_vkey?: Groth16VkeyType;
20
+ process_1p1v_vkey?: Groth16VkeyType;
21
+ tally_1p1v_vkey?: Groth16VkeyType;
22
+ process_qv_vkey?: Groth16VkeyType;
23
+ tally_qv_vkey?: Groth16VkeyType;
26
24
  };
27
25
  plonk?: {
28
26
  process_vkey: {
@@ -1,7 +1,7 @@
1
1
  import { BalanceResponse, RoundResponse, RoundsResponse, OperatorResponse, OperatorsResponse, CircuitResponse, TransactionResponse, TransactionsResponse, CircuitsResponse, ProofResponse } from '../../types';
2
2
  import { IndexerParams } from './types';
3
3
  import { Http } from '../http';
4
- import { Round, Account, Circuit, Operator, Proof, Transaction } from '../query';
4
+ import { Round, UserAccount, Circuit, Operator, Proof, Transaction } from '../query';
5
5
  /**
6
6
  * @class Indexer
7
7
  * @description This class is used to interact with Maci Indexer.
@@ -12,7 +12,7 @@ export declare class Indexer {
12
12
  registryAddress: string;
13
13
  http: Http;
14
14
  round: Round;
15
- account: Account;
15
+ account: UserAccount;
16
16
  circuit: Circuit;
17
17
  operator: Operator;
18
18
  proof: Proof;
File without changes
@@ -0,0 +1,62 @@
1
+ import { OfflineSigner } from '@cosmjs/proto-signing';
2
+ import { Circom, PublicKey } from '../circom';
3
+ import { Contract } from '../contract';
4
+ import { SigningCosmWasmClient } from '@cosmjs/cosmwasm-stargate';
5
+ export declare class MACI {
6
+ circom: Circom;
7
+ contract: Contract;
8
+ constructor({ circom, contract }: {
9
+ circom: Circom;
10
+ contract: Contract;
11
+ });
12
+ signup({ signer, address, contractAddress, oracleCertificate, gasStation, }: {
13
+ signer: OfflineSigner;
14
+ address: string;
15
+ contractAddress: string;
16
+ oracleCertificate?: {
17
+ amount: string;
18
+ signature: string;
19
+ };
20
+ gasStation?: boolean;
21
+ }): Promise<void>;
22
+ submit: ({ signer, address, stateIdx, contractAddress, selectedOptions, operatorCoordPubKey, gasStation, }: {
23
+ signer: OfflineSigner;
24
+ address: string;
25
+ stateIdx: number;
26
+ contractAddress: string;
27
+ selectedOptions: {
28
+ idx: number;
29
+ vc: number;
30
+ }[];
31
+ operatorCoordPubKey: PublicKey;
32
+ gasStation?: boolean;
33
+ }) => Promise<void>;
34
+ submitPlan({ client, address, payload, contractAddress, gasStation, }: {
35
+ client: SigningCosmWasmClient;
36
+ address: string;
37
+ payload: {
38
+ msg: bigint[];
39
+ encPubkeys: PublicKey;
40
+ }[];
41
+ contractAddress: string;
42
+ gasStation: boolean;
43
+ }): Promise<import("@cosmjs/cosmwasm-stargate").DeliverTxResponse>;
44
+ signupSimple({ client, address, pubKey, contractAddress, gasStation, }: {
45
+ client: SigningCosmWasmClient;
46
+ address: string;
47
+ pubKey: PublicKey;
48
+ contractAddress: string;
49
+ gasStation?: boolean;
50
+ }): Promise<import("@cosmjs/cosmwasm-stargate").ExecuteResult>;
51
+ signupOracle({ client, address, pubKey, contractAddress, oracleCertificate, gasStation, }: {
52
+ client: SigningCosmWasmClient;
53
+ address: string;
54
+ pubKey: PublicKey;
55
+ contractAddress: string;
56
+ oracleCertificate: {
57
+ amount: string;
58
+ signature: string;
59
+ };
60
+ gasStation?: boolean;
61
+ }): Promise<import("@cosmjs/cosmwasm-stargate").ExecuteResult>;
62
+ }
@@ -0,0 +1,6 @@
1
+ export type IAccountStatus = {
2
+ stateIdx: number;
3
+ vcbTotal: number;
4
+ whitelistCommitment: number;
5
+ feegrantStatus?: string;
6
+ };
@@ -0,0 +1 @@
1
+ export { OracleCertificate } from './oracle-certificate';
@@ -0,0 +1,27 @@
1
+ import { OracleCertificateParams } from './types';
2
+ /**
3
+ * @class Indexer
4
+ * @description This class is used to interact with Maci Indexer.
5
+ */
6
+ export interface SignatureRequest {
7
+ address: string;
8
+ height: string;
9
+ contractAddress: string;
10
+ amount?: string;
11
+ }
12
+ export interface SignatureResponse {
13
+ code: number;
14
+ data?: {
15
+ signature: string;
16
+ };
17
+ error?: {
18
+ message: string;
19
+ type: string;
20
+ };
21
+ }
22
+ export declare class OracleCertificate {
23
+ private certificateApiEndpoint;
24
+ private http;
25
+ constructor({ certificateApiEndpoint, http }: OracleCertificateParams);
26
+ sign(data: SignatureRequest): Promise<SignatureResponse>;
27
+ }
@@ -0,0 +1,5 @@
1
+ import { Http } from '../http/http';
2
+ export type OracleCertificateParams = {
3
+ certificateApiEndpoint: string;
4
+ http: Http;
5
+ };
@@ -1,6 +1,6 @@
1
1
  import { Http } from '../http';
2
2
  import { BalanceResponse } from '../../types';
3
- export declare class Account {
3
+ export declare class UserAccount {
4
4
  http: Http;
5
5
  constructor(http: Http);
6
6
  balanceOf(address: string): Promise<BalanceResponse>;
@@ -1,4 +1,4 @@
1
- export { Account } from './account';
1
+ export { UserAccount } from './account';
2
2
  export { Circuit } from './circuit';
3
3
  export { Operator } from './operator';
4
4
  export { Round } from './round';
package/dist/maci.d.ts CHANGED
@@ -2,6 +2,7 @@ import { BalanceResponse, ClientParams, RoundResponse, RoundsResponse, OperatorR
2
2
  import { Http, Indexer, Contract } from './libs';
3
3
  import { CreateAMaciRoundParams, CreateMaciRoundParams, CreateOracleMaciRoundParams } from './libs/contract/types';
4
4
  import { OfflineSigner } from '@cosmjs/proto-signing';
5
+ import { Circom } from './libs/circom';
5
6
  /**
6
7
  * @class MaciClient
7
8
  * @description This class is used to interact with Maci Client.
@@ -16,6 +17,7 @@ export declare class MaciClient {
16
17
  http: Http;
17
18
  indexer: Indexer;
18
19
  contract: Contract;
20
+ circom: Circom;
19
21
  feegrantOperator: string;
20
22
  whitelistBackendPubkey: string;
21
23
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dorafactory/maci-sdk",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "SDK for interacting with maci",
5
5
  "keywords": [
6
6
  "maci",
@@ -34,19 +34,23 @@
34
34
  "@cosmjs/launchpad": "^0.27.1",
35
35
  "@cosmjs/proto-signing": "^0.32.1",
36
36
  "@cosmjs/stargate": "^0.32.1",
37
- "@injectivelabs/sdk-ts": "^1.14.33",
38
37
  "assert": "^2.1.0",
39
38
  "bech32": "1.1.4",
40
- "superstruct": "^1.0.3",
41
- "ts-retry-promise": "^0.7.1",
42
- "tweetnacl": "^1.0.3",
39
+ "@dorafactory/circomlib": "^0.0.2",
43
40
  "colorts": "^0.1.63",
41
+ "cosmjs-types": "^0.9.0",
42
+ "blake-hash": "^2.0.0",
43
+ "ffjavascript": "^0.2.60",
44
+ "ethers": "^6.13.4",
45
+ "gql.tada": "^1.7.0",
46
+ "graphql": "^16.8.1",
44
47
  "husky": "^8.0.3",
45
48
  "keccak256": "^1.0.6",
46
49
  "process": "^0.11.10",
47
- "gql.tada": "^1.7.0",
48
- "graphql": "^16.8.1",
50
+ "superstruct": "^1.0.3",
49
51
  "tmp": "^0.2.1",
52
+ "ts-retry-promise": "^0.7.1",
53
+ "tweetnacl": "^1.0.3",
50
54
  "valibot": "0.36.0"
51
55
  },
52
56
  "devDependencies": {
package/src/index.ts CHANGED
@@ -5,9 +5,12 @@ export * from './libs/const';
5
5
  export { MaciClient } from './maci';
6
6
  export { Http } from './libs/http';
7
7
  export { Round } from './libs/query';
8
- export { Account } from './libs/query';
8
+ export { UserAccount } from './libs/query';
9
9
  export { Circuit } from './libs/query';
10
10
  export { Operator } from './libs/query';
11
11
  export { Proof } from './libs/query';
12
12
  export { Transaction } from './libs/query';
13
+ export * from './libs/circom';
13
14
  export * from './utils';
15
+ export { Scalar, utils } from 'ffjavascript';
16
+ export { default as createBlakeHash } from 'blake-hash';
@@ -0,0 +1,308 @@
1
+ import { randomBytes } from 'crypto';
2
+ import {
3
+ babyJub,
4
+ eddsa,
5
+ poseidon,
6
+ poseidonEncrypt,
7
+ Tree,
8
+ } from '@dorafactory/circomlib';
9
+ import { Scalar, utils } from 'ffjavascript';
10
+ import createBlakeHash from 'blake-hash';
11
+ import { solidityPackedSha256 } from 'ethers';
12
+
13
+ type MixedData<T> = T | Array<MixedData<T>> | { [key: string]: MixedData<T> };
14
+
15
+ export type PrivateKey = bigint;
16
+ export type PublicKey = [bigint, bigint];
17
+
18
+ export interface Account {
19
+ privKey: PrivateKey;
20
+ pubKey: PublicKey;
21
+ formatedPrivKey: PrivateKey;
22
+ }
23
+
24
+ const SNARK_FIELD_SIZE =
25
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
26
+
27
+ const bigInt2Buffer = (i: bigint) => {
28
+ let hex = i.toString(16);
29
+ if (hex.length % 2 === 1) {
30
+ hex = '0' + hex;
31
+ }
32
+ return Buffer.from(hex, 'hex');
33
+ };
34
+
35
+ const genRandomKey = () => {
36
+ // Prevent modulo bias
37
+ // const lim = BigInt('0x10000000000000000000000000000000000000000000000000000000000000000')
38
+ // const min = (lim - SNARK_FIELD_SIZE) % SNARK_FIELD_SIZE
39
+ const min =
40
+ 6350874878119819312338956282401532410528162663560392320966563075034087161851n;
41
+
42
+ let rand;
43
+ while (true) {
44
+ rand = BigInt('0x' + randomBytes(32).toString('hex'));
45
+
46
+ if (rand >= min) {
47
+ break;
48
+ }
49
+ }
50
+
51
+ const privKey = rand % SNARK_FIELD_SIZE;
52
+ return privKey;
53
+ };
54
+
55
+ const genPubKey = (privKey: bigint) => {
56
+ return eddsa.prv2pub(bigInt2Buffer(privKey));
57
+ };
58
+
59
+ export const stringizing = (
60
+ o: MixedData<bigint>,
61
+ path: MixedData<bigint>[] = []
62
+ ): MixedData<string> => {
63
+ if (path.includes(o)) {
64
+ throw new Error('loop nesting!');
65
+ }
66
+ const newPath = [...path, o];
67
+
68
+ if (Array.isArray(o)) {
69
+ return o.map((item) => stringizing(item, newPath));
70
+ } else if (typeof o === 'object') {
71
+ const output: { [key: string]: MixedData<string> } = {};
72
+ for (const key in o) {
73
+ output[key] = stringizing(o[key], newPath);
74
+ }
75
+ return output;
76
+ } else {
77
+ return o.toString();
78
+ }
79
+ };
80
+
81
+ export const genKeypair = (pkey?: PrivateKey): Account => {
82
+ const privKey = pkey ? pkey % SNARK_FIELD_SIZE : genRandomKey();
83
+ const pubKey = genPubKey(privKey);
84
+ const formatedPrivKey = formatPrivKeyForBabyJub(privKey);
85
+
86
+ return { privKey, pubKey, formatedPrivKey };
87
+ };
88
+
89
+ const formatPrivKeyForBabyJub = (privKey: PrivateKey) => {
90
+ const sBuff = eddsa.pruneBuffer(
91
+ createBlakeHash('blake512')
92
+ .update(bigInt2Buffer(privKey))
93
+ .digest()
94
+ .slice(0, 32)
95
+ );
96
+ const s = utils.leBuff2int(sBuff);
97
+ return Scalar.shr(s, 3);
98
+ };
99
+
100
+ export const genEcdhSharedKey = (
101
+ privKey: PrivateKey,
102
+ pubKey: PublicKey
103
+ ): PublicKey => {
104
+ const sharedKey = babyJub.mulPointEscalar(
105
+ pubKey,
106
+ formatPrivKeyForBabyJub(privKey)
107
+ );
108
+ if (sharedKey[0] === 0n) {
109
+ return [0n, 1n];
110
+ } else {
111
+ return sharedKey;
112
+ }
113
+ };
114
+
115
+ export const genMessageFactory =
116
+ (
117
+ stateIdx: number,
118
+ signPriKey: PrivateKey,
119
+ signPubKey: PublicKey,
120
+ coordPubKey: PublicKey
121
+ ) =>
122
+ (
123
+ encPriKey: PrivateKey,
124
+ nonce: number,
125
+ voIdx: number,
126
+ newVotes: number,
127
+ isLastCmd: boolean,
128
+ salt?: bigint
129
+ ): bigint[] => {
130
+ if (!salt) {
131
+ // uint56
132
+ salt = BigInt('0x' + randomBytes(7).toString('hex'));
133
+ }
134
+
135
+ const packaged =
136
+ BigInt(nonce) +
137
+ (BigInt(stateIdx) << 32n) +
138
+ (BigInt(voIdx) << 64n) +
139
+ (BigInt(newVotes) << 96n) +
140
+ (BigInt(salt) << 192n);
141
+
142
+ let newPubKey = [...signPubKey];
143
+ if (isLastCmd) {
144
+ newPubKey = [0n, 0n];
145
+ }
146
+
147
+ const hash = poseidon([packaged, ...newPubKey]);
148
+ const signature = eddsa.signPoseidon(bigInt2Buffer(signPriKey), hash);
149
+
150
+ const command = [packaged, ...newPubKey, ...signature.R8, signature.S];
151
+
152
+ const message = poseidonEncrypt(
153
+ command,
154
+ genEcdhSharedKey(encPriKey, coordPubKey),
155
+ 0n
156
+ );
157
+
158
+ return message;
159
+ };
160
+
161
+ // Batch generate encrypted commands.
162
+ // output format just like (with commands 1 ~ N):
163
+ // [
164
+ // [msg_N, msg_N-1, ... msg_3, msg_2, msg_1],
165
+ // [pubkey_N, pubkey_N-1, ... pubkey_3, pubkey_2, pubkey_1]
166
+ // ]
167
+ // and change the public key at command_N
168
+ export const batchGenMessage = (
169
+ stateIdx: number,
170
+ account: Account,
171
+ coordPubKey: PublicKey,
172
+ plan: [number, number][]
173
+ ) => {
174
+ const genMessage = genMessageFactory(
175
+ stateIdx,
176
+ account.privKey,
177
+ account.pubKey,
178
+ coordPubKey
179
+ );
180
+
181
+ const payload = [];
182
+ for (let i = plan.length - 1; i >= 0; i--) {
183
+ const p = plan[i];
184
+ const encAccount = genKeypair();
185
+ const msg = genMessage(
186
+ encAccount.privKey,
187
+ i + 1,
188
+ p[0],
189
+ p[1],
190
+ i === plan.length - 1
191
+ );
192
+
193
+ payload.push({
194
+ msg,
195
+ encPubkeys: encAccount.pubKey,
196
+ });
197
+ }
198
+
199
+ return payload;
200
+ };
201
+
202
+ export const privateKeyFromTxt = (txt: string) => {
203
+ if (typeof txt !== 'string') {
204
+ return;
205
+ }
206
+ const key = txt.split('\n')[1] || '';
207
+ if (key.length !== 512) {
208
+ return;
209
+ }
210
+ const keys = key.match(/[0-9a-f]{128}/g);
211
+ if (!keys || keys.length !== 4) {
212
+ return;
213
+ }
214
+ const priKey = poseidon(keys.map((k) => BigInt('0x' + k)));
215
+ return genKeypair(priKey % SNARK_FIELD_SIZE);
216
+ };
217
+
218
+ const rerandomize = (
219
+ pubKey: bigint[],
220
+ ciphertext: { c1: bigint[]; c2: bigint[] },
221
+ randomVal = genRandomKey()
222
+ ) => {
223
+ const d1 = babyJub.addPoint(
224
+ babyJub.mulPointEscalar(babyJub.Base8, randomVal),
225
+ ciphertext.c1
226
+ );
227
+
228
+ const d2 = babyJub.addPoint(
229
+ babyJub.mulPointEscalar(pubKey, randomVal),
230
+ ciphertext.c2
231
+ );
232
+
233
+ return {
234
+ d1,
235
+ d2,
236
+ } as { d1: bigint[]; d2: bigint[] };
237
+ };
238
+
239
+ export const genAddKeyProof = async (
240
+ depth: number,
241
+ {
242
+ coordPubKey,
243
+ oldKey,
244
+ deactivates,
245
+ }: {
246
+ coordPubKey: PublicKey;
247
+ oldKey: Account;
248
+ deactivates: bigint[][];
249
+ }
250
+ ) => {
251
+ const sharedKeyHash = poseidon(genEcdhSharedKey(oldKey.privKey, coordPubKey));
252
+
253
+ const randomVal = genRandomKey();
254
+ const deactivateIdx = deactivates.findIndex((d) => d[4] === sharedKeyHash);
255
+ if (deactivateIdx < 0) {
256
+ return null;
257
+ }
258
+
259
+ const deactivateLeaf = deactivates[deactivateIdx];
260
+
261
+ const c1 = [deactivateLeaf[0], deactivateLeaf[1]];
262
+ const c2 = [deactivateLeaf[2], deactivateLeaf[3]];
263
+
264
+ const { d1, d2 } = rerandomize(coordPubKey, { c1, c2 }, randomVal);
265
+
266
+ const nullifier = poseidon([oldKey.formatedPrivKey, 1444992409218394441042n]);
267
+
268
+ const tree = new Tree(5, depth, 0n);
269
+ const leaves = deactivates.map((d) => poseidon(d));
270
+ tree.initLeaves(leaves);
271
+
272
+ const deactivateRoot = tree.root;
273
+ const deactivateLeafPathElements = tree.pathElementOf(deactivateIdx);
274
+
275
+ const inputHash =
276
+ BigInt(
277
+ solidityPackedSha256(
278
+ new Array(7).fill('uint256'),
279
+ stringizing([
280
+ deactivateRoot,
281
+ poseidon(coordPubKey),
282
+ nullifier,
283
+ d1[0],
284
+ d1[1],
285
+ d2[0],
286
+ d2[1],
287
+ ]) as string[]
288
+ )
289
+ ) % SNARK_FIELD_SIZE;
290
+
291
+ const input = {
292
+ inputHash,
293
+ coordPubKey,
294
+ deactivateRoot,
295
+ deactivateIndex: deactivateIdx,
296
+ deactivateLeaf: poseidon(deactivateLeaf),
297
+ c1,
298
+ c2,
299
+ randomVal,
300
+ d1,
301
+ d2,
302
+ deactivateLeafPathElements,
303
+ nullifier,
304
+ oldPrivateKey: oldKey.formatedPrivKey,
305
+ };
306
+
307
+ return input;
308
+ };