move onion creation to a separate library

This commit is contained in:
scilio 2023-09-14 11:49:04 -04:00
parent d99aa6ec7c
commit dc3f99ebfa
18 changed files with 374 additions and 265 deletions

37
Cargo.lock generated
View file

@ -1354,6 +1354,42 @@ dependencies = [
"zeroize",
]
[[package]]
name = "grin_onion"
version = "0.1.0"
dependencies = [
"blake2-rfc",
"byteorder",
"bytes 0.5.6",
"chacha20",
"curve25519-dalek 2.1.3",
"ed25519-dalek",
"grin_api 5.2.0-alpha.1 (git+https://github.com/mimblewimble/grin)",
"grin_chain 5.2.0-alpha.1 (git+https://github.com/mimblewimble/grin)",
"grin_core 5.2.0-alpha.1 (git+https://github.com/mimblewimble/grin)",
"grin_keychain 5.2.0-alpha.1 (git+https://github.com/mimblewimble/grin)",
"grin_secp256k1zkp",
"grin_servers",
"grin_store 5.2.0-alpha.1 (git+https://github.com/mimblewimble/grin)",
"grin_util 5.1.1",
"grin_wallet_api",
"grin_wallet_impls",
"grin_wallet_libwallet",
"grin_wallet_util",
"hmac 0.12.0",
"itertools",
"lazy_static",
"rand 0.7.3",
"rpassword",
"serde",
"serde_derive",
"serde_json",
"sha2 0.10.0",
"thiserror",
"toml",
"x25519-dalek 0.6.0",
]
[[package]]
name = "grin_p2p"
version = "5.2.0-alpha.1"
@ -2555,6 +2591,7 @@ dependencies = [
"grin_chain 5.2.0-alpha.1 (git+https://github.com/mimblewimble/grin)",
"grin_core 5.2.0-alpha.1 (git+https://github.com/mimblewimble/grin)",
"grin_keychain 5.2.0-alpha.1 (git+https://github.com/mimblewimble/grin)",
"grin_onion",
"grin_secp256k1zkp",
"grin_servers",
"grin_store 5.2.0-alpha.1 (git+https://github.com/mimblewimble/grin)",

View file

@ -5,6 +5,9 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[workspace]
members = ["onion"]
[dependencies]
blake2 = { package = "blake2-rfc", version = "0.2"}
byteorder = "1"
@ -36,6 +39,7 @@ thiserror = "1.0.31"
tokio = { version = "1", features = ["full"] }
toml = "0.5"
x25519-dalek = "0.6.0"
grin_onion = { path = "./onion" }
grin_secp256k1zkp = { version = "0.7.11", features = ["bullet-proof-sizing"]}
grin_util = "5"
grin_api = { git = "https://github.com/mimblewimble/grin", version = "5.2.0-alpha.1" }

38
onion/Cargo.toml Normal file
View file

@ -0,0 +1,38 @@
[package]
name = "grin_onion"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
blake2 = { package = "blake2-rfc", version = "0.2"}
byteorder = "1"
bytes = "0.5.6"
chacha20 = "0.8.1"
curve25519-dalek = "2.1"
ed25519-dalek = "1.0.1"
hmac = { version = "0.12.0", features = ["std"]}
itertools = { version = "0.10.3"}
lazy_static = "1"
rand = "0.7.3"
rpassword = "4.0"
serde = { version = "1", features= ["derive"]}
serde_derive = "1"
serde_json = "1"
sha2 = "0.10.0"
thiserror = "1.0.31"
toml = "0.5"
x25519-dalek = "0.6.0"
grin_secp256k1zkp = { version = "0.7.11", features = ["bullet-proof-sizing"]}
grin_util = "5"
grin_api = { git = "https://github.com/mimblewimble/grin", version = "5.2.0-alpha.1" }
grin_core = { git = "https://github.com/mimblewimble/grin", version = "5.2.0-alpha.1" }
grin_chain = { git = "https://github.com/mimblewimble/grin", version = "5.2.0-alpha.1" }
grin_keychain = { git = "https://github.com/mimblewimble/grin", version = "5.2.0-alpha.1" }
grin_servers = { git = "https://github.com/mimblewimble/grin", version = "5.2.0-alpha.1" }
grin_store = { git = "https://github.com/mimblewimble/grin", version = "5.2.0-alpha.1" }
grin_wallet_api = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" }
grin_wallet_impls = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" }
grin_wallet_libwallet = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" }
grin_wallet_util = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" }

View file

@ -159,18 +159,6 @@ pub fn sign(sk: &SecretKey, message: &[u8]) -> Result<DalekSignature, DalekError
Ok(DalekSignature(sig))
}
#[cfg(test)]
pub mod test_util {
use super::*;
use crate::crypto::secp::random_secret;
pub fn rand_keypair() -> (SecretKey, DalekPublicKey) {
let sk = random_secret();
let pk = DalekPublicKey::from_secret(&sk);
(sk, pk)
}
}
#[cfg(test)]
mod tests {
use super::*;

View file

@ -60,58 +60,3 @@ pub fn sign(sk: &SecretKey, msg: &Message) -> Result<Signature, secp256k1zkp::Er
let sig = aggsig::sign_single(&secp, &msg, &sk, None, None, None, Some(&pubkey), None)?;
Ok(sig)
}
#[cfg(test)]
pub mod test_util {
use crate::crypto::secp::{self, Commitment, RangeProof, Secp256k1, SecretKey};
use grin_core::core::hash::Hash;
use grin_util::ToHex;
use rand::RngCore;
pub fn rand_commit() -> Commitment {
secp::commit(rand::thread_rng().next_u64(), &secp::random_secret()).unwrap()
}
pub fn rand_hash() -> Hash {
Hash::from_hex(secp::random_secret().to_hex().as_str()).unwrap()
}
pub fn rand_proof() -> RangeProof {
let secp = Secp256k1::new();
secp.bullet_proof(
rand::thread_rng().next_u64(),
secp::random_secret(),
secp::random_secret(),
secp::random_secret(),
None,
None,
)
}
pub fn proof(
value: u64,
fee: u32,
input_blind: &SecretKey,
hop_excesses: &Vec<&SecretKey>,
) -> (Commitment, RangeProof) {
let secp = Secp256k1::new();
let mut blind = input_blind.clone();
for hop_excess in hop_excesses {
blind.add_assign(&secp, &hop_excess).unwrap();
}
let out_value = value - (fee as u64);
let rp = secp.bullet_proof(
out_value,
blind.clone(),
secp::random_secret(),
secp::random_secret(),
None,
None,
);
(secp::commit(out_value, &blind).unwrap(), rp)
}
}

