Application Circuit
Write custom computation circuit for your application.
Last updated
Write custom computation circuit for your application.
Last updated
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.
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 methods Allocate
and Define
.
Build your computation logic in Define
with the help of sdk.CircuitAPI
and sdk.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 to understand the best practices for writing your app circuit.
Here is a demonstration of a custom app circuit in action:
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
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
, IsGreaterThan
Binary: ToBinary
, FromBinary
Assertions: AssertIsEqual
, AssertIsDifferent
, AssertIsLessThanOrEqual
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:
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.
An exhaustive list of circuit functions can be found under Circuit SDK Reference > .
You can find a detailed listing of the data stream functions in .
The input CircuitInput
parameter passed into your Define
function is built from the step. It contains the Receipts
, StorageSlots
, and Transactions
that your circuit wants to process. Read .
You can output your computation results and use them in your contract through the . The values you output will be exposed to your app contract.
Read more about these utilities in .