@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.
- package/dist/index.d.ts +4 -1
- package/dist/index.js +326 -10
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +312 -9
- package/dist/index.mjs.map +1 -1
- package/dist/libs/circom/circomlib.d.ts +39 -0
- package/dist/libs/circom/index.d.ts +10 -0
- package/dist/libs/circom/tree.d.ts +23 -0
- package/dist/libs/circom/types.d.ts +7 -0
- package/dist/libs/contract/contract.d.ts +4 -0
- package/dist/libs/contract/utils.d.ts +2 -2
- package/dist/libs/contract/vars.d.ts +14 -16
- package/dist/libs/indexer/indexer.d.ts +2 -2
- package/dist/libs/maci/index.d.ts +0 -0
- package/dist/libs/maci/maci.d.ts +62 -0
- package/dist/libs/maci/types.d.ts +6 -0
- package/dist/libs/oracle-certificate/index.d.ts +1 -0
- package/dist/libs/oracle-certificate/oracle-certificate.d.ts +27 -0
- package/dist/libs/oracle-certificate/types.d.ts +5 -0
- package/dist/libs/query/account.d.ts +1 -1
- package/dist/libs/query/index.d.ts +1 -1
- package/dist/maci.d.ts +2 -0
- package/package.json +11 -7
- package/src/index.ts +4 -1
- package/src/libs/circom/circomlib.ts +308 -0
- package/src/libs/circom/index.ts +85 -0
- package/src/libs/circom/types.ts +8 -0
- package/src/libs/contract/contract.ts +4 -0
- package/src/libs/contract/utils.ts +11 -4
- package/src/libs/contract/vars.ts +45 -18
- package/src/libs/indexer/indexer.ts +3 -3
- package/src/libs/maci/index.ts +0 -0
- package/src/libs/maci/maci.ts +284 -0
- package/src/libs/maci/types.ts +6 -0
- package/src/libs/oracle-certificate/index.ts +1 -0
- package/src/libs/oracle-certificate/oracle-certificate.ts +90 -0
- package/src/libs/oracle-certificate/types.ts +6 -0
- package/src/libs/query/account.ts +1 -1
- package/src/libs/query/index.ts +1 -1
- 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
|
+
}
|
|
@@ -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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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,
|
|
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:
|
|
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 @@
|
|
|
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
|
+
}
|
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.
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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 {
|
|
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
|
+
};
|