Let $\t{PoseidonHash}$ be defined as in the section PoseidonHash Function.
Let $๐ฝโ, โโ, \t{DerivePubKey}, \t{Lift}_q, G_N, \mathcal{X}, \mathcal{Y}$ be defined as in the section Pallas and Vesta.
Let $\t{PedersenCommit}$ be defined as in the section Homomorphic Pedersen Commitments.
Let $\t{MerklePos}, \t{MerklePath}, \t{MerkleRoot}$ be defined as in the section Incremental Merkle Tree.
Let $\t{Params}\t{DAO}, \t{Bulla}\t{DAO}, \t{Params}\t{Proposal}, \t{Bulla}\t{Proposal}$ be defined as in DAO Model.
Let $\t{AeadEncNote}$ be defined as in In-band Secret Distribution.
Let $\t{ElGamalEncNote}โ, \t{ElGamal}.\t{Encrypt}$ be defined as in the section Verifiable In-Band Secret Distribution.
This function creates a DAO bulla $๐$. It's comparatively simple- we commit to the DAO params and then add the bulla to the set.
src/contract/dao/src/client/mint.rssrc/contract/dao/src/entrypoint/mint.rssrc/contract/dao/proof/mint.zkDefine the DAO mint function params $$ \begin{aligned} ๐ &โ \t{im}(\t{Bulla}_\t{DAO}) \ \t{PK} &โ โโ \end{aligned} $$
{{#include ../../../../../src/contract/dao/src/model.rs:dao-mint-params}}
DAO bulla uniqueness โ whether $๐$ already exists. If yes then fail.
Let there be a prover auxiliary witness inputs: $$ \begin{aligned} L &โ โโโ \ Q &โ โโโ \ EEQ &โ โโโ \ A_q &โ โโโ \ Ab &โ โโโ \ ฯ &โ ๐ฝโ \ Nx &โ ๐ฝโ \ px &โ ๐ฝโ \ Px &โ ๐ฝโ \ Vx &โ ๐ฝโ \ Ex &โ ๐ฝโ \ EEx &โ ๐ฝโ \ b\t{DAO} &โ ๐ฝโ \end{aligned} $$ Attach a proof $ฯ$ such that the following relations hold:
Proof of notes public key ownership โ $\t{NPK} = \t{DerivePubKey}(Nx)$.
Proof of proposer public key ownership โ $\t{pPK} = \t{DerivePubKey}(px)$.
Proof of proposals public key ownership โ $\t{PPK} = \t{DerivePubKey}(Px)$.
Proof of votes public key ownership โ $\t{VPK} = \t{DerivePubKey}(Vx)$.
Proof of executor public key ownership โ $\t{EPK} = \t{DerivePubKey}(Ex)$.
Proof of early executor public key ownership โ $\t{EEPK} = \t{DerivePubKey}(EEx)$.
Early execution quorum is not less than quorum โ $Q โค EEQ$.
DAO bulla integrity โ $๐ = \t{Bulla}_\t{DAO}((L, Q, EEQ, A_q, Ab, ฯ, \t{NPK}, \t{pPK}, \t{PPK}, \t{VPK}, \t{EPK}, \t{EEPK}), b\t{DAO})$
The state update additionally appends $๐$ to the DAO bulla Merkle tree, which is used later for existence proofs in the Propose phase.
There should be a single signature attached, which uses $\t{NPK}$ as the signature public key.
This contract function creates a DAO proposal. It takes a merkle root $R_\t{DAO}$ which contains the DAO bulla created in the Mint phase.
Several inputs are attached containing proof of ownership for the governance
token. This is to satisfy the proposer limit value set in the DAO.
We construct the proposal-specific nullifier $\cN$ which can leak anonymity
when those same coins are spent. To workaround this, wallet implementers
can attach an additional Money::transfer() call to the transaction.
For every input, an SMT non-membership proof shows the corresponding coin was unspent in the Money state snapshot determined by the coin merkle root $R\t{coin}$ and the nullifier set SMT root $R\t{null}$. Each value commit $V$ exported by the inputs is summed and used in the main proof to determine that the total value attached in the inputs crosses the proposer limit threshold.
This is merely a proof of ownership of holding a certain amount of value. Coins are not locked and continue to be spendable.
Additionally the encrypted note $\t{note}$ is used to send the proposal values to the DAO members using the public key set inside the DAO.
A proposal contains a list of auth calls as specified in Auth Calls. This specifies the contract call executed by the DAO on passing.
src/contract/dao/src/client/propose.rssrc/contract/dao/src/entrypoint/propose.rssrc/contract/dao/proof/propose-main.zksrc/contract/dao/proof/propose-input.zkDefine the DAO propose function params $$ \begin{aligned} R\t{DAO} &โ ๐ฝโ \ R\t{coin} &โ ๐ฝโ \ R\t{null} &โ ๐ฝโ \ T &โ ๐ฝโ \ ๐ซ &โ \t{im}(\t{Bulla}\t{Proposal}) \ \t{note} &โ \t{AeadEncNote} \ ๐ข &โ \t{ProposeInput}^* \end{aligned} $$
Define the DAO propose-input function params $$ \begin{aligned} \t{ProposeInput}.\cN &โ ๐ฝโ \ \t{ProposeInput}.V &โ โโ \ \t{ProposeInput}.\t{PK}_ฯ &โ โโ \end{aligned} $$
The coin merkle root $R\t{coin}$ and nullifier SMT root $R\t{null}$ are attached once per call and bound to every input proof.
{{#include ../../../../../src/contract/dao/src/model.rs:dao-propose-params}}
{{#include ../../../../../src/contract/dao/src/model.rs:dao-propose-params-input}}
Let $tโ = \t{BlockWindow} โ ๐ฝโ$ be the current blockwindow as defined in Blockwindow.
Let $\t{Attrs}_\t{Coin}$ be defined as in Coin.
Valid DAO bulla merkle root โ check that $R_\t{DAO}$ is a previously seen merkle root in the DAO contract merkle roots DB.
Valid snapshot โ check that $R\t{coin}$ is a previously seen
merkle root in the money contract merkle roots DB, that $R\t{null}$ is a
previously seen SMT root in the money contract nullifier roots DB, and
that the two snapshots correspond to the same state (the nullifier SMT
root snapshot must contain the coin tree root snapshot). The snapshot
must be recent enough: not older than PROPOSAL_SNAPSHOT_CUTOFF_LIMIT
blocks (100).
Proposal bulla uniqueness โ whether $๐ซ$ already exists. If yes then fail.
Let there be prover auxiliary witness inputs: $$ \begin{aligned} v &โ ๐ฝโ \ bแตฅ &โ ๐ฝแตฅ \ bฯ &โ ๐ฝโ \ p &โ \t{Params}\t{Proposal} \ bp &โ ๐ฝโ \ d &โ \t{Params}\t{DAO} \ b_d &โ ๐ฝโ \ px &โ ๐ฝโ \ (ฯ, ฮ ) &โ \t{MerklePos} ร \t{MerklePath} \ \end{aligned} $$ Attach a proof $ฯ_๐ซ$ such that the following relations hold:
Governance token commit โ export the DAO token ID as an encrypted commit $T = \t{PoseidonHash}(d.ฯ, b_ฯ)$, matching the token commit of every input.
Proof of proposer public key ownership โ $\t{pPK} = \t{DerivePubKey}(px)$.
DAO bulla integrity โ $๐ = \t{Bulla}_\t{DAO}(d, b_d)$
DAO existence โ $R_\t{DAO} = \t{MerkleRoot}(ฯ, ฮ , ๐)$
Proposal bulla integrity โ $๐ซ = \t{Bulla}_\t{Proposal}(p, b_p)$ where $p.tโ = tโ$ is enforced as a public input.
Proposer limit threshold met โ check the proposer has supplied enough inputs that the required funds for the proposer limit set in the DAO is met. Let the total funds $v = โ_{i โ ๐ข} i.v$, then check $d.L โค v$.
Total funds value commit โ $V = \t{PedersenCommit}(v, bแตฅ)$ where $V = โ{i โ ๐ข} i.V$. We use this to check that $v = โ{i โ ๐ข} i.v$ as claimed in the proposer limit threshold met check.
Input uniqueness โ the nullifiers $\cN$ must be unique within the call.
For each input $i โ ๐ข$, perform the following checks:
โ Let there be a prover auxiliary witness inputs: $$ \begin{aligned} xc &โ ๐ฝโ \ c &โ \t{Attrs}\t{Coin} \ bแตฅ &โ ๐ฝแตฅ \ b_ฯ &โ ๐ฝโ \ (ฯแตข, ฮ แตข) &โ \t{MerklePos} ร \t{MerklePath} \ (ฯ^N, ฮ ^N) &โ \t{MerklePos} ร \t{MerklePath} \ x_ฯ &โ ๐ฝโ \ \end{aligned} $$ โ Attach a proof $ฯ_i$ such that the following relations hold:
โ Nullifier integrity โ let $C = \t{Coin}(c)$ and $N = \t{PoseidonHash}(x_c, C)$, then $\cN = \t{PoseidonHash}(N, ๐ซ)$
โ Unspent at snapshot โ $R_\t{null} = \t{MerkleRoot}(ฯ^N, ฮ ^N, 0)$, i.e. an SMT non-membership proof of $N$ in the nullifier set snapshot.
โ Coin value commit โ $i.V = \t{PedersenCommit}(c.v, bแตฅ)$.
โ Token commit โ $T = \t{PoseidonHash}(c.ฯ, b_ฯ)$.
โ Valid coin โ Check $c.P = \t{DerivePubKey}(xc)$. Check $R\t{coin} = \t{MerkleRoot}(ฯแตข, ฮ แตข, C)$.
โ Proof of signature public key ownership โ $i.\t{PK}_ฯ = \t{DerivePubKey}(x_ฯ)$.
Snapshot creation โ once the proposal is accepted, the latest Money coin merkle root and nullifier SMT root are snapshotted alongside the proposal. Only coins in this snapshot are votable with (see Vote).
For each $i โ ๐ข$, attach a signature corresponding to the public key $i.\t{PK}_ฯ$.
After DAO::propose() is called, DAO members can then call this contract
function. Using a similar method as before, they attach inputs proving ownership
of a certain value of governance tokens. This is how we achieve token weighted
voting. The result of the vote is communicated to DAO members that can view votes
through the encrypted note $\t{note}$.
Each nullifier $๐ฉ$ is stored uniquely per proposal. Additionally as before,
there is a leakage here connecting the coins when spent. However prodigious
usage of Money::transfer() to wash the coins after calling DAO::vote()
should mitigate against this attack. In the future this can be fixed using
set non-membership primitives.
Another leakage is that the proposal bulla $๐ซ$ is public. To ensure every vote is discoverable by verifiers (who cannot decrypt values) and protect against 'nothing up my sleeve', we link them all together. This is so the final tally used for executing proposals is accurate.
The total sum of votes is represented by the commit $V\t{all} = โ{i โ ๐ข} i.V$ and the yes votes by $V_\t{yes}$.
src/contract/dao/src/client/vote.rssrc/contract/dao/src/entrypoint/vote.rssrc/contract/dao/proof/vote-main.zksrc/contract/dao/proof/vote-input.zkDefine the DAO vote function params $$ \begin{aligned} T &โ ๐ฝโ \ ๐ซ &โ \t{im}(\t{Bulla}\t{Proposal}) \ V\t{yes} &โ โโ \ \t{note} &โ \t{ElGamalEncNote}โ \ ๐ข &โ \t{VoteInput}^* \end{aligned} $$
Define the DAO vote-input function params $$ \begin{aligned} \t{VoteInput}.๐ฉ &โ ๐ฝโ \ \t{VoteInput}.V &โ โโ \ \t{VoteInput}.\t{PK}_ฯ &โ โโ \end{aligned} $$
Note: $\t{VoteInput}.V$ is a pedersen commitment, where the blinds are selected such that their sum is a valid field element in $๐ฝโ$ so the blind for $โ V$ can be verifiably encrypted. Likewise we do the same for the blind used to calculate $V_\t{yes}$.
This allows DAO members that hold the votes key to securely receive all secrets for votes on a proposal. This is then used in the Exec phase when we work on the sum of DAO votes.
{{#include ../../../../../src/contract/dao/src/model.rs:dao-vote-params}}
{{#include ../../../../../src/contract/dao/src/model.rs:dao-vote-params-input}}
Let $tโ = \t{BlockWindow} โ ๐ฝโ$ be the current blockwindow as defined in Blockwindow.
Let $R\t{coin}, R\t{null}$ be the Money state snapshot attached to the proposal when it was created.
Proposal bulla exists โ check $๐ซ$ exists in the DAO contract proposal bullas DB.
Let there be prover auxiliary witness inputs: $$ \begin{aligned} p &โ \t{Params}_\t{Proposal} \ bp &โ ๐ฝโ \ d &โ \t{Params}\t{DAO} \ b_d &โ ๐ฝโ \ o &โ ๐ฝโ \ b_y &โ ๐ฝโ \ v &โ ๐ฝโ \ bแตฅ &โ ๐ฝโ \ bฯ &โ ๐ฝโ \ t\t{now} &โ ๐ฝโ \ \t{esk} &โ ๐ฝโ \ \end{aligned} $$ Attach a proof $ฯ_\mathcal{V}$ such that the following relations hold:
Governance token commit โ export the DAO token ID as an encrypted commit $T = \t{PoseidonHash}(d.ฯ, b_ฯ)$, matching the token commit of every input.
DAO bulla integrity โ $๐ = \t{Bulla}_\t{DAO}(d, b_d)$
Proposal bulla integrity โ $๐ซ = \t{Bulla}_\t{Proposal}(p, b_p)$
Yes vote commit โ $V_\t{yes} = (o \cdot v)G_V + b_y H_B$
Total vote value commit โ $V_\t{all} = vG_V + bแตฅHB$ where
$V\t{all} = โ_{i โ ๐ข} i.V$ should also hold. Here $G_V$ is the
VALUE_COMMIT_VALUE generator, and the blinds $b_y, bแตฅ$ are base field
elements used with the VALUE_COMMIT_RANDOM_BASE generator $H_B$, so
they can be verifiably encrypted.
Vote option boolean โ enforce $o โ { 0, 1 }$.
Proposal not expired โ let $t\t{end} = โโโ2๐ฝโ(p.tโ) + โโโ2๐ฝโ(p.D)$, and then check $t\t{now} < t\t{end}$, where $t\t{now}$ is enforced to be the current blockwindow via a public input.
Verifiable encryption of vote commit secrets โ let $๐ง = (o, b_y, v, bแตฅ)$, and verify $\t{note} = \t{ElGamal}.\t{Encrypt}(๐ง, \t{esk}, d.\t{VPK})$.
For each input $i โ ๐ข$, perform the following checks:
โ Unused nullifier (proposal) โ check that $๐ฉ$ does not exist in the DAO contract nullifiers DB for this specific proposal (nullifiers are keyed by $(๐ซ, ๐ฉ)$), and is unique within the call.
โ Let there be a prover auxiliary witness inputs: $$ \begin{aligned} xc &โ ๐ฝโ \ c &โ \t{Attrs}\t{Coin} \ bแตฅ &โ ๐ฝแตฅ \ b_ฯ &โ ๐ฝโ \ (ฯแตข, ฮ แตข) &โ \t{MerklePos} ร \t{MerklePath} \ (ฯ^N, ฮ ^N) &โ \t{MerklePos} ร \t{MerklePath} \ x_ฯ &โ ๐ฝโ \ \end{aligned} $$ Attach a proof $ฯแตข$ such that the following relations hold:
โ Nullifier integrity โ let $C = \t{Coin}(c)$ and $N = \t{PoseidonHash}(x_c, C)$, then $๐ฉ = \t{PoseidonHash}(N, x_c, ๐ซ)$
โ Unspent at snapshot โ $R_\t{null} = \t{MerkleRoot}(ฯ^N, ฮ ^N, 0)$, i.e. an SMT non-membership proof of $N$ in the nullifier set snapshot, so only participants from before the proposal was posted can vote.
โ Coin value commit โ $i.V = \t{PedersenCommit}(c.v, bแตฅ)$.
โ Token commit โ $T = \t{PoseidonHash}(c.ฯ, b_ฯ)$.
โ Valid coin โ Check $c.P = \t{DerivePubKey}(xc)$. Check $R\t{coin} = \t{MerkleRoot}(ฯแตข, ฮ แตข, C)$, i.e. the coin existed in the proposal's snapshot of the coin tree.
โ Proof of signature public key ownership โ $i.\t{PK}_ฯ = \t{DerivePubKey}(x_ฯ)$.
Vote aggregation โ the state update adds $V_\t{yes}$ and $โ i.V$ to the proposal's aggregated vote commits ($\t{DaoBlindAggregateVote}$), and records the used vote nullifiers.
For each $i โ ๐ข$, attach a signature corresponding to the public key $i.\t{PK}_ฯ$.
Exec is the final stage after voting is Accepted.
It checks that voting has passed, and correct conditions have been met, in accordance with the DAO params such as quorum and approval ratio. $V\t{yes}$ and $V\t{all}$ are pedersen commits to $v\t{yes}$ and $v\t{all}$ respectively.
It also checks that child calls have been attached in accordance with the auth
calls set inside the proposal. One of these will usually be an auth module
function. Currently the DAO provides a single preset for executing
Money::transfer() calls so DAOs can manage anonymous treasuries.
The early_exec flag selects which proof statement is verified:
Exec for normal execution after expiry, or EarlyExec for strongly
supported proposals (see EarlyExec).
src/contract/dao/src/client/exec.rssrc/contract/dao/src/entrypoint/exec.rssrc/contract/dao/proof/exec.zksrc/contract/dao/proof/early-exec.zkLet $\t{AuthCall}, \t{Commit}_{\t{Auth}^*}$ be defined as in the section Auth Calls.
Define the DAO exec function params $$ \begin{aligned} ๐ซ &โ \t{im}(\t{Bulla}\t{Proposal}) \ ๐ &โ \t{AuthCall}^* \ V\t{yes} &โ โโ \ V_\t{all} &โ โโ \ \t{early} &โ โคโ \ \t{PK}_ฯ &โ โโ \end{aligned} $$
{{#include ../../../../../src/contract/dao/src/model.rs:dao-exec-params}}
{{#include ../../../../../src/contract/dao/src/model.rs:dao-blind-aggregate-vote}}
There are two phases to Exec. In the first we check the calling format of this transaction matches what is specified in the proposal. Then in the second phase, we verify the correct voting rules.
Auth call spec match โ denote the child calls of Exec by $C$. If $#C โ #๐$ then exit. Otherwise, for each $c โ C$ and $a โ ๐$, check the contract ID and function code of $c$ match $a$.
Aggregate votes lookup โ using the proposal bulla, fetch the aggregated votes from the DB and verify $V\t{yes}$ and $V\t{all}$ are set correctly.
Let there be prover auxiliary witness inputs: $$ \begin{aligned} p &โ \t{Params}_\t{Proposal} \ bp &โ ๐ฝโ \ d &โ \t{Params}\t{DAO} \ b_d &โ ๐ฝโ \ v_y &โ ๐ฝโ \ v_a &โ ๐ฝโ \ b_y &โ ๐ฝแตฅ \ ba &โ ๐ฝแตฅ \ t\t{now} &โ ๐ฝโ \ x_ฯ &โ ๐ฝโ \end{aligned} $$ Attach a proof $ฯ$ such that the following relations hold:
Proof of executor public key ownership โ $\t{EPK} = \t{DerivePubKey}(Ex)$.
DAO bulla integrity โ $๐ = \t{Bulla}_\t{DAO}(d, b_d)$
Proposal bulla integrity โ $๐ซ = \t{Bulla}_\t{Proposal}(p, bp)$ where $\t{Commit}{\t{Auth}^}(p.C) = \t{Commit}_{\t{Auth}^}(๐)$ is enforced as a public input.
Proposal has expired โ let $t\t{end} = โโโ2๐ฝโ(p.tโ) + โโโ2๐ฝโ(p.D)$, and then check $t\t{end} โค t\t{now}$, where $t\t{now}$ is enforced to be the current blockwindow via a public input.
Yes vote commit โ $V_\t{yes} = \t{PedersenCommit}(v_y, b_y)$
All vote commit โ $V_\t{all} = \t{PedersenCommit}(v_a, b_a)$
All votes pass quorum โ $Q โค v_a$
Approval ratio satisfied โ we wish to check that $\frac{A_q}{A_b} โค \frac{v_y}{v_a}$. Instead we perform the equivalent check that $v_a A_q โค v_y A_b$.
Proposal removal โ the state update removes the proposal from the DB so it cannot be executed twice.
This is a special case of Exec for when we want to execute a strongly accepted proposal before voting period has passed. A different proof statement is used in this case.
Let there be prover auxiliary witness inputs: $$ \begin{aligned} p &โ \t{Params}_\t{Proposal} \ bp &โ ๐ฝโ \ d &โ \t{Params}\t{DAO} \ b_d &โ ๐ฝโ \ v_y &โ ๐ฝโ \ v_a &โ ๐ฝโ \ b_y &โ ๐ฝแตฅ \ ba &โ ๐ฝแตฅ \ t\t{now} &โ ๐ฝโ \ x_ฯ &โ ๐ฝโ \end{aligned} $$ Attach a proof $ฯ$ such that the following relations hold:
Proof of executor public key ownership โ $\t{EPK} = \t{DerivePubKey}(Ex)$.
Proof of early executor public key ownership โ $\t{EEPK} = \t{DerivePubKey}(EEx)$.
DAO bulla integrity โ $๐ = \t{Bulla}_\t{DAO}(d, b_d)$
Proposal bulla integrity โ $๐ซ = \t{Bulla}_\t{Proposal}(p, bp)$ where $\t{Commit}{\t{Auth}^}(p.C) = \t{Commit}_{\t{Auth}^}(๐)$ is enforced as a public input.
Proposal has not expired โ let $t\t{end} = โโโ2๐ฝโ(p.tโ) + โโโ2๐ฝโ(p.D)$, and then check $t\t{now} < t\t{end}$, where $t\t{now}$ is enforced to be the current blockwindow via a public input.
Yes vote commit โ $V_\t{yes} = \t{PedersenCommit}(v_y, b_y)$
All vote commit โ $V_\t{all} = \t{PedersenCommit}(v_a, b_a)$
All votes pass early execution quorum โ $EEQ โค v_a$
Approval ratio satisfied โ we wish to check that $\frac{A_q}{A_b} โค \frac{v_y}{v_a}$. Instead we perform the equivalent check that $v_a A_q โค v_y A_b$.
A single signature is attached, using $\t{PK}_ฯ$ as the signature public
key. The signature binds the DAO::exec() call to the transaction so it
cannot be combined with other calls.
This is a child call for Exec which can be used for DAO treasuries.
It checks the next sibling call is Money::transfer() and accordingly
verifies the first $n - 1$ output coins match the data set in this
call's auth data.
Additionally we provide verifiably encrypted notes for the coins, to
mitigate the attack where Exec is called, but the supplied
Money::transfer() call contains an invalid note which cannot be
decrypted by the receiver. In this case, the money would still leave the
DAO treasury but be unspendable.
src/contract/dao/src/client/auth_xfer.rssrc/contract/dao/src/entrypoint/auth_xfer.rssrc/contract/dao/proof/auth-money-transfer.zksrc/contract/dao/proof/auth-money-transfer-enc-coin.zkDefine the DAO AuthMoneyTransfer function params $$ \begin{aligned} ๐\t{enc} &โ \t{ElGamalEncNote}โ ^* \ ๐\t{enc} &โ \t{ElGamalEncNote}โ \end{aligned} $$
This provides verifiable note encryption for all output coins in the sibling Money::transfer() call as well as the DAO change coin.
{{#include ../../../../../src/contract/dao/src/model.rs:dao-auth_xfer-params}}
Denote the DAO function ID of Dao::Exec by $\t{FID}_\t{Exec} โ ๐ฝโ$.
Sibling call is Money::transfer() โ load the immediate next
sibling call and check the contract ID and function code match
Money::transfer().
Money originates from the same DAO โ check all the input's user_data
for the sibling Money::transfer() encode the same DAO. We do this by using the
same blind for all user_data. Denote this value by $\t{UD}_\t{enc}$.
Output coins match proposal โ check there are $n + 1$ output coins,
with the first $n$ coins exactly matching those set in this call's auth
data in the parent DAO::exec() call. The auth data is decoded as a
list of $n$ coins.
Let there be a prover auxiliary witness inputs: $$ \begin{aligned} p &โ \t{Params}_\t{Proposal} \ bp &โ ๐ฝโ \ d &โ \t{Params}\t{DAO} \ bd &โ ๐ฝโ \ b\t{UD} &โ ๐ฝโ \ v\t{DAO} &โ ๐ฝโ \ ฯ\t{DAO} &โ ๐ฝโ \ b_\t{DAO} &โ ๐ฝโ \ \t{esk} &โ ๐ฝโ \ \end{aligned} $$
Attach a proof $ฯ_\t{auth}$ such that the following relations hold:
DAO bulla integrity โ $๐ = \t{Bulla}_\t{DAO}(d, b_d)$
Proposal bulla integrity โ $๐ซ = \t{Bulla}_\t{Proposal}(p, bp)$
where $๐ซ$ matches the value in DAO::exec(), and
$\t{Commit}{\t{Auth}^*}(p.C)$ is enforced as a public input.
Input user data commits to DAO bulla โ $\t{UD}\t{enc} = \t{PoseidonHash}(๐, b\t{UD})$
DAO change coin integrity โ denote the last coin in the
Money::transfer() outputs by $C\t{DAO}$. Then check
$$ C\t{DAO} = \t{Coin}(d.\t{NPK}, v\t{DAO}, ฯ\t{DAO},
\t{FID}_\t{Exec}, ๐, b_\t{DAO}) $$
i.e. the change is sent back to the DAO's notes public key, locked to
Dao::Exec via the spend hook, with the DAO bulla as user data. The
spend hook $\t{FID}_\t{Exec}$ is additionally enforced as a public input.
Verifiable DAO change coin note encryption โ let $๐ง = (v\t{DAO}, ฯ\t{DAO}, b\t{DAO})$, and verify $๐\t{enc} = \t{ElGamal}.\t{Encrypt}(๐ง, \t{esk}, d.\t{NPK})$.
Then we do the same for each output coin of Money::transfer().
For $k โ [n+1]$, let $a = (๐\t{enc})โ$ and $C$ be the $k$th output coin from
Money::transfer().
Let there be a prover auxiliary witness inputs:
$$ \begin{aligned}
c &โ \t{Attrs}\t{Coin} \
\end{aligned} $$
Attach a proof $ฯโ$ (reusing the same $\t{esk}$) such that the following
relations hold:
โ Coin integrity โ $C = \t{Coin}(c)$
โ Verifiable output coin note encryption โ let $๐ง = (c.v, c.ฯ, c.\t{SH}, c.\t{UD}, c.b)$, and verify $a = \t{ElGamal}.\t{Encrypt}(๐ง, \t{esk}, c.\t{PK})$, i.e. the coin secrets are encrypted to the coin's own recipient public key.
No signatures are attached.