1
1
#![ no_std]
2
2
3
- use core:: array:: TryFromSliceError ;
4
3
use ed448_goldilocks:: {
5
4
MontgomeryPoint ,
6
5
elliptic_curve:: {
@@ -14,21 +13,10 @@ use zeroize::Zeroize;
14
13
15
14
type MontgomeryScalar = ed448_goldilocks:: Scalar < ed448_goldilocks:: Ed448 > ;
16
15
17
- /// Computes a Scalar according to RFC7748
18
- /// given a byte array of length 56
19
- impl From < [ u8 ; 56 ] > for Secret {
20
- fn from ( arr : [ u8 ; 56 ] ) -> Secret {
21
- let mut secret = Secret ( arr. into ( ) ) ;
22
- secret. clamp ( ) ;
23
- secret
24
- }
25
- }
26
-
27
- /// Given a Secret Key, compute the corresponding public key
16
+ /// Given an [`EphemeralSecret`] Key, compute the corresponding public key
28
17
/// using the generator specified in RFC7748
29
- /// XXX: Waiting for upstream PR to use pre-computation
30
- impl From < & Secret > for PublicKey {
31
- fn from ( secret : & Secret ) -> PublicKey {
18
+ impl From < & EphemeralSecret > for PublicKey {
19
+ fn from ( secret : & EphemeralSecret ) -> PublicKey {
32
20
let secret = secret. as_scalar ( ) ;
33
21
let point = & MontgomeryPoint :: GENERATOR * & secret;
34
22
PublicKey ( point)
@@ -39,10 +27,10 @@ impl From<&Secret> for PublicKey {
39
27
#[ derive( Debug , PartialEq , Eq , Copy , Clone ) ]
40
28
pub struct PublicKey ( MontgomeryPoint ) ;
41
29
42
- /// A Secret is a Scalar on Curve448.
30
+ /// An [`EphemeralSecret`] is a Scalar on Curve448.
43
31
#[ derive( Clone , Zeroize ) ]
44
32
#[ zeroize( drop) ]
45
- pub struct Secret ( Array < u8 , U56 > ) ;
33
+ pub struct EphemeralSecret ( Array < u8 , U56 > ) ;
46
34
47
35
/// A SharedSecret is a point on Curve448.
48
36
/// This point is the result of a Diffie-Hellman key exchange.
@@ -62,6 +50,7 @@ impl PublicKey {
62
50
}
63
51
Some ( public_key)
64
52
}
53
+
65
54
/// Converts a bytes slice into a Public key
66
55
/// Returns None if:
67
56
/// - The length of the slice is not 56
@@ -77,11 +66,6 @@ impl PublicKey {
77
66
78
67
Some ( PublicKey ( point) )
79
68
}
80
-
81
- /// Converts a public key into a byte slice
82
- pub fn as_bytes ( & self ) -> & [ u8 ; 56 ] {
83
- self . 0 . as_bytes ( )
84
- }
85
69
}
86
70
87
71
impl SharedSecret {
@@ -91,18 +75,24 @@ impl SharedSecret {
91
75
}
92
76
}
93
77
94
- impl Secret {
78
+ impl EphemeralSecret {
79
+ fn new ( value : Array < u8 , U56 > ) -> Self {
80
+ let mut out = Self ( value) ;
81
+ out. clamp ( ) ;
82
+ out
83
+ }
84
+
95
85
/// Generate a x448 `Secret` key.
96
86
// Taken from dalek-x25519
97
- pub fn new < T > ( csprng : & mut T ) -> Self
87
+ pub fn random_from_rng < T > ( csprng : & mut T ) -> Self
98
88
where
99
89
T : RngCore + CryptoRng + ?Sized ,
100
90
{
101
- let mut bytes = [ 0u8 ; 56 ] ;
91
+ let mut bytes = Array :: default ( ) ;
102
92
103
- csprng. fill_bytes ( & mut bytes) ;
93
+ csprng. fill_bytes ( bytes. as_mut_slice ( ) ) ;
104
94
105
- Secret :: from ( bytes)
95
+ Self :: new ( bytes)
106
96
}
107
97
108
98
/// Clamps the secret key according to RFC7748
@@ -111,20 +101,18 @@ impl Secret {
111
101
self . 0 [ 55 ] |= 128 ;
112
102
}
113
103
114
- /// Views a Secret as a Scalar
104
+ /// Views an Secret as a Scalar
115
105
fn as_scalar ( & self ) -> MontgomeryScalar {
116
106
let secret = U448 :: from_le_slice ( & self . 0 ) ;
117
107
MontgomeryScalar :: from_uint_unchecked ( secret)
118
108
}
119
109
120
110
/// Performs a Diffie-hellman key exchange between the secret key and an external public key
121
- pub fn as_diffie_hellman ( & self , public_key : & PublicKey ) -> Option < SharedSecret > {
122
- // Check if the point is one of the low order points
123
- if public_key. 0 . is_low_order ( ) {
124
- return None ;
125
- }
111
+ pub fn diffie_hellman ( & self , public_key : & PublicKey ) -> SharedSecret {
112
+ // NOTE(security): it is assumed PublicKey is not a low_order. It should be checked when
113
+ // created.
126
114
let shared_key = & public_key. 0 * & self . as_scalar ( ) ;
127
- Some ( SharedSecret ( shared_key) )
115
+ SharedSecret ( shared_key)
128
116
}
129
117
130
118
/// Converts a secret into a byte array
@@ -133,16 +121,6 @@ impl Secret {
133
121
}
134
122
}
135
123
136
- impl TryFrom < & [ u8 ] > for Secret {
137
- type Error = TryFromSliceError ;
138
-
139
- fn try_from ( bytes : & [ u8 ] ) -> Result < Secret , TryFromSliceError > {
140
- let mut secret = Secret ( Array :: try_from ( bytes) ?) ;
141
- secret. clamp ( ) ;
142
- Ok ( secret)
143
- }
144
- }
145
-
146
124
fn slice_to_array ( bytes : & [ u8 ] ) -> [ u8 ; 56 ] {
147
125
let mut array: [ u8 ; 56 ] = [ 0 ; 56 ] ;
148
126
array. copy_from_slice ( bytes) ;
@@ -157,14 +135,14 @@ fn slice_to_array(bytes: &[u8]) -> [u8; 56] {
157
135
/// [1]: https://github.com/rust-lang/nomicon/issues/59
158
136
pub fn x448 ( scalar_bytes : [ u8 ; 56 ] , point_bytes : [ u8 ; 56 ] ) -> Option < [ u8 ; 56 ] > {
159
137
let point = PublicKey :: from_bytes ( & point_bytes) ?;
160
- let scalar = Secret :: from ( scalar_bytes) . as_scalar ( ) ;
138
+ let scalar = EphemeralSecret :: new ( scalar_bytes. into ( ) ) . as_scalar ( ) ;
161
139
Some ( ( & point. 0 * & scalar) . 0 )
162
140
}
163
141
/// An unchecked version of the x448 function defined in RFC448
164
142
/// No checks are made on the points.
165
143
pub fn x448_unchecked ( scalar_bytes : [ u8 ; 56 ] , point_bytes : [ u8 ; 56 ] ) -> [ u8 ; 56 ] {
166
144
let point = MontgomeryPoint ( point_bytes) ;
167
- let scalar = Secret :: from ( scalar_bytes) . as_scalar ( ) ;
145
+ let scalar = EphemeralSecret :: new ( scalar_bytes. into ( ) ) . as_scalar ( ) ;
168
146
( & point * & scalar) . 0
169
147
}
170
148
@@ -176,45 +154,31 @@ mod test {
176
154
177
155
use super :: * ;
178
156
use alloc:: vec;
157
+ use core:: array:: TryFromSliceError ;
179
158
180
- #[ test]
181
- fn test_low_order ( ) {
182
- // Notice, that this is the only way to add low order points into the system
183
- // and this is not exposed to the user. The user will use `from_bytes` which will check for low order points.
184
- let bad_key_a = PublicKey ( MontgomeryPoint :: LOW_A ) ;
185
- let checked_bad_key_a = PublicKey :: from_bytes ( & MontgomeryPoint :: LOW_A . 0 ) ;
186
- assert ! ( checked_bad_key_a. is_none( ) ) ;
187
-
188
- let bad_key_b = PublicKey ( MontgomeryPoint :: LOW_B ) ;
189
- let checked_bad_key_b = PublicKey :: from_bytes ( & MontgomeryPoint :: LOW_B . 0 ) ;
190
- assert ! ( checked_bad_key_b. is_none( ) ) ;
191
-
192
- let bad_key_c = PublicKey ( MontgomeryPoint :: LOW_C ) ;
193
- let checked_bad_key_c = PublicKey :: from_bytes ( & MontgomeryPoint :: LOW_C . 0 ) ;
194
- assert ! ( checked_bad_key_c. is_none( ) ) ;
195
-
196
- let mut rng = rand:: rng ( ) ;
197
- let bob_priv = Secret :: new ( & mut rng) ;
198
-
199
- // If for some reason, these low order points are added to the system
200
- // The Diffie-Hellman key exchange for the honest party will return None.
201
- let shared_bob = bob_priv. as_diffie_hellman ( & bad_key_a) ;
202
- assert ! ( shared_bob. is_none( ) ) ;
159
+ /// Helpers to test properties of EphemeralSecret. Those `From` and `TryFrom` are not meant to
160
+ /// be exposed outside tests.
161
+ impl From < [ u8 ; 56 ] > for EphemeralSecret {
162
+ fn from ( arr : [ u8 ; 56 ] ) -> Self {
163
+ Self :: new ( arr. into ( ) )
164
+ }
165
+ }
203
166
204
- let shared_bob = bob_priv . as_diffie_hellman ( & bad_key_b ) ;
205
- assert ! ( shared_bob . is_none ( ) ) ;
167
+ impl TryFrom < & [ u8 ] > for EphemeralSecret {
168
+ type Error = TryFromSliceError ;
206
169
207
- let shared_bob = bob_priv. as_diffie_hellman ( & bad_key_c) ;
208
- assert ! ( shared_bob. is_none( ) ) ;
170
+ fn try_from ( bytes : & [ u8 ] ) -> Result < Self , TryFromSliceError > {
171
+ Ok ( Self :: new ( Array :: try_from ( bytes) ?) )
172
+ }
209
173
}
210
174
211
175
#[ test]
212
176
fn test_random_dh ( ) {
213
177
let mut rng = rand:: rng ( ) ;
214
- let alice_priv = Secret :: new ( & mut rng) ;
178
+ let alice_priv = EphemeralSecret :: random_from_rng ( & mut rng) ;
215
179
let alice_pub = PublicKey :: from ( & alice_priv) ;
216
180
217
- let bob_priv = Secret :: new ( & mut rng) ;
181
+ let bob_priv = EphemeralSecret :: random_from_rng ( & mut rng) ;
218
182
let bob_pub = PublicKey :: from ( & bob_priv) ;
219
183
220
184
// Since Alice and Bob are both using the API correctly
@@ -225,15 +189,15 @@ mod test {
225
189
226
190
// Both Alice and Bob perform the DH key exchange.
227
191
// As mentioned above, we unwrap because both Parties are using the API correctly.
228
- let shared_alice = alice_priv. as_diffie_hellman ( & bob_pub) . unwrap ( ) ;
229
- let shared_bob = bob_priv. as_diffie_hellman ( & alice_pub) . unwrap ( ) ;
192
+ let shared_alice = alice_priv. diffie_hellman ( & bob_pub) ;
193
+ let shared_bob = bob_priv. diffie_hellman ( & alice_pub) ;
230
194
231
195
assert_eq ! ( shared_alice. as_bytes( ) [ ..] , shared_bob. as_bytes( ) [ ..] ) ;
232
196
}
233
197
234
198
#[ test]
235
199
fn test_rfc_test_vectors_alice_bob ( ) {
236
- let alice_priv = Secret :: from ( [
200
+ let alice_priv = EphemeralSecret :: from ( [
237
201
0x9a , 0x8f , 0x49 , 0x25 , 0xd1 , 0x51 , 0x9f , 0x57 , 0x75 , 0xcf , 0x46 , 0xb0 , 0x4b , 0x58 ,
238
202
0x0 , 0xd4 , 0xee , 0x9e , 0xe8 , 0xba , 0xe8 , 0xbc , 0x55 , 0x65 , 0xd4 , 0x98 , 0xc2 , 0x8d ,
239
203
0xd9 , 0xc9 , 0xba , 0xf5 , 0x74 , 0xa9 , 0x41 , 0x97 , 0x44 , 0x89 , 0x73 , 0x91 , 0x0 , 0x63 ,
@@ -247,9 +211,9 @@ mod test {
247
211
0xc5 , 0xd9 , 0xbb , 0xc8 , 0x36 , 0x64 , 0x72 , 0x41 , 0xd9 , 0x53 , 0xd4 , 0xc , 0x5b , 0x12 ,
248
212
0xda , 0x88 , 0x12 , 0xd , 0x53 , 0x17 , 0x7f , 0x80 , 0xe5 , 0x32 , 0xc4 , 0x1f , 0xa0 ,
249
213
] ;
250
- assert_eq ! ( got_alice_pub. as_bytes( ) [ ..] , expected_alice_pub[ ..] ) ;
214
+ assert_eq ! ( got_alice_pub. 0 . as_bytes( ) [ ..] , expected_alice_pub[ ..] ) ;
251
215
252
- let bob_priv = Secret :: from ( [
216
+ let bob_priv = EphemeralSecret :: from ( [
253
217
0x1c , 0x30 , 0x6a , 0x7a , 0xc2 , 0xa0 , 0xe2 , 0xe0 , 0x99 , 0xb , 0x29 , 0x44 , 0x70 , 0xcb ,
254
218
0xa3 , 0x39 , 0xe6 , 0x45 , 0x37 , 0x72 , 0xb0 , 0x75 , 0x81 , 0x1d , 0x8f , 0xad , 0xd , 0x1d ,
255
219
0x69 , 0x27 , 0xc1 , 0x20 , 0xbb , 0x5e , 0xe8 , 0x97 , 0x2b , 0xd , 0x3e , 0x21 , 0x37 , 0x4c ,
@@ -263,10 +227,10 @@ mod test {
263
227
0x27 , 0xd8 , 0xb9 , 0x72 , 0xfc , 0x3e , 0x34 , 0xfb , 0x42 , 0x32 , 0xa1 , 0x3c , 0xa7 , 0x6 ,
264
228
0xdc , 0xb5 , 0x7a , 0xec , 0x3d , 0xae , 0x7 , 0xbd , 0xc1 , 0xc6 , 0x7b , 0xf3 , 0x36 , 0x9 ,
265
229
] ;
266
- assert_eq ! ( got_bob_pub. as_bytes( ) [ ..] , expected_bob_pub[ ..] ) ;
230
+ assert_eq ! ( got_bob_pub. 0 . as_bytes( ) [ ..] , expected_bob_pub[ ..] ) ;
267
231
268
- let bob_shared = bob_priv. as_diffie_hellman ( & got_alice_pub) . unwrap ( ) ;
269
- let alice_shared = alice_priv. as_diffie_hellman ( & got_bob_pub) . unwrap ( ) ;
232
+ let bob_shared = bob_priv. diffie_hellman ( & got_alice_pub) ;
233
+ let alice_shared = alice_priv. diffie_hellman ( & got_bob_pub) ;
270
234
assert_eq ! ( bob_shared. as_bytes( ) [ ..] , alice_shared. as_bytes( ) [ ..] ) ;
271
235
272
236
let expected_shared = [
@@ -338,11 +302,11 @@ mod test {
338
302
339
303
for vector in test_vectors {
340
304
let public_key = PublicKey :: from_bytes ( & vector. point ) . unwrap ( ) ;
341
- let secret = Secret :: try_from ( & vector. secret [ ..] ) . unwrap ( ) ;
305
+ let secret = EphemeralSecret :: try_from ( & vector. secret [ ..] ) . unwrap ( ) ;
342
306
343
- let got = secret. as_diffie_hellman ( & public_key) . unwrap ( ) ;
307
+ let got = secret. diffie_hellman ( & public_key) ;
344
308
345
- assert_eq ! ( got. as_bytes( ) [ ..] , vector. expected[ ..] )
309
+ assert_eq ! ( got. 0 . as_bytes( ) [ ..] , vector. expected[ ..] )
346
310
}
347
311
}
348
312
0 commit comments