mirror of
https://github.com/jwinterm/grin-wallet.git
synced 2026-10-17 07:11:36 +02:00
create_mwixnet_req: take server public keys, not secrets
MixnetReqCreationParams carried the mix servers' SECRET keys and derived each x25519 onion pubkey from them — a test artifact, since a wallet only knows the servers' public keys. Take the x25519 onion public keys directly. - MixnetReqCreationParams.server_keys (Vec<SecretKey>) -> server_pubkeys (Vec<x25519 PublicKey>) with a vec_xpubkey_hex serde helper (hex list). - create_mwixnet_req uses the pubkeys directly as the onion hop keys. - owner RPC parses hex pubkeys; docs/examples updated; tests derive the pubkeys from their known secrets so coverage is unchanged. - add x25519-dalek to api and controller.
This commit is contained in:
Generated
+2
@@ -1510,6 +1510,7 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"uuid",
|
"uuid",
|
||||||
|
"x25519-dalek 0.6.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1561,6 +1562,7 @@ dependencies = [
|
|||||||
"tokio 0.2.25",
|
"tokio 0.2.25",
|
||||||
"url",
|
"url",
|
||||||
"uuid",
|
"uuid",
|
||||||
|
"x25519-dalek 0.6.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ chrono = { version = "0.4.11", features = ["serde"] }
|
|||||||
ring = "0.16"
|
ring = "0.16"
|
||||||
base64 = "0.12"
|
base64 = "0.12"
|
||||||
ed25519-dalek = "1.0.0-pre.4"
|
ed25519-dalek = "1.0.0-pre.4"
|
||||||
|
x25519-dalek = "0.6"
|
||||||
|
|
||||||
grin_wallet_libwallet = { path = "../libwallet", version = "5.4.0-alpha.1" }
|
grin_wallet_libwallet = { path = "../libwallet", version = "5.4.0-alpha.1" }
|
||||||
grin_wallet_config = { path = "../config", version = "5.4.0-alpha.1" }
|
grin_wallet_config = { path = "../config", version = "5.4.0-alpha.1" }
|
||||||
|
|||||||
+1
-1
@@ -2543,7 +2543,7 @@ where
|
|||||||
/// let api_owner = Owner::new(wallet.clone(), None);
|
/// let api_owner = Owner::new(wallet.clone(), None);
|
||||||
/// let keychain_mask = None;
|
/// let keychain_mask = None;
|
||||||
/// let params = MixnetReqCreationParams {
|
/// let params = MixnetReqCreationParams {
|
||||||
/// server_keys: vec![], // Public keys here in secret key representation
|
/// server_pubkeys: vec![], // x25519 onion public keys of the mix servers
|
||||||
/// fee_per_hop: 100,
|
/// fee_per_hop: 100,
|
||||||
/// };
|
/// };
|
||||||
///
|
///
|
||||||
|
|||||||
+15
-16
@@ -2023,10 +2023,10 @@ pub trait OwnerRpc {
|
|||||||
"commitment": "08e1da9e6dc4d6e808a718b2f110a991dd775d65ce5ae408a4e1f002a4961aa9e7",
|
"commitment": "08e1da9e6dc4d6e808a718b2f110a991dd775d65ce5ae408a4e1f002a4961aa9e7",
|
||||||
"fee_per_hop": "5000000",
|
"fee_per_hop": "5000000",
|
||||||
"lock_output": true,
|
"lock_output": true,
|
||||||
"server_keys": [
|
"server_pubkeys": [
|
||||||
"97444ae673bb92c713c1a2f7b8882ffbfc1c67401a280a775dce1a8651584332",
|
"24308f58032819d05146db48e78246139f8e30770b1fd1585392df8374d6226a",
|
||||||
"0c9414341f2140ed34a5a12a6479bf5a6404820d001ab81d9d3e8cc38f049b4e",
|
"3ab3b7d1fb643393897a0b942934d34be9cb823621cd49c09b12fdfa69598d71",
|
||||||
"b58ece97d60e71bb7e53218400b0d67bfe6a3cb7d3b4a67a44f8fb7c525cbca5"
|
"80f2ceadcc5a767961772f4ae04826c70b0ae497f4f50d782241ff056b71df45"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"id": 1
|
"id": 1
|
||||||
@@ -2064,7 +2064,7 @@ pub trait OwnerRpc {
|
|||||||
commitment: String,
|
commitment: String,
|
||||||
fee_per_hop: String,
|
fee_per_hop: String,
|
||||||
lock_output: bool,
|
lock_output: bool,
|
||||||
server_keys: Vec<String>,
|
server_pubkeys: Vec<String>,
|
||||||
) -> Result<SwapReq, Error>;
|
) -> Result<SwapReq, Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2541,24 +2541,23 @@ where
|
|||||||
commitment: String,
|
commitment: String,
|
||||||
fee_per_hop: String,
|
fee_per_hop: String,
|
||||||
lock_output: bool,
|
lock_output: bool,
|
||||||
server_keys: Vec<String>,
|
server_pubkeys: Vec<String>,
|
||||||
) -> Result<SwapReq, Error> {
|
) -> Result<SwapReq, Error> {
|
||||||
let commit =
|
let commit =
|
||||||
Commitment::from_vec(from_hex(&commitment).map_err(|e| Error::CommitDeser(e))?);
|
Commitment::from_vec(from_hex(&commitment).map_err(|e| Error::CommitDeser(e))?);
|
||||||
|
|
||||||
let secp_inst = static_secp_instance();
|
let mut pubkeys = vec![];
|
||||||
let secp = secp_inst.lock();
|
for key in server_pubkeys {
|
||||||
|
let bytes = grin_util::from_hex(&key).map_err(|e| Error::ServerKeyDeser(e))?;
|
||||||
let mut keys = vec![];
|
let arr: [u8; 32] = bytes
|
||||||
for key in server_keys {
|
.as_slice()
|
||||||
keys.push(SecretKey::from_slice(
|
.try_into()
|
||||||
&secp,
|
.map_err(|_| Error::GenericError(format!("x25519 pubkey must be 32 bytes: {}", key)))?;
|
||||||
&grin_util::from_hex(&key).map_err(|e| Error::ServerKeyDeser(e))?,
|
pubkeys.push(x25519_dalek::PublicKey::from(arr));
|
||||||
)?)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let req_params = MixnetReqCreationParams {
|
let req_params = MixnetReqCreationParams {
|
||||||
server_keys: keys,
|
server_pubkeys: pubkeys,
|
||||||
fee_per_hop: fee_per_hop
|
fee_per_hop: fee_per_hop
|
||||||
.parse::<u64>()
|
.parse::<u64>()
|
||||||
.map_err(|_| Error::U64Deser(fee_per_hop))?,
|
.map_err(|_| Error::U64Deser(fee_per_hop))?,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ed25519-dalek = "1.0.0-pre.4"
|
ed25519-dalek = "1.0.0-pre.4"
|
||||||
|
x25519-dalek = "0.6"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
hyper = "0.14"
|
hyper = "0.14"
|
||||||
rand = "0.7"
|
rand = "0.7"
|
||||||
|
|||||||
@@ -102,17 +102,18 @@ fn contract_srs_mwixnet_tx_impl(test_dir: &'static str) -> Result<(), libwallet:
|
|||||||
"0c9414341f2140ed34a5a12a6479bf5a6404820d001ab81d9d3e8cc38f049b4e";
|
"0c9414341f2140ed34a5a12a6479bf5a6404820d001ab81d9d3e8cc38f049b4e";
|
||||||
let server_pubkey_str_3 =
|
let server_pubkey_str_3 =
|
||||||
"b58ece97d60e71bb7e53218400b0d67bfe6a3cb7d3b4a67a44f8fb7c525cbca5";
|
"b58ece97d60e71bb7e53218400b0d67bfe6a3cb7d3b4a67a44f8fb7c525cbca5";
|
||||||
let server_key_1 =
|
// Derive each server's x25519 onion pubkey from the known test secret
|
||||||
SecretKey::from_slice(&secp, &grin_util::from_hex(&server_pubkey_str_1).unwrap())
|
// (in practice each server publishes its onion pubkey).
|
||||||
.unwrap();
|
let server_pubkey = |hex: &str| {
|
||||||
let server_key_2 =
|
let sk = SecretKey::from_slice(&secp, &grin_util::from_hex(hex).unwrap()).unwrap();
|
||||||
SecretKey::from_slice(&secp, &grin_util::from_hex(&server_pubkey_str_2).unwrap())
|
x25519_dalek::PublicKey::from(&x25519_dalek::StaticSecret::from(sk.0))
|
||||||
.unwrap();
|
};
|
||||||
let server_key_3 =
|
|
||||||
SecretKey::from_slice(&secp, &grin_util::from_hex(&server_pubkey_str_3).unwrap())
|
|
||||||
.unwrap();
|
|
||||||
let params = MixnetReqCreationParams {
|
let params = MixnetReqCreationParams {
|
||||||
server_keys: vec![server_key_1, server_key_2, server_key_3],
|
server_pubkeys: vec![
|
||||||
|
server_pubkey(server_pubkey_str_1),
|
||||||
|
server_pubkey(server_pubkey_str_2),
|
||||||
|
server_pubkey(server_pubkey_str_3),
|
||||||
|
],
|
||||||
fee_per_hop: 50_000_000,
|
fee_per_hop: 50_000_000,
|
||||||
};
|
};
|
||||||
let outputs = api.retrieve_outputs(recv_mask, false, false, None)?;
|
let outputs = api.retrieve_outputs(recv_mask, false, false, None)?;
|
||||||
|
|||||||
+11
-10
@@ -143,17 +143,18 @@ fn mwixnet_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||||||
"0c9414341f2140ed34a5a12a6479bf5a6404820d001ab81d9d3e8cc38f049b4e";
|
"0c9414341f2140ed34a5a12a6479bf5a6404820d001ab81d9d3e8cc38f049b4e";
|
||||||
let server_pubkey_str_3 =
|
let server_pubkey_str_3 =
|
||||||
"b58ece97d60e71bb7e53218400b0d67bfe6a3cb7d3b4a67a44f8fb7c525cbca5";
|
"b58ece97d60e71bb7e53218400b0d67bfe6a3cb7d3b4a67a44f8fb7c525cbca5";
|
||||||
let server_key_1 =
|
// The mwixnet servers' x25519 onion public keys (derived here from known test
|
||||||
SecretKey::from_slice(&secp, &grin_util::from_hex(&server_pubkey_str_1).unwrap())
|
// secrets; in practice each server publishes its onion pubkey).
|
||||||
.unwrap();
|
let server_pubkey = |hex: &str| {
|
||||||
let server_key_2 =
|
let sk = SecretKey::from_slice(&secp, &grin_util::from_hex(hex).unwrap()).unwrap();
|
||||||
SecretKey::from_slice(&secp, &grin_util::from_hex(&server_pubkey_str_2).unwrap())
|
x25519_dalek::PublicKey::from(&x25519_dalek::StaticSecret::from(sk.0))
|
||||||
.unwrap();
|
};
|
||||||
let server_key_3 =
|
|
||||||
SecretKey::from_slice(&secp, &grin_util::from_hex(&server_pubkey_str_3).unwrap())
|
|
||||||
.unwrap();
|
|
||||||
let params = MixnetReqCreationParams {
|
let params = MixnetReqCreationParams {
|
||||||
server_keys: vec![server_key_1, server_key_2, server_key_3],
|
server_pubkeys: vec![
|
||||||
|
server_pubkey(server_pubkey_str_1),
|
||||||
|
server_pubkey(server_pubkey_str_2),
|
||||||
|
server_pubkey(server_pubkey_str_3),
|
||||||
|
],
|
||||||
fee_per_hop: 50_000_000,
|
fee_per_hop: 50_000_000,
|
||||||
};
|
};
|
||||||
let outputs = api.retrieve_outputs(mask1, false, false, None)?;
|
let outputs = api.retrieve_outputs(mask1, false, false, None)?;
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ use chrono::prelude::{DateTime, NaiveDateTime, Utc};
|
|||||||
use ed25519_dalek::PublicKey as DalekPublicKey;
|
use ed25519_dalek::PublicKey as DalekPublicKey;
|
||||||
use ed25519_dalek::SecretKey as DalekSecretKey;
|
use ed25519_dalek::SecretKey as DalekSecretKey;
|
||||||
use ed25519_dalek::Verifier;
|
use ed25519_dalek::Verifier;
|
||||||
use x25519_dalek::{PublicKey as xPublicKey, StaticSecret};
|
|
||||||
|
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
@@ -1665,12 +1664,7 @@ where
|
|||||||
SwitchCommitmentType::Regular,
|
SwitchCommitmentType::Regular,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let mut server_pubkeys = vec![];
|
let server_pubkeys = params.server_pubkeys.clone();
|
||||||
for i in 0..params.server_keys.len() {
|
|
||||||
server_pubkeys.push(xPublicKey::from(&StaticSecret::from(
|
|
||||||
params.server_keys[i].0,
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
let fee = grin_core::libtx::tx_fee(1, 1, 1);
|
let fee = grin_core::libtx::tx_fee(1, 1, 1);
|
||||||
let new_amount = amount - (fee * server_pubkeys.len() as u64);
|
let new_amount = amount - (fee * server_pubkeys.len() as u64);
|
||||||
|
|||||||
@@ -17,8 +17,8 @@
|
|||||||
|
|
||||||
use super::onion::comsig_serde;
|
use super::onion::comsig_serde;
|
||||||
use grin_core::libtx::secp_ser::string_or_u64;
|
use grin_core::libtx::secp_ser::string_or_u64;
|
||||||
use grin_util::secp::key::SecretKey;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use x25519_dalek::PublicKey as xPublicKey;
|
||||||
|
|
||||||
pub use super::onion::{onion::Onion, ComSignature, Hop};
|
pub use super::onion::{onion::Onion, ComSignature, Hop};
|
||||||
|
|
||||||
@@ -35,9 +35,39 @@ pub struct SwapReq {
|
|||||||
/// mwixnetRequest Creation Params
|
/// mwixnetRequest Creation Params
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct MixnetReqCreationParams {
|
pub struct MixnetReqCreationParams {
|
||||||
/// List of all the server keys
|
/// x25519 onion public keys of the mix servers, in route order
|
||||||
pub server_keys: Vec<SecretKey>,
|
#[serde(with = "vec_xpubkey_hex")]
|
||||||
|
pub server_pubkeys: Vec<xPublicKey>,
|
||||||
/// Fees per hop
|
/// Fees per hop
|
||||||
#[serde(with = "string_or_u64")]
|
#[serde(with = "string_or_u64")]
|
||||||
pub fee_per_hop: u64,
|
pub fee_per_hop: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serializes a Vec<x25519 PublicKey> as a list of hex strings.
|
||||||
|
pub mod vec_xpubkey_hex {
|
||||||
|
use grin_util::{from_hex, ToHex};
|
||||||
|
use serde::de::Error;
|
||||||
|
use serde::{Deserialize, Deserializer, Serializer};
|
||||||
|
use x25519_dalek::PublicKey as xPublicKey;
|
||||||
|
|
||||||
|
///
|
||||||
|
pub fn serialize<S: Serializer>(keys: &Vec<xPublicKey>, s: S) -> Result<S::Ok, S::Error> {
|
||||||
|
let hexes: Vec<String> = keys.iter().map(|k| k.as_bytes().to_hex()).collect();
|
||||||
|
serde::Serialize::serialize(&hexes, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<Vec<xPublicKey>, D::Error> {
|
||||||
|
let hexes: Vec<String> = Deserialize::deserialize(d)?;
|
||||||
|
let mut keys = Vec::with_capacity(hexes.len());
|
||||||
|
for h in hexes {
|
||||||
|
let bytes = from_hex(&h).map_err(Error::custom)?;
|
||||||
|
let arr: [u8; 32] = bytes
|
||||||
|
.as_slice()
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| Error::custom("x25519 pubkey must be 32 bytes"))?;
|
||||||
|
keys.push(xPublicKey::from(arr));
|
||||||
|
}
|
||||||
|
Ok(keys)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user