Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CONTRACTS] Add Owner API function to create mwixnet request #720

Merged
merged 4 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions api/src/owner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use crate::libwallet::{
};
use crate::util::logger::LoggingConfig;
use crate::util::secp::key::SecretKey;
use crate::util::secp::pedersen;
use crate::util::{from_hex, static_secp_instance, Mutex, ZeroingString};
use grin_wallet_util::OnionV3Address;
use std::convert::TryFrom;
Expand Down Expand Up @@ -835,12 +836,12 @@ where
&self,
keychain_mask: Option<&SecretKey>,
params: &MixnetReqCreationParams,
slate: &Slate,
// use_test_rng: bool,
commitment: &pedersen::Commitment,
lock_output: bool, // use_test_rng: bool,
) -> Result<SwapReq, Error> {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
owner::create_mwixnet_req(&mut **w, keychain_mask, params, slate)
owner::create_mwixnet_req(&mut **w, keychain_mask, params, commitment, lock_output)
}

/// Processes an invoice tranaction created by another party, essentially
Expand Down
49 changes: 44 additions & 5 deletions controller/tests/contract_srs_mwmixnet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ extern crate grin_wallet_controller as wallet;
extern crate grin_wallet_impls as impls;
extern crate log;

use grin_util::{secp::SecretKey, static_secp_instance};
use grin_wallet_libwallet as libwallet;

