|
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