Explorar el Código

[consensus] validate public values sigmas

mohab metwally hace 3 años
padre
commit
015dd222e0

+ 4 - 7
proof/lead.zk

@@ -30,13 +30,6 @@ circuit "Lead" {
         PREFIX_CM = witness_base(4);
         PREFIX_PK = witness_base(5);
         PREFIX_SN = witness_base(6);
-        
-        # constrain public values
-        
-        # sigma1
-        #constrain_instance(sigma1);
-        # sigma2
-        #constrain_instance(sigma2);
 
         # coin (1) pk
         pk = poseidon_hash(PREFIX_PK, c1_sk_root, c1_tau, ZERO);
@@ -87,5 +80,9 @@ circuit "Lead" {
         term2 = base_mul(term2_1, value);
         target = base_add(term1, term2);
         #lottery
+        # constrain public value sigma1
+        constrain_instance(sigma1);
+        # constrain public value sigma2
+        constrain_instance(sigma2);
         less_than_loose(y, target);
 }

+ 2 - 0
src/consensus/constants.rs

@@ -77,3 +77,5 @@ pub const PI_COMMITMENT_X_INDEX: usize = 1;
 pub const PI_COMMITMENT_Y_INDEX: usize = 2;
 pub const PI_MU_Y_INDEX: usize = 8;
 pub const PI_MU_RHO_INDEX: usize = 10;
+pub const PI_SIGMA1_INDEX: usize = 12;
+pub const PI_SIGMA2_INDEX: usize = 13;

+ 9 - 3
src/consensus/leadcoin.rs

@@ -203,7 +203,9 @@ impl LeadCoin {
 
     /// Create a vector of `pallas::Base` elements from the `LeadCoin` to be
     /// used as public inputs for the ZK proof.
-    pub fn public_inputs(&self) -> Vec<pallas::Base> {
+    pub fn public_inputs(&self,
+                         sigma1: pallas::Base,
+                         sigma2: pallas::Base) -> Vec<pallas::Base> {
         // pk
         let pk = self.pk();
         // coin 1-2 cm/commitment
@@ -236,6 +238,8 @@ impl LeadCoin {
             y,
             self.rho_mu,
             rho,
+            sigma1,
+            sigma2,
         ]
     }
 
@@ -345,7 +349,7 @@ impl LeadCoin {
             Witness::Base(Value::known(sigma2)),
         ];
         let circuit = ZkCircuit::new(witnesses, zkbin.clone());
-        Ok(Proof::create(pk, &[circuit], &self.public_inputs(), &mut OsRng)?)
+        Ok(Proof::create(pk, &[circuit], &self.public_inputs(sigma1, sigma2), &mut OsRng)?)
     }
 
     pub fn create_xfer_proof(
@@ -355,6 +359,8 @@ impl LeadCoin {
         change_pk: pallas::Base, //change coin public key
         transfered_coin: TxRcpt,
         transfered_pk: pallas::Base, // recipient coin's public key
+        sigma1: pallas::Base,
+        sigma2: pallas::Base,
     ) -> Result<TransferStx> {
         assert!(change_coin.value + transfered_coin.value == self.value && self.value > 0);
         let bincode = include_bytes!("../../proof/tx.zk.bin");
@@ -388,7 +394,7 @@ impl LeadCoin {
             Witness::Base(Value::known(xferval)),
         ];
         let circuit = ZkCircuit::new(witnesses, zkbin.clone());
-        let proof = Proof::create(pk, &[circuit], &self.public_inputs(), &mut OsRng)?;
+        let proof = Proof::create(pk, &[circuit], &self.public_inputs(sigma1, sigma2), &mut OsRng)?;
         let cm3_msg_in = [
             pallas::Base::from(PREFIX_CM),
             change_pk,

+ 32 - 9
src/consensus/state.rs

@@ -89,12 +89,15 @@ pub struct ConsensusState {
     pub leaders_history: Vec<u64>,
     /// Kp
     pub kp: Float10,
+    /// previous slot sigma1
+    pub prev_sigma1: pallas::Base,
+    /// previous slot sigma2
+    pub prev_sigma2: pallas::Base,
 }
 
 impl ConsensusState {
     pub fn new(genesis_ts: Timestamp, genesis_data: blake3::Hash) -> Result<Self> {
         let genesis_block = Block::genesis_block(genesis_ts, genesis_data).blockhash();
-
         Ok(Self {
             genesis_ts,
             genesis_block,
@@ -109,6 +112,8 @@ impl ConsensusState {
             leaders_spent_coins: vec![],
             leaders_history: vec![0],
             kp: constants::FLOAT10_TWO.clone() / constants::FLOAT10_NINE.clone(),
+            prev_sigma1: pallas::Base::zero(),
+            prev_sigma2: pallas::Base::zero(),
         })
     }
 }
@@ -400,8 +405,12 @@ impl ValidatorState {
     /// Check if new epoch has started, to create new epoch coins.
     /// Returns flag to signify if epoch has changed and vector of
     /// new epoch competing coins.
-    pub async fn epoch_changed(&mut self) -> Result<bool> {
+    pub async fn epoch_changed(&mut self,
+                               sigma1: pallas::Base,
+                               sigma2: pallas::Base) -> Result<bool> {
         let epoch = self.current_epoch();
+        self.consensus.prev_sigma1 = sigma1;
+        self.consensus.prev_sigma2 = sigma2;
         if epoch <= self.consensus.epoch {
             return Ok(false)
         }
@@ -411,18 +420,22 @@ impl ValidatorState {
         self.consensus.coins = self.create_epoch_coins(eta, epoch).await?;
         self.consensus.epoch = epoch;
         self.consensus.epoch_eta = eta;
+
         Ok(true)
     }
 
     /// return 2-term target approximation sigma coefficients.
     /// `epoch: absolute epoch index
     /// `slot: relative slot index
-    fn sigmas(&mut self, epoch: u64, slot: u64) -> (pallas::Base, pallas::Base) {
+    pub fn sigmas(&mut self, epoch: u64, slot: u64) -> (pallas::Base, pallas::Base) {
         let f = self.win_prob_with_full_stake();
 
         // Generate sigmas
         let total_stake = self.total_stake_plus(epoch, slot); // Only used for fine-tuning
-
+        debug!("consensus::sigmas(): epoch: {}",epoch);
+        debug!("consensus::sigmas(): slot: {}",slot);
+        debug!("consensus::sigmas(): f: {}",f);
+        debug!("consensus::sigmas(): stake: {}",total_stake);
         let one = constants::FLOAT10_ONE.clone();
         let two = constants::FLOAT10_TWO.clone();
         let field_p = Float10::from_str_native(constants::P)
@@ -593,11 +606,10 @@ impl ValidatorState {
     fn win_prob_with_full_stake(&mut self) -> Float10 {
         let zero = constants::FLOAT10_ZERO.clone();
         let one = constants::FLOAT10_ONE.clone();
-        let mut f = zero.clone();
         let p = self.f_dif();
         let i = self.f_int();
         let d = self.f_der();
-        f = self.consensus.kp.clone() *
+        let mut f = self.consensus.kp.clone() *
             (p.clone() +
              one.clone() / constants::TI.clone() * i.clone() +
              constants::TD.clone() * d.clone());
@@ -629,7 +641,7 @@ impl ValidatorState {
     /// * `slot` - slot relative index
     /// * `epoch_coins` - stakeholder's epoch coins
     /// Returns: (check: bool, idx: usize) where idx is the winning coin's index
-    pub fn is_slot_leader(&mut self) -> (bool, usize, pallas::Base, pallas::Base) {
+    pub fn is_slot_leader(&mut self) -> (bool, usize) {
         // Slot relative index
         let slot = self.relative_slot(self.current_slot());
         let (sigma1, sigma2) = self.sigmas(self.consensus.epoch, slot);
@@ -658,7 +670,7 @@ impl ValidatorState {
             }
         }
 
-        (won, highest_stake_idx, sigma1, sigma2)
+        (won, highest_stake_idx)
     }
 
     /// Generate a block proposal for the current slot, containing all
@@ -703,7 +715,7 @@ impl ValidatorState {
         let lead_info = LeadInfo::new(
             signed_proposal,
             public_key,
-            coin.public_inputs(),
+            coin.public_inputs(sigma1, sigma2),
             eta.to_repr(),
             LeadProof::from(proof),
             self.get_current_offset(),
@@ -854,6 +866,17 @@ impl ValidatorState {
             return Err(Error::ProposalPublicValuesMismatched)
         }
 
+        // sigmas
+        // sigma1
+        let prop_sigma1 = lf.public_inputs[constants::PI_SIGMA1_INDEX];
+        if self.consensus.prev_sigma1 != prop_sigma1 {
+            error!("failed to verify public value sigma1: {:?}, to proposed: {:?}", self.consensus.prev_sigma1, prop_sigma1);
+        }
+        // sigma2
+        let prop_sigma2 = lf.public_inputs[constants::PI_SIGMA2_INDEX];
+        if self.consensus.prev_sigma2 != prop_sigma2 {
+            error!("failed to verify public value sigma2: {:?}, to proposed: {:?}", self.consensus.prev_sigma2, prop_sigma2);
+        }
         // Verify proposal public inputs
         let prop_sn = lf.public_inputs[constants::PI_NULLIFIER_INDEX];
         for sn in &self.consensus.leaders_nullifiers {

+ 10 - 4
src/consensus/task/proposal.rs

@@ -91,8 +91,15 @@ pub async fn proposal_task(consensus_p2p: P2pPtr, sync_p2p: P2pPtr, state: Valid
         info!("consensus: Waiting for next slot ({} sec)", seconds_next_slot);
         sleep(seconds_next_slot).await;
 
+        let sl = state.read().await.current_slot();
+        let rel_sl = state.read().await.relative_slot(sl);
+        let ep = state.read().await.consensus.epoch;
+        info!("proposal::proposal_task(): sl: {}, ep: {}", sl, ep);
+        let (sigma1, sigma2) = state.write().await.sigmas(ep, rel_sl);
+        info!("Proposal::proposal_task(): sigma1: {:?}", sigma1);
+        info!("Proposal::proposal_task(): sigma2: {:?}", sigma2);
         // Node checks if epoch has changed, to generate new epoch coins
-        let epoch_changed = state.write().await.epoch_changed().await;
+        let epoch_changed = state.write().await.epoch_changed(sigma1, sigma2).await;
         match epoch_changed {
             Ok(changed) => {
                 if changed {
@@ -101,7 +108,7 @@ pub async fn proposal_task(consensus_p2p: P2pPtr, sync_p2p: P2pPtr, state: Valid
                     for slot_coins in &state.read().await.consensus.coins {
                         let mut slot_coins_inputs = vec![];
                         for slot_coin in slot_coins {
-                            slot_coins_inputs.push(slot_coin.public_inputs());
+                            slot_coins_inputs.push(slot_coin.public_inputs(sigma1, sigma2));
                         }
                         coins.push(slot_coins_inputs);
                     }
@@ -112,10 +119,9 @@ pub async fn proposal_task(consensus_p2p: P2pPtr, sync_p2p: P2pPtr, state: Valid
                 continue
             }
         };
-
         // Node checks if it's the slot leader to generate a new proposal
         // for that slot.
-        let (won, idx, sigma1, sigma2) = state.write().await.is_slot_leader();
+        let (won, idx) = state.write().await.is_slot_leader();
         let result = if won { state.write().await.propose(idx, sigma1, sigma2) } else { Ok(None) };
         let proposal = match result {
             Ok(prop) => {