LLZK 2.1.1
An open-source IR for Zero Knowledge (ZK) circuits
Loading...
Searching...
No Matches
llzk-witgen.cpp
Go to the documentation of this file.
1//===-- llzk-witgen.cpp - LLZK witness generation tool ----------*- C++ -*-===//
2//
3// Part of the LLZK Project, under the Apache License v2.0.
4// See LICENSE.txt for license information.
5// Copyright 2026 Project LLZK
6// SPDX-License-Identifier: Apache-2.0
7//
8//===----------------------------------------------------------------------===//
9
10#include "JSON.h"
11#include "WitgenDriver.h"
12#include "tools/config.h"
13
31
32#include <mlir/Dialect/Arith/IR/Arith.h>
33#include <mlir/Dialect/ControlFlow/IR/ControlFlowOps.h>
34#include <mlir/Dialect/Func/Extensions/InlinerExtension.h>
35#include <mlir/Dialect/Func/IR/FuncOps.h>
36#include <mlir/Dialect/MemRef/IR/MemRef.h>
37#include <mlir/Dialect/SCF/IR/SCF.h>
38#include <mlir/IR/BuiltinDialect.h>
39#include <mlir/IR/BuiltinOps.h>
40#include <mlir/IR/DialectRegistry.h>
41#include <mlir/Parser/Parser.h>
42
43#include <llvm/ADT/StringExtras.h>
44#include <llvm/Support/CommandLine.h>
45#include <llvm/Support/FileSystem.h>
46#include <llvm/Support/FormatVariadic.h>
47#include <llvm/Support/JSON.h>
48#include <llvm/Support/MemoryBuffer.h>
49#include <llvm/Support/PrettyStackTrace.h>
50#include <llvm/Support/Signals.h>
51
52using namespace mlir;
53
54static llvm::cl::opt<std::string> InputFilename(llvm::cl::Positional, llvm::cl::Required);
55static llvm::cl::opt<std::string>
56 InputsFilename("inputs", llvm::cl::Required, llvm::cl::desc("JSON input file"));
57static llvm::cl::list<std::string> IncludeDirs(
58 "I", llvm::cl::desc("Directory of include files"), llvm::cl::value_desc("directory"),
59 llvm::cl::Prefix
60);
61static llvm::cl::opt<std::string> BackendName(
62 "backend", llvm::cl::desc("Execution backend: interpreter or execution-engine"),
63 llvm::cl::init("interpreter")
64);
65static llvm::cl::opt<std::string> OutputScopeName(
66 "output-scope", llvm::cl::desc("Output scope: public or full-witness"), llvm::cl::init("public")
67);
68static llvm::cl::opt<std::string> UninitializedBehaviorName(
69 "uninitialized-behavior", llvm::cl::desc("Uninitialized value behavior: zero, random, or fail"),
70 llvm::cl::init("zero")
71);
72static llvm::cl::opt<uint64_t>
73 UninitializedSeed("uninitialized-seed", llvm::cl::desc("Seed for random uninitialized values"));
74static llvm::cl::opt<bool>
75 DumpJITCore("dump-jit-core", llvm::cl::desc("Print the pre-LLVM JIT module"));
76static llvm::cl::opt<bool>
77 DumpJITLLVM("dump-jit-llvm", llvm::cl::desc("Print the post-LLVM JIT module"));
78static llvm::cl::opt<std::string>
79 CheckOutputFilename("check-output", llvm::cl::desc("JSON file with expected witgen output"));
80
82int main(int argc, char **argv) {
83 llvm::sys::PrintStackTraceOnErrorSignal(llvm::StringRef());
84 llvm::setBugReportMsg(
85 "PLEASE submit a bug report to " BUG_REPORT_URL
86 " and include the crash backtrace, relevant LLZK files, and associated run script(s).\n"
87 );
88
89 llvm::cl::ParseCommandLineOptions(
90 argc, argv,
91 "llzk-witgen: execute LLZK compute semantics and emit JSON public outputs.\n"
92 "Note: llzk-witgen v1 ignores constrain() and traps on bool.assert.\n"
93 );
94
95 DialectRegistry registry;
97 mlir::func::registerInlinerExtension(registry);
98 registry.insert<
99 mlir::arith::ArithDialect, mlir::cf::ControlFlowDialect, mlir::func::FuncDialect,
100 mlir::memref::MemRefDialect, mlir::scf::SCFDialect>();
101 MLIRContext context;
102 context.appendDialectRegistry(registry);
103 context.loadAllAvailableDialects();
104 context.loadDialect<
105 mlir::arith::ArithDialect, mlir::cf::ControlFlowDialect, mlir::func::FuncDialect,
106 mlir::memref::MemRefDialect, mlir::scf::SCFDialect>();
107 if (failed(llzk::GlobalSourceMgr::get().setup(IncludeDirs))) {
108 return EXIT_FAILURE;
109 }
110
111 auto sourceBuffer = llvm::MemoryBuffer::getFileOrSTDIN(InputFilename);
112 if (!sourceBuffer) {
113 llvm::errs() << sourceBuffer.getError().message() << '\n';
114 return EXIT_FAILURE;
115 }
116
117 ParserConfig parserConfig(&context);
118 OwningOpRef<ModuleOp> moduleOp =
119 parseSourceString<ModuleOp>(sourceBuffer.get()->getBuffer(), parserConfig, InputFilename);
120 if (!moduleOp) {
121 return EXIT_FAILURE;
122 }
123
124 auto buffer = llvm::MemoryBuffer::getFileOrSTDIN(InputsFilename);
125 if (!buffer) {
126 llvm::errs() << buffer.getError().message() << '\n';
127 return EXIT_FAILURE;
128 }
129
130 auto parsed = llvm::json::parse(buffer.get()->getBuffer());
131 if (!parsed) {
132 llvm::errs() << "failed to parse JSON input: " << llvm::toString(parsed.takeError()) << '\n';
133 return EXIT_FAILURE;
134 }
135
137 if (BackendName == "execution-engine") {
139 } else if (BackendName == "interpreter") {
141 } else {
142 llvm::errs() << "unknown backend: " << BackendName << '\n';
143 return EXIT_FAILURE;
144 }
145 if (OutputScopeName == "full-witness") {
147 } else if (OutputScopeName == "public") {
149 } else {
150 llvm::errs() << "unknown output scope: " << OutputScopeName << '\n';
151 return EXIT_FAILURE;
152 }
153 if (UninitializedBehaviorName == "zero") {
155 } else if (UninitializedBehaviorName == "random") {
157 } else if (UninitializedBehaviorName == "fail") {
159 } else {
160 llvm::errs() << "unknown uninitialized behavior: " << UninitializedBehaviorName << '\n';
161 return EXIT_FAILURE;
162 }
163 if (UninitializedSeed.getNumOccurrences() > 0) {
164 options.randomSeed = UninitializedSeed;
165 }
166 options.inlineIncludes = true;
167 options.dumpJITCore = DumpJITCore;
168 options.dumpJITLLVM = DumpJITLLVM;
169
170 auto result = llzk::witgen::runWitgen(*moduleOp, *parsed, options);
171 if (!result) {
172 llvm::errs() << "llzk-witgen error: " << llvm::toString(result.takeError()) << '\n';
173 return EXIT_FAILURE;
174 }
175
176 if (CheckOutputFilename.getNumOccurrences() > 0) {
177 auto expectedBuffer = llvm::MemoryBuffer::getFileOrSTDIN(CheckOutputFilename);
178 if (!expectedBuffer) {
179 llvm::errs() << expectedBuffer.getError().message() << '\n';
180 return EXIT_FAILURE;
181 }
182
183 auto expected = llvm::json::parse(expectedBuffer.get()->getBuffer());
184 if (!expected) {
185 llvm::errs() << "failed to parse expected JSON output: "
186 << llvm::toString(expected.takeError()) << '\n';
187 return EXIT_FAILURE;
188 }
189
190 llvm::SmallVector<llzk::witgen::JSONMismatch> mismatches;
191 llzk::witgen::diffJSON(*expected, *result, mismatches);
192 if (!mismatches.empty()) {
193 llvm::errs() << "llzk-witgen output mismatch:\n";
194 llzk::witgen::printJSONMismatches(llvm::errs(), mismatches);
195 return EXIT_FAILURE;
196 }
197
198 llvm::outs() << "output matched expected JSON\n";
199 return EXIT_SUCCESS;
200 }
201
202 llvm::outs() << llvm::formatv("{0:2}", *result) << '\n';
203 return EXIT_SUCCESS;
204}
static GlobalSourceMgr & get()
#define BUG_REPORT_URL
Definition config.h:15
int main(int argc, char **argv)
Execute the llzk-witgen command-line tool.
This file defines llzk::registerAllDialects.
void diffJSON(const llvm::json::Value &expected, const llvm::json::Value &actual, llvm::SmallVectorImpl< JSONMismatch > &out, llvm::StringRef path)
Compare two JSON values structurally and append any mismatches to out.
Definition JSON.cpp:473
llvm::Expected< llvm::json::Value > runWitgen(ModuleOp moduleOp, const llvm::json::Value &input, const WitgenOptions &options)
Run include preprocessing, field validation, and backend execution.
void printJSONMismatches(llvm::raw_ostream &os, llvm::ArrayRef< JSONMismatch > mismatches)
Render one human-readable mismatch report.
Definition JSON.cpp:504
void registerAllDialects(mlir::DialectRegistry &registry)
Configure one llzk-witgen execution.
UninitializedBehavior uninitializedBehavior
std::optional< uint64_t > randomSeed