]> git.lizzy.rs Git - PAKEs.git/blob - src/spake2.rs
67c2acce0d49375c92602ad867b64b302fbe469a
[PAKEs.git] / src / spake2.rs
1 #![allow(dead_code)]
2
3 use curve25519_dalek::constants::ED25519_BASEPOINT_POINT;
4 use curve25519_dalek::edwards::CompressedEdwardsY;
5 use curve25519_dalek::edwards::EdwardsPoint as c2_Element;
6 use curve25519_dalek::scalar::Scalar as c2_Scalar;
7 use hex;
8 use hkdf::Hkdf;
9 use num_bigint::BigUint;
10 use rand::{CryptoRng, OsRng, Rng};
11 use sha2::{Digest, Sha256};
12 use std::fmt;
13 use std::ops::Deref;
14
15 //use hex::ToHex;
16
17 /* "newtype pattern": it's a Vec<u8>, but only used for a specific argument
18  * type, to distinguish between ones that are meant as passwords, and ones
19  * that are meant as identity strings */
20
21 #[derive(PartialEq, Eq, Clone)]
22 pub struct Password(Vec<u8>);
23 impl Password {
24     pub fn new(p: &[u8]) -> Password {
25         Password(p.to_vec())
26     }
27 }
28 impl Deref for Password {
29     type Target = Vec<u8>;
30     fn deref(&self) -> &Vec<u8> {
31         &self.0
32     }
33 }
34
35 #[derive(PartialEq, Eq, Clone)]
36 pub struct Identity(Vec<u8>);
37 impl Deref for Identity {
38     type Target = Vec<u8>;
39     fn deref(&self) -> &Vec<u8> {
40         &self.0
41     }
42 }
43 impl Identity {
44     pub fn new(p: &[u8]) -> Identity {
45         Identity(p.to_vec())
46     }
47 }
48
49 #[derive(Debug, PartialEq, Eq)]
50 pub enum ErrorType {
51     BadSide,
52     WrongLength,
53     CorruptMessage,
54 }
55
56 #[derive(Debug, PartialEq, Eq)]
57 pub struct SPAKEErr {
58     pub kind: ErrorType,
59 }
60
61 pub trait Group {
62     type Scalar;
63     type Element;
64     //type Element: Add<Output=Self::Element>
65     //    + Mul<Self::Scalar, Output=Self::Element>;
66     // const element_length: usize; // in unstable, or u8
67     //type ElementBytes : Index<usize, Output=u8>+IndexMut<usize>; // later
68     type TranscriptHash;
69     fn const_m() -> Self::Element;
70     fn const_n() -> Self::Element;
71     fn const_s() -> Self::Element;
72     fn hash_to_scalar(s: &[u8]) -> Self::Scalar;
73     fn random_scalar<T>(cspring: &mut T) -> Self::Scalar
74     where
75         T: Rng + CryptoRng;
76     fn scalar_neg(s: &Self::Scalar) -> Self::Scalar;
77     fn element_to_bytes(e: &Self::Element) -> Vec<u8>;
78     fn bytes_to_element(b: &[u8]) -> Option<Self::Element>;
79     fn element_length() -> usize;
80     fn basepoint_mult(s: &Self::Scalar) -> Self::Element;
81     fn scalarmult(e: &Self::Element, s: &Self::Scalar) -> Self::Element;
82     fn add(a: &Self::Element, b: &Self::Element) -> Self::Element;
83 }
84
85 #[derive(Debug, PartialEq, Eq)]
86 pub struct Ed25519Group;
87
88 impl Group for Ed25519Group {
89     type Scalar = c2_Scalar;
90     type Element = c2_Element;
91     //type ElementBytes = Vec<u8>;
92     //type ElementBytes = [u8; 32];
93     //type ScalarBytes
94     type TranscriptHash = Sha256;
95
96     fn const_m() -> c2_Element {
97         // python -c "import binascii, spake2; b=binascii.hexlify(spake2.ParamsEd25519.M.to_bytes()); print(', '.join(['0x'+b[i:i+2] for i in range(0,len(b),2)]))"
98         // 15cfd18e385952982b6a8f8c7854963b58e34388c8e6dae891db756481a02312
99         CompressedEdwardsY([
100             0x15, 0xcf, 0xd1, 0x8e, 0x38, 0x59, 0x52, 0x98, 0x2b, 0x6a, 0x8f, 0x8c, 0x78, 0x54,
101             0x96, 0x3b, 0x58, 0xe3, 0x43, 0x88, 0xc8, 0xe6, 0xda, 0xe8, 0x91, 0xdb, 0x75, 0x64,
102             0x81, 0xa0, 0x23, 0x12,
103         ]).decompress()
104             .unwrap()
105     }
106
107     fn const_n() -> c2_Element {
108         // python -c "import binascii, spake2; b=binascii.hexlify(spake2.ParamsEd25519.N.to_bytes()); print(', '.join(['0x'+b[i:i+2] for i in range(0,len(b),2)]))"
109         // f04f2e7eb734b2a8f8b472eaf9c3c632576ac64aea650b496a8a20ff00e583c3
110         CompressedEdwardsY([
111             0xf0, 0x4f, 0x2e, 0x7e, 0xb7, 0x34, 0xb2, 0xa8, 0xf8, 0xb4, 0x72, 0xea, 0xf9, 0xc3,
112             0xc6, 0x32, 0x57, 0x6a, 0xc6, 0x4a, 0xea, 0x65, 0x0b, 0x49, 0x6a, 0x8a, 0x20, 0xff,
113             0x00, 0xe5, 0x83, 0xc3,
114         ]).decompress()
115             .unwrap()
116     }
117
118     fn const_s() -> c2_Element {
119         // python -c "import binascii, spake2; b=binascii.hexlify(spake2.ParamsEd25519.S.to_bytes()); print(', '.join(['0x'+b[i:i+2] for i in range(0,len(b),2)]))"
120         // 6f00dae87c1be1a73b5922ef431cd8f57879569c222d22b1cd71e8546ab8e6f1
121         CompressedEdwardsY([
122             0x6f, 0x00, 0xda, 0xe8, 0x7c, 0x1b, 0xe1, 0xa7, 0x3b, 0x59, 0x22, 0xef, 0x43, 0x1c,
123             0xd8, 0xf5, 0x78, 0x79, 0x56, 0x9c, 0x22, 0x2d, 0x22, 0xb1, 0xcd, 0x71, 0xe8, 0x54,
124             0x6a, 0xb8, 0xe6, 0xf1,
125         ]).decompress()
126             .unwrap()
127     }
128
129     fn hash_to_scalar(s: &[u8]) -> c2_Scalar {
130         ed25519_hash_to_scalar(s)
131     }
132     fn random_scalar<T>(cspring: &mut T) -> c2_Scalar
133     where
134         T: Rng + CryptoRng,
135     {
136         c2_Scalar::random(cspring)
137     }
138     fn scalar_neg(s: &c2_Scalar) -> c2_Scalar {
139         -s
140     }
141     fn element_to_bytes(s: &c2_Element) -> Vec<u8> {
142         s.compress().as_bytes().to_vec()
143     }
144     fn element_length() -> usize {
145         32
146     }
147     fn bytes_to_element(b: &[u8]) -> Option<c2_Element> {
148         if b.len() != 32 {
149             return None;
150         }
151         //let mut bytes: [u8; 32] =
152         let mut bytes = [0u8; 32];
153         bytes.copy_from_slice(b);
154         let cey = CompressedEdwardsY(bytes);
155         // CompressedEdwardsY::new(b)
156         cey.decompress()
157     }
158
159     fn basepoint_mult(s: &c2_Scalar) -> c2_Element {
160         //c2_Element::basepoint_mult(s)
161         ED25519_BASEPOINT_POINT * s
162     }
163     fn scalarmult(e: &c2_Element, s: &c2_Scalar) -> c2_Element {
164         e * s
165         //e.scalar_mult(s)
166     }
167     fn add(a: &c2_Element, b: &c2_Element) -> c2_Element {
168         a + b
169         //a.add(b)
170     }
171 }
172
173 fn decimal_to_scalar(d: &[u8]) -> c2_Scalar {
174     let bytes = BigUint::parse_bytes(d, 10).unwrap().to_bytes_le();
175     assert_eq!(bytes.len(), 32);
176     let mut b2 = [0u8; 32];
177     b2.copy_from_slice(&bytes);
178     c2_Scalar::from_bytes_mod_order(b2)
179 }
180
181 fn ed25519_hash_to_scalar(s: &[u8]) -> c2_Scalar {
182     //c2_Scalar::hash_from_bytes::<Sha512>(&s)
183     // spake2.py does:
184     //  h = HKDF(salt=b"", ikm=s, hash=SHA256, info=b"SPAKE2 pw", len=32+16)
185     //  i = int(h, 16)
186     //  i % q
187
188     let mut okm = [0u8; 32+16];
189     Hkdf::<Sha256>::extract(Some(b""), s).expand(b"SPAKE2 pw", &mut okm).unwrap();
190     //println!("expanded:   {}{}", "................................", okm.iter().to_hex()); // ok
191
192     let mut reducible = [0u8; 64]; // little-endian
193     for (i, x) in okm.iter().enumerate().take(32 + 16) {
194         reducible[32 + 16 - 1 - i] = *x;
195     }
196     //println!("reducible:  {}", reducible.iter().to_hex());
197     c2_Scalar::from_bytes_mod_order_wide(&reducible)
198     //let reduced = c2_Scalar::reduce(&reducible);
199     //println!("reduced:    {}", reduced.as_bytes().to_hex());
200     //println!("done");
201     //reduced
202 }
203
204 fn ed25519_hash_ab(
205     password_vec: &[u8],
206     id_a: &[u8],
207     id_b: &[u8],
208     first_msg: &[u8],
209     second_msg: &[u8],
210     key_bytes: &[u8],
211 ) -> Vec<u8> {
212     assert_eq!(first_msg.len(), 32);
213     assert_eq!(second_msg.len(), 32);
214     // the transcript is fixed-length, made up of 6 32-byte values:
215     // byte 0-31   : sha256(pw)
216     // byte 32-63  : sha256(idA)
217     // byte 64-95  : sha256(idB)
218     // byte 96-127 : X_msg
219     // byte 128-159: Y_msg
220     // byte 160-191: K_bytes
221     let mut transcript = [0u8; 6 * 32];
222
223     let mut pw_hash = Sha256::new();
224     pw_hash.input(password_vec);
225     transcript[0..32].copy_from_slice(&pw_hash.result());
226
227     let mut ida_hash = Sha256::new();
228     ida_hash.input(id_a);
229     transcript[32..64].copy_from_slice(&ida_hash.result());
230
231     let mut idb_hash = Sha256::new();
232     idb_hash.input(id_b);
233     transcript[64..96].copy_from_slice(&idb_hash.result());
234
235     transcript[96..128].copy_from_slice(first_msg);
236     transcript[128..160].copy_from_slice(second_msg);
237     transcript[160..192].copy_from_slice(key_bytes);
238
239     //println!("transcript: {:?}", transcript.iter().to_hex());
240
241     //let mut hash = G::TranscriptHash::default();
242     let mut hash = Sha256::new();
243     hash.input(&transcript);
244     hash.result().to_vec()
245 }
246
247 fn ed25519_hash_symmetric(
248     password_vec: &[u8],
249     id_s: &[u8],
250     msg_u: &[u8],
251     msg_v: &[u8],
252     key_bytes: &[u8],
253 ) -> Vec<u8> {
254     assert_eq!(msg_u.len(), 32);
255     assert_eq!(msg_v.len(), 32);
256     // # since we don't know which side is which, we must sort the messages
257     // first_msg, second_msg = sorted([msg1, msg2])
258     // transcript = b"".join([sha256(pw).digest(),
259     //                        sha256(idSymmetric).digest(),
260     //                        first_msg, second_msg, K_bytes])
261
262     // the transcript is fixed-length, made up of 5 32-byte values:
263     // byte 0-31   : sha256(pw)
264     // byte 32-63  : sha256(idSymmetric)
265     // byte 64-95  : X_msg
266     // byte 96-127 : Y_msg
267     // byte 128-159: K_bytes
268     let mut transcript = [0u8; 5 * 32];
269
270     let mut pw_hash = Sha256::new();
271     pw_hash.input(password_vec);
272     transcript[0..32].copy_from_slice(&pw_hash.result());
273
274     let mut ids_hash = Sha256::new();
275     ids_hash.input(id_s);
276     transcript[32..64].copy_from_slice(&ids_hash.result());
277
278     if msg_u < msg_v {
279         transcript[64..96].copy_from_slice(msg_u);
280         transcript[96..128].copy_from_slice(msg_v);
281     } else {
282         transcript[64..96].copy_from_slice(msg_v);
283         transcript[96..128].copy_from_slice(msg_u);
284     }
285     transcript[128..160].copy_from_slice(key_bytes);
286
287     let mut hash = Sha256::new();
288     hash.input(&transcript);
289     hash.result().to_vec()
290 }
291
292 /* "session type pattern" */
293
294 #[derive(Debug, PartialEq, Eq)]
295 enum Side {
296     A,
297     B,
298     Symmetric,
299 }
300
301 // we implement a custom Debug below, to avoid revealing secrets in a dump
302 #[derive(PartialEq, Eq)]
303 pub struct SPAKE2<G: Group> {
304     //where &G::Scalar: Neg {
305     side: Side,
306     xy_scalar: G::Scalar,
307     password_vec: Vec<u8>,
308     id_a: Vec<u8>,
309     id_b: Vec<u8>,
310     id_s: Vec<u8>,
311     msg1: Vec<u8>,
312     password_scalar: G::Scalar,
313 }
314
315 impl<G: Group> SPAKE2<G> {
316     fn start_internal(
317         side: Side,
318         password: &Password,
319         id_a: &Identity,
320         id_b: &Identity,
321         id_s: &Identity,
322         xy_scalar: G::Scalar,
323     ) -> (SPAKE2<G>, Vec<u8>) {
324         //let password_scalar: G::Scalar = hash_to_scalar::<G::Scalar>(password);
325         let password_scalar: G::Scalar = G::hash_to_scalar(&password);
326
327         // a: X = B*x + M*pw
328         // b: Y = B*y + N*pw
329         // sym: X = B*x * S*pw
330         let blinding = match side {
331             Side::A => G::const_m(),
332             Side::B => G::const_n(),
333             Side::Symmetric => G::const_s(),
334         };
335         let m1: G::Element = G::add(
336             &G::basepoint_mult(&xy_scalar),
337             &G::scalarmult(&blinding, &password_scalar),
338         );
339         //let m1: G::Element = &G::basepoint_mult(&x) + &(blinding * &password_scalar);
340         let msg1: Vec<u8> = G::element_to_bytes(&m1);
341         let mut password_vec = Vec::new();
342         password_vec.extend_from_slice(&password);
343         let mut id_a_copy = Vec::new();
344         id_a_copy.extend_from_slice(&id_a);
345         let mut id_b_copy = Vec::new();
346         id_b_copy.extend_from_slice(&id_b);
347         let mut id_s_copy = Vec::new();
348         id_s_copy.extend_from_slice(&id_s);
349
350         let mut msg_and_side = Vec::new();
351         msg_and_side.push(match side {
352             Side::A => 0x41,         // 'A'
353             Side::B => 0x42,         // 'B'
354             Side::Symmetric => 0x53, // 'S'
355         });
356         msg_and_side.extend_from_slice(&msg1);
357
358         (
359             SPAKE2 {
360                 side,
361                 xy_scalar,
362                 password_vec, // string
363                 id_a: id_a_copy,
364                 id_b: id_b_copy,
365                 id_s: id_s_copy,
366                 msg1: msg1.clone(),
367                 password_scalar, // scalar
368             },
369             msg_and_side,
370         )
371     }
372
373     fn start_a_internal(
374         password: &Password,
375         id_a: &Identity,
376         id_b: &Identity,
377         xy_scalar: G::Scalar,
378     ) -> (SPAKE2<G>, Vec<u8>) {
379         Self::start_internal(
380             Side::A,
381             &password,
382             &id_a,
383             &id_b,
384             &Identity::new(b""),
385             xy_scalar,
386         )
387     }
388
389     fn start_b_internal(
390         password: &Password,
391         id_a: &Identity,
392         id_b: &Identity,
393         xy_scalar: G::Scalar,
394     ) -> (SPAKE2<G>, Vec<u8>) {
395         Self::start_internal(
396             Side::B,
397             &password,
398             &id_a,
399             &id_b,
400             &Identity::new(b""),
401             xy_scalar,
402         )
403     }
404
405     fn start_symmetric_internal(
406         password: &Password,
407         id_s: &Identity,
408         xy_scalar: G::Scalar,
409     ) -> (SPAKE2<G>, Vec<u8>) {
410         Self::start_internal(
411             Side::Symmetric,
412             &password,
413             &Identity::new(b""),
414             &Identity::new(b""),
415             &id_s,
416             xy_scalar,
417         )
418     }
419
420     pub fn start_a(password: &Password, id_a: &Identity, id_b: &Identity) -> (SPAKE2<G>, Vec<u8>) {
421         let mut cspring: OsRng = OsRng::new().unwrap();
422         let xy_scalar: G::Scalar = G::random_scalar(&mut cspring);
423         Self::start_a_internal(&password, &id_a, &id_b, xy_scalar)
424     }
425
426     pub fn start_b(password: &Password, id_a: &Identity, id_b: &Identity) -> (SPAKE2<G>, Vec<u8>) {
427         let mut cspring: OsRng = OsRng::new().unwrap();
428         let xy_scalar: G::Scalar = G::random_scalar(&mut cspring);
429         Self::start_b_internal(&password, &id_a, &id_b, xy_scalar)
430     }
431
432     pub fn start_symmetric(password: &Password, id_s: &Identity) -> (SPAKE2<G>, Vec<u8>) {
433         let mut cspring: OsRng = OsRng::new().unwrap();
434         let xy_scalar: G::Scalar = G::random_scalar(&mut cspring);
435         Self::start_symmetric_internal(&password, &id_s, xy_scalar)
436     }
437
438     pub fn finish(self, msg2: &[u8]) -> Result<Vec<u8>, SPAKEErr> {
439         if msg2.len() != 1 + G::element_length() {
440             return Err(SPAKEErr {
441                 kind: ErrorType::WrongLength,
442             });
443         }
444         let msg_side = msg2[0];
445
446         match self.side {
447             Side::A => match msg_side {
448                 0x42 => (), // 'B'
449                 _ => {
450                     return Err(SPAKEErr {
451                         kind: ErrorType::BadSide,
452                     })
453                 }
454             },
455             Side::B => match msg_side {
456                 0x41 => (), // 'A'
457                 _ => {
458                     return Err(SPAKEErr {
459                         kind: ErrorType::BadSide,
460                     })
461                 }
462             },
463             Side::Symmetric => match msg_side {
464                 0x53 => (), // 'S'
465                 _ => {
466                     return Err(SPAKEErr {
467                         kind: ErrorType::BadSide,
468                     })
469                 }
470             },
471         }
472
473         let msg2_element = match G::bytes_to_element(&msg2[1..]) {
474             Some(x) => x,
475             None => {
476                 return Err(SPAKEErr {
477                     kind: ErrorType::CorruptMessage,
478                 })
479             }
480         };
481
482         // a: K = (Y+N*(-pw))*x
483         // b: K = (X+M*(-pw))*y
484         let unblinding = match self.side {
485             Side::A => G::const_n(),
486             Side::B => G::const_m(),
487             Side::Symmetric => G::const_s(),
488         };
489         let tmp1 = G::scalarmult(&unblinding, &G::scalar_neg(&self.password_scalar));
490         let tmp2 = G::add(&msg2_element, &tmp1);
491         let key_element = G::scalarmult(&tmp2, &self.xy_scalar);
492         let key_bytes = G::element_to_bytes(&key_element);
493
494         // key = H(H(pw) + H(idA) + H(idB) + X + Y + K)
495         //transcript = b"".join([sha256(pw).digest(),
496         //                       sha256(idA).digest(), sha256(idB).digest(),
497         //                       X_msg, Y_msg, K_bytes])
498         //key = sha256(transcript).digest()
499         // note that both sides must use the same order
500
501         Ok(match self.side {
502             Side::A => ed25519_hash_ab(
503                 &self.password_vec,
504                 &self.id_a,
505                 &self.id_b,
506                 self.msg1.as_slice(),
507                 &msg2[1..],
508                 &key_bytes,
509             ),
510             Side::B => ed25519_hash_ab(
511                 &self.password_vec,
512                 &self.id_a,
513                 &self.id_b,
514                 &msg2[1..],
515                 self.msg1.as_slice(),
516                 &key_bytes,
517             ),
518             Side::Symmetric => ed25519_hash_symmetric(
519                 &self.password_vec,
520                 &self.id_s,
521                 &self.msg1,
522                 &msg2[1..],
523                 &key_bytes,
524             ),
525         })
526     }
527 }
528
529 fn maybe_utf8(s: &[u8]) -> String {
530     match String::from_utf8(s.to_vec()) {
531         Ok(m) => format!("(s={})", m),
532         Err(_) => format!("(hex={})", hex::encode(s)),
533     }
534 }
535
536 impl<G: Group> fmt::Debug for SPAKE2<G> {
537     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
538         write!(
539             f,
540             "SPAKE2(G=?, side={:?}, idA={}, idB={}, idS={})",
541             self.side,
542             maybe_utf8(&self.id_a),
543             maybe_utf8(&self.id_b),
544             maybe_utf8(&self.id_s)
545         )
546     }
547 }
548
549 #[cfg(test)]
550 mod test {
551     /* This compares results against the python compatibility tests:
552     spake2.test.test_compat.SPAKE2.test_asymmetric . The python test passes a
553     deterministic RNG (used only for tests, of course) into the per-Group
554     "random_scalar()" function, which results in some particular scalar.
555      */
556     use super::*;
557     use curve25519_dalek::constants::ED25519_BASEPOINT_POINT;
558     use hex;
559     use spake2::{Ed25519Group, SPAKE2};
560
561     // the python tests show the long-integer form of scalars. the rust code
562     // wants an array of bytes (little-endian). Make sure the way we convert
563     // things works correctly.
564
565     #[test]
566     fn test_convert() {
567         let t1_decimal =
568             b"2238329342913194256032495932344128051776374960164957527413114840482143558222";
569         let t1_scalar = decimal_to_scalar(t1_decimal);
570         let t1_bytes = t1_scalar.to_bytes();
571         let expected = [
572             0x4e, 0x5a, 0xb4, 0x34, 0x5d, 0x47, 0x08, 0x84, 0x59, 0x13, 0xb4, 0x64, 0x1b, 0xc2,
573             0x7d, 0x52, 0x52, 0xa5, 0x85, 0x10, 0x1b, 0xcc, 0x42, 0x44, 0xd4, 0x49, 0xf4, 0xa8,
574             0x79, 0xd9, 0xf2, 0x04,
575         ];
576         assert_eq!(t1_bytes, expected);
577         //println!("t1_scalar is {:?}", t1_scalar);
578     }
579
580     #[test]
581     fn test_serialize_basepoint() {
582         // make sure elements are serialized same as the python library
583         let exp = "5866666666666666666666666666666666666666666666666666666666666666";
584         let base_vec = ED25519_BASEPOINT_POINT.compress().as_bytes().to_vec();
585         let base_hex = hex::encode(base_vec);
586         println!("exp: {:?}", exp);
587         println!("got: {:?}", base_hex);
588         assert_eq!(exp, base_hex);
589     }
590
591     #[test]
592     fn test_password_to_scalar() {
593         let password = Password::new(b"password");
594         let expected_pw_scalar = decimal_to_scalar(
595             b"3515301705789368674385125653994241092664323519848410154015274772661223168839",
596         );
597         let pw_scalar = Ed25519Group::hash_to_scalar(&password);
598         println!("exp: {:?}", hex::encode(expected_pw_scalar.as_bytes()));
599         println!("got: {:?}", hex::encode(pw_scalar.as_bytes()));
600         assert_eq!(&pw_scalar, &expected_pw_scalar);
601     }
602
603     #[test]
604     fn test_sizes() {
605         let (s1, msg1) = SPAKE2::<Ed25519Group>::start_a(
606             &Password::new(b"password"),
607             &Identity::new(b"idA"),
608             &Identity::new(b"idB"),
609         );
610         assert_eq!(msg1.len(), 1 + 32);
611         let (s2, msg2) = SPAKE2::<Ed25519Group>::start_b(
612             &Password::new(b"password"),
613             &Identity::new(b"idA"),
614             &Identity::new(b"idB"),
615         );
616         assert_eq!(msg2.len(), 1 + 32);
617         let key1 = s1.finish(&msg2).unwrap();
618         let key2 = s2.finish(&msg1).unwrap();
619         assert_eq!(key1.len(), 32);
620         assert_eq!(key2.len(), 32);
621
622         let (s1, msg1) = SPAKE2::<Ed25519Group>::start_symmetric(
623             &Password::new(b"password"),
624             &Identity::new(b"idS"),
625         );
626         assert_eq!(msg1.len(), 1 + 32);
627         let (s2, msg2) = SPAKE2::<Ed25519Group>::start_symmetric(
628             &Password::new(b"password"),
629             &Identity::new(b"idS"),
630         );
631         assert_eq!(msg2.len(), 1 + 32);
632         let key1 = s1.finish(&msg2).unwrap();
633         let key2 = s2.finish(&msg1).unwrap();
634         assert_eq!(key1.len(), 32);
635         assert_eq!(key2.len(), 32);
636     }
637
638     #[test]
639     fn test_hash_ab() {
640         let key = ed25519_hash_ab(
641             b"pw",
642             b"idA",
643             b"idB",
644             b"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", // len=32
645             b"YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY",
646             b"KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK",
647         );
648         let expected_key = "d59d9ba920f7092565cec747b08d5b2e981d553ac32fde0f25e5b4a4cfca3efd";
649         assert_eq!(hex::encode(key), expected_key);
650     }
651
652     #[test]
653     fn test_hash_symmetric() {
654         let key = ed25519_hash_symmetric(
655             b"pw",
656             b"idSymmetric",
657             b"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
658             b"YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY",
659             b"KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK",
660         );
661         let expected_key = "b0b31e4401aae37d91a9a8bf6fbb1298cafc005ff9142e3ffc5b9799fb11128b";
662         assert_eq!(hex::encode(key), expected_key);
663     }
664
665     #[test]
666     fn test_asymmetric() {
667         let scalar_a = decimal_to_scalar(
668             b"2611694063369306139794446498317402240796898290761098242657700742213257926693",
669         );
670         let scalar_b = decimal_to_scalar(
671             b"7002393159576182977806091886122272758628412261510164356026361256515836884383",
672         );
673         let expected_pw_scalar = decimal_to_scalar(
674             b"3515301705789368674385125653994241092664323519848410154015274772661223168839",
675         );
676
677         println!("scalar_a is {}", hex::encode(scalar_a.as_bytes()));
678
679         let (s1, msg1) = SPAKE2::<Ed25519Group>::start_a_internal(
680             &Password::new(b"password"),
681             &Identity::new(b"idA"),
682             &Identity::new(b"idB"),
683             scalar_a,
684         );
685         let expected_msg1 = "416fc960df73c9cf8ed7198b0c9534e2e96a5984bfc5edc023fd24dacf371f2af9";
686
687         println!();
688         println!("xys1: {:?}", hex::encode(s1.xy_scalar.as_bytes()));
689         println!();
690         println!("pws1: {:?}", hex::encode(s1.password_scalar.as_bytes()));
691         println!("exp : {:?}", hex::encode(expected_pw_scalar.as_bytes()));
692         println!();
693         println!("msg1: {:?}", hex::encode(&msg1));
694         println!("exp : {:?}", expected_msg1);
695         println!();
696
697         assert_eq!(
698             hex::encode(expected_pw_scalar.as_bytes()),
699             hex::encode(s1.password_scalar.as_bytes())
700         );
701         assert_eq!(hex::encode(&msg1), expected_msg1);
702
703         let (s2, msg2) = SPAKE2::<Ed25519Group>::start_b_internal(
704             &Password::new(b"password"),
705             &Identity::new(b"idA"),
706             &Identity::new(b"idB"),
707             scalar_b,
708         );
709         assert_eq!(expected_pw_scalar, s2.password_scalar);
710         assert_eq!(
711             hex::encode(&msg2),
712             "42354e97b88406922b1df4bea1d7870f17aed3dba7c720b313edae315b00959309"
713         );
714
715         let key1 = s1.finish(&msg2).unwrap();
716         let key2 = s2.finish(&msg1).unwrap();
717         assert_eq!(key1, key2);
718         assert_eq!(
719             hex::encode(key1),
720             "712295de7219c675ddd31942184aa26e0a957cf216bc230d165b215047b520c1"
721         );
722     }
723
724     #[test]
725     fn test_debug() {
726         let (s1, _msg1) = SPAKE2::<Ed25519Group>::start_a(
727             &Password::new(b"password"),
728             &Identity::new(b"idA"),
729             &Identity::new(b"idB"),
730         );
731         println!("s1: {:?}", s1);
732         let (s2, _msg1) = SPAKE2::<Ed25519Group>::start_symmetric(
733             &Password::new(b"password"),
734             &Identity::new(b"idS"),
735         );
736         println!("s2: {:?}", s2);
737     }
738
739 }