170
onion/src/lib.rs Normal file
View file

@ -0,0 +1,170 @@
pub mod crypto;
pub mod onion;
pub mod util;
use crate::crypto::secp::{random_secret, Commitment, SecretKey};
use crate::onion::{new_stream_cipher, Onion, OnionError, Payload, RawBytes};
use chacha20::cipher::StreamCipher;
use grin_core::core::FeeFields;
use secp256k1zkp::pedersen::RangeProof;
use x25519_dalek::PublicKey as xPublicKey;
use x25519_dalek::{SharedSecret, StaticSecret};
#[derive(Clone)]
pub struct Hop {
pub server_pubkey: xPublicKey,
pub excess: SecretKey,
pub fee: FeeFields,
pub rangeproof: Option<RangeProof>,
}
pub fn new_hop(
server_key: &SecretKey,
hop_excess: &SecretKey,
fee: u32,
proof: Option<RangeProof>,
) -> Hop {
Hop {
server_pubkey: xPublicKey::from(&StaticSecret::from(server_key.0.clone())),
excess: hop_excess.clone(),
fee: FeeFields::from(fee as u32),
rangeproof: proof,
}
}
/// Create an Onion for the Commitment, encrypting the payload for each hop
pub fn create_onion(commitment: &Commitment, hops: &Vec<Hop>) -> Result<Onion, OnionError> {
if hops.is_empty() {
return Ok(Onion {
ephemeral_pubkey: xPublicKey::from([0u8; 32]),
commit: commitment.clone(),
enc_payloads: vec![],
});
}
let mut shared_secrets: Vec<SharedSecret> = Vec::new();
let mut enc_payloads: Vec<RawBytes> = Vec::new();
let mut ephemeral_sk = StaticSecret::from(random_secret().0);
let onion_ephemeral_pk = xPublicKey::from(&ephemeral_sk);
for i in 0..hops.len() {
let hop = &hops[i];
let shared_secret = ephemeral_sk.diffie_hellman(&hop.server_pubkey);
shared_secrets.push(shared_secret);
ephemeral_sk = StaticSecret::from(random_secret().0);
let next_ephemeral_pk = if i < (hops.len() - 1) {
xPublicKey::from(&ephemeral_sk)
} else {
xPublicKey::from([0u8; 32])
};
let payload = Payload {
next_ephemeral_pk,
excess: hop.excess.clone(),
fee: hop.fee.clone(),
rangeproof: hop.rangeproof.clone(),
};
enc_payloads.push(payload.serialize()?);
}
for i in (0..shared_secrets.len()).rev() {
let mut cipher = new_stream_cipher(&shared_secrets[i])?;
for j in i..shared_secrets.len() {
cipher.apply_keystream(&mut enc_payloads[j]);
}
}
let onion = Onion {
ephemeral_pubkey: onion_ephemeral_pk,
commit: commitment.clone(),
enc_payloads,
};
Ok(onion)
}
pub mod test_util {
use super::*;
use crate::crypto::dalek::DalekPublicKey;
use crate::crypto::secp;
use grin_core::core::hash::Hash;
use grin_util::ToHex;
use rand::{thread_rng, RngCore};
use secp256k1zkp::Secp256k1;
pub fn rand_onion() -> Onion {
let commit = rand_commit();
let mut hops = Vec::new();
let k = (thread_rng().next_u64() % 5) + 1;
for i in 0..k {
let rangeproof = if i == (k - 1) {
Some(rand_proof())
} else {
None
};
let hop = new_hop(
&random_secret(),
&random_secret(),
thread_rng().next_u32(),
rangeproof,
);
hops.push(hop);
}
create_onion(&commit, &hops).unwrap()
}
pub fn rand_commit() -> Commitment {
secp::commit(rand::thread_rng().next_u64(), &secp::random_secret()).unwrap()
}
pub fn rand_hash() -> Hash {
Hash::from_hex(secp::random_secret().to_hex().as_str()).unwrap()
}
pub fn rand_proof() -> RangeProof {
let secp = Secp256k1::new();
secp.bullet_proof(
rand::thread_rng().next_u64(),
secp::random_secret(),
secp::random_secret(),
secp::random_secret(),
None,
None,
)
}
pub fn proof(
value: u64,
fee: u32,
input_blind: &SecretKey,
hop_excesses: &Vec<&SecretKey>,
) -> (Commitment, RangeProof) {
let secp = Secp256k1::new();
let mut blind = input_blind.clone();
for hop_excess in hop_excesses {
blind.add_assign(&secp, &hop_excess).unwrap();
}
let out_value = value - (fee as u64);
let rp = secp.bullet_proof(
out_value,
blind.clone(),
secp::random_secret(),
secp::random_secret(),
None,
None,
);
(secp::commit(out_value, &blind).unwrap(), rp)
}
pub fn rand_keypair() -> (SecretKey, DalekPublicKey) {
let sk = random_secret();
let pk = DalekPublicKey::from_secret(&sk);
(sk, pk)
}
}

