keyfork-derive-util: allow zeroable input for non-master-key derivation

This commit is contained in:
Ryan Heywood 2024-04-14 23:08:25 -04:00
parent 57354fc714
commit 1de466cad0
Signed by: ryan
GPG Key ID: 8E401478A3FBEF72
6 changed files with 55 additions and 41 deletions

View File

@ -234,7 +234,7 @@ impl Client {
} }
let depth = path.len() as u8; let depth = path.len() as u8;
Ok(ExtendedPrivateKey::new_from_parts( Ok(ExtendedPrivateKey::from_parts(
&d.data, &d.data,
depth, depth,
d.chain_code, d.chain_code,

View File

@ -124,9 +124,9 @@ mod serde_with {
K: PrivateKey + Clone, K: PrivateKey + Clone,
{ {
let variable_len_bytes = <&[u8]>::deserialize(deserializer)?; let variable_len_bytes = <&[u8]>::deserialize(deserializer)?;
let bytes: [u8; 32] = variable_len_bytes let bytes: [u8; 32] = variable_len_bytes.try_into().expect(bug!(
.try_into() "unable to parse serialized private key; no support for static len"
.expect(bug!("unable to parse serialized private key; no support for static len")); ));
Ok(K::from_bytes(&bytes)) Ok(K::from_bytes(&bytes))
} }
} }
@ -179,13 +179,20 @@ where
.into_bytes(); .into_bytes();
let (private_key, chain_code) = hash.split_at(KEY_SIZE / 8); let (private_key, chain_code) = hash.split_at(KEY_SIZE / 8);
Self::new_from_parts( assert!(
!private_key.iter().all(|byte| *byte == 0),
bug!("hmac function returned all-zero master key")
);
Self::from_parts(
private_key private_key
.try_into() .try_into()
.expect(bug!("KEY_SIZE / 8 did not give a 32 byte slice")), .expect(bug!("KEY_SIZE / 8 did not give a 32 byte slice")),
0, 0,
// Checked: chain_code is always the same length, hash is static size // Checked: chain_code is always the same length, hash is static size
chain_code.try_into().expect(bug!("Invalid chain code length")), chain_code
.try_into()
.expect(bug!("Invalid chain code length")),
) )
} }
@ -205,9 +212,9 @@ where
/// # b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; /// # b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
/// let chain_code: &[u8; 32] = // /// let chain_code: &[u8; 32] = //
/// # b"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"; /// # b"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB";
/// let xprv = ExtendedPrivateKey::<PrivateKey>::new_from_parts(key, 4, *chain_code); /// let xprv = ExtendedPrivateKey::<PrivateKey>::from_parts(key, 4, *chain_code);
/// ``` /// ```
pub fn new_from_parts(key: &[u8; 32], depth: u8, chain_code: [u8; 32]) -> Self { pub fn from_parts(key: &[u8; 32], depth: u8, chain_code: [u8; 32]) -> Self {
Self { Self {
private_key: K::from_bytes(key), private_key: K::from_bytes(key),
depth, depth,
@ -229,7 +236,7 @@ where
/// # b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; /// # b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
/// let chain_code: &[u8; 32] = // /// let chain_code: &[u8; 32] = //
/// # b"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"; /// # b"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB";
/// let xprv = ExtendedPrivateKey::<PrivateKey>::new_from_parts(key, 4, *chain_code); /// let xprv = ExtendedPrivateKey::<PrivateKey>::from_parts(key, 4, *chain_code);
/// assert_eq!(xprv.private_key(), &PrivateKey::from_bytes(key)); /// assert_eq!(xprv.private_key(), &PrivateKey::from_bytes(key));
/// ``` /// ```
pub fn private_key(&self) -> &K { pub fn private_key(&self) -> &K {
@ -262,7 +269,7 @@ where
/// # } /// # }
/// ``` /// ```
pub fn extended_public_key(&self) -> ExtendedPublicKey<K::PublicKey> { pub fn extended_public_key(&self) -> ExtendedPublicKey<K::PublicKey> {
ExtendedPublicKey::new_from_parts(self.public_key(), self.depth, self.chain_code) ExtendedPublicKey::from_parts(self.public_key(), self.depth, self.chain_code)
} }
/// Return a public key for the current [`PrivateKey`]. /// Return a public key for the current [`PrivateKey`].
@ -301,7 +308,7 @@ where
/// # b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; /// # b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
/// let chain_code: &[u8; 32] = // /// let chain_code: &[u8; 32] = //
/// # b"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"; /// # b"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB";
/// let xprv = ExtendedPrivateKey::<PrivateKey>::new_from_parts(key, 4, *chain_code); /// let xprv = ExtendedPrivateKey::<PrivateKey>::from_parts(key, 4, *chain_code);
/// assert_eq!(xprv.depth(), 4); /// assert_eq!(xprv.depth(), 4);
/// ``` /// ```
pub fn depth(&self) -> u8 { pub fn depth(&self) -> u8 {
@ -321,7 +328,7 @@ where
/// # b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; /// # b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
/// let chain_code: &[u8; 32] = // /// let chain_code: &[u8; 32] = //
/// # b"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"; /// # b"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB";
/// let xprv = ExtendedPrivateKey::<PrivateKey>::new_from_parts(key, 4, *chain_code); /// let xprv = ExtendedPrivateKey::<PrivateKey>::from_parts(key, 4, *chain_code);
/// assert_eq!(chain_code, &xprv.chain_code()); /// assert_eq!(chain_code, &xprv.chain_code());
/// ``` /// ```
pub fn chain_code(&self) -> [u8; 32] { pub fn chain_code(&self) -> [u8; 32] {

View File

@ -60,11 +60,11 @@ where
/// let chain_code: &[u8; 32] = // /// let chain_code: &[u8; 32] = //
/// # b"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"; /// # b"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB";
/// let pubkey = PublicKey::from_bytes(key); /// let pubkey = PublicKey::from_bytes(key);
/// let xpub = ExtendedPublicKey::<PublicKey>::new_from_parts(pubkey, 0, *chain_code); /// let xpub = ExtendedPublicKey::<PublicKey>::from_parts(pubkey, 0, *chain_code);
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
pub fn new_from_parts(public_key: K, depth: u8, chain_code: ChainCode) -> Self { pub fn from_parts(public_key: K, depth: u8, chain_code: ChainCode) -> Self {
Self { Self {
public_key, public_key,
depth, depth,
@ -86,7 +86,7 @@ where
/// # let chain_code: &[u8; 32] = b"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"; /// # let chain_code: &[u8; 32] = b"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB";
/// # let pubkey = PublicKey::from_bytes(key); /// # let pubkey = PublicKey::from_bytes(key);
/// let xpub = // /// let xpub = //
/// # ExtendedPublicKey::<PublicKey>::new_from_parts(pubkey, 0, *chain_code); /// # ExtendedPublicKey::<PublicKey>::from_parts(pubkey, 0, *chain_code);
/// let pubkey = xpub.public_key(); /// let pubkey = xpub.public_key();
/// # Ok(()) /// # Ok(())
/// # } /// # }
@ -121,7 +121,7 @@ where
/// # let chain_code: &[u8; 32] = b"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"; /// # let chain_code: &[u8; 32] = b"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB";
/// # let pubkey = PublicKey::from_bytes(key); /// # let pubkey = PublicKey::from_bytes(key);
/// let xpub = // /// let xpub = //
/// # ExtendedPublicKey::<PublicKey>::new_from_parts(pubkey, 0, *chain_code); /// # ExtendedPublicKey::<PublicKey>::from_parts(pubkey, 0, *chain_code);
/// let index = DerivationIndex::new(0, false)?; /// let index = DerivationIndex::new(0, false)?;
/// let child = xpub.derive_child(&index)?; /// let child = xpub.derive_child(&index)?;
/// # Ok(()) /// # Ok(())

View File

@ -102,6 +102,10 @@ pub enum PrivateKeyError {
/// For the given algorithm, the private key must be nonzero. /// 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,
/// A scalar could not be constructed for the given algorithm.
#[error("A scalar could not be constructed for the given algorithm")]
InvalidScalar,
} }
#[cfg(feature = "secp256k1")] #[cfg(feature = "secp256k1")]
@ -130,20 +134,19 @@ impl PrivateKey for k256::SecretKey {
} }
fn derive_child(&self, other: &PrivateKeyBytes) -> Result<Self, Self::Err> { fn derive_child(&self, other: &PrivateKeyBytes) -> Result<Self, Self::Err> {
if other.iter().all(|n| n == &0) { use k256::elliptic_curve::ScalarPrimitive;
return Err(PrivateKeyError::NonZero); use k256::{Scalar, Secp256k1};
}
let other = *other; // Construct a scalar from bytes
// Checked: See above nonzero check let scalar = ScalarPrimitive::<Secp256k1>::from_bytes(other.into());
let scalar = Option::<NonZeroScalar>::from(NonZeroScalar::from_repr(other.into())) let scalar = Option::<ScalarPrimitive<Secp256k1>>::from(scalar);
.expect(bug!("Should have been able to get a NonZeroScalar")); let scalar = scalar.ok_or(PrivateKeyError::InvalidScalar)?;
let scalar = Scalar::from(scalar);
let derived_scalar = self.to_nonzero_scalar().as_ref() + scalar.as_ref(); let derived_scalar = self.to_nonzero_scalar().as_ref() + scalar.as_ref();
Ok( let nonzero_scalar = Option::<NonZeroScalar>::from(NonZeroScalar::new(derived_scalar))
Option::<NonZeroScalar>::from(NonZeroScalar::new(derived_scalar)) .ok_or(PrivateKeyError::NonZero)?;
.map(Into::into) Ok(Self::from(nonzero_scalar))
.expect(bug!("Should be able to make Key")),
)
} }
} }
@ -202,9 +205,7 @@ impl PrivateKey for TestPrivateKey {
type Err = PrivateKeyError; type Err = PrivateKeyError;
fn from_bytes(b: &PrivateKeyBytes) -> Self { fn from_bytes(b: &PrivateKeyBytes) -> Self {
Self { Self { key: *b }
key: *b
}
} }
fn to_bytes(&self) -> PrivateKeyBytes { fn to_bytes(&self) -> PrivateKeyBytes {

View File

@ -77,6 +77,10 @@ pub enum PublicKeyError {
#[error("The provided public key must be nonzero, but is not")] #[error("The provided public key must be nonzero, but is not")]
NonZero, NonZero,
/// A scalar could not be constructed for the given algorithm.
#[error("A scalar could not be constructed for the given algorithm")]
InvalidScalar,
/// Public key derivation is unsupported for this algorithm. /// Public key derivation is unsupported for this algorithm.
#[error("Public key derivation is unsupported for this algorithm")] #[error("Public key derivation is unsupported for this algorithm")]
DerivationUnsupported, DerivationUnsupported,
@ -85,7 +89,7 @@ pub enum PublicKeyError {
#[cfg(feature = "secp256k1")] #[cfg(feature = "secp256k1")]
use k256::{ use k256::{
elliptic_curve::{group::prime::PrimeCurveAffine, sec1::ToEncodedPoint}, elliptic_curve::{group::prime::PrimeCurveAffine, sec1::ToEncodedPoint},
AffinePoint, NonZeroScalar, AffinePoint,
}; };
#[cfg(feature = "secp256k1")] #[cfg(feature = "secp256k1")]
@ -105,14 +109,16 @@ impl PublicKey for k256::PublicKey {
} }
fn derive_child(&self, other: PrivateKeyBytes) -> Result<Self, Self::Err> { fn derive_child(&self, other: PrivateKeyBytes) -> Result<Self, Self::Err> {
if other.iter().all(|n| n == &0) { use k256::elliptic_curve::ScalarPrimitive;
return Err(PublicKeyError::NonZero); use k256::{Secp256k1, Scalar};
}
// Checked: See above
let scalar = Option::<NonZeroScalar>::from(NonZeroScalar::from_repr(other.into()))
.expect(bug!("Should have been able to get a NonZeroScalar"));
let point = self.to_projective() + (AffinePoint::generator() * *scalar); // Construct a scalar from bytes
let scalar = ScalarPrimitive::<Secp256k1>::from_bytes(&other.into());
let scalar = Option::<ScalarPrimitive<Secp256k1>>::from(scalar);
let scalar = scalar.ok_or(PublicKeyError::InvalidScalar)?;
let scalar = Scalar::from(scalar);
let point = self.to_projective() + (AffinePoint::generator() * scalar);
Ok(Self::from_affine(point.into()) Ok(Self::from_affine(point.into())
.expect(bug!("Could not from_affine after scalar arithmetic"))) .expect(bug!("Could not from_affine after scalar arithmetic")))
} }

View File

@ -300,7 +300,7 @@ mod secp256k1 {
fn try_from(value: &DerivationResponse) -> Result<Self, Self::Error> { fn try_from(value: &DerivationResponse) -> Result<Self, Self::Error> {
match value.algorithm { match value.algorithm {
DerivationAlgorithm::Secp256k1 => Ok(Self::new_from_parts( DerivationAlgorithm::Secp256k1 => Ok(Self::from_parts(
&value.data, &value.data,
value.depth, value.depth,
value.chain_code, value.chain_code,
@ -335,7 +335,7 @@ mod ed25519 {
fn try_from(value: &DerivationResponse) -> Result<Self, Self::Error> { fn try_from(value: &DerivationResponse) -> Result<Self, Self::Error> {
match value.algorithm { match value.algorithm {
DerivationAlgorithm::Ed25519 => Ok(Self::new_from_parts( DerivationAlgorithm::Ed25519 => Ok(Self::from_parts(
&value.data, &value.data,
value.depth, value.depth,
value.chain_code, value.chain_code,