1use simoom_sys::arch;
7
8#[derive(Clone, Copy)]
10pub struct Output {
11 buf: [u8; 64],
12 len: u8,
13}
14
15impl Output {
16 fn new(bytes: &[u8]) -> Output {
17 let mut buf = [0u8; 64];
18 buf[..bytes.len()].copy_from_slice(bytes);
19 Output { buf, len: bytes.len() as u8 }
20 }
21}
22
23impl core::ops::Deref for Output {
24 type Target = [u8];
25 fn deref(&self) -> &[u8] {
26 &self.buf[..self.len as usize]
27 }
28}
29
30impl AsRef<[u8]> for Output {
31 fn as_ref(&self) -> &[u8] {
32 self
33 }
34}
35
36impl PartialEq for Output {
37 fn eq(&self, o: &Output) -> bool {
38 crate::util::ct_eq(self, o)
39 }
40}
41
42impl core::fmt::Debug for Output {
43 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
44 f.write_str(&crate::util::hex(self))
45 }
46}
47
48const K256: [u32; 64] = [
49 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98,
50 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
51 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8,
52 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
53 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819,
54 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
55 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7,
56 0xc67178f2,
57];
58
59fn compress256_soft(state: &mut [u32; 8], blocks: &[u8]) {
60 for block in blocks.chunks_exact(64) {
61 let mut w = [0u32; 64];
62 for i in 0..16 {
63 w[i] = u32::from_be_bytes(block[4 * i..4 * i + 4].try_into().unwrap());
64 }
65 for i in 16..64 {
66 let s0 = w[i - 15].rotate_right(7) ^ w[i - 15].rotate_right(18) ^ (w[i - 15] >> 3);
67 let s1 = w[i - 2].rotate_right(17) ^ w[i - 2].rotate_right(19) ^ (w[i - 2] >> 10);
68 w[i] = w[i - 16].wrapping_add(s0).wrapping_add(w[i - 7]).wrapping_add(s1);
69 }
70 let [mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut h] = *state;
71 for i in 0..64 {
72 let s1 = e.rotate_right(6) ^ e.rotate_right(11) ^ e.rotate_right(25);
73 let ch = (e & f) ^ (!e & g);
74 let t1 = h.wrapping_add(s1).wrapping_add(ch).wrapping_add(K256[i]).wrapping_add(w[i]);
75 let s0 = a.rotate_right(2) ^ a.rotate_right(13) ^ a.rotate_right(22);
76 let maj = (a & b) ^ (a & c) ^ (b & c);
77 let t2 = s0.wrapping_add(maj);
78 h = g;
79 g = f;
80 f = e;
81 e = d.wrapping_add(t1);
82 d = c;
83 c = b;
84 b = a;
85 a = t1.wrapping_add(t2);
86 }
87 for (s, v) in state.iter_mut().zip([a, b, c, d, e, f, g, h]) {
88 *s = s.wrapping_add(v);
89 }
90 }
91}
92
93fn compress256(state: &mut [u32; 8], blocks: &[u8]) {
94 if !arch::sha256_blocks(state, blocks) {
95 compress256_soft(state, blocks);
96 }
97}
98
99const K512: [u64; 80] = [
100 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538,
101 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe,
102 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235,
103 0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
104 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, 0x983e5152ee66dfab,
105 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725,
106 0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed,
107 0x53380d139d95b3df, 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
108 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218,
109 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, 0x19a4c116b8d2d0c8, 0x1e376c085141ab53,
110 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373,
111 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
112 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, 0xca273eceea26619c,
113 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, 0x0a637dc5a2c898a6,
114 0x113f9804bef90dae, 0x1b710b35131c471b, 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc,
115 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817,
116];
117
118fn compress512(state: &mut [u64; 8], blocks: &[u8]) {
119 for block in blocks.chunks_exact(128) {
120 let mut w = [0u64; 80];
121 for i in 0..16 {
122 w[i] = u64::from_be_bytes(block[8 * i..8 * i + 8].try_into().unwrap());
123 }
124 for i in 16..80 {
125 let s0 = w[i - 15].rotate_right(1) ^ w[i - 15].rotate_right(8) ^ (w[i - 15] >> 7);
126 let s1 = w[i - 2].rotate_right(19) ^ w[i - 2].rotate_right(61) ^ (w[i - 2] >> 6);
127 w[i] = w[i - 16].wrapping_add(s0).wrapping_add(w[i - 7]).wrapping_add(s1);
128 }
129 let [mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut h] = *state;
130 for i in 0..80 {
131 let s1 = e.rotate_right(14) ^ e.rotate_right(18) ^ e.rotate_right(41);
132 let ch = (e & f) ^ (!e & g);
133 let t1 = h.wrapping_add(s1).wrapping_add(ch).wrapping_add(K512[i]).wrapping_add(w[i]);
134 let s0 = a.rotate_right(28) ^ a.rotate_right(34) ^ a.rotate_right(39);
135 let maj = (a & b) ^ (a & c) ^ (b & c);
136 let t2 = s0.wrapping_add(maj);
137 h = g;
138 g = f;
139 f = e;
140 e = d.wrapping_add(t1);
141 d = c;
142 c = b;
143 b = a;
144 a = t1.wrapping_add(t2);
145 }
146 for (s, v) in state.iter_mut().zip([a, b, c, d, e, f, g, h]) {
147 *s = s.wrapping_add(v);
148 }
149 }
150}
151
152#[derive(Clone)]
154struct Buf<const B: usize> {
155 buf: [u8; B],
156 len: usize,
157 total: u128,
158}
159
160impl<const B: usize> Buf<B> {
161 const fn new() -> Self {
162 Buf { buf: [0; B], len: 0, total: 0 }
163 }
164
165 fn update(&mut self, mut data: &[u8], mut compress: impl FnMut(&[u8])) {
166 self.total += data.len() as u128;
167 if self.len > 0 {
168 let n = (B - self.len).min(data.len());
169 self.buf[self.len..self.len + n].copy_from_slice(&data[..n]);
170 self.len += n;
171 data = &data[n..];
172 if self.len < B {
173 return;
174 }
175 compress(&self.buf);
176 self.len = 0;
177 }
178 let whole = data.len() - data.len() % B;
179 if whole > 0 {
180 compress(&data[..whole]);
181 }
182 let rest = &data[whole..];
183 self.buf[..rest.len()].copy_from_slice(rest);
184 self.len = rest.len();
185 }
186
187 fn pad(&mut self, lenbytes: usize, mut compress: impl FnMut(&[u8])) {
189 let bits = self.total * 8;
190 self.buf[self.len] = 0x80;
191 self.buf[self.len + 1..].fill(0);
192 if self.len + 1 > B - lenbytes {
193 compress(&self.buf);
194 self.buf.fill(0);
195 }
196 let lb = bits.to_be_bytes();
197 self.buf[B - lenbytes..].copy_from_slice(&lb[16 - lenbytes..]);
198 compress(&self.buf);
199 }
200}
201
202#[derive(Clone)]
204pub struct Sha256 {
205 state: [u32; 8],
206 buf: Buf<64>,
207}
208
209impl Default for Sha256 {
210 fn default() -> Self {
211 Self::new()
212 }
213}
214
215impl Sha256 {
216 pub const fn new() -> Sha256 {
217 Sha256 {
218 state: [0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19],
219 buf: Buf::new(),
220 }
221 }
222 pub fn update(&mut self, data: &[u8]) {
223 let st = &mut self.state;
224 self.buf.update(data, |b| compress256(st, b));
225 }
226 pub fn finish(mut self) -> [u8; 32] {
227 let st = &mut self.state;
228 self.buf.pad(8, |b| compress256(st, b));
229 let mut out = [0u8; 32];
230 for (o, w) in out.chunks_exact_mut(4).zip(self.state) {
231 o.copy_from_slice(&w.to_be_bytes());
232 }
233 out
234 }
235 pub fn digest(data: &[u8]) -> [u8; 32] {
236 let mut h = Sha256::new();
237 h.update(data);
238 h.finish()
239 }
240}
241
242#[derive(Clone)]
245pub struct Sha512 {
246 state: [u64; 8],
247 buf: Buf<128>,
248 out_words: usize,
249}
250
251const IV512: [u64; 8] = [
252 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, 0x510e527fade682d1,
253 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
254];
255const IV384: [u64; 8] = [
256 0xcbbb9d5dc1059ed8, 0x629a292a367cd507, 0x9159015a3070dd17, 0x152fecd8f70e5939, 0x67332667ffc00b31,
257 0x8eb44a8768581511, 0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4,
258];
259const IV512_256: [u64; 8] = [
261 0x22312194fc2bf72c, 0x9f555fa3c84c64c2, 0x2393b86b6f53b151, 0x963877195940eabd, 0x96283ee2a88effe3,
262 0xbe5e1e2553863992, 0x2b0199fc2c85b8aa, 0x0eb72ddc81c52ca2,
263];
264
265impl Sha512 {
266 pub const fn new() -> Sha512 {
267 Sha512 { state: IV512, buf: Buf::new(), out_words: 8 }
268 }
269 pub const fn new384() -> Sha512 {
270 Sha512 { state: IV384, buf: Buf::new(), out_words: 6 }
271 }
272 pub const fn new512_256() -> Sha512 {
274 Sha512 { state: IV512_256, buf: Buf::new(), out_words: 4 }
275 }
276 pub fn update(&mut self, data: &[u8]) {
277 let st = &mut self.state;
278 self.buf.update(data, |b| compress512(st, b));
279 }
280 pub fn finish(mut self) -> Output {
281 let st = &mut self.state;
282 self.buf.pad(16, |b| compress512(st, b));
283 let mut out = [0u8; 64];
284 for (o, w) in out.chunks_exact_mut(8).zip(self.state) {
285 o.copy_from_slice(&w.to_be_bytes());
286 }
287 Output::new(&out[..8 * self.out_words])
288 }
289 pub fn digest(data: &[u8]) -> [u8; 64] {
290 let mut h = Sha512::new();
291 h.update(data);
292 let mut o = [0u8; 64];
293 o.copy_from_slice(&h.finish());
294 o
295 }
296}
297
298impl Default for Sha512 {
299 fn default() -> Self {
300 Self::new()
301 }
302}
303
304#[derive(Clone, Copy, Debug, PartialEq, Eq)]
306pub enum HashAlg {
307 Sha256,
308 Sha384,
309 Sha512,
310}
311
312#[derive(Clone)]
314pub enum Hasher {
315 Sha256(Sha256),
316 Sha512(Sha512),
317}
318
319impl Hasher {
320 #[inline(never)]
321 pub fn new(alg: HashAlg) -> Hasher {
322 match alg {
323 HashAlg::Sha256 => Hasher::Sha256(Sha256::new()),
324 HashAlg::Sha384 => Hasher::Sha512(Sha512::new384()),
325 HashAlg::Sha512 => Hasher::Sha512(Sha512::new()),
326 }
327 }
328 #[inline(never)]
329 pub fn update(&mut self, data: &[u8]) {
330 match self {
331 Hasher::Sha256(h) => h.update(data),
332 Hasher::Sha512(h) => h.update(data),
333 }
334 }
335 #[inline(never)]
336 pub fn finish(self) -> Output {
337 match self {
338 Hasher::Sha256(h) => Output::new(&h.finish()),
339 Hasher::Sha512(h) => h.finish(),
340 }
341 }
342 pub fn current(&self) -> Output {
344 self.clone().finish()
345 }
346}
347
348impl HashAlg {
349 pub const fn output_len(self) -> usize {
350 match self {
351 HashAlg::Sha256 => 32,
352 HashAlg::Sha384 => 48,
353 HashAlg::Sha512 => 64,
354 }
355 }
356 const fn block_len(self) -> usize {
357 match self {
358 HashAlg::Sha256 => 64,
359 _ => 128,
360 }
361 }
362 pub fn hash(self, data: &[u8]) -> Output {
363 let mut h = Hasher::new(self);
364 h.update(data);
365 h.finish()
366 }
367 pub fn hmac(self, key: &[u8], parts: &[&[u8]]) -> Output {
369 let bl = self.block_len();
370 let mut k = [0u8; 128];
371 if key.len() > bl {
372 let d = self.hash(key);
373 k[..d.len()].copy_from_slice(&d);
374 } else {
375 k[..key.len()].copy_from_slice(key);
376 }
377 let mut pad = [0u8; 128];
378 for (p, x) in pad.iter_mut().zip(k.iter()) {
379 *p = x ^ 0x36;
380 }
381 let mut inner = Hasher::new(self);
382 inner.update(&pad[..bl]);
383 for p in parts {
384 inner.update(p);
385 }
386 let ih = inner.finish();
387 for (p, x) in pad.iter_mut().zip(k.iter()) {
388 *p = x ^ 0x5c;
389 }
390 let mut outer = Hasher::new(self);
391 outer.update(&pad[..bl]);
392 outer.update(&ih);
393 crate::util::zeroize(&mut k);
394 crate::util::zeroize(&mut pad);
395 outer.finish()
396 }
397 pub fn hkdf_extract(self, salt: &[u8], ikm: &[u8]) -> Output {
399 let zeros = [0u8; 64];
400 let salt = if salt.is_empty() { &zeros[..self.output_len()] } else { salt };
401 self.hmac(salt, &[ikm])
402 }
403 pub fn hkdf_expand(self, prk: &[u8], info: &[&[u8]], out: &mut [u8]) {
405 assert!(out.len() <= 255 * self.output_len(), "HKDF output too long");
406 let mut t = Output::new(&[]);
407 for (i, chunk) in out.chunks_mut(self.output_len()).enumerate() {
408 let ctr = [i as u8 + 1];
409 let next = {
410 let mut parts: Vec<&[u8]> = Vec::with_capacity(info.len() + 2);
411 parts.push(&t);
412 parts.extend_from_slice(info);
413 parts.push(&ctr);
414 self.hmac(prk, &parts)
415 };
416 chunk.copy_from_slice(&next[..chunk.len()]);
417 t = next;
418 }
419 }
420}
421
422#[cfg(test)]
423mod tests {
424 use super::*;
425 use crate::util::{hex, unhex};
426
427 #[test]
428 fn sha256_vectors_hardware_and_soft() {
429 let million = vec![b'a'; 1_000_000];
430 for soft in [false, true] {
431 let digest = |d: &[u8]| -> [u8; 32] {
432 if soft {
433 let mut st = Sha256::new().state;
434 let mut b = Buf::<64>::new();
435 b.update(d, |x| compress256_soft(&mut st, x));
436 b.pad(8, |x| compress256_soft(&mut st, x));
437 let mut out = [0u8; 32];
438 for (o, w) in out.chunks_exact_mut(4).zip(st) {
439 o.copy_from_slice(&w.to_be_bytes());
440 }
441 out
442 } else {
443 Sha256::digest(d)
444 }
445 };
446 assert_eq!(hex(&digest(b"")), "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
447 assert_eq!(hex(&digest(b"abc")), "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
448 assert_eq!(
449 hex(&digest(b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")),
450 "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"
451 );
452 assert_eq!(hex(&digest(&million)), "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0");
453 }
454 for len in [55usize, 56, 63, 64, 65, 119, 120, 1000] {
456 let data: Vec<u8> = (0..len).map(|i| i as u8).collect();
457 let mut h = Sha256::new();
458 for c in data.chunks(7) {
459 h.update(c);
460 }
461 assert_eq!(h.finish(), Sha256::digest(&data));
462 }
463 let mut h = Sha256::new();
464 for c in million.chunks(37) {
465 h.update(c);
466 }
467 assert_eq!(hex(&h.finish()), "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0");
468 }
469
470 #[test]
471 fn sha384_sha512_vectors() {
472 assert_eq!(
473 hex(&HashAlg::Sha384.hash(b"abc")),
474 "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7"
475 );
476 assert_eq!(
477 hex(&HashAlg::Sha384.hash(b"")),
478 "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"
479 );
480 assert_eq!(
481 hex(&HashAlg::Sha384.hash(b"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu")),
482 "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039"
483 );
484 assert_eq!(
485 hex(&{
486 let mut h = Sha512::new512_256();
487 h.update(b"abc");
488 h.finish()
489 }),
490 "53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23"
491 );
492 assert_eq!(
493 hex(&HashAlg::Sha512.hash(b"abc")),
494 "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"
495 );
496 let data = vec![0x61u8; 1000];
497 let mut h = Hasher::new(HashAlg::Sha512);
498 for c in data.chunks(111) {
499 h.update(c);
500 }
501 assert_eq!(h.finish(), HashAlg::Sha512.hash(&data));
502 }
503
504 #[test]
505 fn hmac_rfc4231() {
506 let key = [0x0bu8; 20];
507 assert_eq!(
508 hex(&HashAlg::Sha256.hmac(&key, &[b"Hi There"])),
509 "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7"
510 );
511 assert_eq!(
512 hex(&HashAlg::Sha384.hmac(&key, &[b"Hi ", b"There"])),
513 "afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59cfaea9ea9076ede7f4af152e8b2fa9cb6"
514 );
515 assert_eq!(
516 hex(&HashAlg::Sha512.hmac(&key, &[b"Hi There"])),
517 "87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854"
518 );
519 assert_eq!(
520 hex(&HashAlg::Sha256.hmac(b"Jefe", &[b"what do ya want for nothing?"])),
521 "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843"
522 );
523 let key = [0xaau8; 131];
524 assert_eq!(
525 hex(&HashAlg::Sha256.hmac(&key, &[b"Test Using Larger Than Block-Size Key - Hash Key First"])),
526 "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54"
527 );
528 }
529
530 #[test]
531 fn hkdf_rfc5869() {
532 let ikm = [0x0bu8; 22];
533 let prk = HashAlg::Sha256.hkdf_extract(&unhex("000102030405060708090a0b0c"), &ikm);
534 assert_eq!(hex(&prk), "077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5");
535 let mut okm = [0u8; 42];
536 HashAlg::Sha256.hkdf_expand(&prk, &[&unhex("f0f1f2f3f4"), &unhex("f5f6f7f8f9")], &mut okm);
537 assert_eq!(hex(&okm), "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865");
538 let prk = HashAlg::Sha256.hkdf_extract(&[], &ikm);
539 assert_eq!(hex(&prk), "19ef24a32c717b167f33a91d6f648bdf96596776afdb6377ac434c1c293ccb04");
540 HashAlg::Sha256.hkdf_expand(&prk, &[], &mut okm);
541 assert_eq!(hex(&okm), "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8");
542 }
543}