Skip to content

Commit

Permalink
Merge pull request #142 from h4sh3d/manage-accordant-address
Browse files Browse the repository at this point in the history
Manage accordant address
  • Loading branch information
Lederstrumpf authored Sep 27, 2021
2 parents bd5587d + 61b2868 commit 75dbcab
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 12 deletions.
15 changes: 15 additions & 0 deletions src/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use thiserror::Error;
use tiny_keccak::{Hasher, Keccak};

use crate::consensus::{self, CanonicalBytes, Decodable, Encodable};
use crate::role::Accordant;

/// List of cryptographic errors that can be encountered in cryptographic operations such as
/// signatures, proofs, key derivation, or commitments.
Expand All @@ -19,6 +20,9 @@ pub enum Error {
/// The key identifier is not supported and the key cannot be derived.
#[error("The key identifier is not supported and the key cannot be derived")]
UnsupportedKey,
/// The key or key identifier does not exists or is missing.
#[error("The key or key identifier does not exists or is missing")]
MissingKey,
/// The signature does not pass the validation tests.
#[error("The signature does not pass the validation")]
InvalidSignature,
Expand Down Expand Up @@ -239,6 +243,17 @@ impl Decodable for SharedKeyId {
}
}

pub struct AccordantKeys<A: Accordant> {
pub spend_key: A::PublicKey,
pub extra_accordant_keys: Vec<TaggedElement<u16, A::PublicKey>>,
pub shared_keys: Vec<TaggedElement<SharedKeyId, A::SharedSecretKey>>,
}

pub struct SwapAccordantKeys<A: Accordant> {
pub alice: AccordantKeys<A>,
pub bob: AccordantKeys<A>,
}

fixed_hash::construct_fixed_hash!(
/// Result of a keccak256 commitment.
#[cfg_attr(
Expand Down
51 changes: 48 additions & 3 deletions src/monero.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//! Implementation of the Monero blockchain as an accordant blockchain in a swap. This
//! implementation should work in pair with any other arbitrating implementation, like Bitcoin.
use crate::blockchain::{self, Asset};
use crate::blockchain::{self, Asset, Network};
use crate::consensus::{self, CanonicalBytes};
use crate::crypto::{Keys, SharedKeyId, SharedSecretKeys};
use crate::crypto::{self, AccordantKeys, Keys, SharedKeyId, SharedSecretKeys, SwapAccordantKeys};
use crate::role::Accordant;

use monero::util::key::{PrivateKey, PublicKey};
Expand All @@ -22,7 +22,52 @@ pub const SHARED_VIEW_KEY_ID: u16 = 0x01;
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
pub struct Monero;

impl Accordant for Monero {}
impl Accordant for Monero {
fn derive_lock_address(
network: Network,
keys: SwapAccordantKeys<Self>,
) -> Result<Address, crypto::Error> {
let SwapAccordantKeys {
alice:
AccordantKeys {
spend_key: alice_spend_key,
shared_keys: alice_shared_keys,
..
},
bob:
AccordantKeys {
spend_key: bob_spend_key,
shared_keys: bob_shared_keys,
..
},
} = keys;

let alice_tagged_view_secretkey = alice_shared_keys
.iter()
.find(|tagged_key| *tagged_key.tag() == SharedKeyId::new(SHARED_VIEW_KEY_ID))
.ok_or(crypto::Error::MissingKey)?;
let bob_tagged_view_secretkey = bob_shared_keys
.iter()
.find(|tagged_key| *tagged_key.tag() == SharedKeyId::new(SHARED_VIEW_KEY_ID))
.ok_or(crypto::Error::MissingKey)?;

let public_spend = alice_spend_key + bob_spend_key;
let secret_view = alice_tagged_view_secretkey.elem() + bob_tagged_view_secretkey.elem();
let public_view = PublicKey::from_private_key(&secret_view);

Ok(Address::standard(network.into(), public_spend, public_view))
}
}

impl From<Network> for monero::Network {
fn from(network: Network) -> Self {
match network {
Network::Mainnet => monero::Network::Mainnet,
Network::Testnet => monero::Network::Stagenet,
Network::Local => monero::Network::Testnet,
}
}
}

impl std::str::FromStr for Monero {
type Err = crate::consensus::Error;
Expand Down
3 changes: 0 additions & 3 deletions src/protocol_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,9 +318,6 @@ where
type Strategy = AsStrict;
}

// TODO: Add more common data to reveal, e.g. help to ensure that both node uses the same value for
// fee

/// Reveals the parameters commited by the [`CommitAliceParameters`] protocol message.
#[derive(Clone, Debug, Display)]
#[display(Debug)]
Expand Down
18 changes: 13 additions & 5 deletions src/role.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,18 @@ use std::fmt::Debug;
use std::io;
use std::str::FromStr;

use crate::blockchain::{Address, Asset, Fee, FeePriority, Onchain, Timelock, Transactions};
use crate::blockchain::{
Address, Asset, Fee, FeePriority, Network, Onchain, Timelock, Transactions,
};
use crate::bundle::{
AliceParameters, BobParameters, CoreArbitratingTransactions, CosignedArbitratingCancel,
FullySignedBuy, FullySignedPunish, FullySignedRefund, SignedAdaptorBuy, SignedAdaptorRefund,
SignedArbitratingLock,
};
use crate::consensus::{self, Decodable, Encodable};
use crate::crypto::{
AccordantKeyId, ArbitratingKeyId, KeyGenerator, Keys, SharedSecretKeys, Sign, Signatures,
TaggedElement, TaggedExtraKeys, TaggedSharedKeys,
self, AccordantKeyId, ArbitratingKeyId, KeyGenerator, Keys, SharedSecretKeys, Sign, Signatures,
SwapAccordantKeys, TaggedElement, TaggedExtraKeys, TaggedSharedKeys,
};
use crate::negotiation::PublicOffer;
use crate::script::{DataLock, DataPunishableLock, DoubleKeys, ScriptPath};
Expand Down Expand Up @@ -1329,5 +1331,11 @@ pub trait Arbitrating:
}

