diff --git a/Cargo.toml b/Cargo.toml index 1bd7d71..c7a2507 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,9 @@ name = "linar" version = "0.1.0" edition = "2021" +[features] +dev-graph = ["halo2_proofs/dev-graph", "plotters", "plotters/bitmap_backend","plotters/bitmap_encoder"] + [dependencies] hex = "0.4" sha2 = "0.10.8" @@ -15,5 +18,8 @@ bs58 = "0.5.0" secp256k1 ={ version = "0.28.0",features = ["rand-std"] } ripemd = "0.1.3" rand = "0.8" -halo2_gadgets = "0.3.0" -ecies = "0.2.6" \ No newline at end of file +halo2_gadgets = { version = "0.3.0",features = ["unstable-sha256-gadget"] } +ecies = "0.2.6" +halo2_proofs = "0.3.0" +plotters = { version = "0.3.0", default-features = true, optional = true } +pasta_curves = "0.5" \ No newline at end of file diff --git a/src/circuit.rs b/src/circuit.rs index deaedfe..19dc1e3 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -1,9 +1,16 @@ -use serde::{Deserialize, Serialize}; - use crate::coin::Coin; +use halo2_gadgets::sha256::{BlockWord,Bits,AssignedBits, Table16Chip, Table16Config}; +use halo2_proofs::{ + arithmetic::Field, + circuit::{AssignedCell, Layouter, SimpleFloorPlanner, Value}, + plonk::{Advice, Assigned, Circuit, Column, ConstraintSystem, Error, Instance, Selector}, + poly::Rotation, +}; +use pasta_curves::{arithmetic::CurveAffine, pallas, vesta}; +use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize)] -pub struct WitnessX { +pub struct InstanceX { pub rt: Vec, pub old_sn: Vec, pub new_cm: Vec, @@ -19,4 +26,147 @@ pub struct WitnessA { pub new_coin: Coin, } -pub fn create_proof(x: WitnessX, a: WitnessA) -> Vec {} +pub fn create_proof(x: &InstanceX, a: &WitnessA) -> Vec { + vec![] +} + +#[derive(Debug, Clone)] +struct CircuitConfig { + advice: Column, + instance: Column, + sha_config: Table16Config, +} + +#[derive(Default)] +struct PourCircuit { + pk: [BlockWord;16], + sk: [BlockWord;8], +} + +impl PourCircuit { + fn load_private( + &self, + config: &CircuitConfig, + mut layouter: impl Layouter, + values: [BlockWord;16] + ) -> Result>, Error> { + layouter.assign_region( + || "assign private values", + |mut region| { + values + .iter() + .enumerate() + .map(|(i, value)| { + // Check that each cell of the input is a binary value + // Assign the private input value to an advice cell + region + .assign_advice(|| "assign private input", config.advice, i, || -> Bits<32> {value.0.into()}) + } + ) + .collect() + } + ) + } +} + + +impl Circuit for PourCircuit { + type Config = CircuitConfig; + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self::default() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let sha_config = Table16Chip::configure(meta); + + let advice = meta.advice_column(); + let instance = meta.instance_column(); + + meta.enable_equality(instance); + meta.enable_equality(advice); + + CircuitConfig { + advice, + instance, + sha_config, + } + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + Table16Chip::load(config.sha_config.clone(), &mut layouter)?; + let table16_chip = Table16Chip::construct(config.sha_config); + + let a = self.load_private(&config, layouter, self.pk); + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use halo2_proofs::{dev::MockProver, pasta::Fp}; + #[test] + fn test_chap_1() { + // ANCHOR: test-circuit + // The number of rows in our circuit cannot exceed 2^k. Since our example + // circuit is very small, we can pick a very small value here. + let k = 5; + + // Prepare the private and public inputs to the circuit! + let c = Fp::from(1); + let a = Fp::from(2); + let b = Fp::from(3); + let out = c * a.square() * b.square(); + println!("out=:{:?}", out); + + // Instantiate the circuit with the private inputs. + let circuit = PourCircuit {}; + + // Arrange the public input. We expose the multiplication result in row 0 + // of the instance column, so we position it there in our public inputs. + let mut public_inputs = vec![out]; + + // Given the correct public input, our circuit will verify. + let prover = MockProver::run(k, &circuit, vec![public_inputs.clone()]).unwrap(); + assert_eq!(prover.verify(), Ok(())); + + // If we try some other public input, the proof will fail! + public_inputs[0] += Fp::one(); + let prover = MockProver::run(k, &circuit, vec![public_inputs]).unwrap(); + assert!(prover.verify().is_err()); + println!("\n\n\n!!!!!OHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH!!!!!\n simple example success !\n!!!!!OHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH!!!!!\n\n\n") + // ANCHOR_END: test-circuit + } + + #[cfg(feature = "dev-graph")] + //cargo test plot_chap_1_circuit --features dev-graph + #[test] + fn plot_chap_1_circuit() { + // Instantiate the circuit with the private inputs. + let circuit = PourCircuit::::default(); + // Create the area you want to draw on. + // Use SVGBackend if you want to render to .svg instead. + use plotters::prelude::*; + let root = BitMapBackend::new("./chap_1_simple.png", (1024, 768)).into_drawing_area(); + root.fill(&WHITE).unwrap(); + let root = root + .titled("Simple Circuit without chip", ("sans-serif", 60)) + .unwrap(); + halo2_proofs::dev::CircuitLayout::default() + // You can optionally render only a section of the circuit. + // .view_width(0..2) + // .view_height(0..16) + // You can hide labels, which can be useful with smaller areas. + .show_labels(true) + // Render the circuit onto your area! + // The first argument is the size parameter for the circuit. + .render(5, &circuit, &root) + .unwrap(); + } +} diff --git a/src/coin.rs b/src/coin.rs index 0a4347b..9ca0a5f 100644 --- a/src/coin.rs +++ b/src/coin.rs @@ -12,14 +12,14 @@ pub struct Coin { } impl Coin { - pub fn new(public_key: String, value: u64) -> Self { + pub fn new(public_key: &String, value: u64) -> Self { let rho = generate_random_bytes(256); let r = generate_random_bytes(384); let k = Self::get_k_inner(public_key, &rho, &r); let cm = Self::get_cm(&k, value); Coin { - addr_pk: public_key, + addr_pk: public_key.clone(), rho, v: value, r, @@ -27,11 +27,11 @@ impl Coin { } } pub fn get_k(&self) -> Vec { - Self::get_k_inner(self.addr_pk, &self.rho, &self.r) + Self::get_k_inner(&self.addr_pk, &self.rho, &self.r) } //H(r || H(pk || rho)) - fn get_k_inner(public_key: String, rho: &Vec, r: &Vec) -> Vec { + fn get_k_inner(public_key: &String, rho: &Vec, r: &Vec) -> Vec { let public_key_bytes = hex::decode(public_key).expect("Failed to decode public key"); let secp = Secp256k1::new(); let public_key = PublicKey::from_slice(&public_key_bytes).expect("Invalid public key"); diff --git a/src/mint.rs b/src/mint.rs index 8e21014..87e81a6 100644 --- a/src/mint.rs +++ b/src/mint.rs @@ -15,7 +15,8 @@ pub fn mint(address: String, value: u64) -> (Coin, MintTransaction) { let wallets = Wallets::new(); let wallet = wallets.get_wallet(&address).unwrap(); - let c = Coin::new(wallet.public_key, value); + let c = Coin::new(&wallet.public_key, value); + let cm = c.cm(); let k = c.get_k(); ( c, @@ -24,7 +25,7 @@ pub fn mint(address: String, value: u64) -> (Coin, MintTransaction) { vout: TXMint { v: value, k, - cm: c.cm(), + cm: cm, }, }, ) diff --git a/src/pour.rs b/src/pour.rs index 8c79d85..6b7837f 100644 --- a/src/pour.rs +++ b/src/pour.rs @@ -1,5 +1,5 @@ use crate::{ - circuit::{self, WitnessA, WitnessX}, + circuit::{self, WitnessA, InstanceX}, coin::Coin, wallet::Wallet, wallets::Wallets, @@ -39,21 +39,21 @@ pub fn pour( let wallet_new = wallets.get_wallet(&new_address).unwrap(); let wallet_old = wallets.get_wallet(&old_adress).unwrap(); - let sn_msg = wallet_old.private_key.as_bytes().to_vec(); - sn_msg.extend(old_coin.rho); + let mut sn_msg = wallet_old.private_key.as_bytes().to_vec(); + sn_msg.extend(&old_coin.rho); let old_sn = Sha256::digest(sn_msg).to_vec(); - let c = Coin::new(wallet_new.public_key, new_value); + let c = Coin::new(&wallet_new.public_key, new_value); let c_info = create_c_info(&wallet_new.public_key, &c.rho, c.v, &c.r); let sig_wallet = Wallet::new(); let h_sig = Sha256::digest(&sig_wallet.public_key).to_vec(); - - let h_msg = wallet_old.private_key.as_bytes().to_vec(); - h_msg.extend(h_sig); + + let mut h_msg = wallet_old.private_key.as_bytes().to_vec(); + h_msg.extend(&h_sig); let h = Sha256::digest(h_msg).to_vec(); - let wx = WitnessX { + let wx = InstanceX { rt: merkle_root.clone(), old_sn: old_sn.clone(), new_cm: c.cm(), @@ -65,12 +65,12 @@ pub fn pour( path: merkle_path.clone(), old_coin: old_coin.clone(), secret_key: wallet_old.private_key.clone(), - new_coin: c, + new_coin: c.clone(), }; - let pi_pour = circuit::create_proof(wx, wa); + let pi_pour = circuit::create_proof(&wx, &wa); let sigma = create_sig(&sig_wallet.private_key, &wx, &pi_pour, &info, &c_info); - + let cm = c.cm(); ( c, PourTransaction { @@ -78,7 +78,7 @@ pub fn pour( vout: TXPour { rt: merkle_root.clone(), old_sn, - new_cm: c.cm(), + new_cm: cm, public_value, info, pk_sig: sig_wallet.public_key, @@ -102,14 +102,14 @@ fn create_c_info(public_key: &String, rho: &Vec, v: u64, r: &Vec) -> Vec fn create_sig( sk: &String, - x: &WitnessX, + x: &InstanceX, pi_pour: &Vec, info: &String, c_info: &Vec, ) -> Vec { let priv_key = secp256k1::SecretKey::from_slice(hex::decode(sk).unwrap().as_slice()).unwrap(); - let msg = serde_json::to_string(x).unwrap(); + let mut msg = serde_json::to_string(x).unwrap(); msg = format!("{}{:?}{}{:?}", msg, pi_pour, info, c_info); let sig_message = secp256k1::Message::from_digest_slice(&msg.as_bytes()).unwrap(); @@ -118,3 +118,7 @@ fn create_sig( .serialize_compact() .to_vec() } + +pub fn verify_pour(tx: &PourTransaction) -> bool { + false +}