Use the new keypair module throughout the codebase.

This commit is contained in:
parazyd
2021-12-02 19:03:34 +01:00
parent d79a18e37c
commit ff01e7b685
28 changed files with 421 additions and 377 deletions

View File

@@ -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<Bridge>,
cashier_wallet: Arc<CashierDb>,
recv_coin: async_channel::Receiver<(pallas::Point, u64)>,
recv_coin: async_channel::Receiver<(PublicKey, u64)>,
executor: Arc<Executor<'_>>,
) -> 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::<MerkleNode, 32>::new(100),
merkle_roots,
nullifiers,
public_keys: cashier_public_keys,
mint_vk,
spend_vk,
public_keys: cashier_public_keys,
}));
if get_address_flag {

View File

@@ -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 {

View File

@@ -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<pallas::Base>,
secrets: Vec<SecretKey>,
}
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,
}],
};

View File

@@ -102,7 +102,8 @@ pub struct SpendContract {
pub asset_blind: Option<pallas::Scalar>,
pub leaf_pos: Option<u32>,
pub merkle_path: Option<[pallas::Base; 32]>,
pub sig_secret: Option<pallas::Scalar>,
//pub sig_secret: Option<pallas::Scalar>,
pub sig_secret: Option<pallas::Base>,
}
impl UtilitiesInstructions<pallas::Base> for SpendContract {
@@ -442,11 +443,16 @@ impl Circuit<pallas::Base> 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(

View File

@@ -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<Mutex<State>>,
) -> ClientResult<()> {
@@ -222,11 +231,11 @@ impl Client {
}
async fn update_state(
secret_keys: Vec<pallas::Base>,
secret_keys: Vec<SecretKey>,
slab: &Slab,
state: Arc<Mutex<State>>,
wallet: WalletPtr,
notify: Option<async_channel::Sender<(pallas::Point, u64)>>,
notify: Option<async_channel::Sender<(PublicKey, u64)>>,
) -> 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<Mutex<State>>,
cashier_wallet: CashierDbPtr,
notify: async_channel::Sender<(pallas::Point, u64)>,
notify: async_channel::Sender<(PublicKey, u64)>,
executor: Arc<Executor<'_>>,
) -> 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<Result<()>> = executor.spawn(async move {
let task: smol::Task<Result<()>> = executor.spawn(async move {
loop {
let slab = gateway_slabs_sub.recv().await?;
debug!("Received new slab");
let mut secret_keys: Vec<pallas::Base> = 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<Result<()>> = executor.spawn(async move {

View File

@@ -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 {

View File

@@ -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
// <ExtendedPoint as CofactorGroup>::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()
}

View File

@@ -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<S: io::Write>(&self, mut s: S) -> Result<usize> {
s.write_slice(&self.to_bytes()[..])?;
Ok(32)
}
}
impl Decodable for pallas::Base {
fn decode<D: io::Read>(mut d: D) -> Result<Self> {
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<S: io::Write>(&self, mut s: S) -> Result<usize> {
s.write_slice(&self.to_bytes()[..])?;
Ok(32)
}
}
impl Decodable for pallas::Scalar {
fn decode<D: io::Read>(mut d: D) -> Result<Self> {
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<S: io::Write>(&self, mut s: S) -> Result<usize> {
s.write_slice(&self.to_bytes()[..])?;
Ok(32)
}
}
impl Decodable for pallas::Point {
fn decode<D: io::Read>(mut d: D) -> Result<Self> {
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<S: io::Write>(&self, mut s: S) -> Result<usize> {
s.write_slice(&self.0.to_bytes()[..])?;
Ok(32)
}
}
impl Decodable for SecretKey {
fn decode<D: io::Read>(mut d: D) -> Result<Self> {
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<S: io::Write>(&self, mut s: S) -> Result<usize> {
s.write_slice(&self.0.to_bytes()[..])?;
Ok(32)
}
}
impl Decodable for PublicKey {
fn decode<D: io::Read>(mut d: D) -> Result<Self> {
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)
}
}
}

View File

@@ -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()),

View File

@@ -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<merkle_node::MerkleNode>,
//pub witness: BridgeFrontier<merkle::MerkleHash, 32>,
pub nullifier: nullifier::Nullifier,

View File

@@ -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<EncryptedNote> {
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<EncryptedNote> {
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<Note> {
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<Note> {
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!(

View File

@@ -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)
}

View File

@@ -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<S: io::Write>(&self, mut s: S) -> Result<usize> {
s.write_slice(&self.to_bytes()[..])?;
Ok(32)
}
}
impl Decodable for pasta::Fp {
fn decode<D: io::Read>(mut d: D) -> Result<Self> {
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<S: io::Write>(&self, mut s: S) -> Result<usize> {
s.write_slice(&self.to_bytes()[..])?;
Ok(32)
}
}
impl Decodable for pasta::Fq {
fn decode<D: io::Read>(mut d: D) -> Result<Self> {
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<S: io::Write>(&self, mut s: S) -> Result<usize> {
s.write_slice(&self.to_bytes()[..])?;
Ok(32)
}
}
impl Decodable for pasta::Ep {
fn decode<D: io::Read>(mut d: D) -> Result<Self> {
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)
}
}
}

View File

@@ -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<S: io::Write>(&self, s: S) -> Result<usize> {
self.0.encode(s)
}
}
impl Decodable for PublicKey {
fn decode<D: io::Read>(mut d: D) -> Result<Self> {
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));
}

View File

@@ -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<MerkleNode>,
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<MerkleNode>,
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),

View File

@@ -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<Self>,
drk_pub_key: DrkPublicKey,
drk_pub_key: PublicKey,
mint: Option<String>,
executor: Arc<Executor<'_>>,
) -> BridgeSubscribtion {
@@ -128,7 +131,7 @@ impl Bridge {
self: Arc<Self>,
req: async_channel::Receiver<BridgeRequests>,
rep: async_channel::Sender<BridgeResponse>,
drk_pub_key: DrkPublicKey,
drk_pub_key: PublicKey,
mint: Option<String>,
executor: Arc<Executor<'_>>,
) -> Result<()> {
@@ -232,7 +235,7 @@ impl Bridge {
pub trait NetworkClient {
async fn subscribe(
self: Arc<Self>,
drk_pub_key: DrkPublicKey,
drk_pub_key: PublicKey,
mint: Option<String>,
executor: Arc<Executor<'_>>,
) -> Result<TokenSubscribtion>;
@@ -242,7 +245,7 @@ pub trait NetworkClient {
self: Arc<Self>,
private_key: Vec<u8>,
public_key: Vec<u8>,
drk_pub_key: DrkPublicKey,
drk_pub_key: PublicKey,
mint: Option<String>,
executor: Arc<Executor<'_>>,
) -> Result<String>;

View File

@@ -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,
};

View File

@@ -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<Self>,
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<Self>,
drk_pub_key: DrkPublicKey,
drk_pub_key: PublicKey,
_mint_address: Option<String>,
executor: Arc<Executor<'_>>,
) -> Result<TokenSubscribtion> {
@@ -414,7 +414,7 @@ impl NetworkClient for EthClient {
self: Arc<Self>,
_private_key: Vec<u8>,
public_key: Vec<u8>,
drk_pub_key: DrkPublicKey,
drk_pub_key: PublicKey,
_mint_address: Option<String>,
executor: Arc<Executor<'_>>,
) -> Result<String> {

View File

@@ -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<Self>,
keypair: Keypair,
drk_pub_key: DrkPublicKey,
drk_pub_key: PublicKey,
mint: Option<Pubkey>,
) -> SolResult<()> {
debug!(target: "SOL BRIDGE", "handle_subscribe_request()");
@@ -396,7 +396,7 @@ impl SolClient {
impl NetworkClient for SolClient {
async fn subscribe(
self: Arc<Self>,
drk_pub_key: DrkPublicKey,
drk_pub_key: PublicKey,
mint_address: Option<String>,
executor: Arc<Executor<'_>>,
) -> Result<TokenSubscribtion> {
@@ -431,7 +431,7 @@ impl NetworkClient for SolClient {
self: Arc<Self>,
private_key: Vec<u8>,
_public_key: Vec<u8>,
drk_pub_key: DrkPublicKey,
drk_pub_key: PublicKey,
mint_address: Option<String>,
executor: Arc<Executor<'_>>,
) -> Result<String> {

View File

@@ -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<S: ProgramState>(state: &S, tx: Transaction) -> VerifyResult<StateUpdate> {
// 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<S: ProgramState>(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<columns::Nullifiers>,
/// List of Cashier public keys
pub public_keys: Vec<pallas::Point>,
pub public_keys: Vec<PublicKey>,
/// 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<pallas::Base>,
notify: Option<async_channel::Sender<(pallas::Point, u64)>>,
secret_keys: Vec<SecretKey>,
notify: Option<async_channel::Sender<(PublicKey, u64)>>,
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<Note> {
fn try_decrypt_note(ciphertext: &EncryptedNote, secret: SecretKey) -> Option<Note> {
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 {

View File

@@ -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<MerkleNode>,
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<Transaction> {
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,

View File

@@ -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,
}

View File

@@ -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 {

View File

@@ -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<u8> {
fn get_hash(raw: &PublicKey) -> Vec<u8> {
// 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

View File

@@ -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<NetworkName, HashMap<String, pallas::Base>>,
pub tokens: HashMap<NetworkName, HashMap<String, DrkTokenId>>,
}
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<String, pallas::Base> = sol_symbols
let sol_tokens: HashMap<String, DrkTokenId> = sol_symbols
.iter()
.filter_map(|symbol| {
Self::generate_hash_pair(sol_list, &NetworkName::Solana, symbol).ok()
})
.collect();
let eth_tokens: HashMap<String, pallas::Base> = eth_symbols
let eth_tokens: HashMap<String, DrkTokenId> = eth_symbols
.iter()
.filter_map(|symbol| {
Self::generate_hash_pair(eth_list, &NetworkName::Ethereum, symbol).ok()
})
.collect();
let btc_tokens: HashMap<String, pallas::Base> = btc_symbols
let btc_tokens: HashMap<String, DrkTokenId> = btc_symbols
.iter()
.filter_map(|symbol| {
Self::generate_hash_pair(btc_list, &NetworkName::Bitcoin, symbol).ok()
})
.collect();
let tokens: HashMap<NetworkName, HashMap<String, pallas::Base>> = HashMap::from([
let tokens: HashMap<NetworkName, HashMap<String, DrkTokenId>> = 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<Option<(NetworkName, String)>> {
pub fn symbol_from_id(&self, id: &DrkTokenId) -> Result<Option<(NetworkName, String)>> {
for (network, tokens) in self.tokens.iter() {
for (key, val) in tokens.iter() {
if val == id {

View File

@@ -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<CashierDb>;
@@ -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<Vec<DrkSecretKey>> {
pub async fn get_withdraw_private_keys(&self) -> Result<Vec<SecretKey>> {
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<Option<WithdrawToken>> {
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<Vec<TokenKey>> {
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");

View File

@@ -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};

View File

@@ -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<WalletDb>;
#[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<Vec<pallas::Base>> {
pub async fn get_token_id(&self) -> Result<Vec<DrkTokenId>> {
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<bool> {
pub async fn token_id_exists(&self, token_id: DrkTokenId) -> Result<bool> {
debug!("Checking if token ID exists");
let is_spent = 0;
let id = self.get_value_serialized(&token_id)?;