# How it works

NEBRA UPA v1 (currently v1.2) aggregates `Groth16` proofs (more proof systems to be supported in 2.0) from different sources. After a certain number of proofs (our current batch size is `32`) from different parties have been submitted to our address (see [deployments](https://docs.nebra.one/developer-guide/deployments "mention")), our off-chain prover network will generate an aggregated proof $$\pi\_{agg}$$. This aggregated proof effectively states that all the proofs in this batch have been verified.  By only verifying aggregated proofs on-chain, the verification cost of each proof is amortized, bringing up to 10x gas savings (see [gas-costs-on-l1s](https://docs.nebra.one/developer-guide/gas-costs-on-l1s "mention") for details). &#x20;

<figure><img src="https://3334770660-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMoBOXBLhvoWsjDCMhdCm%2Fuploads%2FY8PzpSlXN8SaSVC5fivu%2Fimage.png?alt=media&#x26;token=6e9037ec-02e7-4ae6-9203-7c36f1a3dcd7" alt=""><figcaption><p>NEBRA Overview</p></figcaption></figure>

The workflow of a blockchain application powered by zero-knowledge proof using NEBRA is as follows:

1. Register your verification key with NEBRA UPA. This will give you a `circuitId` (see [registering-applications](https://docs.nebra.one/developer-guide/registering-applications "mention"))
2. Submit your proof to NEBRA UPA together with the public input associated with the proof&#x20;
3. Wait for the event indicating that the proof is verified. After this event, application can query `isVerified` function to execute the application logic
4. Verified (or rejected) proofs can be viewed at NEBRA proof explorer: [nebrascan.io](https://www.nebrascan.io)

<br>
