Skip to content

Commit

Permalink
Implement de/serialization for SharedSecret
Browse files Browse the repository at this point in the history
As we do for other keys implement serde de/serialization for the
`SharedSecret`.
  • Loading branch information
tcharding committed Mar 10, 2022
1 parent 39e47fb commit 3c46b65
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 1 deletion.
88 changes: 87 additions & 1 deletion src/ecdh.rs
Expand Up @@ -15,9 +15,10 @@
//! Support for shared secret computations.
//!

use core::ptr;
use core::{ptr, str};
use core::borrow::Borrow;

use {Error, from_hex};
use key::{SecretKey, PublicKey};
use ffi::{self, CPtr};
use secp256k1_sys::types::{c_int, c_uchar, c_void};
Expand Down Expand Up @@ -71,6 +72,36 @@ impl SharedSecret {
pub fn secret_bytes(&self) -> [u8; SHARED_SECRET_SIZE] {
self.0
}

/// Creates a `SharedSecret` from `data` array.
#[inline]
pub fn from_bytes(data: [u8; SHARED_SECRET_SIZE]) -> SharedSecret {
SharedSecret(data)
}

/// Creates a `SharedSecret` from `data` slice.
#[inline]
pub fn from_slice(data: &[u8]) -> Result<SharedSecret, Error> {
match data.len() {
SHARED_SECRET_SIZE => {
let mut ret = [0u8; SHARED_SECRET_SIZE];
ret[..].copy_from_slice(data);
Ok(SharedSecret(ret))
}
_ => Err(Error::InvalidSharedSecret)
}
}
}

impl str::FromStr for SharedSecret {
type Err = Error;
fn from_str(s: &str) -> Result<SharedSecret, Error> {
let mut res = [0u8; SHARED_SECRET_SIZE];
match from_hex(s, &mut res) {
Ok(SHARED_SECRET_SIZE) => Ok(SharedSecret::from_bytes(res)),
_ => Err(Error::InvalidSharedSecret)
}
}
}

impl Borrow<[u8]> for SharedSecret {
Expand Down Expand Up @@ -140,6 +171,36 @@ unsafe extern "C" fn c_callback(output: *mut c_uchar, x: *const c_uchar, y: *con
1
}

#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
impl ::serde::Serialize for SharedSecret {
fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
if s.is_human_readable() {
let mut buf = [0u8; SHARED_SECRET_SIZE * 2];
s.serialize_str(::to_hex(&self.0, &mut buf).expect("fixed-size hex serialization"))
} else {
s.serialize_bytes(&self.as_ref()[..])
}
}
}

#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
impl<'de> ::serde::Deserialize<'de> for SharedSecret {
fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
if d.is_human_readable() {
d.deserialize_str(super::serde_util::FromStrVisitor::new(
"a hex string representing 32 byte SharedSecret"
))
} else {
d.deserialize_bytes(super::serde_util::BytesVisitor::new(
"raw 32 bytes SharedSecret",
SharedSecret::from_slice
))
}
}
}

#[cfg(test)]
#[allow(unused_imports)]
mod tests {
Expand Down Expand Up @@ -202,6 +263,31 @@ mod tests {

assert_eq!(secret_bh.as_inner(), secret_sys.as_ref());
}

#[test]
#[cfg(all(feature = "serde", any(feature = "alloc", feature = "std")))]
fn serde() {
use serde_test::{Configure, Token, assert_tokens};
static BYTES: [u8; 32] = [
1, 1, 1, 1, 1, 1, 1, 1,
0, 1, 2, 3, 4, 5, 6, 7,
0xff, 0xff, 0, 0, 0xff, 0xff, 0, 0,
99, 99, 99, 99, 99, 99, 99, 99
];
static STR: &'static str = "\
01010101010101010001020304050607ffff0000ffff00006363636363636363\
";

let secret = SharedSecret::from_slice(&BYTES).unwrap();

assert_tokens(&secret.compact(), &[Token::BorrowedBytes(&BYTES[..])]);
assert_tokens(&secret.compact(), &[Token::Bytes(&BYTES)]);
assert_tokens(&secret.compact(), &[Token::ByteBuf(&BYTES)]);

assert_tokens(&secret.readable(), &[Token::BorrowedStr(STR)]);
assert_tokens(&secret.readable(), &[Token::Str(STR)]);
assert_tokens(&secret.readable(), &[Token::String(STR)]);
}
}

#[cfg(all(test, feature = "unstable"))]
Expand Down
4 changes: 4 additions & 0 deletions src/lib.rs
Expand Up @@ -352,6 +352,8 @@ pub enum Error {
InvalidSignature,
/// Bad secret key.
InvalidSecretKey,
/// Bad shared secret.
InvalidSharedSecret,
/// Bad recovery id.
InvalidRecoveryId,
/// Invalid tweak for `add_*_assign` or `mul_*_assign`.
Expand All @@ -372,6 +374,7 @@ impl Error {
Error::InvalidPublicKey => "secp: malformed public key",
Error::InvalidSignature => "secp: malformed signature",
Error::InvalidSecretKey => "secp: malformed or out-of-range secret key",
Error::InvalidSharedSecret => "secp: malformed or out-of-range shared secret",
Error::InvalidRecoveryId => "secp: bad recovery id",
Error::InvalidTweak => "secp: bad tweak",
Error::NotEnoughMemory => "secp: not enough memory allocated",
Expand Down Expand Up @@ -399,6 +402,7 @@ impl std::error::Error for Error {
Error::InvalidPublicKey => None,
Error::InvalidSignature => None,
Error::InvalidSecretKey => None,
Error::InvalidSharedSecret => None,
Error::InvalidRecoveryId => None,
Error::InvalidTweak => None,
Error::NotEnoughMemory => None,
Expand Down

0 comments on commit 3c46b65

Please sign in to comment.