Skip to content

Commit 732d442

Browse files
committed
add and test cli
1 parent 53fd761 commit 732d442

File tree

2 files changed

+135
-13
lines changed

2 files changed

+135
-13
lines changed

Diff for: circom-compat/app/Main.hs

+4-13
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,17 @@ module Main where
22

33
import Circuit
44
import Circuit.Language
5-
import Circuit.Solver.Circom (CircomProgram (..), mkCircomProgram, nativeGenWitness)
5+
import Circom.Solver (CircomProgram (..), mkCircomProgram, nativeGenWitness)
66
import Data.Binary (decodeFile, encodeFile)
77
import Data.Field.Galois (Prime)
88
import Data.Map qualified as Map
99
import Protolude
1010
import R1CS (toR1CS)
11-
import R1CS.Circom (r1csToCircomR1CS)
11+
import Circom.CLI (defaultMain)
12+
import Circom.R1CS (r1csToCircomR1CS)
1213

1314
main :: IO ()
14-
main = do
15-
let BuilderState {..} = snd $ runCircuitBuilder program
16-
prog = mkCircomProgram bsVars bsCircuit
17-
r1cs = r1csToCircomR1CS $ toR1CS (cpVars prog) (cpCircuit prog)
18-
inputs = Map.fromList [("n", 6), ("a", 2), ("b", 3)]
19-
wtns = nativeGenWitness prog inputs
20-
encodeFile "circom-compat/examples/factors/circuit.r1cs" r1cs
21-
encodeFile "circom-compat/examples/factors/circuit.bin" prog
22-
encodeFile "circom-compat/examples/factors/witness.wtns" wtns
23-
prog' <- decodeFile "circom-compat/examples/factors/circuit.bin"
24-
print $ nativeGenWitness prog' inputs == wtns
15+
main = defaultMain "factors" program
2516

2617
type Fr = Prime 21888242871839275222246405745257275088548364400416034343698204186575808495617
2718

Diff for: circom-compat/src/Circom/CLI.hs

