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