Compare commits
2 Commits
5424e66aed
...
1006fd9503
Author | SHA1 | Date |
---|---|---|
Ryan Heywood | 1006fd9503 | |
Ryan Heywood | 96e6c236f0 |
|
@ -1,26 +0,0 @@
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
|
||||||
pub enum Error {
|
|
||||||
#[error("Index is too large, must be less than 0x80000000: {0}")]
|
|
||||||
IndexTooLarge(u32),
|
|
||||||
|
|
||||||
#[error("Unable to parse integer for index")]
|
|
||||||
IntParseError(#[from] std::num::ParseIntError),
|
|
||||||
|
|
||||||
#[error("Unable to parse path due to bad path prefix")]
|
|
||||||
UnknownPathPrefix,
|
|
||||||
|
|
||||||
#[error("Seed length in bits must be divisible by 32")]
|
|
||||||
BadSeedLength(usize),
|
|
||||||
|
|
||||||
/// This should never happen. HMAC keys should be able to take any size input.
|
|
||||||
#[error("Invalid length for HMAC key while generating master key (report me!)")]
|
|
||||||
HmacInvalidLength(#[from] hmac::digest::InvalidLength),
|
|
||||||
|
|
||||||
/// There's a 1 in 2^256 chance this will happen. If it does, I'm sorry. Pick a new mnemonic.
|
|
||||||
#[error("Seed hash generated 32 bytes of zero, pick a new seed")]
|
|
||||||
HashedSeedIsZero,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Result<T, E = Error> = std::result::Result<T, E>;
|
|
|
@ -7,11 +7,14 @@ use thiserror::Error;
|
||||||
|
|
||||||
const KEY_SIZE: usize = 256;
|
const KEY_SIZE: usize = 256;
|
||||||
|
|
||||||
|
/// Errors associated with creating or deriving Extended Private Keys.
|
||||||
#[derive(Error, Clone, Debug)]
|
#[derive(Error, Clone, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
/// The seed has an unsuitable length; supported lengths are 16 bytes, 32 bytes, or 64 bytes.
|
||||||
#[error("Seed had an unsuitable length: {0}")]
|
#[error("Seed had an unsuitable length: {0}")]
|
||||||
BadSeedLength(usize),
|
BadSeedLength(usize),
|
||||||
|
|
||||||
|
/// The maximum depth for key derivation has been reached. The supported maximum depth is 255.
|
||||||
#[error("Reached maximum depth for key derivation")]
|
#[error("Reached maximum depth for key derivation")]
|
||||||
Depth,
|
Depth,
|
||||||
|
|
||||||
|
@ -19,16 +22,21 @@ pub enum Error {
|
||||||
#[error("Invalid length for HMAC key while generating master key (report me!)")]
|
#[error("Invalid length for HMAC key while generating master key (report me!)")]
|
||||||
HmacInvalidLength(#[from] hmac::digest::InvalidLength),
|
HmacInvalidLength(#[from] hmac::digest::InvalidLength),
|
||||||
|
|
||||||
|
/// An unknown error occurred while deriving a child key.
|
||||||
#[error("Unknown error while deriving child key")]
|
#[error("Unknown error while deriving child key")]
|
||||||
Derivation,
|
Derivation,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Result<T, E = Error> = std::result::Result<T, E>;
|
type Result<T, E = Error> = std::result::Result<T, E>;
|
||||||
pub type ChainCode = [u8; 32];
|
type ChainCode = [u8; 32];
|
||||||
type HmacSha512 = Hmac<Sha512>;
|
type HmacSha512 = Hmac<Sha512>;
|
||||||
|
|
||||||
|
/// Extended private keys derived using BIP-0032.
|
||||||
|
///
|
||||||
|
/// Generic over types implementing [`PrivateKey`].
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
pub struct ExtendedPrivateKey<K: PrivateKey + Clone> {
|
pub struct ExtendedPrivateKey<K: PrivateKey + Clone> {
|
||||||
|
/// The internal private key data.
|
||||||
pub private_key: K,
|
pub private_key: K,
|
||||||
depth: u8,
|
depth: u8,
|
||||||
pub(crate) chain_code: ChainCode,
|
pub(crate) chain_code: ChainCode,
|
||||||
|
@ -48,7 +56,7 @@ impl<K> ExtendedPrivateKey<K>
|
||||||
where
|
where
|
||||||
K: PrivateKey + Clone,
|
K: PrivateKey + Clone,
|
||||||
{
|
{
|
||||||
/// Generate a new [`ExtendedPublicKey`] from a seed, ideally from a 12-word or 24-word
|
/// Generate a new [`ExtendedPrivateKey`] from a seed, ideally from a 12-word or 24-word
|
||||||
/// mnemonic, but may take 16-byte seeds.
|
/// mnemonic, but may take 16-byte seeds.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
|
@ -83,6 +91,7 @@ where
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return a public key for the current [`PrivateKey`].
|
||||||
pub fn public_key(&self) -> K::PublicKey {
|
pub fn public_key(&self) -> K::PublicKey {
|
||||||
self.private_key.public_key()
|
self.private_key.public_key()
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,14 @@ use thiserror::Error;
|
||||||
|
|
||||||
const KEY_SIZE: usize = 256;
|
const KEY_SIZE: usize = 256;
|
||||||
|
|
||||||
|
/// Errors associated with creating or deriving Extended Public Keys.
|
||||||
#[derive(Error, Clone, Debug)]
|
#[derive(Error, Clone, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
/// BIP-0032 does not support deriving public keys from hardened private keys.
|
||||||
#[error("Public keys may not be derived when hardened")]
|
#[error("Public keys may not be derived when hardened")]
|
||||||
HardenedIndex,
|
HardenedIndex,
|
||||||
|
|
||||||
|
/// The maximum depth for key derivation has been reached. The supported maximum depth is 255.
|
||||||
#[error("Reached maximum depth for key derivation")]
|
#[error("Reached maximum depth for key derivation")]
|
||||||
Depth,
|
Depth,
|
||||||
|
|
||||||
|
@ -18,14 +21,18 @@ pub enum Error {
|
||||||
#[error("Invalid length for HMAC key while generating master key (report me!)")]
|
#[error("Invalid length for HMAC key while generating master key (report me!)")]
|
||||||
HmacInvalidLength(#[from] hmac::digest::InvalidLength),
|
HmacInvalidLength(#[from] hmac::digest::InvalidLength),
|
||||||
|
|
||||||
|
/// An unknown error occurred while deriving a child key.
|
||||||
#[error("Unknown error while deriving child key")]
|
#[error("Unknown error while deriving child key")]
|
||||||
Derivation,
|
Derivation,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Result<T, E = Error> = std::result::Result<T, E>;
|
type Result<T, E = Error> = std::result::Result<T, E>;
|
||||||
pub type ChainCode = [u8; 32];
|
type ChainCode = [u8; 32];
|
||||||
type HmacSha512 = Hmac<Sha512>;
|
type HmacSha512 = Hmac<Sha512>;
|
||||||
|
|
||||||
|
/// Extended public keys derived using BIP-0032.
|
||||||
|
///
|
||||||
|
/// Generic over types implementing [`PublicKey`].
|
||||||
pub struct ExtendedPublicKey<K: PublicKey> {
|
pub struct ExtendedPublicKey<K: PublicKey> {
|
||||||
public_key: K,
|
public_key: K,
|
||||||
depth: u8,
|
depth: u8,
|
||||||
|
@ -36,6 +43,8 @@ impl<K> ExtendedPublicKey<K>
|
||||||
where
|
where
|
||||||
K: PublicKey,
|
K: PublicKey,
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
/// Create a new [`ExtendedPublicKey`] from previously known values.
|
||||||
pub fn new(public_key: K, chain_code: ChainCode) -> Self {
|
pub fn new(public_key: K, chain_code: ChainCode) -> Self {
|
||||||
Self {
|
Self {
|
||||||
public_key,
|
public_key,
|
||||||
|
@ -43,6 +52,7 @@ where
|
||||||
chain_code,
|
chain_code,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
/// Derive a child with a given [`DerivationIndex`].
|
/// Derive a child with a given [`DerivationIndex`].
|
||||||
///
|
///
|
||||||
|
|
|
@ -1,6 +1,21 @@
|
||||||
use crate::error::{Error, Result};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// Errors associated with creating a [`DerivationIndex`].
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
/// The index was too large and should be less than 2^31.
|
||||||
|
#[error("Index is too large, must be less than 0x80000000: {0}")]
|
||||||
|
IndexTooLarge(u32),
|
||||||
|
|
||||||
|
/// An integer could not be parsed from the string.
|
||||||
|
#[error("Unable to parse integer for index")]
|
||||||
|
IntParseError(#[from] std::num::ParseIntError),
|
||||||
|
}
|
||||||
|
|
||||||
|
type Result<T, E = Error> = std::result::Result<T, E>;
|
||||||
|
|
||||||
|
/// Index for a given extended private key.
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct DerivationIndex(pub(crate) u32);
|
pub struct DerivationIndex(pub(crate) u32);
|
||||||
|
|
||||||
|
@ -28,6 +43,7 @@ impl DerivationIndex {
|
||||||
self.0.to_be_bytes()
|
self.0.to_be_bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether or not the index is hardened, allowing deriving the key from a known parent key.
|
||||||
pub fn is_hardened(&self) -> bool {
|
pub fn is_hardened(&self) -> bool {
|
||||||
self.0 & (0b1 << 31) != 0
|
self.0 & (0b1 << 31) != 0
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#![allow(clippy::module_name_repetitions, clippy::must_use_candidate)]
|
#![allow(clippy::module_name_repetitions, clippy::must_use_candidate)]
|
||||||
|
|
||||||
pub mod error;
|
//! BIP-0032 derivation utilities.
|
||||||
|
|
||||||
pub mod extended_key;
|
pub mod extended_key;
|
||||||
pub mod index;
|
pub mod index;
|
||||||
pub mod master_key;
|
|
||||||
pub mod path;
|
pub mod path;
|
||||||
pub mod private_key;
|
pub mod private_key;
|
||||||
pub mod public_key;
|
pub mod public_key;
|
||||||
|
@ -12,7 +12,6 @@ pub mod public_key;
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
error::{Error, Result},
|
|
||||||
extended_key::{private_key::ExtendedPrivateKey, public_key::ExtendedPublicKey},
|
extended_key::{private_key::ExtendedPrivateKey, public_key::ExtendedPublicKey},
|
||||||
index::DerivationIndex,
|
index::DerivationIndex,
|
||||||
path::DerivationPath,
|
path::DerivationPath,
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
use crate::error::{Error, Result};
|
|
||||||
|
|
||||||
use hmac::{Hmac, Mac};
|
|
||||||
use sha2::Sha512;
|
|
||||||
|
|
||||||
pub trait MasterKey<'a> {
|
|
||||||
/// Return the textual content used to derive the master key, as specified in BIP 0032 and SLIP
|
|
||||||
/// 0010. For example, a secp256k1 master key would use the textual content "Bitcoin seed", to
|
|
||||||
/// ensure compatibility with BIP 0032, despite the key being used for more functionality than
|
|
||||||
/// purely Bitcoin.
|
|
||||||
fn key() -> &'static str;
|
|
||||||
|
|
||||||
/// Some key algorithms, such as Ed25519, allow 0 as a valid private key. Those algorithhms
|
|
||||||
/// should override this method to indicate as such.
|
|
||||||
fn is_zero_valid_private_key() -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the seed used to derive the Master Key, with a size between 128 to 512 bits. Most
|
|
||||||
/// seeds should be 256 bits, the largest size available from a BIP-0039 mnemonic.
|
|
||||||
fn seed(&self) -> &'a [u8];
|
|
||||||
}
|
|
||||||
|
|
||||||
type HmacSha512 = Hmac<Sha512>;
|
|
||||||
|
|
||||||
/// Generate a Master Secret Key and Chain Code (what is this used for?).
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// An error may be returned if:
|
|
||||||
/// * The `HmacSha512` key returned by `T::key()` is invalid. This should never happen.
|
|
||||||
/// * The generated master key is all zeroes. This has a cosmically small chance of happening.
|
|
||||||
pub fn generate<'a, T: MasterKey<'a>>(generator: &T) -> Result<(Vec<u8>, Vec<u8>)> {
|
|
||||||
let seed = generator.seed();
|
|
||||||
let len = seed.len();
|
|
||||||
if len * 8 % 32 != 0 {
|
|
||||||
return Err(Error::BadSeedLength(len));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut hmac = HmacSha512::new_from_slice(&T::key().bytes().collect::<Vec<_>>())?;
|
|
||||||
hmac.update(seed);
|
|
||||||
let result = hmac.finalize().into_bytes();
|
|
||||||
let left = &result[..32];
|
|
||||||
let right = &result[32..];
|
|
||||||
if left.iter().all(|n| n == &0) {
|
|
||||||
// Wow. Impressive.
|
|
||||||
// NOTE: SLIP-0010 says to retry if this happens, but uses some weird terminology to do so.
|
|
||||||
// I do not trust it. BIP-0032 says this key is "invalid", with no instructions to retry.
|
|
||||||
// This is a low enough chance I am fine with it being freak-of-nature error.
|
|
||||||
return Err(Error::HashedSeedIsZero);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok((left.to_vec(), right.to_vec()))
|
|
||||||
}
|
|
|
@ -1,15 +1,36 @@
|
||||||
use crate::error::{Error, Result};
|
|
||||||
use crate::index::DerivationIndex;
|
use crate::index::DerivationIndex;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// Errors associated with creating a [`DerivationPath`].
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
/// A [`DerivationIndex`] was not able to be created.
|
||||||
|
#[error("Unable to create index: {0}")]
|
||||||
|
UnableToCreateIndex(#[from] super::index::Error),
|
||||||
|
|
||||||
|
/// The path could not be parsed due to a bad prefix. Paths must be in the format:
|
||||||
|
///
|
||||||
|
/// m [/ index [']]+
|
||||||
|
///
|
||||||
|
/// The prefix for the path must be `m`, and all indices must be integers between 0 and
|
||||||
|
/// 2^31.
|
||||||
|
#[error("Unable to parse path due to bad path prefix")]
|
||||||
|
UnknownPathPrefix,
|
||||||
|
}
|
||||||
|
|
||||||
|
type Result<T, E = Error> = std::result::Result<T, E>;
|
||||||
|
|
||||||
const PREFIX: &str = "m";
|
const PREFIX: &str = "m";
|
||||||
|
|
||||||
|
/// A fully qualified path to derive a key.
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
||||||
pub struct DerivationPath {
|
pub struct DerivationPath {
|
||||||
pub(crate) path: Vec<DerivationIndex>,
|
pub(crate) path: Vec<DerivationIndex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DerivationPath {
|
impl DerivationPath {
|
||||||
|
/// Returns an iterator over the [`DerivationPath`].
|
||||||
pub fn iter(&self) -> impl Iterator<Item = &DerivationIndex> {
|
pub fn iter(&self) -> impl Iterator<Item = &DerivationIndex> {
|
||||||
self.path.iter()
|
self.path.iter()
|
||||||
}
|
}
|
||||||
|
@ -24,7 +45,10 @@ impl std::str::FromStr for DerivationPath {
|
||||||
return Err(Error::UnknownPathPrefix);
|
return Err(Error::UnknownPathPrefix);
|
||||||
}
|
}
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
path: iter.map(DerivationIndex::from_str).collect::<Result<_>>()?,
|
path: iter
|
||||||
|
.map(DerivationIndex::from_str)
|
||||||
|
.map(|maybe_err| maybe_err.map_err(From::from))
|
||||||
|
.collect::<Result<Vec<DerivationIndex>>>()?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,20 +2,31 @@ use crate::PublicKey;
|
||||||
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
pub type PrivateKeyBytes = [u8; 32];
|
pub(crate) type PrivateKeyBytes = [u8; 32];
|
||||||
|
|
||||||
|
/// Functions required to use an `ExtendedPrivateKey`.
|
||||||
pub trait PrivateKey: Sized {
|
pub trait PrivateKey: Sized {
|
||||||
|
/// A type implementing [`PublicKey`] associated with Self.
|
||||||
type PublicKey: PublicKey;
|
type PublicKey: PublicKey;
|
||||||
|
|
||||||
|
/// The error returned by [`PrivateKey::derive_child()`].
|
||||||
type Err: std::error::Error;
|
type Err: std::error::Error;
|
||||||
|
|
||||||
|
/// Create a Self from bytes.
|
||||||
fn from_bytes(b: &PrivateKeyBytes) -> Self;
|
fn from_bytes(b: &PrivateKeyBytes) -> Self;
|
||||||
|
|
||||||
|
/// Convert a &Self to bytes.
|
||||||
fn to_bytes(&self) -> PrivateKeyBytes;
|
fn to_bytes(&self) -> PrivateKeyBytes;
|
||||||
|
|
||||||
|
/// Whether or not zero is a valid public key (such as with ed25519 keys).
|
||||||
fn is_zero_valid_public_key() -> bool {
|
fn is_zero_valid_public_key() -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The initial key for BIP-0032 and SLIP-0010 derivation, such as secp256k1's "Bitcoin seed".
|
||||||
fn key() -> &'static str;
|
fn key() -> &'static str;
|
||||||
|
|
||||||
|
/// Generate a [`Self::PublicKey`].
|
||||||
fn public_key(&self) -> Self::PublicKey;
|
fn public_key(&self) -> Self::PublicKey;
|
||||||
|
|
||||||
/// Derive a child [`PrivateKey`] with given `PrivateKeyBytes`.
|
/// Derive a child [`PrivateKey`] with given `PrivateKeyBytes`.
|
||||||
|
@ -28,11 +39,15 @@ pub trait PrivateKey: Sized {
|
||||||
fn derive_child(&self, other: &PrivateKeyBytes) -> Result<Self, Self::Err>;
|
fn derive_child(&self, other: &PrivateKeyBytes) -> Result<Self, Self::Err>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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)]
|
#[derive(Clone, Debug, Error)]
|
||||||
pub enum PrivateKeyError {
|
pub enum PrivateKeyError {
|
||||||
|
/// For the given algorithm, the private key must be nonzero.
|
||||||
#[error("The provided private key must be nonzero, but is not")]
|
#[error("The provided private key must be nonzero, but is not")]
|
||||||
NonZero,
|
NonZero,
|
||||||
|
|
||||||
|
/// Unable to convert a point to a key.
|
||||||
#[error("Unable to convert point to key")]
|
#[error("Unable to convert point to key")]
|
||||||
PointToKey(#[from] k256::elliptic_curve::Error),
|
PointToKey(#[from] k256::elliptic_curve::Error),
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,17 @@ use ripemd::Ripemd160;
|
||||||
use sha2::Sha256;
|
use sha2::Sha256;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
pub type PublicKeyBytes = [u8; 33];
|
pub(crate) type PublicKeyBytes = [u8; 33];
|
||||||
|
|
||||||
|
/// Functions required to use an `ExtendedPublicKey`.
|
||||||
pub trait PublicKey: Sized {
|
pub trait PublicKey: Sized {
|
||||||
|
/// The error returned by [`PublicKey::derive_child()`].
|
||||||
type Err: std::error::Error;
|
type Err: std::error::Error;
|
||||||
|
|
||||||
|
/// Create a Self from bytes.
|
||||||
fn from_bytes(b: &PublicKeyBytes) -> Self;
|
fn from_bytes(b: &PublicKeyBytes) -> Self;
|
||||||
|
|
||||||
|
/// Convert a &Self to bytse.
|
||||||
fn to_bytes(&self) -> PublicKeyBytes;
|
fn to_bytes(&self) -> PublicKeyBytes;
|
||||||
|
|
||||||
/// Derive a child [`PublicKey`] with given `PrivateKeyBytes`.
|
/// Derive a child [`PublicKey`] with given `PrivateKeyBytes`.
|
||||||
|
@ -22,6 +27,7 @@ pub trait PublicKey: Sized {
|
||||||
/// * An error specific to the given algorithm was encountered.
|
/// * An error specific to the given algorithm was encountered.
|
||||||
fn derive_child(&self, other: PrivateKeyBytes) -> Result<Self, Self::Err>;
|
fn derive_child(&self, other: PrivateKeyBytes) -> Result<Self, Self::Err>;
|
||||||
|
|
||||||
|
/// Create a BIP-0032/SLIP-0010 fingerprint from the public key.
|
||||||
fn fingerprint(&self) -> [u8; 4] {
|
fn fingerprint(&self) -> [u8; 4] {
|
||||||
let hash = Sha256::new().chain_update(self.to_bytes()).finalize();
|
let hash = Sha256::new().chain_update(self.to_bytes()).finalize();
|
||||||
let hash = Ripemd160::new().chain_update(hash).finalize();
|
let hash = Ripemd160::new().chain_update(hash).finalize();
|
||||||
|
@ -30,11 +36,15 @@ pub trait PublicKey: Sized {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Errors associated with creating and arithmetic on public keys. This specific error is only
|
||||||
|
/// intended to be used by the implementations in this crate.
|
||||||
#[derive(Clone, Debug, Error)]
|
#[derive(Clone, Debug, Error)]
|
||||||
pub enum PublicKeyError {
|
pub enum PublicKeyError {
|
||||||
|
/// For the given algorithm, the private key must be nonzero.
|
||||||
#[error("The provided public key must be nonzero, but is not")]
|
#[error("The provided public key must be nonzero, but is not")]
|
||||||
NonZero,
|
NonZero,
|
||||||
|
|
||||||
|
/// Unable to convert a point to a key.
|
||||||
#[error("Unable to convert point to key")]
|
#[error("Unable to convert point to key")]
|
||||||
PointToKey(#[from] k256::elliptic_curve::Error),
|
PointToKey(#[from] k256::elliptic_curve::Error),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue