|
16 | 16 | //! Support for shared secret computations |
17 | 17 | //! |
18 | 18 |
|
19 | | -use core::{ops, ptr}; |
| 19 | +use core::ptr; |
| 20 | +use core::ops::Deref; |
20 | 21 |
|
21 | 22 | use key::{SecretKey, PublicKey}; |
22 | 23 | use ffi::{self, CPtr}; |
23 | 24 |
|
24 | 25 | /// A tag used for recovering the public key from a compact signature |
25 | | -#[derive(Copy, Clone, PartialEq, Eq, Debug)] |
26 | | -pub struct SharedSecret(ffi::SharedSecret); |
| 26 | +#[derive(Copy, Clone)] |
| 27 | +pub struct SharedSecret { |
| 28 | + data: [u8; 256], |
| 29 | + len: usize, |
| 30 | +} |
| 31 | +impl_raw_debug!(SharedSecret); |
| 32 | + |
| 33 | + |
| 34 | +// This implementes `From<N>` for all `[u8; N]` arrays from 128bits(16 byte) to 2048bits allowing known hash lengths. |
| 35 | +// Lower than 128 bits isn't resistant to collisions any more. |
| 36 | +impl_from_array_len!(SharedSecret, 256, (16 20 28 32 48 64 96 128 256)); |
27 | 37 |
|
28 | 38 | impl SharedSecret { |
29 | | - /// Creates a new shared secret from a pubkey and secret key |
30 | | - #[inline] |
31 | | - pub fn new(point: &PublicKey, scalar: &SecretKey) -> SharedSecret { |
32 | | - unsafe { |
33 | | - let mut ss = ffi::SharedSecret::new(); |
34 | | - let res = ffi::secp256k1_ecdh( |
35 | | - ffi::secp256k1_context_no_precomp, |
36 | | - &mut ss, |
37 | | - point.as_c_ptr(), |
38 | | - scalar.as_c_ptr(), |
39 | | - ffi::secp256k1_ecdh_hash_function_default, |
40 | | - ptr::null_mut(), |
41 | | - ); |
42 | | - debug_assert_eq!(res, 1); |
43 | | - SharedSecret(ss) |
| 39 | + |
| 40 | + /// Create an empty SharedSecret |
| 41 | + pub(crate) fn empty() -> SharedSecret { |
| 42 | + SharedSecret { |
| 43 | + data: [0u8; 256], |
| 44 | + len: 0, |
44 | 45 | } |
45 | 46 | } |
46 | 47 |
|
47 | | - /// Obtains a raw pointer suitable for use with FFI functions |
48 | | - #[inline] |
49 | | - pub fn as_ptr(&self) -> *const ffi::SharedSecret { |
50 | | - &self.0 as *const _ |
| 48 | + /// Get a pointer to the underlying data with the specified capacity. |
| 49 | + pub(crate) fn get_data_mut_ptr(&mut self) -> *mut u8 { |
| 50 | + self.data.as_mut_ptr() |
51 | 51 | } |
52 | | -} |
53 | 52 |
|
54 | | -/// Creates a new shared secret from a FFI shared secret |
55 | | -impl From<ffi::SharedSecret> for SharedSecret { |
56 | | - #[inline] |
57 | | - fn from(ss: ffi::SharedSecret) -> SharedSecret { |
58 | | - SharedSecret(ss) |
| 53 | + /// Get the capacity of the underlying data buffer. |
| 54 | + pub fn capacity(&self) -> usize { |
| 55 | + self.data.len() |
59 | 56 | } |
60 | | -} |
61 | 57 |
|
| 58 | + /// Get the len of the used data. |
| 59 | + pub fn len(&self) -> usize { |
| 60 | + self.len |
| 61 | + } |
62 | 62 |
|
63 | | -impl ops::Index<usize> for SharedSecret { |
64 | | - type Output = u8; |
65 | | - |
66 | | - #[inline] |
67 | | - fn index(&self, index: usize) -> &u8 { |
68 | | - &self.0[index] |
| 63 | + /// Set the length of the object. |
| 64 | + pub(crate) fn set_len(&mut self, len: usize) { |
| 65 | + self.len = len; |
69 | 66 | } |
70 | 67 | } |
71 | 68 |
|
72 | | -impl ops::Index<ops::Range<usize>> for SharedSecret { |
73 | | - type Output = [u8]; |
74 | | - |
75 | | - #[inline] |
76 | | - fn index(&self, index: ops::Range<usize>) -> &[u8] { |
77 | | - &self.0[index] |
| 69 | +impl PartialEq for SharedSecret { |
| 70 | + fn eq(&self, other: &SharedSecret) -> bool { |
| 71 | + &self.data[..self.len] == &other.data[..other.len] |
78 | 72 | } |
79 | 73 | } |
80 | 74 |
|
81 | | -impl ops::Index<ops::RangeFrom<usize>> for SharedSecret { |
82 | | - type Output = [u8]; |
| 75 | +impl AsRef<[u8]> for SharedSecret { |
| 76 | + fn as_ref(&self) -> &[u8] { |
| 77 | + &self.data[..self.len] |
| 78 | + } |
| 79 | +} |
83 | 80 |
|
84 | | - #[inline] |
85 | | - fn index(&self, index: ops::RangeFrom<usize>) -> &[u8] { |
86 | | - &self.0[index.start..] |
| 81 | +impl Deref for SharedSecret { |
| 82 | + type Target = [u8]; |
| 83 | + fn deref(&self) -> &[u8] { |
| 84 | + &self.data[..self.len] |
87 | 85 | } |
88 | 86 | } |
89 | 87 |
|
90 | | -impl ops::Index<ops::RangeFull> for SharedSecret { |
91 | | - type Output = [u8]; |
92 | 88 |
|
| 89 | +impl SharedSecret { |
| 90 | + /// Creates a new shared secret from a pubkey and secret key |
93 | 91 | #[inline] |
94 | | - fn index(&self, _: ops::RangeFull) -> &[u8] { |
95 | | - &self.0[..] |
| 92 | + pub fn new(point: &PublicKey, scalar: &SecretKey) -> SharedSecret { |
| 93 | + let mut ss = SharedSecret::empty(); |
| 94 | + let res = unsafe { |
| 95 | + ffi::secp256k1_ecdh( |
| 96 | + ffi::secp256k1_context_no_precomp, |
| 97 | + ss.get_data_mut_ptr(), |
| 98 | + point.as_c_ptr(), |
| 99 | + scalar.as_c_ptr(), |
| 100 | + ffi::secp256k1_ecdh_hash_function_default, |
| 101 | + ptr::null_mut(), |
| 102 | + ) |
| 103 | + }; |
| 104 | + debug_assert_eq!(res, 1); // The default `secp256k1_ecdh_hash_function_default` should always return 1. |
| 105 | + ss.set_len(32); // The default hash function is SHA256, which is 32 bytes long. |
| 106 | + ss |
96 | 107 | } |
97 | 108 | } |
98 | 109 |
|
|
0 commit comments