mohab 4 жил өмнө
parent
commit
f67d309d41

+ 617 - 0
src/zk/circuit/lead_contract.rs

@@ -0,0 +1,617 @@
+use halo2_gadgets::{
+    ecc::{
+        chip::{EccChip, EccConfig},
+        FixedPoint, FixedPointShort,NonIdentityPoint,Point
+    },
+    poseidon::{Hash as PoseidonHash, Pow5Chip as PoseidonChip, Pow5Config as PoseidonConfig},
+    primitives::poseidon::{ConstantLength, P128Pow5T3},
+    utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions},
+};
+
+use halo2_proofs::{
+    circuit::{AssignedCell, Layouter, SimpleFloorPlanner},
+    plonk,
+    plonk::{Advice, Circuit, Column, ConstraintSystem, Instance as InstanceColumn},
+};
+
+use pasta_curves::{pallas, Fp};
+
+use crate::crypto::constants::{
+    constants::{
+        util::gen_const_array,
+    },
+    OrchardFixedBases, OrchardFixedBasesFull, ValueCommitV,
+};
+
+use create::zk::{
+    arith_chip::{ArithmeticChipConfig, ArithmeticChip},
+    GreaterThanChip, GreatherThanConfig,
+};
+
+#[derive(Clone,Debug)]
+pub struct LeadConfig
+{
+    primary: Column<InstanceColumn>,
+    advices: [Column<Advice>;19],
+    ecc_config: EccConfig<OrchardFixedBases>,
+    poseidon_config: PoseidonConfig<pallas::Base,3,2>,
+    merkle_config_1: MerkleConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
+    merkle_config_2: MerkleConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
+    sinsemilla_config_1: SinsemillaConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
+    sinsemilla_config_2: SinsemillaConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
+    greaterthan_config: GreaterThanConfig,
+    arith_config: ArithmeticChipConfig,
+}
+
+//TODO what is the pederson commitment pallas order number of bits?
+const COMMIT_GROUP_ORDER_BITS : usize = 264;
+
+impl LeadConfig
+{
+    fn ecc_chip(&self) -> EccChip<OrchardFixedBass>
+    {
+        EccChip::construct(self.ecc_config.clone())
+    }
+
+    fn poseidon_chip(&self) -> PoseidonChip<pallas::Base, 3, 2>
+    {
+        PoseidonChip::construct(self.poseidon_config.clone())
+    }
+
+    fn merkle_chip_1(
+        &self,
+    ) -> MerkleChip<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases> {
+        MerkleChip::construct(self.merkle_config_1.clone())
+    }
+
+    fn merkle_chip_2(
+        &self,
+    ) -> MerkleChip<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases> {
+        MerkleChip::construct(self.merkle_config_2.clone())
+    }
+
+    fn greaterthan_chip(&self) -> GreaterThanChip<pallas::Base, WORD_BITS> {
+        GreaterThanChip::construct(self.greaterthan_config.clone())
+    }
+
+    fn arith_chip(&self) -> ArithmeticChip {
+        ArithmeticChip::construct(self.arith_config.clone())
+    }
+}
+
+
+//
+const LEAD_COIN_PK_X_OFFSET: usize = 0;
+const LEAD_COIN_PK_y_OFFSET: usize = 1;
+//
+const LEAD_COIN_NONCE2_X_OFFSET: usize = 2;
+const LEAD_COIN_NONCE2_y_OFFSET: usize = 3;
+
+const LEAD_COIN_SERIAL_NUMBER_X_OFFSET: usize = 4;
+const LEAD_COIN_SERIAL_NUMBER_Y_OFFSET: usize = 5;
+//
+
+const LEAD_COIN2_SERIAL_NUMBER_X_OFFSET: usize = 8;
+const LEAD_COIN2_SERIAL_NUMBER_Y_OFFSET: usize = 9;
+//
+const LEAD_COIN_COMMIT_PATH_OFFSET: usize = 6;
+
+const LEAD_LEAD_THRESHOLD_OFFSET: usize = 7;
+
+#[derive(Debug,Default)]
+pub struct LeadContract
+{
+    // witness
+    pub path : Option<[MerkleNode;MERKLE_DEPTH_ORCHARD]>,
+    pub root_sk : Option<u32>, // coins merkle tree secret key of coin1
+    pub path_sk : Option<[MerkleNode; MERKLE_DEPTH_ORCHARD]>, // path to the secret key root_sk
+    pub coin_timestamp: Option<u32>,
+    pub coin_nonce : Option<u32>,
+    pub coin_opening_1 :Option<pallas::Base>,
+    pub value: Option<u32>,
+    pub coin_opening_2 :Option<pallas::Base>,
+    // public advices
+    pub cm_c2 : Option<NonIdentityPoint>,
+    pub sn_c1 : Option<u32>,
+    pub eta : Option<u32>, //TODO name, type
+    pub slot : Option<u32>,
+    pub rho : Option<u32>, //TODO name, type
+    pub h : Option<u32>, // hash of this data
+    pub ptr: Option<u32>, //hash of the previous block
+    pub mau_rho: Option<u32>, //TODO name, type
+    pub mau_y: Option<u32>, //TODO name, type
+    pub root : Option<u32>, //TODO name, type
+}
+
+impl UtilitiesInstruction<pallas::Base> for LeadContract {
+    type var = AssignedCell<Fp, Fp>;
+}
+
+impl circuit<pallas::Base> for LeadContract {
+    type Config = LeadConfig;
+    type FloorPlanner = SimpleFloorPlanner;
+
+    fn without_witness(&self) -> Self {
+        Self::default()
+    }
+
+    fn configure(meta: &mut ConstraintSystem<pallas::Base>) -> Self::Config {
+        let advices = [
+            meta.advice_column(),
+            meta.advice_column(),
+            meta.advice_column(),
+            meta.advice_column(),
+            meta.advice_column(),
+            meta.advice_column(),
+            meta.advice_column(),
+            meta.advice_column(),
+            meta.advice_column(),
+            meta.advice_column(),
+            meta.advice_column(),
+            meta.advice_column(),
+        ];
+
+        let table_idx = meta.lookup_table_column();
+        let lookup = (table_idx, meta.lookup_table_column(), meta.lookup_table_column());
+
+        let primary = meta.instance_column();
+        meta.enable_equality(primary);
+
+        for advice in advices.iter() {
+            meta.enable_equality(*advice);
+        }
+
+        let lagrange_coeffs = [
+            meta.fixed_column(),
+            meta.fixed_column(),
+            meta.fixed_column(),
+            meta.fixed_column(),
+            meta.fixed_column(),
+            meta.fixed_column(),
+            meta.fixed_column(),
+            meta.fixed_column(),
+            meta.fixed_column(),
+        ];
+
+        let rc_a = lagrange_coeffs[2..5].try_into().unwrap();
+        let rc_b = lagrange_coeffs[5..8].try_into().unwrap();
+
+        meta.enable_constant(laggrange_coeffs[0]);
+        let range_check = LookupRangeCheckConfig::configure(meta, advices[8], table_idx);
+
+
+        //TODO how many columns needed for the eccChip?
+        //i assumed 5 for constants/private_witnesses
+        let ecc_config = EccChip::<OrchardFixedBases>::configure(meta, advices, lagrange_coeffs, range_check);
+
+        let poseidon_config = PoseidonChip::configure<P128Pow5T3>(
+            meta,
+            advices[6..9].try_into().unwrap(),
+            advices[5],
+            rc_a,
+            rc_b,
+        );
+
+        let (sinsemilla_config_1, merkle_config_1) = {
+            let sinsemilla_config_1 = SinsemillaChip::configure(
+                meta,
+                advices[..5].try_into().unwrap(),
+                advices[6],
+                lagrange_coeffs[0],
+                lookup,
+                range_check,
+            );
+            let merkle_config_1 = MerkleChip::configure(meta, sinsemilla_config_1.clone());
+            (sinsemilla_config_1, merkle_config_1)
+        };
+
+        let (sinsemilla_config_2, merkle_config_2) = {
+            let sinsemilla_config_2 = SinsemillaChip::configure(
+                meta,
+                advices[5.9].try_into().unwrap(),
+                advices[7],
+                lagrange_coeffs[1],
+                lookup,
+                range_check,
+            );
+            let merkle_config_2 = MerkleChip::configure(meta, sinsemilla_config_2.clone());
+
+            (sinsemilla_config_2, merkle_config_2)
+        };
+
+        let  greaterthan_config = GreaterThanChip::<pallas::Base>::configure(meta, advices[10..11]);
+        let arith_config = ArithmeticChip::configure(meta);
+
+        LeadConfig {
+            primary,
+            advices,
+            ecc_config,
+            poseidon_config,
+            merkle_config_1,
+            merkle_config_2,
+            sinsemilla_config_1,
+            sinsemilla_config_2,
+            greaterthan_config,
+            arith_config,
+        }
+    }
+
+    fn synthesize(&self,
+                  config: Self::Config,
+                  mut layouter: impl Layouter<pallas::Base>,
+    ) -> Result<(),Error> {
+        SinsemillaChip::load(config.sinsemilla_config_1.clone(), &mut layouter)?;
+        let ecc_chip = config.ecc_chip();
+        let ar_chip = config.arith_chip();
+
+        // ===============
+        // load witnesses
+        // ===============
+
+        // coin_timestamp tau
+        let coin_timestamp = self.load_private(
+            layouter.namespace(|| "load coin time stamp"),
+            config.advices[0],
+            self.coin_timestamp,
+        )?;
+
+        // root of coin
+        let coin_root = self.load_private(
+            layouter.namespace(|| "load root coin"),
+            config.advices[0],
+            self.root_sk,
+        )?;
+
+        // coin nonce
+        let coin_nonce = self.load_private(
+            layouter.namespace(|| "load coin nonce"),
+            config.advices[0],
+            self.nonce,
+        )?;
+
+        let coin_opening_1 = self.load_private(
+            layouter.namespace(|| "load opening 1"),
+            config.advices[0],
+            self.coin_opening_1,
+        )?;
+
+        let coin_value = self.load_private(
+            layouter.namespace(|| "load opening 1"),
+            config.advices[0],
+            self.value,
+        )?;
+
+        let coin_opening_2 = self.load_private(
+            layouter.namespace(|| "load opening 2"),
+            config.advices[0],
+            self.coin_opening_2,
+        )?;
+
+        let cm_c2 = self.load_private(
+            layouter.namespace(|| ""),
+            config.advices[0],
+            self.cm_c2,
+        )?;
+
+        let sn_c1 = self.load_private(
+            layouter.namespace(|| ""),
+            config.advices[0],
+            self.sn_c1,
+        )?;
+
+        let eta = self.load_private(
+            layouter.namespace(|| ""),
+            config.advices[0],
+            self.eta,
+        )?;
+
+        let slot = self.load_private(
+            layouter.namespace(|| ""),
+            config.advices[0],
+            self.slot,
+        )?;
+
+        let rho = self.load_private(
+            layouter.namespace(|| ""),
+            config.advices[0],
+            self.rho,
+        )?;
+
+        let h = self.load_private(
+            layouter.namespace(|| ""),
+            config.advices[0],
+            self.h,
+        )?;
+
+        let ptr = self.load_private(
+            layouter.namespace(|| ""),
+            config.advices[0],
+            self.ptr,
+        )?;
+
+        let mau_rho = self.load_private(
+            layouter.namespace(|| ""),
+            config.advices[0],
+            self.mau_rho,
+        )?;
+
+        let mau_y = self.load_private(
+            layouter.namespace(|| ""),
+            config.advices[0],
+            self.mau_y,
+        )?;
+
+        let root = self.load_private(
+            layouter.namespace(|| ""),
+            config.advices[0],
+            self.root,
+        )?;
+
+        //TODO read the second coin commitment as constant(public input)
+        // in this case
+        //
+
+        // ===============
+        // coin 2 nonce
+        // ===============
+        // m*G_1
+        let (com, _ )  = {
+            let nonce2_commit_v = ValueCommitV;
+            let nonce2_commit_v = FixedPointShort::from_inner(ecc_chip.clone(), nonce2_commit_v);
+            nonce2_commit_v.mul(layouter.namespace(|| "coin_pk commit v"), (coin_nonce, one))?
+        };
+        // r*G_2
+        let (blind, _) = {
+            let nonce2_commit_r = OrchardFixedBasesFull::ValueCommitR;
+            let nonce2_commit_r = FixedPoint::from_inner(ecc_chip.clone(), nonce2_commit_r);
+            nonce2_commit_r.mul(layouter.namespace(|| "nonce2 commit R"), (coin_root.clone(), one))?
+        };
+        let coin2_nonce = com.add(layouter.namespace(|| "nonce2 commit"), &blind)?;
+        layouter.constrain_instance(
+            coin2_nonce.inner().x().cell(),
+            config.primary,
+            LEAD_COIN_PK_X_OFFSET,
+        )?;
+        // constrain coin's pub key y value
+        layouter.constrain_instance(
+            coin2_nonce.inner().y().cell(),
+            coinfig.primary,
+            CLEAD_COIN_PK_Y_OFFSET,
+        )?;
+        // ================
+        // coin public key constraints derived from the coin timestamp
+        // ================
+
+        // m*G_1
+        let (com, _ )  = {
+            let coin_pk_commit_v = ValueCommitV;
+            let coin_pk_commit_v = FixedPointShort::from_inner(ecc_chip.clone(), coin_pk_commit_v);
+            coin_timestamp_commit_v.mul(layouter.namespace(|| "coin_pk commit v"), (coin_timestamp, one))?
+        };
+        // r*G_2
+        let (blind, _) = {
+            let coin_pk_commit_r = OrchardFixedBasesFull::ValueCommitR;
+            let coin_pk_commit_r = FixedPoint::from_inner(ecc_chip.clone(), coin_pk_commit_r);
+            coin_timestamp_commit_r.mul(layouter.namespace(|| "coin_pk commit R"), (coin_root.clone(), one))?
+        };
+        let coin_pk_commit = com.add(layouter.namespace(|| "coin timestamp commit"), &blind)?;
+        // constrain coin's pub key x value
+        layouter.constrain_instance(
+            coin_pk_commit.inner().x().cell(),
+            config.primary,
+            LEAD_COIN_PK_X_OFFSET,
+        )?;
+        // constrain coin's pub key y value
+        layouter.constrain_instance(
+            coin_pk_commit.inner().y().cell(),
+            coinfig.primary,
+            CLEAD_COIN_PK_Y_OFFSET,
+        )?;
+
+        // =================
+        // nonce constraints derived from previous coin's nonce
+        // =================
+
+
+        // =============
+        // constrain coin c1 serial number
+        // =============
+        // m*G_1
+        let (com, _ )  = {
+            let sn_commit_v = ValueCommitV;
+            let sn_commit_v = FixedPointShort::from_inner(ecc_chip.clone(), sn_commit_v);
+            sn_commit_v.mul(layouter.namespace(|| "coin serial number commit v"), (coin_nonce, one))?
+        };
+        // r*G_2
+        let (blind, _) = {
+            let sn_commit_r = OrchardFixedBasesFull::ValueCommitR;
+            let sn_commit_r = FixedPoint::from_inner(ecc_chip.clone(), sn_commit_r);
+            sn_commit_r.mul(layouter.namespace(|| "coin serial number commit R"), (coin_root.clone(), one))?
+        };
+        //
+        let sn_commit = com.add(layouter.namespace(|| "nonce commit"), &blind)?;
+        // constrain coin's pub key x value
+        layouter.constrain_instance(
+            sn_commit.inner().x().cell(),
+            config.primary,
+            LEAD_COIN_SERIAL_NUMBER_X_OFFSET,
+        )?;
+        // constrain coin's pub key y value
+        layouter.constrain_instance(
+            nonce_commit.inner().y().cell(),
+            coinfig.primary,
+            LEAD_COIN_SERIAL_NUMBER_X_OFFSET,
+        )?;
+
+        // ==========================
+        // commitment of coins c1,c2
+        // ==========================
+        //TODO should the reward be added to new minted coin?
+        // read the commitment
+        // concatenate message
+        // subtract those cm and commit output, constraint the output, that should equal 1.
+        //
+        //TODO this proof need to be for the two coins commitment,
+        // but cm1 doesn't exist in public inputs, or witnesses,
+        // does it make sense to calculate cm1, and proof decomm(cm1, coin2, r2)=true?
+        // that doesn't make any sense!
+        // this is the proof for the second commitment only
+        //TODO does both coins have the same value?!! doesn't make sense
+        //but only single value is in witness.
+        //let coin_tup = [coin_pk_commit, coin_value, coin2_nonce];
+        //TODO this should be the concat of coin_tup
+        let coin_ = ar_chip.add(layouter.namespace(|| ""), (coin_pk_commit, coin_value))?;
+        let coin = ar_chip.add(layouter.namespace(|| ""), (coin_, coin_nonce))?;
+        let (com, _ )  = {
+            let coin_commit_v = ValueCommitV;
+            let coin_commit_v = FixedPointShort::from_inner(ecc_chip.clone(), coin_commit_v);
+            sn_commit_v.mul(layouter.namespace(|| "coin commit v"), (coin, one))?
+        };
+        // r*G_2
+        let (blind, _) = {
+            let sn_commit_r = OrchardFixedBasesFull::ValueCommitR;
+            let sn_commit_r = FixedPoint::from_inner(ecc_chip.clone(), coin_opening_1);
+            sn_commit_r.mul(layouter.namespace(|| "coin serial number commit R"), (coin_root, one))?
+        };
+        let coin_commit = com.add(layouter.namespace(|| "nonce commit"), &blind)?;
+        //TODO it would be better if you coin1_commit +  -1*cm_c2 and constraint 0 (output)
+        // constrain coin's pub key x value
+        layouter.constrain_instance(
+            coin_commit.inner().x().cell(),
+            config.primary,
+            LEAD_COIN_SERIAL_NUMBER_X_OFFSET,
+        )?;
+        // constrain coin's pub key y value
+        layouter.constrain_instance(
+            coin_commit.inner().y().cell(),
+            config.primary,
+            LEAD_COIN_SERIAL_NUMBER_X_OFFSET,
+        )?;
+        //=========================
+        let coin = ar_chip.add(layouter.namespace(|| ""), (coin_, coin2_nonce))?;
+        let (com, _ )  = {
+            let coin_commit_v = ValueCommitV;
+            let coin_commit_v = FixedPointShort::from_inner(ecc_chip.clone(), coin_commit_v);
+            sn_commit_v.mul(layouter.namespace(|| "coin commit v"), (coin, one))?
+        };
+        // r*G_2
+        let (blind, _) = {
+            let r = self.root_sk;
+            let sn_commit_r = OrchardFixedBasesFull::ValueCommitR;
+            let sn_commit_r = FixedPoint::from_inner(ecc_chip.clone(), coin_opening_2);
+            sn_commit_r.mul(layouter.namespace(|| "coin serial number commit R"), r)?
+        };
+        let coin2_commit = com.add(layouter.namespace(|| "nonce commit"), &blind)?;
+        layouter.constrain_instance(
+            coin2_commit.inner().x().cell(),
+            config.primary,
+            LEAD_COIN2_SERIAL_NUMBER_X_OFFSET,
+        )?;
+        // constrain coin's pub key y value
+        layouter.constrain_instance(
+            coin2_commit.inner().y().cell(),
+            config.primary,
+            LEAD_COIN2_SERIAL_NUMBER_X_OFFSET,
+        )?;
+        //TODO you need to add this coin1_commit to the tree and return rooted by self.root,
+        // and return the position coin1_commit_pos
+        let coin1_commit_pos : u32 = 0;
+        // ===========================
+        let path: Option<[pallas::Base; MERKLE_DEPTH_ORCHARD]> =
+            self.path.map(|typed_path| gen_const_array(|i| typed_path[i].inner()));
+
+        let merkle_inputs = MerklePath::construct(
+            config.merkle_chip_1(),
+            config.merkle_chip_2(),
+            OrchardHashDomains::MerkleCrh,
+            coin1_commit_pos,
+            path,
+        );
+
+        let computed_final_root =
+            merkle_inputs.calculate_root(layouter.namespace(|| "calculate root"), coin1_commit)?;
+
+        layouter.constrain_instance(
+            computed_final_root.cell(),
+            config.primary,
+            LEAD_COIN_COMMIT_PATH_OFFSET,
+        )?;
+        // =============================
+        /*
+        let path: Option<[pallas::Base; MERKLE_DEPTH_ORCHARD]> =
+            self.path_sk.map(|typed_path| gen_const_array(|i| typed_path[i].inner()));
+
+        let merkle_inputs = MerklePath::construct(
+            config.merkle_chip_1(),
+            config.merkle_chip_2(),
+            OrchardHashDomains::MerkleCrh,
+            self.slot - self.coin_timestamp,
+            path,
+        );
+
+        //TODO fix this is a path to a leaf, i have no clue of that leaf
+        let computed_final_root =
+            merkle_inputs.calculate_root(layouter.namespace(|| "calculate root"), coin1_commit)?;
+
+        layouter.constrain_instance(
+            computed_final_root.cell(),
+            config.primary,
+            LEAD_COIN_COMMIT_PATH_OFFSET,
+        )?;
+         */
+        // ============================
+        // constrain y
+        //
+        let message = ar_chip.add(layouter.namespace(|| ""), root_sk, coin_nonce)?;
+        let (com, _ )  = {
+            //TODO concatenate message
+            //TODO message need to be eccchip::var
+            //let message = [root_sk, coin_nonce];
+            let y_commit_v = ValueCommitV;
+            let y_commit_v = FixedPointShort::from_inner(ecc_chip.clone(), y_commit_v);
+            y_commit_v.mul(layouter.namespace(|| "coin commit v"), (message.clone(), one))?
+        };
+        // r*G_2
+        let (blind, _) = {
+            //let r = mau_y;
+            let y_commit_r = OrchardFixedBasesFull::ValueCommitR;
+            let y_commit_r = FixedPoint::from_inner(ecc_chip.clone(), y_commit_r);
+            y_commit_r.mul(layouter.namespace(|| "coin serial number commit R"), (mau_y, one))?
+        };
+        let y_commit = com.add(layouter.namespace(|| "nonce commit"), &blind)?;
+        // ============================
+        // constraint rho
+        //
+        let (com, _ )  = {
+            //TODO concatenate message
+            //TODO message need to be eccchip::var
+            //let message = [root_sk, coin_nonce];
+            let y_commit_v = ValueCommitV;
+            let y_commit_v = FixedPointShort::from_inner(ecc_chip.clone(), y_commit_v);
+            y_commit_v.mul(layouter.namespace(|| "coin commit v"), (message.clone(), one))?
+        };
+        // r*G_2
+        let (blind, _) = {
+            let r = mau_rho;
+            let y_commit_r = OrchardFixedBasesFull::ValueCommitR;
+            let y_commit_r = FixedPoint::from_inner(ecc_chip.clone(), y_commit_r);
+            y_commit_r.mul(layouter.namespace(|| "coin serial number commit R"), r)?
+        };
+        let rho_commit = com.add(layouter.namespace(|| "nonce commit"), &blind)?;
+
+        // ===========================
+        // lead statment
+        // ===========================
+        let scalar = pallas::Scalar::from(1024);
+        let c = pallas::Scalar::from(3); // leadership coefficient
+        let target = ar_chip.mul(layouter.namespace(|| "calculate target"), scalar, value)?;
+
+        let greater_than_chip = config.greaterthan_config();
+        greater_than_chip.greater_than(layouter.namespace("t>y"), target , y_commit);
+        layouter.constrain_instance(
+            greater_than_chip.cell(),
+            config.primary,
+            LEAD_LEAD_THRESHOLD_OFFSET,
+        )?;
+    }
+}