From 2509f30c942115b8dbcd1e0ab9f82a0b835f4437 Mon Sep 17 00:00:00 2001 From: Chris O'Neil Date: Fri, 10 Jun 2022 17:14:35 +0100 Subject: [PATCH] feat!: provide hex conversion utilities Implement `from_hex` and `to_hex` functions for the `PublicKey` and `SecretKey` types. BREAKING CHANGE: the `Eq`, `Serialize` and `Deserialize` derivations are removed from the error type because the derived hex error doesn't implement these. I'm finding myself repeating this code several times in places where I'm using the BLS library, so I thought it would be useful to just have it directly on these types. --- Cargo.toml | 2 +- src/error.rs | 7 ++++--- src/lib.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ec05b08..bcd080e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ version = "5.2.0" [dependencies] ff = "0.11.0" group = "0.11.0" +hex = "0.4.3" hex_fmt = "0.3.0" pairing = "0.21.0" rand = "0.8.5" @@ -42,7 +43,6 @@ features = [ "js" ] bincode = "1.3.3" criterion = "0.3.1" eyre = "0.6.5" -hex = "0.4.3" rand_core = "0.6.3" rand_xorshift = "0.3.0" diff --git a/src/error.rs b/src/error.rs index a8f99aa..4f1117e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,10 +1,8 @@ //! Crypto errors. use thiserror::Error; -use serde::{Deserialize, Serialize}; - /// A crypto error. -#[derive(Clone, Eq, PartialEq, Debug, Error, Serialize, Deserialize)] +#[derive(Clone, PartialEq, Debug, Error)] pub enum Error { /// Not enough signature shares. #[error("Not enough shares for interpolation")] @@ -21,6 +19,9 @@ pub enum Error { /// The result of Hash To Field is zero which should never happen. #[error("Hash To Field returned zero")] HashToFieldIsZero, + /// An error converting to or from a hex representation of a key. + #[error("Failed to convert the key from hex")] + HexConversionFailed(#[from] hex::FromHexError), } /// A crypto result. diff --git a/src/lib.rs b/src/lib.rs index e406231..77e1d06 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -182,6 +182,18 @@ impl PublicKey { pub fn to_bytes(self) -> [u8; PK_SIZE] { self.0.to_compressed() } + + /// Deserialize a hex-encoded representation of a `PublicKey` to a `PublicKey` instance. + pub fn from_hex(hex: &str) -> Result { + let pk_bytes = hex::decode(hex)?; + let pk_bytes: [u8; PK_SIZE] = pk_bytes.try_into().map_err(|_| Error::InvalidBytes)?; + Self::from_bytes(pk_bytes) + } + + /// Serialize this `PublicKey` instance to a hex-encoded `String`. + pub fn to_hex(&self) -> String { + hex::encode(self.to_bytes()) + } } /// A public key share. @@ -430,6 +442,18 @@ impl SecretKey { Ok(SecretKey::from_mut(&mut fr)) } + /// Deserialize a hex-encoded representation of a `SecretKey` to a `SecretKey` instance. + pub fn from_hex(hex: &str) -> Result { + let sk_bytes = hex::decode(hex)?; + let sk_bytes: [u8; SK_SIZE] = sk_bytes.try_into().map_err(|_| Error::InvalidBytes)?; + Self::from_bytes(sk_bytes) + } + + /// Serialize this `SecretKey` instance to a hex-encoded `String`. + pub fn to_hex(&self) -> String { + hex::encode(self.to_bytes()) + } + /// Returns the decrypted text, or `None`, if the ciphertext isn't valid. pub fn decrypt(&self, ct: &Ciphertext) -> Option> { if !ct.verify() { @@ -1198,6 +1222,22 @@ mod tests { Ok(()) } + #[test] + fn test_from_to_hex() -> Result<()> { + let sk_hex = "4a353be3dac091a0a7e640620372f5e1e2e4401717c1e79cac6ffba8f6905604"; + let sk = SecretKey::from_hex(sk_hex)?; + let sk2_hex = sk.to_hex(); + let sk2 = SecretKey::from_hex(&sk2_hex)?; + assert_eq!(sk, sk2); + let pk_hex = "85695fcbc06cc4c4c9451f4dce21cbf8de3e5a13bf48f44cdbb18e203\ + 8ba7b8bb1632d7911ef1e2e08749bddbf165352"; + let pk = PublicKey::from_hex(pk_hex)?; + let pk2_hex = pk.to_hex(); + let pk2 = PublicKey::from_hex(&pk2_hex)?; + assert_eq!(pk, pk2); + Ok(()) + } + #[test] fn test_serde() -> Result<()> { let sk = SecretKey::random();