Skip to content

Commit

Permalink
add ecash keypair to client
Browse files Browse the repository at this point in the history
  • Loading branch information
simonwicky committed Oct 31, 2023
1 parent bb20f4f commit 0da1894
Show file tree
Hide file tree
Showing 11 changed files with 168 additions and 2 deletions.
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion clients/native/src/client/config/old_config_v1_1_20.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ use crate::client::config::old_config_v1_1_20_2::{
ClientPathsV1_1_20_2, ConfigV1_1_20_2, SocketTypeV1_1_20_2, SocketV1_1_20_2,
};
use nym_bin_common::logging::LoggingSettings;
use nym_client_core::config::disk_persistence::keys_paths::ClientKeysPaths;
use nym_client_core::config::disk_persistence::keys_paths::{self, ClientKeysPaths};
use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2;
use nym_client_core::config::old_config_v1_1_20::ConfigV1_1_20 as BaseConfigV1_1_20;
use nym_client_core::config::old_config_v1_1_20_2::{
ClientV1_1_20_2, ConfigV1_1_20_2 as BaseConfigV1_1_20_2,
};
use nym_config::defaults::DEFAULT_WEBSOCKET_LISTENING_PORT;
use nym_config::legacy_helpers::nym_config::MigrationNymConfig;
use nym_sphinx::crypto::keys;
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
use std::net::{IpAddr, Ipv4Addr};
Expand Down Expand Up @@ -65,6 +66,8 @@ impl From<ConfigV1_1_20> for ConfigV1_1_20_2 {
public_identity_key_file: value.base.client.public_identity_key_file,
private_encryption_key_file: value.base.client.private_encryption_key_file,
public_encryption_key_file: value.base.client.public_encryption_key_file,
private_ecash_key_file: PathBuf::new(),
public_ecash_key_file: PathBuf::new(),
gateway_shared_key_file: value.base.client.gateway_shared_key_file,
ack_key_file: value.base.client.ack_key_file,
},
Expand Down
2 changes: 2 additions & 0 deletions clients/socks5/src/config/old_config_v1_1_20.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ impl From<ConfigV1_1_20> for ConfigV1_1_20_2 {
public_identity_key_file: value.base.client.public_identity_key_file,
private_encryption_key_file: value.base.client.private_encryption_key_file,
public_encryption_key_file: value.base.client.public_encryption_key_file,
private_ecash_key_file: PathBuf::new(),
public_ecash_key_file: PathBuf::new(),
gateway_shared_key_file: value.base.client.gateway_shared_key_file,
ack_key_file: value.base.client.ack_key_file,
},
Expand Down
1 change: 1 addition & 0 deletions common/client-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ zeroize = { workspace = true }
nym-bandwidth-controller = { path = "../bandwidth-controller" }
nym-config = { path = "../config" }
nym-crypto = { path = "../crypto" }
nym-compact-ecash = { path = "../nym_offline_compact_ecash" }
nym-explorer-client = { path = "../../explorer-api/explorer-client" }
nym-gateway-client = { path = "../client-libs/gateway-client" }
nym-gateway-requests = { path = "../../gateway/gateway-requests" }
Expand Down
41 changes: 41 additions & 0 deletions common/client-core/src/client/key_manager/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
// SPDX-License-Identifier: Apache-2.0

use crate::client::key_manager::persistence::KeyStore;
use nym_compact_ecash::scheme::keygen::KeyPairUser;
use nym_compact_ecash::setup::GroupParameters;
use nym_compact_ecash::{generate_keypair_user, PublicKeyUser};
use nym_crypto::asymmetric::{encryption, identity};
use nym_gateway_requests::registration::handshake::SharedKeys;
use nym_sphinx::acknowledgements::AckKey;
Expand Down Expand Up @@ -87,6 +90,14 @@ impl ManagedKeys {
}
}

