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

[stakeholder] merge leadcoin keypair with minted owncoin

mohab metwally 3 лет назад
Родитель
Сommit
7392d00e4c
4 измененных файлов с 96 добавлено и 74 удалено
  1. 34 28
      src/blockchain/epoch.rs
  2. 7 4
      src/crypto/leadcoin.rs
  3. 10 14
      src/stakeholder/mod.rs
  4. 45 28
      src/zk/circuit/lead_contract.rs

+ 34 - 28
src/blockchain/epoch.rs

@@ -21,6 +21,7 @@ use crate::crypto::{
     proof::{Proof, ProvingKey},
     types::DrkValueBlind,
     util::{mod_r_p, pedersen_commitment_base, pedersen_commitment_u64},
+    keypair::{Keypair,SecretKey},
 };
 
 const PRF_NULLIFIER_PREFIX: u64 = 0;
@@ -132,12 +133,11 @@ impl Epoch {
         (lead_mu, nonce_mu)
     }
 
-    fn create_coins_sks(&self) -> (Vec<MerkleNode>, Vec<[MerkleNode; MERKLE_DEPTH_ORCHARD]>) {
-        /*
-        at the onset of an epoch, the first slot's coin's secret key
-        is sampled at random, and the rest of the secret keys are derived,
-        for sk (secret key) at time i+1 is derived from secret key at time i.
-         */
+    /// at the onset of an epoch, the first slot's coin's secret key
+    /// is sampled at random, and the rest of the secret keys are derived,
+    /// for sk (secret key) at time i+1 is derived from secret key at time i.
+    ///
+    fn create_coins_sks(&self, sks: &mut Vec<SecretKey>) -> (Vec<MerkleNode>, Vec<[MerkleNode; MERKLE_DEPTH_ORCHARD]>) {
         let mut rng = thread_rng();
         let mut tree = BridgeTree::<MerkleNode, MERKLE_DEPTH>::new(self.len());
         let mut root_sks: Vec<MerkleNode> = vec![];
@@ -145,19 +145,17 @@ impl Epoch {
         let mut prev_sk_base: pallas::Base = pallas::Base::one();
         for _i in 0..self.len() {
             //TODO (fix) add sk for the coin struct to be used in txs decryption of tx notes.
-            let sk_bytes = if _i == 0 {
-                let base = pedersen_commitment_u64(1, pallas::Scalar::random(&mut rng));
-                let coord = base.to_affine().coordinates().unwrap();
-                let sk_base = coord.x() * coord.y();
-                prev_sk_base = sk_base;
-                sk_base.to_repr()
+            let base : pallas::Point = if _i == 0 {
+                pedersen_commitment_u64(1, pallas::Scalar::random(&mut rng))
             } else {
-                let base = pedersen_commitment_u64(1, mod_r_p(prev_sk_base));
-                let coord = base.to_affine().coordinates().unwrap();
-                let sk_base = coord.x() * coord.y();
-                prev_sk_base = sk_base;
-                sk_base.to_repr()
+                pedersen_commitment_u64(1, mod_r_p(prev_sk_base))
             };
+            let coord = base.to_affine().coordinates().unwrap();
+            //TODO (fix) change this to sk = hash(x,y)
+            let sk_base = coord.x() * coord.y();
+            sks.push(SecretKey::from(SecretKey(sk_base)));
+            prev_sk_base = sk_base;
+            let sk_bytes = sk_base.to_repr();
             let node = MerkleNode::from_bytes(&sk_bytes).unwrap();
             //let serialized = serde_json::to_string(&node).unwrap();
             //debug!("serialized: {}", serialized);
@@ -173,6 +171,7 @@ impl Epoch {
         }
         (root_sks, path_sks)
     }
+
     //note! the strategy here is single competing coin per slot.
     pub fn create_coins(&mut self, sigma: pallas::Base, owned: Vec<OwnCoin>) -> Vec<Vec<LeadCoin>> {
         let mut rng = thread_rng();
@@ -181,7 +180,8 @@ impl Epoch {
             let rho: u64 = rng.gen();
             seeds.push(rho);
         }
-        let (root_sks, path_sks) = self.create_coins_sks();
+        let mut sks: Vec<SecretKey> = vec![];
+        let (root_sks, path_sks) = self.create_coins_sks(&mut sks);
 
         // matrix of leadcoins, each row has competing coins per slot.
         let _coins: Vec<Vec<LeadCoin>> = vec![];
@@ -197,6 +197,7 @@ impl Epoch {
                         root_sks[i],
                         path_sks[i],
                         seeds[i],
+                        sks[i]
                     );
                     slot_coins.push(coin);
                 }
@@ -204,7 +205,7 @@ impl Epoch {
             }
             // otherwise compete with zero stake
             else {
-                let coin = self.create_leadcoin(sigma, 0, i, root_sks[i], path_sks[i], seeds[i]);
+                let coin = self.create_leadcoin(sigma, 0, i, root_sks[i], path_sks[i], seeds[i], sks[i]);
                 self.coins.push(vec![coin]);
             }
         }
@@ -219,7 +220,10 @@ impl Epoch {
         c_root_sk: MerkleNode,
         c_path_sk: [MerkleNode; MERKLE_DEPTH_ORCHARD],
         seed: u64,
+        sk: SecretKey,
     ) -> LeadCoin {
+        // keypair
+        let keypair : Keypair = Keypair::new(sk);
         //random commitment blinding values
         let mut rng = thread_rng();
         let c_cm1_blind: DrkValueBlind = pallas::Scalar::random(&mut rng);
@@ -233,10 +237,12 @@ impl Epoch {
         let c_tau = pallas::Base::from(u64::try_from(i).unwrap());
         //
 
-        let coin_pk_msg = [c_tau, c_root_sk.inner()];
-        let c_pk: pallas::Base =
-            poseidon::Hash::<_, poseidon::P128Pow5T3, poseidon::ConstantLength<2>, 3, 2>::init()
-                .hash(coin_pk_msg);
+        //let coin_pk_msg = [c_tau, c_root_sk.inner()];
+        //let c_pk: pallas::Base = poseidon::Hash::<_, poseidon::P128Pow5T3, poseidon::ConstantLength<2>, 3, 2>::init().hash(coin_pk_msg);
+        let c_pk: pallas::Point = keypair.public.0;
+        let c_pk_coord = c_pk.to_affine().coordinates().unwrap();
+        let c_pk_x = c_pk_coord.x();
+        let c_pk_y = c_pk_coord.y();
 
         let c_seed = pallas::Base::from(seed);
         let sn_msg = [c_seed, c_root_sk.inner()];
@@ -244,9 +250,9 @@ impl Epoch {
             poseidon::Hash::<_, poseidon::P128Pow5T3, poseidon::ConstantLength<2>, 3, 2>::init()
                 .hash(sn_msg);
 
-        let coin_commit_msg_input = [pallas::Base::from(PRF_NULLIFIER_PREFIX), c_pk, c_v, c_seed];
+        let coin_commit_msg_input = [pallas::Base::from(PRF_NULLIFIER_PREFIX), *c_pk_x, *c_pk_y, c_v, c_seed];
         let coin_commit_msg: pallas::Base =
-            poseidon::Hash::<_, poseidon::P128Pow5T3, poseidon::ConstantLength<4>, 3, 2>::init()
+            poseidon::Hash::<_, poseidon::P128Pow5T3, poseidon::ConstantLength<5>, 3, 2>::init()
                 .hash(coin_commit_msg_input);
         let c_cm: pallas::Point = pedersen_commitment_base(coin_commit_msg, c_cm1_blind);
         let c_cm_coordinates = c_cm.to_affine().coordinates().unwrap();
@@ -262,9 +268,9 @@ impl Epoch {
             poseidon::Hash::<_, poseidon::P128Pow5T3, poseidon::ConstantLength<2>, 3, 2>::init()
                 .hash(coin_nonce2_msg);
 
-        let coin2_commit_msg_input = [pallas::Base::from(PRF_NULLIFIER_PREFIX), c_pk, c_v, c_seed2];
+        let coin2_commit_msg_input = [pallas::Base::from(PRF_NULLIFIER_PREFIX), *c_pk_x, *c_pk_y, c_v, c_seed2];
         let coin2_commit_msg: pallas::Base =
-            poseidon::Hash::<_, poseidon::P128Pow5T3, poseidon::ConstantLength<4>, 3, 2>::init()
+            poseidon::Hash::<_, poseidon::P128Pow5T3, poseidon::ConstantLength<5>, 3, 2>::init()
                 .hash(coin2_commit_msg_input);
         let c_cm2 = pedersen_commitment_base(coin2_commit_msg, c_cm2_blind);
 
@@ -280,7 +286,7 @@ impl Epoch {
             nonce: Some(c_seed),
             nonce_cm: Some(c_seed2),
             sn: Some(c_sn),
-            pk: Some(c_pk),
+            keypair: Some(keypair),
             root_cm: Some(mod_r_p(c_root_cm.inner())),
             root_sk: Some(c_root_sk.inner()),
             path: Some(c_cm_path.as_slice().try_into().unwrap()),

+ 7 - 4
src/crypto/leadcoin.rs

@@ -7,6 +7,7 @@ use crate::{
         constants::MERKLE_DEPTH_ORCHARD,
         merkle_node::MerkleNode,
         util::{mod_r_p, pedersen_commitment_base},
+        keypair::{Keypair, SecretKey, PublicKey},
     },
     zk::circuit::lead_contract::LeadContract,
 };
@@ -17,7 +18,7 @@ use pasta_curves::{arithmetic::CurveAffine, group::Curve};
 
 //use halo2_proofs::arithmetic::CurveAffine;
 
-pub const LEAD_PUBLIC_INPUT_LEN: usize = 10;
+pub const LEAD_PUBLIC_INPUT_LEN: usize = 11;
 
 #[derive(Debug, Default, Clone, Copy)]
 pub struct LeadCoin {
@@ -30,7 +31,7 @@ pub struct LeadCoin {
     pub nonce: Option<pallas::Base>,                         // coin nonce
     pub nonce_cm: Option<pallas::Base>,                      // coin nonce's commitment
     pub sn: Option<pallas::Base>,                            // coin's serial number
-    pub pk: Option<pallas::Base>,                            // coin public key
+    pub keypair: Option<Keypair>,
     pub root_cm: Option<pallas::Scalar>,                     // root of coin commitment
     pub root_sk: Option<pallas::Base>,                       // coin's secret key
     pub path: Option<[MerkleNode; MERKLE_DEPTH_ORCHARD]>,    // path to the coin's commitment
@@ -53,7 +54,7 @@ impl LeadCoin {
 
         let po_cm = self.cm.unwrap().to_affine().coordinates().unwrap();
         let po_cm2 = self.cm2.unwrap().to_affine().coordinates().unwrap();
-        let po_pk = self.pk.unwrap();
+        let po_pk = self.keypair.unwrap().public.0.to_affine().coordinates().unwrap();
         let po_sn = self.sn.unwrap();
 
         let y_mu = self.y_mu.unwrap();
@@ -98,7 +99,8 @@ impl LeadCoin {
             *po_cm2.y(),
             po_nonce,
             cm_root.0,
-            po_pk,
+            *po_pk.x(),
+            *po_pk.y(),
             po_sn,
             po_y,
             po_rho,
@@ -113,6 +115,7 @@ impl LeadCoin {
     pub fn create_contract(&self) -> LeadContract {
         LeadContract {
             path: Value::known(self.path.unwrap()),
+            sk: Value::known(self.keypair.unwrap().secret.0),
             root_sk: Value::known(self.root_sk.unwrap()),
             path_sk: Value::known(self.path_sk.unwrap()),
             coin_timestamp: Value::known(self.tau.unwrap()), //

+ 10 - 14
src/stakeholder/mod.rs

@@ -238,7 +238,6 @@ pub struct Stakeholder {
     pub playing: bool,
     pub workspace: SlotWorkspace,
     pub id: i64,
-    pub keypair: Keypair,
     pub cashier_signature_public: PublicKey,
     pub faucet_signature_public: PublicKey,
     pub cashier_signature_secret: SecretKey,
@@ -284,7 +283,6 @@ impl Stakeholder {
         let faucet_signature_secret = SecretKey::random(&mut OsRng);
         let faucet_signature_public = PublicKey::from_secret(faucet_signature_secret);
 
-        let keypair = Keypair::random(&mut OsRng);
         debug!(target: LOG_T, "stakeholder constructed");
         Ok(Self {
             blockchain: bc,
@@ -302,7 +300,6 @@ impl Stakeholder {
             playing: true,
             workspace,
             id,
-            keypair,
             cashier_signature_public,
             faucet_signature_public,
             cashier_signature_secret,
@@ -310,17 +307,13 @@ impl Stakeholder {
         })
     }
 
-    /// wrapper on Schnorr signature
-    pub fn sign(&self, message: &[u8]) -> Signature {
-        info!(target: LOG_T, "sign()");
-        self.keypair.secret.sign(message)
-    }
-
+    /*
     /// wrapper on schnorr public verify
     pub fn verify(&self, message: &[u8], signature: &Signature) -> bool {
         info!(target: LOG_T, "verify()");
         self.keypair.public.verify(message, signature)
     }
+    */
 
     pub fn get_leadprovkingkey(&self) -> ProvingKey {
         info!(target: LOG_T, "get_leadprovkingkey()");
@@ -555,8 +548,10 @@ impl Stakeholder {
         self.workspace.set_leader(won);
         self.workspace.set_proof(proof.clone());
 
-        let addr = Address::from(self.keypair.public);
-        let sign = self.sign(proof.as_ref());
+        let coin = self.epoch.get_coin(sl as usize, winning_coin_idx as usize);
+        let keypair = coin.keypair.unwrap();
+        let addr = Address::from(keypair.public);
+        let sign = keypair.secret.sign(proof.as_ref());
         let stakeholder_meta = StakeholderMetadata::new(sign, addr);
         let ouroboros_meta =
             OuroborosMetadata::new(self.get_eta().to_repr(), TransactionLeadProof::from(proof));
@@ -575,6 +570,7 @@ impl Stakeholder {
     //TODO (res) validate the owncoin is the same winning leadcoin
     pub fn finalize_coin(&self, coin: &LeadCoin) -> OwnCoin {
         info!(target: LOG_T, "finalize coin");
+        let keypair = coin.keypair.unwrap();
         let mut state = StakeholderState {
             tree: BridgeTree::<MerkleNode, MERKLE_DEPTH>::new(TREE_LEN),
             merkle_roots: vec![],
@@ -584,7 +580,7 @@ impl Stakeholder {
             burn_vk: self.burn_vk.clone(),
             cashier_signature_public: self.cashier_signature_public,
             faucet_signature_public: self.faucet_signature_public,
-            secrets: vec![self.keypair.secret],
+            secrets: vec![keypair.secret],
         };
 
         let token_id = pallas::Base::random(&mut OsRng);
@@ -598,13 +594,13 @@ impl Stakeholder {
             outputs: vec![TransactionBuilderOutputInfo {
                 value: coin.value.unwrap(),
                 token_id,
-                public: self.keypair.public,
+                public: keypair.public,
             }],
         };
         let tx = builder.build(&self.mint_pk, &self.burn_pk).unwrap();
 
         tx.verify(&state.mint_vk, &state.burn_vk).unwrap();
-        let _note = tx.outputs[0].enc_note.decrypt(&self.keypair.secret).unwrap();
+        let _note = tx.outputs[0].enc_note.decrypt(&keypair.secret).unwrap();
         let update = state_transition(&state, tx).unwrap();
         state.apply(update);
         state.own_coins[0].clone()

+ 45 - 28
src/zk/circuit/lead_contract.rs

@@ -97,10 +97,11 @@ const LEAD_COIN_COMMIT2_X_OFFSET: usize = 2;
 const LEAD_COIN_COMMIT2_Y_OFFSET: usize = 3;
 const LEAD_COIN_NONCE2_OFFSET: usize = 4;
 const LEAD_COIN_COMMIT_PATH_OFFSET: usize = 5;
-const LEAD_COIN_PK_OFFSET: usize = 6;
-const LEAD_COIN_SERIAL_NUMBER_OFFSET: usize = 7;
-const LEAD_Y_COMMIT_BASE_OFFSET: usize = 8;
-const LEAD_RHO_COMMIT_BASE_OFFSET: usize = 9;
+const LEAD_COIN_PK_X_OFFSET: usize = 6;
+const LEAD_COIN_PK_Y_OFFSET: usize = 7;
+const LEAD_COIN_SERIAL_NUMBER_OFFSET: usize = 8;
+const LEAD_Y_COMMIT_BASE_OFFSET: usize = 9;
+const LEAD_RHO_COMMIT_BASE_OFFSET: usize = 10;
 
 pub fn concat_u8(lhs: &[u8], rhs: &[u8]) -> Vec<u8> {
     [lhs, rhs].concat()
@@ -110,6 +111,7 @@ pub fn concat_u8(lhs: &[u8], rhs: &[u8]) -> Vec<u8> {
 pub struct LeadContract {
     // witness
     pub path: Value<[MerkleNode; MERKLE_DEPTH_ORCHARD]>,
+    pub sk: Value<pallas::Base>,
     pub root_sk: Value<pallas::Base>, // coins merkle tree secret key of coin1
     pub path_sk: Value<[MerkleNode; MERKLE_DEPTH_ORCHARD]>, // path to the secret key root_sk
     pub coin_timestamp: Value<pallas::Base>,
@@ -318,7 +320,11 @@ impl Circuit<pallas::Base> for LeadContract {
 
         // staking coin secret key
         let _root_sk =
-            self.load_private(layouter.namespace(|| ""), config.advices[0], self.root_sk)?;
+            self.load_private(layouter.namespace(|| "root sk"), config.advices[0], self.root_sk)?;
+
+        // staking coin secret key
+        let sk: AssignedCell<Fp, Fp> =
+            self.load_private(layouter.namespace(|| "sk"), config.advices[0], self.sk).unwrap();
 
         // sigma scalar is 2^254/(total network stake + epsilon)
         let sigma_scalar = self.load_private(
@@ -334,28 +340,36 @@ impl Circuit<pallas::Base> for LeadContract {
             Value::known(pallas::Base::one()), // note! this parameter to be tuned.
         )?;
 
+        // the original crypsinous pk is as follows.
         // coin public key pk=PRF_{root_sk}(tau)
         // coin public key is pseudo random hash of concatenation of the following:
         // coin timestamp, and root of coin's secret key.
-        let coin_pk_commit: AssignedCell<Fp, Fp> = {
-            let poseidon_message = [coin_timestamp, _root_sk.clone()];
-            let poseidon_hasher = PoseidonHash::<
-                _,
-                _,
-                poseidon::P128Pow5T3,
-                poseidon::ConstantLength<2>,
-                3,
-                2,
-            >::init(
-                config.poseidon_chip(), layouter.namespace(|| "Poseidon init")
-            )?;
-
-            let poseidon_output =
-                poseidon_hasher.hash(layouter.namespace(|| "Poseidon hash"), poseidon_message)?;
-            let poseidon_output: AssignedCell<Fp, Fp> = poseidon_output;
-            poseidon_output
+        //let coin_pk_commit: AssignedCell<Fp, Fp> = {
+        //    let poseidon_message = [coin_timestamp, _root_sk.clone()];
+        //  //let poseidon_hasher = PoseidonHash::<
+        //      _,
+        //      _,
+        //      poseidon::P128Pow5T3,
+        //      poseidon::ConstantLength<2>,
+        //      3,
+        //      2,
+        //  >::init(
+        //      config.poseidon_chip(), layouter.namespace(|| "Poseidon init")
+        //  )?;
+        //
+        //  let poseidon_output =
+        //      poseidon_hasher.hash(layouter.namespace(|| "Poseidon hash"), poseidon_message)?;
+        //  let poseidon_output: AssignedCell<Fp, Fp> = poseidon_output;
+        //  poseidon_output
+        //};
+        // darkfi coin pk
+        //
+        let coin_pk  = {
+            let coin_pk_commit_v = FixedPointBaseField::from_inner(ecc_chip.clone(), NullifierK);
+            coin_pk_commit_v.mul(layouter.namespace(|| "coin pk commit v"), sk.clone())?
         };
-
+        let coin_pk_x = coin_pk.inner().x();
+        let coin_pk_y = coin_pk.inner().y();
         // coin c1 serial number sn=PRF_{root_sk}(nonce)
         // coin's serial number is derived from coin nonce (sampled at random)
         // and root of the coin's secret key sampled an random.
@@ -386,7 +400,8 @@ impl Circuit<pallas::Base> for LeadContract {
             let nullifier_msg: AssignedCell<Fp, Fp> = {
                 let poseidon_message = [
                     prf_nullifier_prefix_base.clone(),
-                    coin_pk_commit.clone(),
+                    coin_pk_x.clone(),
+                    coin_pk_y.clone(),
                     coin_value.clone(),
                     coin_nonce.clone(),
                 ];
@@ -394,7 +409,7 @@ impl Circuit<pallas::Base> for LeadContract {
                     _,
                     _,
                     poseidon::P128Pow5T3,
-                    poseidon::ConstantLength<4>,
+                    poseidon::ConstantLength<5>,
                     3,
                     2,
                 >::init(
@@ -457,7 +472,8 @@ impl Circuit<pallas::Base> for LeadContract {
             let nullifier2_msg: AssignedCell<Fp, Fp> = {
                 let poseidon_message = [
                     prf_nullifier_prefix_base,
-                    coin_pk_commit.clone(),
+                    coin_pk_x.clone(),
+                    coin_pk_y.clone(),
                     coin_value.clone(),
                     coin2_nonce.clone(),
                 ];
@@ -465,7 +481,7 @@ impl Circuit<pallas::Base> for LeadContract {
                     _,
                     _,
                     poseidon::P128Pow5T3,
-                    poseidon::ConstantLength<4>,
+                    poseidon::ConstantLength<5>,
                     3,
                     2,
                 >::init(
@@ -624,7 +640,8 @@ impl Circuit<pallas::Base> for LeadContract {
             LEAD_COIN_COMMIT_PATH_OFFSET,
         )?;
 
-        layouter.constrain_instance(coin_pk_commit.cell(), config.primary, LEAD_COIN_PK_OFFSET)?;
+        layouter.constrain_instance(coin_pk_x.cell(), config.primary, LEAD_COIN_PK_X_OFFSET)?;
+        layouter.constrain_instance(coin_pk_y.cell(), config.primary, LEAD_COIN_PK_Y_OFFSET)?;
 
         // constrain coin's pub key x value
         layouter.constrain_instance(