diff --git a/README.md b/README.md index b4df443..4e2a48b 100644 --- a/README.md +++ b/README.md @@ -7,13 +7,16 @@ files generated by [`circom-witnesscalc`](https://github.com/iden3/circom-witnes and either interpret or compile them to various algebra backends. While this is quite straightforward in principle, and seems to work on particular -examples, it turns out that `circom-witnesscalc` itself has some serious limitations. +examples, it turns out that (the legacy version of) `circom-witnesscalc` itself +has some serious limitations. The biggest one is that it doesn't support any kind of dynamic computation (which should be obvious from the fact that it produces a static graph). But even if one uses only static computations, there are further very annoying things which just don't work. -However at the end this is still a useful thing, as many circuits still work. +However at the end this is still a useful thing, as many (most?) circuits still work, and +the resulting static graph is much simpler than a VM bytecode (and easy to statically +analyse too!). ### Compiler @@ -42,7 +45,7 @@ Haskell compiler: - [ ] zikkurat backend - [ ] arkworks backend -Nim witness generator (to be used with [`nim-groth16`](https://github.com/codex-storage/nim-groth16)) +Nim witness generator (to be used with [`nim-groth16`](https://github.com/logos-storage/nim-groth16)) - [x] parsing the graph file - [x] parsing json input @@ -68,9 +71,12 @@ by `circom-witnesscalc`. ### Graph file format -`circom-witnesscalc` produces binary files encoding a computation graph. +The (legacy version of) `circom-witnesscalc` produces binary files encoding a computation graph. -This has the following format: +Note: `circom-witnesscalc` since changed to a VM based approach to support dynamic +computations (see above). However here we require the legacy version, called `build-circuit`. + +This computation graph description file has the following format: - magic header: `"wtns.graph.001"` (14 bytes) - number of nodes (8 bytes little endian) diff --git a/nim/.gitignore b/nim/.gitignore index 88d050b..6c8c417 100644 --- a/nim/.gitignore +++ b/nim/.gitignore @@ -1 +1,3 @@ -main \ No newline at end of file +.DS_Store +main +tmp/ \ No newline at end of file diff --git a/nim/circom_witnessgen/dependencies.nim b/nim/circom_witnessgen/dependencies.nim new file mode 100644 index 0000000..72c06fe --- /dev/null +++ b/nim/circom_witnessgen/dependencies.nim @@ -0,0 +1,78 @@ + +# figure out the part of the witness which depends on a given set of inputs +# +# this is intended to be used when a significant part of the witness is +# either constant or rarely changes, so a part of the proof generation +# can be precomputed + +#------------------------------------------------------------------------------- + +import std/sequtils +import std/sets + +import ./types +import ./graph + +#------------------------------------------------------------------------------- + +func isElem[T](what: T, list: seq[T]): bool = count(list,what) > 0 + +# note: the resulting set contains the _normal_ witness indices of the _unchanging_ inputs +# these indices are _different_ from the graph indices, because normally there +# are much more graph nodes than witness elements +proc unchangingInputIndices(circuitInputs: seq[(string, SignalDescription)], unchanging: seq[string]): HashSet[int] = + var table: HashSet[int] + incl(table, 0) # index 0 is constant 1, it never changes + for (key, desc) in circuitInputs: + if isElem(key,unchanging): + let k: int = int(desc.length) + let o: int = int(desc.offset) + for i in 0.. " & fToDecimal(output[j]) & " | from " & ($idx) return output - #------------------------------------------------------------------------------- diff --git a/nim/main.nim b/nim/main.nim index b665f81..172fdb1 100644 --- a/nim/main.nim +++ b/nim/main.nim @@ -1,17 +1,25 @@ +import std/options + import circom_witnessgen/field # import circom_witnessgen/div_mod +import circom_witnessgen/types import circom_witnessgen/load import circom_witnessgen/input_json +import circom_witnessgen/dependencies import circom_witnessgen/witness +import circom_witnessgen/partial import circom_witnessgen/export_wtns #------------------------------------------------------------------------------- -const graph_file: string = "../tmp/graph3.bin" -const input_file: string = "../tmp/input3.json" -const wtns_file: string = "../tmp/nim3.wtns" +const graph_file: string = "./tmp/rln_main.graph" +const input_file: string = "./tmp/input.json" +const partial_file: string = "./tmp/partial.json" +const wtns_file: string = "./tmp/output.wtns" + +const unchanging_inputs: seq[string] = @["secret_key","msg_limit","merkle_root","leaf_idx","merkle_path"] #------------------------------------------------------------------------------- @@ -24,15 +32,49 @@ when isMainModule: when isMainModule: - echo "loading in " & input_file + echo "\nloading in " & graph_file + let gr = loadGraph(graph_file) + # echo $gr + echo $gr.meta.inputSignals + + echo "\ncalculating witness mask" + let mask = calcWitnessMask(gr, unchanging_inputs) + echo $countMask(mask) & " filled out of " & $(mask.len) + + echo "\nloading in " & partial_file + let partial_inp = loadInputJSON(partial_file) + # printInputs(partial_inp) + + echo "\ngenerating partial witness" + let partial_wtns = generatePartialWitness(gr, partial_inp) + let cnt = countSome(partial_wtns) + echo $cnt & " filled out of " & $(partial_wtns.len) + + echo "\nloading in " & input_file let inp = loadInputJSON(input_file) # printInputs(inp) - echo "loading in " & graph_file - let gr = loadGraph(graph_file) - echo $gr - - echo "generating witness" + echo "\ngenerating witness" let wtns = generateWitness( gr, inp ) exportWitness(wtns_file, wtns) + echo "\ncomparing partial and full witness" + var ok = true + for i in 0..