@devtion/devcli 0.0.0-a6dcd68 → 0.0.0-a9e4cd4
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/LICENSE +21 -0
- package/README.md +3 -1
- package/dist/.env +40 -39
- package/dist/index.js +117 -79
- package/dist/types/commands/contribute.d.ts +1 -1
- package/dist/types/commands/finalize.d.ts +4 -3
- package/dist/types/commands/observe.d.ts +1 -1
- package/dist/types/commands/setup.d.ts +2 -2
- package/dist/types/lib/prompts.d.ts +6 -6
- package/dist/types/lib/utils.d.ts +3 -2
- package/package.json +5 -4
- package/src/commands/auth.ts +17 -7
- package/src/commands/contribute.ts +12 -8
- package/src/commands/finalize.ts +19 -10
- package/src/commands/index.ts +1 -1
- package/src/commands/listCeremonies.ts +2 -3
- package/src/commands/observe.ts +3 -3
- package/src/commands/setup.ts +56 -45
- package/src/commands/validate.ts +2 -3
- package/src/index.ts +17 -8
- package/src/lib/localConfigs.ts +1 -1
- package/src/lib/prompts.ts +20 -20
- package/src/lib/services.ts +1 -3
- package/src/lib/utils.ts +42 -9
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Answers } from "prompts";
|
|
2
2
|
import { Firestore } from "firebase/firestore";
|
|
3
|
-
import { CeremonyInputData, FirebaseDocumentInfo, CircomCompilerData, CircuitInputData, CeremonyTimeoutType, DiskTypeForVM } from "@
|
|
3
|
+
import { CeremonyInputData, FirebaseDocumentInfo, CircomCompilerData, CircuitInputData, CeremonyTimeoutType, DiskTypeForVM } from "@devtion/actions";
|
|
4
4
|
/**
|
|
5
5
|
* Ask a binary (yes/no or true/false) customizable question.
|
|
6
6
|
* @param question <string> - the question to be answered.
|
|
@@ -24,14 +24,14 @@ export declare const promptCircomCompiler: () => Promise<CircomCompilerData>;
|
|
|
24
24
|
* Shows a list of circuits for a single option selection.
|
|
25
25
|
* @dev the circuit names are derived from local R1CS files.
|
|
26
26
|
* @param options <Array<string>> - an array of circuits names.
|
|
27
|
-
* @returns Promise<string> - the name of the
|
|
27
|
+
* @returns Promise<string> - the name of the chosen circuit.
|
|
28
28
|
*/
|
|
29
29
|
export declare const promptCircuitSelector: (options: Array<string>) => Promise<string>;
|
|
30
30
|
/**
|
|
31
31
|
* Shows a list of standard EC2 VM instance types for a single option selection.
|
|
32
32
|
* @notice the suggested VM configuration type is calculated based on circuit constraint size.
|
|
33
33
|
* @param constraintSize <number> - the amount of circuit constraints
|
|
34
|
-
* @returns Promise<string> - the name of the
|
|
34
|
+
* @returns Promise<string> - the name of the chosen VM type.
|
|
35
35
|
*/
|
|
36
36
|
export declare const promptVMTypeSelector: (constraintSize: any) => Promise<string>;
|
|
37
37
|
/**
|
|
@@ -42,7 +42,7 @@ export declare const promptVMDiskTypeSelector: () => Promise<DiskTypeForVM>;
|
|
|
42
42
|
/**
|
|
43
43
|
* Show a series of questions about the circuits.
|
|
44
44
|
* @param constraintSize <number> - the amount of circuit constraints.
|
|
45
|
-
* @param timeoutMechanismType <CeremonyTimeoutType> - the
|
|
45
|
+
* @param timeoutMechanismType <CeremonyTimeoutType> - the chosen timeout mechanism type for the ceremony.
|
|
46
46
|
* @param needPromptCircomCompiler <boolean> - a boolean value indicating if the questions related to the Circom compiler version and commit hash must be asked.
|
|
47
47
|
* @param enforceVM <boolean> - a boolean value indicating if the contribution verification could be supported by VM-only approach or not.
|
|
48
48
|
* @returns Promise<Array<Circuit>> - circuit info prompted by the coordinator.
|
|
@@ -67,7 +67,7 @@ export declare const promptCircuitAddition: () => Promise<boolean>;
|
|
|
67
67
|
* Shows a list of pre-computed zKeys for a single option selection.
|
|
68
68
|
* @dev the names are derived from local zKeys files.
|
|
69
69
|
* @param options <Array<string>> - an array of pre-computed zKeys names.
|
|
70
|
-
* @returns Promise<string> - the name of the
|
|
70
|
+
* @returns Promise<string> - the name of the chosen pre-computed zKey.
|
|
71
71
|
*/
|
|
72
72
|
export declare const promptPreComputedZkeySelector: (options: Array<string>) => Promise<string>;
|
|
73
73
|
/**
|
|
@@ -80,7 +80,7 @@ export declare const promptNeededPowersForCircuit: (suggestedSmallestNeededPower
|
|
|
80
80
|
* Shows a list of PoT files for a single option selection.
|
|
81
81
|
* @dev the names are derived from local PoT files.
|
|
82
82
|
* @param options <Array<string>> - an array of PoT file names.
|
|
83
|
-
* @returns Promise<string> - the name of the
|
|
83
|
+
* @returns Promise<string> - the name of the chosen PoT.
|
|
84
84
|
*/
|
|
85
85
|
export declare const promptPotSelector: (options: Array<string>) => Promise<string>;
|
|
86
86
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FirebaseDocumentInfo } from "@
|
|
1
|
+
import { FirebaseDocumentInfo } from "@devtion/actions";
|
|
2
2
|
import { OAuthCredential } from "firebase/auth";
|
|
3
3
|
import { DocumentData, Firestore } from "firebase/firestore";
|
|
4
4
|
import { Functions } from "firebase/functions";
|
|
@@ -154,5 +154,6 @@ export declare const getLatestUpdatesFromParticipant: (firestoreDatabase: Firest
|
|
|
154
154
|
* @param entropyOrBeaconHash <string> - the entropy or beacon hash (only when finalizing) for the contribution.
|
|
155
155
|
* @param contributorOrCoordinatorIdentifier <string> - the identifier of the contributor or coordinator (only when finalizing).
|
|
156
156
|
* @param isFinalizing <boolean> - flag to discriminate between ceremony finalization (true) and contribution (false).
|
|
157
|
+
* @param circuitsLength <number> - the total number of circuits in the ceremony.
|
|
157
158
|
*/
|
|
158
|
-
export declare const handleStartOrResumeContribution: (cloudFunctions: Functions, firestoreDatabase: Firestore, ceremony: FirebaseDocumentInfo, circuit: FirebaseDocumentInfo, participant: FirebaseDocumentInfo, entropyOrBeaconHash: any, contributorOrCoordinatorIdentifier: string, isFinalizing: boolean) => Promise<void>;
|
|
159
|
+
export declare const handleStartOrResumeContribution: (cloudFunctions: Functions, firestoreDatabase: Firestore, ceremony: FirebaseDocumentInfo, circuit: FirebaseDocumentInfo, participant: FirebaseDocumentInfo, entropyOrBeaconHash: any, contributorOrCoordinatorIdentifier: string, isFinalizing: boolean, circuitsLength: number) => Promise<void>;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devtion/devcli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.0-
|
|
4
|
+
"version": "0.0.0-a9e4cd4",
|
|
5
5
|
"description": "All-in-one interactive command-line for interfacing with zkSNARK Phase 2 Trusted Setup ceremonies",
|
|
6
6
|
"repository": "git@github.com:privacy-scaling-explorations/p0tion.git",
|
|
7
7
|
"homepage": "https://github.com/privacy-scaling-explorations/p0tion",
|
|
@@ -64,11 +64,11 @@
|
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
66
|
"@adobe/node-fetch-retry": "^2.2.0",
|
|
67
|
+
"@aws-sdk/client-s3": "^3.329.0",
|
|
68
|
+
"@devtion/actions": "latest",
|
|
67
69
|
"@octokit/auth-oauth-app": "^5.0.5",
|
|
68
70
|
"@octokit/auth-oauth-device": "^4.0.4",
|
|
69
71
|
"@octokit/request": "^6.2.3",
|
|
70
|
-
"@p0tion/actions": "^0.0.0-a6dcd68",
|
|
71
|
-
"@aws-sdk/client-s3": "^3.329.0",
|
|
72
72
|
"blakejs": "^1.2.1",
|
|
73
73
|
"boxen": "^7.1.0",
|
|
74
74
|
"chalk": "^5.2.0",
|
|
@@ -96,5 +96,6 @@
|
|
|
96
96
|
},
|
|
97
97
|
"publishConfig": {
|
|
98
98
|
"access": "public"
|
|
99
|
-
}
|
|
99
|
+
},
|
|
100
|
+
"gitHead": "6ae3553e4d11b4344404ad493cf95a169ae14a56"
|
|
100
101
|
}
|
package/src/commands/auth.ts
CHANGED
|
@@ -63,8 +63,13 @@ export const expirationCountdownForGithubOAuth = (expirationInSeconds: number) =
|
|
|
63
63
|
*/
|
|
64
64
|
export const onVerification = async (verification: Verification): Promise<void> => {
|
|
65
65
|
// Copy code to clipboard.
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
let noClipboard = false
|
|
67
|
+
try {
|
|
68
|
+
clipboard.writeSync(verification.user_code)
|
|
69
|
+
clipboard.readSync()
|
|
70
|
+
} catch (error) {
|
|
71
|
+
noClipboard = true
|
|
72
|
+
}
|
|
68
73
|
|
|
69
74
|
// Display data.
|
|
70
75
|
console.log(
|
|
@@ -73,12 +78,13 @@ export const onVerification = async (verification: Verification): Promise<void>
|
|
|
73
78
|
)} on this device to generate a new token and authenticate\n`
|
|
74
79
|
)
|
|
75
80
|
|
|
76
|
-
console.log(theme.colors.magenta(figlet.textSync(
|
|
81
|
+
console.log(theme.colors.magenta(figlet.textSync("Code is Below", { font: "ANSI Shadow" })), "\n")
|
|
77
82
|
|
|
83
|
+
const message = !noClipboard ? `has been copied to your clipboard (${theme.emojis.clipboard})` : ``
|
|
78
84
|
console.log(
|
|
79
|
-
`${theme.symbols.info} Your auth code: ${theme.text.bold(verification.user_code)}
|
|
85
|
+
`${theme.symbols.info} Your auth code: ${theme.text.bold(verification.user_code)} ${message} ${
|
|
80
86
|
theme.symbols.success
|
|
81
|
-
}
|
|
87
|
+
}\n`
|
|
82
88
|
)
|
|
83
89
|
|
|
84
90
|
const spinner = customSpinner(`Redirecting to Github...`, `clock`)
|
|
@@ -86,8 +92,12 @@ export const onVerification = async (verification: Verification): Promise<void>
|
|
|
86
92
|
|
|
87
93
|
await sleep(10000) // ~10s to make users able to read the CLI.
|
|
88
94
|
|
|
89
|
-
|
|
90
|
-
|
|
95
|
+
try {
|
|
96
|
+
// Automatically open the page (# Step 2).
|
|
97
|
+
await open(verification.verification_uri)
|
|
98
|
+
} catch (error: any) {
|
|
99
|
+
console.log(`${theme.symbols.info} Please authenticate via GitHub at ${verification.verification_uri}`)
|
|
100
|
+
}
|
|
91
101
|
|
|
92
102
|
spinner.stop()
|
|
93
103
|
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
generateValidContributionsAttestation,
|
|
23
23
|
commonTerms,
|
|
24
24
|
convertToDoubleDigits
|
|
25
|
-
} from "@
|
|
25
|
+
} from "@devtion/actions"
|
|
26
26
|
import { DocumentSnapshot, DocumentData, Firestore, onSnapshot, Timestamp } from "firebase/firestore"
|
|
27
27
|
import { Functions } from "firebase/functions"
|
|
28
28
|
import open from "open"
|
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
estimateParticipantFreeGlobalDiskSpace
|
|
41
41
|
} from "../lib/utils.js"
|
|
42
42
|
import { COMMAND_ERRORS, showError } from "../lib/errors.js"
|
|
43
|
-
import { bootstrapCommandExecutionAndServices, checkAuth } from "../lib/services.js"
|
|
43
|
+
import { authWithToken, bootstrapCommandExecutionAndServices, checkAuth } from "../lib/services.js"
|
|
44
44
|
import { getAttestationLocalFilePath, localPaths } from "../lib/localConfigs.js"
|
|
45
45
|
import theme from "../lib/theme.js"
|
|
46
46
|
import { checkAndMakeNewDirectoryIfNonexistent, writeFile } from "../lib/files.js"
|
|
@@ -724,7 +724,8 @@ export const listenToParticipantDocumentChanges = async (
|
|
|
724
724
|
participant,
|
|
725
725
|
entropy,
|
|
726
726
|
providerUserId,
|
|
727
|
-
false // not finalizing.
|
|
727
|
+
false, // not finalizing.
|
|
728
|
+
circuits.length
|
|
728
729
|
)
|
|
729
730
|
}
|
|
730
731
|
// Scenario (3.A).
|
|
@@ -810,7 +811,9 @@ export const listenToParticipantDocumentChanges = async (
|
|
|
810
811
|
await getLatestVerificationResult(firestoreDatabase, ceremony.id, circuit.id, participant.id)
|
|
811
812
|
|
|
812
813
|
// Get next circuit for contribution.
|
|
813
|
-
const nextCircuit = timeoutExpired
|
|
814
|
+
const nextCircuit = timeoutExpired
|
|
815
|
+
? getCircuitBySequencePosition(circuits, changedContributionProgress)
|
|
816
|
+
: getCircuitBySequencePosition(circuits, changedContributionProgress + 1)
|
|
814
817
|
|
|
815
818
|
// Check disk space requirements for participant.
|
|
816
819
|
const wannaGenerateAttestation = await handleDiskSpaceRequirementForNextContribution(
|
|
@@ -891,12 +894,13 @@ export const listenToParticipantDocumentChanges = async (
|
|
|
891
894
|
const contribute = async (opt: any) => {
|
|
892
895
|
const { firebaseApp, firebaseFunctions, firestoreDatabase } = await bootstrapCommandExecutionAndServices()
|
|
893
896
|
|
|
894
|
-
// Check for authentication.
|
|
895
|
-
const { user, providerUserId, token } = await checkAuth(firebaseApp)
|
|
896
|
-
|
|
897
897
|
// Get options.
|
|
898
898
|
const ceremonyOpt = opt.ceremony
|
|
899
899
|
const entropyOpt = opt.entropy
|
|
900
|
+
const { auth } = opt
|
|
901
|
+
|
|
902
|
+
// Check for authentication.
|
|
903
|
+
const { user, providerUserId, token } = auth ? await authWithToken(firebaseApp, auth) : await checkAuth(firebaseApp)
|
|
900
904
|
|
|
901
905
|
// Prepare data.
|
|
902
906
|
let selectedCeremony: FirebaseDocumentInfo
|
|
@@ -948,7 +952,7 @@ const contribute = async (opt: any) => {
|
|
|
948
952
|
const userData = userDoc.data()
|
|
949
953
|
if (!userData) {
|
|
950
954
|
spinner.fail(
|
|
951
|
-
`Unfortunately we could not find a user document with your information. This likely means that you did not pass the GitHub reputation checks and therefore are not elegible to contribute to any ceremony. Please contact the coordinator if you believe this to be an error.`
|
|
955
|
+
`Unfortunately we could not find a user document with your information. This likely means that you did not pass the GitHub reputation checks and therefore are not elegible to contribute to any ceremony. If you believe you pass the requirements, it might be possible that your profile is private and we were not able to fetch your real statistics, in this case please consider making your profile public for the duration of the contribution. Please contact the coordinator if you believe this to be an error.`
|
|
952
956
|
)
|
|
953
957
|
process.exit(0)
|
|
954
958
|
}
|
package/src/commands/finalize.ts
CHANGED
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
exportVerifierContract,
|
|
23
23
|
FirebaseDocumentInfo,
|
|
24
24
|
exportVkey
|
|
25
|
-
} from "@
|
|
25
|
+
} from "@devtion/actions"
|
|
26
26
|
import { Functions } from "firebase/functions"
|
|
27
27
|
import { Firestore } from "firebase/firestore"
|
|
28
28
|
import { dirname } from "path"
|
|
@@ -36,9 +36,9 @@ import {
|
|
|
36
36
|
sleep,
|
|
37
37
|
terminate
|
|
38
38
|
} from "../lib/utils.js"
|
|
39
|
-
import { bootstrapCommandExecutionAndServices, checkAuth } from "../lib/services.js"
|
|
39
|
+
import { authWithToken, bootstrapCommandExecutionAndServices, checkAuth } from "../lib/services.js"
|
|
40
40
|
import {
|
|
41
|
-
|
|
41
|
+
getFinalAttestationLocalFilePath,
|
|
42
42
|
getFinalZkeyLocalFilePath,
|
|
43
43
|
getVerificationKeyLocalFilePath,
|
|
44
44
|
getVerifierContractLocalFilePath,
|
|
@@ -112,7 +112,7 @@ export const handleVerifierSmartContract = async (
|
|
|
112
112
|
? `${dirname(
|
|
113
113
|
fileURLToPath(import.meta.url)
|
|
114
114
|
)}/../../../../node_modules/snarkjs/templates/verifier_groth16.sol.ejs`
|
|
115
|
-
: `${dirname(fileURLToPath(import.meta.url))}
|
|
115
|
+
: `${dirname(fileURLToPath(import.meta.url))}/../node_modules/snarkjs/templates/verifier_groth16.sol.ejs`
|
|
116
116
|
|
|
117
117
|
// Export the Solidity verifier smart contract.
|
|
118
118
|
const verifierCode = await exportVerifierContract(finalZkeyLocalFilePath, verifierPath)
|
|
@@ -152,6 +152,7 @@ export const handleVerifierSmartContract = async (
|
|
|
152
152
|
* @param participant <FirebaseDocumentInfo> - the Firestore document of the participant (coordinator).
|
|
153
153
|
* @param beacon <string> - the value used to compute the final contribution while finalizing the ceremony.
|
|
154
154
|
* @param coordinatorIdentifier <string> - the identifier of the coordinator.
|
|
155
|
+
* @param circuitsLength <number> - the number of circuits in the ceremony.
|
|
155
156
|
*/
|
|
156
157
|
export const handleCircuitFinalization = async (
|
|
157
158
|
cloudFunctions: Functions,
|
|
@@ -160,7 +161,8 @@ export const handleCircuitFinalization = async (
|
|
|
160
161
|
circuit: FirebaseDocumentInfo,
|
|
161
162
|
participant: FirebaseDocumentInfo,
|
|
162
163
|
beacon: string,
|
|
163
|
-
coordinatorIdentifier: string
|
|
164
|
+
coordinatorIdentifier: string,
|
|
165
|
+
circuitsLength: number
|
|
164
166
|
) => {
|
|
165
167
|
// Step (1).
|
|
166
168
|
await handleStartOrResumeContribution(
|
|
@@ -171,7 +173,8 @@ export const handleCircuitFinalization = async (
|
|
|
171
173
|
participant,
|
|
172
174
|
computeSHA256ToHex(beacon),
|
|
173
175
|
coordinatorIdentifier,
|
|
174
|
-
true
|
|
176
|
+
true,
|
|
177
|
+
circuitsLength
|
|
175
178
|
)
|
|
176
179
|
|
|
177
180
|
await sleep(2000) // workaound for descriptors.
|
|
@@ -241,11 +244,16 @@ export const handleCircuitFinalization = async (
|
|
|
241
244
|
* @dev For proper execution, the command requires the coordinator to be authenticated with a GitHub account (run auth command first) in order to
|
|
242
245
|
* handle sybil-resistance and connect to GitHub APIs to publish the gist containing the final public attestation.
|
|
243
246
|
*/
|
|
244
|
-
const finalize = async () => {
|
|
247
|
+
const finalize = async (opt: any) => {
|
|
245
248
|
const { firebaseApp, firebaseFunctions, firestoreDatabase } = await bootstrapCommandExecutionAndServices()
|
|
246
249
|
|
|
247
250
|
// Check for authentication.
|
|
248
|
-
const {
|
|
251
|
+
const { auth } = opt
|
|
252
|
+
const {
|
|
253
|
+
user,
|
|
254
|
+
providerUserId,
|
|
255
|
+
token: coordinatorAccessToken
|
|
256
|
+
} = auth ? await authWithToken(firebaseApp, auth) : await checkAuth(firebaseApp)
|
|
249
257
|
|
|
250
258
|
// Preserve command execution only for coordinators.
|
|
251
259
|
if (!(await isCoordinator(user))) showError(COMMAND_ERRORS.COMMAND_NOT_COORDINATOR, true)
|
|
@@ -306,7 +314,8 @@ const finalize = async () => {
|
|
|
306
314
|
circuit,
|
|
307
315
|
participant,
|
|
308
316
|
beacon,
|
|
309
|
-
providerUserId
|
|
317
|
+
providerUserId,
|
|
318
|
+
circuits.length
|
|
310
319
|
)
|
|
311
320
|
|
|
312
321
|
process.stdout.write(`\n`)
|
|
@@ -344,7 +353,7 @@ const finalize = async () => {
|
|
|
344
353
|
|
|
345
354
|
// Write public attestation locally.
|
|
346
355
|
writeFile(
|
|
347
|
-
|
|
356
|
+
getFinalAttestationLocalFilePath(
|
|
348
357
|
`${prefix}_${finalContributionIndex}_${commonTerms.foldersAndPathsTerms.attestation}.log`
|
|
349
358
|
),
|
|
350
359
|
Buffer.from(publicAttestation)
|
package/src/commands/index.ts
CHANGED
|
@@ -6,4 +6,4 @@ export { default as finalize } from "./finalize.js"
|
|
|
6
6
|
export { default as clean } from "./clean.js"
|
|
7
7
|
export { default as logout } from "./logout.js"
|
|
8
8
|
export { default as validate } from "./validate.js"
|
|
9
|
-
export { default as listCeremonies} from "./listCeremonies.js"
|
|
9
|
+
export { default as listCeremonies } from "./listCeremonies.js"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { commonTerms, getAllCollectionDocs } from "@
|
|
1
|
+
import { commonTerms, getAllCollectionDocs } from "@devtion/actions"
|
|
2
2
|
import { showError } from "../lib/errors.js"
|
|
3
3
|
import { bootstrapCommandExecutionAndServices } from "../lib/services.js"
|
|
4
4
|
|
|
@@ -17,11 +17,10 @@ const listCeremonies = async () => {
|
|
|
17
17
|
|
|
18
18
|
// loop through all ceremonies
|
|
19
19
|
for (const ceremony of ceremonies) names.push(ceremony.data().prefix)
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
// print them to the console
|
|
22
22
|
console.log(names.join(", "))
|
|
23
23
|
process.exit(0)
|
|
24
|
-
|
|
25
24
|
} catch (err: any) {
|
|
26
25
|
showError(`${err.toString()}`, false)
|
|
27
26
|
// we want to exit with a non-zero exit code
|
package/src/commands/observe.ts
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
getOpenedCeremonies,
|
|
8
8
|
isCoordinator,
|
|
9
9
|
convertToDoubleDigits
|
|
10
|
-
} from "@
|
|
10
|
+
} from "@devtion/actions"
|
|
11
11
|
import { Firestore } from "firebase/firestore"
|
|
12
12
|
import logSymbols from "log-symbols"
|
|
13
13
|
import readline from "readline"
|
|
@@ -15,7 +15,7 @@ import { COMMAND_ERRORS, GENERIC_ERRORS, showError } from "../lib/errors.js"
|
|
|
15
15
|
import { promptForCeremonySelection } from "../lib/prompts.js"
|
|
16
16
|
import { bootstrapCommandExecutionAndServices, checkAuth } from "../lib/services.js"
|
|
17
17
|
import theme from "../lib/theme.js"
|
|
18
|
-
import {customSpinner, getSecondsMinutesHoursFromMillis, sleep } from "../lib/utils.js"
|
|
18
|
+
import { customSpinner, getSecondsMinutesHoursFromMillis, sleep } from "../lib/utils.js"
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Clean cursor lines from current position back to root (default: zero).
|
|
@@ -143,7 +143,7 @@ const observe = async () => {
|
|
|
143
143
|
// Preserve command execution only for coordinators].
|
|
144
144
|
if (!(await isCoordinator(user))) showError(COMMAND_ERRORS.COMMAND_NOT_COORDINATOR, true)
|
|
145
145
|
|
|
146
|
-
// Get running
|
|
146
|
+
// Get running ceremonies info (if any).
|
|
147
147
|
const runningCeremoniesDocs = await getOpenedCeremonies(firestoreDatabase)
|
|
148
148
|
|
|
149
149
|
// Ask to select a ceremony.
|
package/src/commands/setup.ts
CHANGED
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import { zKey } from "snarkjs"
|
|
4
4
|
import boxen from "boxen"
|
|
5
|
-
import { createWriteStream, Dirent, renameSync } from "fs"
|
|
5
|
+
import { createWriteStream, Dirent, renameSync, existsSync } from "fs"
|
|
6
6
|
import { pipeline } from "node:stream"
|
|
7
7
|
import { promisify } from "node:util"
|
|
8
8
|
import fetch from "node-fetch"
|
|
9
9
|
import { Functions } from "firebase/functions"
|
|
10
|
-
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3"
|
|
11
10
|
import {
|
|
12
11
|
CeremonyTimeoutType,
|
|
13
12
|
CircomCompilerData,
|
|
@@ -37,7 +36,7 @@ import {
|
|
|
37
36
|
setupCeremony,
|
|
38
37
|
parseCeremonyFile,
|
|
39
38
|
CircuitContributionVerificationMechanism
|
|
40
|
-
} from "@
|
|
39
|
+
} from "@devtion/actions"
|
|
41
40
|
import { customSpinner, simpleLoader, sleep, terminate } from "../lib/utils.js"
|
|
42
41
|
import {
|
|
43
42
|
promptCeremonyInputData,
|
|
@@ -63,7 +62,6 @@ import {
|
|
|
63
62
|
getFileStats,
|
|
64
63
|
checkAndMakeNewDirectoryIfNonexistent
|
|
65
64
|
} from "../lib/files.js"
|
|
66
|
-
import { Readable } from "stream"
|
|
67
65
|
|
|
68
66
|
/**
|
|
69
67
|
* Handle whatever is needed to obtain the input data for a circuit that the coordinator would like to add to the ceremony.
|
|
@@ -183,7 +181,7 @@ export const handleAdditionOfCircuitsToCeremony = async (
|
|
|
183
181
|
|
|
184
182
|
if (matchingWasms.length !== 1) showError(COMMAND_ERRORS.COMMAND_SETUP_MISMATCH_R1CS_WASM, true)
|
|
185
183
|
|
|
186
|
-
// Get input data for
|
|
184
|
+
// Get input data for chosen circuit.
|
|
187
185
|
const circuitInputData = await getInputDataToAddCircuitToCeremony(
|
|
188
186
|
choosenCircuitFilename,
|
|
189
187
|
matchingWasms[0],
|
|
@@ -324,7 +322,7 @@ export const checkAndDownloadSmallestPowersOfTau = async (
|
|
|
324
322
|
* number of powers greater than or equal to the powers needed by the zKey), the coordinator will be asked
|
|
325
323
|
* to provide a number of powers manually, ranging from the smallest possible to the largest.
|
|
326
324
|
* @param neededPowers <number> - the smallest amount of powers needed by the zKey.
|
|
327
|
-
* @returns Promise<string, string> - the information about the
|
|
325
|
+
* @returns Promise<string, string> - the information about the chosen Powers of Tau file for the pre-computed zKey
|
|
328
326
|
* along with related powers.
|
|
329
327
|
*/
|
|
330
328
|
export const handlePreComputedZkeyPowersOfTauSelection = async (
|
|
@@ -468,7 +466,7 @@ export const handleCircuitArtifactUploadToStorage = async (
|
|
|
468
466
|
* from Hermez's ceremony Phase 1 Reliable Setup Ceremony.
|
|
469
467
|
* @param cmd? <any> - the path to the ceremony setup file.
|
|
470
468
|
*/
|
|
471
|
-
const setup = async (cmd: { template?: string
|
|
469
|
+
const setup = async (cmd: { template?: string; auth?: string }) => {
|
|
472
470
|
// Setup command state.
|
|
473
471
|
const circuits: Array<CircuitDocument> = [] // Circuits.
|
|
474
472
|
let ceremonyId: string = "" // The unique identifier of the ceremony.
|
|
@@ -476,8 +474,10 @@ const setup = async (cmd: { template?: string, auth?: string}) => {
|
|
|
476
474
|
const { firebaseApp, firebaseFunctions, firestoreDatabase } = await bootstrapCommandExecutionAndServices()
|
|
477
475
|
|
|
478
476
|
// Check for authentication.
|
|
479
|
-
const { user, providerUserId } = cmd.auth
|
|
480
|
-
|
|
477
|
+
const { user, providerUserId } = cmd.auth
|
|
478
|
+
? await authWithToken(firebaseApp, cmd.auth)
|
|
479
|
+
: await checkAuth(firebaseApp)
|
|
480
|
+
|
|
481
481
|
// Preserve command execution only for coordinators.
|
|
482
482
|
if (!(await isCoordinator(user))) showError(COMMAND_ERRORS.COMMAND_NOT_COORDINATOR, true)
|
|
483
483
|
|
|
@@ -503,7 +503,7 @@ const setup = async (cmd: { template?: string, auth?: string}) => {
|
|
|
503
503
|
// if there is the file option, then set up the non interactively
|
|
504
504
|
if (cmd.template) {
|
|
505
505
|
// 1. parse the file
|
|
506
|
-
// tmp data - do not cleanup files as we need them
|
|
506
|
+
// tmp data - do not cleanup files as we need them
|
|
507
507
|
const spinner = customSpinner(`Parsing ${theme.text.bold(cmd.template!)} setup configuration file...`, `clock`)
|
|
508
508
|
spinner.start()
|
|
509
509
|
const setupCeremonyData = await parseCeremonyFile(cmd.template!)
|
|
@@ -516,9 +516,6 @@ const setup = async (cmd: { template?: string, auth?: string}) => {
|
|
|
516
516
|
const bucketName = await handleCeremonyBucketCreation(firebaseFunctions, ceremonySetupData.ceremonyPrefix)
|
|
517
517
|
console.log(`\n${theme.symbols.success} Ceremony bucket name: ${theme.text.bold(bucketName)}`)
|
|
518
518
|
|
|
519
|
-
// create S3 clienbt
|
|
520
|
-
const s3 = new S3Client({region: 'us-east-1'})
|
|
521
|
-
|
|
522
519
|
// loop through each circuit
|
|
523
520
|
for await (const circuit of setupCeremonyData.circuits) {
|
|
524
521
|
// Local paths.
|
|
@@ -529,36 +526,44 @@ const setup = async (cmd: { template?: string, auth?: string}) => {
|
|
|
529
526
|
const zkeyLocalPathAndFileName = getZkeyLocalFilePath(circuit.files.initialZkeyFilename)
|
|
530
527
|
|
|
531
528
|
// 2. download the pot and wasm files
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
529
|
+
await checkAndDownloadSmallestPowersOfTau(
|
|
530
|
+
convertToDoubleDigits(circuit.metadata?.pot!),
|
|
531
|
+
circuit.files.potFilename
|
|
532
|
+
)
|
|
533
|
+
|
|
534
|
+
// 3. generate the zKey
|
|
536
535
|
const spinner = customSpinner(
|
|
537
|
-
`
|
|
538
|
-
`#${circuit.name}`
|
|
539
|
-
)} WASM file from the project's bucket...`,
|
|
536
|
+
`Generating genesis zKey for circuit ${theme.text.bold(circuit.name)}...`,
|
|
540
537
|
`clock`
|
|
541
538
|
)
|
|
542
539
|
spinner.start()
|
|
543
|
-
const command = new GetObjectCommand({ Bucket: ceremonySetupData.circuitArtifacts[index].artifacts.bucket, Key: ceremonySetupData.circuitArtifacts[index].artifacts.wasmStoragePath })
|
|
544
|
-
|
|
545
|
-
const response = await s3.send(command)
|
|
546
540
|
|
|
547
|
-
if (
|
|
548
|
-
|
|
541
|
+
if (existsSync(zkeyLocalPathAndFileName)) {
|
|
542
|
+
spinner.succeed(
|
|
543
|
+
`The genesis zKey for circuit ${theme.text.bold(circuit.name)} is already present on disk`
|
|
544
|
+
)
|
|
545
|
+
} else {
|
|
546
|
+
await zKey.newZKey(
|
|
547
|
+
r1csLocalPathAndFileName,
|
|
548
|
+
getPotLocalFilePath(circuit.files.potFilename),
|
|
549
|
+
zkeyLocalPathAndFileName,
|
|
550
|
+
undefined
|
|
551
|
+
)
|
|
552
|
+
spinner.succeed(
|
|
553
|
+
`Generation of the genesis zKey for circuit ${theme.text.bold(circuit.name)} completed successfully`
|
|
554
|
+
)
|
|
549
555
|
}
|
|
550
556
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
await zKey.newZKey(r1csLocalPathAndFileName, getPotLocalFilePath(circuit.files.potFilename), zkeyLocalPathAndFileName, undefined)
|
|
557
|
-
|
|
557
|
+
const hashSpinner = customSpinner(
|
|
558
|
+
`Calculating hashes for circuit ${theme.text.bold(circuit.name)}...`,
|
|
559
|
+
`clock`
|
|
560
|
+
)
|
|
561
|
+
hashSpinner.start()
|
|
558
562
|
// 4. calculate the hashes
|
|
559
563
|
const wasmBlake2bHash = await blake512FromPath(wasmLocalPathAndFileName)
|
|
560
564
|
const potBlake2bHash = await blake512FromPath(getPotLocalFilePath(circuit.files.potFilename))
|
|
561
565
|
const initialZkeyBlake2bHash = await blake512FromPath(zkeyLocalPathAndFileName)
|
|
566
|
+
hashSpinner.succeed(`Hashes for circuit ${theme.text.bold(circuit.name)} calculated successfully`)
|
|
562
567
|
|
|
563
568
|
// 5. upload the artifacts
|
|
564
569
|
|
|
@@ -570,7 +575,7 @@ const setup = async (cmd: { template?: string, auth?: string}) => {
|
|
|
570
575
|
zkeyLocalPathAndFileName,
|
|
571
576
|
circuit.files.initialZkeyFilename
|
|
572
577
|
)
|
|
573
|
-
|
|
578
|
+
|
|
574
579
|
// Check if PoT file has been already uploaded to storage.
|
|
575
580
|
const alreadyUploadedPot = await checkIfObjectExist(
|
|
576
581
|
firebaseFunctions,
|
|
@@ -611,25 +616,31 @@ const setup = async (cmd: { template?: string, auth?: string}) => {
|
|
|
611
616
|
// 6 update the setup data object
|
|
612
617
|
ceremonySetupData.circuits[index].files = {
|
|
613
618
|
...circuit.files,
|
|
614
|
-
potBlake2bHash
|
|
615
|
-
wasmBlake2bHash
|
|
616
|
-
initialZkeyBlake2bHash
|
|
619
|
+
potBlake2bHash,
|
|
620
|
+
wasmBlake2bHash,
|
|
621
|
+
initialZkeyBlake2bHash
|
|
617
622
|
}
|
|
618
623
|
|
|
619
624
|
ceremonySetupData.circuits[index].zKeySizeInBytes = getFileStats(zkeyLocalPathAndFileName).size
|
|
620
625
|
}
|
|
621
|
-
|
|
622
626
|
|
|
623
627
|
// 7. setup the ceremony
|
|
624
|
-
const ceremonyId = await setupCeremony(
|
|
625
|
-
|
|
626
|
-
ceremonySetupData.ceremonyInputData
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
628
|
+
const ceremonyId = await setupCeremony(
|
|
629
|
+
firebaseFunctions,
|
|
630
|
+
ceremonySetupData.ceremonyInputData,
|
|
631
|
+
ceremonySetupData.ceremonyPrefix,
|
|
632
|
+
ceremonySetupData.circuits
|
|
633
|
+
)
|
|
634
|
+
console.log(
|
|
635
|
+
`Congratulations, the setup of ceremony ${theme.text.bold(
|
|
636
|
+
ceremonySetupData.ceremonyInputData.title
|
|
637
|
+
)} (${`UID: ${theme.text.bold(ceremonyId)}`}) has been successfully completed ${
|
|
638
|
+
theme.emojis.tada
|
|
639
|
+
}. You will be able to find all the files and info respectively in the ceremony bucket and database document.`
|
|
640
|
+
)
|
|
641
|
+
|
|
631
642
|
terminate(providerUserId)
|
|
632
|
-
}
|
|
643
|
+
}
|
|
633
644
|
|
|
634
645
|
// Look for R1CS files.
|
|
635
646
|
const r1csFilePaths = await filterDirectoryFilesByExtension(cwd, `.r1cs`)
|
package/src/commands/validate.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { parseCeremonyFile } from "@
|
|
1
|
+
import { parseCeremonyFile } from "@devtion/actions"
|
|
2
2
|
import { showError } from "../lib/errors.js"
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Validate ceremony setup command.
|
|
6
6
|
*/
|
|
7
|
-
const validate = async (cmd: { template: string
|
|
7
|
+
const validate = async (cmd: { template: string; constraints?: number }) => {
|
|
8
8
|
try {
|
|
9
9
|
// parse the file and cleanup after
|
|
10
10
|
const parsedFile = await parseCeremonyFile(cmd.template, true)
|
|
@@ -18,7 +18,6 @@ const validate = async (cmd: { template: string, constraints?: number }) => {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
console.log(true)
|
|
21
|
-
|
|
22
21
|
} catch (err: any) {
|
|
23
22
|
showError(`${err.toString()}`, false)
|
|
24
23
|
// we want to exit with a non-zero exit code
|
package/src/index.ts
CHANGED
|
@@ -4,7 +4,17 @@ import { createCommand } from "commander"
|
|
|
4
4
|
import { readFileSync } from "fs"
|
|
5
5
|
import { dirname } from "path"
|
|
6
6
|
import { fileURLToPath } from "url"
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
setup,
|
|
9
|
+
auth,
|
|
10
|
+
contribute,
|
|
11
|
+
observe,
|
|
12
|
+
finalize,
|
|
13
|
+
clean,
|
|
14
|
+
logout,
|
|
15
|
+
validate,
|
|
16
|
+
listCeremonies
|
|
17
|
+
} from "./commands/index.js"
|
|
8
18
|
|
|
9
19
|
// Get pkg info (e.g., name, version).
|
|
10
20
|
const packagePath = `${dirname(fileURLToPath(import.meta.url))}/..`
|
|
@@ -21,15 +31,13 @@ program
|
|
|
21
31
|
.description("compute contributions for a Phase2 Trusted Setup ceremony circuits")
|
|
22
32
|
.option("-c, --ceremony <string>", "the prefix of the ceremony you want to contribute for", "")
|
|
23
33
|
.option("-e, --entropy <string>", "the entropy (aka toxic waste) of your contribution", "")
|
|
34
|
+
.option("-a, --auth <string>", "the Github OAuth 2.0 token", "")
|
|
24
35
|
.action(contribute)
|
|
25
36
|
program
|
|
26
37
|
.command("clean")
|
|
27
38
|
.description("clean up output generated by commands from the current working directory")
|
|
28
39
|
.action(clean)
|
|
29
|
-
program
|
|
30
|
-
.command("list")
|
|
31
|
-
.description("List all ceremonies prefixes")
|
|
32
|
-
.action(listCeremonies)
|
|
40
|
+
program.command("list").description("List all ceremonies prefixes").action(listCeremonies)
|
|
33
41
|
program
|
|
34
42
|
.command("logout")
|
|
35
43
|
.description("sign out from Firebae Auth service and delete Github OAuth 2.0 token from local storage")
|
|
@@ -47,10 +55,10 @@ const ceremony = program.command("coordinate").description("commands for coordin
|
|
|
47
55
|
ceremony
|
|
48
56
|
.command("setup")
|
|
49
57
|
.description("setup a Groth16 Phase 2 Trusted Setup ceremony for zk-SNARK circuits")
|
|
50
|
-
.option(
|
|
51
|
-
.option(
|
|
58
|
+
.option("-t, --template <path>", "The path to the ceremony setup template", "")
|
|
59
|
+
.option("-a, --auth <string>", "The Github OAuth 2.0 token", "")
|
|
52
60
|
.action(setup)
|
|
53
|
-
|
|
61
|
+
|
|
54
62
|
ceremony
|
|
55
63
|
.command("observe")
|
|
56
64
|
.description("observe in real-time the waiting queue of each ceremony circuit")
|
|
@@ -61,6 +69,7 @@ ceremony
|
|
|
61
69
|
.description(
|
|
62
70
|
"finalize a Phase2 Trusted Setup ceremony by applying a beacon, exporting verification key and verifier contract"
|
|
63
71
|
)
|
|
72
|
+
.option("-a, --auth <string>", "the Github OAuth 2.0 token", "")
|
|
64
73
|
.action(finalize)
|
|
65
74
|
|
|
66
75
|
program.parseAsync(process.argv)
|
package/src/lib/localConfigs.ts
CHANGED