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",
|
||||
"tempfile",
|
||||
"uuid",
|
||||
"x25519-dalek 0.6.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1561,6 +1562,7 @@ dependencies = [
|
||||
"tokio 0.2.25",
|
||||
"url",
|
||||
"uuid",
|
||||
"x25519-dalek 0.6.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -21,6 +21,7 @@ chrono = { version = "0.4.11", features = ["serde"] }
|
||||
ring = "0.16"
|
||||
base64 = "0.12"
|
||||
ed25519-dalek = "1.0.0-pre.4"
|
||||
x25519-dalek = "0.6"
|
||||
|
||||
grin_wallet_libwallet = { path = "../libwallet", 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 keychain_mask = None;
|
||||
/// 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,
|
||||
/// };
|
||||
///
|
||||
|
||||
+15
-16
@@ -2023,10 +2023,10 @@ pub trait OwnerRpc {
|
||||
"commitment": "08e1da9e6dc4d6e808a718b2f110a991dd775d65ce5ae408a4e1f002a4961aa9e7",
|
||||
"fee_per_hop": "5000000",
|
||||
"lock_output": true,
|
||||
"server_keys": [
|
||||
"97444ae673bb92c713c1a2f7b8882ffbfc1c67401a280a775dce1a8651584332",
|
||||
"0c9414341f2140ed34a5a12a6479bf5a6404820d001ab81d9d3e8cc38f049b4e",
|
||||
"b58ece97d60e71bb7e53218400b0d67bfe6a3cb7d3b4a67a44f8fb7c525cbca5"
|
||||
"server_pubkeys": [
|
||||
"24308f58032819d05146db48e78246139f8e30770b1fd1585392df8374d6226a",
|
||||
"3ab3b7d1fb643393897a0b942934d34be9cb823621cd49c09b12fdfa69598d71",
|
||||
"80f2ceadcc5a767961772f4ae04826c70b0ae497f4f50d782241ff056b71df45"
|
||||
]
|
||||
},
|
||||
"id": 1
|
||||
@@ -2064,7 +2064,7 @@ pub trait OwnerRpc {
|
||||
commitment: String,
|
||||
fee_per_hop: String,
|
||||
lock_output: bool,
|
||||
server_keys: Vec<String>,
|
||||
server_pubkeys: Vec<String>,
|
||||
) -> Result<SwapReq, Error>;
|
||||
}
|
||||
|
||||
@@ -2541,24 +2541,23 @@ where
|
||||
commitment: String,
|
||||
fee_per_hop: String,
|
||||
lock_output: bool,
|
||||
server_keys: Vec<String>,
|
||||
server_pubkeys: Vec<String>,
|
||||
) -> Result<SwapReq, Error> {
|
||||
let commit =
|
||||
Commitment::from_vec(from_hex(&commitment).map_err(|e| Error::CommitDeser(e))?);
|
||||
|
||||
let secp_inst = static_secp_instance();
|
||||
let secp = secp_inst.lock();
|
||||
|
||||
let mut keys = vec![];
|
||||
for key in server_keys {
|
||||
keys.push(SecretKey::from_slice(
|
||||
&secp,
|
||||
&grin_util::from_hex(&key).map_err(|e| Error::ServerKeyDeser(e))?,
|
||||
)?)
|
||||
let mut pubkeys = vec![];
|
||||
for key in server_pubkeys {
|
||||
let bytes = grin_util::from_hex(&key).map_err(|e| Error::ServerKeyDeser(e))?;
|
||||
let arr: [u8; 32] = bytes
|
||||
.as_slice()
|
||||
.try_into()
|
||||
.map_err(|_| Error::GenericError(format!("x25519 pubkey must be 32 bytes: {}", key)))?;
|
||||
pubkeys.push(x25519_dalek::PublicKey::from(arr));
|
||||
}
|
||||
|
||||
let req_params = MixnetReqCreationParams {
|
||||
server_keys: keys,
|
||||
server_pubkeys: pubkeys,
|
||||
fee_per_hop: fee_per_hop
|
||||
.parse::<u64>()
|
||||
.map_err(|_| Error::U64Deser(fee_per_hop))?,
|
||||
|
||||
@@ -12,6 +12,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
ed25519-dalek = "1.0.0-pre.4"
|
||||
x25519-dalek = "0.6"
|
||||
futures = "0.3"
|
||||
hyper = "0.14"
|
||||
rand = "0.7"
|
||||
|
||||
@@ -102,17 +102,18 @@ fn contract_srs_mwixnet_tx_impl(test_dir: &'static str) -> Result<(), libwallet:
|
||||
"0c9414341f2140ed34a5a12a6479bf5a6404820d001ab81d9d3e8cc38f049b4e";
|
||||
let server_pubkey_str_3 =
|
||||
"b58ece97d60e71bb7e53218400b0d67bfe6a3cb7d3b4a67a44f8fb7c525cbca5";
|
||||
let server_key_1 =
|
||||
SecretKey::from_slice(&secp, &grin_util::from_hex(&server_pubkey_str_1).unwrap())
|
||||
.unwrap();
|
||||
let server_key_2 =
|
||||
SecretKey::from_slice(&secp, &grin_util::from_hex(&server_pubkey_str_2).unwrap())
|
||||
.unwrap();
|
||||
let server_key_3 =
|
||||
SecretKey::from_slice(&secp, &grin_util::from_hex(&server_pubkey_str_3).unwrap())
|
||||
.unwrap();
|
||||
// Derive each server's x25519 onion pubkey from the known test secret
|
||||
// (in practice each server publishes its onion pubkey).
|
||||
let server_pubkey = |hex: &str| {
|
||||
let sk = SecretKey::from_slice(&secp, &grin_util::from_hex(hex).unwrap()).unwrap();
|
||||
x25519_dalek::PublicKey::from(&x25519_dalek::StaticSecret::from(sk.0))
|
||||
};
|
||||
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,
|
||||
};
|
||||
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";
|
||||
let server_pubkey_str_3 =
|
||||
"b58ece97d60e71bb7e53218400b0d67bfe6a3cb7d3b4a67a44f8fb7c525cbca5";
|
||||
let server_key_1 =
|
||||
SecretKey::from_slice(&secp, &grin_util::from_hex(&server_pubkey_str_1).unwrap())
|
||||
.unwrap();
|
||||
let server_key_2 =
|
||||
SecretKey::from_slice(&secp, &grin_util::from_hex(&server_pubkey_str_2).unwrap())
|
||||
.unwrap();
|
||||
let server_key_3 =
|
||||
SecretKey::from_slice(&secp, &grin_util::from_hex(&server_pubkey_str_3).unwrap())
|
||||
.unwrap();
|
||||
// The mwixnet servers' x25519 onion public keys (derived here from known test
|
||||
// secrets; in practice each server publishes its onion pubkey).
|
||||
let server_pubkey = |hex: &str| {
|
||||
let sk = SecretKey::from_slice(&secp, &grin_util::from_hex(hex).unwrap()).unwrap();
|
||||
x25519_dalek::PublicKey::from(&x25519_dalek::StaticSecret::from(sk.0))
|
||||
};
|
||||
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,
|
||||
};
|
||||
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::SecretKey as DalekSecretKey;
|
||||
use ed25519_dalek::Verifier;
|
||||
use x25519_dalek::{PublicKey as xPublicKey, StaticSecret};
|
||||
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::sync::mpsc::Sender;
|
||||
@@ -1665,12 +1664,7 @@ where
|
||||
SwitchCommitmentType::Regular,
|
||||
)?;
|
||||
|
||||
let mut server_pubkeys = vec![];
|
||||
for i in 0..params.server_keys.len() {
|
||||
server_pubkeys.push(xPublicKey::from(&StaticSecret::from(
|
||||
params.server_keys[i].0,
|
||||
)));
|
||||
}
|
||||
let server_pubkeys = params.server_pubkeys.clone();
|
||||
|
||||
let fee = grin_core::libtx::tx_fee(1, 1, 1);
|
||||
let new_amount = amount - (fee * server_pubkeys.len() as u64);
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
|
||||
use super::onion::comsig_serde;
|
||||
use grin_core::libtx::secp_ser::string_or_u64;
|
||||
use grin_util::secp::key::SecretKey;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use x25519_dalek::PublicKey as xPublicKey;
|
||||
|
||||
pub use super::onion::{onion::Onion, ComSignature, Hop};
|
||||
|
||||
@@ -35,9 +35,39 @@ pub struct SwapReq {
|
||||
/// mwixnetRequest Creation Params
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct MixnetReqCreationParams {
|
||||
/// List of all the server keys
|
||||
pub server_keys: Vec<SecretKey>,
|
||||
/// x25519 onion public keys of the mix servers, in route order
|
||||
#[serde(with = "vec_xpubkey_hex")]
|
||||
pub server_pubkeys: Vec<xPublicKey>,
|
||||
/// Fees per hop
|
||||
#[serde(with = "string_or_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