mirror of
https://github.com/mimblewimble/mwixnet.git
synced 2025-01-20 19:11:09 +03:00
commit
b989948eef
8 changed files with 181 additions and 114 deletions
26
Cargo.lock
generated
26
Cargo.lock
generated
|
@ -45,7 +45,7 @@ dependencies = [
|
|||
"nom 7.1.0",
|
||||
"pin-project",
|
||||
"rand 0.7.3",
|
||||
"rand 0.8.4",
|
||||
"rand 0.8.5",
|
||||
"rust-embed",
|
||||
"scrypt",
|
||||
"sha2 0.9.8",
|
||||
|
@ -65,7 +65,7 @@ dependencies = [
|
|||
"cookie-factory",
|
||||
"hkdf",
|
||||
"nom 7.1.0",
|
||||
"rand 0.8.4",
|
||||
"rand 0.8.5",
|
||||
"secrecy 0.8.0",
|
||||
"sha2 0.9.8",
|
||||
]
|
||||
|
@ -2475,7 +2475,9 @@ dependencies = [
|
|||
"bytes 0.5.6",
|
||||
"chacha20",
|
||||
"clap",
|
||||
"curve25519-dalek 2.1.3",
|
||||
"dirs",
|
||||
"ed25519-dalek",
|
||||
"futures 0.3.17",
|
||||
"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)",
|
||||
|
@ -2488,6 +2490,7 @@ dependencies = [
|
|||
"grin_wallet_api",
|
||||
"grin_wallet_impls",
|
||||
"grin_wallet_libwallet",
|
||||
"grin_wallet_util",
|
||||
"hmac 0.12.0",
|
||||
"hyper 0.14.14",
|
||||
"itertools",
|
||||
|
@ -2496,7 +2499,7 @@ dependencies = [
|
|||
"jsonrpc-http-server",
|
||||
"lazy_static",
|
||||
"pbkdf2 0.8.0",
|
||||
"rand 0.8.4",
|
||||
"rand 0.7.3",
|
||||
"ring",
|
||||
"rpassword",
|
||||
"serde",
|
||||
|
@ -2506,6 +2509,7 @@ dependencies = [
|
|||
"thiserror",
|
||||
"tokio 1.12.0",
|
||||
"toml",
|
||||
"x25519-dalek 0.6.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3033,14 +3037,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha 0.3.1",
|
||||
"rand_core 0.6.3",
|
||||
"rand_hc 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3124,15 +3127,6 @@ dependencies = [
|
|||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
|
||||
dependencies = [
|
||||
"rand_core 0.6.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_isaac"
|
||||
version = "0.1.1"
|
||||
|
@ -3854,7 +3848,7 @@ checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
|
|||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"rand 0.8.4",
|
||||
"rand 0.8.5",
|
||||
"redox_syscall 0.2.10",
|
||||
"remove_dir_all",
|
||||
"winapi 0.3.9",
|
||||
|
|
|
@ -11,7 +11,9 @@ byteorder = "1"
|
|||
bytes = "0.5.6"
|
||||
chacha20 = "0.8.1"
|
||||
clap = { version = "2.33", features = ["yaml"] }
|
||||
curve25519-dalek = "2.1"
|
||||
dirs = "2.0"
|
||||
ed25519-dalek = "1.0.1"
|
||||
futures = "0.3"
|
||||
hmac = { version = "0.12.0", features = ["std"]}
|
||||
hyper = { version = "0.14", features = ["full"] }
|
||||
|
@ -21,7 +23,7 @@ jsonrpc-derive = "18.0"
|
|||
jsonrpc-http-server = "18.0"
|
||||
lazy_static = "1"
|
||||
pbkdf2 = "0.8.0"
|
||||
rand = "0.8.4"
|
||||
rand = "0.7.3"
|
||||
ring = "0.16"
|
||||
rpassword = "4.0"
|
||||
serde = { version = "1", features= ["derive"]}
|
||||
|
@ -31,6 +33,7 @@ sha2 = "0.10.0"
|
|||
thiserror = "1.0.31"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
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" }
|
||||
|
@ -41,4 +44,5 @@ grin_servers = { git = "https://github.com/mimblewimble/grin", version = "5.2.0-
|
|||
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_libwallet = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" }
|
||||
grin_wallet_util = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" }
|
|
@ -35,7 +35,7 @@ args:
|
|||
long: wallet_pass
|
||||
takes_value: true
|
||||
- bind_addr:
|
||||
help: Address to bind the rpc server to (e.g. 0.0.0.0:3000)
|
||||
help: Address to bind the rpc server to (e.g. 127.0.0.1:3000)
|
||||
long: bind_addr
|
||||
takes_value: true
|
||||
subcommands:
|
||||
|
|
85
src/main.rs
85
src/main.rs
|
@ -1,5 +1,6 @@
|
|||
use config::ServerConfig;
|
||||
use node::HttpGrinNode;
|
||||
use std::collections::HashMap;
|
||||
use store::SwapStore;
|
||||
use wallet::HttpWallet;
|
||||
|
||||
|
@ -9,6 +10,9 @@ use clap::App;
|
|||
use grin_core::global;
|
||||
use grin_core::global::ChainTypes;
|
||||
use grin_util::{StopState, ZeroingString};
|
||||
use grin_wallet_impls::tor::config as tor_config;
|
||||
use grin_wallet_impls::tor::process as tor_process;
|
||||
use grin_wallet_util::OnionV3Address;
|
||||
use rpassword;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
@ -74,7 +78,7 @@ fn real_main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
let server_config = ServerConfig {
|
||||
key: secp::random_secret(),
|
||||
interval_s: round_time.unwrap_or(DEFAULT_INTERVAL),
|
||||
addr: bind_addr.unwrap_or("0.0.0.0:3000").parse()?,
|
||||
addr: bind_addr.unwrap_or("127.0.0.1:3000").parse()?,
|
||||
grin_node_url: match grin_node_url {
|
||||
Some(u) => u.parse()?,
|
||||
None => config::grin_node_url(&chain_type),
|
||||
|
@ -171,12 +175,15 @@ fn real_main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
)))?,
|
||||
)?;
|
||||
|
||||
let mut tor_process = init_tor_listener(&server_config)?;
|
||||
|
||||
let stop_state = Arc::new(StopState::new());
|
||||
let stop_state_clone = stop_state.clone();
|
||||
|
||||
let rt = Runtime::new()?;
|
||||
rt.spawn(async move {
|
||||
futures::executor::block_on(build_signals_fut());
|
||||
let _ = tor_process.kill();
|
||||
stop_state_clone.stop();
|
||||
});
|
||||
|
||||
|
@ -190,28 +197,30 @@ fn real_main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
async fn build_signals_fut() {
|
||||
if cfg!(unix) {
|
||||
use tokio::signal::unix::{signal, SignalKind};
|
||||
use tokio::signal::unix::{signal, SignalKind};
|
||||
|
||||
// Listen for SIGINT, SIGQUIT, and SIGTERM
|
||||
let mut terminate_signal =
|
||||
signal(SignalKind::terminate()).expect("failed to create terminate signal");
|
||||
let mut quit_signal = signal(SignalKind::quit()).expect("failed to create quit signal");
|
||||
let mut interrupt_signal =
|
||||
signal(SignalKind::interrupt()).expect("failed to create interrupt signal");
|
||||
// Listen for SIGINT, SIGQUIT, and SIGTERM
|
||||
let mut terminate_signal =
|
||||
signal(SignalKind::terminate()).expect("failed to create terminate signal");
|
||||
let mut quit_signal = signal(SignalKind::quit()).expect("failed to create quit signal");
|
||||
let mut interrupt_signal =
|
||||
signal(SignalKind::interrupt()).expect("failed to create interrupt signal");
|
||||
|
||||
futures::future::select_all(vec![
|
||||
Box::pin(terminate_signal.recv()),
|
||||
Box::pin(quit_signal.recv()),
|
||||
Box::pin(interrupt_signal.recv()),
|
||||
])
|
||||
.await;
|
||||
} else {
|
||||
tokio::signal::ctrl_c()
|
||||
.await
|
||||
.expect("failed to install CTRL+C signal handler");
|
||||
}
|
||||
futures::future::select_all(vec![
|
||||
Box::pin(terminate_signal.recv()),
|
||||
Box::pin(quit_signal.recv()),
|
||||
Box::pin(interrupt_signal.recv()),
|
||||
])
|
||||
.await;
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
async fn build_signals_fut() {
|
||||
tokio::signal::ctrl_c()
|
||||
.await
|
||||
.expect("failed to install CTRL+C signal handler");
|
||||
}
|
||||
|
||||
fn prompt_password() -> ZeroingString {
|
||||
|
@ -236,3 +245,39 @@ fn prompt_wallet_password(wallet_pass: &Option<&str>) -> ZeroingString {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn init_tor_listener(
|
||||
server_config: &ServerConfig,
|
||||
) -> Result<tor_process::TorProcess, Box<dyn std::error::Error>> {
|
||||
let mut tor_dir = config::get_grin_path(&global::get_chain_type());
|
||||
tor_dir.push("tor/listener");
|
||||
|
||||
let mut torrc_dir = tor_dir.clone();
|
||||
torrc_dir.push("torrc");
|
||||
|
||||
tor_config::output_tor_listener_config(
|
||||
tor_dir.to_str().unwrap(),
|
||||
server_config.addr.to_string().as_str(),
|
||||
&vec![server_config.key.clone()],
|
||||
HashMap::new(),
|
||||
HashMap::new(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Start TOR process
|
||||
let mut process = tor_process::TorProcess::new();
|
||||
process
|
||||
.torrc_path(torrc_dir.to_str().unwrap())
|
||||
.working_dir(tor_dir.to_str().unwrap())
|
||||
.timeout(20)
|
||||
.completion_percent(100)
|
||||
.launch()
|
||||
.unwrap();
|
||||
|
||||
let onion_address = OnionV3Address::from_private(&server_config.key.0).unwrap();
|
||||
println!(
|
||||
"Server listening at http://{}.onion",
|
||||
onion_address.to_ov3_str()
|
||||
);
|
||||
Ok(process)
|
||||
}
|
||||
|
|
157
src/onion.rs
157
src/onion.rs
|
@ -1,34 +1,62 @@
|
|||
use crate::secp::{self, Commitment, PublicKey, Secp256k1, SecretKey, SharedSecret};
|
||||
use crate::secp::{self, Commitment, SecretKey};
|
||||
use crate::types::Payload;
|
||||
|
||||
use crate::onion::OnionError::{InvalidKeyLength, SerializationError};
|
||||
use chacha20::cipher::{NewCipher, StreamCipher};
|
||||
use chacha20::{ChaCha20, Key, Nonce};
|
||||
use grin_core::ser::{self, ProtocolVersion, Readable, Reader, Writeable, Writer};
|
||||
use grin_core::ser::{self, Readable, Reader, Writeable, Writer};
|
||||
use grin_util::{self, ToHex};
|
||||
use hmac::digest::InvalidLength;
|
||||
use hmac::{Hmac, Mac};
|
||||
use serde::ser::SerializeStruct;
|
||||
use serde::Deserialize;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::convert::TryInto;
|
||||
use std::fmt;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::result::Result;
|
||||
use thiserror::Error;
|
||||
use x25519_dalek::{PublicKey as xPublicKey, SharedSecret, StaticSecret};
|
||||
|
||||
type HmacSha256 = Hmac<Sha256>;
|
||||
type RawBytes = Vec<u8>;
|
||||
|
||||
/// A data packet with layers of encryption
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Onion {
|
||||
/// The onion originator's portion of the shared secret
|
||||
pub ephemeral_pubkey: PublicKey,
|
||||
pub ephemeral_pubkey: xPublicKey,
|
||||
/// The pedersen commitment before adjusting the excess and subtracting the fee
|
||||
pub commit: Commitment,
|
||||
/// The encrypted payloads which represent the layers of the onion
|
||||
pub enc_payloads: Vec<RawBytes>,
|
||||
}
|
||||
|
||||
impl PartialEq for Onion {
|
||||
fn eq(&self, other: &Onion) -> bool {
|
||||
*self.ephemeral_pubkey.as_bytes() == *other.ephemeral_pubkey.as_bytes()
|
||||
&& self.commit == other.commit
|
||||
&& self.enc_payloads == other.enc_payloads
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Onion {}
|
||||
|
||||
impl Hash for Onion {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
state.write(self.ephemeral_pubkey.as_bytes());
|
||||
state.write(self.commit.as_ref());
|
||||
state.write_usize(self.enc_payloads.len());
|
||||
for p in &self.enc_payloads {
|
||||
state.write(p.as_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn vec_to_32_byte_arr(v: Vec<u8>) -> Result<[u8; 32], OnionError> {
|
||||
v.try_into().map_err(|_| InvalidKeyLength)
|
||||
}
|
||||
|
||||
impl Onion {
|
||||
pub fn serialize(&self) -> Result<Vec<u8>, ser::Error> {
|
||||
let mut vec = vec![];
|
||||
|
@ -38,9 +66,7 @@ impl Onion {
|
|||
|
||||
/// Peel a single layer off of the Onion, returning the peeled Onion and decrypted Payload
|
||||
pub fn peel_layer(&self, secret_key: &SecretKey) -> Result<(Payload, Onion), OnionError> {
|
||||
let secp = Secp256k1::new();
|
||||
|
||||
let shared_secret = SharedSecret::new(&secp, &self.ephemeral_pubkey, &secret_key);
|
||||
let shared_secret = StaticSecret::from(secret_key.0).diffie_hellman(&self.ephemeral_pubkey);
|
||||
let mut cipher = new_stream_cipher(&shared_secret)?;
|
||||
|
||||
let mut decrypted_bytes = self.enc_payloads[0].clone();
|
||||
|
@ -62,10 +88,12 @@ impl Onion {
|
|||
|
||||
let blinding_factor = calc_blinding_factor(&shared_secret, &self.ephemeral_pubkey)?;
|
||||
|
||||
let mut ephemeral_pubkey = self.ephemeral_pubkey.clone();
|
||||
ephemeral_pubkey
|
||||
.mul_assign(&secp, &blinding_factor)
|
||||
.map_err(|e| OnionError::CalcPubKeyError(e))?;
|
||||
let ephemeral_key = StaticSecret::from(
|
||||
*blinding_factor
|
||||
.diffie_hellman(&self.ephemeral_pubkey)
|
||||
.as_bytes(),
|
||||
);
|
||||
let ephemeral_pubkey = xPublicKey::from(&ephemeral_key);
|
||||
|
||||
let mut commitment = self.commit.clone();
|
||||
commitment = secp::add_excess(&commitment, &decrypted_payload.excess)
|
||||
|
@ -84,23 +112,23 @@ impl Onion {
|
|||
|
||||
fn calc_blinding_factor(
|
||||
shared_secret: &SharedSecret,
|
||||
ephemeral_pubkey: &PublicKey,
|
||||
) -> Result<SecretKey, OnionError> {
|
||||
let serialized_pubkey = ser::ser_vec(&ephemeral_pubkey, ProtocolVersion::local())?;
|
||||
|
||||
ephemeral_pubkey: &xPublicKey,
|
||||
) -> Result<StaticSecret, OnionError> {
|
||||
let mut hasher = Sha256::default();
|
||||
hasher.update(&serialized_pubkey);
|
||||
hasher.update(&shared_secret[0..32]);
|
||||
hasher.update(ephemeral_pubkey.as_bytes());
|
||||
hasher.update(shared_secret.as_bytes());
|
||||
let hashed: [u8; 32] = hasher
|
||||
.finalize()
|
||||
.as_slice()
|
||||
.try_into()
|
||||
.map_err(|_| InvalidKeyLength)?;
|
||||
|
||||
let secp = Secp256k1::new();
|
||||
let blind = SecretKey::from_slice(&secp, &hasher.finalize())
|
||||
.map_err(|e| OnionError::CalcBlindError(e))?;
|
||||
Ok(blind)
|
||||
Ok(StaticSecret::from(hashed))
|
||||
}
|
||||
|
||||
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[0..32]);
|
||||
mu_hmac.update(shared_secret.as_bytes());
|
||||
let mukey = mu_hmac.finalize().into_bytes();
|
||||
|
||||
let key = Key::from_slice(&mukey[0..32]);
|
||||
|
@ -111,7 +139,7 @@ fn new_stream_cipher(shared_secret: &SharedSecret) -> Result<ChaCha20, OnionErro
|
|||
|
||||
impl Writeable for Onion {
|
||||
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
|
||||
self.ephemeral_pubkey.write(writer)?;
|
||||
writer.write_fixed_bytes(self.ephemeral_pubkey.as_bytes())?;
|
||||
writer.write_fixed_bytes(&self.commit)?;
|
||||
writer.write_u64(self.enc_payloads.len() as u64)?;
|
||||
for p in &self.enc_payloads {
|
||||
|
@ -124,7 +152,9 @@ impl Writeable for Onion {
|
|||
|
||||
impl Readable for Onion {
|
||||
fn read<R: Reader>(reader: &mut R) -> Result<Onion, ser::Error> {
|
||||
let ephemeral_pubkey = PublicKey::read(reader)?;
|
||||
let pubkey_bytes: [u8; 32] =
|
||||
vec_to_32_byte_arr(reader.read_fixed_bytes(32)?).map_err(|_| ser::Error::CountError)?;
|
||||
let ephemeral_pubkey = xPublicKey::from(pubkey_bytes);
|
||||
let commit = Commitment::read(reader)?;
|
||||
let mut enc_payloads: Vec<RawBytes> = Vec::new();
|
||||
let len = reader.read_u64()?;
|
||||
|
@ -148,11 +178,7 @@ impl serde::ser::Serialize for Onion {
|
|||
{
|
||||
let mut state = serializer.serialize_struct("Onion", 3)?;
|
||||
|
||||
let secp = Secp256k1::new();
|
||||
state.serialize_field(
|
||||
"pubkey",
|
||||
&self.ephemeral_pubkey.serialize_vec(&secp, true).to_hex(),
|
||||
)?;
|
||||
state.serialize_field("pubkey", &self.ephemeral_pubkey.as_bytes().to_hex())?;
|
||||
state.serialize_field("commit", &self.commit.to_hex())?;
|
||||
|
||||
let hex_payloads: Vec<String> = self.enc_payloads.iter().map(|v| v.to_hex()).collect();
|
||||
|
@ -197,11 +223,10 @@ impl<'de> serde::de::Deserialize<'de> for Onion {
|
|||
let val: String = map.next_value()?;
|
||||
let vec =
|
||||
grin_util::from_hex(&val).map_err(serde::de::Error::custom)?;
|
||||
let secp = Secp256k1::new();
|
||||
pubkey = Some(
|
||||
PublicKey::from_slice(&secp, &vec[..])
|
||||
.map_err(serde::de::Error::custom)?,
|
||||
);
|
||||
pubkey =
|
||||
Some(xPublicKey::from(vec_to_32_byte_arr(vec).map_err(|_| {
|
||||
serde::de::Error::custom("Invalid length pubkey")
|
||||
})?));
|
||||
}
|
||||
Field::Commit => {
|
||||
let val: String = map.next_value()?;
|
||||
|
@ -267,40 +292,49 @@ impl From<ser::Error> for OnionError {
|
|||
#[cfg(test)]
|
||||
pub mod test_util {
|
||||
use super::{Onion, OnionError, RawBytes};
|
||||
use crate::secp::test_util::{rand_commit, rand_proof, rand_pubkey};
|
||||
use crate::secp::{self, Commitment, PublicKey, Secp256k1, SecretKey, SharedSecret};
|
||||
use crate::secp::test_util::{rand_commit, rand_proof};
|
||||
use crate::secp::{random_secret, Commitment, SecretKey};
|
||||
use crate::types::Payload;
|
||||
|
||||
use chacha20::cipher::StreamCipher;
|
||||
use grin_core::core::FeeFields;
|
||||
use rand::RngCore;
|
||||
use rand::{thread_rng, RngCore};
|
||||
use x25519_dalek::PublicKey as xPublicKey;
|
||||
use x25519_dalek::{SharedSecret, StaticSecret};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Hop {
|
||||
pub pubkey: PublicKey,
|
||||
pub pubkey: xPublicKey,
|
||||
pub payload: Payload,
|
||||
}
|
||||
/*
|
||||
Choose random xi for each node ni and create a Payload (Pi) for each containing xi
|
||||
Build a rangeproof for Cn=Cin+(Σx1...n)*G and include it in payload Pn
|
||||
Choose random initial ephemeral keypair (r1, R1)
|
||||
Derive remaining ephemeral keypairs such that ri+1=ri*Sha256(Ri||si) where si=ECDH(Ri, Ki)
|
||||
For each node ni, use ChaCha20 stream cipher with key=HmacSha256("MWIXNET"||si) and nonce "NONCE1234567" to encrypt payloads Pi...n
|
||||
*/
|
||||
|
||||
/// Create an Onion for the Commitment, encrypting the payload for each hop
|
||||
pub fn create_onion(commitment: &Commitment, hops: &Vec<Hop>) -> Result<Onion, OnionError> {
|
||||
let secp = Secp256k1::new();
|
||||
let session_key = secp::random_secret();
|
||||
let mut ephemeral_key = session_key.clone();
|
||||
let initial_key = StaticSecret::new(&mut thread_rng());
|
||||
let mut ephemeral_key = initial_key.clone();
|
||||
|
||||
let mut shared_secrets: Vec<SharedSecret> = Vec::new();
|
||||
let mut enc_payloads: Vec<RawBytes> = Vec::new();
|
||||
for hop in hops {
|
||||
let shared_secret = SharedSecret::new(&secp, &hop.pubkey, &ephemeral_key);
|
||||
let shared_secret = ephemeral_key.diffie_hellman(&hop.pubkey);
|
||||
|
||||
let ephemeral_pubkey = PublicKey::from_secret_key(&secp, &ephemeral_key)
|
||||
.map_err(|e| OnionError::CalcPubKeyError(e))?;
|
||||
let ephemeral_pubkey = xPublicKey::from(&ephemeral_key);
|
||||
let blinding_factor = super::calc_blinding_factor(&shared_secret, &ephemeral_pubkey)?;
|
||||
|
||||
shared_secrets.push(shared_secret);
|
||||
enc_payloads.push(hop.payload.serialize()?);
|
||||
ephemeral_key
|
||||
.mul_assign(&secp, &blinding_factor)
|
||||
.map_err(|e| OnionError::CalcPubKeyError(e))?;
|
||||
ephemeral_key = StaticSecret::from(
|
||||
*ephemeral_key
|
||||
.diffie_hellman(&xPublicKey::from(&blinding_factor))
|
||||
.as_bytes(),
|
||||
);
|
||||
}
|
||||
|
||||
for i in (0..shared_secrets.len()).rev() {
|
||||
|
@ -311,8 +345,7 @@ pub mod test_util {
|
|||
}
|
||||
|
||||
let onion = Onion {
|
||||
ephemeral_pubkey: PublicKey::from_secret_key(&secp, &session_key)
|
||||
.map_err(|e| OnionError::CalcPubKeyError(e))?,
|
||||
ephemeral_pubkey: xPublicKey::from(&initial_key),
|
||||
commit: commitment.clone(),
|
||||
enc_payloads,
|
||||
};
|
||||
|
@ -322,13 +355,13 @@ pub mod test_util {
|
|||
pub fn rand_onion() -> Onion {
|
||||
let commit = rand_commit();
|
||||
let mut hops = Vec::new();
|
||||
let k = (rand::thread_rng().next_u64() % 5) + 1;
|
||||
let k = (thread_rng().next_u64() % 5) + 1;
|
||||
for i in 0..k {
|
||||
let hop = Hop {
|
||||
pubkey: rand_pubkey(),
|
||||
pubkey: xPublicKey::from(random_secret().0),
|
||||
payload: Payload {
|
||||
excess: secp::random_secret(),
|
||||
fee: FeeFields::from(rand::thread_rng().next_u32()),
|
||||
excess: random_secret(),
|
||||
fee: FeeFields::from(thread_rng().next_u32()),
|
||||
rangeproof: if i == (k - 1) {
|
||||
Some(rand_proof())
|
||||
} else {
|
||||
|
@ -346,15 +379,12 @@ pub mod test_util {
|
|||
pub fn next_ephemeral_pubkey(
|
||||
onion: &Onion,
|
||||
server_key: &SecretKey,
|
||||
) -> Result<PublicKey, OnionError> {
|
||||
let secp = Secp256k1::new();
|
||||
let mut ephemeral_pubkey = onion.ephemeral_pubkey.clone();
|
||||
let shared_secret = SharedSecret::new(&secp, &ephemeral_pubkey, &server_key);
|
||||
let blinding_factor = super::calc_blinding_factor(&shared_secret, &ephemeral_pubkey)?;
|
||||
ephemeral_pubkey
|
||||
.mul_assign(&secp, &blinding_factor)
|
||||
.map_err(|e| OnionError::CalcPubKeyError(e))?;
|
||||
Ok(ephemeral_pubkey)
|
||||
) -> Result<xPublicKey, OnionError> {
|
||||
let shared_secret =
|
||||
StaticSecret::from(server_key.0.clone()).diffie_hellman(&onion.ephemeral_pubkey);
|
||||
let blinding_factor = super::calc_blinding_factor(&shared_secret, &onion.ephemeral_pubkey)?;
|
||||
let mul = blinding_factor.diffie_hellman(&onion.ephemeral_pubkey);
|
||||
Ok(xPublicKey::from(&StaticSecret::from(*mul.as_bytes())))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -365,6 +395,7 @@ pub mod tests {
|
|||
use crate::types::Payload;
|
||||
|
||||
use grin_core::core::FeeFields;
|
||||
use x25519_dalek::{PublicKey as xPublicKey, StaticSecret};
|
||||
|
||||
/// Test end-to-end Onion creation and unwrapping logic.
|
||||
#[test]
|
||||
|
@ -405,7 +436,7 @@ pub mod tests {
|
|||
};
|
||||
|
||||
hops.push(Hop {
|
||||
pubkey: secp::PublicKey::from_secret_key(&secp, &keys[i]).unwrap(),
|
||||
pubkey: xPublicKey::from(&StaticSecret::from(keys[i].0.clone())),
|
||||
payload: Payload {
|
||||
excess,
|
||||
fee: FeeFields::from(fee_per_hop as u32),
|
||||
|
|
|
@ -100,7 +100,6 @@ pub fn listen(
|
|||
};
|
||||
|
||||
let http_server = rpc_server.start_http();
|
||||
println!("Server listening on {}", server_config.addr);
|
||||
|
||||
let close_handle = http_server.close_handle();
|
||||
let round_handle = spawn(move || {
|
||||
|
|
|
@ -218,7 +218,7 @@ pub fn sign(sk: &SecretKey, msg: &Message) -> Result<Signature, secp256k1zkp::Er
|
|||
|
||||
#[cfg(test)]
|
||||
pub mod test_util {
|
||||
use crate::secp::{self, Commitment, PublicKey, RangeProof, Secp256k1};
|
||||
use crate::secp::{self, Commitment, RangeProof, Secp256k1};
|
||||
use grin_core::core::hash::Hash;
|
||||
use grin_util::ToHex;
|
||||
use rand::RngCore;
|
||||
|
@ -242,11 +242,6 @@ pub mod test_util {
|
|||
None,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn rand_pubkey() -> PublicKey {
|
||||
let secp = Secp256k1::new();
|
||||
PublicKey::from_secret_key(&secp, &secp::random_secret()).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -270,9 +270,7 @@ mod tests {
|
|||
use crate::node::mock::MockGrinNode;
|
||||
use crate::onion::test_util::{self, Hop};
|
||||
use crate::onion::Onion;
|
||||
use crate::secp::{
|
||||
self, ComSignature, Commitment, PublicKey, RangeProof, Secp256k1, SecretKey,
|
||||
};
|
||||
use crate::secp::{self, ComSignature, Commitment, RangeProof, Secp256k1, SecretKey};
|
||||
use crate::server::{Server, ServerImpl, SwapError};
|
||||
use crate::store::{SwapData, SwapStatus, SwapStore};
|
||||
use crate::types::Payload;
|
||||
|
@ -283,6 +281,8 @@ mod tests {
|
|||
use grin_core::global::{self, ChainTypes};
|
||||
use std::net::TcpListener;
|
||||
use std::sync::Arc;
|
||||
use x25519_dalek::PublicKey as xPublicKey;
|
||||
use x25519_dalek::StaticSecret;
|
||||
|
||||
macro_rules! assert_error_type {
|
||||
($result:expr, $error_type:pat) => {
|
||||
|
@ -351,9 +351,8 @@ mod tests {
|
|||
fee: u64,
|
||||
proof: Option<RangeProof>,
|
||||
) -> Hop {
|
||||
let secp = Secp256k1::new();
|
||||
Hop {
|
||||
pubkey: PublicKey::from_secret_key(&secp, &server_key).unwrap(),
|
||||
pubkey: xPublicKey::from(&StaticSecret::from(server_key.0.clone())),
|
||||
payload: Payload {
|
||||
excess: hop_excess.clone(),
|
||||
fee: FeeFields::from(fee as u32),
|
||||
|
|
Loading…
Reference in a new issue