From eab39f4a6bb396c00aa34b5bf057137d398eb7c3 Mon Sep 17 00:00:00 2001 From: Nickqiaoo Date: Mon, 11 Dec 2023 17:20:54 +0800 Subject: [PATCH] feat:add pour --- Cargo.toml | 14 +++--- src/circuit.rs | 22 +++++++++ src/coin.rs | 77 +++++++++++++++++++++++++++++ src/main.rs | 4 ++ src/mint.rs | 67 ++++--------------------- src/pour.rs | 120 +++++++++++++++++++++++++++++++++++++++++++++ src/transaction.rs | 10 ++-- src/wallet.rs | 29 +++-------- 8 files changed, 253 insertions(+), 90 deletions(-) create mode 100644 src/circuit.rs create mode 100644 src/coin.rs create mode 100644 src/pour.rs diff --git a/Cargo.toml b/Cargo.toml index 4b7d8bc..1bd7d71 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,13 +5,15 @@ edition = "2021" [dependencies] hex = "0.4" -sha2 = "0.9.5" -num = "0.2" +sha2 = "0.10.8" +num = "0.4.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" sled = "0.34.6" structopt = "0.3" -bs58 = "0.4" -secp256k1 = "0.14" -ripemd160 = "0.8" -rand = "0.8" \ No newline at end of file +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 diff --git a/src/circuit.rs b/src/circuit.rs new file mode 100644 index 0000000..deaedfe --- /dev/null +++ b/src/circuit.rs @@ -0,0 +1,22 @@ +use serde::{Deserialize, Serialize}; + +use crate::coin::Coin; + +#[derive(Serialize, Deserialize)] +pub struct WitnessX { + pub rt: Vec, + pub old_sn: Vec, + pub new_cm: Vec, + pub public_value: u64, + pub h_sig: Vec, + pub h: Vec, +} + +pub struct WitnessA { + pub path: Vec>, + pub old_coin: Coin, + pub secret_key: String, + pub new_coin: Coin, +} + +pub fn create_proof(x: WitnessX, a: WitnessA) -> Vec {} diff --git a/src/coin.rs b/src/coin.rs new file mode 100644 index 0000000..0a4347b --- /dev/null +++ b/src/coin.rs @@ -0,0 +1,77 @@ +use rand::Rng; +use secp256k1::{PublicKey, Secp256k1}; +use sha2::{Digest, Sha256}; + +#[derive(Clone)] +pub struct Coin { + addr_pk: String, + pub rho: Vec, + pub v: u64, + pub r: Vec, + cm: Vec, +} + +impl Coin { + 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, + rho, + v: value, + r, + cm, + } + } + pub fn get_k(&self) -> Vec { + 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 { + 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"); + + let mut combined_data = Vec::new(); + combined_data.extend_from_slice(&public_key.serialize_uncompressed()); + combined_data.extend(rho); + + let midk = Sha256::digest(&combined_data).to_vec(); + let truncated_hash: Vec = midk.iter().take(128 / 8).cloned().collect(); + + combined_data = Vec::new(); + combined_data.extend(truncated_hash); + combined_data.extend(r); + + Sha256::digest(&combined_data).to_vec() + } + + pub fn cm(&self) -> Vec { + self.cm.clone() + } + + pub fn get_cm(k: &Vec, v: u64) -> Vec { + let zero_padding: Vec = vec![0; 192 / 8]; + + let mut combined_data = Vec::new(); + combined_data.extend(k); + combined_data.extend(zero_padding); + combined_data.extend_from_slice(&v.to_be_bytes()); + + Sha256::digest(&combined_data).to_vec() + } +} + +pub fn generate_random_bytes(bits: usize) -> Vec { + let mut rng = rand::thread_rng(); + + let byte_count = (bits + 7) / 8; + + let random_bytes: Vec = (0..byte_count).map(|_| rng.gen()).collect(); + + random_bytes +} diff --git a/src/main.rs b/src/main.rs index 74d62a1..db390e2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,8 +2,12 @@ use structopt::StructOpt; mod block; mod blockchain; +mod circuit; mod cli; +mod coin; mod iterator; +mod mint; +mod pour; mod pow; mod transaction; mod transaction_input; diff --git a/src/mint.rs b/src/mint.rs index e57ca69..8e21014 100644 --- a/src/mint.rs +++ b/src/mint.rs @@ -1,15 +1,4 @@ -use secp256k1::{PublicKey, Secp256k1}; -use sha2::{Digest, Sha256}; - -use crate::{util, wallets::Wallets}; - -pub struct Coin { - addr_pk: String, - rho: Vec, - v: u64, - r: Vec, - cm: Vec, -} +use crate::{coin::Coin, wallets::Wallets}; pub struct TXMint { v: u64, @@ -26,60 +15,22 @@ pub fn mint(address: String, value: u64) -> (Coin, MintTransaction) { let wallets = Wallets::new(); let wallet = wallets.get_wallet(&address).unwrap(); - let rho = util::generate_random_bytes(256); - let r = util::generate_random_bytes(384); - - let k = create_k(wallet.public_key, &rho, &r); - let cm = create_cm(&k, value); - - let c = Coin { - addr_pk: wallet.public_key, - rho, - v: value, - r, - cm, - }; + let c = Coin::new(wallet.public_key, value); + let k = c.get_k(); ( c, MintTransaction { id: vec![], - vout: TXMint { v: value, k, cm }, + vout: TXMint { + v: value, + k, + cm: c.cm(), + }, }, ) } -//H(r || H(pk || rho)) -fn create_k(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"); - - let mut combined_data = Vec::new(); - combined_data.extend_from_slice(&public_key.serialize_uncompressed()); - combined_data.extend_from_slice(&rho); - - let midk = Sha256::digest(&combined_data).to_vec(); - let truncated_hash: Vec = midk.iter().take(128 / 8).cloned().collect(); - - combined_data = Vec::new(); - combined_data.extend_from_slice(&truncated_hash); - combined_data.extend_from_slice(&r); - - Sha256::digest(&combined_data).to_vec() -} - -fn create_cm(k: &Vec, v: u64) -> Vec { - let zero_padding: Vec = vec![0; 192 / 8]; - - let mut combined_data = Vec::new(); - combined_data.extend_from_slice(&k); - combined_data.extend_from_slice(&zero_padding); - combined_data.extend_from_slice(&v.to_be_bytes()); - - Sha256::digest(&combined_data).to_vec() -} - pub fn verify_mint(tx: &MintTransaction) -> bool { - let cm = create_cm(&tx.vout.k, tx.vout.v); + let cm = Coin::get_cm(&tx.vout.k, tx.vout.v); cm == tx.vout.cm } diff --git a/src/pour.rs b/src/pour.rs new file mode 100644 index 0000000..8c79d85 --- /dev/null +++ b/src/pour.rs @@ -0,0 +1,120 @@ +use crate::{ + circuit::{self, WitnessA, WitnessX}, + coin::Coin, + wallet::Wallet, + wallets::Wallets, +}; +use ecies::{decrypt, encrypt}; +use sha2::{Digest, Sha256}; + +pub struct TXPour { + rt: Vec, + old_sn: Vec, + new_cm: Vec, + public_value: u64, + info: String, + pk_sig: String, + h: Vec, + pi_pour: Vec, + c_info: Vec, + sigma: Vec, +} + +pub struct PourTransaction { + pub id: Vec, + pub vout: TXPour, +} + +pub fn pour( + merkle_root: &Vec, + old_coin: &Coin, + old_adress: String, + merkle_path: &Vec>, + new_value: u64, + new_address: String, + public_value: u64, + info: String, +) -> (Coin, PourTransaction) { + let wallets = Wallets::new(); + 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 old_sn = Sha256::digest(sn_msg).to_vec(); + + 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 h = Sha256::digest(h_msg).to_vec(); + + let wx = WitnessX { + rt: merkle_root.clone(), + old_sn: old_sn.clone(), + new_cm: c.cm(), + public_value, + h_sig: h_sig.clone(), + h: h.clone(), + }; + let wa = WitnessA { + path: merkle_path.clone(), + old_coin: old_coin.clone(), + secret_key: wallet_old.private_key.clone(), + new_coin: c, + }; + + let pi_pour = circuit::create_proof(wx, wa); + let sigma = create_sig(&sig_wallet.private_key, &wx, &pi_pour, &info, &c_info); + + ( + c, + PourTransaction { + id: vec![], + vout: TXPour { + rt: merkle_root.clone(), + old_sn, + new_cm: c.cm(), + public_value, + info, + pk_sig: sig_wallet.public_key, + h, + pi_pour, + c_info, + sigma, + }, + }, + ) +} + +fn create_c_info(public_key: &String, rho: &Vec, v: u64, r: &Vec) -> Vec { + let mut message = Vec::new(); + message.extend(rho); + message.extend(&v.to_be_bytes().to_vec()); + message.extend(r); + + encrypt(public_key.as_bytes(), &message).unwrap() +} + +fn create_sig( + sk: &String, + x: &WitnessX, + 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(); + msg = format!("{}{:?}{}{:?}", msg, pi_pour, info, c_info); + let sig_message = secp256k1::Message::from_digest_slice(&msg.as_bytes()).unwrap(); + + let secp = secp256k1::Secp256k1::new(); + secp.sign_ecdsa(&sig_message, &priv_key) + .serialize_compact() + .to_vec() +} diff --git a/src/transaction.rs b/src/transaction.rs index 799d543..47b27a9 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -93,9 +93,9 @@ impl Transaction { tx_copy.id = tx_copy.hash(); tx_copy.vin[in_id].pub_key = vec![]; - let tx_copy_message = secp256k1::Message::from_slice(&tx_copy.id).unwrap(); + let tx_copy_message = secp256k1::Message::from_digest_slice(&tx_copy.id).unwrap(); let context = secp256k1::Secp256k1::new(); - let signature = context.sign(&tx_copy_message, &private_key); + let signature = context.sign_ecdsa(&tx_copy_message, &private_key); let sig = signature.serialize_compact(); self.vin[in_id].signature = sig.to_vec(); @@ -113,14 +113,14 @@ impl Transaction { tx_copy.id = tx_copy.hash(); tx_copy.vin[in_id].pub_key = vec![]; - let tx_copy_message = secp256k1::Message::from_slice(&tx_copy.id).unwrap(); + let tx_copy_message = secp256k1::Message::from_digest_slice(&tx_copy.id).unwrap(); let pk = secp256k1::PublicKey::from_slice(hex::decode(&vin.pub_key).unwrap().as_slice()) .unwrap(); - let sig = secp256k1::Signature::from_compact(&vin.signature).unwrap(); - if secp.verify(&tx_copy_message, &sig, &pk).is_err() { + let sig = secp256k1::ecdsa::Signature::from_compact(&vin.signature).unwrap(); + if secp.verify_ecdsa(&tx_copy_message, &sig, &pk).is_err() { return false; } } diff --git a/src/wallet.rs b/src/wallet.rs index 161935a..0ec48b5 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -1,8 +1,8 @@ -use rand::Rng; -use ripemd160::{Digest as RipemdDigest, Ripemd160}; -use secp256k1::{PublicKey, Secp256k1, SecretKey}; +use ripemd::{Digest as RipemdDigest, Ripemd160}; +use secp256k1::rand::rngs::OsRng; +use secp256k1::Secp256k1; use serde::{Deserialize, Serialize}; -use sha2::{Digest, Sha256}; +use sha2::Sha256; const VERSION: u8 = 0x00; pub(crate) const CHECKSUM_LENGTH: usize = 4; @@ -15,10 +15,11 @@ pub struct Wallet { impl Wallet { pub fn new() -> Wallet { - let (private_key, public_key) = new_key_pair(); + let secp = Secp256k1::new(); + let (private_key, public_key) = secp.generate_keypair(&mut OsRng); Wallet { - private_key: private_key.to_string(), + private_key: hex::encode(private_key.secret_bytes()), public_key: public_key.to_string(), } } @@ -43,24 +44,10 @@ pub fn validate_address(address: &String) -> bool { actual_checksum == target_checksum } -pub fn new_key_pair() -> (SecretKey, PublicKey) { - let secp = Secp256k1::new(); - let mut rng = rand::thread_rng(); - loop { - let private_key_candidate = SecretKey::from_slice(&rng.gen::<[u8; 32]>()); - if let Ok(private_key) = private_key_candidate { - let public_key = PublicKey::from_secret_key(&secp, &private_key); - return (private_key, public_key); - } - } -} - pub fn hash_pub_key(pub_key: &[u8]) -> Vec { let pub_key_sha256 = Sha256::digest(pub_key); - let mut ripemd160 = Ripemd160::new(); - ripemd160.input(pub_key_sha256); - ripemd160.result().to_vec() + Ripemd160::digest(pub_key_sha256).to_vec() } pub fn checksum(payload: &[u8]) -> Vec {