#![forbid(unsafe_code)]
extern crate num_bigint_dig as num_bigint;
mod rsa;
pub use crate::rsa::*;
mod ec;
pub use ec::*;
mod bitcoin;
pub use bitcoin::*;
mod password;
pub use password::*;
mod integer;
pub use integer::*;
mod secret;
pub use secret::*;
mod bytes;
pub use bytes::*;
mod prime;
pub use prime::*;
mod tool_state;
pub use tool_state::*;
#[cfg(test)]
mod tests;
#[macro_use]
#[allow(unused_imports)]
pub mod prelude {
pub use crate::Derivable as _;
pub use crate::Ecc as _;
pub use crate::ExtractBitcoinV1 as _;
pub use crate::ExtractBytes as _;
pub use crate::ExtractInteger as _;
pub use crate::ExtractPassword as _;
pub use crate::ExtractPrimeV1 as _;
pub use crate::ExtractRsaV1 as _;
pub use crate::MutateWith as _;
pub use crate::SubsecretFrom as _;
pub use crate::ToolState as _;
}
#[doc(hidden)]
#[macro_use]
#[allow(unused_imports)]
pub(crate) mod prelude_internal {
pub use crate::Derivable;
pub use crate::Ecc;
pub use crate::ExtractBitcoinV1;
pub use crate::ExtractBytes;
pub use crate::ExtractInteger;
pub use crate::ExtractPassword;
pub use crate::ExtractPrimeV1;
pub use crate::ExtractRsaV1;
pub use crate::MutateWith;
pub use crate::Result;
pub use crate::Secret;
pub use crate::SecretId;
pub use crate::SubsecretFrom;
pub use crate::ToolState;
pub use ::anyhow::{bail, ensure, format_err, Error};
pub use ::digest::Digest;
pub use ::hkdf::Hkdf;
pub use ::ripemd::Ripemd160;
pub use ::sha2::Sha256;
pub use ::std::fmt::Debug;
pub use ::std::fmt::{Display, Formatter};
pub use ::std::path::Path;
pub use hex_literal::hex;
}
use crate::prelude_internal::*;
pub type Result<T = (), E = Error> = std::result::Result<T, E>;
pub trait Derivable:
MutateWith
+ SubsecretFrom
+ ExtractBytes
+ ExtractInteger
+ ExtractBitcoinV1
+ Ecc
+ ExtractPassword
+ ExtractPrimeV1
+ ExtractRsaV1
+ Clone
+ Debug
{
fn bytes(&self) -> Result<[u8; 32]>;
fn id(&self) -> SecretId;
}
#[derive(Default, Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct SecretId(pub(crate) [u8; SecretId::LEN]);
impl SecretId {
const LEN: usize = 16;
pub fn as_slice(&self) -> &[u8] {
&self.0
}
pub fn as_bytes(&self) -> &[u8; SecretId::LEN] {
&self.0
}
pub fn into_bytes(self) -> [u8; SecretId::LEN] {
self.0
}
#[allow(clippy::inherent_to_string_shadow_display)]
pub fn to_string(&self) -> String {
bs58::encode(&self.0).into_string()
}
}
impl Display for SecretId {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.to_string())
}
}
impl From<[u8; SecretId::LEN]> for SecretId {
fn from(value: [u8; SecretId::LEN]) -> Self {
SecretId(value)
}
}
pub trait MutateWith {
fn mutate_with_salt(&mut self, salt: &[u8]) -> Result;
fn mutate_with_label(&mut self, label: &str) -> Result {
self.mutate_with_salt(label.as_bytes())
}
fn mutate_with_path(&mut self, path: &str) -> Result {
for label in path.split('/').filter(|w| !w.is_empty()) {
let (label, count) = if let Some((label, count_str)) = label.split_once('@') {
if count_str.is_empty() {
bail!("Missing count after '@'");
}
(label, count_str.parse::<u32>()?)
} else {
(label, 1)
};
if count == 0 {
bail!("Zero label count");
}
for _ in 0..count {
self.mutate_with_label(label)?;
}
}
Ok(())
}
}
impl MutateWith for Secret {
fn mutate_with_salt(&mut self, salt: &[u8]) -> Result {
let salt = if salt.is_empty() { None } else { Some(salt) };
self.0 = Hkdf::<Sha256>::extract(salt, self.as_bytes()).0.into();
Ok(())
}
}
pub trait SubsecretFrom: Sized {
fn subsecret_from_salt(&self, salt: &[u8]) -> Result<Self>;
fn subsecret_from_label(&self, label: &str) -> Result<Self>;
fn subsecret_from_path(&self, path: &str) -> Result<Self>;
}
impl SubsecretFrom for Secret {
fn subsecret_from_salt(&self, salt: &[u8]) -> Result<Secret> {
let mut ret = self.clone();
ret.mutate_with_salt(salt)?;
Ok(ret)
}
fn subsecret_from_label(&self, label: &str) -> Result<Secret> {
let mut ret = self.clone();
ret.mutate_with_label(label)?;
Ok(ret)
}
fn subsecret_from_path(&self, path: &str) -> Result<Secret> {
let mut ret = self.clone();
ret.mutate_with_path(path)?;
Ok(ret)
}
}