/// An accordant is the blockchain which does not need transaction inside the protocol nor
/// timelocks, it is the blockchain with the less requirements for an atomic swap.
pub trait Accordant: Asset + Address + Keys + SharedSecretKeys + Clone + Eq {}
/// timelocks: it is the blockchain with fewer requirements for an atomic swap.
pub trait Accordant: Asset + Address + Keys + SharedSecretKeys + Clone + Eq {
/// Derive the lock address for the accordant blockchain.
fn derive_lock_address(
network: Network,
keys: SwapAccordantKeys<Self>,
) -> Result<Self::Address, crypto::Error>;
}
60 changes: 59 additions & 1 deletion tests/wallet.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
use bitcoin::hashes::{sha256d, Hash};
use rand::prelude::*;
use std::convert::TryInto;
use std::str::FromStr;

use farcaster_core::consensus::CanonicalBytes;
use farcaster_core::crypto::{
AccordantKeyId, ArbitratingKeyId, GenerateKey, GenerateSharedKey, ProveCrossGroupDleq,
SharedKeyId, Sign,
};
use farcaster_core::monero::SHARED_VIEW_KEY_ID;
use farcaster_core::swap::btcxmr::*;
use farcaster_core::{consensus::CanonicalBytes, crypto::SwapAccordantKeys};

#[test]
fn create_key_manager_from_seed() {
Expand Down Expand Up @@ -182,3 +183,60 @@ fn key_manager_can_recover_secret() {
secret.reverse();
assert_eq!(secret, recovered_secret.as_canonical_bytes());
}

#[test]
fn can_create_accordant_address() {
use farcaster_core::crypto::{AccordantKeys, TaggedElement};
use farcaster_core::monero::Monero;
use farcaster_core::role::Accordant;
use monero::{Address, Network, PrivateKey, PublicKey};

let swap_index = 0;
let mut alice_key_manager = KeyManager::new([1u8; 32], swap_index).unwrap();
let mut bob_key_manager = KeyManager::new([2u8; 32], swap_index).unwrap();

let alice_spend_pubkey = alice_key_manager.get_pubkey(AccordantKeyId::Spend).unwrap();
let bob_spend_pubkey = bob_key_manager.get_pubkey(AccordantKeyId::Spend).unwrap();

let alice_view_secretkey: PrivateKey = alice_key_manager
.get_shared_key(SharedKeyId::new(SHARED_VIEW_KEY_ID))
.unwrap();
let bob_view_secretkey: PrivateKey = bob_key_manager
.get_shared_key(SharedKeyId::new(SHARED_VIEW_KEY_ID))
.unwrap();

let public_spend = alice_spend_pubkey + bob_spend_pubkey;
let secret_view = alice_view_secretkey + bob_view_secretkey;
let public_view = PublicKey::from_private_key(&secret_view);

let accordant_address = Address::standard(Network::Testnet, public_spend, public_view);
let addr = "9srAu5mbgRwjoUiobvJ6zXB2JL7MZsPRPTgzhVjFdZJb6afRPaeN1ND4e4MWz55Q2JM3bQLTWmMgyjPZZHLa4X587UgdkNy";
assert_eq!(Address::from_str(addr), Ok(accordant_address));

// redo process like manual above, but test against result from Monero's derive_lock_address implementation
let lock_address = Monero::derive_lock_address(
farcaster_core::blockchain::Network::Local,
SwapAccordantKeys {
alice: AccordantKeys {
spend_key: alice_spend_pubkey,
shared_keys: vec![TaggedElement::new(
SharedKeyId::new(SHARED_VIEW_KEY_ID),
alice_view_secretkey,
)],
extra_accordant_keys: vec![],
},
bob: AccordantKeys {
spend_key: bob_spend_pubkey,
shared_keys: vec![TaggedElement::new(
SharedKeyId::new(SHARED_VIEW_KEY_ID),
bob_view_secretkey,
)],
extra_accordant_keys: vec![],
},
},
);
assert_eq!(
lock_address.expect("derivation of lock address should work since manual does"),
accordant_address
);
}

0 comments on commit 75dbcab

Please sign in to comment.