diff --git a/Cargo.toml b/Cargo.toml index 597046f00..8450403c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -374,3 +374,8 @@ required-features = ["node"] name = "crypsinous" path = "example/crypsinous.rs" required-features = ["node"] + +[[example]] +name = "lessthan" +path = "example/less_than.rs" +required_features = ["node"] diff --git a/example/less_than.rs b/example/less_than.rs new file mode 100644 index 000000000..2b9c8c61d --- /dev/null +++ b/example/less_than.rs @@ -0,0 +1,154 @@ +use halo2_proofs::{ + arithmetic::FieldExt, + circuit::{AssignedCell, Chip, Layouter, Region, Value}, + pasta::pallas, + plonk::{Circuit, Advice, Column, ConstraintSystem, Error, Expression, Selector, TableColumn}, + poly::Rotation, + circuit::{floor_planner}, + dev::{CircuitLayout, MockProver}, +}; + + +use darkfi::{ + consensus::{utils::{fbig2base}, types::Float10}, + crypto::{Proof, proof::{ProvingKey, VerifyingKey}, }, + zk::gadget::{native_range_check::{NativeRangeCheckChip}, + less_than::{LessThanChip, LessThanConfig}}, + VerifyFailed +}; +use log::{info, error}; +use rand::rngs::OsRng; + +const WINDOW_SIZE : usize= 3; +const NUM_BITS : usize = 253; +const NUM_WINDOWS : usize =85; + +#[derive(Default)] +struct LessThanCircuit { + a: Value, + b: Value, +} + +impl Circuit for LessThanCircuit { + type Config = + (LessThanConfig, Column); + type FloorPlanner = floor_planner::V1; + + fn without_witnesses(&self) -> Self { + Self { a: Value::unknown(), b: Value::unknown() } + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let w = meta.advice_column(); + meta.enable_equality(w); + + let a = meta.advice_column(); + let b = meta.advice_column(); + let a_offset = meta.advice_column(); + let z1 = meta.advice_column(); + let z2 = meta.advice_column(); + + let k_values_table = meta.lookup_table_column(); + + let constants = meta.fixed_column(); + meta.enable_constant(constants); + + ( + LessThanChip::::configure( + meta, + a, + b, + a_offset, + z1, + z2, + k_values_table, + ), + w, + ) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + let less_than_chip = + LessThanChip::::construct( + config.0.clone(), + ); + + NativeRangeCheckChip::::load_k_table( + &mut layouter, + config.0.k_values_table, + )?; + + less_than_chip.witness_less_than( + layouter.namespace(|| "a < b"), + self.a, + self.b, + 0, + true, + )?; + Ok(()) + } +} + +fn simple_lessthan (k: u32) -> Result<(), halo2_proofs::plonk::Error>{ + let y : pallas::Base = pallas::Base::zero(); + let t : pallas::Base = pallas::Base::one(); + let circuit = LessThanCircuit { a: Value::known(y), b: Value::known(t) }; + + let prover = MockProver::run(k, &circuit, vec![]).unwrap(); + prover.assert_satisfied(); + assert!(prover.verify().is_ok()); + + let public_inputs : Vec = vec![]; + let pk = ProvingKey::build(k, &LessThanCircuit::default()); + let vk = VerifyingKey::build(k, &LessThanCircuit::default()); + let proof = Proof::create(&pk, &[circuit], &public_inputs, &mut OsRng)?; + match proof.verify(&vk, &public_inputs) { + Ok(()) => { + info!("proof verified"); + Ok(()) + }, + Err(e) => { + error!("verification failed: {}", e); + return Err(e) + } + } +} + +fn fullrange_lessthan (k: u32) -> Result<(), halo2_proofs::plonk::Error> { + let y_str : &'static str = "0x057eaec1c805d808f70c4e2d2f173c72d091e9c9f78b11dddf52d072c30951ad"; + let t_str : &'static str = "0x2cb8d8aec6766dc83595602e3050b0b908191bbe59dcc3d1e2b7020a37339a14"; + let y : pallas::Base = fbig2base(Float10::from_str_native(y_str).unwrap().with_precision(74).value()); + let t : pallas::Base = fbig2base(Float10::from_str_native(t_str).unwrap().with_precision(74).value()); + + let circuit = LessThanCircuit { a: Value::known(y), b: Value::known(t) }; + + let prover = MockProver::run(k, &circuit, vec![]).unwrap(); + prover.assert_satisfied(); + assert!(prover.verify().is_ok()); + + let public_inputs : Vec = vec![]; + let pk = ProvingKey::build(k, &LessThanCircuit::default()); + let vk = VerifyingKey::build(k, &LessThanCircuit::default()); + let proof = Proof::create(&pk, &[circuit], &public_inputs, &mut OsRng)?; + match proof.verify(&vk, &public_inputs) { + Ok(()) => { + info!("proof verified"); + Ok(()) + }, + Err(e) => { + error!("verification failed: {}", e); + return Err(e) + } + } +} + +fn main () { + env_logger::init(); + let k = 11; + let res_simple = simple_lessthan(k).unwrap(); + let res_fullrange = fullrange_lessthan(k).unwrap(); +} diff --git a/src/consensus/coins.rs b/src/consensus/coins.rs index ba41ae436..02268d931 100644 --- a/src/consensus/coins.rs +++ b/src/consensus/coins.rs @@ -239,10 +239,13 @@ fn create_leadcoin( //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(); + info!("coin pk [{}] x: {:?}", i, c_pk_x); + info!("coin pk [{}] y: {:?}", i, c_pk_y); let c_seed = pallas::Base::from(seed); let sn_msg = [c_seed, c_root_sk.inner(), zero.clone(), one.clone()]; @@ -289,7 +292,7 @@ fn create_leadcoin( let c_seed2: pallas::Base = poseidon::Hash::<_, poseidon::P128Pow5T3, poseidon::ConstantLength<4>, 3, 2>::init() .hash(coin_nonce2_msg); - + info!("coin2 seed [{}] : {:?}", i, c_seed2); let coin2_commit_msg_input = [pallas::Base::from(*PRF_NULLIFIER_PREFIX), *c_pk_x, *c_pk_y, c_v, c_seed2, one]; let coin2_commit_msg: pallas::Base = diff --git a/src/zk/circuit/lead_contract.rs b/src/zk/circuit/lead_contract.rs index e578ac6f8..0f6bcb57e 100644 --- a/src/zk/circuit/lead_contract.rs +++ b/src/zk/circuit/lead_contract.rs @@ -675,14 +675,7 @@ impl Circuit for LeadContract { info!("y: {:?}", y); info!("T: {:?}", T); - // Constrain y < target - lessthan_chip.copy_less_than( - layouter.namespace(|| "y < target"), - y_commit_base.clone(), - target, - 0, - true, - )?; + // Constrain derived `sn_commit` to be equal to witnessed `coin1_serial`. info!("coin1 cm root LHS: {:?}", coin1_cm_root.value()); info!("coin1 cm root RHS: {:?}", coin1_commit_root.value()); @@ -712,6 +705,8 @@ impl Circuit for LeadContract { // Constrain derived rho_commit to witnessed rho rho_commit.constrain_equal(layouter.namespace(|| "rho equality"), &rho)?; + info!("coin pk: x {:?}", coin_pk.inner().x()); + info!("coin pk: y {:?}", coin_pk.inner().y()); // Constrain coin's public key coordinates with public inputs layouter.constrain_instance( coin_pk.inner().x().cell(), @@ -723,6 +718,7 @@ impl Circuit for LeadContract { config.primary, LEADCOIN_PK_Y_OFFSET, )?; + info!("coin2 nonce: {:?}", coin2_nonce); // Constrain coin2_nonce with associated public input layouter.constrain_instance( coin2_nonce.cell(), @@ -737,6 +733,15 @@ impl Circuit for LeadContract { LEADCOIN_Y_BASE_OFFSET, )?; + // Constrain y < target + lessthan_chip.copy_less_than( + layouter.namespace(|| "y < target"), + y_commit_base.clone(), + target, + 0, + true, + )?; + Ok(()) } }