Application Circuit
Write custom computation circuit for your application.
The application circuit is a Go program and is the core part of your Brevis app. It is where you process the data you obtained in the data access step with your intended business logic. Even though you are indeed writing a ZK circuit, you don't actually need to know anything about ZK. This is because Brevis's SDK has abstracted away many low-level circuit framework details and only exposes easy-to-use APIs. When certain low-level details have to be exposed, we will explain what needs to be done clearly.
Dependencies
How to Build a Circuit
To implement an application circuit, you need to:
Define a struct that houses your custom inputs (custom inputs are optional). This is where you specify things like user wallet addresses, trading pairs, time periods or other "variables" that are going to be different across each query to your App Service.
Implement the
AppCircuit
interface that has two methodsAllocate
andDefine
.Build your computation logic in
Define
with the help ofsdk.CircuitAPI
andsdk.DataStream
Output the computation result using various output methods from
sdk.CircuitAPI
The circuit must implement the sdk.AppCircuit Interface:
Define
is where you write your circuit logic.Allocate
defines the maximal number of receipts/storage slots/transactions your application is going to use. Note that the higher the upper bounds are, the slower the application circuit is going to run for the same number of actual inputs. Read more on Allocate to understand the best practices for writing your app circuit.
Here is a demonstration of a custom app circuit in action:
Circuit API
sdk.CircuitAPI
is supplied to your circuit as a parameter of your Define
function. It houses many building blocks for circuit constructions. All control flows, logic operations, and math must go through circuit APIs.
Global Checks:
AssertInputsAreUnique
Hashing:
StorageKey
,StorageKeyOfArrayElement
,StorageKeyOfStructFieldInMapping
Output:
OutputUint
,OutputBytes32
,OutputBool
,OutputAddress
Casting:
ToBytes32
,ToUint521
,ToUint248
,ToInt248
Type-Specific Circuit APIs
The sdk.CircuitAPI struct has several submodules for type specific operations: Uint32, Uint248, Uint521, Int248, Bytes32.
Not every type's API has the same set of operations. In general you will be looking to use the sdk.Uint248 type most of the time. The following is a list of operations supported for Uint248:
Arithmetics:
Add
,Sub
,Mul
,Div
,Sqrt
Logic:
Select
,And
,Or
,Not
Comparison:
IsZero
,IsEqual
,IsLessThan
, IsGreaterThanBinary:
ToBinary
,FromBinary
Assertions:
AssertIsEqual
,AssertIsDifferent
,AssertIsLessThanOrEqual
An exhaustive list of circuit functions can be found under Circuit SDK Reference > Circuit API.
Data Stream API
The data stream API allows you to perform data analysis computations over receipts/storages/transactions in a MapReduce style. To create a DataStream
, simply wrap it around the data:
You can find a detailed listing of the data stream functions in Data Stream API doc.
Circuit Inputs
The input CircuitInput
parameter passed into your Define
function is built from the data preparation step. It contains the Receipts
, StorageSlots
, and Transactions
that your circuit wants to process. Read more on these types.
Circuit Outputs
You can output your computation results and use them in your contract through the output functions. The values you output will be exposed to your app contract.
Circuit Testing
The brevis-sdk/test
package contains some testing utilities.
During development: use test.IsSolved
to help in debugging circuit logic.
Before deployment: use test.ProverSucceeded
and test.ProverFailed
to check that your proofs are complete and sound.
Read more about these utilities in Circuit Testing.
Last updated