Skip to content

Commit

Permalink
Add Ed25519 support (#317)
Browse files Browse the repository at this point in the history
* temporarily switch tofn/protos to forks supporting ed25519

* add ed25519 support

* switch dependant repos back
  • Loading branch information
eranrund authored Oct 17, 2023
1 parent 7da5025 commit 7c8a2ec
Show file tree
Hide file tree
Showing 10 changed files with 514 additions and 157 deletions.
377 changes: 295 additions & 82 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ chacha20poly1305 = { version = "0.9", features = ["alloc"], default-features = f
rand = {version = "0.8", default-features = false }

rpassword = { version = "5.0", default-features = false }
scrypt = { version = "0.8", default-features = false, features = ["std"] }
scrypt = { version = "0.11", default-features = false, features = ["std"] }

# tonic dependencies
prost = {version = "0.9", default-features = false}
Expand Down
2 changes: 1 addition & 1 deletion proto
Submodule proto updated 2 files
+6 −0 common.proto
+4 −2 multisig.proto
11 changes: 9 additions & 2 deletions src/multisig/key_presence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,23 @@ use super::service::MultisigService;
use tracing::debug;

// error handling
use crate::{proto, TofndResult};
use crate::{
proto::{self, Algorithm},
TofndResult,
};
use anyhow::anyhow;

impl MultisigService {
pub(super) async fn handle_key_presence(
&self,
request: proto::KeyPresenceRequest,
) -> TofndResult<proto::key_presence_response::Response> {
// check if mnemonic is available
let algorithm = Algorithm::from_i32(request.algorithm)
.ok_or(anyhow!("Invalid algorithm: {}", request.algorithm))?;

let _ = self
.find_matching_seed(&request.key_uid, &request.pub_key)
.find_matching_seed(&request.key_uid, &request.pub_key, algorithm)
.await?;

// key presence for multisig always returns `Present`.
Expand Down
19 changes: 11 additions & 8 deletions src/multisig/keygen.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
use super::service::MultisigService;
use crate::{proto::KeygenRequest, TofndResult};
use tofn::ecdsa::keygen;

use super::{keypair::KeyPair, service::MultisigService};
use crate::{
proto::{Algorithm, KeygenRequest},
TofndResult,
};
use anyhow::anyhow;

impl MultisigService {
pub(super) async fn handle_keygen(&self, request: &KeygenRequest) -> TofndResult<Vec<u8>> {
let algorithm = Algorithm::from_i32(request.algorithm)
.ok_or(anyhow!("Invalid algorithm: {}", request.algorithm))?;
let secret_recovery_key = self.kv_manager.seed().await?;

let key_pair = keygen(&secret_recovery_key, request.key_uid.as_bytes())
.map_err(|_| anyhow!("Cannot generate keypair"))?;

Ok(key_pair.encoded_verifying_key().to_vec())
Ok(
KeyPair::generate(&secret_recovery_key, request.key_uid.as_bytes(), algorithm)?
.encoded_verifying_key(),
)
}
}
52 changes: 52 additions & 0 deletions src/multisig/keypair.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use crate::{proto::Algorithm, TofndResult};
use anyhow::anyhow;
use tofn::{
ecdsa, ed25519,
multisig::{keygen::SecretRecoveryKey, sign::MessageDigest},
};

pub enum KeyPair {
Ecdsa(ecdsa::KeyPair),
Ed25519(ed25519::KeyPair),
}

impl KeyPair {
pub fn generate(
secret_recovery_key: &SecretRecoveryKey,
session_nonce: &[u8],
algorithm: Algorithm,
) -> TofndResult<Self> {
Ok(match algorithm {
Algorithm::Ecdsa => {
let key_pair = ecdsa::keygen(&secret_recovery_key, session_nonce)
.map_err(|_| anyhow!("Cannot generate keypair"))?;

Self::Ecdsa(key_pair)
}

Algorithm::Ed25519 => {
let key_pair = ed25519::keygen(&secret_recovery_key, session_nonce)
.map_err(|_| anyhow!("Cannot generate keypair"))?;

Self::Ed25519(key_pair)
}
})
}

pub fn encoded_verifying_key(&self) -> Vec<u8> {
match self {
Self::Ecdsa(key_pair) => key_pair.encoded_verifying_key().to_vec(),
Self::Ed25519(key_pair) => key_pair.encoded_verifying_key().to_vec(),
}
}

pub fn sign(&self, msg_to_sign: &MessageDigest) -> TofndResult<Vec<u8>> {
match self {
Self::Ecdsa(key_pair) => ecdsa::sign(key_pair.signing_key(), msg_to_sign)
.map_err(|_| anyhow!("signing failed")),
Self::Ed25519(key_pair) => {
ed25519::sign(key_pair, msg_to_sign).map_err(|_| anyhow!("signing failed"))
}
}
}
}
1 change: 1 addition & 0 deletions src/multisig/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod key_presence;
mod keygen;
mod keypair;
pub mod service;
mod sign;

Expand Down
36 changes: 19 additions & 17 deletions src/multisig/sign.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
use super::service::MultisigService;
use crate::{proto::SignRequest, TofndResult};
use std::convert::TryInto;

use anyhow::anyhow;
use tofn::{
ecdsa::{keygen, sign},
multisig::keygen::SecretRecoveryKey,
use super::{keypair::KeyPair, service::MultisigService};
use crate::{
proto::{Algorithm, SignRequest},
TofndResult,
};
use anyhow::anyhow;
use std::convert::TryInto;
use tofn::multisig::keygen::SecretRecoveryKey;

impl MultisigService {
pub(super) async fn handle_sign(&self, request: &SignRequest) -> TofndResult<Vec<u8>> {
// re-generate secret key from seed, then sign
let algorithm = Algorithm::from_i32(request.algorithm)
.ok_or(anyhow!("Invalid algorithm: {}", request.algorithm))?;

let secret_recovery_key = self
.find_matching_seed(&request.key_uid, &request.pub_key)
.find_matching_seed(&request.key_uid, &request.pub_key, algorithm)
.await?;

let key_pair = keygen(&secret_recovery_key, request.key_uid.as_bytes())
.map_err(|_| anyhow!("key re-generation failed"))?;
let key_pair =
KeyPair::generate(&secret_recovery_key, request.key_uid.as_bytes(), algorithm)
.map_err(|_| anyhow!("key re-generation failed"))?;

let signature = sign(
key_pair.signing_key(),
&request.msg_to_sign.as_slice().try_into()?,
)
.map_err(|_| anyhow!("sign failed"))?;
let signature = key_pair
.sign(&request.msg_to_sign.as_slice().try_into()?)
.map_err(|_| anyhow!("sign failed"))?;

Ok(signature)
}
Expand All @@ -33,6 +34,7 @@ impl MultisigService {
&self,
key_uid: &str,
pub_key: &[u8],
algorithm: Algorithm,
) -> TofndResult<SecretRecoveryKey> {
if pub_key.is_empty() {
return self
Expand All @@ -51,7 +53,7 @@ impl MultisigService {
for seed_key in seed_key_iter {
let secret_recovery_key = self.kv_manager.get_seed(&seed_key).await?;

let key_pair = keygen(&secret_recovery_key, key_uid.as_bytes())
let key_pair = KeyPair::generate(&secret_recovery_key, key_uid.as_bytes(), algorithm)
.map_err(|_| anyhow!("key re-generation failed"))?;

if pub_key == key_pair.encoded_verifying_key() {
Expand Down
Loading

0 comments on commit 7c8a2ec

Please sign in to comment.