-
Notifications
You must be signed in to change notification settings - Fork 65
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(setup): implement non interactive setup
- Loading branch information
Showing
8 changed files
with
366 additions
and
217 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,184 +1,176 @@ | ||
import fs from "fs" | ||
import { CeremonyTimeoutType } from "../types/enums" | ||
import { | ||
CircuitDocument, | ||
CircuitInputData, | ||
convertToDoubleDigits, | ||
genesisZkeyIndex, | ||
getPotStorageFilePath, | ||
getR1CSInfo, | ||
getR1csStorageFilePath, | ||
getWasmStorageFilePath, | ||
getZkeyStorageFilePath, | ||
potFilenameTemplate | ||
} from "../index" | ||
import { SetupCeremonyData } from "../types" | ||
|
||
/** | ||
* | ||
* { | ||
"ceremonyName": "Example Ceremony", | ||
"description": "This is an example ceremony", | ||
"startDate": "2023-07-01", | ||
"endDate": "2023-07-31", | ||
"timeoutThreshold": 3600, | ||
"fixed": true, | ||
"threshold": 10, | ||
"circomVersion": "0.5.1", | ||
"githubCircomTemplate": "github.com/circom/template", | ||
"commitHash": "1234567890", | ||
"paramsArray": ["param1", "param2", "param3"] | ||
} | ||
* Parse and validate that the ceremony configuration is correct | ||
* @notice this does not upload any files to storage | ||
* @param path <string> - the path to the configuration file | ||
* @returns SetupCeremonyData - the data to pass to the cloud function for setup | ||
*/ | ||
export const parseCeremonyFile = (path: string): SetupCeremonyData => { | ||
// check that the path exists | ||
if (!fs.existsSync(path)) throw new Error("Error while setting up the ceremony. The provided path to the configuration file does not exist. Please provide an absolute path and try again.") | ||
|
||
// read the data | ||
const data = JSON.parse(fs.readFileSync(path).toString()) | ||
|
||
// verify that the data is correct | ||
if (data['timeoutMechanismType'] !== CeremonyTimeoutType.DYNAMIC && data['timeoutMechanismType'] !== CeremonyTimeoutType.FIXED) | ||
throw new Error("Invalid timeout type. Please choose between") | ||
|
||
// validate that we have at least 1 circuit input data | ||
if (!data['circuits']) | ||
throw new Error("Error while setting up the ceremony. You need to provide the data for at least 1 circuit.") | ||
|
||
// validate that the end date is in the future | ||
let endDate: Date | ||
let startDate: Date | ||
try { | ||
endDate = new Date(data['endDate']) | ||
startDate = new Date(data['startDate']) | ||
} catch (error: any) { | ||
throw new Error("Error while setting up the ceremony. The dates should follow this format: 2023-07-04T00:00:00.") | ||
} | ||
|
||
if (endDate <= startDate) throw new Error("Error while setting up the ceremony. The end date should be greater than the start date.") | ||
|
||
const currentDate = new Date() | ||
|
||
if (endDate <= currentDate || startDate <= currentDate) | ||
throw new Error("Error while setting up the ceremony. The start and end dates should be in the future.") | ||
|
||
// validate penalty | ||
if (data['penalty'] <= 0) throw new Error("Error while setting up the ceremony. The penalty should be greater than zero.") | ||
|
||
const circuits: CircuitDocument[] = [] | ||
const urlPattern = /(https?:\/\/[^\s]+)/g | ||
const commitHashPattern = /^[a-f0-9]{40}$/i | ||
|
||
for (let i = 0; i < data['circuits'].length; i++) { | ||
const circuitData = data['circuits'][i] | ||
const artifacts = circuitData['artifacts'] | ||
const r1csPath = artifacts['r1csLocalFilePath'] | ||
const wasmPath = artifacts['wasmLocalFilePath'] | ||
|
||
// ensure that the artifact exist locally | ||
if (!fs.existsSync(r1csPath)) throw new Error("Error while setting up the ceremony. The path to the r1cs file does not exist. Please ensure this is correct and that an absolute path is provided.") | ||
if (!fs.existsSync(wasmPath)) throw new Error("Error while setting up the ceremony. The path to the wasm file does not exist. Please ensure this is correct and that an absolute path is provided.") | ||
|
||
// extract the metadata from the r1cs | ||
const metadata = getR1CSInfo(r1csPath) | ||
|
||
// validate that the circuit hash and template links are valid | ||
const template = circuitData['template'] | ||
|
||
const URLMatch = template['source'].match(urlPattern) | ||
if (URLMatch.length === 0 || URLMatch.length > 1) throw new Error("Error while setting up the ceremony. You should provide the URL to the circuits templates on GitHub.") | ||
|
||
import { Functions } from "firebase/functions" | ||
|
||
// ceremonyInputData: CeremonyInputData, | ||
// ceremonyPrefix: string, | ||
// circuits: CircuitDocument[] | ||
|
||
/* | ||
export type CeremonyInputData = { | ||
title: string | ||
description: string | ||
startDate: number | ||
endDate: number | ||
timeoutMechanismType: CeremonyTimeoutType | ||
penalty: number | ||
} | ||
export const enum CeremonyTimeoutType { | ||
DYNAMIC = "DYNAMIC", | ||
FIXED = "FIXED" | ||
} | ||
export type CircuitDocument = CircuitInputData & { | ||
metadata?: CircuitMetadata | ||
files?: CircuitArtifacts | ||
avgTimings?: CircuitTimings | ||
template?: SourceTemplateData | ||
compiler?: CircomCompilerData | ||
waitingQueue?: CircuitWaitingQueue | ||
lastUpdated?: number | ||
} | ||
export type CircuitWaitingQueue = { | ||
completedContributions: number | ||
contributors: Array<string> | ||
currentContributor: string | ||
failedContributions: number | ||
} | ||
export type CircuitTimings = { | ||
contributionComputation: number | ||
fullContribution: number | ||
verifyCloudFunction: number | ||
} | ||
export type CircuitArtifacts = { | ||
potFilename: string | ||
r1csFilename: string | ||
wasmFilename: string | ||
initialZkeyFilename: string | ||
potStoragePath: string | ||
r1csStoragePath: string | ||
wasmStoragePath: string | ||
initialZkeyStoragePath: string | ||
potBlake2bHash: string | ||
r1csBlake2bHash: string | ||
wasmBlake2bHash: string | ||
initialZkeyBlake2bHash: string | ||
} | ||
export type CircuitMetadata = { | ||
curve: string | ||
wires: number | ||
constraints: number | ||
privateInputs: number | ||
publicInputs: number | ||
labels: number | ||
outputs: number | ||
pot: number | ||
} | ||
export type CircuitInputData = { | ||
description: string | ||
compiler: CircomCompilerData | ||
template: SourceTemplateData | ||
verification: CircuitContributionVerification | ||
compilationArtifacts?: CompilationArtifacts | ||
metadata?: CircuitMetadata | ||
name?: string | ||
dynamicThreshold?: number | ||
fixedTimeWindow?: number | ||
sequencePosition?: number | ||
prefix?: string | ||
zKeySizeInBytes?: number | ||
} | ||
export type CircuitContributionVerification = { | ||
cfOrVm: CircuitContributionVerificationMechanism | ||
vm?: VMConfiguration | ||
} | ||
export type VMConfiguration = { | ||
vmConfigurationType?: string | ||
vmDiskType?: DiskTypeForVM | ||
vmDiskSize?: number | ||
vmInstanceId?: string | ||
} | ||
export type VMConfigurationType = { | ||
type: string | ||
ram: number | ||
vcpu: number | ||
} | ||
export type CircomCompilerData = { | ||
version: string | ||
commitHash: string | ||
} | ||
export type SourceTemplateData = { | ||
source: string | ||
commitHash: string | ||
paramsConfiguration: Array<string> | ||
} | ||
export const enum DiskTypeForVM { | ||
GP2 = "gp2", | ||
GP3 = "gp3", | ||
IO1 = "io1", | ||
ST1 = "st1", | ||
SC1 = "sc1" | ||
} | ||
export type CompilationArtifacts = { | ||
r1csFilename: string | ||
wasmFilename: string | ||
} | ||
*/ | ||
|
||
/* | ||
{ | ||
"title": "Example Ceremony", | ||
"description": "This is an example ceremony", | ||
"startDate": "2023-07-01", | ||
"endDate": "2023-07-31", | ||
"timeoutMechanismType": "FIXED", | ||
"penalty": 10 | ||
"timeoutThreshold": 3600, | ||
"fixed": true, | ||
"threshold": 10, | ||
"circuits": [ | ||
{ | ||
description: string | ||
compiler: { | ||
"version": "1.0", | ||
"commitHash": "0x1" | ||
const hashMatch = template['commitHash'].match(commitHashPattern) | ||
if (hashMatch.length === 0 || hashMatch.length > 1) throw new Error("Error while setting up the ceremony. You should provide a valid commit hash of the circuit templates.") | ||
|
||
const circuitPrefix = circuitData['prefix'] | ||
|
||
// filenames | ||
const doubleDigitsPowers = convertToDoubleDigits(metadata.pot!) | ||
const r1csCompleteFilename = `${circuitData['name']}.r1cs` | ||
const wasmCompleteFilename = `${circuitData['name']}.wasm` | ||
const smallestPowersOfTauCompleteFilenameForCircuit = `${potFilenameTemplate}${doubleDigitsPowers}.ptau` | ||
const firstZkeyCompleteFilename = `${circuitData['prefix']}_${genesisZkeyIndex}.zkey` | ||
|
||
// storage paths | ||
const r1csStorageFilePath = getR1csStorageFilePath(circuitPrefix, r1csCompleteFilename) | ||
const wasmStorageFilePath = getWasmStorageFilePath(circuitPrefix, wasmCompleteFilename) | ||
const potStorageFilePath = getPotStorageFilePath(smallestPowersOfTauCompleteFilenameForCircuit) | ||
const zkeyStorageFilePath = getZkeyStorageFilePath(circuitPrefix, firstZkeyCompleteFilename) | ||
|
||
const files: any = { | ||
potFilename: smallestPowersOfTauCompleteFilenameForCircuit, | ||
r1csFilename: r1csCompleteFilename, | ||
wasmFilename: wasmCompleteFilename, | ||
initialZkeyFilename: firstZkeyCompleteFilename, | ||
potStoragePath: potStorageFilePath, | ||
r1csStoragePath: r1csStorageFilePath, | ||
wasmStoragePath: wasmStorageFilePath, | ||
initialZkeyStoragePath: zkeyStorageFilePath | ||
} | ||
template: { | ||
"source": "https://github.com", | ||
"commitHash": "0x1", | ||
"paramConfiguration": [6,8,3,2] | ||
|
||
// validate that the compiler hash is a valid hash | ||
const compiler = circuitData['compiler'] | ||
const compilerHashMatch = compiler['commitHash'].match(commitHashPattern) | ||
if (compilerHashMatch.length === 0 || compilerHashMatch.length > 1) throw new Error("Error while setting up the ceremony. You should provide a valid commit hash of the circuit compiler.") | ||
|
||
// validate that the verification options are valid | ||
const verification = circuitData['verification'] | ||
if (verification['cfOrVM'] !== "CF" && verification['cfOrVM'] !== "VM") | ||
throw new Error("Error while setting up the ceremony. Please enter a valid verification mechanism: either CF or VM") | ||
|
||
// @todo VM parameters verification | ||
// if (verification['cfOrVM'] === "VM") {} | ||
|
||
// check that the timeout is provided for the correct configuration | ||
let dynamicThreshold: number | undefined | ||
let fixedTimeWindow: number | undefined | ||
if (data['timeoutMechanismType'] === CeremonyTimeoutType.DYNAMIC) { | ||
if (circuitData['dynamicTreshold'] <= 0) | ||
throw new Error("Error while setting up the ceremony. The dynamic threshold should be > 0.") | ||
dynamicThreshold = circuitData['dynamicTreshold'] | ||
} | ||
verification: { | ||
"cfOrVM": "VM", | ||
"vm": { | ||
"vmConfigurationType" : "1" | ||
"vmDiskType": "gp2", | ||
"vmDiskSize": 5, | ||
"vmInstanceId": "none yet" | ||
} | ||
|
||
if (data['timeoutMechanismType'] === CeremonyTimeoutType.FIXED) { | ||
if (circuitData['fixedTimeWindow'] <= 0) | ||
throw new Error("Error while setting up the ceremony. The fixed time window threshold should be > 0.") | ||
fixedTimeWindow = circuitData['fixedTimeWindow'] | ||
} | ||
compilationArtifacts?: { | ||
"r1csFileName": "circuit.r1cs", | ||
"wasmFileName": "circuit.wasm" | ||
|
||
// the Circuit data for the ceremony setup | ||
const circuit: CircuitDocument | CircuitInputData = { | ||
name: circuitData['name'], | ||
description: circuitData['description'], | ||
prefix: circuitData['prefix'], | ||
sequencePosition: i+1, | ||
metadata: metadata, | ||
files: files, | ||
template: template, | ||
compiler: compiler, | ||
verification: verification, | ||
fixedTimeWindow: fixedTimeWindow, | ||
dynamicThreshold: dynamicThreshold, | ||
avgTimings: { | ||
contributionComputation: 0, | ||
fullContribution: 0, | ||
verifyCloudFunction: 0 | ||
}, | ||
|
||
} | ||
name: "circuit1" | ||
dynamicThreshold: 0 | ||
fixedTimeWindow: 3600 | ||
sequencePosition: 1 | ||
prefix: "circuit1" | ||
} | ||
] | ||
} | ||
*/ | ||
|
||
circuits.push(circuit) | ||
} | ||
|
||
export const parseCeremonyFile = async (path: string) => { | ||
const data = JSON.parse(fs.readFileSync(path).toString()) | ||
const setupData: SetupCeremonyData = { | ||
ceremonyInputData: { | ||
title: data['title'], | ||
description: data['description'], | ||
startDate: startDate.valueOf(), | ||
endDate: endDate.valueOf(), | ||
timeoutMechanismType: data['timeoutMechanismType'], | ||
penalty: data['penalty'] | ||
}, | ||
ceremonyPrefix: data['prefix'], | ||
circuits: circuits | ||
} | ||
|
||
console.log(data) | ||
return setupData | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.