1 //! "Edwards25519" elliptic curve group.
3 use crate::{c2_Element, c2_Scalar, Group};
5 use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, edwards::CompressedEdwardsY};
7 use rand_core::{CryptoRng, RngCore};
8 use sha2::{Digest, Sha256};
10 /// Ed25519 elliptic curve group.
11 #[derive(Debug, PartialEq, Eq)]
12 pub struct Ed25519Group;
14 impl Group for Ed25519Group {
15 type Scalar = c2_Scalar;
16 type Element = c2_Element;
17 type TranscriptHash = Sha256;
19 fn name() -> &'static str {
23 fn const_m() -> c2_Element {
24 // 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)]))"
25 // 15cfd18e385952982b6a8f8c7854963b58e34388c8e6dae891db756481a02312
27 0x15, 0xcf, 0xd1, 0x8e, 0x38, 0x59, 0x52, 0x98, 0x2b, 0x6a, 0x8f, 0x8c, 0x78, 0x54,
28 0x96, 0x3b, 0x58, 0xe3, 0x43, 0x88, 0xc8, 0xe6, 0xda, 0xe8, 0x91, 0xdb, 0x75, 0x64,
29 0x81, 0xa0, 0x23, 0x12,
35 fn const_n() -> c2_Element {
36 // 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)]))"
37 // f04f2e7eb734b2a8f8b472eaf9c3c632576ac64aea650b496a8a20ff00e583c3
39 0xf0, 0x4f, 0x2e, 0x7e, 0xb7, 0x34, 0xb2, 0xa8, 0xf8, 0xb4, 0x72, 0xea, 0xf9, 0xc3,
40 0xc6, 0x32, 0x57, 0x6a, 0xc6, 0x4a, 0xea, 0x65, 0x0b, 0x49, 0x6a, 0x8a, 0x20, 0xff,
41 0x00, 0xe5, 0x83, 0xc3,
47 fn const_s() -> c2_Element {
48 // 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)]))"
49 // 6f00dae87c1be1a73b5922ef431cd8f57879569c222d22b1cd71e8546ab8e6f1
51 0x6f, 0x00, 0xda, 0xe8, 0x7c, 0x1b, 0xe1, 0xa7, 0x3b, 0x59, 0x22, 0xef, 0x43, 0x1c,
52 0xd8, 0xf5, 0x78, 0x79, 0x56, 0x9c, 0x22, 0x2d, 0x22, 0xb1, 0xcd, 0x71, 0xe8, 0x54,
53 0x6a, 0xb8, 0xe6, 0xf1,
59 fn hash_to_scalar(s: &[u8]) -> c2_Scalar {
60 ed25519_hash_to_scalar(s)
63 fn random_scalar<T>(cspring: &mut T) -> c2_Scalar
65 T: RngCore + CryptoRng,
67 c2_Scalar::random(cspring)
70 fn scalar_neg(s: &c2_Scalar) -> c2_Scalar {
74 fn element_to_bytes(s: &c2_Element) -> Vec<u8> {
75 s.compress().as_bytes().to_vec()
78 fn element_length() -> usize {
82 fn bytes_to_element(b: &[u8]) -> Option<c2_Element> {
87 let mut bytes = [0u8; 32];
88 bytes.copy_from_slice(b);
90 let cey = CompressedEdwardsY(bytes);
94 fn basepoint_mult(s: &c2_Scalar) -> c2_Element {
95 ED25519_BASEPOINT_POINT * s
97 fn scalarmult(e: &c2_Element, s: &c2_Scalar) -> c2_Element {
101 fn add(a: &c2_Element, b: &c2_Element) -> c2_Element {
106 fn ed25519_hash_to_scalar(s: &[u8]) -> c2_Scalar {
107 //c2_Scalar::hash_from_bytes::<Sha512>(&s)
109 // h = HKDF(salt=b"", ikm=s, hash=SHA256, info=b"SPAKE2 pw", len=32+16)
113 let mut okm = [0u8; 32 + 16];
114 Hkdf::<Sha256>::new(Some(b""), s)
115 .expand(b"SPAKE2 pw", &mut okm)
117 //println!("expanded: {}{}", "................................", okm.iter().to_hex()); // ok
119 let mut reducible = [0u8; 64]; // little-endian
120 for (i, x) in okm.iter().enumerate().take(32 + 16) {
121 reducible[32 + 16 - 1 - i] = *x;
123 //println!("reducible: {}", reducible.iter().to_hex());
124 c2_Scalar::from_bytes_mod_order_wide(&reducible)
125 //let reduced = c2_Scalar::reduce(&reducible);
126 //println!("reduced: {}", reduced.as_bytes().to_hex());
131 /// Hash `idA` and `idB` identities.
132 pub(crate) fn hash_ab(
140 assert_eq!(first_msg.len(), 32);
141 assert_eq!(second_msg.len(), 32);
142 // the transcript is fixed-length, made up of 6 32-byte values:
143 // byte 0-31 : sha256(pw)
144 // byte 32-63 : sha256(idA)
145 // byte 64-95 : sha256(idB)
146 // byte 96-127 : X_msg
147 // byte 128-159: Y_msg
148 // byte 160-191: K_bytes
149 let mut transcript = [0u8; 6 * 32];
151 let mut pw_hash = Sha256::new();
152 pw_hash.update(password_vec);
153 transcript[0..32].copy_from_slice(&pw_hash.finalize());
155 let mut ida_hash = Sha256::new();
156 ida_hash.update(id_a);
157 transcript[32..64].copy_from_slice(&ida_hash.finalize());
159 let mut idb_hash = Sha256::new();
160 idb_hash.update(id_b);
161 transcript[64..96].copy_from_slice(&idb_hash.finalize());
163 transcript[96..128].copy_from_slice(first_msg);
164 transcript[128..160].copy_from_slice(second_msg);
165 transcript[160..192].copy_from_slice(key_bytes);
167 //println!("transcript: {:?}", transcript.iter().to_hex());
169 //let mut hash = G::TranscriptHash::default();
170 let mut hash = Sha256::new();
171 hash.update(transcript.to_vec());
172 hash.finalize().to_vec()
175 /// Hash symmetric identities.
176 pub(crate) fn hash_symmetric(
183 assert_eq!(msg_u.len(), 32);
184 assert_eq!(msg_v.len(), 32);
185 // # since we don't know which side is which, we must sort the messages
186 // first_msg, second_msg = sorted([msg1, msg2])
187 // transcript = b"".join([sha256(pw).digest(),
188 // sha256(idSymmetric).digest(),
189 // first_msg, second_msg, K_bytes])
191 // the transcript is fixed-length, made up of 5 32-byte values:
192 // byte 0-31 : sha256(pw)
193 // byte 32-63 : sha256(idSymmetric)
194 // byte 64-95 : X_msg
195 // byte 96-127 : Y_msg
196 // byte 128-159: K_bytes
197 let mut transcript = [0u8; 5 * 32];
199 let mut pw_hash = Sha256::new();
200 pw_hash.update(password_vec);
201 transcript[0..32].copy_from_slice(&pw_hash.finalize());
203 let mut ids_hash = Sha256::new();
204 ids_hash.update(id_s);
205 transcript[32..64].copy_from_slice(&ids_hash.finalize());
208 transcript[64..96].copy_from_slice(msg_u);
209 transcript[96..128].copy_from_slice(msg_v);
211 transcript[64..96].copy_from_slice(msg_v);
212 transcript[96..128].copy_from_slice(msg_u);
214 transcript[128..160].copy_from_slice(key_bytes);
216 let mut hash = Sha256::new();
217 hash.update(transcript.to_vec());
218 hash.finalize().to_vec()