diff --git a/src/bip340.rs b/src/bip340.rs index b136278..914a7a9 100644 --- a/src/bip340.rs +++ b/src/bip340.rs @@ -28,7 +28,11 @@ use secp256k1::{Keypair, Message, SecretKey, XOnlyPublicKey, SECP256K1}; use crate::{Algo, Chain, InvalidPubkey, InvalidSig, SsiPub, SsiSig}; #[derive(Clone, Eq, PartialEq, From)] -pub struct Bip340Secret(pub(crate) SecretKey); +pub struct Bip340Secret { + chain: Chain, + algo: Algo, + key: SecretKey, +} impl Ord for Bip340Secret { fn cmp(&self, other: &Self) -> Ordering { self.0.secret_bytes().cmp(&other.0.secret_bytes()) } @@ -42,33 +46,21 @@ impl Hash for Bip340Secret { fn hash(&self, state: &mut H) { self.0.secret_bytes().hash(state) } } -impl From for [u8; 32] { - fn from(ssi: Bip340Secret) -> Self { ssi.0.secret_bytes() } -} - -impl From<[u8; 32]> for Bip340Secret { - fn from(value: [u8; 32]) -> Self { - Self(SecretKey::from_slice(&value).expect("invalid secret key")) - } -} - impl Bip340Secret { pub fn new(chain: Chain) -> Self { use rand::thread_rng; - loop { - let sk = SecretKey::new(&mut thread_rng()); - let (pk, _) = sk.x_only_public_key(SECP256K1); - let data = pk.serialize(); - if data[30] == u8::from(Algo::Bip340) && data[31] == u8::from(chain) { - return Self(sk); - } + let key = SecretKey::new(&mut thread_rng()); + Self { + chain, + algo: Algo::Bip340, + key, } } - pub fn to_public(&self) -> SsiPub { - let (pk, _) = self.0.x_only_public_key(SECP256K1); + pub fn to_public(&self, chain: Chain, algo: Algo) -> SsiPub { + let (pk, _) = self.key.x_only_public_key(SECP256K1); let data = pk.serialize(); - SsiPub::from(data) + SsiPub::with(chain, algo, data) } pub fn sign(&self, msg: [u8; 32]) -> SsiSig { diff --git a/src/ed25519.rs b/src/ed25519.rs index b7185e6..fb5a4c0 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -23,15 +23,19 @@ use std::cmp::Ordering; use std::hash::{Hash, Hasher}; use std::ops::Deref; -use ec25519::{KeyPair, Noise, PublicKey, SecretKey, Seed, Signature}; +use ec25519::{KeyPair, PublicKey, SecretKey, Seed, Signature}; use crate::{Algo, Chain, InvalidPubkey, InvalidSig, SsiPub, SsiSig}; #[derive(Clone, Eq, PartialEq, From)] -pub struct Ed25519Secret(pub(crate) SecretKey); +pub struct Ed25519Secret { + chain: Chain, + algo: Algo, + key: SecretKey, +} impl Ord for Ed25519Secret { - fn cmp(&self, other: &Self) -> Ordering { self.0.as_slice().cmp(other.0.as_slice()) } + fn cmp(&self, other: &Self) -> Ordering { self.serialize().cmp(other.serialize()) } } impl PartialOrd for Ed25519Secret { @@ -39,43 +43,43 @@ impl PartialOrd for Ed25519Secret { } impl Hash for Ed25519Secret { - fn hash(&self, state: &mut H) { self.0.as_slice().hash(state) } -} - -impl From for [u8; 64] { - fn from(ssi: Ed25519Secret) -> Self { *ssi.0.deref() } -} - -impl From<[u8; 64]> for Ed25519Secret { - fn from(value: [u8; 64]) -> Self { - Self(SecretKey::from_slice(&value).expect("invalid secret key")) - } + fn hash(&self, state: &mut H) { self.serialize().hash(state) } } impl Ed25519Secret { pub fn new(chain: Chain) -> Self { - loop { - let pair = KeyPair::from_seed(Seed::generate()); - let pk = pair.pk; + let pair = KeyPair::from_seed(Seed::generate()); - if pk[30] != u8::from(Algo::Ed25519) || pk[31] != u8::from(chain) { - continue; - } + Self { + chain, + algo: Algo::Ed25519, + key: pair.sk, + } + } - let sig = pair.sk.sign("test", Some(Noise::generate())); - pk.verify("test", &sig).expect("unable to create key"); + pub fn serialize(&self) -> [u8; 34] { + let mut bytes = [0u8; 34]; + bytes[0] = self.algo.to_u8(); + bytes[1] = self.chain.to_u8(); + bytes[2..].copy_from_slice(self.key.as_slice()); + bytes + } - return Self(pair.sk); + pub fn deserialize(bytes: &[u8; 34]) -> Self { + Self { + chain: bytes[0].try_into()?, + algo: bytes[1].try_into()?, + key: SecretKey::, } } pub fn to_public(&self) -> SsiPub { - let pk = self.0.public_key(); + let pk = self.key.public_key(); SsiPub::from(*pk) } pub fn sign(&self, msg: [u8; 32]) -> SsiSig { - let sig = self.0.sign(msg, None); + let sig = self.key.sign(msg, None); SsiSig::from(*sig) } } diff --git a/src/public.rs b/src/public.rs index aefd243..c2d3fcc 100644 --- a/src/public.rs +++ b/src/public.rs @@ -187,35 +187,49 @@ impl Chain { pub struct SsiPub { chain: Chain, algo: Algo, - key: Bytes<30>, + key: Bytes32, } -impl DisplayBaid64 for SsiPub { +impl DisplayBaid64<34> for SsiPub { const HRI: &'static str = "ssi"; const CHUNKING: bool = true; const PREFIX: bool = true; const EMBED_CHECKSUM: bool = false; const MNEMONIC: bool = false; - fn to_baid64_payload(&self) -> [u8; 32] { <[u8; 32]>::from(*self) } + fn to_baid64_payload(&self) -> [u8; 34] { <[u8; 34]>::from(*self) } } -impl FromBaid64Str for SsiPub {} +impl FromBaid64Str<34> for SsiPub {} -impl From for [u8; 32] { - fn from(ssi: SsiPub) -> Self { ssi.to_byte_array() } +impl From for [u8; 34] { + fn from(ssi: SsiPub) -> Self { + let mut bytes = [0u8; 34]; + bytes[0] = ssi.algo.to_u8(); + bytes[1] = ssi.chain.to_u8(); + bytes[2..].copy_from_slice(&ssi.to_byte_array()); + bytes + } } -impl From<[u8; 32]> for SsiPub { - fn from(value: [u8; 32]) -> Self { - let key = Bytes::from_slice_unsafe(&value[0..30]); - let algo = Algo::from(value[30]); - let chain = Chain::from(value[31]); +impl From<[u8; 34]> for SsiPub { + fn from(value: [u8; 34]) -> Self { + let algo = Algo::from(value[0]); + let chain = Chain::from(value[1]); + let key = Bytes::from_slice_unsafe(&value[2..]); Self { algo, key, chain } } } impl SsiPub { + pub fn with(chain: Chain, algo: Algo, key: impl Into<[u8; 32]>) -> Self { + Self { + chain, + algo, + key: Bytes32::from(key.into()), + } + } + pub fn verify_text(self, text: &str, sig: SsiSig) -> Result<(), InvalidSig> { let msg = Sha256::digest(text); let digest = Sha256::digest(msg); @@ -234,11 +248,11 @@ impl SsiPub { Fingerprint([self.key[0], self.key[1], self.key[2], self.key[3], self.key[4], self.key[5]]) } - pub fn to_byte_array(&self) -> [u8; 32] { - let mut buf = [0u8; 32]; - buf[0..30].copy_from_slice(self.key.as_slice()); - buf[30] = self.algo.into(); - buf[31] = self.chain.into(); + pub fn to_byte_array(&self) -> [u8; 34] { + let mut buf = [0u8; 34]; + buf[0] = self.algo.into(); + buf[1] = self.chain.into(); + buf[2..32].copy_from_slice(self.key.as_slice()); buf } } diff --git a/src/secret.rs b/src/secret.rs index 3a16fcd..76097e9 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -61,6 +61,7 @@ pub struct EncryptedSecret { pub fp: Fingerprint, pub nonce: Nonce, pub algo: Algo, + pub chain: Chain, pub key: Vec, } @@ -68,7 +69,9 @@ impl EncryptedSecret { pub fn reveal(&self, passwd: impl AsRef) -> Result { let sk = decrypt(&self.key, self.nonce, passwd.as_ref())?; match self.algo { - Algo::Ed25519 => Ok(ec25519::SecretKey::from_slice(&sk)?.into()), + Algo::Ed25519 => { + Ok(Ed25519Secret::with(self.chain, ec25519::SecretKey::from_slice(&sk)?).into()) + } Algo::Bip340 => Ok(secp256k1::SecretKey::from_slice(&sk)?.into()), Algo::Other(algo) => Err(RevealError::Unsupported(algo)), } @@ -148,10 +151,8 @@ impl Display for EncryptedSecret { #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, From)] pub enum SsiSecret { #[from] - #[from(secp256k1::SecretKey)] Bip340(Bip340Secret), #[from] - #[from(ec25519::SecretKey)] Ed25519(Ed25519Secret), }