switch to x25519 for onion encryption

This commit is contained in:
scilio 2022-10-13 11:15:52 -04:00
parent f70e1dfbf2
commit c59688a045
6 changed files with 136 additions and 111 deletions

26
Cargo.lock generated
View file

@ -45,7 +45,7 @@ dependencies = [
"nom 7.1.0", "nom 7.1.0",
"pin-project", "pin-project",
"rand 0.7.3", "rand 0.7.3",
"rand 0.8.4", "rand 0.8.5",
"rust-embed", "rust-embed",
"scrypt", "scrypt",
"sha2 0.9.8", "sha2 0.9.8",
@ -65,7 +65,7 @@ dependencies = [
"cookie-factory", "cookie-factory",
"hkdf", "hkdf",
"nom 7.1.0", "nom 7.1.0",
"rand 0.8.4", "rand 0.8.5",
"secrecy 0.8.0", "secrecy 0.8.0",
"sha2 0.9.8", "sha2 0.9.8",
] ]
@ -2475,7 +2475,9 @@ dependencies = [
"bytes 0.5.6", "bytes 0.5.6",
"chacha20", "chacha20",
"clap", "clap",
"curve25519-dalek 2.1.3",
"dirs", "dirs",
"ed25519-dalek",
"futures 0.3.17", "futures 0.3.17",
"grin_api 5.2.0-alpha.1 (git+https://github.com/mimblewimble/grin)", "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_chain 5.2.0-alpha.1 (git+https://github.com/mimblewimble/grin)",
@ -2488,6 +2490,7 @@ dependencies = [
"grin_wallet_api", "grin_wallet_api",
"grin_wallet_impls", "grin_wallet_impls",
"grin_wallet_libwallet", "grin_wallet_libwallet",
"grin_wallet_util",
"hmac 0.12.0", "hmac 0.12.0",
"hyper 0.14.14", "hyper 0.14.14",
"itertools", "itertools",
@ -2496,7 +2499,7 @@ dependencies = [
"jsonrpc-http-server", "jsonrpc-http-server",
"lazy_static", "lazy_static",
"pbkdf2 0.8.0", "pbkdf2 0.8.0",
"rand 0.8.4", "rand 0.7.3",
"ring", "ring",
"rpassword", "rpassword",
"serde", "serde",
@ -2506,6 +2509,7 @@ dependencies = [
"thiserror", "thiserror",
"tokio 1.12.0", "tokio 1.12.0",
"toml", "toml",
"x25519-dalek 0.6.0",
] ]
[[package]] [[package]]
@ -3033,14 +3037,13 @@ dependencies = [
[[package]] [[package]]
name = "rand" name = "rand"
version = "0.8.4" version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [ dependencies = [
"libc", "libc",
"rand_chacha 0.3.1", "rand_chacha 0.3.1",
"rand_core 0.6.3", "rand_core 0.6.3",
"rand_hc 0.3.1",
] ]
[[package]] [[package]]
@ -3124,15 +3127,6 @@ dependencies = [
"rand_core 0.5.1", "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]] [[package]]
name = "rand_isaac" name = "rand_isaac"
version = "0.1.1" version = "0.1.1"
@ -3854,7 +3848,7 @@ checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"libc", "libc",
"rand 0.8.4", "rand 0.8.5",
"redox_syscall 0.2.10", "redox_syscall 0.2.10",
"remove_dir_all", "remove_dir_all",
"winapi 0.3.9", "winapi 0.3.9",

View file

@ -11,7 +11,9 @@ byteorder = "1"
bytes = "0.5.6" bytes = "0.5.6"
chacha20 = "0.8.1" chacha20 = "0.8.1"
clap = { version = "2.33", features = ["yaml"] } clap = { version = "2.33", features = ["yaml"] }
curve25519-dalek = "2.1"
dirs = "2.0" dirs = "2.0"
ed25519-dalek = "1.0.1"
futures = "0.3" futures = "0.3"
hmac = { version = "0.12.0", features = ["std"]} hmac = { version = "0.12.0", features = ["std"]}
hyper = { version = "0.14", features = ["full"] } hyper = { version = "0.14", features = ["full"] }
@ -21,7 +23,7 @@ jsonrpc-derive = "18.0"
jsonrpc-http-server = "18.0" jsonrpc-http-server = "18.0"
lazy_static = "1" lazy_static = "1"
pbkdf2 = "0.8.0" pbkdf2 = "0.8.0"
rand = "0.8.4" rand = "0.7.3"
ring = "0.16" ring = "0.16"
rpassword = "4.0" rpassword = "4.0"
serde = { version = "1", features= ["derive"]} serde = { version = "1", features= ["derive"]}
@ -31,6 +33,7 @@ sha2 = "0.10.0"
thiserror = "1.0.31" 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"
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" }
@ -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_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_api = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" }
grin_wallet_impls = { 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" }

View file

@ -190,28 +190,30 @@ fn real_main() -> Result<(), Box<dyn std::error::Error>> {
) )
} }
#[cfg(unix)]
async fn build_signals_fut() { 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 // Listen for SIGINT, SIGQUIT, and SIGTERM
let mut terminate_signal = let mut terminate_signal =
signal(SignalKind::terminate()).expect("failed to create 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 quit_signal = signal(SignalKind::quit()).expect("failed to create quit signal");
let mut interrupt_signal = let mut interrupt_signal =
signal(SignalKind::interrupt()).expect("failed to create interrupt signal"); signal(SignalKind::interrupt()).expect("failed to create interrupt signal");
futures::future::select_all(vec![ futures::future::select_all(vec![
Box::pin(terminate_signal.recv()), Box::pin(terminate_signal.recv()),
Box::pin(quit_signal.recv()), Box::pin(quit_signal.recv()),
Box::pin(interrupt_signal.recv()), Box::pin(interrupt_signal.recv()),
]) ])
.await; .await;
} else { }
tokio::signal::ctrl_c()
.await #[cfg(not(unix))]
.expect("failed to install CTRL+C signal handler"); async fn build_signals_fut() {
} tokio::signal::ctrl_c()
.await
.expect("failed to install CTRL+C signal handler");
} }
fn prompt_password() -> ZeroingString { fn prompt_password() -> ZeroingString {

View file

@ -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::types::Payload;
use crate::onion::OnionError::{InvalidKeyLength, SerializationError}; use crate::onion::OnionError::{InvalidKeyLength, SerializationError};
use chacha20::cipher::{NewCipher, StreamCipher}; use chacha20::cipher::{NewCipher, StreamCipher};
use chacha20::{ChaCha20, Key, Nonce}; 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 grin_util::{self, ToHex};
use hmac::digest::InvalidLength; use hmac::digest::InvalidLength;
use hmac::{Hmac, Mac}; use hmac::{Hmac, Mac};
use serde::ser::SerializeStruct; use serde::ser::SerializeStruct;
use serde::Deserialize; use serde::Deserialize;
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use std::convert::TryInto;
use std::fmt; use std::fmt;
use std::hash::{Hash, Hasher};
use std::result::Result; use std::result::Result;
use thiserror::Error; use thiserror::Error;
use x25519_dalek::{PublicKey as xPublicKey, SharedSecret, StaticSecret};
type HmacSha256 = Hmac<Sha256>; type HmacSha256 = Hmac<Sha256>;
type RawBytes = Vec<u8>; type RawBytes = Vec<u8>;
/// A data packet with layers of encryption /// A data packet with layers of encryption
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug)]
pub struct Onion { pub struct Onion {
/// The onion originator's portion of the shared secret /// 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 /// The pedersen commitment before adjusting the excess and subtracting the fee
pub commit: Commitment, pub commit: Commitment,
/// The encrypted payloads which represent the layers of the onion /// The encrypted payloads which represent the layers of the onion
pub enc_payloads: Vec<RawBytes>, 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 { impl Onion {
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![];
@ -38,9 +66,7 @@ impl Onion {
/// Peel a single layer off of the Onion, returning the peeled Onion and decrypted Payload /// 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> { pub fn peel_layer(&self, secret_key: &SecretKey) -> Result<(Payload, Onion), OnionError> {
let secp = Secp256k1::new(); let shared_secret = StaticSecret::from(secret_key.0).diffie_hellman(&self.ephemeral_pubkey);
let shared_secret = SharedSecret::new(&secp, &self.ephemeral_pubkey, &secret_key);
let mut cipher = new_stream_cipher(&shared_secret)?; let mut cipher = new_stream_cipher(&shared_secret)?;
let mut decrypted_bytes = self.enc_payloads[0].clone(); 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 blinding_factor = calc_blinding_factor(&shared_secret, &self.ephemeral_pubkey)?;
let mut ephemeral_pubkey = self.ephemeral_pubkey.clone(); let ephemeral_key = StaticSecret::from(
ephemeral_pubkey *blinding_factor
.mul_assign(&secp, &blinding_factor) .diffie_hellman(&self.ephemeral_pubkey)
.map_err(|e| OnionError::CalcPubKeyError(e))?; .as_bytes(),
);
let ephemeral_pubkey = xPublicKey::from(&ephemeral_key);
let mut commitment = self.commit.clone(); let mut commitment = self.commit.clone();
commitment = secp::add_excess(&commitment, &decrypted_payload.excess) commitment = secp::add_excess(&commitment, &decrypted_payload.excess)
@ -84,23 +112,23 @@ impl Onion {
fn calc_blinding_factor( fn calc_blinding_factor(
shared_secret: &SharedSecret, shared_secret: &SharedSecret,
ephemeral_pubkey: &PublicKey, ephemeral_pubkey: &xPublicKey,
) -> Result<SecretKey, OnionError> { ) -> Result<StaticSecret, OnionError> {
let serialized_pubkey = ser::ser_vec(&ephemeral_pubkey, ProtocolVersion::local())?;
let mut hasher = Sha256::default(); let mut hasher = Sha256::default();
hasher.update(&serialized_pubkey); hasher.update(ephemeral_pubkey.as_bytes());
hasher.update(&shared_secret[0..32]); hasher.update(shared_secret.as_bytes());
let hashed: [u8; 32] = hasher
.finalize()
.as_slice()
.try_into()
.map_err(|_| InvalidKeyLength)?;
let secp = Secp256k1::new(); Ok(StaticSecret::from(hashed))
let blind = SecretKey::from_slice(&secp, &hasher.finalize())
.map_err(|e| OnionError::CalcBlindError(e))?;
Ok(blind)
} }
fn new_stream_cipher(shared_secret: &SharedSecret) -> Result<ChaCha20, OnionError> { 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[0..32]); mu_hmac.update(shared_secret.as_bytes());
let mukey = mu_hmac.finalize().into_bytes(); let mukey = mu_hmac.finalize().into_bytes();
let key = Key::from_slice(&mukey[0..32]); 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 { impl Writeable for Onion {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> { 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_fixed_bytes(&self.commit)?;
writer.write_u64(self.enc_payloads.len() as u64)?; writer.write_u64(self.enc_payloads.len() as u64)?;
for p in &self.enc_payloads { for p in &self.enc_payloads {
@ -124,7 +152,9 @@ impl Writeable for Onion {
impl Readable for Onion { impl Readable for Onion {
fn read<R: Reader>(reader: &mut R) -> Result<Onion, ser::Error> { 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 commit = Commitment::read(reader)?;
let mut enc_payloads: Vec<RawBytes> = Vec::new(); let mut enc_payloads: Vec<RawBytes> = Vec::new();
let len = reader.read_u64()?; let len = reader.read_u64()?;
@ -148,11 +178,7 @@ impl serde::ser::Serialize for Onion {
{ {
let mut state = serializer.serialize_struct("Onion", 3)?; let mut state = serializer.serialize_struct("Onion", 3)?;
let secp = Secp256k1::new(); state.serialize_field("pubkey", &self.ephemeral_pubkey.as_bytes().to_hex())?;
state.serialize_field(
"pubkey",
&self.ephemeral_pubkey.serialize_vec(&secp, true).to_hex(),
)?;
state.serialize_field("commit", &self.commit.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(); 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 val: String = map.next_value()?;
let vec = let vec =
grin_util::from_hex(&val).map_err(serde::de::Error::custom)?; grin_util::from_hex(&val).map_err(serde::de::Error::custom)?;
let secp = Secp256k1::new(); pubkey =
pubkey = Some( Some(xPublicKey::from(vec_to_32_byte_arr(vec).map_err(|_| {
PublicKey::from_slice(&secp, &vec[..]) serde::de::Error::custom("Invalid length pubkey")
.map_err(serde::de::Error::custom)?, })?));
);
} }
Field::Commit => { Field::Commit => {
let val: String = map.next_value()?; let val: String = map.next_value()?;
@ -267,40 +292,49 @@ impl From<ser::Error> for OnionError {
#[cfg(test)] #[cfg(test)]
pub mod test_util { pub mod test_util {
use super::{Onion, OnionError, RawBytes}; use super::{Onion, OnionError, RawBytes};
use crate::secp::test_util::{rand_commit, rand_proof, rand_pubkey}; use crate::secp::test_util::{rand_commit, rand_proof};
use crate::secp::{self, Commitment, PublicKey, Secp256k1, SecretKey, SharedSecret}; use crate::secp::{random_secret, Commitment, SecretKey};
use crate::types::Payload; use crate::types::Payload;
use chacha20::cipher::StreamCipher; use chacha20::cipher::StreamCipher;
use grin_core::core::FeeFields; 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)] #[derive(Clone)]
pub struct Hop { pub struct Hop {
pub pubkey: PublicKey, pub pubkey: xPublicKey,
pub payload: Payload, 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 /// Create an Onion for the Commitment, encrypting the payload for each hop
pub fn create_onion(commitment: &Commitment, hops: &Vec<Hop>) -> Result<Onion, OnionError> { pub fn create_onion(commitment: &Commitment, hops: &Vec<Hop>) -> Result<Onion, OnionError> {
let secp = Secp256k1::new(); let initial_key = StaticSecret::new(&mut thread_rng());
let session_key = secp::random_secret(); let mut ephemeral_key = initial_key.clone();
let mut ephemeral_key = session_key.clone();
let mut shared_secrets: Vec<SharedSecret> = Vec::new(); let mut shared_secrets: Vec<SharedSecret> = Vec::new();
let mut enc_payloads: Vec<RawBytes> = Vec::new(); let mut enc_payloads: Vec<RawBytes> = Vec::new();
for hop in hops { 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) let ephemeral_pubkey = xPublicKey::from(&ephemeral_key);
.map_err(|e| OnionError::CalcPubKeyError(e))?;
let blinding_factor = super::calc_blinding_factor(&shared_secret, &ephemeral_pubkey)?; let blinding_factor = super::calc_blinding_factor(&shared_secret, &ephemeral_pubkey)?;
shared_secrets.push(shared_secret); shared_secrets.push(shared_secret);
enc_payloads.push(hop.payload.serialize()?); enc_payloads.push(hop.payload.serialize()?);
ephemeral_key ephemeral_key = StaticSecret::from(
.mul_assign(&secp, &blinding_factor) *ephemeral_key
.map_err(|e| OnionError::CalcPubKeyError(e))?; .diffie_hellman(&xPublicKey::from(&blinding_factor))
.as_bytes(),
);
} }
for i in (0..shared_secrets.len()).rev() { for i in (0..shared_secrets.len()).rev() {
@ -311,8 +345,7 @@ pub mod test_util {
} }
let onion = Onion { let onion = Onion {
ephemeral_pubkey: PublicKey::from_secret_key(&secp, &session_key) ephemeral_pubkey: xPublicKey::from(&initial_key),
.map_err(|e| OnionError::CalcPubKeyError(e))?,
commit: commitment.clone(), commit: commitment.clone(),
enc_payloads, enc_payloads,
}; };
@ -322,13 +355,13 @@ pub mod test_util {
pub fn rand_onion() -> Onion { pub fn rand_onion() -> Onion {
let commit = rand_commit(); let commit = rand_commit();
let mut hops = Vec::new(); 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 { for i in 0..k {
let hop = Hop { let hop = Hop {
pubkey: rand_pubkey(), pubkey: xPublicKey::from(random_secret().0),
payload: Payload { payload: Payload {
excess: secp::random_secret(), excess: random_secret(),
fee: FeeFields::from(rand::thread_rng().next_u32()), fee: FeeFields::from(thread_rng().next_u32()),
rangeproof: if i == (k - 1) { rangeproof: if i == (k - 1) {
Some(rand_proof()) Some(rand_proof())
} else { } else {
@ -346,15 +379,12 @@ pub mod test_util {
pub fn next_ephemeral_pubkey( pub fn next_ephemeral_pubkey(
onion: &Onion, onion: &Onion,
server_key: &SecretKey, server_key: &SecretKey,
) -> Result<PublicKey, OnionError> { ) -> Result<xPublicKey, OnionError> {
let secp = Secp256k1::new(); let shared_secret =
let mut ephemeral_pubkey = onion.ephemeral_pubkey.clone(); StaticSecret::from(server_key.0.clone()).diffie_hellman(&onion.ephemeral_pubkey);
let shared_secret = SharedSecret::new(&secp, &ephemeral_pubkey, &server_key); let blinding_factor = super::calc_blinding_factor(&shared_secret, &onion.ephemeral_pubkey)?;
let blinding_factor = super::calc_blinding_factor(&shared_secret, &ephemeral_pubkey)?; let mul = blinding_factor.diffie_hellman(&onion.ephemeral_pubkey);
ephemeral_pubkey Ok(xPublicKey::from(&StaticSecret::from(*mul.as_bytes())))
.mul_assign(&secp, &blinding_factor)
.map_err(|e| OnionError::CalcPubKeyError(e))?;
Ok(ephemeral_pubkey)
} }
} }
@ -365,6 +395,7 @@ pub mod tests {
use crate::types::Payload; use crate::types::Payload;
use grin_core::core::FeeFields; use grin_core::core::FeeFields;
use x25519_dalek::{PublicKey as xPublicKey, StaticSecret};
/// Test end-to-end Onion creation and unwrapping logic. /// Test end-to-end Onion creation and unwrapping logic.
#[test] #[test]
@ -405,7 +436,7 @@ pub mod tests {
}; };
hops.push(Hop { hops.push(Hop {
pubkey: secp::PublicKey::from_secret_key(&secp, &keys[i]).unwrap(), pubkey: xPublicKey::from(&StaticSecret::from(keys[i].0.clone())),
payload: Payload { payload: Payload {
excess, excess,
fee: FeeFields::from(fee_per_hop as u32), fee: FeeFields::from(fee_per_hop as u32),

View file

@ -218,7 +218,7 @@ pub fn sign(sk: &SecretKey, msg: &Message) -> Result<Signature, secp256k1zkp::Er
#[cfg(test)] #[cfg(test)]
pub mod test_util { 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_core::core::hash::Hash;
use grin_util::ToHex; use grin_util::ToHex;
use rand::RngCore; use rand::RngCore;
@ -242,11 +242,6 @@ pub mod test_util {
None, None,
) )
} }
pub fn rand_pubkey() -> PublicKey {
let secp = Secp256k1::new();
PublicKey::from_secret_key(&secp, &secp::random_secret()).unwrap()
}
} }
#[cfg(test)] #[cfg(test)]

View file

@ -270,9 +270,7 @@ mod tests {
use crate::node::mock::MockGrinNode; use crate::node::mock::MockGrinNode;
use crate::onion::test_util::{self, Hop}; use crate::onion::test_util::{self, Hop};
use crate::onion::Onion; use crate::onion::Onion;
use crate::secp::{ use crate::secp::{self, ComSignature, Commitment, RangeProof, Secp256k1, SecretKey};
self, ComSignature, Commitment, PublicKey, RangeProof, Secp256k1, SecretKey,
};
use crate::server::{Server, ServerImpl, SwapError}; use crate::server::{Server, ServerImpl, SwapError};
use crate::store::{SwapData, SwapStatus, SwapStore}; use crate::store::{SwapData, SwapStatus, SwapStore};
use crate::types::Payload; use crate::types::Payload;
@ -283,6 +281,8 @@ mod tests {
use grin_core::global::{self, ChainTypes}; use grin_core::global::{self, ChainTypes};
use std::net::TcpListener; use std::net::TcpListener;
use std::sync::Arc; use std::sync::Arc;
use x25519_dalek::PublicKey as xPublicKey;
use x25519_dalek::StaticSecret;
macro_rules! assert_error_type { macro_rules! assert_error_type {
($result:expr, $error_type:pat) => { ($result:expr, $error_type:pat) => {
@ -351,9 +351,8 @@ mod tests {
fee: u64, fee: u64,
proof: Option<RangeProof>, proof: Option<RangeProof>,
) -> Hop { ) -> Hop {
let secp = Secp256k1::new();
Hop { Hop {
pubkey: PublicKey::from_secret_key(&secp, &server_key).unwrap(), pubkey: xPublicKey::from(&StaticSecret::from(server_key.0.clone())),
payload: Payload { payload: Payload {
excess: hop_excess.clone(), excess: hop_excess.clone(),
fee: FeeFields::from(fee as u32), fee: FeeFields::from(fee as u32),