1use std::ops;
20
21use super::Secp256k1;
22use key::{SecretKey, PublicKey};
23use ffi;
24
25#[derive(Copy, Clone, PartialEq, Eq, Debug)]
27#[repr(C)]
28pub struct SharedSecret(ffi::SharedSecret);
29
30impl SharedSecret {
31 #[inline]
33 pub fn new(secp: &Secp256k1, point: &PublicKey, scalar: &SecretKey) -> SharedSecret {
34 unsafe {
35 let mut ss = ffi::SharedSecret::blank();
36 let res = ffi::secp256k1_ecdh(secp.ctx, &mut ss, point.as_ptr(), scalar.as_ptr());
37 debug_assert_eq!(res, 1);
38 SharedSecret(ss)
39 }
40 }
41
42 #[inline]
44 pub fn new_raw(secp: &Secp256k1, point: &PublicKey, scalar: &SecretKey) -> SharedSecret {
45 unsafe {
46 let mut ss = ffi::SharedSecret::blank();
47 let res = ffi::secp256k1_ecdh_raw(secp.ctx, &mut ss, point.as_ptr(), scalar.as_ptr());
48 debug_assert_eq!(res, 1);
49 SharedSecret(ss)
50 }
51 }
52
53 #[inline]
55 pub fn as_ptr(&self) -> *const ffi::SharedSecret {
56 &self.0 as *const _
57 }
58}
59
60impl From<ffi::SharedSecret> for SharedSecret {
62 #[inline]
63 fn from(ss: ffi::SharedSecret) -> SharedSecret {
64 SharedSecret(ss)
65 }
66}
67
68
69impl ops::Index<usize> for SharedSecret {
70 type Output = u8;
71
72 #[inline]
73 fn index(&self, index: usize) -> &u8 {
74 &self.0[index]
75 }
76}
77
78impl ops::Index<ops::Range<usize>> for SharedSecret {
79 type Output = [u8];
80
81 #[inline]
82 fn index(&self, index: ops::Range<usize>) -> &[u8] {
83 &self.0[index]
84 }
85}
86
87impl ops::Index<ops::RangeFrom<usize>> for SharedSecret {
88 type Output = [u8];
89
90 #[inline]
91 fn index(&self, index: ops::RangeFrom<usize>) -> &[u8] {
92 &self.0[index.start..]
93 }
94}
95
96impl ops::Index<ops::RangeFull> for SharedSecret {
97 type Output = [u8];
98
99 #[inline]
100 fn index(&self, _: ops::RangeFull) -> &[u8] {
101 &self.0[..]
102 }
103}
104
105#[cfg(test)]
106mod tests {
107 use rand::thread_rng;
108 use super::SharedSecret;
109 use super::super::Secp256k1;
110
111 #[test]
112 fn ecdh() {
113 let s = Secp256k1::with_caps(::ContextFlag::SignOnly);
114 let (sk1, pk1) = s.generate_keypair(&mut thread_rng()).unwrap();
115 let (sk2, pk2) = s.generate_keypair(&mut thread_rng()).unwrap();
116
117 let sec1 = SharedSecret::new(&s, &pk1, &sk2);
118 let sec2 = SharedSecret::new(&s, &pk2, &sk1);
119 let sec_odd = SharedSecret::new(&s, &pk1, &sk1);
120 assert_eq!(sec1, sec2);
121 assert!(sec_odd != sec2);
122 }
123}
124
125#[cfg(all(test, feature = "unstable"))]
126mod benches {
127 use rand::thread_rng;
128 use test::{Bencher, black_box};
129
130 use super::SharedSecret;
131 use super::super::Secp256k1;
132
133 #[bench]
134 pub fn bench_ecdh(bh: &mut Bencher) {
135 let s = Secp256k1::with_caps(::ContextFlag::SignOnly);
136 let (sk, pk) = s.generate_keypair(&mut thread_rng()).unwrap();
137
138 let s = Secp256k1::new();
139 bh.iter( || {
140 let res = SharedSecret::new(&s, &pk, &sk);
141 black_box(res);
142 });
143 }
144}
145