From ff01e7b685c4baefbf2c1ef76f93c115e59dbe6d Mon Sep 17 00:00:00 2001 From: parazyd Date: Thu, 2 Dec 2021 19:03:34 +0100 Subject: [PATCH] Use the new keypair module throughout the codebase. --- src/bin/cashierd.rs | 29 ++++--- src/bin/darkfid.rs | 14 +-- src/bin/tx2.rs | 27 +++--- src/circuit/spend_contract.rs | 18 ++-- src/client.rs | 37 ++++---- src/crypto/coin.rs | 4 - src/crypto/diffie_hellman.rs | 17 ++-- src/crypto/keypair.rs | 158 +++++++++++++++++++++++++++++----- src/crypto/mint_proof.rs | 41 ++++----- src/crypto/mod.rs | 5 +- src/crypto/note.rs | 27 +++--- src/crypto/nullifier.rs | 5 +- src/crypto/pasta_serial.rs | 69 --------------- src/crypto/schnorr.rs | 98 ++++++++------------- src/crypto/spend_proof.rs | 38 ++++---- src/service/bridge.rs | 15 ++-- src/service/btc.rs | 4 +- src/service/eth.rs | 8 +- src/service/sol.rs | 8 +- src/state.rs | 37 ++++---- src/tx/builder.rs | 19 ++-- src/tx/mod.rs | 4 +- src/tx/partial.rs | 4 +- src/util/address.rs | 14 +-- src/util/token_list.rs | 16 ++-- src/wallet/cashierdb.rs | 33 ++++--- src/wallet/mod.rs | 4 - src/wallet/walletdb.rs | 45 +++++----- 28 files changed, 421 insertions(+), 377 deletions(-) delete mode 100644 src/crypto/pasta_serial.rs diff --git a/src/bin/cashierd.rs b/src/bin/cashierd.rs index 67080444d..42d700eed 100644 --- a/src/bin/cashierd.rs +++ b/src/bin/cashierd.rs @@ -7,7 +7,7 @@ use clap::clap_app; use easy_parallel::Parallel; use incrementalmerkletree::bridgetree::BridgeTree; use log::{debug, info}; -use pasta_curves::pallas; +use rand::rngs::OsRng; use serde_json::{json, Value}; use drk::{ @@ -15,7 +15,11 @@ use drk::{ circuit::{MintContract, SpendContract}, cli::{CashierdConfig, Config}, client::Client, - crypto::{merkle_node::MerkleNode, proof::VerifyingKey, schnorr}, + crypto::{ + keypair::{PublicKey, SecretKey}, + merkle_node::MerkleNode, + proof::VerifyingKey, + }, rpc::{ jsonrpc::{error as jsonerr, response as jsonresp, ErrorCode::*, JsonRequest, JsonResult}, rpcserver::{listen_and_serve, RequestHandler, RpcServerConfig}, @@ -25,7 +29,10 @@ use drk::{ state::State, types::DrkTokenId, util::{expand_path, generate_id, join_config_path, parse::truncate, NetworkName}, - wallet::{cashierdb::TokenKey, CashierDb, WalletDb}, + wallet::{ + cashierdb::{CashierDb, TokenKey}, + walletdb::WalletDb, + }, Error, Result, }; @@ -103,7 +110,7 @@ impl Cashierd { async fn listen_for_receiving_coins( bridge: Arc, cashier_wallet: Arc, - recv_coin: async_channel::Receiver<(pallas::Point, u64)>, + recv_coin: async_channel::Receiver<(PublicKey, u64)>, executor: Arc>, ) -> Result<()> { // received drk coin @@ -208,7 +215,7 @@ impl Cashierd { mint_address = ""; } let drk_pub_key = bs58::decode(&drk_pub_key).into_vec()?; - let drk_pub_key: pallas::Point = deserialize(&drk_pub_key)?; + let drk_pub_key: PublicKey = deserialize(&drk_pub_key)?; // check if the drk public key already exist let check = self @@ -336,7 +343,7 @@ impl Cashierd { let address = serialize(&address.to_string()); - let cashier_public: pallas::Point; + let cashier_public: PublicKey; if let Some(addr) = self .cashier_wallet @@ -345,14 +352,14 @@ impl Cashierd { { cashier_public = addr.public; } else { - let cashier_secret = schnorr::SecretKey::random(); - cashier_public = cashier_secret.public_key().inner(); + let cashier_secret = SecretKey::random(&mut OsRng); + cashier_public = PublicKey::from_secret(cashier_secret); self.cashier_wallet .put_withdraw_keys( &address, &cashier_public, - &cashier_secret.inner(), + &cashier_secret, &network, &token_id, mint_address.into(), @@ -601,7 +608,7 @@ impl Cashierd { client.start().await?; - let (notify, recv_coin) = async_channel::unbounded::<(pallas::Point, u64)>(); + let (notify, recv_coin) = async_channel::unbounded::<(PublicKey, u64)>(); client .connect_to_subscriber_from_cashier( @@ -703,9 +710,9 @@ async fn start( tree: BridgeTree::::new(100), merkle_roots, nullifiers, + public_keys: cashier_public_keys, mint_vk, spend_vk, - public_keys: cashier_public_keys, })); if get_address_flag { diff --git a/src/bin/darkfid.rs b/src/bin/darkfid.rs index 3bf509526..843ffacab 100644 --- a/src/bin/darkfid.rs +++ b/src/bin/darkfid.rs @@ -17,7 +17,7 @@ use drk::{ circuit::{MintContract, SpendContract}, cli::{Config, DarkfidConfig}, client::Client, - crypto::{merkle_node::MerkleNode, proof::VerifyingKey}, + crypto::{keypair::PublicKey, merkle_node::MerkleNode, proof::VerifyingKey}, rpc::{ jsonrpc::{ error as jsonerr, request as jsonreq, response as jsonresp, send_raw_request, @@ -31,7 +31,7 @@ use drk::{ assign_id, decode_base10, encode_base10, expand_path, join_config_path, DrkTokenList, NetworkName, TokenList, }, - wallet::WalletDb, + wallet::walletdb::WalletDb, Error, Result, }; @@ -39,7 +39,7 @@ use drk::{ pub struct Cashier { pub name: String, pub rpc_url: String, - pub public_key: pallas::Point, + pub public_key: PublicKey, } #[async_trait] @@ -424,7 +424,7 @@ impl Darkfid { let result: Result<()> = async { let cashier_public = cashier_public.result.as_str().unwrap(); - let cashier_public: pallas::Point = + let cashier_public: PublicKey = deserialize(&bs58::decode(cashier_public).into_vec()?)?; self.client @@ -509,7 +509,7 @@ impl Darkfid { let result: Result<()> = async { let drk_address = bs58::decode(&address).into_vec()?; - let drk_address: pallas::Point = deserialize(&drk_address)?; + let drk_address: PublicKey = deserialize(&drk_address)?; let decimals: usize = 8; let amount = decode_base10(amount, decimals, true)?; @@ -546,7 +546,7 @@ async fn start( let mut cashier_keys = Vec::new(); if let Some(cpub) = local_cashier { - let cashier_public: pallas::Point = deserialize(&bs58::decode(cpub).into_vec()?)?; + let cashier_public: PublicKey = deserialize(&bs58::decode(cpub).into_vec()?)?; cashiers.push(Cashier { name: "localCashier".into(), @@ -561,7 +561,7 @@ async fn start( return Err(Error::CashierKeysNotFound) } - let cashier_public: pallas::Point = + let cashier_public: PublicKey = deserialize(&bs58::decode(cashier.public_key).into_vec()?)?; cashiers.push(Cashier { diff --git a/src/bin/tx2.rs b/src/bin/tx2.rs index 1e6a3c6d8..d148a29d6 100644 --- a/src/bin/tx2.rs +++ b/src/bin/tx2.rs @@ -6,12 +6,11 @@ use drk::{ circuit::{mint_contract::MintContract, spend_contract::SpendContract}, crypto::{ coin::Coin, - keypair::Keypair, + keypair::{Keypair, PublicKey, SecretKey}, merkle_node::MerkleNode, note::{EncryptedNote, Note}, nullifier::Nullifier, proof::VerifyingKey, - schnorr, }, state::{state_transition, ProgramState, StateUpdate}, tx, Result, @@ -35,13 +34,13 @@ struct MemoryState { spend_vk: VerifyingKey, // Public key of the cashier - cashier_signature_public: schnorr::PublicKey, + cashier_signature_public: PublicKey, // List of all our secret keys - secrets: Vec, + secrets: Vec, } impl ProgramState for MemoryState { - fn is_valid_cashier_public_key(&self, public: &schnorr::PublicKey) -> bool { + fn is_valid_cashier_public_key(&self, public: &PublicKey) -> bool { public == &self.cashier_signature_public } @@ -73,7 +72,7 @@ impl MemoryState { let node = MerkleNode(coin.0); self.tree.append(&node); - //// Keep track of all merkle roots that have existed + // Keep track of all merkle roots that have existed self.merkle_roots.push(self.tree.root()); if let Some((note, _secret)) = self.try_decrypt_note(enc_note) { @@ -83,7 +82,7 @@ impl MemoryState { } } - fn try_decrypt_note(&self, ciphertext: EncryptedNote) -> Option<(Note, pallas::Base)> { + fn try_decrypt_note(&self, ciphertext: EncryptedNote) -> Option<(Note, SecretKey)> { // Loop through all our secret keys... for secret in &self.secrets { // ... attempt to decrypt the note ... @@ -98,8 +97,8 @@ impl MemoryState { } fn main() -> Result<()> { - let cashier_signature_secret = schnorr::SecretKey::random(); - let cashier_signature_public = cashier_signature_secret.public_key(); + let cashier_signature_secret = SecretKey::random(&mut OsRng); + let cashier_signature_public = PublicKey::from_secret(cashier_signature_secret); let keypair = Keypair::random(&mut OsRng); @@ -115,7 +114,7 @@ fn main() -> Result<()> { mint_vk, spend_vk, cashier_signature_public, - secrets: vec![keypair.secret.inner()], + secrets: vec![keypair.secret], }; let token_id = pallas::Base::from(110); @@ -130,7 +129,7 @@ fn main() -> Result<()> { outputs: vec![tx::TransactionBuilderOutputInfo { value: 110, token_id, - public: keypair.public.inner(), + public: keypair.public, }], }; @@ -138,7 +137,7 @@ fn main() -> Result<()> { tx.verify(&state.mint_vk, &state.spend_vk).expect("tx verify"); - let _note = tx.outputs[0].enc_note.decrypt(&keypair.secret.inner())?; + let _note = tx.outputs[0].enc_note.decrypt(&keypair.secret)?; let update = state_transition(&state, tx)?; state.apply(update); @@ -153,13 +152,13 @@ fn main() -> Result<()> { inputs: vec![tx::TransactionBuilderInputInfo { leaf_position, merkle_path, - secret: keypair.secret.inner(), + secret: keypair.secret, note: note.clone(), }], outputs: vec![tx::TransactionBuilderOutputInfo { value: 110, token_id, - public: keypair.public.inner(), + public: keypair.public, }], }; diff --git a/src/circuit/spend_contract.rs b/src/circuit/spend_contract.rs index 59126f8c6..78e9656ca 100644 --- a/src/circuit/spend_contract.rs +++ b/src/circuit/spend_contract.rs @@ -102,7 +102,8 @@ pub struct SpendContract { pub asset_blind: Option, pub leaf_pos: Option, pub merkle_path: Option<[pallas::Base; 32]>, - pub sig_secret: Option, + //pub sig_secret: Option, + pub sig_secret: Option, } impl UtilitiesInstructions for SpendContract { @@ -442,11 +443,16 @@ impl Circuit for SpendContract { // ======================== // Signature key derivation // ======================== - let (sig_pub, _) = { - let spend_auth_g = OrchardFixedBases::SpendAuthG; - let spend_auth_g = FixedPoint::from_inner(ecc_chip, spend_auth_g); - // TODO: Do we need to load sig_secret somewhere first? - spend_auth_g.mul(layouter.namespace(|| "[x_s] SpendAuthG"), self.sig_secret)? + let sig_secret = self.load_private( + layouter.namespace(|| "load sig_secret"), + config.advices[0], + self.sig_secret, + )?; + + let sig_pub = { + 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"), sig_secret)? }; layouter.constrain_instance( diff --git a/src/client.rs b/src/client.rs index 1f464777e..96bfaaa19 100644 --- a/src/client.rs +++ b/src/client.rs @@ -7,12 +7,20 @@ use url::Url; use crate::{ blockchain::{rocks::columns, Rocks, RocksColumn, Slab}, - crypto::{coin::Coin, merkle_node::MerkleNode, schnorr, util::mod_r_p, OwnCoin}, + crypto::{ + coin::Coin, + keypair::{Keypair, PublicKey, SecretKey}, + merkle_node::MerkleNode, + OwnCoin, + }, serial::{serialize, Decodable, Encodable}, service::GatewayClient, state::{state_transition, State}, tx, - wallet::{walletdb::Balances, CashierDbPtr, Keypair, WalletPtr}, + wallet::{ + cashierdb::CashierDbPtr, + walletdb::{Balances, WalletPtr}, + }, Result, }; @@ -95,7 +103,7 @@ impl Client { async fn build_slab_from_tx( &mut self, - pubkey: pallas::Point, + pubkey: PublicKey, value: u64, token_id: pallas::Base, clear_input: bool, @@ -109,8 +117,9 @@ impl Client { if clear_input { // TODO: FIXME: - let base_secret = self.main_keypair.secret; - let signature_secret = schnorr::SecretKey(mod_r_p(base_secret)); + let signature_secret = self.main_keypair.clone().secret; + let signature_public = PublicKey::from_secret(signature_secret); + debug!("SIGNATURE PUBLIC: {:?}", signature_public); let input = tx::TransactionBuilderClearInputInfo { value, token_id, signature_secret }; clear_inputs.push(input); } else { @@ -124,7 +133,7 @@ impl Client { break } - let node = MerkleNode(own_coin.coin.inner()); + let node = MerkleNode(own_coin.coin.0); let (leaf_position, merkle_path) = state_m.tree.authentication_path(&node).unwrap(); // TODO: What is this counting? Is it everything or does it know to separate // different tokens? @@ -179,7 +188,7 @@ impl Client { pub async fn send( &mut self, - pubkey: pallas::Point, + pubkey: PublicKey, amount: u64, token_id: pallas::Base, clear_input: bool, @@ -204,7 +213,7 @@ impl Client { pub async fn transfer( &mut self, token_id: pallas::Base, - pubkey: pallas::Point, + pubkey: PublicKey, amount: u64, state: Arc>, ) -> ClientResult<()> { @@ -222,11 +231,11 @@ impl Client { } async fn update_state( - secret_keys: Vec, + secret_keys: Vec, slab: &Slab, state: Arc>, wallet: WalletPtr, - notify: Option>, + notify: Option>, ) -> Result<()> { debug!("Build tx from slab and update the state"); let tx = tx::Transaction::decode(&slab.get_payload()[..])?; @@ -242,7 +251,7 @@ impl Client { &self, state: Arc>, cashier_wallet: CashierDbPtr, - notify: async_channel::Sender<(pallas::Point, u64)>, + notify: async_channel::Sender<(PublicKey, u64)>, executor: Arc>, ) -> Result<()> { debug!("Start subscriber for cashier"); @@ -251,13 +260,12 @@ impl Client { let secret_key = self.main_keypair.secret; let wallet = self.wallet.clone(); - //let task: smol::Task> = executor.spawn(async move { let task: smol::Task> = executor.spawn(async move { loop { let slab = gateway_slabs_sub.recv().await?; debug!("Received new slab"); - let mut secret_keys: Vec = vec![secret_key]; + let mut secret_keys = vec![secret_key]; let mut withdraw_keys = cashier_wallet.get_withdraw_private_keys().await?; secret_keys.append(&mut withdraw_keys); @@ -289,8 +297,7 @@ impl Client { debug!("Start subscriber for darkfid"); let gateway_slabs_sub = self.gateway.start_subscriber(executor.clone()).await?; - let secret_key = self.main_keypair.secret; - + let secret_key = self.main_keypair.secret.clone(); let wallet = self.wallet.clone(); let task: smol::Task> = executor.spawn(async move { diff --git a/src/crypto/coin.rs b/src/crypto/coin.rs index 4331fc2dc..a2c475f73 100644 --- a/src/crypto/coin.rs +++ b/src/crypto/coin.rs @@ -18,10 +18,6 @@ impl Coin { pub fn to_bytes(self) -> [u8; 32] { self.0.to_bytes() } - - pub(crate) fn inner(&self) -> pallas::Base { - self.0 - } } impl Encodable for Coin { diff --git a/src/crypto/diffie_hellman.rs b/src/crypto/diffie_hellman.rs index 0a634dba4..ba54cc94b 100644 --- a/src/crypto/diffie_hellman.rs +++ b/src/crypto/diffie_hellman.rs @@ -1,7 +1,11 @@ use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams}; -use pasta_curves as pasta; use pasta_curves::group::{cofactor::CofactorGroup, GroupEncoding}; +use crate::crypto::{ + keypair::{PublicKey, SecretKey}, + util::mod_r_p, +}; + pub const KDF_SAPLING_PERSONALIZATION: &[u8; 16] = b"DarkFiSaplingKDF"; /// Functions used for encrypting the note in transaction outputs. @@ -9,7 +13,7 @@ pub const KDF_SAPLING_PERSONALIZATION: &[u8; 16] = b"DarkFiSaplingKDF"; /// Sapling key agreement for note encryption. /// /// Implements section 5.4.4.3 of the Zcash Protocol Specification. -pub fn sapling_ka_agree(esk: &pasta::Fq, pk_d: &pasta::Ep) -> pasta::Ep { +pub fn sapling_ka_agree(esk: &SecretKey, pk_d: &PublicKey) -> PublicKey { // [8 esk] pk_d // ::clear_cofactor is implemented using // ExtendedPoint::mul_by_cofactor in the jubjub crate. @@ -19,19 +23,20 @@ pub fn sapling_ka_agree(esk: &pasta::Fq, pk_d: &pasta::Ep) -> pasta::Ep { // of bits instead of individual bits). // We want that to be fast because it's in the hot path for trial decryption of // notes on chain. + let esk_s = mod_r_p(esk.0); let mut wnaf = group::Wnaf::new(); - wnaf.scalar(esk).base(*pk_d).clear_cofactor() + PublicKey(wnaf.scalar(&esk_s).base(pk_d.0).clear_cofactor()) } /// Sapling KDF for note encryption. /// /// Implements section 5.4.4.4 of the Zcash Protocol Specification. -pub fn kdf_sapling(dhsecret: pasta::Ep, epk: &pasta::Ep) -> Blake2bHash { +pub fn kdf_sapling(dhsecret: &PublicKey, epk: &PublicKey) -> Blake2bHash { Blake2bParams::new() .hash_length(32) .personal(KDF_SAPLING_PERSONALIZATION) .to_state() - .update(&dhsecret.to_bytes()) - .update(&epk.to_bytes()) + .update(&dhsecret.0.to_bytes()) + .update(&epk.0.to_bytes()) .finalize() } diff --git a/src/crypto/keypair.rs b/src/crypto/keypair.rs index 671cd2626..e086c5e75 100644 --- a/src/crypto/keypair.rs +++ b/src/crypto/keypair.rs @@ -1,22 +1,28 @@ +use std::io; + use halo2_gadgets::ecc::FixedPoints; -use pasta_curves::{arithmetic::Field, pallas}; +use pasta_curves::{ + arithmetic::{Field, FieldExt}, + group::{Group, GroupEncoding}, + pallas, +}; use rand::RngCore; -use crate::crypto::{constants::OrchardFixedBases, util::mod_r_p}; +use crate::{ + crypto::{constants::OrchardFixedBases, util::mod_r_p}, + serial::{Decodable, Encodable, ReadExt, WriteExt}, + Error, Result, +}; -#[derive(Clone, Debug)] +#[derive(Copy, Clone, Debug)] pub struct Keypair { pub secret: SecretKey, pub public: PublicKey, } impl Keypair { - fn derive_public_key(s: SecretKey) -> PublicKey { - PublicKey(OrchardFixedBases::NullifierK.generator() * mod_r_p(s.inner())) - } - pub fn new(secret: SecretKey) -> Self { - let public = Keypair::derive_public_key(secret.clone()); + let public = PublicKey::from_secret(secret.clone()); Keypair { secret, public } } @@ -26,25 +32,135 @@ impl Keypair { } } -#[derive(Clone, Debug)] -pub struct SecretKey(pallas::Base); +#[derive(Copy, Clone, Debug)] +pub struct SecretKey(pub pallas::Base); impl SecretKey { - pub fn inner(&self) -> pallas::Base { - self.0 - } - pub fn random(mut rng: impl RngCore) -> Self { let x = pallas::Base::random(&mut rng); SecretKey(x) } -} -#[derive(Clone, Debug)] -pub struct PublicKey(pallas::Point); - -impl PublicKey { - pub fn inner(&self) -> pallas::Point { - self.0 + pub fn to_bytes(self) -> [u8; 32] { + self.0.to_bytes() + } +} + +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct PublicKey(pub pallas::Point); + +impl PublicKey { + pub fn random(mut rng: impl RngCore) -> Self { + let p = pallas::Point::random(&mut rng); + PublicKey(p) + } + + pub fn from_secret(s: SecretKey) -> Self { + let p = OrchardFixedBases::NullifierK.generator() * mod_r_p(s.0); + PublicKey(p) + } + + pub fn to_bytes(self) -> [u8; 32] { + self.0.to_bytes() + } +} + +impl Encodable for pallas::Base { + fn encode(&self, mut s: S) -> Result { + s.write_slice(&self.to_bytes()[..])?; + Ok(32) + } +} + +impl Decodable for pallas::Base { + fn decode(mut d: D) -> Result { + let mut bytes = [0u8; 32]; + d.read_slice(&mut bytes)?; + let result = pallas::Base::from_bytes(&bytes); + if result.is_some().into() { + Ok(result.unwrap()) + } else { + Err(Error::BadOperationType) + } + } +} + +impl Encodable for pallas::Scalar { + fn encode(&self, mut s: S) -> Result { + s.write_slice(&self.to_bytes()[..])?; + Ok(32) + } +} + +impl Decodable for pallas::Scalar { + fn decode(mut d: D) -> Result { + let mut bytes = [0u8; 32]; + d.read_slice(&mut bytes)?; + let result = pallas::Scalar::from_bytes(&bytes); + if result.is_some().into() { + Ok(result.unwrap()) + } else { + Err(Error::BadOperationType) + } + } +} + +impl Encodable for pallas::Point { + fn encode(&self, mut s: S) -> Result { + s.write_slice(&self.to_bytes()[..])?; + Ok(32) + } +} + +impl Decodable for pallas::Point { + fn decode(mut d: D) -> Result { + let mut bytes = [0u8; 32]; + d.read_slice(&mut bytes)?; + let result = Self::from_bytes(&bytes); + if result.is_some().into() { + Ok(result.unwrap()) + } else { + Err(Error::BadOperationType) + } + } +} + +impl Encodable for SecretKey { + fn encode(&self, mut s: S) -> Result { + s.write_slice(&self.0.to_bytes()[..])?; + Ok(32) + } +} + +impl Decodable for SecretKey { + fn decode(mut d: D) -> Result { + let mut bytes = [0u8; 32]; + d.read_slice(&mut bytes)?; + let result = pallas::Base::from_bytes(&bytes); + if result.is_some().into() { + Ok(SecretKey(result.unwrap())) + } else { + Err(Error::BadOperationType) + } + } +} + +impl Encodable for PublicKey { + fn encode(&self, mut s: S) -> Result { + s.write_slice(&self.0.to_bytes()[..])?; + Ok(32) + } +} + +impl Decodable for PublicKey { + fn decode(mut d: D) -> Result { + let mut bytes = [0u8; 32]; + d.read_slice(&mut bytes)?; + let result = pallas::Point::from_bytes(&bytes); + if result.is_some().into() { + Ok(PublicKey(result.unwrap())) + } else { + Err(Error::BadOperationType) + } } } diff --git a/src/crypto/mint_proof.rs b/src/crypto/mint_proof.rs index 7679dcf15..8748e5c45 100644 --- a/src/crypto/mint_proof.rs +++ b/src/crypto/mint_proof.rs @@ -8,15 +8,16 @@ use log::debug; use pasta_curves::{ arithmetic::{CurveAffine, FieldExt}, group::Curve, - pallas, }; -use super::{ - proof::{Proof, ProvingKey, VerifyingKey}, - util::{mod_r_p, pedersen_commitment_scalar, pedersen_commitment_u64}, -}; use crate::{ circuit::mint_contract::MintContract, + crypto::{ + coin::Coin, + keypair::PublicKey, + proof::{Proof, ProvingKey, VerifyingKey}, + util::{mod_r_p, pedersen_commitment_scalar, pedersen_commitment_u64}, + }, serial::{Decodable, Encodable}, types::*, Result, @@ -42,8 +43,7 @@ impl MintProofKeys { pub struct MintRevealedValues { pub value_commit: DrkValueCommit, pub token_commit: DrkValueCommit, - //pub coin: [u8; 32], - pub coin: pallas::Base, + pub coin: Coin, } impl MintRevealedValues { @@ -54,26 +54,18 @@ impl MintRevealedValues { token_blind: DrkValueBlind, serial: DrkSerial, coin_blind: DrkCoinBlind, - public_key: DrkPublicKey, + public_key: PublicKey, ) -> Self { let value_commit = pedersen_commitment_u64(value, value_blind); let token_commit = pedersen_commitment_scalar(mod_r_p(token_id), token_blind); - let coords = public_key.to_affine().coordinates().unwrap(); - let messages = [ - [*coords.x(), *coords.y()], - [DrkValue::from_u64(value), token_id], - [serial, coin_blind], - ]; + let coords = public_key.0.to_affine().coordinates().unwrap(); + let messages = + [*coords.x(), *coords.y(), DrkValue::from_u64(value), token_id, serial, coin_blind]; - let mut coin = DrkCoin::zero(); - for msg in messages.iter() { - coin += primitives::poseidon::Hash::init(P128Pow5T3, ConstantLength::<2>).hash(*msg); - } + let coin = primitives::poseidon::Hash::init(P128Pow5T3, ConstantLength::<6>).hash(messages); - //let coin = hash.to_bytes(); - - MintRevealedValues { value_commit, token_commit, coin } + MintRevealedValues { value_commit, token_commit, coin: Coin(coin) } } fn make_outputs(&self) -> [DrkCircuitField; 5] { @@ -81,8 +73,7 @@ impl MintRevealedValues { let token_coords = self.token_commit.to_affine().coordinates().unwrap(); vec![ - //DrkCircuitField::from_bytes(&self.coin).unwrap(), - self.coin, + self.coin.0, *value_coords.x(), *value_coords.y(), *token_coords.x(), @@ -121,7 +112,7 @@ pub fn create_mint_proof( token_blind: DrkValueBlind, serial: DrkSerial, coin_blind: DrkCoinBlind, - public_key: DrkPublicKey, + public_key: PublicKey, ) -> Result<(Proof, MintRevealedValues)> { const K: u32 = 11; @@ -135,7 +126,7 @@ pub fn create_mint_proof( public_key, ); - let coords = public_key.to_affine().coordinates().unwrap(); + let coords = public_key.0.to_affine().coordinates().unwrap(); let c = MintContract { pub_x: Some(*coords.x()), diff --git a/src/crypto/mod.rs b/src/crypto/mod.rs index 86efa7fef..2161cae51 100644 --- a/src/crypto/mod.rs +++ b/src/crypto/mod.rs @@ -7,7 +7,6 @@ pub mod merkle_node; pub mod mint_proof; pub mod note; pub mod nullifier; -pub mod pasta_serial; pub mod proof; pub mod schnorr; pub mod spend_proof; @@ -17,13 +16,13 @@ pub(crate) use mint_proof::MintRevealedValues; pub(crate) use proof::Proof; pub(crate) use spend_proof::SpendRevealedValues; -use crate::types::DrkSecretKey; +use keypair::SecretKey; #[derive(Clone)] pub struct OwnCoin { pub coin: coin::Coin, pub note: note::Note, - pub secret: DrkSecretKey, + pub secret: SecretKey, //pub witness: merkle::IncrementalWitness, //pub witness: BridgeFrontier, pub nullifier: nullifier::Nullifier, diff --git a/src/crypto/note.rs b/src/crypto/note.rs index 96607407f..24db1a16a 100644 --- a/src/crypto/note.rs +++ b/src/crypto/note.rs @@ -1,14 +1,13 @@ use std::io; use crypto_api_chachapoly::ChachaPolyIetf; -use pasta_curves::arithmetic::Field; use rand::rngs::OsRng; -use super::{ - diffie_hellman::{kdf_sapling, sapling_ka_agree}, - util::mod_r_p, -}; use crate::{ + crypto::{ + diffie_hellman::{kdf_sapling, sapling_ka_agree}, + keypair::{PublicKey, SecretKey}, + }, serial::{Decodable, Encodable, ReadExt, WriteExt}, types::*, Error, Result, @@ -56,11 +55,11 @@ impl Decodable for Note { } impl Note { - pub fn encrypt(&self, public: &DrkPublicKey) -> Result { - let ephem_secret = DrkSecretKey::random(&mut OsRng); - let ephem_public = derive_public_key(ephem_secret); - let shared_secret = sapling_ka_agree(&mod_r_p(ephem_secret), public); - let key = kdf_sapling(shared_secret, &ephem_public); + pub fn encrypt(&self, public: &PublicKey) -> Result { + let ephem_secret = SecretKey::random(&mut OsRng); + let ephem_public = PublicKey::from_secret(ephem_secret); + let shared_secret = sapling_ka_agree(&ephem_secret, public); + let key = kdf_sapling(&shared_secret, &ephem_public); let mut input = Vec::new(); self.encode(&mut input)?; @@ -79,7 +78,7 @@ impl Note { pub struct EncryptedNote { ciphertext: [u8; ENC_CIPHERTEXT_SIZE], - ephem_public: DrkPublicKey, + ephem_public: PublicKey, } impl Encodable for EncryptedNote { @@ -101,9 +100,9 @@ impl Decodable for EncryptedNote { } impl EncryptedNote { - pub fn decrypt(&self, secret: &DrkSecretKey) -> Result { - let shared_secret = sapling_ka_agree(&mod_r_p(*secret), &self.ephem_public); - let key = kdf_sapling(shared_secret, &self.ephem_public); + pub fn decrypt(&self, secret: &SecretKey) -> Result { + let shared_secret = sapling_ka_agree(&secret, &self.ephem_public); + let key = kdf_sapling(&shared_secret, &self.ephem_public); let mut plaintext = [0; ENC_CIPHERTEXT_SIZE]; assert_eq!( diff --git a/src/crypto/nullifier.rs b/src/crypto/nullifier.rs index 62bca690d..3c4ec70e3 100644 --- a/src/crypto/nullifier.rs +++ b/src/crypto/nullifier.rs @@ -7,6 +7,7 @@ use halo2_gadgets::primitives::{ use pasta_curves::{arithmetic::FieldExt, pallas}; use crate::{ + crypto::keypair::SecretKey, serial::{Decodable, Encodable, ReadExt, WriteExt}, Result, }; @@ -15,8 +16,8 @@ use crate::{ pub struct Nullifier(pub(crate) pallas::Base); impl Nullifier { - pub fn new(secret: pallas::Base, serial: pallas::Base) -> Self { - let nullifier = [secret, serial]; + pub fn new(secret: SecretKey, serial: pallas::Base) -> Self { + let nullifier = [secret.0, serial]; let nullifier = poseidon::Hash::init(P128Pow5T3, ConstantLength::<2>).hash(nullifier); Nullifier(nullifier) } diff --git a/src/crypto/pasta_serial.rs b/src/crypto/pasta_serial.rs deleted file mode 100644 index 96c746c4d..000000000 --- a/src/crypto/pasta_serial.rs +++ /dev/null @@ -1,69 +0,0 @@ -use std::io; - -use pasta_curves as pasta; -use pasta_curves::{arithmetic::FieldExt, group::GroupEncoding}; - -use crate::{ - serial::{Decodable, Encodable, ReadExt, WriteExt}, - Error, Result, -}; - -impl Encodable for pasta::Fp { - fn encode(&self, mut s: S) -> Result { - s.write_slice(&self.to_bytes()[..])?; - Ok(32) - } -} - -impl Decodable for pasta::Fp { - fn decode(mut d: D) -> Result { - let mut bytes = [0u8; 32]; - d.read_slice(&mut bytes)?; - let result = Self::from_bytes(&bytes); - if result.is_some().into() { - Ok(result.unwrap()) - } else { - Err(Error::BadOperationType) - } - } -} - -impl Encodable for pasta::Fq { - fn encode(&self, mut s: S) -> Result { - s.write_slice(&self.to_bytes()[..])?; - Ok(32) - } -} - -impl Decodable for pasta::Fq { - fn decode(mut d: D) -> Result { - let mut bytes = [0u8; 32]; - d.read_slice(&mut bytes)?; - let result = Self::from_bytes(&bytes); - if result.is_some().into() { - Ok(result.unwrap()) - } else { - Err(Error::BadOperationType) - } - } -} - -impl Encodable for pasta::Ep { - fn encode(&self, mut s: S) -> Result { - s.write_slice(&self.to_bytes()[..])?; - Ok(32) - } -} - -impl Decodable for pasta::Ep { - fn decode(mut d: D) -> Result { - let mut bytes = [0u8; 32]; - d.read_slice(&mut bytes)?; - let result = Self::from_bytes(&bytes); - if result.is_some().into() { - Ok(result.unwrap()) - } else { - Err(Error::BadOperationType) - } - } -} diff --git a/src/crypto/schnorr.rs b/src/crypto/schnorr.rs index 34e9a496c..18fea0961 100644 --- a/src/crypto/schnorr.rs +++ b/src/crypto/schnorr.rs @@ -4,50 +4,47 @@ use halo2_gadgets::ecc::FixedPoints; use pasta_curves::{arithmetic::Field, group::GroupEncoding, pallas}; use rand::rngs::OsRng; -use super::{ - constants::{OrchardFixedBases, DRK_SCHNORR_DOMAIN}, - util::hash_to_scalar, -}; use crate::{ - error::Result, + crypto::{ + constants::{OrchardFixedBases, DRK_SCHNORR_DOMAIN}, + keypair::{PublicKey, SecretKey}, + util::{hash_to_scalar, mod_r_p}, + }, serial::{Decodable, Encodable}, - types::{DrkPublicKey, DrkValueBlind, DrkValueCommit}, + Result, }; -#[derive(Clone)] -pub struct SecretKey(pub pallas::Scalar); +pub struct Signature { + commit: pallas::Point, + response: pallas::Scalar, +} -impl SecretKey { - pub fn random() -> Self { - Self(pallas::Scalar::random(&mut OsRng)) - } +pub trait SchnorrSecret { + fn sign(&self, message: &[u8]) -> Signature; +} - pub fn sign(&self, message: &[u8]) -> Signature { - let mask = DrkValueBlind::random(&mut OsRng); - let commit = OrchardFixedBases::SpendAuthG.generator() * mask; +pub trait SchnorrPublic { + fn verify(&self, message: &[u8], signature: &Signature) -> bool; +} + +impl SchnorrSecret for SecretKey { + fn sign(&self, message: &[u8]) -> Signature { + let mask = pallas::Scalar::random(&mut OsRng); + let commit = OrchardFixedBases::NullifierK.generator() * mask; let challenge = hash_to_scalar(DRK_SCHNORR_DOMAIN, &commit.to_bytes(), message); - let response = mask + challenge * self.0; + let response = mask + challenge * mod_r_p(self.0); Signature { commit, response } } - - pub fn public_key(&self) -> PublicKey { - let public_key = OrchardFixedBases::SpendAuthG.generator() * self.0; - PublicKey(public_key) - } - - pub fn inner(&self) -> pallas::Scalar { - self.0 - } } -#[derive(PartialEq)] -pub struct PublicKey(pub DrkPublicKey); - -pub struct Signature { - commit: DrkValueCommit, - response: DrkValueBlind, +impl SchnorrPublic for PublicKey { + fn verify(&self, message: &[u8], signature: &Signature) -> bool { + let challenge = hash_to_scalar(DRK_SCHNORR_DOMAIN, &signature.commit.to_bytes(), message); + OrchardFixedBases::NullifierK.generator() * signature.response - self.0 * challenge == + signature.commit + } } impl Encodable for Signature { @@ -65,35 +62,16 @@ impl Decodable for Signature { } } -impl PublicKey { - pub fn verify(&self, message: &[u8], signature: &Signature) -> bool { - let challenge = hash_to_scalar(DRK_SCHNORR_DOMAIN, &signature.commit.to_bytes(), message); - OrchardFixedBases::SpendAuthG.generator() * signature.response - self.0 * challenge == - signature.commit - } +#[cfg(test)] +mod tests { + use super::*; - pub fn inner(&self) -> pallas::Point { - self.0 + #[test] + fn test_schnorr() { + let secret = SecretKey::random(); + let message = b"Foo bar"; + let signature = secret.sign(&message[..]); + let public = PublicKey::from_secret(secret); + assert!(public.verify(&message[..], &signature)); } } - -impl Encodable for PublicKey { - fn encode(&self, s: S) -> Result { - self.0.encode(s) - } -} - -impl Decodable for PublicKey { - fn decode(mut d: D) -> Result { - Ok(Self(Decodable::decode(&mut d)?)) - } -} - -#[test] -fn test_schnorr() { - let secret = SecretKey::random(); - let message = b"Foo bar"; - let signature = secret.sign(&message[..]); - let public = secret.public_key(); - assert!(public.verify(&message[..], &signature)); -} diff --git a/src/crypto/spend_proof.rs b/src/crypto/spend_proof.rs index 36cd8b7d7..d2ae2dd35 100644 --- a/src/crypto/spend_proof.rs +++ b/src/crypto/spend_proof.rs @@ -19,7 +19,10 @@ use super::{ }; use crate::{ circuit::spend_contract::SpendContract, - crypto::{merkle_node::MerkleNode, schnorr}, + crypto::{ + keypair::{PublicKey, SecretKey}, + merkle_node::MerkleNode, + }, serial::{Decodable, Encodable}, types::*, Result, @@ -47,7 +50,7 @@ pub struct SpendRevealedValues { pub token_commit: DrkValueCommit, pub nullifier: Nullifier, pub merkle_root: MerkleNode, - pub signature_public: schnorr::PublicKey, + pub signature_public: PublicKey, } impl SpendRevealedValues { @@ -59,27 +62,22 @@ impl SpendRevealedValues { token_blind: DrkValueBlind, serial: DrkSerial, coin_blind: DrkCoinBlind, - secret: DrkSecretKey, + secret: SecretKey, leaf_position: incrementalmerkletree::Position, merkle_path: Vec, - signature_secret: schnorr::SecretKey, + signature_secret: SecretKey, ) -> Self { - let nullifier = [secret, serial]; + let nullifier = [secret.0, serial]; let nullifier = primitives::poseidon::Hash::init(P128Pow5T3, ConstantLength::<2>).hash(nullifier); - let public_key = derive_public_key(secret); - let coords = public_key.to_affine().coordinates().unwrap(); - let messages = [ - [*coords.x(), *coords.y()], - [DrkValue::from_u64(value), token_id], - [serial, coin_blind], - ]; + let public_key = PublicKey::from_secret(secret); + let coords = public_key.0.to_affine().coordinates().unwrap(); - let mut coin = DrkCoin::zero(); - for msg in messages.iter() { - coin += primitives::poseidon::Hash::init(P128Pow5T3, ConstantLength::<2>).hash(*msg); - } + let messages = + [*coords.x(), *coords.y(), DrkValue::from_u64(value), token_id, serial, coin_blind]; + + let coin = primitives::poseidon::Hash::init(P128Pow5T3, ConstantLength::<6>).hash(messages); let merkle_root = { let position: u64 = leaf_position.into(); @@ -103,7 +101,7 @@ impl SpendRevealedValues { token_commit, nullifier: Nullifier(nullifier), merkle_root, - signature_public: signature_secret.public_key(), + signature_public: PublicKey::from_secret(signature_secret), } } @@ -160,10 +158,10 @@ pub fn create_spend_proof( token_blind: DrkValueBlind, serial: DrkSerial, coin_blind: DrkCoinBlind, - secret: DrkSecretKey, + secret: SecretKey, leaf_position: incrementalmerkletree::Position, merkle_path: Vec, - signature_secret: schnorr::SecretKey, + signature_secret: SecretKey, ) -> Result<(Proof, SpendRevealedValues)> { const K: u32 = 11; @@ -184,7 +182,7 @@ pub fn create_spend_proof( let leaf_position: u64 = leaf_position.into(); let c = SpendContract { - secret_key: Some(secret), + secret_key: Some(secret.0), serial: Some(serial), value: Some(DrkValue::from_u64(value)), asset: Some(token_id), diff --git a/src/service/bridge.rs b/src/service/bridge.rs index 87f3ca85a..bf921940b 100644 --- a/src/service/bridge.rs +++ b/src/service/bridge.rs @@ -6,7 +6,10 @@ use async_trait::async_trait; use futures::stream::{FuturesUnordered, StreamExt}; use log::{debug, error}; -use crate::{types::*, util::NetworkName, wallet::cashierdb::TokenKey, Error, Result}; +use crate::{ + crypto::keypair::PublicKey, types::*, util::NetworkName, wallet::cashierdb::TokenKey, Error, + Result, +}; pub struct BridgeRequests { pub network: NetworkName, @@ -53,7 +56,7 @@ pub struct TokenSubscribtion { pub struct TokenNotification { pub network: NetworkName, pub token_id: DrkTokenId, - pub drk_pub_key: DrkPublicKey, + pub drk_pub_key: PublicKey, pub received_balance: u64, pub decimals: u16, } @@ -109,7 +112,7 @@ impl Bridge { pub async fn subscribe( self: Arc, - drk_pub_key: DrkPublicKey, + drk_pub_key: PublicKey, mint: Option, executor: Arc>, ) -> BridgeSubscribtion { @@ -128,7 +131,7 @@ impl Bridge { self: Arc, req: async_channel::Receiver, rep: async_channel::Sender, - drk_pub_key: DrkPublicKey, + drk_pub_key: PublicKey, mint: Option, executor: Arc>, ) -> Result<()> { @@ -232,7 +235,7 @@ impl Bridge { pub trait NetworkClient { async fn subscribe( self: Arc, - drk_pub_key: DrkPublicKey, + drk_pub_key: PublicKey, mint: Option, executor: Arc>, ) -> Result; @@ -242,7 +245,7 @@ pub trait NetworkClient { self: Arc, private_key: Vec, public_key: Vec, - drk_pub_key: DrkPublicKey, + drk_pub_key: PublicKey, mint: Option, executor: Arc>, ) -> Result; diff --git a/src/service/btc.rs b/src/service/btc.rs index 180f60f70..c86e0ba28 100644 --- a/src/service/btc.rs +++ b/src/service/btc.rs @@ -1,3 +1,5 @@ +// TODO: This module needs cleanup related to PublicKey/SecretKey types. + use std::{ cmp::max, collections::BTreeMap, @@ -40,8 +42,8 @@ use secp256k1::{ use super::bridge::{NetworkClient, TokenNotification, TokenSubscribtion}; use crate::{ + crypto::keypair::PublicKey as DrkPublicKey, serial::{deserialize, serialize, Decodable, Encodable}, - types::*, util::{generate_id, NetworkName}, Error, Result, }; diff --git a/src/service/eth.rs b/src/service/eth.rs index c9735c933..ceab2cb58 100644 --- a/src/service/eth.rs +++ b/src/service/eth.rs @@ -13,9 +13,9 @@ use serde_json::{json, Value}; use super::bridge::{NetworkClient, TokenNotification, TokenSubscribtion}; use crate::{ + crypto::keypair::PublicKey, rpc::{jsonrpc, jsonrpc::JsonResult}, serial::{deserialize, serialize, Decodable, Encodable}, - types::*, util::{generate_id, parse::truncate, NetworkName}, Error, Result, }; @@ -228,7 +228,7 @@ impl EthClient { async fn handle_subscribe_request( self: Arc, addr: String, - drk_pub_key: DrkPublicKey, + drk_pub_key: PublicKey, ) -> Result<()> { if self.subscriptions.lock().await.contains(&addr) { return Ok(()) @@ -381,7 +381,7 @@ impl EthClient { impl NetworkClient for EthClient { async fn subscribe( self: Arc, - drk_pub_key: DrkPublicKey, + drk_pub_key: PublicKey, _mint_address: Option, executor: Arc>, ) -> Result { @@ -414,7 +414,7 @@ impl NetworkClient for EthClient { self: Arc, _private_key: Vec, public_key: Vec, - drk_pub_key: DrkPublicKey, + drk_pub_key: PublicKey, _mint_address: Option, executor: Arc>, ) -> Result { diff --git a/src/service/sol.rs b/src/service/sol.rs index db5ad16b4..e388e7025 100644 --- a/src/service/sol.rs +++ b/src/service/sol.rs @@ -23,9 +23,9 @@ use tungstenite::Message; use super::bridge::{NetworkClient, TokenNotification, TokenSubscribtion}; use crate::{ + crypto::keypair::PublicKey, rpc::{jsonrpc, jsonrpc::JsonResult, websockets, websockets::WsStream}, serial::{deserialize, serialize, Decodable, Encodable}, - types::*, util::{generate_id, parse::truncate, NetworkName}, Error, Result, }; @@ -85,7 +85,7 @@ impl SolClient { async fn handle_subscribe_request( self: Arc, keypair: Keypair, - drk_pub_key: DrkPublicKey, + drk_pub_key: PublicKey, mint: Option, ) -> SolResult<()> { debug!(target: "SOL BRIDGE", "handle_subscribe_request()"); @@ -396,7 +396,7 @@ impl SolClient { impl NetworkClient for SolClient { async fn subscribe( self: Arc, - drk_pub_key: DrkPublicKey, + drk_pub_key: PublicKey, mint_address: Option, executor: Arc>, ) -> Result { @@ -431,7 +431,7 @@ impl NetworkClient for SolClient { self: Arc, private_key: Vec, _public_key: Vec, - drk_pub_key: DrkPublicKey, + drk_pub_key: PublicKey, mint_address: Option, executor: Arc>, ) -> Result { diff --git a/src/state.rs b/src/state.rs index 734ec0887..9516b60b8 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,28 +1,25 @@ -use halo2_gadgets::ecc::FixedPoints; use incrementalmerkletree::{bridgetree::BridgeTree, Frontier, Tree}; use log::debug; -use pasta_curves::pallas; use crate::{ blockchain::{rocks::columns, RocksColumn}, crypto::{ coin::Coin, - constants::OrchardFixedBases, + keypair::{PublicKey, SecretKey}, merkle_node::MerkleNode, note::{EncryptedNote, Note}, nullifier::Nullifier, proof::VerifyingKey, - schnorr, - util::mod_r_p, OwnCoin, }, + serial::serialize, tx::Transaction, - wallet::WalletPtr, + wallet::walletdb::WalletPtr, Result, }; pub trait ProgramState { - fn is_valid_cashier_public_key(&self, public: &schnorr::PublicKey) -> bool; + fn is_valid_cashier_public_key(&self, public: &PublicKey) -> bool; fn is_valid_merkle(&self, merkle: &MerkleNode) -> bool; fn nullifier_exists(&self, nullifier: &Nullifier) -> bool; fn mint_vk(&self) -> &VerifyingKey; @@ -61,15 +58,17 @@ pub enum VerifyFailed { pub fn state_transition(state: &S, tx: Transaction) -> VerifyResult { // Check deposits are legit - debug!(target: "STATE TRANSITION", "iterate clear_inputs"); for (i, input) in tx.clear_inputs.iter().enumerate() { // Check the public key in the clear inputs // It should be a valid public key for the cashier - if !state.is_valid_cashier_public_key(&input.signature_public) { - log::error!(target: "STATE TRANSITION", "Not valid cashier public key"); + debug!( + "CASHIER PUBLIC: {}", + bs58::encode(serialize(&input.signature_public)).into_string() + ); + log::error!(target: "STATE TRANSITION", "Invalid cashier public key"); return Err(VerifyFailed::InvalidCashierKey(i)) } } @@ -108,7 +107,7 @@ pub fn state_transition(state: &S, tx: Transaction) -> VerifyRe let mut enc_notes = vec![]; for output in tx.outputs { // Gather all the coins - coins.push(Coin(output.revealed.coin)); + coins.push(output.revealed.coin); enc_notes.push(output.enc_note); } @@ -124,7 +123,7 @@ pub struct State { /// Nullifiers prevent double-spending pub nullifiers: RocksColumn, /// List of Cashier public keys - pub public_keys: Vec, + pub public_keys: Vec, /// Verifying key for the Mint contract pub mint_vk: VerifyingKey, /// Verifying key for the Spend contract @@ -135,8 +134,8 @@ impl State { pub async fn apply( &mut self, update: StateUpdate, - secret_keys: Vec, - notify: Option>, + secret_keys: Vec, + notify: Option>, wallet: WalletPtr, ) -> Result<()> { // Extend our list of nullifiers with the ones from the update. @@ -170,8 +169,7 @@ impl State { wallet.put_own_coins(own_coin).await?; - // TODO: Place somewhere proper - let pubkey = OrchardFixedBases::NullifierK.generator() * mod_r_p(*secret); + let pubkey = PublicKey::from_secret(*secret); debug!("Received a coin: amount {}", note.value); debug!("Send a notification"); @@ -186,7 +184,7 @@ impl State { Ok(()) } - fn try_decrypt_note(ciphertext: &EncryptedNote, secret: pallas::Base) -> Option { + fn try_decrypt_note(ciphertext: &EncryptedNote, secret: SecretKey) -> Option { match ciphertext.decrypt(&secret) { Ok(note) => Some(note), Err(_) => None, @@ -195,10 +193,9 @@ impl State { } impl ProgramState for State { - // TODO: Proper keypair type - fn is_valid_cashier_public_key(&self, public: &schnorr::PublicKey) -> bool { + fn is_valid_cashier_public_key(&self, public: &PublicKey) -> bool { debug!("Check if it is a valid cashier public key"); - self.public_keys.contains(&public.inner()) + self.public_keys.contains(&public) } fn is_valid_merkle(&self, merkle_root: &MerkleNode) -> bool { diff --git a/src/tx/builder.rs b/src/tx/builder.rs index 7beaef291..cb19541b7 100644 --- a/src/tx/builder.rs +++ b/src/tx/builder.rs @@ -7,11 +7,15 @@ use super::{ }; use crate::{ crypto::{ - merkle_node::MerkleNode, mint_proof::create_mint_proof, note::Note, schnorr, + keypair::{PublicKey, SecretKey}, + merkle_node::MerkleNode, + mint_proof::create_mint_proof, + note::Note, + schnorr::SchnorrSecret, spend_proof::create_spend_proof, }, serial::Encodable, - types::{DrkCoinBlind, DrkPublicKey, DrkSecretKey, DrkSerial, DrkTokenId, DrkValueBlind}, + types::{DrkCoinBlind, DrkSerial, DrkTokenId, DrkValueBlind}, Result, }; @@ -24,20 +28,20 @@ pub struct TransactionBuilder { pub struct TransactionBuilderClearInputInfo { pub value: u64, pub token_id: DrkTokenId, - pub signature_secret: schnorr::SecretKey, + pub signature_secret: SecretKey, } pub struct TransactionBuilderInputInfo { pub leaf_position: incrementalmerkletree::Position, pub merkle_path: Vec, - pub secret: DrkSecretKey, + pub secret: SecretKey, pub note: Note, } pub struct TransactionBuilderOutputInfo { pub value: u64, pub token_id: DrkTokenId, - pub public: DrkPublicKey, + pub public: PublicKey, } impl TransactionBuilder { @@ -63,11 +67,12 @@ impl TransactionBuilder { total } + // TODO: pass proving keys as args to this function pub fn build(self) -> Result { let mut clear_inputs = vec![]; let token_blind = DrkValueBlind::random(&mut OsRng); for input in &self.clear_inputs { - let signature_public = input.signature_secret.public_key(); + let signature_public = PublicKey::from_secret(input.signature_secret); let value_blind = DrkValueBlind::random(&mut OsRng); let clear_input = PartialTransactionClearInput { @@ -86,7 +91,7 @@ impl TransactionBuilder { for input in self.inputs { input_blinds.push(input.note.value_blind); - let signature_secret = schnorr::SecretKey::random(); + let signature_secret = SecretKey::random(&mut OsRng); let (proof, revealed) = create_spend_proof( input.note.value, diff --git a/src/tx/mod.rs b/src/tx/mod.rs index 1d251dbb3..2f94fe635 100644 --- a/src/tx/mod.rs +++ b/src/tx/mod.rs @@ -7,10 +7,12 @@ use pasta_curves::group::Group; use crate::{ crypto::{ + keypair::PublicKey, mint_proof::verify_mint_proof, note::EncryptedNote, proof::{Proof, VerifyingKey}, schnorr, + schnorr::SchnorrPublic, spend_proof::verify_spend_proof, util::{mod_r_p, pedersen_commitment_scalar, pedersen_commitment_u64}, MintRevealedValues, SpendRevealedValues, @@ -38,7 +40,7 @@ pub struct TransactionClearInput { pub token_id: DrkTokenId, pub value_blind: DrkValueBlind, pub token_blind: DrkValueBlind, - pub signature_public: schnorr::PublicKey, + pub signature_public: PublicKey, pub signature: schnorr::Signature, } diff --git a/src/tx/partial.rs b/src/tx/partial.rs index 338923135..a01f06b06 100644 --- a/src/tx/partial.rs +++ b/src/tx/partial.rs @@ -2,7 +2,7 @@ use std::io; use super::TransactionOutput; use crate::{ - crypto::{schnorr, spend_proof::SpendRevealedValues, Proof}, + crypto::{keypair::PublicKey, spend_proof::SpendRevealedValues, Proof}, error::Result, impl_vec, serial::{Decodable, Encodable, VarInt}, @@ -20,7 +20,7 @@ pub struct PartialTransactionClearInput { pub token_id: DrkTokenId, pub value_blind: DrkValueBlind, pub token_blind: DrkValueBlind, - pub signature_public: schnorr::PublicKey, + pub signature_public: PublicKey, } pub struct PartialTransactionInput { diff --git a/src/util/address.rs b/src/util/address.rs index 06ae500b7..70d7eee19 100644 --- a/src/util/address.rs +++ b/src/util/address.rs @@ -1,21 +1,21 @@ -use crate::types::*; -use group::GroupEncoding; use sha2::Digest; +use crate::crypto::keypair::PublicKey; + #[derive(Clone, Debug)] pub struct Address { - pub raw: DrkPublicKey, + pub raw: PublicKey, pub pkh: String, } impl Address { - pub fn new(raw: DrkPublicKey) -> Self { + pub fn new(raw: PublicKey) -> Self { let pkh = Self::pkh_address(&raw); Address { raw, pkh } } - fn get_hash(raw: &DrkPublicKey) -> Vec { + fn get_hash(raw: &PublicKey) -> Vec { // sha256 let mut hasher = sha2::Sha256::new(); hasher.update(raw.to_bytes()); @@ -28,7 +28,7 @@ impl Address { hash.to_vec() } - pub fn pkh_address(raw: &DrkPublicKey) -> String { + pub fn pkh_address(raw: &PublicKey) -> String { let mut hash = Self::get_hash(raw); // add version @@ -44,7 +44,7 @@ impl Address { payload.append(&mut payload_hash[0..4].to_vec()); - // base56 encoding + // base58 encoding let address: String = bs58::encode(payload).into_string(); address diff --git a/src/util/token_list.rs b/src/util/token_list.rs index b4a10f7a7..c534c112b 100644 --- a/src/util/token_list.rs +++ b/src/util/token_list.rs @@ -1,9 +1,9 @@ use std::collections::HashMap; -use pasta_curves::pallas; use serde_json::Value; use crate::{ + types::DrkTokenId, util::{generate_id, NetworkName}, Error, Result, }; @@ -55,7 +55,7 @@ impl TokenList { #[derive(Debug, Clone)] pub struct DrkTokenList { - pub tokens: HashMap>, + pub tokens: HashMap>, } impl DrkTokenList { @@ -64,28 +64,28 @@ impl DrkTokenList { let eth_symbols = eth_list.get_symbols()?; let btc_symbols = btc_list.get_symbols()?; - let sol_tokens: HashMap = sol_symbols + let sol_tokens: HashMap = sol_symbols .iter() .filter_map(|symbol| { Self::generate_hash_pair(sol_list, &NetworkName::Solana, symbol).ok() }) .collect(); - let eth_tokens: HashMap = eth_symbols + let eth_tokens: HashMap = eth_symbols .iter() .filter_map(|symbol| { Self::generate_hash_pair(eth_list, &NetworkName::Ethereum, symbol).ok() }) .collect(); - let btc_tokens: HashMap = btc_symbols + let btc_tokens: HashMap = btc_symbols .iter() .filter_map(|symbol| { Self::generate_hash_pair(btc_list, &NetworkName::Bitcoin, symbol).ok() }) .collect(); - let tokens: HashMap> = HashMap::from([ + let tokens: HashMap> = HashMap::from([ (NetworkName::Solana, sol_tokens), (NetworkName::Ethereum, eth_tokens), (NetworkName::Bitcoin, btc_tokens), @@ -98,7 +98,7 @@ impl DrkTokenList { token_list: &TokenList, network_name: &NetworkName, symbol: &str, - ) -> Result<(String, pallas::Base)> { + ) -> Result<(String, DrkTokenId)> { if let Some(token_id) = &token_list.search_id(symbol)? { return Ok((symbol.to_string(), generate_id(token_id, network_name)?)) }; @@ -106,7 +106,7 @@ impl DrkTokenList { Err(Error::NotSupportedToken) } - pub fn symbol_from_id(&self, id: &pallas::Base) -> Result> { + pub fn symbol_from_id(&self, id: &DrkTokenId) -> Result> { for (network, tokens) in self.tokens.iter() { for (key, val) in tokens.iter() { if val == id { diff --git a/src/wallet/cashierdb.rs b/src/wallet/cashierdb.rs index d20424498..1787d9495 100644 --- a/src/wallet/cashierdb.rs +++ b/src/wallet/cashierdb.rs @@ -2,14 +2,19 @@ use std::{path::Path, str::FromStr}; use async_std::sync::Arc; use log::{debug, error, info}; -use pasta_curves::pallas; use sqlx::{ sqlite::{SqliteConnectOptions, SqliteJournalMode, SqlitePoolOptions}, Row, SqlitePool, }; -use super::{Keypair, WalletApi}; -use crate::{client::ClientFailed, types::*, util::NetworkName, Error, Result}; +use super::wallet_api::WalletApi; +use crate::{ + client::ClientFailed, + crypto::keypair::{Keypair, PublicKey, SecretKey}, + types::DrkTokenId, + util::NetworkName, + Error, Result, +}; pub type CashierDbPtr = Arc; @@ -27,7 +32,7 @@ pub struct WithdrawToken { } pub struct DepositToken { - pub drk_public_key: DrkPublicKey, + pub drk_public_key: PublicKey, pub token_key: TokenKey, pub token_id: DrkTokenId, pub mint_address: String, @@ -64,11 +69,15 @@ impl CashierDb { let main_kps = include_str!("../../sql/cashier_main_keypairs.sql"); let deposit_kps = include_str!("../../sql/cashier_deposit_keypairs.sql"); let withdraw_kps = include_str!("../../sql/cashier_withdraw_keypairs.sql"); + let mut conn = self.conn.acquire().await?; + debug!("Initializing main keypairs table"); sqlx::query(main_kps).execute(&mut conn).await?; + debug!("Initializing deposit keypairs table"); sqlx::query(deposit_kps).execute(&mut conn).await?; + debug!("Initializing withdraw keypairs table"); sqlx::query(withdraw_kps).execute(&mut conn).await?; Ok(()) @@ -130,8 +139,8 @@ impl CashierDb { pub async fn put_withdraw_keys( &self, token_key_public: &[u8], - d_key_public: &pallas::Point, - d_key_secret: &pallas::Scalar, + d_key_public: &PublicKey, + d_key_secret: &SecretKey, network: &NetworkName, token_id: &DrkTokenId, mint_address: String, @@ -167,7 +176,7 @@ impl CashierDb { pub async fn put_deposit_keys( &self, - d_key_public: &DrkPublicKey, + d_key_public: &PublicKey, token_key_secret: &[u8], token_key_public: &[u8], network: &NetworkName, @@ -202,7 +211,7 @@ impl CashierDb { Ok(()) } - pub async fn get_withdraw_private_keys(&self) -> Result> { + pub async fn get_withdraw_private_keys(&self) -> Result> { debug!("Getting withdraw private keys"); let confirm = self.get_value_serialized(&false)?; @@ -217,7 +226,7 @@ impl CashierDb { let mut secret_keys = vec![]; for row in rows { - let key = self.get_value_deserialized(row.get("d_key_secret"))?; + let key: SecretKey = self.get_value_deserialized(row.get("d_key_secret"))?; secret_keys.push(key); } @@ -226,7 +235,7 @@ impl CashierDb { pub async fn get_withdraw_token_public_key_by_dkey_public( &self, - pubkey: &DrkPublicKey, + pubkey: &PublicKey, ) -> Result> { debug!("Get token address by pubkey"); let d_key_public = self.get_value_serialized(pubkey)?; @@ -259,7 +268,7 @@ impl CashierDb { pub async fn get_deposit_token_keys_by_dkey_public( &self, - d_key_public: &DrkPublicKey, + d_key_public: &PublicKey, network: &NetworkName, ) -> Result> { debug!("Checking for existing dkey"); @@ -350,7 +359,7 @@ impl CashierDb { pub async fn confirm_deposit_key_record( &self, - d_key_public: &DrkPublicKey, + d_key_public: &PublicKey, network: &NetworkName, ) -> Result<()> { debug!("Confirm deposit keys"); diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs index 9abde8812..8a1a521bc 100644 --- a/src/wallet/mod.rs +++ b/src/wallet/mod.rs @@ -1,7 +1,3 @@ pub mod cashierdb; pub mod wallet_api; pub mod walletdb; - -pub use cashierdb::{CashierDb, CashierDbPtr}; -pub use wallet_api::WalletApi; -pub use walletdb::{Keypair, WalletDb, WalletPtr}; diff --git a/src/wallet/walletdb.rs b/src/wallet/walletdb.rs index 890967cd4..0aadb9a3f 100644 --- a/src/wallet/walletdb.rs +++ b/src/wallet/walletdb.rs @@ -1,10 +1,7 @@ use std::{path::Path, str::FromStr}; use async_std::sync::Arc; -use halo2::arithmetic::Field; -use halo2_gadgets::ecc::FixedPoints; use log::{debug, error, info}; -use pasta_curves::pallas; use rand::rngs::OsRng; use sqlx::{ sqlite::{SqliteConnectOptions, SqliteJournalMode}, @@ -14,25 +11,23 @@ use sqlx::{ use crate::{ client::ClientFailed, crypto::{ - coin::Coin, constants::OrchardFixedBases, note::Note, nullifier::Nullifier, util::mod_r_p, + coin::Coin, + keypair::{Keypair, PublicKey, SecretKey}, + note::Note, + nullifier::Nullifier, OwnCoin, OwnCoins, }, serial::serialize, - wallet::WalletApi, + types::DrkTokenId, + wallet::wallet_api::WalletApi, Error, Result, }; pub type WalletPtr = Arc; -#[derive(Clone, Debug)] -pub struct Keypair { - pub public: pallas::Point, - pub secret: pallas::Base, -} - #[derive(Clone, Debug)] pub struct Balance { - pub token_id: pallas::Base, + pub token_id: DrkTokenId, pub value: u64, pub nullifier: Nullifier, } @@ -73,9 +68,12 @@ impl WalletDb { debug!("Initializing wallet database"); let keys = include_str!("../../sql/keys.sql"); let coins = include_str!("../../sql/coins.sql"); + let mut conn = self.conn.acquire().await?; + debug!("Initializing keys table"); sqlx::query(keys).execute(&mut conn).await?; + debug!("Initializing coins table"); sqlx::query(coins).execute(&mut conn).await?; Ok(()) @@ -92,23 +90,22 @@ impl WalletDb { Err(Error::from(ClientFailed::KeyExists)) } Err(_) => { - let secret = pallas::Base::random(&mut OsRng); - let public = OrchardFixedBases::NullifierK.generator() * mod_r_p(secret); - self.put_keypair(&public, &secret).await?; + let keypair = Keypair::random(&mut OsRng); + self.put_keypair(&keypair.public, &keypair.secret).await?; Ok(()) } } } - pub async fn put_keypair(&self, public: &pallas::Point, secret: &pallas::Base) -> Result<()> { + pub async fn put_keypair(&self, public: &PublicKey, secret: &SecretKey) -> Result<()> { debug!("Writing keypair into the wallet database"); - let p = serialize(public); - let s = serialize(secret); + let pubkey = serialize(&public.0); + let secret = serialize(&secret.0); let mut conn = self.conn.acquire().await?; sqlx::query("INSERT INTO keys(public, secret) VALUES (?1, ?2)") - .bind(p) - .bind(s) + .bind(pubkey) + .bind(secret) .execute(&mut conn) .await?; @@ -121,8 +118,8 @@ impl WalletDb { // TODO: Think about multiple keys let row = sqlx::query("SELECT * FROM keys").fetch_one(&mut conn).await?; - let public: pallas::Point = self.get_value_deserialized(row.get("public"))?; - let secret: pallas::Base = self.get_value_deserialized(row.get("secret"))?; + let public: PublicKey = self.get_value_deserialized(row.get("public"))?; + let secret: SecretKey = self.get_value_deserialized(row.get("secret"))?; Ok(vec![Keypair { public, secret }]) } @@ -256,7 +253,7 @@ impl WalletDb { Ok(Balances { list }) } - pub async fn get_token_id(&self) -> Result> { + pub async fn get_token_id(&self) -> Result> { debug!("Getting token ID"); let is_spent = 0; @@ -275,7 +272,7 @@ impl WalletDb { Ok(token_ids) } - pub async fn token_id_exists(&self, token_id: pallas::Base) -> Result { + pub async fn token_id_exists(&self, token_id: DrkTokenId) -> Result { debug!("Checking if token ID exists"); let is_spent = 0; let id = self.get_value_serialized(&token_id)?;