View file

@ -1,5 +1,4 @@
use crate::crypto::secp::{self, Commitment, RangeProof, SecretKey};
use crate::onion::OnionError::{InvalidKeyLength, SerializationError};
use crate::util::{read_optional, vec_to_array, write_optional};
use chacha20::cipher::{NewCipher, StreamCipher};
@ -19,7 +18,7 @@ use thiserror::Error;
use x25519_dalek::{PublicKey as xPublicKey, SharedSecret, StaticSecret};
type HmacSha256 = Hmac<Sha256>;
type RawBytes = Vec<u8>;
pub type RawBytes = Vec<u8>;
const CURRENT_ONION_VERSION: u8 = 0;
@ -70,7 +69,6 @@ impl Payload {
Ok(payload)
}
#[cfg(test)]
pub fn serialize(&self) -> Result<Vec<u8>, ser::Error> {
let mut vec = vec![];
ser::serialize_default(&mut vec, &self)?;
@ -166,7 +164,7 @@ impl Onion {
}
}
fn new_stream_cipher(shared_secret: &SharedSecret) -> Result<ChaCha20, OnionError> {
pub fn new_stream_cipher(shared_secret: &SharedSecret) -> Result<ChaCha20, OnionError> {
let mut mu_hmac = HmacSha256::new_from_slice(b"MWIXNET")?;
mu_hmac.update(shared_secret.as_bytes());
let mukey = mu_hmac.finalize().into_bytes();
@ -318,129 +316,21 @@ pub enum OnionError {
impl From<InvalidLength> for OnionError {
fn from(_err: InvalidLength) -> OnionError {
InvalidKeyLength
OnionError::InvalidKeyLength
}
}
impl From<ser::Error> for OnionError {
fn from(err: ser::Error) -> OnionError {
SerializationError(err)
}
}
#[cfg(test)]
pub mod test_util {
use super::{Onion, OnionError, Payload, RawBytes};
use crate::crypto::secp::test_util::{rand_commit, rand_proof};
use crate::crypto::secp::{random_secret, Commitment, SecretKey};
use chacha20::cipher::StreamCipher;
use grin_core::core::FeeFields;
use rand::{thread_rng, RngCore};
use secp256k1zkp::pedersen::RangeProof;
use x25519_dalek::PublicKey as xPublicKey;
use x25519_dalek::{SharedSecret, StaticSecret};
#[derive(Clone)]
pub struct Hop {
pub server_pubkey: xPublicKey,
pub excess: SecretKey,
pub fee: FeeFields,
pub rangeproof: Option<RangeProof>,
}
pub fn new_hop(
server_key: &SecretKey,
hop_excess: &SecretKey,
fee: u32,
proof: Option<RangeProof>,
) -> Hop {
Hop {
server_pubkey: xPublicKey::from(&StaticSecret::from(server_key.0.clone())),
excess: hop_excess.clone(),
fee: FeeFields::from(fee as u32),
rangeproof: proof,
}
}
/// Create an Onion for the Commitment, encrypting the payload for each hop
pub fn create_onion(commitment: &Commitment, hops: &Vec<Hop>) -> Result<Onion, OnionError> {
if hops.is_empty() {
return Ok(Onion {
ephemeral_pubkey: xPublicKey::from([0u8; 32]),
commit: commitment.clone(),
enc_payloads: vec![],
});
}
let mut shared_secrets: Vec<SharedSecret> = Vec::new();
let mut enc_payloads: Vec<RawBytes> = Vec::new();
let mut ephemeral_sk = StaticSecret::from(random_secret().0);
let onion_ephemeral_pk = xPublicKey::from(&ephemeral_sk);
for i in 0..hops.len() {
let hop = &hops[i];
let shared_secret = ephemeral_sk.diffie_hellman(&hop.server_pubkey);
shared_secrets.push(shared_secret);
ephemeral_sk = StaticSecret::from(random_secret().0);
let next_ephemeral_pk = if i < (hops.len() - 1) {
xPublicKey::from(&ephemeral_sk)
} else {
xPublicKey::from([0u8; 32])
};
let payload = Payload {
next_ephemeral_pk,
excess: hop.excess.clone(),
fee: hop.fee.clone(),
rangeproof: hop.rangeproof.clone(),
};
enc_payloads.push(payload.serialize()?);
}
for i in (0..shared_secrets.len()).rev() {
let mut cipher = super::new_stream_cipher(&shared_secrets[i])?;
for j in i..shared_secrets.len() {
cipher.apply_keystream(&mut enc_payloads[j]);
}
}
let onion = Onion {
ephemeral_pubkey: onion_ephemeral_pk,
commit: commitment.clone(),
enc_payloads,
};
Ok(onion)
}
pub fn rand_onion() -> Onion {
let commit = rand_commit();
let mut hops = Vec::new();
let k = (thread_rng().next_u64() % 5) + 1;
for i in 0..k {
let rangeproof = if i == (k - 1) {
Some(rand_proof())
} else {
None
};
let hop = new_hop(
&random_secret(),
&random_secret(),
thread_rng().next_u32(),
rangeproof,
);
hops.push(hop);
}
create_onion(&commit, &hops).unwrap()
OnionError::SerializationError(err)
}
}
#[cfg(test)]
pub mod tests {
use super::test_util::{new_hop, Hop};
use super::*;
use crate::crypto::secp::random_secret;
use crate::{new_hop, Hop};
use grin_core::core::FeeFields;

View file

@ -1,9 +1,9 @@
use crate::config::ServerConfig;
use crate::crypto::dalek;
use crate::onion::Onion;
use crate::servers::mix_rpc::MixReq;
use crate::tx::TxComponents;
use crate::{tor, DalekPublicKey};
use grin_onion::onion::Onion;
use grin_api::client;
use grin_api::json_rpc::build_request;
@ -97,8 +97,8 @@ impl MixClient for MixClientImpl {
#[cfg(test)]
pub mod mock {
use super::{ClientError, MixClient};
use crate::onion::Onion;
use crate::tx::TxComponents;
use grin_onion::onion::Onion;
use std::collections::HashMap;
@ -136,12 +136,12 @@ pub mod test_util {
use super::{ClientError, MixClient};
use crate::crypto::dalek;
use crate::crypto::secp::SecretKey;
use crate::onion::Onion;
use crate::servers::mix::MixServer;
use crate::tx::TxComponents;
use crate::DalekPublicKey;
use grin_core::ser;
use grin_core::ser::ProtocolVersion;
use grin_onion::onion::Onion;
use std::sync::Arc;
/// Implementation of the 'MixClient' trait that calls a mix server implementation directly.

View file

@ -4,12 +4,13 @@ use store::SwapStore;
use wallet::HttpWallet;
use crate::client::{MixClient, MixClientImpl};
use crate::crypto::dalek::DalekPublicKey;
use crate::node::GrinNode;
use crate::store::StoreError;
use clap::App;
use grin_core::global;
use grin_core::global::ChainTypes;
use grin_onion::crypto;
use grin_onion::crypto::dalek::DalekPublicKey;
use grin_util::{StopState, ZeroingString};
use rpassword;
use std::path::PathBuf;
@ -21,14 +22,11 @@ extern crate clap;
mod client;
mod config;
mod crypto;
mod node;
mod onion;
mod servers;
mod store;
mod tor;
mod tx;
mod util;
mod wallet;
const DEFAULT_INTERVAL: u32 = 12 * 60 * 60;

View file

@ -1,19 +1,19 @@
use crate::client::MixClient;
use crate::config::ServerConfig;
use crate::crypto::dalek::{self, DalekSignature};
use crate::onion::{Onion, OnionError, PeeledOnion};
use crate::tx::TxComponents;
use crate::wallet::Wallet;
use crate::{node, tx, GrinNode};
use std::collections::{HashMap, HashSet};
use crate::client::MixClient;
use crate::tx::TxComponents;
use grin_core::core::{Output, OutputFeatures, TransactionBody};
use grin_core::global::DEFAULT_ACCEPT_FEE_BASE;
use grin_core::ser;
use grin_core::ser::ProtocolVersion;
use grin_onion::crypto::dalek::{self, DalekSignature};
use grin_onion::onion::{Onion, OnionError, PeeledOnion};
use itertools::Itertools;
use secp256k1zkp::key::ZERO_KEY;
use secp256k1zkp::Secp256k1;
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use thiserror::Error;
@ -320,14 +320,13 @@ mod test_util {
#[cfg(test)]
mod tests {
use crate::crypto::dalek;
use crate::crypto::secp::{self, Commitment};
use crate::node::mock::MockGrinNode;
use crate::onion::test_util;
use crate::{DalekPublicKey, MixClient};
use crate::onion::test_util::Hop;
use ::function_name::named;
use grin_onion::crypto::secp::{self, Commitment};
use grin_onion::test_util as onion_test_util;
use grin_onion::{create_onion, new_hop, Hop};
use secp256k1zkp::pedersen::RangeProof;
use secp256k1zkp::SecretKey;
use std::collections::HashSet;
@ -353,7 +352,7 @@ mod tests {
impl ServerVars {
fn new(fee: u32) -> Self {
let (sk, pk) = dalek::test_util::rand_keypair();
let (sk, pk) = onion_test_util::rand_keypair();
let excess = secp::random_secret();
ServerVars {
fee,
@ -364,7 +363,7 @@ mod tests {
}
fn build_hop(&self, proof: Option<RangeProof>) -> Hop {
test_util::new_hop(&self.sk, &self.excess, self.fee, proof)
new_hop(&self.sk, &self.excess, self.fee, proof)
}
}
@ -408,7 +407,7 @@ mod tests {
);
// Build rangeproof
let (output_commit, proof) = secp::test_util::proof(
let (output_commit, proof) = onion_test_util::proof(
input1_value,
swap_vars.fee + mix1_vars.fee + mix2_vars.fee,
&input1_blind,
@ -416,7 +415,7 @@ mod tests {
);
// Create Onion
let onion = test_util::create_onion(
let onion = create_onion(
&input1_commit,
&vec![
swap_vars.build_hop(None),

View file

@ -1,11 +1,11 @@
use crate::client::MixClient;
use crate::config::ServerConfig;
use crate::crypto::dalek::{self, DalekSignature};
use crate::node::GrinNode;
use crate::onion::Onion;
use crate::servers::mix::{MixError, MixServer, MixServerImpl};
use crate::wallet::Wallet;
use crate::client::MixClient;
use grin_onion::onion::Onion;
use grin_util::StopState;
use jsonrpc_derive::rpc;
use jsonrpc_http_server::jsonrpc_core::{self as jsonrpc, IoHandler};

View file

@ -1,19 +1,19 @@
use crate::client::MixClient;
use crate::config::ServerConfig;
use crate::crypto::comsig::ComSignature;
use crate::crypto::secp::{Commitment, Secp256k1, SecretKey};
use crate::node::{self, GrinNode};
use crate::onion::{Onion, OnionError};
use crate::store::{StoreError, SwapData, SwapStatus, SwapStore};
use crate::tx;
use crate::wallet::Wallet;
use std::collections::HashSet;
use crate::client::MixClient;
use grin_core::core::hash::Hashed;
use grin_core::core::{Input, Output, OutputFeatures, Transaction, TransactionBody};
use grin_core::global::DEFAULT_ACCEPT_FEE_BASE;
use grin_onion::onion::{Onion, OnionError};
use itertools::Itertools;
use secp256k1zkp::key::ZERO_KEY;
use std::collections::HashSet;
use std::result::Result;
use std::sync::{Arc, Mutex};
use thiserror::Error;
@ -268,9 +268,9 @@ impl SwapServer for SwapServerImpl {
pub mod mock {
use super::{SwapError, SwapServer};
use crate::crypto::comsig::ComSignature;
use crate::onion::Onion;
use grin_core::core::Transaction;
use grin_onion::onion::Onion;
use std::collections::HashMap;
pub struct MockSwapServer {
@ -339,12 +339,7 @@ pub mod test_util {
#[cfg(test)]
mod tests {
use crate::crypto::comsig::ComSignature;
use crate::crypto::dalek;
use crate::crypto::secp;
use crate::node::mock::MockGrinNode;
use crate::onion::test_util::{self, Hop};
use crate::onion::Onion;
use crate::servers::swap::{SwapError, SwapServer};
use crate::store::{SwapData, SwapStatus};
use crate::tx::TxComponents;
@ -353,6 +348,11 @@ mod tests {
use ::function_name::named;
use grin_core::core::hash::Hashed;
use grin_core::core::{Committed, Input, Output, OutputFeatures, Transaction, Weighting};
use grin_onion::crypto::comsig::ComSignature;
use grin_onion::crypto::secp;
use grin_onion::onion::Onion;
use grin_onion::test_util as onion_test_util;
use grin_onion::{create_onion, new_hop, Hop};
use secp256k1zkp::key::ZERO_KEY;
use std::sync::Arc;
use x25519_dalek::PublicKey as xPublicKey;
@ -392,10 +392,10 @@ mod tests {
let server_key = secp::random_secret();
let hop_excess = secp::random_secret();
let (output_commit, proof) = secp::test_util::proof(value, fee, &blind, &vec![&hop_excess]);
let hop = test_util::new_hop(&server_key, &hop_excess, fee, Some(proof));
let (output_commit, proof) = onion_test_util::proof(value, fee, &blind, &vec![&hop_excess]);
let hop = new_hop(&server_key, &hop_excess, fee, Some(proof));
let onion = test_util::create_onion(&input_commit, &vec![hop.clone()])?;
let onion = create_onion(&input_commit, &vec![hop.clone()])?;
let comsig = ComSignature::sign(value, &blind, &onion.serialize()?)?;
let node: Arc<MockGrinNode> = Arc::new(MockGrinNode::new_with_utxos(&vec![&input_commit]));
@ -464,24 +464,24 @@ mod tests {
// Swapper data
let swap_fee: u32 = 50_000_000;
let (swap_sk, _swap_pk) = dalek::test_util::rand_keypair();
let (swap_sk, _swap_pk) = onion_test_util::rand_keypair();
let swap_hop_excess = secp::random_secret();
let swap_hop = test_util::new_hop(&swap_sk, &swap_hop_excess, swap_fee, None);
let swap_hop = new_hop(&swap_sk, &swap_hop_excess, swap_fee, None);
// Mixer data
let mixer_fee: u32 = 30_000_000;
let (mixer_sk, mixer_pk) = dalek::test_util::rand_keypair();
let (mixer_sk, mixer_pk) = onion_test_util::rand_keypair();
let mixer_hop_excess = secp::random_secret();
let (output_commit, proof) = secp::test_util::proof(
let (output_commit, proof) = onion_test_util::proof(
value,
swap_fee + mixer_fee,
&blind,
&vec![&swap_hop_excess, &mixer_hop_excess],
);
let mixer_hop = test_util::new_hop(&mixer_sk, &mixer_hop_excess, mixer_fee, Some(proof));
let mixer_hop = new_hop(&mixer_sk, &mixer_hop_excess, mixer_fee, Some(proof));
// Create onion
let onion = test_util::create_onion(&input_commit, &vec![swap_hop, mixer_hop])?;
let onion = create_onion(&input_commit, &vec![swap_hop, mixer_hop])?;
let comsig = ComSignature::sign(value, &blind, &onion.serialize()?)?;
// Mock mixer
@ -540,11 +540,11 @@ mod tests {
let server_key = secp::random_secret();
let hop_excess = secp::random_secret();
let (_output_commit, proof) =
secp::test_util::proof(value, fee, &blind, &vec![&hop_excess]);
let hop = test_util::new_hop(&server_key, &hop_excess, fee, Some(proof));
onion_test_util::proof(value, fee, &blind, &vec![&hop_excess]);
let hop = new_hop(&server_key, &hop_excess, fee, Some(proof));
let hops: Vec<Hop> = vec![hop.clone(), hop.clone()]; // Multiple payloads
let onion = test_util::create_onion(&input_commit, &hops)?;
let onion = create_onion(&input_commit, &hops)?;
let comsig = ComSignature::sign(value, &blind, &onion.serialize()?)?;
let node: Arc<MockGrinNode> = Arc::new(MockGrinNode::new_with_utxos(&vec![&input_commit]));
@ -575,10 +575,10 @@ mod tests {
let server_key = secp::random_secret();
let hop_excess = secp::random_secret();
let (_output_commit, proof) =
secp::test_util::proof(value, fee, &blind, &vec![&hop_excess]);
let hop = test_util::new_hop(&server_key, &hop_excess, fee, Some(proof));
onion_test_util::proof(value, fee, &blind, &vec![&hop_excess]);
let hop = new_hop(&server_key, &hop_excess, fee, Some(proof));
let onion = test_util::create_onion(&input_commit, &vec![hop])?;
let onion = create_onion(&input_commit, &vec![hop])?;
let wrong_blind = secp::random_secret();
let comsig = ComSignature::sign(value, &wrong_blind, &onion.serialize()?)?;
@ -612,10 +612,10 @@ mod tests {
let hop_excess = secp::random_secret();
let wrong_value = value + 10_000_000;
let (_output_commit, proof) =
secp::test_util::proof(wrong_value, fee, &blind, &vec![&hop_excess]);
let hop = test_util::new_hop(&server_key, &hop_excess, fee, Some(proof));
onion_test_util::proof(wrong_value, fee, &blind, &vec![&hop_excess]);
let hop = new_hop(&server_key, &hop_excess, fee, Some(proof));
let onion = test_util::create_onion(&input_commit, &vec![hop])?;
let onion = create_onion(&input_commit, &vec![hop])?;
let comsig = ComSignature::sign(value, &blind, &onion.serialize()?)?;
let node: Arc<MockGrinNode> = Arc::new(MockGrinNode::new_with_utxos(&vec![&input_commit]));
@ -645,9 +645,9 @@ mod tests {
let server_key = secp::random_secret();
let hop_excess = secp::random_secret();
let hop = test_util::new_hop(&server_key, &hop_excess, fee, None);
let hop = new_hop(&server_key, &hop_excess, fee, None);
let onion = test_util::create_onion(&input_commit, &vec![hop])?;
let onion = create_onion(&input_commit, &vec![hop])?;
let comsig = ComSignature::sign(value, &blind, &onion.serialize()?)?;
let node: Arc<MockGrinNode> = Arc::new(MockGrinNode::new_with_utxos(&vec![&input_commit]));
@ -678,10 +678,10 @@ mod tests {
let server_key = secp::random_secret();
let hop_excess = secp::random_secret();
let (_output_commit, proof) =
secp::test_util::proof(value, fee, &blind, &vec![&hop_excess]);
let hop = test_util::new_hop(&server_key, &hop_excess, fee, Some(proof));
onion_test_util::proof(value, fee, &blind, &vec![&hop_excess]);
let hop = new_hop(&server_key, &hop_excess, fee, Some(proof));
let onion = test_util::create_onion(&input_commit, &vec![hop])?;
let onion = create_onion(&input_commit, &vec![hop])?;
let comsig = ComSignature::sign(value, &blind, &onion.serialize()?)?;
let node: Arc<MockGrinNode> = Arc::new(MockGrinNode::new());
@ -717,10 +717,10 @@ mod tests {
let server_key = secp::random_secret();
let hop_excess = secp::random_secret();
let (_output_commit, proof) =
secp::test_util::proof(value, fee, &blind, &vec![&hop_excess]);
let hop = test_util::new_hop(&server_key, &hop_excess, fee, Some(proof));
onion_test_util::proof(value, fee, &blind, &vec![&hop_excess]);
let hop = new_hop(&server_key, &hop_excess, fee, Some(proof));
let onion = test_util::create_onion(&input_commit, &vec![hop])?;
let onion = create_onion(&input_commit, &vec![hop])?;
let comsig = ComSignature::sign(value, &blind, &onion.serialize()?)?;
let node: Arc<MockGrinNode> = Arc::new(MockGrinNode::new_with_utxos(&vec![&input_commit]));
@ -753,12 +753,12 @@ mod tests {
let server_key = secp::random_secret();
let hop_excess = secp::random_secret();
let (_output_commit, proof) =
secp::test_util::proof(value, fee, &blind, &vec![&hop_excess]);
onion_test_util::proof(value, fee, &blind, &vec![&hop_excess]);
let wrong_server_key = secp::random_secret();
let hop = test_util::new_hop(&wrong_server_key, &hop_excess, fee, Some(proof));
let hop = new_hop(&wrong_server_key, &hop_excess, fee, Some(proof));
let onion = test_util::create_onion(&input_commit, &vec![hop])?;
let onion = create_onion(&input_commit, &vec![hop])?;
let comsig = ComSignature::sign(value, &blind, &onion.serialize()?)?;
let node: Arc<MockGrinNode> = Arc::new(MockGrinNode::new_with_utxos(&vec![&input_commit]));
@ -785,10 +785,10 @@ mod tests {
let server_key = secp::random_secret();
let hop_excess = secp::random_secret();
let (_output_commit, proof) =
secp::test_util::proof(value, fee, &blind, &vec![&hop_excess]);
let hop = test_util::new_hop(&server_key, &hop_excess, fee, Some(proof));
onion_test_util::proof(value, fee, &blind, &vec![&hop_excess]);
let hop = new_hop(&server_key, &hop_excess, fee, Some(proof));
let onion = test_util::create_onion(&input_commit, &vec![hop])?;
let onion = create_onion(&input_commit, &vec![hop])?;
let comsig = ComSignature::sign(value, &blind, &onion.serialize()?)?;
let node: Arc<MockGrinNode> = Arc::new(MockGrinNode::new_with_utxos(&vec![&input_commit]));

View file

@ -1,12 +1,12 @@
use crate::client::MixClient;
use crate::config::ServerConfig;
use crate::crypto::comsig::{self, ComSignature};
use crate::node::GrinNode;
use crate::onion::Onion;
use crate::servers::swap::{SwapError, SwapServer, SwapServerImpl};
use crate::store::SwapStore;
use crate::wallet::Wallet;
use crate::client::MixClient;
use grin_onion::crypto::comsig::{self, ComSignature};
use grin_onion::onion::Onion;
use grin_util::StopState;
use jsonrpc_core::Value;
use jsonrpc_derive::rpc;
@ -133,11 +133,11 @@ mod tests {
use crate::config::ServerConfig;
use crate::crypto::comsig::ComSignature;
use crate::crypto::secp;
use crate::onion::test_util;
use crate::servers::swap::mock::MockSwapServer;
use crate::servers::swap::{SwapError, SwapServer};
use crate::servers::swap_rpc::{RPCSwapServer, SwapReq};
use grin_onion::create_onion;
use std::net::TcpListener;
use std::sync::{Arc, Mutex};
@ -208,7 +208,7 @@ mod tests {
#[test]
fn swap_success() -> Result<(), Box<dyn std::error::Error>> {
let commitment = secp::commit(1234, &secp::random_secret())?;
let onion = test_util::create_onion(&commitment, &vec![])?;
let onion = create_onion(&commitment, &vec![])?;
let comsig = ComSignature::sign(1234, &secp::random_secret(), &onion.serialize()?)?;
let swap = SwapReq {
onion: onion.clone(),
@ -247,7 +247,7 @@ mod tests {
#[test]
fn swap_utxo_missing() -> Result<(), Box<dyn std::error::Error>> {
let commitment = secp::commit(1234, &secp::random_secret())?;
let onion = test_util::create_onion(&commitment, &vec![])?;
let onion = create_onion(&commitment, &vec![])?;
let comsig = ComSignature::sign(1234, &secp::random_secret(), &onion.serialize()?)?;
let swap = SwapReq {
onion: onion.clone(),

View file

@ -1,7 +1,7 @@
use crate::crypto::secp::{self, Commitment, RangeProof, SecretKey};
use crate::onion::Onion;
use crate::util::{read_optional, write_optional};
use grin_core::core::hash::Hash;
use grin_onion::crypto::secp::{self, Commitment, RangeProof, SecretKey};
use grin_onion::onion::Onion;
use grin_onion::util::{read_optional, write_optional};
use grin_core::core::Input;
use grin_core::ser::{
@ -244,13 +244,12 @@ impl SwapStore {
#[cfg(test)]
mod tests {
use crate::crypto::secp;
use crate::crypto::secp::test_util::{rand_commit, rand_hash, rand_proof};
use crate::onion::test_util::rand_onion;
use crate::store::{SwapData, SwapStatus, SwapStore};
use crate::StoreError;
use grin_core::core::{Input, OutputFeatures};
use grin_core::global::{self, ChainTypes};
use grin_onion::crypto::secp;
use grin_onion::test_util as onion_test_util;
use rand::RngCore;
use std::cmp::Ordering;
@ -264,11 +263,11 @@ mod tests {
fn rand_swap_with_status(status: SwapStatus) -> SwapData {
SwapData {
excess: secp::random_secret(),
output_commit: rand_commit(),
rangeproof: Some(rand_proof()),
input: Input::new(OutputFeatures::Plain, rand_commit()),
output_commit: onion_test_util::rand_commit(),
rangeproof: Some(onion_test_util::rand_proof()),
input: Input::new(OutputFeatures::Plain, onion_test_util::rand_commit()),
fee: rand::thread_rng().next_u64(),
onion: rand_onion(),
onion: onion_test_util::rand_onion(),
status,
}
}
@ -279,12 +278,12 @@ mod tests {
SwapStatus::Unprocessed
} else if s == 1 {
SwapStatus::InProcess {
kernel_hash: rand_hash(),
kernel_hash: onion_test_util::rand_hash(),
}
} else {
SwapStatus::Completed {
kernel_hash: rand_hash(),
block_hash: rand_hash(),
kernel_hash: onion_test_util::rand_hash(),
block_hash: onion_test_util::rand_hash(),
}
};
rand_swap_with_status(status)
@ -331,7 +330,7 @@ mod tests {
assert!(store.swap_exists(&swap.input.commit)?);
swap.status = SwapStatus::InProcess {
kernel_hash: rand_hash(),
kernel_hash: onion_test_util::rand_hash(),
};
let result = store.save_swap(&swap, false);
assert_eq!(

View file

@ -167,6 +167,47 @@ fn add_kernel_and_collect_fees(
})
}
/// Builds a transaction kernel for the Grin network.
///
/// Transaction kernels are a critical part of the Grin transaction process. Each transaction contains a
/// kernel. It includes features chosen for this transaction, a fee chosen for this transaction, and
/// a proof that the total sum of outputs, transaction fees and block reward equals the total sum of inputs.
/// The `build_kernel` function handles this process, building the kernel and handling any potential errors.
///
/// # Arguments
///
/// * `excess`: A reference to a `SecretKey`. This key is used as an excess value for the transaction.
/// The excess is a kind of cryptographic proof that the total sum of outputs and fees equals the
/// total sum of inputs.
/// * `fee`: An unsigned 64-bit integer representing the transaction fee in nanogrin. This is the fee
/// that will be paid to the miner who mines the block containing this transaction.
///
/// # Returns
///
/// The function returns a `Result` enum with `TxKernel` as the Ok variant and `TxError` as the Err variant.
/// If the kernel is successfully built, it is returned as part of the Ok variant. If there is an error at any point
/// during the process, it is returned as part of the Err variant.
///
/// # Errors
///
/// This function can return several types of errors, all defined in the `TxError` enum. These include:
///
/// * `KernelFeeError`: There was an error building the kernel's fee fields.
/// * `KernelExcessError`: There was an error computing the kernel's excess.
/// * `KernelSigMessageError`: There was an error computing the kernel's signature message.
/// * `KernelSigError`: There was an error signing the kernel.
/// * `KernelVerifyError`: The built kernel failed to verify.
///
/// # Example
///
/// ```rust
/// use secp256k1zkp::key::SecretKey;
/// use crate::crypto::secp;
///
/// let secret_key = SecretKey::new(&mut secp::rand::thread_rng());
/// let fee = 10; // 10 nanogrin
/// let kernel = build_kernel(&secret_key, fee);
/// ```
pub fn build_kernel(excess: &SecretKey, fee: u64) -> Result<TxKernel, TxError> {
let mut kernel = TxKernel::with_features(KernelFeatures::Plain {
fee: FeeFields::new(0, fee).map_err(TxError::KernelFeeError)?,