mirror of
https://github.com/mimblewimble/mwixnet.git
synced 2025-02-01 08:51:09 +03:00
move onion creation to a separate library
This commit is contained in:
parent
d99aa6ec7c
commit
dc3f99ebfa
18 changed files with 374 additions and 265 deletions
37
Cargo.lock
generated
37
Cargo.lock
generated
|
@ -1354,6 +1354,42 @@ dependencies = [
|
||||||
"zeroize",
|
"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]]
|
[[package]]
|
||||||
name = "grin_p2p"
|
name = "grin_p2p"
|
||||||
version = "5.2.0-alpha.1"
|
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_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_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_keychain 5.2.0-alpha.1 (git+https://github.com/mimblewimble/grin)",
|
||||||
|
"grin_onion",
|
||||||
"grin_secp256k1zkp",
|
"grin_secp256k1zkp",
|
||||||
"grin_servers",
|
"grin_servers",
|
||||||
"grin_store 5.2.0-alpha.1 (git+https://github.com/mimblewimble/grin)",
|
"grin_store 5.2.0-alpha.1 (git+https://github.com/mimblewimble/grin)",
|
||||||
|
|
|
@ -5,6 +5,9 @@ edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
members = ["onion"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
blake2 = { package = "blake2-rfc", version = "0.2"}
|
blake2 = { package = "blake2-rfc", version = "0.2"}
|
||||||
byteorder = "1"
|
byteorder = "1"
|
||||||
|
@ -36,6 +39,7 @@ thiserror = "1.0.31"
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
toml = "0.5"
|
toml = "0.5"
|
||||||
x25519-dalek = "0.6.0"
|
x25519-dalek = "0.6.0"
|
||||||
|
grin_onion = { path = "./onion" }
|
||||||
grin_secp256k1zkp = { version = "0.7.11", features = ["bullet-proof-sizing"]}
|
grin_secp256k1zkp = { version = "0.7.11", features = ["bullet-proof-sizing"]}
|
||||||
grin_util = "5"
|
grin_util = "5"
|
||||||
grin_api = { git = "https://github.com/mimblewimble/grin", version = "5.2.0-alpha.1" }
|
grin_api = { git = "https://github.com/mimblewimble/grin", version = "5.2.0-alpha.1" }
|
||||||
|
|
38
onion/Cargo.toml
Normal file
38
onion/Cargo.toml
Normal 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" }
|
|
@ -159,18 +159,6 @@ pub fn sign(sk: &SecretKey, message: &[u8]) -> Result<DalekSignature, DalekError
|
||||||
Ok(DalekSignature(sig))
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
|
@ -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)?;
|
let sig = aggsig::sign_single(&secp, &msg, &sk, None, None, None, Some(&pubkey), None)?;
|
||||||
Ok(sig)
|
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
170
onion/src/lib.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::crypto::secp::{self, Commitment, RangeProof, SecretKey};
|
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 crate::util::{read_optional, vec_to_array, write_optional};
|
||||||
|
|
||||||
use chacha20::cipher::{NewCipher, StreamCipher};
|
use chacha20::cipher::{NewCipher, StreamCipher};
|
||||||
|
@ -19,7 +18,7 @@ use thiserror::Error;
|
||||||
use x25519_dalek::{PublicKey as xPublicKey, SharedSecret, StaticSecret};
|
use x25519_dalek::{PublicKey as xPublicKey, SharedSecret, StaticSecret};
|
||||||
|
|
||||||
type HmacSha256 = Hmac<Sha256>;
|
type HmacSha256 = Hmac<Sha256>;
|
||||||
type RawBytes = Vec<u8>;
|
pub type RawBytes = Vec<u8>;
|
||||||
|
|
||||||
const CURRENT_ONION_VERSION: u8 = 0;
|
const CURRENT_ONION_VERSION: u8 = 0;
|
||||||
|
|
||||||
|
@ -70,7 +69,6 @@ impl Payload {
|
||||||
Ok(payload)
|
Ok(payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
pub fn serialize(&self) -> Result<Vec<u8>, ser::Error> {
|
pub fn serialize(&self) -> Result<Vec<u8>, ser::Error> {
|
||||||
let mut vec = vec![];
|
let mut vec = vec![];
|
||||||
ser::serialize_default(&mut vec, &self)?;
|
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")?;
|
let mut mu_hmac = HmacSha256::new_from_slice(b"MWIXNET")?;
|
||||||
mu_hmac.update(shared_secret.as_bytes());
|
mu_hmac.update(shared_secret.as_bytes());
|
||||||
let mukey = mu_hmac.finalize().into_bytes();
|
let mukey = mu_hmac.finalize().into_bytes();
|
||||||
|
@ -318,129 +316,21 @@ pub enum OnionError {
|
||||||
|
|
||||||
impl From<InvalidLength> for OnionError {
|
impl From<InvalidLength> for OnionError {
|
||||||
fn from(_err: InvalidLength) -> OnionError {
|
fn from(_err: InvalidLength) -> OnionError {
|
||||||
InvalidKeyLength
|
OnionError::InvalidKeyLength
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ser::Error> for OnionError {
|
impl From<ser::Error> for OnionError {
|
||||||
fn from(err: ser::Error) -> OnionError {
|
fn from(err: ser::Error) -> OnionError {
|
||||||
SerializationError(err)
|
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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
use super::test_util::{new_hop, Hop};
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::crypto::secp::random_secret;
|
use crate::crypto::secp::random_secret;
|
||||||
|
use crate::{new_hop, Hop};
|
||||||
|
|
||||||
use grin_core::core::FeeFields;
|
use grin_core::core::FeeFields;
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use crate::config::ServerConfig;
|
use crate::config::ServerConfig;
|
||||||
use crate::crypto::dalek;
|
use crate::crypto::dalek;
|
||||||
use crate::onion::Onion;
|
|
||||||
use crate::servers::mix_rpc::MixReq;
|
use crate::servers::mix_rpc::MixReq;
|
||||||
use crate::tx::TxComponents;
|
use crate::tx::TxComponents;
|
||||||
use crate::{tor, DalekPublicKey};
|
use crate::{tor, DalekPublicKey};
|
||||||
|
use grin_onion::onion::Onion;
|
||||||
|
|
||||||
use grin_api::client;
|
use grin_api::client;
|
||||||
use grin_api::json_rpc::build_request;
|
use grin_api::json_rpc::build_request;
|
||||||
|
@ -97,8 +97,8 @@ impl MixClient for MixClientImpl {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod mock {
|
pub mod mock {
|
||||||
use super::{ClientError, MixClient};
|
use super::{ClientError, MixClient};
|
||||||
use crate::onion::Onion;
|
|
||||||
use crate::tx::TxComponents;
|
use crate::tx::TxComponents;
|
||||||
|
use grin_onion::onion::Onion;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
@ -136,12 +136,12 @@ pub mod test_util {
|
||||||
use super::{ClientError, MixClient};
|
use super::{ClientError, MixClient};
|
||||||
use crate::crypto::dalek;
|
use crate::crypto::dalek;
|
||||||
use crate::crypto::secp::SecretKey;
|
use crate::crypto::secp::SecretKey;
|
||||||
use crate::onion::Onion;
|
|
||||||
use crate::servers::mix::MixServer;
|
use crate::servers::mix::MixServer;
|
||||||
use crate::tx::TxComponents;
|
use crate::tx::TxComponents;
|
||||||
use crate::DalekPublicKey;
|
use crate::DalekPublicKey;
|
||||||
use grin_core::ser;
|
use grin_core::ser;
|
||||||
use grin_core::ser::ProtocolVersion;
|
use grin_core::ser::ProtocolVersion;
|
||||||
|
use grin_onion::onion::Onion;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Implementation of the 'MixClient' trait that calls a mix server implementation directly.
|
/// Implementation of the 'MixClient' trait that calls a mix server implementation directly.
|
||||||
|
|
|
@ -4,12 +4,13 @@ use store::SwapStore;
|
||||||
use wallet::HttpWallet;
|
use wallet::HttpWallet;
|
||||||
|
|
||||||
use crate::client::{MixClient, MixClientImpl};
|
use crate::client::{MixClient, MixClientImpl};
|
||||||
use crate::crypto::dalek::DalekPublicKey;
|
|
||||||
use crate::node::GrinNode;
|
use crate::node::GrinNode;
|
||||||
use crate::store::StoreError;
|
use crate::store::StoreError;
|
||||||
use clap::App;
|
use clap::App;
|
||||||
use grin_core::global;
|
use grin_core::global;
|
||||||
use grin_core::global::ChainTypes;
|
use grin_core::global::ChainTypes;
|
||||||
|
use grin_onion::crypto;
|
||||||
|
use grin_onion::crypto::dalek::DalekPublicKey;
|
||||||
use grin_util::{StopState, ZeroingString};
|
use grin_util::{StopState, ZeroingString};
|
||||||
use rpassword;
|
use rpassword;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
@ -21,14 +22,11 @@ extern crate clap;
|
||||||
|
|
||||||
mod client;
|
mod client;
|
||||||
mod config;
|
mod config;
|
||||||
mod crypto;
|
|
||||||
mod node;
|
mod node;
|
||||||
mod onion;
|
|
||||||
mod servers;
|
mod servers;
|
||||||
mod store;
|
mod store;
|
||||||
mod tor;
|
mod tor;
|
||||||
mod tx;
|
mod tx;
|
||||||
mod util;
|
|
||||||
mod wallet;
|
mod wallet;
|
||||||
|
|
||||||
const DEFAULT_INTERVAL: u32 = 12 * 60 * 60;
|
const DEFAULT_INTERVAL: u32 = 12 * 60 * 60;
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
|
use crate::client::MixClient;
|
||||||
use crate::config::ServerConfig;
|
use crate::config::ServerConfig;
|
||||||
use crate::crypto::dalek::{self, DalekSignature};
|
use crate::tx::TxComponents;
|
||||||
use crate::onion::{Onion, OnionError, PeeledOnion};
|
|
||||||
use crate::wallet::Wallet;
|
use crate::wallet::Wallet;
|
||||||
use crate::{node, tx, GrinNode};
|
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::core::{Output, OutputFeatures, TransactionBody};
|
||||||
use grin_core::global::DEFAULT_ACCEPT_FEE_BASE;
|
use grin_core::global::DEFAULT_ACCEPT_FEE_BASE;
|
||||||
use grin_core::ser;
|
use grin_core::ser;
|
||||||
use grin_core::ser::ProtocolVersion;
|
use grin_core::ser::ProtocolVersion;
|
||||||
|
use grin_onion::crypto::dalek::{self, DalekSignature};
|
||||||
|
use grin_onion::onion::{Onion, OnionError, PeeledOnion};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use secp256k1zkp::key::ZERO_KEY;
|
use secp256k1zkp::key::ZERO_KEY;
|
||||||
use secp256k1zkp::Secp256k1;
|
use secp256k1zkp::Secp256k1;
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
@ -320,14 +320,13 @@ mod test_util {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::crypto::dalek;
|
|
||||||
use crate::crypto::secp::{self, Commitment};
|
|
||||||
use crate::node::mock::MockGrinNode;
|
use crate::node::mock::MockGrinNode;
|
||||||
use crate::onion::test_util;
|
|
||||||
use crate::{DalekPublicKey, MixClient};
|
use crate::{DalekPublicKey, MixClient};
|
||||||
|
|
||||||
use crate::onion::test_util::Hop;
|
|
||||||
use ::function_name::named;
|
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::pedersen::RangeProof;
|
||||||
use secp256k1zkp::SecretKey;
|
use secp256k1zkp::SecretKey;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
@ -353,7 +352,7 @@ mod tests {
|
||||||
|
|
||||||
impl ServerVars {
|
impl ServerVars {
|
||||||
fn new(fee: u32) -> Self {
|
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();
|
let excess = secp::random_secret();
|
||||||
ServerVars {
|
ServerVars {
|
||||||
fee,
|
fee,
|
||||||
|
@ -364,7 +363,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_hop(&self, proof: Option<RangeProof>) -> Hop {
|
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
|
// Build rangeproof
|
||||||
let (output_commit, proof) = secp::test_util::proof(
|
let (output_commit, proof) = onion_test_util::proof(
|
||||||
input1_value,
|
input1_value,
|
||||||
swap_vars.fee + mix1_vars.fee + mix2_vars.fee,
|
swap_vars.fee + mix1_vars.fee + mix2_vars.fee,
|
||||||
&input1_blind,
|
&input1_blind,
|
||||||
|
@ -416,7 +415,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create Onion
|
// Create Onion
|
||||||
let onion = test_util::create_onion(
|
let onion = create_onion(
|
||||||
&input1_commit,
|
&input1_commit,
|
||||||
&vec![
|
&vec![
|
||||||
swap_vars.build_hop(None),
|
swap_vars.build_hop(None),
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
|
use crate::client::MixClient;
|
||||||
use crate::config::ServerConfig;
|
use crate::config::ServerConfig;
|
||||||
use crate::crypto::dalek::{self, DalekSignature};
|
use crate::crypto::dalek::{self, DalekSignature};
|
||||||
use crate::node::GrinNode;
|
use crate::node::GrinNode;
|
||||||
use crate::onion::Onion;
|
|
||||||
use crate::servers::mix::{MixError, MixServer, MixServerImpl};
|
use crate::servers::mix::{MixError, MixServer, MixServerImpl};
|
||||||
use crate::wallet::Wallet;
|
use crate::wallet::Wallet;
|
||||||
|
|
||||||
use crate::client::MixClient;
|
use grin_onion::onion::Onion;
|
||||||
use grin_util::StopState;
|
use grin_util::StopState;
|
||||||
use jsonrpc_derive::rpc;
|
use jsonrpc_derive::rpc;
|
||||||
use jsonrpc_http_server::jsonrpc_core::{self as jsonrpc, IoHandler};
|
use jsonrpc_http_server::jsonrpc_core::{self as jsonrpc, IoHandler};
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
|
use crate::client::MixClient;
|
||||||
use crate::config::ServerConfig;
|
use crate::config::ServerConfig;
|
||||||
use crate::crypto::comsig::ComSignature;
|
use crate::crypto::comsig::ComSignature;
|
||||||
use crate::crypto::secp::{Commitment, Secp256k1, SecretKey};
|
use crate::crypto::secp::{Commitment, Secp256k1, SecretKey};
|
||||||
use crate::node::{self, GrinNode};
|
use crate::node::{self, GrinNode};
|
||||||
use crate::onion::{Onion, OnionError};
|
|
||||||
use crate::store::{StoreError, SwapData, SwapStatus, SwapStore};
|
use crate::store::{StoreError, SwapData, SwapStatus, SwapStore};
|
||||||
use crate::tx;
|
use crate::tx;
|
||||||
use crate::wallet::Wallet;
|
use crate::wallet::Wallet;
|
||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
use crate::client::MixClient;
|
|
||||||
use grin_core::core::hash::Hashed;
|
use grin_core::core::hash::Hashed;
|
||||||
use grin_core::core::{Input, Output, OutputFeatures, Transaction, TransactionBody};
|
use grin_core::core::{Input, Output, OutputFeatures, Transaction, TransactionBody};
|
||||||
use grin_core::global::DEFAULT_ACCEPT_FEE_BASE;
|
use grin_core::global::DEFAULT_ACCEPT_FEE_BASE;
|
||||||
|
use grin_onion::onion::{Onion, OnionError};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use secp256k1zkp::key::ZERO_KEY;
|
use secp256k1zkp::key::ZERO_KEY;
|
||||||
|
use std::collections::HashSet;
|
||||||
use std::result::Result;
|
use std::result::Result;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
@ -268,9 +268,9 @@ impl SwapServer for SwapServerImpl {
|
||||||
pub mod mock {
|
pub mod mock {
|
||||||
use super::{SwapError, SwapServer};
|
use super::{SwapError, SwapServer};
|
||||||
use crate::crypto::comsig::ComSignature;
|
use crate::crypto::comsig::ComSignature;
|
||||||
use crate::onion::Onion;
|
|
||||||
|
|
||||||
use grin_core::core::Transaction;
|
use grin_core::core::Transaction;
|
||||||
|
use grin_onion::onion::Onion;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub struct MockSwapServer {
|
pub struct MockSwapServer {
|
||||||
|
@ -339,12 +339,7 @@ pub mod test_util {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::crypto::comsig::ComSignature;
|
|
||||||
use crate::crypto::dalek;
|
|
||||||
use crate::crypto::secp;
|
|
||||||
use crate::node::mock::MockGrinNode;
|
use crate::node::mock::MockGrinNode;
|
||||||
use crate::onion::test_util::{self, Hop};
|
|
||||||
use crate::onion::Onion;
|
|
||||||
use crate::servers::swap::{SwapError, SwapServer};
|
use crate::servers::swap::{SwapError, SwapServer};
|
||||||
use crate::store::{SwapData, SwapStatus};
|
use crate::store::{SwapData, SwapStatus};
|
||||||
use crate::tx::TxComponents;
|
use crate::tx::TxComponents;
|
||||||
|
@ -353,6 +348,11 @@ mod tests {
|
||||||
use ::function_name::named;
|
use ::function_name::named;
|
||||||
use grin_core::core::hash::Hashed;
|
use grin_core::core::hash::Hashed;
|
||||||
use grin_core::core::{Committed, Input, Output, OutputFeatures, Transaction, Weighting};
|
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 secp256k1zkp::key::ZERO_KEY;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use x25519_dalek::PublicKey as xPublicKey;
|
use x25519_dalek::PublicKey as xPublicKey;
|
||||||
|
@ -392,10 +392,10 @@ mod tests {
|
||||||
|
|
||||||
let server_key = secp::random_secret();
|
let server_key = secp::random_secret();
|
||||||
let hop_excess = secp::random_secret();
|
let hop_excess = secp::random_secret();
|
||||||
let (output_commit, proof) = secp::test_util::proof(value, fee, &blind, &vec![&hop_excess]);
|
let (output_commit, proof) = onion_test_util::proof(value, fee, &blind, &vec![&hop_excess]);
|
||||||
let hop = test_util::new_hop(&server_key, &hop_excess, fee, Some(proof));
|
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 comsig = ComSignature::sign(value, &blind, &onion.serialize()?)?;
|
||||||
|
|
||||||
let node: Arc<MockGrinNode> = Arc::new(MockGrinNode::new_with_utxos(&vec![&input_commit]));
|
let node: Arc<MockGrinNode> = Arc::new(MockGrinNode::new_with_utxos(&vec![&input_commit]));
|
||||||
|
@ -464,24 +464,24 @@ mod tests {
|
||||||
|
|
||||||
// Swapper data
|
// Swapper data
|
||||||
let swap_fee: u32 = 50_000_000;
|
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_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
|
// Mixer data
|
||||||
let mixer_fee: u32 = 30_000_000;
|
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 mixer_hop_excess = secp::random_secret();
|
||||||
let (output_commit, proof) = secp::test_util::proof(
|
let (output_commit, proof) = onion_test_util::proof(
|
||||||
value,
|
value,
|
||||||
swap_fee + mixer_fee,
|
swap_fee + mixer_fee,
|
||||||
&blind,
|
&blind,
|
||||||
&vec![&swap_hop_excess, &mixer_hop_excess],
|
&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
|
// 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()?)?;
|
let comsig = ComSignature::sign(value, &blind, &onion.serialize()?)?;
|
||||||
|
|
||||||
// Mock mixer
|
// Mock mixer
|
||||||
|
@ -540,11 +540,11 @@ mod tests {
|
||||||
let server_key = secp::random_secret();
|
let server_key = secp::random_secret();
|
||||||
let hop_excess = secp::random_secret();
|
let hop_excess = secp::random_secret();
|
||||||
let (_output_commit, proof) =
|
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 hop = test_util::new_hop(&server_key, &hop_excess, fee, Some(proof));
|
let hop = new_hop(&server_key, &hop_excess, fee, Some(proof));
|
||||||
|
|
||||||
let hops: Vec<Hop> = vec![hop.clone(), hop.clone()]; // Multiple payloads
|
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 comsig = ComSignature::sign(value, &blind, &onion.serialize()?)?;
|
||||||
|
|
||||||
let node: Arc<MockGrinNode> = Arc::new(MockGrinNode::new_with_utxos(&vec![&input_commit]));
|
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 server_key = secp::random_secret();
|
||||||
let hop_excess = secp::random_secret();
|
let hop_excess = secp::random_secret();
|
||||||
let (_output_commit, proof) =
|
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 hop = test_util::new_hop(&server_key, &hop_excess, fee, Some(proof));
|
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 wrong_blind = secp::random_secret();
|
||||||
let comsig = ComSignature::sign(value, &wrong_blind, &onion.serialize()?)?;
|
let comsig = ComSignature::sign(value, &wrong_blind, &onion.serialize()?)?;
|
||||||
|
@ -612,10 +612,10 @@ mod tests {
|
||||||
let hop_excess = secp::random_secret();
|
let hop_excess = secp::random_secret();
|
||||||
let wrong_value = value + 10_000_000;
|
let wrong_value = value + 10_000_000;
|
||||||
let (_output_commit, proof) =
|
let (_output_commit, proof) =
|
||||||
secp::test_util::proof(wrong_value, fee, &blind, &vec![&hop_excess]);
|
onion_test_util::proof(wrong_value, fee, &blind, &vec![&hop_excess]);
|
||||||
let hop = test_util::new_hop(&server_key, &hop_excess, fee, Some(proof));
|
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 comsig = ComSignature::sign(value, &blind, &onion.serialize()?)?;
|
||||||
|
|
||||||
let node: Arc<MockGrinNode> = Arc::new(MockGrinNode::new_with_utxos(&vec![&input_commit]));
|
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 server_key = secp::random_secret();
|
||||||
let hop_excess = 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 comsig = ComSignature::sign(value, &blind, &onion.serialize()?)?;
|
||||||
|
|
||||||
let node: Arc<MockGrinNode> = Arc::new(MockGrinNode::new_with_utxos(&vec![&input_commit]));
|
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 server_key = secp::random_secret();
|
||||||
let hop_excess = secp::random_secret();
|
let hop_excess = secp::random_secret();
|
||||||
let (_output_commit, proof) =
|
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 hop = test_util::new_hop(&server_key, &hop_excess, fee, Some(proof));
|
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 comsig = ComSignature::sign(value, &blind, &onion.serialize()?)?;
|
||||||
|
|
||||||
let node: Arc<MockGrinNode> = Arc::new(MockGrinNode::new());
|
let node: Arc<MockGrinNode> = Arc::new(MockGrinNode::new());
|
||||||
|
@ -717,10 +717,10 @@ mod tests {
|
||||||
let server_key = secp::random_secret();
|
let server_key = secp::random_secret();
|
||||||
let hop_excess = secp::random_secret();
|
let hop_excess = secp::random_secret();
|
||||||
let (_output_commit, proof) =
|
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 hop = test_util::new_hop(&server_key, &hop_excess, fee, Some(proof));
|
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 comsig = ComSignature::sign(value, &blind, &onion.serialize()?)?;
|
||||||
|
|
||||||
let node: Arc<MockGrinNode> = Arc::new(MockGrinNode::new_with_utxos(&vec![&input_commit]));
|
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 server_key = secp::random_secret();
|
||||||
let hop_excess = secp::random_secret();
|
let hop_excess = secp::random_secret();
|
||||||
let (_output_commit, proof) =
|
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 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 comsig = ComSignature::sign(value, &blind, &onion.serialize()?)?;
|
||||||
|
|
||||||
let node: Arc<MockGrinNode> = Arc::new(MockGrinNode::new_with_utxos(&vec![&input_commit]));
|
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 server_key = secp::random_secret();
|
||||||
let hop_excess = secp::random_secret();
|
let hop_excess = secp::random_secret();
|
||||||
let (_output_commit, proof) =
|
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 hop = test_util::new_hop(&server_key, &hop_excess, fee, Some(proof));
|
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 comsig = ComSignature::sign(value, &blind, &onion.serialize()?)?;
|
||||||
|
|
||||||
let node: Arc<MockGrinNode> = Arc::new(MockGrinNode::new_with_utxos(&vec![&input_commit]));
|
let node: Arc<MockGrinNode> = Arc::new(MockGrinNode::new_with_utxos(&vec![&input_commit]));
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
|
use crate::client::MixClient;
|
||||||
use crate::config::ServerConfig;
|
use crate::config::ServerConfig;
|
||||||
use crate::crypto::comsig::{self, ComSignature};
|
|
||||||
use crate::node::GrinNode;
|
use crate::node::GrinNode;
|
||||||
use crate::onion::Onion;
|
|
||||||
use crate::servers::swap::{SwapError, SwapServer, SwapServerImpl};
|
use crate::servers::swap::{SwapError, SwapServer, SwapServerImpl};
|
||||||
use crate::store::SwapStore;
|
use crate::store::SwapStore;
|
||||||
use crate::wallet::Wallet;
|
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 grin_util::StopState;
|
||||||
use jsonrpc_core::Value;
|
use jsonrpc_core::Value;
|
||||||
use jsonrpc_derive::rpc;
|
use jsonrpc_derive::rpc;
|
||||||
|
@ -133,11 +133,11 @@ mod tests {
|
||||||
use crate::config::ServerConfig;
|
use crate::config::ServerConfig;
|
||||||
use crate::crypto::comsig::ComSignature;
|
use crate::crypto::comsig::ComSignature;
|
||||||
use crate::crypto::secp;
|
use crate::crypto::secp;
|
||||||
use crate::onion::test_util;
|
|
||||||
use crate::servers::swap::mock::MockSwapServer;
|
use crate::servers::swap::mock::MockSwapServer;
|
||||||
use crate::servers::swap::{SwapError, SwapServer};
|
use crate::servers::swap::{SwapError, SwapServer};
|
||||||
use crate::servers::swap_rpc::{RPCSwapServer, SwapReq};
|
use crate::servers::swap_rpc::{RPCSwapServer, SwapReq};
|
||||||
|
|
||||||
|
use grin_onion::create_onion;
|
||||||
use std::net::TcpListener;
|
use std::net::TcpListener;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn swap_success() -> Result<(), Box<dyn std::error::Error>> {
|
fn swap_success() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let commitment = secp::commit(1234, &secp::random_secret())?;
|
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 comsig = ComSignature::sign(1234, &secp::random_secret(), &onion.serialize()?)?;
|
||||||
let swap = SwapReq {
|
let swap = SwapReq {
|
||||||
onion: onion.clone(),
|
onion: onion.clone(),
|
||||||
|
@ -247,7 +247,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn swap_utxo_missing() -> Result<(), Box<dyn std::error::Error>> {
|
fn swap_utxo_missing() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let commitment = secp::commit(1234, &secp::random_secret())?;
|
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 comsig = ComSignature::sign(1234, &secp::random_secret(), &onion.serialize()?)?;
|
||||||
let swap = SwapReq {
|
let swap = SwapReq {
|
||||||
onion: onion.clone(),
|
onion: onion.clone(),
|
||||||
|
|
27
src/store.rs
27
src/store.rs
|
@ -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_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::core::Input;
|
||||||
use grin_core::ser::{
|
use grin_core::ser::{
|
||||||
|
@ -244,13 +244,12 @@ impl SwapStore {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
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::store::{SwapData, SwapStatus, SwapStore};
|
||||||
use crate::StoreError;
|
use crate::StoreError;
|
||||||
use grin_core::core::{Input, OutputFeatures};
|
use grin_core::core::{Input, OutputFeatures};
|
||||||
use grin_core::global::{self, ChainTypes};
|
use grin_core::global::{self, ChainTypes};
|
||||||
|
use grin_onion::crypto::secp;
|
||||||
|
use grin_onion::test_util as onion_test_util;
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
@ -264,11 +263,11 @@ mod tests {
|
||||||
fn rand_swap_with_status(status: SwapStatus) -> SwapData {
|
fn rand_swap_with_status(status: SwapStatus) -> SwapData {
|
||||||
SwapData {
|
SwapData {
|
||||||
excess: secp::random_secret(),
|
excess: secp::random_secret(),
|
||||||
output_commit: rand_commit(),
|
output_commit: onion_test_util::rand_commit(),
|
||||||
rangeproof: Some(rand_proof()),
|
rangeproof: Some(onion_test_util::rand_proof()),
|
||||||
input: Input::new(OutputFeatures::Plain, rand_commit()),
|
input: Input::new(OutputFeatures::Plain, onion_test_util::rand_commit()),
|
||||||
fee: rand::thread_rng().next_u64(),
|
fee: rand::thread_rng().next_u64(),
|
||||||
onion: rand_onion(),
|
onion: onion_test_util::rand_onion(),
|
||||||
status,
|
status,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -279,12 +278,12 @@ mod tests {
|
||||||
SwapStatus::Unprocessed
|
SwapStatus::Unprocessed
|
||||||
} else if s == 1 {
|
} else if s == 1 {
|
||||||
SwapStatus::InProcess {
|
SwapStatus::InProcess {
|
||||||
kernel_hash: rand_hash(),
|
kernel_hash: onion_test_util::rand_hash(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SwapStatus::Completed {
|
SwapStatus::Completed {
|
||||||
kernel_hash: rand_hash(),
|
kernel_hash: onion_test_util::rand_hash(),
|
||||||
block_hash: rand_hash(),
|
block_hash: onion_test_util::rand_hash(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
rand_swap_with_status(status)
|
rand_swap_with_status(status)
|
||||||
|
@ -331,7 +330,7 @@ mod tests {
|
||||||
assert!(store.swap_exists(&swap.input.commit)?);
|
assert!(store.swap_exists(&swap.input.commit)?);
|
||||||
|
|
||||||
swap.status = SwapStatus::InProcess {
|
swap.status = SwapStatus::InProcess {
|
||||||
kernel_hash: rand_hash(),
|
kernel_hash: onion_test_util::rand_hash(),
|
||||||
};
|
};
|
||||||
let result = store.save_swap(&swap, false);
|
let result = store.save_swap(&swap, false);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
41
src/tx.rs
41
src/tx.rs
|
@ -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> {
|
pub fn build_kernel(excess: &SecretKey, fee: u64) -> Result<TxKernel, TxError> {
|
||||||
let mut kernel = TxKernel::with_features(KernelFeatures::Plain {
|
let mut kernel = TxKernel::with_features(KernelFeatures::Plain {
|
||||||
fee: FeeFields::new(0, fee).map_err(TxError::KernelFeeError)?,
|
fee: FeeFields::new(0, fee).map_err(TxError::KernelFeeError)?,
|
||||||
|
|
Loading…
Reference in a new issue