Q: What is a zero-knowledge proof?
A: A zero-knowledge proof (or ZKP) is a protocol allowing "one party (the prover) [to] prove to another party (the verifier) that a given statement is true [without] conveying any additional information". In the specific case of the RISC Zero ZKP system, the prover can run an agreed-upon function F, passing it secret input and generating both a public output and a 'receipt' of F’s correct execution. The prover can send this receipt to the verifier, who can then check it, and presuming it checks correctly, the verifier can be very sure that prover ran the function correctly and that it produced a specific output. See our explainer on the RISC Zero ZKP system for more details.
Q: How did you make your RISC-V circuit?
A: The RISC-V circuit is found in step.cpp.inc and is generated by the make-circuit program. It consists of:
- Code to emulate RISC-V, including decoding RISC-V instructions and constructing the execution trace.
- Code to evaluate the constraint polynomials that check the execution trace.
- Auxiliary data to support structures such as ‘taps’.
Because the data structures supporting all three of these need to match very carefully, we created a ‘circuit compiler’ program that generates code for all three of these systems.
Q: What exactly is the method ID and how can we use it to determine if program code is altered before execution?
A: To confirm an execution path is possible given a particular binary, we want to match a record of executed instruction cycles to the instructions loaded into the code columns of our proof system. Because we can't know which program instructions will be read before runtime, we match the observed execution path against a table of Merkle tree roots representing successively larger portions of the code columns, increasing by powers of two up to an upper limit. The method ID is the table of Merkle roots, and it allows us to efficiently match executed program instructions to a loaded binary representing many possible instructions.
Code Project Help
Q: What do I do with the proof receipt once I’ve created it?
A: The receipt can be serialized and sent over the network to the verifier. The verifier does not need to have access to the host code, but they do need the method ID of the expected program. The method ID is a required parameter for the receipt.verify() function and is used to confirm that the expected code was executed.
In our code examples, the proof receipt is generated and verified within the same program, but the most common use case is one in which the verification happens on another system.
Q: What types of programs does the zkVM support in Rust?
Guest / Host Interactions
Q: If the guest zkVM lives on the host machine, can’t the host still tamper with the compiled code?
A: Like other zk-STARKs, RISC Zero’s implementation makes it cryptographically infeasable to generate an invalid receipt:
- If the binary is modified, then the receipt’s seal will not match the method ID of the expected binary.
- If the execution is modified, then the execution trace will be invalid.
- If the output is modified, then the journal’s hash will not match the hash recorded in the receipt.
Q: When can information be shared with the guest zkVM? How do you prevent buffer overflows?
A: Data can be sent during program execution from the host to the guest via a memory map. The host-writeable memory is write-once, meaning that adjacent memory regions cannot be overwritten and executed.
Q: How do I know which computations should be performed in the guest zkVM, and which can be offloaded to the host?
A: If you don't need to perform a computation securely, if others don't rely on it, and if it doesn't produce outputs that others rely on, it can probably be performed outside of the zkVM.
However, consider that code run in the RISC Zero zkVM can be shown to behave as expected even on a host that is entirely untrusted. To get the most value out of this guarantee, we recommend dividing the computational labor with an untrusted host in mind. That is, other parties should not need to trust the host's output or operations in order to benefit from the work done in the zkVM.
Data Processing & Performance
Q: If I want the guest to process large volumes of data during execution, I might be constrained by space limitations. What are my options?
A: If data is loaded from the host to restrict guest program size, the most significant limitation on zkVM data processing is a constraint on instruction cycles. The zkVM supports programs up to a number of instruction cycles determined by the upper limit for the method ID (which must include a Merkle tree of all program instruction cycles). Loading data into the guest costs instruction cycles, as does data processing.
There are workarounds for data limitations if the data is only included to ensure that its integrity becomes part of the proof of computation. If the data can be processed externally and simply needs to be verifiably unchanged, consider processing data externally and sending the guest a Merkle proof or (if no processing is needed) generating a SHA of a large dataset.
In the future, we plan to lift these processing limitations (with execution time tradeoffs or sufficient hardware to parallelize instructions).
Q: What is the current recommended size of a program running on the zkVM?
A: Although the theoretical maximum size is 128 MB, we recommend that programs be kept no larger than ~1 MB to run on RISC Zero’s current zkVM implementation.
Q: I’d like to speed up the processing done inside the zkVM. What are my options?
A: For cryptographic operations, it is possible to build ‘accelerator’ circuits such as our implementation of SHA26. Fast cryptography is sufficient to support many ‘DeFi’ applications. For many other applications, it is possible to perform most computation on the host (outside the zkVM) and then verify the results in the zkVM.