use impls::test_framework::{self};
use libwallet::contract::my_fee_contribution;
use libwallet::contract::types::{ContractNewArgsAPI, ContractSetupArgsAPI};
use libwallet::mwixnet::onion::crypto::secp;
use libwallet::mwixnet::types::MixnetReqCreationParams;
use libwallet::{Slate, SlateState, TxLogEntryType};
use std::sync::atomic::Ordering;
Expand Down Expand Up @@ -83,13 +83,52 @@ fn contract_srs_mwixnet_tx_impl(test_dir: &'static str) -> Result<(), libwallet:
assert_eq!(slate.state, SlateState::Standard3);

wallet::controller::owner_single_use(Some(send_wallet.clone()), send_mask, None, |api, m| {
let server_key_1 = secp::random_secret();
let server_key_2 = secp::random_secret();
api.post_tx(m, &slate, false)?;
Ok(())
})?;
bh += 1;

let _ =
test_framework::award_blocks_to_wallet(&chain, send_wallet.clone(), send_mask, 3, false);
bh += 3;

// Recipient wallet sends outputs to mwixnet
wallet::controller::owner_single_use(Some(recv_wallet.clone()), recv_mask, None, |api, m| {
let secp_locked = static_secp_instance();
let secp = secp_locked.lock();
let server_pubkey_str_1 =
"97444ae673bb92c713c1a2f7b8882ffbfc1c67401a280a775dce1a8651584332";
let server_pubkey_str_2 =
"0c9414341f2140ed34a5a12a6479bf5a6404820d001ab81d9d3e8cc38f049b4e";
let server_pubkey_str_3 =
"b58ece97d60e71bb7e53218400b0d67bfe6a3cb7d3b4a67a44f8fb7c525cbca5";
let server_key_1 =
SecretKey::from_slice(&secp, &grin_util::from_hex(&server_pubkey_str_1).unwrap())
.unwrap();
let server_key_2 =
SecretKey::from_slice(&secp, &grin_util::from_hex(&server_pubkey_str_2).unwrap())
.unwrap();
let server_key_3 =
SecretKey::from_slice(&secp, &grin_util::from_hex(&server_pubkey_str_3).unwrap())
.unwrap();
let params = MixnetReqCreationParams {
server_keys: vec![server_key_1, server_key_2],
server_keys: vec![server_key_1, server_key_2, server_key_3],
fee_per_hop: 50_000_000,
};
//api.create_mwixnet_req(send_mask, &params, &slate)?;
let outputs = api.retrieve_outputs(recv_mask, false, false, None)?;
// get last output
let last_output = outputs.1[outputs.1.len() - 1].clone();

let mwixnet_req = api.create_mwixnet_req(m, &params, &last_output.commit, true)?;

println!("MWIXNET REQ: {:?}", mwixnet_req);

// check output we created comsig for is indeed locked
let outputs = api.retrieve_outputs(recv_mask, false, false, None)?;
// get last output
let last_output = outputs.1[outputs.1.len() - 1].clone();
assert!(last_output.output.status == libwallet::OutputStatus::Locked);

Ok(())
})?;

Expand Down
109 changes: 71 additions & 38 deletions libwallet/src/api_impl/owner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use uuid::Uuid;
use crate::api_impl::foreign::finalize_tx as foreign_finalize;
use crate::contract::proofs::{InvoiceProof, ProofWitness};
use crate::grin_core::core::hash::Hashed;
use crate::grin_core::core::{Output, OutputFeatures, Transaction};
use crate::grin_core::core::{FeeFields, Output, OutputFeatures, Transaction};
use crate::grin_core::libtx::proof;
use crate::grin_keychain::ViewKey;
use crate::grin_util::secp::key::SecretKey;
Expand Down Expand Up @@ -49,6 +49,7 @@ use chrono::prelude::{DateTime, NaiveDateTime, Utc};
use ed25519_dalek::PublicKey as DalekPublicKey;
use ed25519_dalek::SecretKey as DalekSecretKey;
use ed25519_dalek::Verifier;
use x25519_dalek::{PublicKey as xPublicKey, StaticSecret};

use std::convert::{TryFrom, TryInto};
use std::sync::mpsc::Sender;
Expand Down Expand Up @@ -1608,56 +1609,88 @@ pub fn create_mwixnet_req<'a, T: ?Sized, C, K>(
w: &mut T,
keychain_mask: Option<&SecretKey>,
params: &MixnetReqCreationParams,
slate: &Slate,
// use_test_rng: bool,
commitment: &pedersen::Commitment,
lock_output: bool,
) -> Result<SwapReq, Error>
where
T: WalletBackend<'a, C, K>,
C: NodeClient + 'a,
K: Keychain + 'a,
{
let context = w.get_private_context(keychain_mask, slate.id.as_bytes())?;

let my_keys = context.get_private_keys();
let kernel = slate.tx_or_err()?.kernels()[0];
let parent_key_id = w.parent_key_id();
let keychain = w.keychain(keychain_mask)?;
let outputs = updater::retrieve_outputs(w, keychain_mask, false, None, Some(&parent_key_id))?;

let msg = kernel.msg_to_sign()?;
let mut output = None;
for o in &outputs {
if o.commit == *commitment {
output = Some(o.output.clone());
break;
}
}

let comsig = ComSignature::sign(slate.amount, &my_keys.0, &msg.to_hex().as_bytes().to_vec())?;
if output.is_none() {
return Err(Error::GenericError(String::from("output not found")));
}

let mut hops: Vec<Hop> = Vec::new();
let mut final_commit = kernel.excess.clone();
let mut final_blind = my_keys.0.clone();
let amount = output.clone().unwrap().value;
let input_blind = keychain.derive_key(
amount,
&output.clone().unwrap().key_id,
SwitchCommitmentType::Regular,
)?;

let mut server_pubkeys = vec![];
for i in 0..params.server_keys.len() {
let excess = params.server_keys[i].clone();

let secp = secp256k1zkp::Secp256k1::with_caps(secp256k1zkp::ContextFlag::Commit);
final_blind.add_assign(&secp, &excess).unwrap();
final_commit = add_excess(&final_commit, &excess).unwrap();
let proof = if i == params.server_keys.len() - 1 {
let n1 = random_secret();
let rp = secp.bullet_proof(
slate.amount - (params.fee_per_hop * params.server_keys.len() as u32) as u64,
final_blind.clone(),
n1.clone(),
n1.clone(),
None,
None,
);
assert!(secp.verify_bullet_proof(final_commit, rp, None).is_ok());
Some(rp)
} else {
None
};

let hop = new_hop(&params.server_keys[i], &excess, params.fee_per_hop, proof);
hops.push(hop);
server_pubkeys.push(xPublicKey::from(&StaticSecret::from(
params.server_keys[i].0,
)));
}

let onion = create_onion(&kernel.excess, &hops)?;
let fee = grin_core::libtx::tx_fee(1, 1, 1);
let new_amount = amount - (fee * server_pubkeys.len() as u64);
let new_output = build_output(w, keychain_mask, OutputFeatures::Plain, new_amount)?;
let secp = keychain.secp();

let mut blind_sum = new_output
.blind
.split(&BlindingFactor::from_secret_key(input_blind.clone()), &secp)?;

let hops = server_pubkeys
.iter()
.enumerate()
.map(|(i, &p)| {
if (i + 1) == server_pubkeys.len() {
Hop {
server_pubkey: p.clone(),
excess: blind_sum.secret_key(&secp).unwrap(),
fee: FeeFields::from(fee as u32),
rangeproof: Some(new_output.output.proof.clone()),
}
} else {
let hop_excess = BlindingFactor::rand(&secp);
blind_sum = blind_sum.split(&hop_excess, &secp).unwrap();
Hop {
server_pubkey: p.clone(),
excess: hop_excess.secret_key(&secp).unwrap(),
fee: FeeFields::from(fee as u32),
rangeproof: None,
}
}
})
.collect();

let onion = create_onion(&commitment, &hops).unwrap();
let comsig = ComSignature::sign(amount, &input_blind, &onion.serialize().unwrap()).unwrap();

Ok(SwapReq { comsig, onion })
// Lock output if requested
if lock_output {
let mut batch = w.batch(keychain_mask)?;
let mut update_output = batch.get(&output.as_ref().unwrap().key_id, &None)?;
update_output.lock();
batch.lock_output(&mut update_output)?;
batch.commit()?;
}

//slate.find_index_matching_context(&keychain, &context)
Ok(SwapReq { comsig, onion })
}
1 change: 1 addition & 0 deletions libwallet/src/contract/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use crate::types::{Context, NodeClient, StoredProofInfo, TxLogEntryType, WalletB
use crate::util::OnionV3Address;
use crate::{address, Error, OutputData, OutputStatus, TxLogEntry};
use grin_core::core::FeeFields;
use grin_util::file::delete;
use uuid::Uuid;

/// Creates an initial TxLogEntry without input/output or kernel information
Expand Down
6 changes: 3 additions & 3 deletions libwallet/src/internal/selection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,9 @@ where
sender_address: sender_address.to_ed25519()?,
sender_address_path,
sender_signature: None,
/// TODO: Will fill these as separate steps for now, check whether this
/// can be merged in a general case (which means knowing which nonces here belong to
/// the recipient)
// TODO: Will fill these as separate steps for now, check whether this
// can be merged in a general case (which means knowing which nonces here belong to
// the recipient)
proof_type: None,
receiver_public_nonce: None,
receiver_public_excess: None,
Expand Down
2 changes: 1 addition & 1 deletion libwallet/src/mwixnet/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::grin_util::secp::key::SecretKey;
use serde::{Deserialize, Serialize};

/// A Swap request
#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Debug)]
pub struct SwapReq {
/// Com signature
#[serde(with = "comsig::comsig_serde")]
Expand Down
Loading