Parcourir la source

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

zero il y a 2 ans
Parent
commit
111c803085

+ 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)]