Browse Source

migrate over spend contract from burn.rs to src/

narodnik 4 years ago
parent
commit
9a9169590f
5 changed files with 119 additions and 20 deletions
  1. 0 4
      src/bin/burn.rs
  2. 3 3
      src/bin/tx2.rs
  3. 112 10
      src/circuit/spend_contract.rs
  4. 2 2
      src/crypto/spend_proof.rs
  5. 2 1
      src/tx/builder.rs

+ 0 - 4
src/bin/burn.rs

@@ -128,7 +128,6 @@ struct BurnCircuit {
     coin_blind: Option<pallas::Base>,
     value_blind: Option<pallas::Scalar>,
     asset_blind: Option<pallas::Scalar>,
-    leaf: Option<pallas::Base>,
     leaf_pos: Option<u32>,
     merkle_path: Option<[pallas::Base; 32]>,
     sig_secret: Option<pallas::Scalar>,
@@ -671,8 +670,6 @@ fn main() {
     let (merkle_position, merkle_path) = tree.authentication_path(&node).unwrap();
 
     // Merkle root
-    //let leaf = pallas::Base::random(&mut OsRng);
-    let leaf = coin.clone();
     let pos: u64 = merkle_position.into();
     let path: Vec<pallas::Base> = merkle_path.iter().map(|node| node.0).collect();
     let merkle_root = tree.root().0;
@@ -710,7 +707,6 @@ fn main() {
         coin_blind: Some(coin_blind),
         value_blind: Some(value_blind),
         asset_blind: Some(asset_blind),
-        leaf: Some(leaf),
         leaf_pos: Some(pos as u32),
         merkle_path: Some(path.try_into().unwrap()),
         sig_secret: Some(sig_secret),

+ 3 - 3
src/bin/tx2.rs

@@ -710,10 +710,10 @@ fn main() -> std::result::Result<(), failure::Error> {
     let node = MerkleNode(tx.outputs[0].revealed.coin.clone());
     tree.append(&node);
     tree.witness();
-    let (merkle_position, merkle_path) = tree.authentication_path(&node).unwrap();
+    let (leaf_position, merkle_path) = tree.authentication_path(&node).unwrap();
 
     let mut current = node;
-    let position: u64 = merkle_position.into();
+    let position: u64 = leaf_position.into();
     for (level, sibling) in merkle_path.iter().enumerate() {
         let level = level as u8;
         current = if position & (1 << level) == 0 {
@@ -734,7 +734,7 @@ fn main() -> std::result::Result<(), failure::Error> {
     let builder = tx::TransactionBuilder {
         clear_inputs: vec![],
         inputs: vec![tx::TransactionBuilderInputInfo {
-            merkle_position,
+            leaf_position,
             merkle_path,
             secret,
             note,

+ 112 - 10
src/circuit/spend_contract.rs

@@ -23,7 +23,7 @@ use halo2_gadgets::{
         merkle::MerklePath,
     },
     utilities::{
-        lookup_range_check::LookupRangeCheckConfig, CellValue, UtilitiesInstructions, Var,
+        copy, lookup_range_check::LookupRangeCheckConfig, CellValue, UtilitiesInstructions, Var,
     },
 };
 
@@ -102,7 +102,6 @@ pub struct SpendContract {
     pub coin_blind: Option<pasta::Fp>,
     pub value_blind: Option<pasta::Fq>,
     pub asset_blind: Option<pasta::Fq>,
-    pub leaf: Option<pasta::Fp>,
     pub leaf_pos: Option<u32>,
     pub merkle_path: Option<[pasta::Fp; 32]>,
     pub sig_secret: Option<pasta::Fq>,
@@ -273,7 +272,7 @@ impl Circuit<pasta::Fp> for SpendContract {
         // =========
         // Nullifier
         // =========
-        let hashed_secret_key = self.load_private(
+        let secret_key = self.load_private(
             layouter.namespace(|| "load sinsemilla(secret key)"),
             config.advices[0],
             self.secret_key,
@@ -285,7 +284,7 @@ impl Circuit<pasta::Fp> for SpendContract {
             self.serial,
         )?;
 
-        let message = [hashed_secret_key, serial];
+        let message = [secret_key, serial];
         let hash = {
             let poseidon_message = layouter.assign_region(
                 || "load message",
@@ -324,14 +323,117 @@ impl Circuit<pasta::Fp> for SpendContract {
 
         layouter.constrain_instance(hash.cell(), config.primary, BURN_NULLIFIER_OFFSET)?;
 
+        // let nullifier_k = FixedPointBaseField::from_inner(ecc_chip.clone(), NullifierK);
+        //     nullifier_k.mul(
+        //         layouter.namespace(|| "[poseidon_output + psi_old] NullifierK"),
+        //         scalar,
+        //     )?
+
+        let value = self.load_private(
+            layouter.namespace(|| "load value"),
+            config.advices[0],
+            self.value,
+        )?;
+
+        let asset = self.load_private(
+            layouter.namespace(|| "load asset"),
+            config.advices[0],
+            self.asset,
+        )?;
+
+        let coin_blind = self.load_private(
+            layouter.namespace(|| "load coin_blind"),
+            config.advices[0],
+            self.coin_blind,
+        )?;
+
+        let public_key = {
+            let nullifier_k = OrchardFixedBases::NullifierK;
+            let nullifier_k = FixedPoint::from_inner(ecc_chip.clone(), nullifier_k);
+            nullifier_k.mul_base_field(layouter.namespace(|| "[x_s] Nullifier"), secret_key)?
+        };
+
+        let (pub_x, pub_y) = (public_key.inner().x(), public_key.inner().y());
+
+        // =========
+        // Coin hash
+        // =========
+        let messages = [[pub_x, pub_y], [value, asset], [serial, coin_blind]];
+        let mut hashes = vec![];
+
+        for message in messages.iter() {
+            let hash = {
+                let poseidon_message = layouter.assign_region(
+                    || "load message",
+                    |mut region| {
+                        let mut message_word = |i: usize| {
+                            let value = message[i].value();
+                            let var = region.assign_advice(
+                                || format!("load message_{}", i),
+                                config.poseidon_config.state()[i],
+                                0,
+                                || value.ok_or(Error::SynthesisError),
+                            )?;
+                            region.constrain_equal(var, message[i].cell())?;
+                            Ok(Word::<_, _, P128Pow5T3, 3, 2>::from_inner(StateWord::new(
+                                var, value,
+                            )))
+                        };
+                        Ok([message_word(0)?, message_word(1)?])
+                    },
+                )?;
+
+                let poseidon_hasher = PoseidonHash::init(
+                    config.poseidon_chip(),
+                    layouter.namespace(|| "Poseidon init"),
+                    ConstantLength::<2>,
+                )?;
+
+                let poseidon_output = poseidon_hasher.hash(
+                    layouter.namespace(|| "Poseidon hash (a, b)"),
+                    poseidon_message,
+                )?;
+
+                let poseidon_output: CellValue<pasta::Fp> = poseidon_output.inner().into();
+                poseidon_output
+            };
+
+            hashes.push(hash);
+        }
+
+        let coin = layouter.assign_region(
+            || " `coin` = hash(a,b) + hash(c, d) + hash(e, f)",
+            |mut region| {
+                config.q_add.enable(&mut region, 0)?;
+
+                copy(&mut region, || "copy ab", config.advices[6], 0, &hashes[0])?;
+                copy(&mut region, || "copy cd", config.advices[7], 0, &hashes[1])?;
+                copy(&mut region, || "copy ef", config.advices[8], 0, &hashes[2])?;
+
+                let scalar_val = hashes[0]
+                    .value()
+                    .zip(hashes[1].value())
+                    .zip(hashes[2].value())
+                    .map(|(abcd, ef)| abcd.0 + abcd.1 + ef);
+
+                let cell = region.assign_advice(
+                    || "hash(a,b)+hash(c,d)+hash(e,f)",
+                    config.advices[5],
+                    0,
+                    || scalar_val.ok_or(Error::SynthesisError),
+                )?;
+                Ok(CellValue::new(cell, scalar_val))
+            },
+        )?;
+
         // ===========
         // Merkle root
         // ===========
-        let leaf = self.load_private(
-            layouter.namespace(|| "load leaf"),
-            config.advices[0],
-            self.leaf,
-        )?;
+        //let leaf = self.load_private(
+        //    layouter.namespace(|| "load leaf"),
+        //    config.advices[0],
+        //    self.leaf,
+        //)?;
 
         let path = MerklePath {
             chip_1: merkle_chip_1,
@@ -342,7 +444,7 @@ impl Circuit<pasta::Fp> for SpendContract {
         };
 
         let computed_final_root =
-            path.calculate_root(layouter.namespace(|| "calculate root"), leaf)?;
+            path.calculate_root(layouter.namespace(|| "calculate root"), coin)?;
 
         layouter.constrain_instance(
             computed_final_root.cell(),

+ 2 - 2
src/crypto/spend_proof.rs

@@ -132,6 +132,7 @@ pub fn create_spend_proof(
     serial: DrkSerial,
     coin_blind: DrkCoinBlind,
     secret: DrkSecretKey,
+    leaf_position: u64,
     merkle_path: Vec<MerkleNode>,
     signature_secret: DrkSecretKey,
 ) -> Result<(Proof, SpendRevealedValues)> {
@@ -159,8 +160,7 @@ pub fn create_spend_proof(
         coin_blind: Some(coin_blind),
         value_blind: Some(value_blind),
         asset_blind: Some(token_blind),
-        leaf: Some(pasta_curves::Fp::one()), // TODO:
-        leaf_pos: Some(0),                   // TODO:
+        leaf_pos: Some(leaf_position as u32),
         merkle_path: Some(merkle_path.try_into().unwrap()),
         sig_secret: Some(mod_r_p(signature_secret)),
     };

+ 2 - 1
src/tx/builder.rs

@@ -28,7 +28,7 @@ pub struct TransactionBuilderClearInputInfo {
 }
 
 pub struct TransactionBuilderInputInfo {
-    pub merkle_position: incrementalmerkletree::Position,
+    pub leaf_position: incrementalmerkletree::Position,
     pub merkle_path: Vec<MerkleNode>,
     pub secret: DrkSecretKey,
     pub note: Note,
@@ -96,6 +96,7 @@ impl TransactionBuilder {
                 input.note.serial,
                 input.note.coin_blind,
                 input.secret,
+                input.leaf_position.into(),
                 input.merkle_path,
                 signature_secret,
             )?;