132 lines
3.7 KiB
Rust
132 lines
3.7 KiB
Rust
use crate::PublicKey;
|
|
|
|
use thiserror::Error;
|
|
|
|
pub(crate) type PrivateKeyBytes = [u8; 32];
|
|
|
|
/// Functions required to use an `ExtendedPrivateKey`.
|
|
pub trait PrivateKey: Sized {
|
|
/// A type implementing [`PublicKey`] associated with Self.
|
|
type PublicKey: PublicKey;
|
|
|
|
/// The error returned by [`PrivateKey::derive_child()`].
|
|
type Err: std::error::Error;
|
|
|
|
/// Create a Self from bytes.
|
|
fn from_bytes(b: &PrivateKeyBytes) -> Self;
|
|
|
|
/// Convert a &Self to bytes.
|
|
fn to_bytes(&self) -> PrivateKeyBytes;
|
|
|
|
/*
|
|
* Freak of nature, unsupported?
|
|
/// Whether or not zero is a valid public key (such as with ed25519 keys).
|
|
fn is_zero_valid_public_key() -> bool {
|
|
false
|
|
}
|
|
*/
|
|
|
|
/// The initial key for BIP-0032 and SLIP-0010 derivation, such as secp256k1's "Bitcoin seed".
|
|
fn key() -> &'static str;
|
|
|
|
/// Generate a [`Self::PublicKey`].
|
|
fn public_key(&self) -> Self::PublicKey;
|
|
|
|
/// Derive a child [`PrivateKey`] with given `PrivateKeyBytes`.
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// An error may be returned if:
|
|
/// * A nonzero `other` is provided.
|
|
/// * An error specific to the given algorithm was encountered.
|
|
fn derive_child(&self, other: &PrivateKeyBytes) -> Result<Self, Self::Err>;
|
|
|
|
/// Whether the algorithm requires hardened derivation, such as for ed25519.
|
|
fn requires_hardened_derivation() -> bool {
|
|
false
|
|
}
|
|
}
|
|
|
|
/// Errors associated with creating and arithmetic on private keys. This specific error is only
|
|
/// intended to be used by the implementations in this crate.
|
|
#[derive(Clone, Debug, Error)]
|
|
pub enum PrivateKeyError {
|
|
/// For the given algorithm, the private key must be nonzero.
|
|
#[error("The provided private key must be nonzero, but is not")]
|
|
NonZero,
|
|
}
|
|
|
|
#[cfg(feature = "secp256k1")]
|
|
use k256::NonZeroScalar;
|
|
|
|
#[cfg(feature = "secp256k1")]
|
|
impl PrivateKey for k256::SecretKey {
|
|
type Err = PrivateKeyError;
|
|
type PublicKey = k256::PublicKey;
|
|
|
|
fn key() -> &'static str {
|
|
"Bitcoin seed"
|
|
}
|
|
|
|
fn from_bytes(b: &PrivateKeyBytes) -> Self {
|
|
Self::from_slice(b).expect("Invalid private key bytes")
|
|
}
|
|
|
|
fn to_bytes(&self) -> PrivateKeyBytes {
|
|
// Note: Safety assured by type returned from EncodedPoint
|
|
self.to_bytes().into()
|
|
}
|
|
|
|
fn public_key(&self) -> Self::PublicKey {
|
|
self.public_key()
|
|
}
|
|
|
|
fn derive_child(&self, other: &PrivateKeyBytes) -> Result<Self, Self::Err> {
|
|
if other.iter().all(|n| n == &0) {
|
|
return Err(PrivateKeyError::NonZero);
|
|
}
|
|
let other = *other;
|
|
// Checked: See above nonzero check
|
|
let scalar = Option::<NonZeroScalar>::from(NonZeroScalar::from_repr(other.into()))
|
|
.expect("Should have been able to get a NonZeroScalar");
|
|
|
|
let derived_scalar = self.to_nonzero_scalar().as_ref() + scalar.as_ref();
|
|
Ok(
|
|
Option::<NonZeroScalar>::from(NonZeroScalar::new(derived_scalar))
|
|
.map(Into::into)
|
|
.expect("Should be able to make Key"),
|
|
)
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "ed25519")]
|
|
impl PrivateKey for ed25519_dalek::SigningKey {
|
|
type Err = PrivateKeyError;
|
|
type PublicKey = ed25519_dalek::VerifyingKey;
|
|
|
|
fn key() -> &'static str {
|
|
"ed25519 seed"
|
|
}
|
|
|
|
fn from_bytes(b: &PrivateKeyBytes) -> Self {
|
|
Self::from_bytes(b)
|
|
}
|
|
|
|
fn to_bytes(&self) -> PrivateKeyBytes {
|
|
self.to_bytes()
|
|
}
|
|
|
|
fn public_key(&self) -> Self::PublicKey {
|
|
self.verifying_key()
|
|
}
|
|
|
|
fn derive_child(&self, other: &PrivateKeyBytes) -> Result<Self, Self::Err> {
|
|
// SLIP-0010: No arithmetic required for ed25519 keys.
|
|
Ok(Self::from_bytes(other))
|
|
}
|
|
|
|
fn requires_hardened_derivation() -> bool {
|
|
true
|
|
}
|
|
}
|