2024-05-01 21:12:24 +00:00
|
|
|
import std/[hashes, json, strutils, strformat, os, osproc]
|
2024-04-24 10:00:05 +00:00
|
|
|
|
2024-05-01 21:12:24 +00:00
|
|
|
type
|
|
|
|
CircuitEnv* = object
|
|
|
|
nimCircuitCli =
|
|
|
|
"vendor" / "codex-storage-proofs-circuits" / "reference" / "nim" / "proof_input" /
|
|
|
|
"cli"
|
|
|
|
circuitDirIncludes = "vendor" / "codex-storage-proofs-circuits" / "circuit"
|
|
|
|
ptauDefPath = "benchmarks" / "ceremony" / "powersOfTau28_hez_final_23.ptau"
|
|
|
|
ptauDefUrl = "https://storage.googleapis.com/zkevm/ptau/"
|
|
|
|
codexProjDir = ""
|
|
|
|
|
|
|
|
CircArgs* = object
|
|
|
|
depth*: int
|
|
|
|
maxslots*: int
|
|
|
|
cellsize*: int
|
|
|
|
blocksize*: int
|
|
|
|
nsamples*: int
|
|
|
|
entropy*: int
|
|
|
|
seed*: int
|
|
|
|
nslots*: int
|
|
|
|
ncells*: int
|
|
|
|
index*: int
|
2024-04-24 10:14:41 +00:00
|
|
|
|
2024-05-01 21:21:45 +00:00
|
|
|
template withDir(dir: string, blk: untyped) =
|
|
|
|
let prev = getCurrentDir()
|
|
|
|
try:
|
|
|
|
setCurrentDir(dir)
|
|
|
|
`blk`
|
|
|
|
finally:
|
|
|
|
setCurrentDir(prev)
|
|
|
|
|
2024-05-01 21:31:15 +00:00
|
|
|
template runit(cmd: string) =
|
|
|
|
echo "RUNNING: ", cmd
|
|
|
|
let cmdRes = execShellCmd(cmd)
|
|
|
|
echo "STATUS: ", cmdRes
|
|
|
|
assert cmdRes == 0
|
|
|
|
|
2024-05-01 21:21:45 +00:00
|
|
|
proc findCodexProjectDir(prev = getCurrentDir()): string =
|
|
|
|
## check that the CWD of script is in the codex parent
|
|
|
|
if not "codex.nimble".fileExists():
|
2024-05-01 21:33:30 +00:00
|
|
|
setCurrentDir(".."
|
2024-05-01 21:21:45 +00:00
|
|
|
if prev == getCurrentDir():
|
|
|
|
echo "\nERROR: Codex project folder not found (could not find codex.nimble)"
|
|
|
|
echo "\nBenchmark must be run from within the Codex project folder"
|
|
|
|
quit 1
|
|
|
|
setProjDir()
|
|
|
|
else:
|
|
|
|
getCurrentDir()
|
|
|
|
|
|
|
|
proc checkEnv*(env: CircuitEnv) =
|
|
|
|
## check that the CWD of script is in the codex parent
|
|
|
|
codexProjDir = findCodexProjectDir()
|
2024-04-24 10:14:41 +00:00
|
|
|
echo "\n\nFound project dir: ", codexProjDir
|
|
|
|
|
|
|
|
let snarkjs = findExe("snarkjs")
|
|
|
|
if snarkjs == "":
|
|
|
|
echo dedent"""
|
|
|
|
ERROR: must install snarkjs first
|
|
|
|
|
|
|
|
npm install -g snarkjs@latest
|
|
|
|
"""
|
|
|
|
|
|
|
|
let circom = findExe("circom")
|
|
|
|
if circom == "":
|
|
|
|
echo dedent"""
|
|
|
|
ERROR: must install circom first
|
|
|
|
|
|
|
|
git clone https://github.com/iden3/circom.git
|
|
|
|
cargo install --path circom
|
|
|
|
"""
|
|
|
|
|
|
|
|
if snarkjs == "" or circom == "":
|
|
|
|
quit 2
|
|
|
|
|
|
|
|
echo "Found SnarkJS: ", snarkjs
|
|
|
|
echo "Found Circom: ", circom
|
|
|
|
|
|
|
|
if not nimCircuitCli.fileExists:
|
|
|
|
echo "Nim Circuit reference cli not found: ", nimCircuitCli
|
|
|
|
echo "Building Circuit reference cli...\n"
|
2024-05-01 21:33:30 +00:00
|
|
|
withDir nimCircuitCli.parentDir:
|
2024-05-01 21:31:15 +00:00
|
|
|
runit "nimble build -d:release --styleCheck:off cli"
|
2024-04-24 10:14:41 +00:00
|
|
|
echo "CWD: ", getCurrentDir()
|
|
|
|
assert nimCircuitCli.fileExists()
|
|
|
|
|
|
|
|
nimCircuitCli = nimCircuitCli.absolutePath()
|
|
|
|
echo "Found NimCircuitCli: ", nimCircuitCli
|
|
|
|
|
|
|
|
circuitDirIncludes = circuitDirIncludes.absolutePath
|
|
|
|
echo "Found Circuit Path: ", circuitDirIncludes
|
|
|
|
|
|
|
|
ptauDefPath = ptauDefPath.absolutePath
|
|
|
|
echo "Found PTAU file: ", ptauDefPath
|
|
|
|
|
|
|
|
proc downloadPtau*(ptauPath, ptauUrl: string) =
|
2024-05-01 21:22:36 +00:00
|
|
|
## download ptau file using curl if needed
|
2024-04-24 10:14:41 +00:00
|
|
|
if not ptauPath.fileExists:
|
|
|
|
echo "Ceremony file not found, downloading..."
|
2024-05-01 21:33:30 +00:00
|
|
|
createDir ptauPath.parentDir
|
|
|
|
withDir ptauPath.parentDir:
|
2024-05-01 21:31:15 +00:00
|
|
|
runit fmt"curl --output '{ptauPath}' '{ptauUrl}'"
|
2024-04-29 10:55:08 +00:00
|
|
|
else:
|
|
|
|
echo "Found PTAU file at: ", ptauPath
|
2024-04-24 10:14:41 +00:00
|
|
|
|
|
|
|
proc getCircuitBenchPath*(args: CircArgs): string =
|
2024-04-24 14:28:53 +00:00
|
|
|
var an = ""
|
|
|
|
for f, v in fieldPairs(args):
|
|
|
|
an &= "_" & f & $v
|
|
|
|
absolutePath("benchmarks/circuit_bench" & an)
|
2024-04-24 10:14:41 +00:00
|
|
|
|
2024-04-24 12:24:35 +00:00
|
|
|
proc generateCircomAndSamples*(args: CircArgs, name: string) =
|
|
|
|
## run nim circuit and sample generator
|
|
|
|
var cliCmd = nimCircuitCli
|
|
|
|
for f, v in fieldPairs(args):
|
|
|
|
cliCmd &= " --" & f & "=" & $v
|
|
|
|
|
|
|
|
if not "input.json".fileExists:
|
|
|
|
echo "Generating Circom Files..."
|
2024-05-01 21:31:15 +00:00
|
|
|
runit fmt"{cliCmd} -v --circom={name}.circom --output=input.json"
|
2024-04-24 12:24:35 +00:00
|
|
|
|
2024-04-24 10:14:41 +00:00
|
|
|
proc createCircuit*(
|
|
|
|
args: CircArgs,
|
|
|
|
name = "proof_main",
|
|
|
|
circBenchDir = getCircuitBenchPath(args),
|
|
|
|
circuitDirIncludes = circuitDirIncludes,
|
|
|
|
ptauPath = ptauDefPath,
|
2024-04-29 10:55:08 +00:00
|
|
|
ptauUrl = ptauDefUrl & ptauPath.splitPath.tail,
|
2024-04-24 10:14:41 +00:00
|
|
|
someEntropy = "some_entropy_75289v3b7rcawcsyiur",
|
2024-05-01 21:12:24 +00:00
|
|
|
doGenerateWitness = false,
|
2024-04-24 12:11:55 +00:00
|
|
|
): tuple[dir: string, name: string] =
|
2024-04-24 10:14:41 +00:00
|
|
|
## Generates all the files needed for to run a proof circuit. Downloads the PTAU file if needed.
|
|
|
|
##
|
|
|
|
let circdir = circBenchDir
|
|
|
|
|
2024-05-01 21:33:30 +00:00
|
|
|
downloadPtau ptauPath, ptauUrl
|
2024-04-24 10:14:41 +00:00
|
|
|
|
|
|
|
echo "Creating circuit dir: ", circdir
|
2024-05-01 21:33:30 +00:00
|
|
|
createDir circdir
|
2024-04-24 10:14:41 +00:00
|
|
|
withDir circdir:
|
|
|
|
writeFile("circuit_params.json", pretty(%*args))
|
|
|
|
let
|
2024-05-01 21:12:24 +00:00
|
|
|
inputs = circdir / "input.json"
|
2024-04-24 10:14:41 +00:00
|
|
|
zkey = circdir / fmt"{name}.zkey"
|
|
|
|
wasm = circdir / fmt"{name}.wasm"
|
|
|
|
r1cs = circdir / fmt"{name}.r1cs"
|
2024-05-01 21:12:24 +00:00
|
|
|
wtns = circdir / fmt"{name}.wtns"
|
2024-04-24 10:14:41 +00:00
|
|
|
|
2024-04-24 12:24:35 +00:00
|
|
|
generateCircomAndSamples(args, name)
|
2024-04-24 10:14:41 +00:00
|
|
|
|
|
|
|
if not wasm.fileExists or not r1cs.fileExists:
|
2024-05-01 21:31:15 +00:00
|
|
|
runit fmt"circom --r1cs --wasm --O2 -l{circuitDirIncludes} {name}.circom"
|
2024-05-01 21:33:30 +00:00
|
|
|
moveFile fmt"{name}_js" / fmt"{name}.wasm", fmt"{name}.wasm"
|
2024-04-24 10:14:41 +00:00
|
|
|
echo "Found wasm: ", wasm
|
|
|
|
echo "Found r1cs: ", r1cs
|
|
|
|
|
|
|
|
if not zkey.fileExists:
|
|
|
|
echo "Zkey not found, generating..."
|
2024-05-01 21:33:30 +00:00
|
|
|
putEnv "NODE_OPTIONS", "--max-old-space-size=8192"
|
2024-04-24 10:14:41 +00:00
|
|
|
if not fmt"{name}_0000.zkey".fileExists:
|
2024-05-01 21:31:15 +00:00
|
|
|
runit fmt"snarkjs groth16 setup {r1cs} {ptauPath} {name}_0000.zkey"
|
2024-04-24 10:14:41 +00:00
|
|
|
echo fmt"Generated {name}_0000.zkey"
|
|
|
|
|
|
|
|
let cmd =
|
|
|
|
fmt"snarkjs zkey contribute {name}_0000.zkey {name}_0001.zkey --name='1st Contributor Name'"
|
|
|
|
echo "CMD: ", cmd
|
|
|
|
let cmdRes = execCmdEx(cmd, options = {}, input = someEntropy & "\n")
|
|
|
|
assert cmdRes.exitCode == 0
|
2024-04-24 10:00:05 +00:00
|
|
|
|
2024-05-01 21:33:30 +00:00
|
|
|
moveFile fmt"{name}_0001.zkey", fmt"{name}.zkey"
|
|
|
|
removeFile fmt"{name}_0000.zkey"
|
2024-04-24 10:00:05 +00:00
|
|
|
|
2024-05-01 21:12:24 +00:00
|
|
|
if not wtns.fileExists and doGenerateWitness:
|
2024-05-01 21:31:15 +00:00
|
|
|
runit fmt"node generate_witness.js {wtns} ../input.json ../witness.wtns"
|
2024-05-01 21:12:24 +00:00
|
|
|
|
2024-04-24 12:11:55 +00:00
|
|
|
return (circdir, name)
|
|
|
|
|
2024-04-24 10:14:41 +00:00
|
|
|
when isMainModule:
|
2024-05-01 21:21:45 +00:00
|
|
|
## test run creating a circuit
|
2024-04-24 10:14:41 +00:00
|
|
|
checkEnv()
|
2024-04-24 10:00:05 +00:00
|
|
|
|
2024-04-24 10:14:41 +00:00
|
|
|
let args = CircArgs(
|
|
|
|
depth: 32, # maximum depth of the slot tree
|
|
|
|
maxslots: 256, # maximum number of slots
|
|
|
|
cellsize: 2048, # cell size in bytes
|
|
|
|
blocksize: 65536, # block size in bytes
|
|
|
|
nsamples: 5, # number of samples to prove
|
|
|
|
entropy: 1234567, # external randomness
|
|
|
|
seed: 12345, # seed for creating fake data
|
|
|
|
nslots: 11, # number of slots in the dataset
|
|
|
|
index: 3, # which slot we prove (0..NSLOTS-1)
|
|
|
|
ncells: 512, # number of cells in this slot
|
|
|
|
)
|
2024-04-24 12:11:55 +00:00
|
|
|
let benchenv = createCircuit(args)
|
2024-05-01 21:12:24 +00:00
|
|
|
echo "\nBench dir:\n", benchenv
|