# A suggested aggregation interface

**URL:** <https://forum.anoma.net/t/a-suggested-aggregation-interface/1711>\
**Category:** Proof aggregation\
**Created:** [July 1, 2025, 11:16am UTC](https://forum.anoma.net/t/a-suggested-aggregation-interface/1711 "2025-07-01T11:16:20Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![kike](https://dub1.discourse-cdn.com/flex013/user_avatar/forum.anoma.net/kike/32/745_2.png) [@kike](https://forum.anoma.net/u/kike)\
**Post date:** [July 1, 2025, 11:16am UTC](https://forum.anoma.net/t/a-suggested-aggregation-interface/1711/1 "2025-07-01T11:16:20Z")

</div>

## Compliance and logic relations

For a program\[1\] \mathsf P, let the image set

\mathcal L\_{\mathsf P} := \{u\ |\ \exists w\text{ s.t. } \mathsf P (w)=u\}.

In the context of the resource machine, this captures both, compliance statements ``u\in\mathcal L\_c" and resource logic statements ``u\in\mathcal L\_l".

- Compliance statements: the program \mathsf P\_c are the [compliance constraints](https://specs.anoma.net/latest/arch/system/state/resource_machine/data_structures/compliance_unit/compliance_proof.html#compliance-constraints), w is the [compliance witness](https://specs.anoma.net/latest/arch/system/state/resource_machine/data_structures/compliance_unit/compliance_proof.html#instance), and u is the [compliance instance](https://specs.anoma.net/latest/arch/system/state/resource_machine/data_structures/compliance_unit/compliance_proof.html#instance).

- Resource logic statements: the program \mathsf P \_l are the [logic constraints](https://specs.anoma.net/latest/arch/system/state/resource_machine/data_structures/action/resource_logic_proof.html#constraints), w is the [logic witness](https://specs.anoma.net/latest/arch/system/state/resource_machine/data_structures/action/resource_logic_proof.html#witness), and u is a [logic instance](https://specs.anoma.net/latest/arch/system/state/resource_machine/data_structures/action/resource_logic_proof.html#instance).

## The aggregated relation

\mathcal L\_\mathsf P is actually the induced language of the NP relation \mathcal R\_\mathsf P := \{(u;w)\ |\ \mathsf P (w)=u\}. Statements can be proved with a preprocessing SNARK (setup,prove,verify):

setup(\mathsf P)\to (pk\_\mathsf P,vk\_\mathsf P) produces a pair of proving and verifying keys for a given program (and implicit security parameter --input omitted).

prove(pk\_\mathsf P, u,w)\to \pi produces a proof for instance/witness pairs in \mathcal R\_{\mathsf P}.

verify(vk\_\mathsf P,u,\pi)\to \{true,false\} accepts the proof only if u\in\mathcal L\_\mathsf P (with high probability in the security parameter).

**Note:** For the RISC0 RM, the proof system is [STARK](https://eprint.iacr.org/2018/046.pdf), and verifying keys are the digest of the executed RISC-V program (the so-called [image id](https://dev.risczero.com/terminology#image-id)).

For the following aggregation program

\mathsf P\_a (\{vk\_i,u\_i,\pi\_i\}\_{i=1}^n) = \begin{cases} \bot \text{ if } verify(vk\_i,u\_i,\pi\_i) = false \text{ for some } i\\ h=commit(u\_1,\ldots,u\_n), d:=commit(vk\_1,\ldots,vk\_n) \text{ otherwise (if all proofs are valid)} \end{cases}

where commit is a binding commitment function\[2\], we define the correct aggregation relation as

\mathcal R\_a := \left\{(u:= (h,d,n);w:=(\{vk\_i,u\_i,\pi\_i\}\_{i=1}^n))\ |\ \mathsf P\_a (w) = u\right\}

Note that n is part of the aggregated instance u. That is, the relation does not fix the number of aggregated base instances u\_i. We want to be able to aggregate variable-length batches.

**Correct aggregation SNARK.** [This post](https://forum.anoma.net/t/recursive-proof-aggregation/1643) discusses a space-efficient proving strategy based in proof-carrying-data (PCD), where instance verification and generation of commitments h,d is done incrementally, using the same SNARK as for the compliance and logic programs. Let’s denote with pk\_{ag},vk\_{ag} the pair of proving/verifying aggregation keys output by the SNARK setup:

setup(\mathsf P\_{ag})\to (pk\_{ag},vk\_{ag})

**Instance reduction.** To generate the aggregated instance u we need the base instances u\_i, the base verifying keys vk\_i, and the function commit.

## The aggregation interface

The suggestion (based in the above discussion) is to spec up the following algorithms for aggregation.

### Minimal interface

- to\_transaction\_instance(Transaction)\to u\_{tx} =(h\_{tx},d\_{tx},n). Computes commitments of compliance and logic instances/verifying keys of a [transaction](https://specs.anoma.net/latest/arch/system/state/resource_machine/data_structures/transaction/transaction.html). There are n\_{tx} total instances in the transaction. This algorithm is used as a subroutine in the next two.

- aggregate\_transaction(pk\_{ag},Transaction)\to \pi\_{tx}. Produces a single aggregated proof attesting to the validity of all compliance and logic proofs of the [transaction](https://specs.anoma.net/latest/arch/system/state/resource_machine/data_structures/transaction/transaction.html).

- verify\_transaction\_proof(vk\_{ag},Transaction,\pi\_{tx})\to b\in\{true,false\}. Accepts or rejects the proof of a [transaction](https://specs.anoma.net/latest/arch/system/state/resource_machine/data_structures/transaction/transaction.html).

**Note:** The minimal interface does not change existing types, nor adds new ones. It would be possible to remove all compliance and logic proofs from a transaction, yielding a CompactTransaction with a single proof: the transaction proof \pi\_{tx} (which could be passed to proof verification).

### Extended interface

The next algorithms are optional, but nice to have. The observation is that once an aggregated proof \pi\_{ag} = prove(pk\_{ag},u\_{ag},w\_{ag}) is produced, it can be passed as a base instance in a subsequent batch for further aggregation (by a different actor). This allows to aggregate proofs of actions.

The extended interface is defined over CompactActions, which have a single (action) proof \pi\_{a}, and its (action) aggregation key vk\_{a}, and over CombinedTransaction, which are form by compact actions.

**Action scope:**

- to\_action\_instance(Action)\to u\_a:=(h\_a,d\_a,n\_a). Computes commitments of compliance and logic instances/verifying keys of an [action](https://specs.anoma.net/latest/arch/system/state/resource_machine/data_structures/action/index.html). There are n\_a total instances in the action.

- aggregate\_action(pk\_{ag},Action)\to (\pi\_{a},CompactAction). Produces a single aggregated proof attesting to the validity of all compliance and logic proofs of the [action](https://specs.anoma.net/latest/arch/system/state/resource_machine/data_structures/action/index.html).

- verify\_action\_proof(vk\_{ag},CompactAction,\pi\_{a})\to b\in\{true,false\}. Accepts or rejects the proof.

**Transaction scope:**

- to\_combined\_instance(CombinedTransaction)\to u\_{ctx}:=(h\_{ctx},d\_{ctx},n\_{ca}). Computes commitments of action instances and action verifying keys of a combined transaction. There are n\_{ctx} action instances.

- aggregate\_transaction(pk\_{ag},CombinedTransaction)\to (\pi\_{ctx},CompactTransaction). Produces a single aggregated proof attesting to the validity of all action proofs of the combined transaction.

- verify\_compact\_transaction\_proof(vk\_{ag},CompactTransaction,\pi\_{ctx})\to b\in\{true,false\}. Accepts or rejects the proof.

* * *

1. By program I mean an efficiently-computable function. 

2. We can use a collision-resistant hash function if we are willing to see it as a random oracle.

---

<div class="post-metadata">

**Author:** ![vveiln](https://dub1.discourse-cdn.com/flex013/user_avatar/forum.anoma.net/vveiln/32/60_2.png) [@vveiln](https://forum.anoma.net/u/vveiln)\
**Post date:** [July 7, 2025, 12:37pm UTC](https://forum.anoma.net/t/a-suggested-aggregation-interface/1711/2 "2025-07-07T12:37:16Z")

</div>

Thanks for the write up! It generally looks good to me. A couple of comments:

1. What would be a situation when the prover wants to prove actions first and then aggregate the proofs together?
2. I would suggest to rename things like `to_transaction_instance` and `verify_transaction_proof` to `to_aggregated_instance` and `verify_aggregated_proof` respectively and adjust names to align with that so that we can tell if the function is relevant to snark proof aggregation or other proving/verification

---

<div class="post-metadata">

**Author:** ![kike](https://dub1.discourse-cdn.com/flex013/user_avatar/forum.anoma.net/kike/32/745_2.png) [@kike](https://forum.anoma.net/u/kike)\
**Post date:** [July 7, 2025, 1:33pm UTC](https://forum.anoma.net/t/a-suggested-aggregation-interface/1711/3 "2025-07-07T13:33:19Z")

</div>

> [@vveiln](#):
>
> What would be a situation when the prover wants to prove actions first and then aggregate the proofs together?

The users can provide a single proof for their actions in their unbalanced transaction. Solvers, after matching, can generate the transaction proof by aggregating the action proofs.

It can be useful to reduce communication complexity (and intent pool size). Also, you can also see it as distributing the aggregation across different untrusted parties (a solver that assembles large number of actions in a tx might benefit from this).

> [@vveiln](#):
>
> I would suggest to rename things like `to_transaction_instance` and `verify_transaction_proof` to `to_aggregated_instance` and `verify_aggregated_proof` respectively and adjust names to align with that so that we can tell if the function is relevant to snark proof aggregation or other proving/verification

Fine with me. If it is decided to not aggregate in scopes, then there is no ambiguity: i.e. an aggregation will always mean aggregate in a transaction.
