Skip to content

Generating proofs

The following document describes how proofs of execution correctness are generated using pil-stark package.

Once the constant and the committed polynomials are filled (as seen in the Filling polynomials section), the next step is generation of a proof of correctness.

A Javascript package called pil-stark has been specially designed to work together with pilcom to generate STARK proofs for execution correctness of programs being verified.

The pil-stark package utilizes three functions: starkSetup, starkGen, and starkVerify.

starkSetup

The first function, starkSetup, is for setting up the STARK. Its computational output is independent of the values of committed polynomials. This includes computation of the tree of evaluations of the constant polynomials.

In order to execute the setup generation, one needs an object called starkStruct, which specifies the following FRI-related parameters:

  • the size of the trace domain (which must coincide with \(\texttt{N}\), as defined in PIL),

  • the size of the extended domain (which together with the previous parameter specifies the correspondent blowup factor),

  • the number of queries to be executed and the reduction factors for each of the FRI steps.

We execute the setup using the code below:

const { FGL, starkSetup } = require("pil-stark");

async function execute() {

  // ... input PIL Code

  const starkStruct = {
    "nBits": 10, 
    "nBitsExt": 11, 
    "nQueries": 128, 
    "verificationHashType": "GL", 
    "steps": [ 
      {"nBits": 11}, 
      {"nBits": 5}, 
      {"nBits": 3}, 
      {"nBits": 1} 
    ]
  };

  const setup = await starkSetup(constPols, pil, starkStruct); 
} 

starkGen

After setting up the STARK with the starkSetup function, the proof of execution correctness can be generated with the starkGen function.

The code shown below carries out this task.

const { FGL, starkSetup, starkGen } = require("pil-stark"); 

async function execute() {

  // ... Previous Code

  const resProof = await starkGen(cmPols, constPols, setup.constTree, setup.starkInfo); 
} 

Observe that the starkGen object contains a starkInfo field which contains, besides all the starkStruct parameters, a lot of useful information about how the input PIL code looks like.

starkVerify

Now that a proof has been generated, it can be verified by invoking the starkVerify function.

This function needs some information provided by the outputs of both the starkSetup and starkGen function as arguments.

const { FGL, starkSetup, starkGen, starkVerify } = require("pil-stark"); 

async function execute() {
  // ... Previous Code

  const resVerify = await starkVerify( 
    resP.proof, resP.publics, setup.constRoot, setup.starkInfo
  );

  if (resVerify === true) { 
    console.log("The proof is VALID!");
  } else {
    console.log("INVALID proof!");
  }
}

If the output of the starkVerify function is true, the proof is valid. Otherwise, the verifier should invalidate the proof sent by the prover.

A pil-stark DIY guide is given here.