Compare commits

..

2 Commits

4 changed files with 118 additions and 5 deletions

View File

@ -0,0 +1,51 @@
# Keyfork Derive: BIP-0032 Key Derivation
Keyfork offers a [BIP-0032] based hierarchial key derivation system enabling
the ability to create keys based on a [BIP-0032] seed, a value between 128 to
512 bits. The keys can be made using any algorithm supported by Keyfork Derive.
Newtypes can be added to wrap around foreign key types that aren't supported by
Keyfork.
Keys derived with the same parameters, from the same seed, will _always_ return
the same value. This makes Keyfork a reliable backend for generating encryption
or signature keys, as every key can be recovered using the previously used
derivation algorithm. However, this may be seen as a concern, as all an
attacker may need to recreate all previously-used seeds would be the original
derivation seed. For this reason, it is recommended to use the Keyfork server
for derivation from the root seed. The Keyfork server will ensure the root seed
and any highest-level keys (such as BIP-44, BIP-85, etc.) keys are not leaked.
The primary use case of Keyfork Derive will be the creation of Derivation
Requests, to be used by Keyforkd Client. In the included example, derivation is
performed directly on a master seed. This is how Keyforkd works internally.
## Example
```rust
use std::str::FromStr;
use keyfork_mnemonic_util::Mnemonic;
use keyfork_derive_util::{*, request::*};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mnemonic = Mnemonic::from_str(
"enter settle kiwi high shift absorb protect sword talent museum lazy okay"
)?;
let path = DerivationPath::from_str("m/44'/0'/0'/0/0")?;
let request = DerivationRequest::new(
DerivationAlgorithm::Secp256k1,
&path
);
let key1 = request.derive_with_mnemonic(&mnemonic)?;
let seed = mnemonic.seed(None)?;
let key2 = request.derive_with_master_seed(seed)?;
assert_eq!(key1, key2);
Ok(())
}
```
[BIP-0032]: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki

View File

@ -1,4 +1,49 @@
//! # Extended Key Derivation
//!
//! Oftentimes, a client will want to create multiple keys. Some examples may include deriving
//! non-hardened public keys to see how many wallets have been used, deriving multiple OpenPGP
//! keys, or generally avoiding key reuse. While Keyforkd locks the root mnemonic and the
//! first-level derivation, any second-level derivations acquired from Keyforkd (for example,
//! `"m/44'/0'"`) can be used to derive further keys by converting the key to an Extended Public
//! Key or Extended Private Key and calling [`ExtendedPublicKey::derive_child`] or
//! [`ExtendedPrivateKey::derive_child`].
//!
//! # Examples
//! ```rust
//! use std::str::FromStr;
//! use keyfork_mnemonic_util::Mnemonic;
//! use keyfork_derive_util::{*, request::*};
//! use k256::SecretKey;
//!
//! # fn check_wallet<T: PublicKey>(_: ExtendedPublicKey<T>) -> Result<(), Box<dyn std::error::Error>> { Ok(()) }
//! fn main() -> Result<(), Box<dyn std::error::Error>> {
//! # let mnemonic = Mnemonic::from_str(
//! # "enter settle kiwi high shift absorb protect sword talent museum lazy okay"
//! # )?;
//! let path = DerivationPath::from_str("m/44'/0'/0'/0")?;
//! let request = DerivationRequest::new(
//! DerivationAlgorithm::Secp256k1, // The algorithm of k256::SecretKey
//! &path,
//! );
//!
//! let response = // perform a Keyforkd Client request...
//! # request.derive_with_mnemonic(&mnemonic)?;
//! let key: ExtendedPrivateKey<SecretKey> = response.try_into()?;
//! let pubkey = key.extended_public_key();
//! drop(key);
//!
//! for account in (0..20).map(|i| DerivationIndex::new(i, false).unwrap()) {
//! let derived_key = pubkey.derive_child(&account)?;
//! check_wallet(derived_key);
//! }
//!
//! Ok(())
//! }
//! ```
///
pub mod private_key;
///
pub mod public_key;
pub use {private_key::ExtendedPrivateKey, public_key::ExtendedPublicKey};

View File

@ -1,9 +1,9 @@
#![allow(clippy::module_name_repetitions, clippy::must_use_candidate)]
//! BIP-0032 derivation utilities.
#![doc = include_str!("../README.md")]
///
pub mod extended_key;
///
pub mod index;
///

View File

@ -1,6 +1,23 @@
// Because all algorithms make use of wildcard matching
#![allow(clippy::match_wildcard_for_single_variants)]
//! # Derivation Requests
//!
//! Derivation requests can be sent to Keyforkd using Keyforkd Client to request derivation from a
//! mnemonic or seed that has been loaded into Keyforkd.
//!
//! # Examples
//! ```rust
//! use std::str::FromStr;
//! use keyfork_derive_util::{DerivationPath, request::{DerivationRequest, DerivationAlgorithm}};
//!
//! let path = DerivationPath::from_str("m/44'/0'/0'/0/0").unwrap();
//! let request = DerivationRequest::new(
//! DerivationAlgorithm::Secp256k1,
//! &path
//! );
//! ```
use crate::{
extended_key::private_key::Error as XPrvError,
private_key::{PrivateKey, TestPrivateKey},
@ -31,7 +48,7 @@ pub type Result<T, E = DerivationError> = std::result::Result<T, E>;
/// The algorithm to derive a key for. The choice of algorithm will result in a different resulting
/// derivation.
#[derive(Serialize, Deserialize, Clone, Debug)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum DerivationAlgorithm {
#[allow(missing_docs)]
@ -94,7 +111,7 @@ impl std::str::FromStr for DerivationAlgorithm {
}
/// A derivation request.
#[derive(Serialize, Deserialize, Clone, Debug)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct DerivationRequest {
algorithm: DerivationAlgorithm,
path: DerivationPath,
@ -211,7 +228,7 @@ impl DerivationRequest {
}
/// A response to a [`DerivationRequest`]
#[derive(Serialize, Deserialize, Clone, Debug)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct DerivationResponse {
/// The algorithm used to derive the data.
pub algorithm: DerivationAlgorithm,