+131
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
module Circom.CLI (defaultMain) where
2+
3+
import Circom.R1CS (r1csToCircomR1CS)
4+
import Circom.Solver (CircomProgram (..), mkCircomProgram, nativeGenWitness)
5+
import Circuit.Arithmetic (CircuitVars (cvInputsLabels), InputBidings (labelToVar))
6+
import Circuit.Language.Compile (BuilderState (..), ExprM, runCircuitBuilder)
7+
import Data.Aeson (decodeFileStrict)
8+
import Data.Aeson qualified as A
9+
import Data.Aeson.Encode.Pretty (encodePretty)
10+
import Data.Binary (decode, decodeFile, encodeFile)
11+
import Data.ByteString.Lazy qualified as LBS
12+
import Data.Field.Galois (PrimeField)
13+
import Data.Text qualified as Text
14+
import Options.Applicative (CommandFields, Mod, Parser, ParserInfo, command, execParser, fullDesc, header, help, helper, hsubparser, info, long, progDesc, showDefault, strOption, switch, value)
15+
import Protolude
16+
import R1CS (toR1CS)
17+
import System.Directory (createDirectoryIfMissing)
18+
19+
data GlobalOpts = GlobalOpts
20+
{ outputDir :: FilePath,
21+
cmd :: Command
22+
}
23+
24+
optsParser :: Text -> ParserInfo GlobalOpts
25+
optsParser progName =
26+
info
27+
(helper <*> globalOptsParser)
28+
( fullDesc
29+
<> progDesc ("Compiling " <> Text.unpack progName <> " to a zk-SNARK")
30+
<> header ("Compile " <> Text.unpack progName <> " to a system of constraints and solve for a witness")
31+
)
32+
where
33+
globalOptsParser :: Parser GlobalOpts
34+
globalOptsParser =
35+
GlobalOpts
36+
<$> strOption
37+
( long "output-dir"
38+
<> help "output directory"
39+
<> showDefault
40+
<> value "circuit-output"
41+
)
42+
<*> hsubparser (compileCommand <> solveCommand)
43+
44+
compileCommand :: Mod CommandFields Command
45+
compileCommand =
46+
command "compile" (info (Compile <$> compileOptsParser <**> helper) (progDesc "Compile the program to an r1cs and constraint system"))
47+
48+
solveCommand :: Mod CommandFields Command
49+
solveCommand =
50+
command "solve" (info (Solve <$> solveOptsParser <**> helper) (progDesc "Generate a witness"))
51+
52+
data Command = Compile CompileOpts | Solve SolveOpts
53+
54+
data CompileOpts = CompileOpts
55+
{ optimizeOpts :: OptimizeOpts,
56+
includeJson :: Bool
57+
}
58+
59+
compileOptsParser :: Parser CompileOpts
60+
compileOptsParser =
61+
CompileOpts
62+
<$> optimizeOptsParser
63+
<*> switch
64+
( long "json"
65+
<> help "also write json versions of artifacts"
66+
)
67+
68+
data OptimizeOpts = OptimizeOpts
69+
{ propogateConstants :: Bool,
70+
removeUnreachable :: Bool
71+
}
72+
73+
optimizeOptsParser :: Parser OptimizeOpts
74+
optimizeOptsParser =
75+
OptimizeOpts
76+
<$> switch
77+
( long "propogate-constants"
78+
<> help "propogate constants through the circuit"
79+
)
80+
<*> switch
81+
( long "remove-unreachable"
82+
<> help "detect and remove variables not contributing to the output"
83+
)
84+
85+
data SolveOpts
86+
= SolveOpts
87+
{ inputsFile :: FilePath
88+
}
89+
90+
solveOptsParser :: Parser SolveOpts
91+
solveOptsParser =
92+
SolveOpts
93+
<$> strOption
94+
( long "inputs"
95+
<> help "inputs json file"
96+
<> showDefault
97+
<> value "inputs.json"
98+
)
99+
100+
defaultMain ::
101+
forall f a.
102+
(PrimeField f) =>
103+
Text ->
104+
ExprM f a ->
105+
IO ()
106+
defaultMain progName program = do
107+
opts <- execParser (optsParser progName)
108+
case cmd opts of
109+
Compile _ -> do
110+
let BuilderState {..} = snd $ runCircuitBuilder program
111+
prog = mkCircomProgram bsVars bsCircuit
112+
r1cs = r1csToCircomR1CS $ toR1CS (cpVars prog) (cpCircuit prog)
113+
createDirectoryIfMissing True (outputDir opts)
114+
encodeFile (r1csFilePath $ outputDir opts) r1cs
115+
encodeFile (binFilePath $ outputDir opts) prog
116+
let inputsTemplate = map (const A.Null) $ labelToVar $ cvInputsLabels $ cpVars prog
117+
LBS.writeFile (inputsTemplateFilePath $ outputDir opts) (encodePretty $ inputsTemplate)
118+
Solve solveOpts -> do
119+
inputs <- do
120+
mInputs <- decodeFileStrict (inputsFile solveOpts)
121+
maybe (panic "Failed to decode inputs") (pure . map (fromInteger @f)) mInputs
122+
circuit <- decodeFile (binFilePath $ outputDir opts)
123+
let wtns = nativeGenWitness circuit inputs
124+
encodeFile (witnessFilePath $ outputDir opts) wtns
125+
where
126+
baseFilePath :: FilePath -> FilePath
127+
baseFilePath dir = dir <> "/" <> Text.unpack progName
128+
inputsTemplateFilePath dir = dir <> "/" <> "inputs-template.json"
129+
binFilePath dir = baseFilePath dir <> ".bin"
130+
r1csFilePath dir = baseFilePath dir <> ".r1cs"
131+
witnessFilePath dir = baseFilePath dir <> ".wtns"

0 commit comments

Comments
 (0)