Просмотр исходного кода

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

zero 2 лет назад
Родитель
Сommit
9257e01e35

+ 1 - 0
doc/src/SUMMARY.md

@@ -82,6 +82,7 @@
   - [DAO](spec/contracts/dao/dao.md)
   - [DAO](spec/contracts/dao/dao.md)
     - [Concepts](spec/contracts/dao/concepts.md)
     - [Concepts](spec/contracts/dao/concepts.md)
     - [Model](spec/contracts/dao/model.md)
     - [Model](spec/contracts/dao/model.md)
+    - [Contract](spec/contracts/dao/contract.md)
 
 
 # P2P API Tutorial
 # 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.
 threshold they are finalized, then the proposal can be executed.
 
 
 - [Concepts](concepts.md)
 - [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}.L &∈ ℕ₆₄ \\
   \t{Params}_\t{DAO}.Q &∈ ℕ₆₄ \\
   \t{Params}_\t{DAO}.Q &∈ ℕ₆₄ \\
   \t{Params}_\t{DAO}.A^\% &∈ ℕ₆₄ × ℕ₆₄ \\
   \t{Params}_\t{DAO}.A^\% &∈ ℕ₆₄ × ℕ₆₄ \\
-  \t{Params}_\t{DAO}.T &∈ 𝔽ₚ \\
+  \t{Params}_\t{DAO}.τ &∈ 𝔽ₚ \\
   \t{Params}_\t{DAO}.PK &∈ ℙₚ
   \t{Params}_\t{DAO}.PK &∈ ℙₚ
 \end{aligned} $$
 \end{aligned} $$
 where the approval ratio $\t{Approval}^\% = (q, d)$ defines the equivalence
 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}}
 {{#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
 ## Proposals
 
 
@@ -62,7 +62,7 @@ which commits to a `Vec<DaoAuthCall>`.
 Define the proposal params
 Define the proposal params
 $$ \begin{aligned}
 $$ \begin{aligned}
   \t{Params}_\t{Proposal}.C &∈ \t{AuthCall}^* \\
   \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}.D &∈ ℕ₆₄ \\
   \t{Params}_\t{Proposal}.φ &∈ 𝔽ₚ \\
   \t{Params}_\t{Proposal}.φ &∈ 𝔽ₚ \\
   \t{Params}_\t{Proposal}.\t{DAO} &∈ \t{Bulla}(\t{DAO2𝔽ₚ}(\t{Params}_\t{DAO})) \\
   \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} : \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
 ## Vote Nullifiers
 
 
 Additionally for proposals, we keep track of nullifiers for each token weighted
 Additionally for proposals, we keep track of nullifiers for each token weighted
 vote for or against a proposal.
 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
 Let $\mathcal{C}$ be the coin params, and $C$ be the coin commitment
 as defined in [Money Contract](TODO).
 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
 Let $\textrm{Params} ∈ 𝔽ₚⁿ$ represent object parameters, then we can define
 $$ \textrm{Bulla} : 𝔽ₚⁿ × 𝔽ₚ → 𝔽ₚ $$
 $$ \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
 Then the bulla (on chain anonymized representation) can be used in contracts
 with ZK proofs to construct statements on $\textrm{Params}$.
 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.
 $𝔹$ denotes a single byte $[0, 2⁸)$ corresponding to `u8` in Rust.
 We use $𝔹^*$ for an arbitrary sequence of bytes.
 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 = ec_mul_base(secret, NULLIFIER_K);
     pub_x = ec_get_x(pub);
     pub_x = ec_get_x(pub);
     pub_y = ec_get_y(pub);
     pub_y = ec_get_y(pub);
-    C = poseidon_hash(
+    coin = poseidon_hash(
         pub_x,
         pub_x,
         pub_y,
         pub_y,
         value,
         value,
@@ -50,8 +50,12 @@ circuit "DaoProposeInput" {
         user_data,
         user_data,
     );
     );
 
 
+    # BUG: doesn't check if coin was spent.
+    # we need to fix this.
+    # ideas???
+
     # Merkle root
     # Merkle root
-    root = merkle_root(leaf_pos, path, C);
+    root = merkle_root(leaf_pos, path, coin);
     constrain_instance(root);
     constrain_instance(root);
 
 
     # Finally we derive a public key for the signature and constrain
     # 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())
         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 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 {
     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");
         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::fp_to_bs58!(DaoProposalBulla);
 darkfi_sdk::ty_from_fp!(DaoProposalBulla);
 darkfi_sdk::ty_from_fp!(DaoProposalBulla);
 
 
-/// Parameters for `Dao::Mint`
 #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
 #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
+// ANCHOR: dao-mint-params
+/// Parameters for `Dao::Mint`
 pub struct DaoMintParams {
 pub struct DaoMintParams {
     /// The DAO bulla
     /// The DAO bulla
     pub dao_bulla: DaoBulla,
     pub dao_bulla: DaoBulla,
     /// The DAO public key
     /// The DAO public key
     pub dao_pubkey: PublicKey,
     pub dao_pubkey: PublicKey,
 }
 }
+// ANCHOR_END: dao-mint-params
 
 
 /// State update for `Dao::Mint`
 /// State update for `Dao::Mint`
 #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
 #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
@@ -217,8 +219,9 @@ pub struct DaoMintUpdate {
     pub dao_bulla: DaoBulla,
     pub dao_bulla: DaoBulla,
 }
 }
 
 
-/// Parameters for `Dao::Propose`
 #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
 #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
+// ANCHOR: dao-propose-params
+/// Parameters for `Dao::Propose`
 pub struct DaoProposeParams {
 pub struct DaoProposeParams {
     /// Merkle root of the DAO in the DAO state
     /// Merkle root of the DAO in the DAO state
     pub dao_merkle_root: MerkleNode,
     pub dao_merkle_root: MerkleNode,
@@ -231,9 +234,11 @@ pub struct DaoProposeParams {
     /// Inputs for the proposal
     /// Inputs for the proposal
     pub inputs: Vec<DaoProposeParamsInput>,
     pub inputs: Vec<DaoProposeParamsInput>,
 }
 }
+// ANCHOR_END: dao-propose-params
 
 
-/// Input for a DAO proposal
 #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
 #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
+// ANCHOR: dao-propose-input-params
+/// Input for a DAO proposal
 pub struct DaoProposeParamsInput {
 pub struct DaoProposeParamsInput {
     /// Value commitment for the input
     /// Value commitment for the input
     pub value_commit: pallas::Point,
     pub value_commit: pallas::Point,
@@ -242,6 +247,7 @@ pub struct DaoProposeParamsInput {
     /// Public key used for signing
     /// Public key used for signing
     pub signature_public: PublicKey,
     pub signature_public: PublicKey,
 }
 }
+// ANCHOR_END: dao-propose-input-params
 
 
 /// State update for `Dao::Propose`
 /// State update for `Dao::Propose`
 #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
 #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]