From 7eee50992207f53b0b959c729794ed68e25a53ee Mon Sep 17 00:00:00 2001 From: mohab metwally Date: Mon, 18 Jul 2022 11:57:25 +0200 Subject: [PATCH] [WIP/crypsinous simulation] crypsinous simualtion still wip --- bin/crypsinous/src/main.rs | 24 ++++++++++ example/lead.rs | 4 +- src/blockchain/epoch.rs | 77 ++++++++++++++++++++++++++++----- src/blockchain/mod.rs | 2 + src/crypto/lead_proof.rs | 33 ++++---------- src/crypto/proof.rs | 3 +- src/stakeholder/stakeholder.rs | 59 ++++++++++++++++++++++--- src/zk/circuit/lead_contract.rs | 4 +- 8 files changed, 161 insertions(+), 45 deletions(-) create mode 100644 bin/crypsinous/src/main.rs diff --git a/bin/crypsinous/src/main.rs b/bin/crypsinous/src/main.rs new file mode 100644 index 000000000..826a4317b --- /dev/null +++ b/bin/crypsinous/src/main.rs @@ -0,0 +1,24 @@ +use darkfi::{ + stakeholder::Stakeholder, + blockchain::{EpochConsensus} +}; + +fn main() +{ + let slots=3; + let reward=22; + let epoch_consensus = EpochConsensus::new(slots, reward); + /// read n from the cmd + let n = 3; + /// initialize n stakeholders + let stakeholders = vec!(n); + for i in n { + let stakeholder = Stakeholder::new(); + stakeholders.push(stakeholder); + } + /// when the clock signal a new slot. + /// check for leadership. + /// if lead publish construct block metadata. + /// push the new block before the end of the slot (clock should siganl the beging, and 1/k of the way to the end). + ///TODO stakeholder should signal new epoch, new slot in the background +} diff --git a/example/lead.rs b/example/lead.rs index 9b02782e2..dca99c850 100644 --- a/example/lead.rs +++ b/example/lead.rs @@ -62,6 +62,7 @@ fn main() { //TODO (fix) proof panics let lead_tx = TransactionLeadProof::new(lead_pk, coin.clone()); + /* //lead_tx.verify(lead_vk, coin); let (st_id, st_hash) = stakeholder.blockchain.last().unwrap(); let empty_txs : Vec = vec!(); @@ -74,7 +75,6 @@ fn main() { // calculate public inputs let public_inputs = coin.public_inputs(); let prover = MockProver::run(k, &contract, vec![public_inputs]).unwrap(); - // assert_eq!(prover.verify(), Ok(())); - // + */ } diff --git a/src/blockchain/epoch.rs b/src/blockchain/epoch.rs index 388cd290e..d46adc22b 100644 --- a/src/blockchain/epoch.rs +++ b/src/blockchain/epoch.rs @@ -27,6 +27,30 @@ pub struct EpochItem { pub value: u64, // the stake value is static during the epoch. } +/// epoch configuration +/// this struct need be a singleton, +/// should be populated from configuration file. +#[derive(Copy,Debug,Default,Clone)] +pub struct EpochConsensus { + pub len : u64, /// number of slots per epoch + pub reward: u64, +} + +impl EpochConsensus{ + fn new(len: u64, reward: u64) { + Self {len, reward} + } + + /// TODO how is the reward derived? + fn get_reward(&self) { + self.reward + } + + fn get_sl(&self) { + self.len + } +} + #[derive(Copy,Debug,Default,Clone)] pub struct Epoch { // TODO this need to emulate epoch @@ -36,20 +60,18 @@ pub struct Epoch { //epoch item pub item: Option, pub eta: pallas::Base, // CRS for the leader selection. - + pub coins: Vec, } -#[derive(Debug,Default,Clone)] -pub struct LifeTime { - //lifetime metadata - //... - //lifetime epochs - pub epochs : Vec, -} - - impl Epoch { + pub fn new(consensus: EpochConsensus, true_random:pallas::Base) + { + Self {len: consensus.len, + item: EpochItem {consensus.reward}, + eta: true_random, + } + } fn create_coins_election_seeds(&self, sl: pallas::Base) -> (pallas::Base, pallas::Base) { let ELECTION_SEED_NONCE : pallas::Base = pallas::Base::from(3); let ELECTION_SEED_LEAD : pallas::Base = pallas::Base::from(22); @@ -221,6 +243,41 @@ impl Epoch { }; coins.push(coin); } + self.coins = coins; coins } + + /// retrive leadership lottary coins of static stake, + /// retrived for for commitment in the genesis data + pub fn get_coins(&self) -> Vec { + return self.coins + } + + /// see if the participant stakeholder of this epoch is + /// winning the lottery, in case of success return True + pub fn is_leader(&self, sl: u64) -> bool { + let coin = self.coins[i]; + let y_exp = [ + coin.root_sk, + coin.nonce, + ]; + let y_exp_hash : pallas::Base = PoseidonHash::<_, _, poseidon::P128Pow5T3, poseidon::ContractLength<2>,3,2,>::init(y_exp); + let y = pedersen_commitment_scalar(coin.y_mu, y_exp_hash); + let ord = 1024; //TODO (res) + let target = ord*coin.value; + y < target + } + + pub fn get_proof(&self, sl: u64) -> Proof { + let coin = self.coins[sl]; + lead_proof::create_lead_proof(pk, coin) + } +} + +#[derive(Debug,Default,Clone)] +pub struct LifeTime { + //lifetime metadata + //... + //lifetime epochs + pub epochs : Vec, } diff --git a/src/blockchain/mod.rs b/src/blockchain/mod.rs index a7e4ffafd..133cd9c55 100644 --- a/src/blockchain/mod.rs +++ b/src/blockchain/mod.rs @@ -50,6 +50,8 @@ pub struct Blockchain { } impl Blockchain { + //FIXME why the blockchain taking genesis_data on the constructor as a hash? + //genesis data are supposed to be a a hash? /// Instantiate a new `Blockchain` with the given `sled` database. pub fn new(db: &sled::Db, genesis_ts: Timestamp, genesis_data: blake3::Hash) -> Result { let blocks = BlockStore::new(db, genesis_ts, genesis_data)?; diff --git a/src/crypto/lead_proof.rs b/src/crypto/lead_proof.rs index ca64e2dff..bfdd157c6 100644 --- a/src/crypto/lead_proof.rs +++ b/src/crypto/lead_proof.rs @@ -24,34 +24,17 @@ use rand::{thread_rng, Rng}; #[allow(clippy::too_many_arguments)] pub fn create_lead_proof(pk: ProvingKey, coin: LeadCoin) -> Result { // - let mut rng = thread_rng(); - let yu64: u64 = rng.gen(); - let rhou64: u64 = rng.gen(); - let mau_y: pallas::Base = pallas::Base::from(yu64); - let mau_rho: pallas::Base = pallas::Base::from(rhou64); - let contract = LeadContract { - path: Value::known(coin.path.unwrap()), - coin_pk_x: Value::known(coin.pk_x.unwrap()), - coin_pk_y: Value::known(coin.pk_y.unwrap()), - root_sk: Value::known(coin.root_sk.unwrap()), - sf_root_sk: Value::known(mod_r_p(coin.root_sk.unwrap())), - path_sk: Value::known(coin.path_sk.unwrap()), - coin_timestamp: Value::known(coin.tau.unwrap()), - coin_nonce: Value::known(coin.nonce.unwrap()), - coin1_blind: Value::known(coin.c1_blind.unwrap()), - value: Value::known(coin.value.unwrap()), - coin2_blind: Value::known(coin.c2_blind.unwrap()), - cm_pos: Value::known(coin.idx), - //sn_c1: Value::known(coin.sn.unwrap()), - slot: Value::known(coin.sl.unwrap()), - mau_rho: Value::known(mod_r_p(mau_rho)), - mau_y: Value::known(mod_r_p(mau_y)), - root_cm: Value::known(coin.root_cm.unwrap()), - }; - + //let mut rng = thread_rng(); + //let yu64: u64 = rng.gen(); + //let rhou64: u64 = rng.gen(); + //let mau_y: pallas::Base = pallas::Base::from(yu64); + //let mau_rho: pallas::Base = pallas::Base::from(rhou64); + let contract = coin.create_contract(); //let start = Instant::now(); let public_inputs = coin.public_inputs(); + println!("creating proof"); let proof = Proof::create(&pk, &[contract], &public_inputs, &mut OsRng)?; + println!("proof created"); //debug!("Prove lead: [{:?}]", start.elapsed()); Ok(proof) } diff --git a/src/crypto/proof.rs b/src/crypto/proof.rs index 96e51c783..62d31f522 100644 --- a/src/crypto/proof.rs +++ b/src/crypto/proof.rs @@ -61,7 +61,7 @@ impl Proof { mut rng: impl RngCore, ) -> std::result::Result { let mut transcript = Blake2bWrite::<_, vesta::Affine, _>::init(vec![]); - + println!("creating plonk proof"); plonk::create_proof( &pk.params, &pk.pk, @@ -70,6 +70,7 @@ impl Proof { &mut rng, &mut transcript, )?; + println!("created plonk proof"); Ok(Proof(transcript.finalize())) } diff --git a/src/stakeholder/stakeholder.rs b/src/stakeholder/stakeholder.rs index 405121201..44ef15804 100644 --- a/src/stakeholder/stakeholder.rs +++ b/src/stakeholder/stakeholder.rs @@ -1,10 +1,15 @@ use crate::{ consensus::{BlockInfo}, util::time::Timestamp, - blockchain::{Blockchain}, + blockchain::{Blockchain,Epoch}, Result, }; + +use darkfi::crypto::proof::VerifyingKey; +use darkfi::crypto::proof::ProvingKey; + + use pasta_curves::{ pallas, }; @@ -13,28 +18,44 @@ use group::ff::PrimeField; pub struct Stakeholder { - pub blockchain: Blockchain // stakeholder view of the blockchain + pub blockchain: Blockchain, // stakeholder view of the blockchain + pub clock : Clock, + pub coins : Vec, // owned stakes + pub epoch : &Epoch, // current epoch + pub epoch_consensus : EpochConsensus, // configuration for the epoch + pub pk : ProvingKey, + pub vk : VerifyingKey, } impl Stakeholder { - pub fn new() -> Result + /// initialize new stakeholder with sled in /tmp + pub fn new(consensus: EpochConsensus) -> Result { //TODO initialize the blockchain let path = "/tmp"; let db = sled::open(path).unwrap(); let ts = Timestamp::current_time(); - let genesis_hash = blake3::hash(b"data"); + let genesis_hash = blake3::hash(b""); let bc = Blockchain::new(&db, ts, genesis_hash).unwrap(); - Ok(Self{blockchain: bc}) + //TODO replace with const + let eta = pallas::base::one(); + //let epoch = Epoch::new(consensus, eta); + let lead_pk = ProvingKey::build(k, &LeadContract::default()); + let lead_vk = VerifyingKey::build(k, &LeadContract::default()); + Ok(Self{blockchain: bc, epoch_consensus: consensus, pk:lead_pk, vk:lead_vk}) } + /// add new blockinfo to the blockchain pub fn add_block(&self, block: BlockInfo) { let blocks = [block]; self.blockchain.add(&blocks); } + /// extract leader selection lottery randomness \eta + /// it's the hash of the previous lead proof + /// converted to pallas base pub fn get_eta(&self) -> pallas::Base { let last_proof_slot : u64 = 0; @@ -45,4 +66,32 @@ impl Stakeholder bytes[31] = 0; pallas::Base::from_repr(bytes).unwrap() } + + /// on the onset of the epoch, layout the new the competing coins + /// assuming static stake during the epoch, enforced by the commitment to competing coins + /// in the epoch's gen2esis data. + pub fn new_epoch(&self) + { + let eta = self.get_eta(); + let epoch = Epoch::new(self.consensus, self.get_eta()); + let coins : Vec = epoch.create_coins(); + self.epoch = epoch; + //TODO initialize blocks in the epoch, and add coin commitment in genesis + } + + /// at the begining of the slot + /// stakeholder need to play the lottery for the slot. + /// FIXME if the stakeholder is not winning, staker can try different coins before, + /// commiting it's coins, to maximize success, thus, + /// the lottery proof need to be conditioned on the slot itself, and previous proof. + /// this will encourage each potential leader to play with honesty. + pub fn new_slot(&self) -> Result + { + let sl : u64 = self.clock.slot(); + let is_leader : bool = self.epoch.is_leader(sl); + // if is leader create proof + let proof = self.epoch.get_proof(sl, self.pk); + //TODO initialize blocks in the epoch, and add proof + Ok(is_leader, proof) + } } diff --git a/src/zk/circuit/lead_contract.rs b/src/zk/circuit/lead_contract.rs index 664e6f4fc..ee05b0245 100644 --- a/src/zk/circuit/lead_contract.rs +++ b/src/zk/circuit/lead_contract.rs @@ -651,9 +651,9 @@ impl Circuit for LeadContract { //TODO (research) this multiplication panics! let y_commit_exp = ar_chip.mul( - layouter.namespace(|| ""), + layouter.namespace(|| ""), + //root_sk.clone(), //(fix) &coin_nonce, - //root_sk.clone(), //(fix) &one, )?;