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

contract/consensus: use vrf proof for eta calculation

aggstam 3 лет назад
Родитель
Сommit
8630082855

+ 1 - 0
Cargo.lock

@@ -1235,6 +1235,7 @@ name = "darkfi-consensus-contract"
 version = "0.4.1"
 dependencies = [
  "async-std",
+ "blake3",
  "bs58",
  "chacha20poly1305",
  "darkfi",

+ 2 - 0
src/consensus/state.rs

@@ -669,6 +669,8 @@ pub struct SlotCheckpoint {
     /// Slot UID
     pub slot: u64,
     /// Slot eta
+    // TODO: this should be renamed to previous_eta,
+    //       corresponding to previous block eta.
     pub eta: pallas::Base,
     /// Slot sigma1
     pub sigma1: pallas::Base,

+ 1 - 0
src/contract/consensus/Cargo.toml

@@ -9,6 +9,7 @@ edition = "2021"
 crate-type = ["cdylib", "rlib"]
 
 [dependencies]
+blake3 = "1.3.3"
 darkfi-sdk = { path = "../../sdk" }
 darkfi-serial = { path = "../../serial", features = ["derive", "crypto"] }
 darkfi-money-contract = { path = "../money", features = ["no-entrypoint"] }

+ 1 - 1
src/contract/consensus/proof/proposal_reward_v1.zk

@@ -85,7 +85,7 @@ circuit "ProposalReward_V1" {
 	constrain_instance(rho);
 
 	# Calculate lottery target
-	term_1 =  base_mul(sigma1, value);
+	term_1 = base_mul(sigma1, value);
 	term_2 = base_mul(sigma2, value);
 	shifted_term_2 = base_mul(term_2, value);
 	target = base_add(term_1, shifted_term_2);

+ 12 - 4
src/contract/consensus/src/client/proposal_v1.rs

@@ -30,12 +30,12 @@ use darkfi_money_contract::{
 };
 use darkfi_sdk::{
     crypto::{
-        note::AeadEncryptedNote, pasta_prelude::*, pedersen_commitment_base,
+        ecvrf::VrfProof, note::AeadEncryptedNote, pasta_prelude::*, pedersen_commitment_base,
         pedersen_commitment_u64, poseidon_hash, Coin, MerkleTree, Nullifier, PublicKey, SecretKey,
         CONSENSUS_CONTRACT_ID, DARK_TOKEN_ID,
     },
     incrementalmerkletree::Tree,
-    pasta::pallas,
+    pasta::{group::ff::FromUniformBytes, pallas},
 };
 use log::{debug, info};
 use rand::rngs::OsRng;
@@ -68,6 +68,7 @@ pub struct ConsensusProposalRewardRevealed {
     pub value_commit: pallas::Point,
     pub new_serial_commit: pallas::Point,
     pub new_value_commit: pallas::Point,
+    pub vrf_proof: VrfProof,
     pub mu_y: pallas::Base,
     pub y: pallas::Base,
     pub mu_rho: pallas::Base,
@@ -299,6 +300,7 @@ impl ConsensusProposalCallBuilder {
         let burnt_public_key = public_inputs.public_key;
         let new_serial_commit = serial_commit;
         let slot = self.slot_checkpoint.slot;
+        let vrf_proof = public_inputs.vrf_proof;
         let y = public_inputs.y;
         let rho = public_inputs.rho;
         let reward_params = ConsensusProposalRewardParamsV1 {
@@ -308,6 +310,7 @@ impl ConsensusProposalCallBuilder {
             output,
             new_serial_commit,
             slot,
+            vrf_proof,
             y,
             rho,
         };
@@ -347,9 +350,13 @@ pub fn create_proposal_reward_proof(
     let new_value_commit = pedersen_commitment_u64(value + REWARD, value_blind);
     let slot_pallas = pallas::Base::from(slot_checkpoint.slot);
     let seed = poseidon_hash([SEED_PREFIX, serial, ZERO]);
-    let mu_y = poseidon_hash([MU_Y_PREFIX, slot_checkpoint.eta, slot_pallas]);
+    let vrf_proof = VrfProof::prove(secret_key.into(), &slot_checkpoint.eta.to_repr(), &mut OsRng);
+    let mut eta = [0u8; 64];
+    eta[..blake3::OUT_LEN].copy_from_slice(vrf_proof.hash_output().as_bytes());
+    let eta = pallas::Base::from_uniform_bytes(&eta);
+    let mu_y = poseidon_hash([MU_Y_PREFIX, eta, slot_pallas]);
     let y = poseidon_hash([seed, mu_y]);
-    let mu_rho = poseidon_hash([MU_RHO_PREFIX, slot_checkpoint.eta, slot_pallas]);
+    let mu_rho = poseidon_hash([MU_RHO_PREFIX, eta, slot_pallas]);
     let rho = poseidon_hash([seed, mu_rho]);
     let (sigma1, sigma2) = (slot_checkpoint.sigma1, slot_checkpoint.sigma2);
 
@@ -360,6 +367,7 @@ pub fn create_proposal_reward_proof(
         value_commit,
         new_serial_commit,
         new_value_commit,
+        vrf_proof,
         mu_y,
         y,
         mu_rho,

+ 13 - 3
src/contract/consensus/src/entrypoint/proposal_reward_v1.rs

@@ -24,7 +24,7 @@ use darkfi_sdk::{
     },
     error::{ContractError, ContractResult},
     msg,
-    pasta::pallas,
+    pasta::{group::ff::FromUniformBytes, pallas},
     util::get_slot_checkpoint,
     ContractCall,
 };
@@ -81,10 +81,20 @@ pub(crate) fn consensus_proposal_reward_get_metadata_v1(
     };
     let slot_checkpoint: SlotCheckpoint = deserialize(&slot_checkpoint)?;
 
+    // Verify eta VRF proof
+    let vrf_proof = &params.vrf_proof;
+    if !vrf_proof.verify(params.burnt_public_key, &slot_checkpoint.eta.to_repr()) {
+        msg!("[ConsensusProposalRewardV1] Error: eta VRF proof couldn't be verified");
+        return Err(ConsensusError::ProposalErroneousVrfProof.into())
+    }
+    let mut eta = [0u8; 64];
+    eta[..blake3::OUT_LEN].copy_from_slice(vrf_proof.hash_output().as_bytes());
+    let eta = pallas::Base::from_uniform_bytes(&eta);
+
     // Calculate election seeds
     let slot_pallas = pallas::Base::from(slot_checkpoint.slot);
-    let mu_y = poseidon_hash([MU_Y_PREFIX, slot_checkpoint.eta, slot_pallas]);
-    let mu_rho = poseidon_hash([MU_RHO_PREFIX, slot_checkpoint.eta, slot_pallas]);
+    let mu_y = poseidon_hash([MU_Y_PREFIX, eta, slot_pallas]);
+    let mu_rho = poseidon_hash([MU_RHO_PREFIX, eta, slot_pallas]);
 
     // Grab sigmas from slot checkpoint
     let (sigma1, sigma2) = (slot_checkpoint.sigma1, slot_checkpoint.sigma2);

+ 4 - 0
src/contract/consensus/src/error.rs

@@ -22,12 +22,16 @@ use darkfi_sdk::error::ContractError;
 pub enum ConsensusError {
     #[error("Missing slot checkpoint from db")]
     ProposalMissingSlotCheckpoint,
+
+    #[error("Eta VRF proof couldn't be verified")]
+    ProposalErroneousVrfProof,
 }
 
 impl From<ConsensusError> for ContractError {
     fn from(e: ConsensusError) -> Self {
         match e {
             ConsensusError::ProposalMissingSlotCheckpoint => Self::Custom(1),
+            ConsensusError::ProposalErroneousVrfProof => Self::Custom(2),
         }
     }
 }

+ 6 - 1
src/contract/consensus/src/model.rs

@@ -17,7 +17,10 @@
  */
 
 use darkfi_money_contract::model::{Input, Output, StakeInput};
-use darkfi_sdk::{crypto::PublicKey, pasta::pallas};
+use darkfi_sdk::{
+    crypto::{ecvrf::VrfProof, PublicKey},
+    pasta::pallas,
+};
 use darkfi_serial::{SerialDecodable, SerialEncodable};
 
 /// Parameters for `Consensus::ProposalBurn`
@@ -46,6 +49,8 @@ pub struct ConsensusProposalRewardParamsV1 {
     pub new_serial_commit: pallas::Point,
     /// Rewarded slot
     pub slot: u64,
+    /// VRF proof for eta calculation
+    pub vrf_proof: VrfProof,
     /// Coin y
     pub y: pallas::Base,
     /// Lottery rho used