Skip to content

Commit 3c46b65

Browse files
committed
Implement de/serialization for SharedSecret
As we do for other keys implement serde de/serialization for the `SharedSecret`.
1 parent 39e47fb commit 3c46b65

File tree

2 files changed

+91
-1
lines changed

2 files changed

+91
-1
lines changed

src/ecdh.rs

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@
1515
//! Support for shared secret computations.
1616
//!
1717
18-
use core::ptr;
18+
use core::{ptr, str};
1919
use core::borrow::Borrow;
2020

21+
use {Error, from_hex};
2122
use key::{SecretKey, PublicKey};
2223
use ffi::{self, CPtr};
2324
use secp256k1_sys::types::{c_int, c_uchar, c_void};
@@ -71,6 +72,36 @@ impl SharedSecret {
7172
pub fn secret_bytes(&self) -> [u8; SHARED_SECRET_SIZE] {
7273
self.0
7374
}
75+
76+
/// Creates a `SharedSecret` from `data` array.
77+
#[inline]
78+
pub fn from_bytes(data: [u8; SHARED_SECRET_SIZE]) -> SharedSecret {
79+
SharedSecret(data)
80+
}
81+
82+
/// Creates a `SharedSecret` from `data` slice.
83+
#[inline]
84+
pub fn from_slice(data: &[u8]) -> Result<SharedSecret, Error> {
85+
match data.len() {
86+
SHARED_SECRET_SIZE => {
87+
let mut ret = [0u8; SHARED_SECRET_SIZE];
88+
ret[..].copy_from_slice(data);
89+
Ok(SharedSecret(ret))
90+
}
91+
_ => Err(Error::InvalidSharedSecret)
92+
}
93+
}
94+
}
95+
96+
impl str::FromStr for SharedSecret {
97+
type Err = Error;
98+
fn from_str(s: &str) -> Result<SharedSecret, Error> {
99+
let mut res = [0u8; SHARED_SECRET_SIZE];
100+
match from_hex(s, &mut res) {
101+
Ok(SHARED_SECRET_SIZE) => Ok(SharedSecret::from_bytes(res)),
102+
_ => Err(Error::InvalidSharedSecret)
103+
}
104+
}
74105
}
75106

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

174+
#[cfg(feature = "serde")]
175+
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
176+
impl ::serde::Serialize for SharedSecret {
177+
fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
178+
if s.is_human_readable() {
179+
let mut buf = [0u8; SHARED_SECRET_SIZE * 2];
180+
s.serialize_str(::to_hex(&self.0, &mut buf).expect("fixed-size hex serialization"))
181+
} else {
182+
s.serialize_bytes(&self.as_ref()[..])
183+
}
184+
}
185+
}
186+
187+
#[cfg(feature = "serde")]
188+
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
189+
impl<'de> ::serde::Deserialize<'de> for SharedSecret {
190+
fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
191+
if d.is_human_readable() {
192+
d.deserialize_str(super::serde_util::FromStrVisitor::new(
193+
"a hex string representing 32 byte SharedSecret"
194+
))
195+
} else {
196+
d.deserialize_bytes(super::serde_util::BytesVisitor::new(
197+
"raw 32 bytes SharedSecret",
198+
SharedSecret::from_slice
199+
))
200+
}
201+
}
202+
}
203+
143204
#[cfg(test)]
144205
#[allow(unused_imports)]
145206
mod tests {
@@ -202,6 +263,31 @@ mod tests {
202263

203264
assert_eq!(secret_bh.as_inner(), secret_sys.as_ref());
204265
}
266+
267+
#[test]
268+
#[cfg(all(feature = "serde", any(feature = "alloc", feature = "std")))]
269+
fn serde() {
270+
use serde_test::{Configure, Token, assert_tokens};
271+
static BYTES: [u8; 32] = [
272+
1, 1, 1, 1, 1, 1, 1, 1,
273+
0, 1, 2, 3, 4, 5, 6, 7,
274+
0xff, 0xff, 0, 0, 0xff, 0xff, 0, 0,
275+
99, 99, 99, 99, 99, 99, 99, 99
276+
];
277+
static STR: &'static str = "\
278+
01010101010101010001020304050607ffff0000ffff00006363636363636363\
279+
";
280+
281+
let secret = SharedSecret::from_slice(&BYTES).unwrap();
282+
283+
assert_tokens(&secret.compact(), &[Token::BorrowedBytes(&BYTES[..])]);
284+
assert_tokens(&secret.compact(), &[Token::Bytes(&BYTES)]);
285+
assert_tokens(&secret.compact(), &[Token::ByteBuf(&BYTES)]);
286+
287+
assert_tokens(&secret.readable(), &[Token::BorrowedStr(STR)]);
288+
assert_tokens(&secret.readable(), &[Token::Str(STR)]);
289+
assert_tokens(&secret.readable(), &[Token::String(STR)]);
290+
}
205291
}
206292

207293
#[cfg(all(test, feature = "unstable"))]

src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,8 @@ pub enum Error {
352352
InvalidSignature,
353353
/// Bad secret key.
354354
InvalidSecretKey,
355+
/// Bad shared secret.
356+
InvalidSharedSecret,
355357
/// Bad recovery id.
356358
InvalidRecoveryId,
357359
/// Invalid tweak for `add_*_assign` or `mul_*_assign`.
@@ -372,6 +374,7 @@ impl Error {
372374
Error::InvalidPublicKey => "secp: malformed public key",
373375
Error::InvalidSignature => "secp: malformed signature",
374376
Error::InvalidSecretKey => "secp: malformed or out-of-range secret key",
377+
Error::InvalidSharedSecret => "secp: malformed or out-of-range shared secret",
375378
Error::InvalidRecoveryId => "secp: bad recovery id",
376379
Error::InvalidTweak => "secp: bad tweak",
377380
Error::NotEnoughMemory => "secp: not enough memory allocated",
@@ -399,6 +402,7 @@ impl std::error::Error for Error {
399402
Error::InvalidPublicKey => None,
400403
Error::InvalidSignature => None,
401404
Error::InvalidSecretKey => None,
405+
Error::InvalidSharedSecret => None,
402406
Error::InvalidRecoveryId => None,
403407
Error::InvalidTweak => None,
404408
Error::NotEnoughMemory => None,

0 commit comments

Comments
 (0)