Compare commits

..

No commits in common. "de6d8e4b565317fa6a11d3cb70c2195cb5fe179e" and "0119e58d2d6f7583c2d6f4722a5a1f60560a0658" have entirely different histories.

13 changed files with 3649 additions and 93 deletions

12
Cargo.lock generated
View File

@ -865,8 +865,9 @@ name = "keyfork"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"clap", "clap",
"keyfork-derive-key",
"keyfork-entropy", "keyfork-entropy",
"keyfork-mnemonic-util", "keyfork-mnemonic-from-seed",
"smex", "smex",
"thiserror", "thiserror",
] ]
@ -875,10 +876,17 @@ dependencies = [
name = "keyfork-derive-key" name = "keyfork-derive-key"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bincode",
"clap",
"ed25519-dalek",
"keyfork-derive-util", "keyfork-derive-util",
"keyfork-frame",
"keyfork-slip10-test-data",
"keyforkd",
"keyforkd-client", "keyforkd-client",
"smex", "tempdir",
"thiserror", "thiserror",
"tokio",
] ]
[[package]] [[package]]

View File

@ -6,7 +6,16 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
bincode = { version = "1.3.3", default-features = false }
clap = { version = "4.4.2", default-features = false, features = ["std", "usage", "help", "derive"] }
keyfork-derive-util = { version = "0.1.0", path = "../keyfork-derive-util" } keyfork-derive-util = { version = "0.1.0", path = "../keyfork-derive-util" }
keyfork-frame = { version = "0.1.0", path = "../keyfork-frame", default-features = false }
keyforkd-client = { version = "0.1.0", path = "../keyforkd-client" } keyforkd-client = { version = "0.1.0", path = "../keyforkd-client" }
smex = { version = "0.1.0", path = "../smex" }
thiserror = "1.0.48" thiserror = "1.0.48"
[dev-dependencies]
ed25519-dalek = "2.0.0"
keyfork-slip10-test-data = { path = "../keyfork-slip10-test-data" }
keyforkd = { path = "../keyforkd", default-features = false }
tempdir = "0.3.7"
tokio = { version = "1.32.0", features = ["rt", "rt-multi-thread"] }

View File

@ -0,0 +1,23 @@
use clap::Parser;
use keyfork_derive_util::{
request::{DerivationAlgorithm, DerivationRequest, DerivationResponse},
DerivationPath,
};
use keyforkd_client::{Client, Result};
#[derive(Parser, Clone, Debug)]
pub struct Command {
#[arg(long)]
pub path: DerivationPath,
#[arg(long)]
pub algorithm: DerivationAlgorithm,
}
impl Command {
pub fn handle(&self) -> Result<DerivationResponse> {
let mut client = Client::discover_socket()?;
let request = DerivationRequest::new(self.algorithm.clone(), &self.path);
client.request(&request)
}
}

View File

