Files
nym/common/topology/src/mix.rs
T
Jędrzej Stuczyński a2324f98f8 Feature/identity verification (#930)
* Base58 representation of ed25519 signature

* Helper for verifying ed25519 signature on sender address

* Signature verification for gateway bonding

* Signature verification for mixnode bonding

* Added owner signatures for bonding in vesting contract

* Fixed choosing mixnode layer test

* Added owner signature fields to nymd client for bonding

* 'Updated' tauri wallet with new bond requirements

* Mixnode sign command with extra address validation

* Sign command for the gateway

* Signing own gateway's address derived with known mnemonic in not(coconut) case

* Fixed imports post-merge
2021-12-07 10:28:44 +00:00

139 lines
4.6 KiB
Rust

// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::{filter, NetworkAddress};
use crypto::asymmetric::{encryption, identity};
use mixnet_contract::{Layer, MixNodeBond};
use nymsphinx_addressing::nodes::NymNodeRoutingAddress;
use nymsphinx_types::Node as SphinxNode;
use std::convert::{TryFrom, TryInto};
use std::fmt::{self, Display, Formatter};
use std::io;
use std::net::SocketAddr;
#[derive(Debug)]
pub enum MixnodeConversionError {
InvalidIdentityKey(identity::Ed25519RecoveryError),
InvalidSphinxKey(encryption::KeyRecoveryError),
InvalidAddress(String, io::Error),
InvalidStake,
Other(Box<dyn std::error::Error + Send + Sync>),
}
impl From<encryption::KeyRecoveryError> for MixnodeConversionError {
fn from(err: encryption::KeyRecoveryError) -> Self {
MixnodeConversionError::InvalidSphinxKey(err)
}
}
impl From<identity::Ed25519RecoveryError> for MixnodeConversionError {
fn from(err: identity::Ed25519RecoveryError) -> Self {
MixnodeConversionError::InvalidIdentityKey(err)
}
}
impl Display for MixnodeConversionError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
MixnodeConversionError::InvalidIdentityKey(err) => write!(
f,
"failed to convert mixnode due to invalid identity key - {}",
err
),
MixnodeConversionError::InvalidSphinxKey(err) => write!(
f,
"failed to convert mixnode due to invalid sphinx key - {}",
err
),
MixnodeConversionError::InvalidAddress(address, err) => {
write!(
f,
"failed to convert mixnode due to invalid address {} - {}",
address, err
)
}
MixnodeConversionError::InvalidStake => {
write!(f, "failed to convert mixnode due to invalid stake")
}
MixnodeConversionError::Other(err) => {
write!(
f,
"failed to convert mixnode due to another error - {}",
err
)
}
}
}
}
#[derive(Debug, Clone)]
pub struct Node {
pub owner: String,
// somebody correct me if I'm wrong, but we should only ever have a single denom of currency
// on the network at a type, right?
pub stake: u128,
pub delegation: u128,
pub host: NetworkAddress,
// we're keeping this as separate resolved field since we do not want to be resolving the potential
// hostname every time we want to construct a path via this node
pub mix_host: SocketAddr,
pub identity_key: identity::PublicKey,
pub sphinx_key: encryption::PublicKey, // TODO: or nymsphinx::PublicKey? both are x25519
pub layer: Layer,
pub version: String,
}
impl filter::Versioned for Node {
fn version(&self) -> String {
self.version.clone()
}
}
impl<'a> From<&'a Node> for SphinxNode {
fn from(node: &'a Node) -> Self {
let node_address_bytes = NymNodeRoutingAddress::from(node.mix_host)
.try_into()
.unwrap();
SphinxNode::new(node_address_bytes, (&node.sphinx_key).into())
}
}
impl<'a> TryFrom<&'a MixNodeBond> for Node {
type Error = MixnodeConversionError;
fn try_from(bond: &'a MixNodeBond) -> Result<Self, Self::Error> {
let host: NetworkAddress = bond.mix_node.host.parse().map_err(|err| {
MixnodeConversionError::InvalidAddress(bond.mix_node.host.clone(), err)
})?;
// try to completely resolve the host in the mix situation to avoid doing it every
// single time we want to construct a path
let mix_host = host
.to_socket_addrs(bond.mix_node.mix_port)
.map_err(|err| {
MixnodeConversionError::InvalidAddress(bond.mix_node.host.clone(), err)
})?[0];
Ok(Node {
owner: bond.owner.as_str().to_owned(),
stake: bond.pledge_amount.amount.into(),
delegation: bond.total_delegation.amount.into(),
host,
mix_host,
identity_key: identity::PublicKey::from_base58_string(&bond.mix_node.identity_key)?,
sphinx_key: encryption::PublicKey::from_base58_string(&bond.mix_node.sphinx_key)?,
layer: bond.layer,
version: bond.mix_node.version.clone(),
})
}
}
impl TryFrom<MixNodeBond> for Node {
type Error = MixnodeConversionError;
fn try_from(bond: MixNodeBond) -> Result<Self, Self::Error> {
Node::try_from(&bond)
}
}