Browse Source

spec: DAO::mint() and DAO::propose()

zero 2 years ago
parent
commit
9257e01e35

+ 1 - 0
doc/src/SUMMARY.md

@@ -82,6 +82,7 @@
   - [DAO](spec/contracts/dao/dao.md)
     - [Concepts](spec/contracts/dao/concepts.md)
     - [Model](spec/contracts/dao/model.md)
+    - [Contract](spec/contracts/dao/contract.md)
 
 # P2P API Tutorial
 

+ 153 - 0
doc/src/spec/contracts/dao/contract.md

@@ -0,0 +1,153 @@
+# Contract
+
+<!-- toc -->
+
+Let $\t{PoseidonHash}$ be defined as in the section [PoseidonHash Function](../../crypto-schemes.md#poseidonhash-function).
+
+Let $โ„™โ‚š$ be defined as in the section [Pallas and Vesta](../../crypto-schemes.md#pallas-and-vesta).
+
+Let $\t{Params}_\t{DAO}, \t{Bulla}_\t{DAO}, \t{Params}_\t{Proposal}, \t{Bulla}_\t{Proposal}$ be defined as in [DAO Model](model.md).
+
+TODO: add derivepubkey fn
+
+TODO: add merkle section to crypto-schemes with merklepos, merklepath,
+MerkleRoot
+
+TODO: add pedersencommit
+
+TODO: need params coin
+
+TODO: document current day = $๐”ฝโ‚š$ CurrentDay
+
+## Mint
+
+### Function Params
+
+Define the DAO mint function params
+$$ \begin{aligned}
+  โ„ฌ  &โˆˆ \t{im}(\t{Bulla}_\t{DAO}) \\
+  \t{PK} &โˆˆ โ„™โ‚š
+\end{aligned} $$
+
+```rust
+{{#include ../../../../../src/contract/dao/src/model.rs:dao-mint-params}}
+```
+
+### Contract Statement
+
+**DAO bulla uniqueness** &emsp; whether $โ„ฌ $ already exists. If yes then fail.
+
+Let there be a prover auxiliary witness inputs:
+$$ \begin{aligned}
+  \t{Params}_\t{DAO}.L &โˆˆ โ„•โ‚†โ‚„ \\
+  \t{Params}_\t{DAO}.Q &โˆˆ โ„•โ‚†โ‚„ \\
+  \t{Params}_\t{DAO}.A^\% &โˆˆ โ„•โ‚†โ‚„ ร— โ„•โ‚†โ‚„ \\
+  \t{Params}_\t{DAO}.T &โˆˆ ๐”ฝโ‚š \\
+  x &โˆˆ ๐”ฝโ‚š \\
+  b_\t{DAO} &โˆˆ ๐”ฝโ‚š
+\end{aligned} $$
+
+Attach a proof $ฯ€ = \{ ๐ฏ, ๐ฑ : R(๐ฏ, ๐ฑ) = 1 \}$ such that the
+following relations hold:
+
+**Proof of public key ownership** &emsp; $\t{PK} = \t{DerivePubKey}(x)$.
+
+**DAO bulla integrity** &emsp; $โ„ฌ  = \t{Bulla}_\t{DAO}(\t{Params}_\t{DAO}, b_\t{DAO})$
+
+### Signatures
+
+There should be a single signature attached, which uses
+$\t{PK}$ as the signature public key.
+
+## Propose
+
+### Function Params
+
+Define the DAO propose function params
+$$ \begin{aligned}
+  R_\t{DAO} &โˆˆ ๐”ฝโ‚š \\
+  T &โˆˆ ๐”ฝโ‚š \\
+  ๐’ซ &โˆˆ \t{im}(\t{Bulla}_\t{Proposal}) \\
+  \t{EncNote} &โˆˆ โŸ‚ \\
+  ๐ข &โˆˆ \t{ProposeInput}^*
+\end{aligned} $$
+
+Define the DAO propose input function params
+$$ \begin{aligned}
+  \t{ProposeInput}.V &โˆˆ โ„™โ‚š \\
+  \t{ProposeInput}.R_\t{coin} &โˆˆ ๐”ฝโ‚š \\
+  \t{ProposeInput}.\t{PK}_ฯƒ &โˆˆ โ„™โ‚š
+\end{aligned} $$
+
+```rust
+{{#include ../../../../../src/contract/dao/src/model.rs:dao-propose-params}}
+```
+
+```rust
+{{#include ../../../../../src/contract/dao/src/model.rs:dao-propose-input-params}}
+```
+
+### Contract Statement
+
+Let $tโ‚€ = \t{CurrentDay} โˆˆ ๐”ฝโ‚š$ be the current day.
+
+**Valid DAO bulla merkle root** &emsp; check that $R_\t{DAO}$ is a previously
+seen merkle root in the DAO contract merkle roots DB.
+
+**Proposal bulla uniqueness** &emsp; whether $๐’ซ $ already exists. If yes then fail.
+
+Let there be a prover auxiliary witness inputs:
+$$ \begin{aligned}
+  v &โˆˆ ๐”ฝโ‚š \\
+  bแตฅ &โˆˆ ๐”ฝแตฅ \\
+  b_ฯ„ &โˆˆ ๐”ฝโ‚š \\
+  p &โˆˆ \t{Params}_\t{Proposal} \\
+  p_d &โˆˆ ๐”ฝโ‚š \\
+  d &โˆˆ \t{Params}_\t{DAO} \\
+  b_d &โˆˆ ๐”ฝโ‚š \\
+  (ฯˆ, ฮ ) &โˆˆ \t{MerklePos} ร— \t{MerklePath} \\
+\end{aligned} $$
+Attach a proof $ฯ€_\t{๐’ซ }$ such that the following relations hold:
+
+**Governance token commit** &emsp; export the DAO token ID as an encrypted pedersen
+commit $T = \t{PedersenCommit}(d.ฯ„, d.b_ฯ„)$ where $T = โˆ‘_{i โˆˆ ๐ข} Tแตข$.
+
+**DAO bulla integrity** &emsp; $โ„ฌ  = \t{Bulla}_\t{DAO}(d, b_d)$
+
+**DAO existence** &emsp; $R_\t{DAO} = \t{MerkleRoot}(ฯˆ, ฮ , โ„ฌ )$
+
+**Proposal bulla integrity** &emsp; $๐’ซ = \t{Bulla}_\t{Proposal}(p, p_d)$
+where $p.tโ‚€ = tโ‚€$.
+
+**Proposer limit threshold met** &emsp; 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** &emsp; $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.
+
+For each input $i โˆˆ ๐ข$,
+
+&emsp; **Valid input coins merkle root** &emsp; check that $i.R_\t{coin}$ is a
+previously seen merkle root in the money contract merkle roots DB.
+
+&emsp; Let there be a prover auxiliary witness inputs:
+$$ \begin{aligned}
+  x_ฯƒ &โˆˆ ๐”ฝโ‚š \\
+  c &โˆˆ \t{Params}_\t{Coin} \\
+  bแตฅ &โˆˆ ๐”ฝแตฅ \\
+  b_ฯ„ &โˆˆ ๐”ฝโ‚š \\
+  (ฯˆแตข, ฮ แตข) &โˆˆ \t{MerklePos} ร— \t{MerklePath} \\
+\end{aligned} $$
+&emsp; Attach a proof $ฯ€_i$ such that the following relations hold:
+
+&emsp; **Coin value commit** &emsp; $i.V = \t{PedersenCommit}(c.v, bแตฅ)$.
+
+&emsp; **Token commit** &emsp; $T = \t{PoseidonHash}(c.ฯ„, b_ฯ„)$.
+
+&emsp; **Valid coin** &emsp; let $C = \t{Commit}(c)$. Check
+$i.R_\t{coin} = \t{MerkleRoot}(ฯˆแตข, ฮ แตข, C)$.
+
+&emsp; **Proof of signature public key ownership** &emsp; $i.\t{PK}_ฯƒ = \t{DerivePubKey}(x_ฯƒ)$.
+

+ 2 - 1
doc/src/spec/contracts/dao/dao.md

@@ -8,5 +8,6 @@ make proposals which are then voted on. When proposals pass a specified
 threshold they are finalized, then the proposal can be executed.
 
 - [Concepts](concepts.md)
-- [State](state.md)
+- [Model](model.md)
+- [Contract](contract.md)
 

+ 7 - 5
doc/src/spec/contracts/dao/model.md

@@ -25,7 +25,7 @@ $$ \begin{aligned}
   \t{Params}_\t{DAO}.L &โˆˆ โ„•โ‚†โ‚„ \\
   \t{Params}_\t{DAO}.Q &โˆˆ โ„•โ‚†โ‚„ \\
   \t{Params}_\t{DAO}.A^\% &โˆˆ โ„•โ‚†โ‚„ ร— โ„•โ‚†โ‚„ \\
-  \t{Params}_\t{DAO}.T &โˆˆ ๐”ฝโ‚š \\
+  \t{Params}_\t{DAO}.ฯ„ &โˆˆ ๐”ฝโ‚š \\
   \t{Params}_\t{DAO}.PK &โˆˆ โ„™โ‚š
 \end{aligned} $$
 where the approval ratio $\t{Approval}^\% = (q, d)$ defines the equivalence
@@ -35,8 +35,8 @@ class $[\frac{q}{d}]$ of fractions defined by $qโ‚dโ‚‚ = qโ‚‚dโ‚ โŸบ  [\frac{q
 {{#include ../../../../../src/contract/dao/src/model.rs:dao}}
 ```
 
-$$ \t{Bulla}_\t{DAO} : \t{Params}_\t{DAO} โ†’ ๐”ฝโ‚š $$
-$$ \t{Bulla}_\t{DAO}(p) = \t{Bulla}(โ„•โ‚†โ‚„2๐”ฝโ‚š(p.L), โ„•โ‚†โ‚„2๐”ฝโ‚š(p.Q), โ„•โ‚†โ‚„2๐”ฝโ‚š(p.A^\%), p.T, \mathcal{X}(p.PK), \mathcal{Y}(p.PK)) $$
+$$ \t{Bulla}_\t{DAO} : \t{Params}_\t{DAO} ร— ๐”ฝโ‚š โ†’ ๐”ฝโ‚š $$
+$$ \t{Bulla}_\t{DAO}(p, b_\t{DAO}) = \t{Bulla}(โ„•โ‚†โ‚„2๐”ฝโ‚š(p.L), โ„•โ‚†โ‚„2๐”ฝโ‚š(p.Q), โ„•โ‚†โ‚„2๐”ฝโ‚š(p.A^\%), p.ฯ„, \mathcal{X}(p.PK), \mathcal{Y}(p.PK), b_\t{DAO}) $$
 
 ## Proposals
 
@@ -62,7 +62,7 @@ which commits to a `Vec<DaoAuthCall>`.
 Define the proposal params
 $$ \begin{aligned}
   \t{Params}_\t{Proposal}.C &โˆˆ \t{AuthCall}^* \\
-  \t{Params}_\t{Proposal}.Tโ‚€ &โˆˆ โ„•โ‚†โ‚„ \\
+  \t{Params}_\t{Proposal}.tโ‚€ &โˆˆ โ„•โ‚†โ‚„ \\
   \t{Params}_\t{Proposal}.D &โˆˆ โ„•โ‚†โ‚„ \\
   \t{Params}_\t{Proposal}.ฯ† &โˆˆ ๐”ฝโ‚š \\
   \t{Params}_\t{Proposal}.\t{DAO} &โˆˆ \t{Bulla}(\t{DAO2๐”ฝโ‚š}(\t{Params}_\t{DAO})) \\
@@ -73,13 +73,15 @@ $$ \begin{aligned}
 ```
 
 $$ \t{Bulla}_\t{Proposal} : \t{Params}_\t{Proposal} โ†’ ๐”ฝโ‚šโต $$
-$$ \t{Bulla}_\t{Proposal}(p) = (\t{Commit}_{\t{Auth}^*}(p.C), โ„•โ‚†โ‚„2๐”ฝโ‚š(p.Tโ‚€), โ„•โ‚†โ‚„2๐”ฝโ‚š(p.D), p.ฯ†, p.\t{DAO}) $$
+$$ \t{Bulla}_\t{Proposal}(p) = (\t{Commit}_{\t{Auth}^*}(p.C), โ„•โ‚†โ‚„2๐”ฝโ‚š(p.tโ‚€), โ„•โ‚†โ‚„2๐”ฝโ‚š(p.D), p.ฯ†, p.\t{DAO}) $$
 
 ## Vote Nullifiers
 
 Additionally for proposals, we keep track of nullifiers for each token weighted
 vote for or against a proposal.
 
+Let $\t{PoseidonHash}$ be defined as in the section [PoseidonHash Function](../../crypto-schemes.md#poseidonhash-function).
+
 Let $\mathcal{C}$ be the coin params, and $C$ be the coin commitment
 as defined in [Money Contract](TODO).
 

+ 2 - 2
doc/src/spec/crypto-schemes.md

@@ -24,8 +24,8 @@ representations which we call bullas.
 
 Let $\textrm{Params} โˆˆ ๐”ฝโ‚šโฟ$ represent object parameters, then we can define
 $$ \textrm{Bulla} : ๐”ฝโ‚šโฟ ร— ๐”ฝโ‚š โ†’ ๐”ฝโ‚š $$
-$$ \textrm{Bulla}(\textrm{Params}, r) = \textrm{PoseidonHash}(\textrm{Params}, r) $$
-where $r โˆˆ ๐”ฝโ‚š$ is a random blinding factor.
+$$ \textrm{Bulla}(\textrm{Params}, b) = \textrm{PoseidonHash}(\textrm{Params}, b) $$
+where $b โˆˆ ๐”ฝโ‚š$ is a random blinding factor.
 
 Then the bulla (on chain anonymized representation) can be used in contracts
 with ZK proofs to construct statements on $\textrm{Params}$.

+ 2 - 0
doc/src/spec/notation.md

@@ -6,3 +6,5 @@ corresponding to `u64` in Rust of $[0, 2โถโด)$.
 $๐”น$ denotes a single byte $[0, 2โธ)$ corresponding to `u8` in Rust.
 We use $๐”น^*$ for an arbitrary sequence of bytes.
 
+$\t{im}(f)$ denotes the image of a function $f$.
+

+ 6 - 2
src/contract/dao/proof/dao-propose-burn.zk

@@ -40,7 +40,7 @@ circuit "DaoProposeInput" {
     pub = ec_mul_base(secret, NULLIFIER_K);
     pub_x = ec_get_x(pub);
     pub_y = ec_get_y(pub);
-    C = poseidon_hash(
+    coin = poseidon_hash(
         pub_x,
         pub_y,
         value,
@@ -50,8 +50,12 @@ circuit "DaoProposeInput" {
         user_data,
     );
 
+    # BUG: doesn't check if coin was spent.
+    # we need to fix this.
+    # ideas???
+
     # Merkle root
-    root = merkle_root(leaf_pos, path, C);
+    root = merkle_root(leaf_pos, path, coin);
     constrain_instance(root);
 
     # Finally we derive a public key for the signature and constrain

+ 1 - 1
src/contract/dao/src/entrypoint/propose.rs

@@ -136,7 +136,7 @@ pub(crate) fn dao_propose_process_instruction(
         return Err(DaoError::ProposalAlreadyExists.into())
     }
 
-    // Snapshot the latest Money Mekrle tree
+    // Snapshot the latest Money merkle tree
     let money_info_db = db_lookup(*MONEY_CONTRACT_ID, MONEY_CONTRACT_INFO_TREE)?;
     let Some(data) = db_get(money_info_db, MONEY_CONTRACT_LATEST_COIN_ROOT)? else {
         msg!("[Dao::Propose] Error: Failed to fetch latest Money Merkle root");

+ 9 - 3
src/contract/dao/src/model.rs

@@ -201,14 +201,16 @@ darkfi_sdk::fp_from_bs58!(DaoProposalBulla);
 darkfi_sdk::fp_to_bs58!(DaoProposalBulla);
 darkfi_sdk::ty_from_fp!(DaoProposalBulla);
 
-/// Parameters for `Dao::Mint`
 #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
+// ANCHOR: dao-mint-params
+/// Parameters for `Dao::Mint`
 pub struct DaoMintParams {
     /// The DAO bulla
     pub dao_bulla: DaoBulla,
     /// The DAO public key
     pub dao_pubkey: PublicKey,
 }
+// ANCHOR_END: dao-mint-params
 
 /// State update for `Dao::Mint`
 #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
@@ -217,8 +219,9 @@ pub struct DaoMintUpdate {
     pub dao_bulla: DaoBulla,
 }
 
-/// Parameters for `Dao::Propose`
 #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
+// ANCHOR: dao-propose-params
+/// Parameters for `Dao::Propose`
 pub struct DaoProposeParams {
     /// Merkle root of the DAO in the DAO state
     pub dao_merkle_root: MerkleNode,
@@ -231,9 +234,11 @@ pub struct DaoProposeParams {
     /// Inputs for the proposal
     pub inputs: Vec<DaoProposeParamsInput>,
 }
+// ANCHOR_END: dao-propose-params
 
-/// Input for a DAO proposal
 #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
+// ANCHOR: dao-propose-input-params
+/// Input for a DAO proposal
 pub struct DaoProposeParamsInput {
     /// Value commitment for the input
     pub value_commit: pallas::Point,
@@ -242,6 +247,7 @@ pub struct DaoProposeParamsInput {
     /// Public key used for signing
     pub signature_public: PublicKey,
 }
+// ANCHOR_END: dao-propose-input-params
 
 /// State update for `Dao::Propose`
 #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]