@ -0,0 +1,15 @@
pub mod cli;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("The first argument to the command should be a derivation path")]
Args,
#[error("The given path was incorrectly formatted: {0}")]
ArgsFormat(#[from] keyfork_derive_util::path::Error),
#[error("Unable to perform key derivation request: {0}")]
KeyforkdClient(#[from] keyforkd_client::Error),
}
pub type Result<T, E = Error> = std::result::Result<T, E>;

View File

@ -1,44 +1,10 @@
use std::{env, str::FromStr}; use clap::Parser;
use keyfork_derive_util::{ #[allow(clippy::wildcard_imports)]
request::{DerivationAlgorithm, DerivationError, DerivationRequest}, use keyfork_derive_key::*;
DerivationPath,
};
use keyforkd_client::Client;
#[derive(Debug, thiserror::Error)] fn main() -> Result<()> {
pub enum Error { let args = cli::Command::parse();
#[error("Could not parse the given algorithm {0:?}: {1}")] args.handle()?;
AlgoFormat(String, DerivationError),
#[error("Could not parse the given path: {0}")]
PathFormat(#[from] keyfork_derive_util::path::Error),
#[error("Unable to perform key derivation request: {0}")]
KeyforkdClient(#[from] keyforkd_client::Error),
}
pub type Result<T, E = Error> = std::result::Result<T, E>;
fn validate(algo: &str, path: &str) -> Result<(DerivationAlgorithm, DerivationPath)> {
let algo =
DerivationAlgorithm::from_str(algo).map_err(|e| Error::AlgoFormat(algo.to_string(), e))?;
let path = DerivationPath::from_str(path)?;
Ok((algo, path))
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut args = env::args();
let program_name = args.next().expect("program name");
let args = args.collect::<Vec<_>>();
let (algo, path) = match args.as_slice() {
[algo, path] => validate(algo, path)?,
_ => panic!("Usage: {program_name} algorithm path"),
};
let mut client = Client::discover_socket()?;
let request = DerivationRequest::new(algo, &path);
let response = client.request(&request)?;
println!("{}", smex::encode(&response.data));
Ok(()) Ok(())
} }

View File

@ -1,11 +1,24 @@
use std::{env, str::FromStr}; use std::{
env,
str::FromStr,
time::{Duration, SystemTime},
};
use ed25519_dalek::SigningKey;
use keyfork_derive_util::{ use keyfork_derive_util::{
request::{DerivationAlgorithm, DerivationRequest}, request::{DerivationAlgorithm, DerivationRequest},
DerivationIndex, DerivationPath, DerivationIndex, DerivationPath, ExtendedPrivateKey, PrivateKey,
}; };
use keyforkd_client::Client; use keyforkd_client::Client;
use sequoia_openpgp::{packet::UserID, types::KeyFlags}; use sequoia_openpgp::{
packet::{
key::{Key4, PrimaryRole, SubordinateRole},
signature::SignatureBuilder,
Key, UserID,
},
types::{KeyFlags, SignatureType},
Cert, Packet,
};
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
enum Error { enum Error {
@ -108,10 +121,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let request = DerivationRequest::new(DerivationAlgorithm::Ed25519, &path); let request = DerivationRequest::new(DerivationAlgorithm::Ed25519, &path);
let derived_data = Client::discover_socket()?.request(&request)?; let derived_data = Client::discover_socket()?.request(&request)?;
let subkeys = subkey_format let subkeys = subkey_format.iter().map(|kt| kt.inner().clone()).collect::<Vec<_>>();
.iter()
.map(|kt| kt.inner().clone())
.collect::<Vec<_>>();
let cert = keyfork_derive_openpgp::derive(derived_data, subkeys.as_slice(), default_userid)?; let cert = keyfork_derive_openpgp::derive(derived_data, subkeys.as_slice(), default_userid)?;

View File

@ -0,0 +1,49 @@
use keyfork_mnemonic_util::{Mnemonic, MnemonicGenerationError, Wordlist};
pub fn generate_mnemonic(entropy: &[u8]) -> Result<Mnemonic, MnemonicGenerationError> {
let wordlist = Wordlist::default().arc();
Mnemonic::from_entropy(entropy, wordlist)
}
#[cfg(test)]
mod tests {
use keyfork_mnemonic_util::{Mnemonic, Wordlist};
use std::{collections::HashSet, io::Read};
#[test]
fn count_to_get_duplicate_words() {
let tests = 100_000;
let mut count = 0.;
let entropy = &mut [0u8; 256 / 8];
let wordlist = Wordlist::default().arc();
let mut random = std::fs::File::open("/dev/urandom").unwrap();
let mut hs = HashSet::<usize>::with_capacity(24);
for _ in 0..tests {
random.read_exact(&mut entropy[..]).unwrap();
let mnemonic = Mnemonic::from_entropy(&entropy[..256 / 8], wordlist.clone()).unwrap();
let (words, _) = mnemonic.into_inner();
hs.clear();
hs.extend(words);
if hs.len() != 24 {
count += 1.;
}
}
// NOTE: Birthday problem math is: 0.126532
// Set values to (about) 1 below, 1 above
// Source: https://en.wikipedia.org/wiki/Birthday_problem
let min = 11.5;
let max = 13.5;
assert!(
count > f64::from(tests) * min / 100.,
"{count} probability should be more than {min}%: {}",
count / f64::from(tests)
);
assert!(
count < f64::from(tests) * max / 100.,
"{count} probability should be more than {max}%: {}",
count / f64::from(tests)
);
}
}

View File

@ -1,4 +1,5 @@
use keyfork_mnemonic_util::Mnemonic; #[allow(clippy::wildcard_imports)]
use keyfork_mnemonic_from_seed::*;
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
let input = std::io::stdin(); let input = std::io::stdin();
@ -6,7 +7,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
input.read_line(&mut line)?; input.read_line(&mut line)?;
let decoded = smex::decode(line.trim())?; let decoded = smex::decode(line.trim())?;
let mnemonic = Mnemonic::from_entropy(&decoded, Default::default())?; let mnemonic = generate_mnemonic(&decoded)?;
println!("{mnemonic}"); println!("{mnemonic}");

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -225,7 +225,7 @@ impl Mnemonic {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::{collections::HashSet, fs::File, io::Read}; use std::{fs::File, io::Read};
use super::*; use super::*;
@ -278,41 +278,4 @@ mod tests {
let their_mnemonic = bip39::Mnemonic::from_entropy(&entropy[..256 / 8]).unwrap(); let their_mnemonic = bip39::Mnemonic::from_entropy(&entropy[..256 / 8]).unwrap();
assert_eq!(my_mnemonic.to_string(), their_mnemonic.to_string()); assert_eq!(my_mnemonic.to_string(), their_mnemonic.to_string());
} }
#[test]
fn count_to_get_duplicate_words() {
let tests = 100_000;
let mut count = 0.;
let entropy = &mut [0u8; 256 / 8];
let wordlist = Wordlist::default().arc();
let mut random = std::fs::File::open("/dev/urandom").unwrap();
let mut hs = HashSet::<usize>::with_capacity(24);
for _ in 0..tests {
random.read_exact(&mut entropy[..]).unwrap();
let mnemonic = Mnemonic::from_entropy(&entropy[..256 / 8], wordlist.clone()).unwrap();
let (words, _) = mnemonic.into_inner();
hs.clear();
hs.extend(words);
if hs.len() != 24 {
count += 1.;
}
}
// NOTE: Birthday problem math is: 0.126532
// Set values to (about) 1 below, 1 above
// Source: https://en.wikipedia.org/wiki/Birthday_problem
let min = 11.5;
let max = 13.5;
assert!(
count > f64::from(tests) * min / 100.,
"{count} probability should be more than {min}%: {}",
count / f64::from(tests)
);
assert!(
count < f64::from(tests) * max / 100.,
"{count} probability should be more than {max}%: {}",
count / f64::from(tests)
);
}
} }

View File

@ -6,8 +6,9 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
keyfork-entropy = { version = "0.1.0", path = "../keyfork-entropy" }
keyfork-mnemonic-util = { version = "0.1.0", path = "../keyfork-mnemonic-util" }
clap = { version = "4.4.2", features = ["derive", "env"] } clap = { version = "4.4.2", features = ["derive", "env"] }
keyfork-mnemonic-from-seed = { version = "0.1.0", path = "../keyfork-mnemonic-from-seed" }
keyfork-derive-key = { version = "0.1.0", path = "../keyfork-derive-key" }
thiserror = "1.0.48" thiserror = "1.0.48"
smex = { version = "0.1.0", path = "../smex" } smex = { version = "0.1.0", path = "../smex" }
keyfork-entropy = { version = "0.1.0", path = "../keyfork-entropy" }

View File

@ -96,7 +96,7 @@ impl MnemonicSeedSource {
MnemonicSeedSource::Tarot => todo!(), MnemonicSeedSource::Tarot => todo!(),
MnemonicSeedSource::Dice => todo!(), MnemonicSeedSource::Dice => todo!(),
}; };
let mnemonic = keyfork_mnemonic_util::Mnemonic::from_entropy(&seed, Default::default())?; let mnemonic = keyfork_mnemonic_from_seed::generate_mnemonic(&seed)?;
Ok(mnemonic.to_string()) Ok(mnemonic.to_string())
} }
} }