pub fn ecash_keypair(&self) -> Arc<KeyPairUser> {
match self {
ManagedKeys::Initial(keys) => keys.ecash_keypair(),
ManagedKeys::FullyDerived(keys) => keys.ecash_keypair(),
ManagedKeys::Invalidated => unreachable!("the managed keys got invalidated"),
}
}

pub fn ack_key(&self) -> Arc<AckKey> {
match self {
ManagedKeys::Initial(keys) => keys.ack_key(),
Expand Down Expand Up @@ -124,6 +135,14 @@ impl ManagedKeys {
}
}

pub fn ecash_public_key(&self) -> PublicKeyUser {
match self {
ManagedKeys::Initial(keys) => keys.ecash_keypair().public_key(),
ManagedKeys::FullyDerived(keys) => keys.ecash_keypair().public_key(),
ManagedKeys::Invalidated => unreachable!("the managed keys got invalidated"),
}
}

pub fn ensure_gateway_key(&self, gateway_shared_key: Option<Arc<SharedKeys>>) {
if let ManagedKeys::FullyDerived(key_manager) = &self {
if self.gateway_shared_key().is_none() && gateway_shared_key.is_none() {
Expand Down Expand Up @@ -185,6 +204,9 @@ pub struct KeyManagerBuilder {

/// key used for producing and processing acknowledgement packets.
ack_key: Arc<AckKey>,

/// key used for ecash wallet
ecash_keypair: Arc<KeyPairUser>,
}

impl KeyManagerBuilder {
Expand All @@ -197,6 +219,7 @@ impl KeyManagerBuilder {
identity_keypair: Arc::new(identity::KeyPair::new(rng)),
encryption_keypair: Arc::new(encryption::KeyPair::new(rng)),
ack_key: Arc::new(AckKey::new(rng)),
ecash_keypair: Arc::new(generate_keypair_user(&GroupParameters::new().unwrap())),
}
}

Expand All @@ -207,6 +230,7 @@ impl KeyManagerBuilder {
KeyManager {
identity_keypair: self.identity_keypair,
encryption_keypair: self.encryption_keypair,
ecash_keypair: self.ecash_keypair,
gateway_shared_key,
ack_key: self.ack_key,
}
Expand All @@ -220,6 +244,10 @@ impl KeyManagerBuilder {
Arc::clone(&self.encryption_keypair)
}

pub fn ecash_keypair(&self) -> Arc<KeyPairUser> {
Arc::clone(&self.ecash_keypair)
}

pub fn ack_key(&self) -> Arc<AckKey> {
Arc::clone(&self.ack_key)
}
Expand All @@ -240,6 +268,9 @@ pub struct KeyManager {
/// encryption key associated with the client instance.
encryption_keypair: Arc<encryption::KeyPair>,

/// ecash key associated with the client instance
ecash_keypair: Arc<KeyPairUser>,

/// shared key derived with the gateway during "registration handshake"
// I'm not a fan of how we broke the nice transition of `KeyManagerBuilder` -> `KeyManager`
// by making this field optional.
Expand All @@ -255,12 +286,14 @@ impl KeyManager {
pub fn from_keys(
id_keypair: identity::KeyPair,
enc_keypair: encryption::KeyPair,
ecash_keypair: KeyPairUser,
gateway_shared_key: Option<SharedKeys>,
ack_key: AckKey,
) -> Self {
Self {
identity_keypair: Arc::new(id_keypair),
encryption_keypair: Arc::new(enc_keypair),
ecash_keypair: Arc::new(ecash_keypair),
gateway_shared_key: gateway_shared_key.map(Arc::new),
ack_key: Arc::new(ack_key),
}
Expand All @@ -283,6 +316,12 @@ impl KeyManager {
pub fn encryption_keypair(&self) -> Arc<encryption::KeyPair> {
Arc::clone(&self.encryption_keypair)
}

/// Gets an atomically reference counted pointer to [`encryption::KeyPair`].
pub fn ecash_keypair(&self) -> Arc<KeyPairUser> {
Arc::clone(&self.ecash_keypair)
}

/// Gets an atomically reference counted pointer to [`AckKey`].
pub fn ack_key(&self) -> Arc<AckKey> {
Arc::clone(&self.ack_key)
Expand Down Expand Up @@ -310,6 +349,7 @@ impl KeyManager {
KeyManagerBuilder {
identity_keypair: self.identity_keypair,
encryption_keypair: self.encryption_keypair,
ecash_keypair: self.ecash_keypair,
ack_key: self.ack_key,
}
}
Expand All @@ -320,6 +360,7 @@ fn _assert_keys_zeroize_on_drop() {

_assert_zeroize_on_drop::<identity::KeyPair>();
_assert_zeroize_on_drop::<encryption::KeyPair>();
_assert_zeroize_on_drop::<KeyPairUser>();
_assert_zeroize_on_drop::<AckKey>();
_assert_zeroize_on_drop::<SharedKeys>();
}
11 changes: 11 additions & 0 deletions common/client-core/src/client/key_manager/persistence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

use crate::client::key_manager::KeyManager;
use async_trait::async_trait;
use nym_compact_ecash::scheme::keygen::KeyPairUser;
use std::error::Error;
use tokio::sync::Mutex;

Expand Down Expand Up @@ -104,6 +105,12 @@ impl OnDiskKeys {
self.load_keypair(identity_paths, "identity")
}

#[doc(hidden)]
pub fn load_ecash_keypair(&self) -> Result<KeyPairUser, OnDiskKeysError> {
let ecash_paths = self.paths.ecash_key_pair_path();
self.load_keypair(ecash_paths, "ecash")
}

fn load_key<T: PemStorableKey>(
&self,
path: &std::path::Path,
Expand Down Expand Up @@ -159,6 +166,7 @@ impl OnDiskKeys {
fn load_keys(&self) -> Result<KeyManager, OnDiskKeysError> {
let identity_keypair = self.load_identity_keypair()?;
let encryption_keypair = self.load_encryption_keypair()?;
let ecash_keypair = self.load_ecash_keypair()?;

let ack_key: AckKey = self.load_key(self.paths.ack_key(), "ack key")?;
let gateway_shared_key: Option<SharedKeys> = self
Expand All @@ -168,6 +176,7 @@ impl OnDiskKeys {
Ok(KeyManager::from_keys(
identity_keypair,
encryption_keypair,
ecash_keypair,
gateway_shared_key,
ack_key,
))
Expand All @@ -178,6 +187,7 @@ impl OnDiskKeys {

let identity_paths = self.paths.identity_key_pair_path();
let encryption_paths = self.paths.encryption_key_pair_path();
let ecash_paths = self.paths.ecash_key_pair_path();

self.store_keypair(
keys.identity_keypair.as_ref(),
Expand All @@ -189,6 +199,7 @@ impl OnDiskKeys {
encryption_paths,
"encryption keys",
)?;
self.store_keypair(keys.ecash_keypair.as_ref(), ecash_paths, "ecash keys")?;

self.store_key(keys.ack_key.as_ref(), self.paths.ack_key(), "ack key")?;

Expand Down
29 changes: 29 additions & 0 deletions common/client-core/src/config/disk_persistence/keys_paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ pub const DEFAULT_PRIVATE_IDENTITY_KEY_FILENAME: &str = "private_identity.pem";
pub const DEFAULT_PUBLIC_IDENTITY_KEY_FILENAME: &str = "public_identity.pem";
pub const DEFAULT_PRIVATE_ENCRYPTION_KEY_FILENAME: &str = "private_encryption.pem";
pub const DEFAULT_PUBLIC_ENCRYPTION_KEY_FILENAME: &str = "public_encryption.pem";
pub const DEFAULT_PRIVATE_ECASH_KEY_FILENAME: &str = "private_ecash.pem";
pub const DEFAULT_PUBLIC_ECASH_KEY_FILENAME: &str = "public_ecash.pem";
pub const DEFAULT_GATEWAY_SHARED_KEY_FILENAME: &str = "gateway_shared.pem";
pub const DEFAULT_ACK_KEY_FILENAME: &str = "ack_key.pem";

Expand All @@ -25,6 +27,12 @@ pub struct ClientKeysPaths {
/// Path to file containing public encryption key.
pub public_encryption_key_file: PathBuf,

/// Path to file containing private ecash key.
pub private_ecash_key_file: PathBuf,

/// Path to file containing public ecash key.
pub public_ecash_key_file: PathBuf,

/// Path to file containing shared key derived with the specified gateway that is used
/// for all communication with it.
pub gateway_shared_key_file: PathBuf,
Expand All @@ -43,6 +51,8 @@ impl ClientKeysPaths {
public_identity_key_file: base_dir.join(DEFAULT_PUBLIC_IDENTITY_KEY_FILENAME),
private_encryption_key_file: base_dir.join(DEFAULT_PRIVATE_ENCRYPTION_KEY_FILENAME),
public_encryption_key_file: base_dir.join(DEFAULT_PUBLIC_ENCRYPTION_KEY_FILENAME),
private_ecash_key_file: base_dir.join(DEFAULT_PRIVATE_ECASH_KEY_FILENAME),
public_ecash_key_file: base_dir.join(DEFAULT_PUBLIC_ECASH_KEY_FILENAME),
gateway_shared_key_file: base_dir.join(DEFAULT_GATEWAY_SHARED_KEY_FILENAME),
ack_key_file: base_dir.join(DEFAULT_ACK_KEY_FILENAME),
}
Expand All @@ -62,11 +72,20 @@ impl ClientKeysPaths {
)
}

pub fn ecash_key_pair_path(&self) -> nym_pemstore::KeyPairPath {
nym_pemstore::KeyPairPath::new(
self.private_ecash_key().to_path_buf(),
self.public_ecash_key().to_path_buf(),
)
}

pub fn any_file_exists(&self) -> bool {
matches!(self.public_identity_key_file.try_exists(), Ok(true))
|| matches!(self.private_identity_key_file.try_exists(), Ok(true))
|| matches!(self.public_encryption_key_file.try_exists(), Ok(true))
|| matches!(self.private_encryption_key_file.try_exists(), Ok(true))
|| matches!(self.public_ecash_key_file.try_exists(), Ok(true))
|| matches!(self.private_ecash_key_file.try_exists(), Ok(true))
|| matches!(self.gateway_shared_key_file.try_exists(), Ok(true))
|| matches!(self.ack_key_file.try_exists(), Ok(true))
}
Expand All @@ -76,6 +95,8 @@ impl ClientKeysPaths {
.or_else(|| file_exists(&self.private_identity_key_file))
.or_else(|| file_exists(&self.public_encryption_key_file))
.or_else(|| file_exists(&self.private_encryption_key_file))
.or_else(|| file_exists(&self.public_ecash_key_file))
.or_else(|| file_exists(&self.private_ecash_key_file))
.or_else(|| file_exists(&self.gateway_shared_key_file))
.or_else(|| file_exists(&self.ack_key_file))
}
Expand All @@ -100,6 +121,14 @@ impl ClientKeysPaths {
&self.public_encryption_key_file
}

pub fn private_ecash_key(&self) -> &Path {
&self.private_ecash_key_file
}

pub fn public_ecash_key(&self) -> &Path {
&self.public_ecash_key_file
}

pub fn gateway_shared_key(&self) -> &Path {
&self.gateway_shared_key_file
}
Expand Down
4 changes: 4 additions & 0 deletions common/nym_offline_compact_ecash/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ sha2 = "0.9"
bs58 = "0.4.0"
serde = "1.0.189"
getset = "0.1.1"
zeroize = "1.6.0"

# internal
nym-pemstore = { path = "../pemstore", version = "0.3.0" }

[dev-dependencies]
criterion = { version = "0.3", features = ["html_reports"] }
Expand Down
Loading

0 comments on commit 0da1894

Please sign in to comment.