1#![no_std]
39#![allow(
40 non_snake_case,
41 clippy::cast_lossless,
42 clippy::eq_op,
43 clippy::identity_op,
44 clippy::many_single_char_names,
45 clippy::unreadable_literal
46)]
47
48#[inline(always)]
49fn load_be(base: &[u8], offset: usize) -> u32 {
50 let addr = &base[offset..];
51 (addr[3] as u32) | (addr[2] as u32) << 8 | (addr[1] as u32) << 16 | (addr[0] as u32) << 24
52}
53
54#[inline(always)]
55fn store_be(base: &mut [u8], offset: usize, x: u32) {
56 let addr = &mut base[offset..];
57 addr[3] = x as u8;
58 addr[2] = (x >> 8) as u8;
59 addr[1] = (x >> 16) as u8;
60 addr[0] = (x >> 24) as u8;
61}
62
63fn verify(x: &[u8], y: &[u8]) -> bool {
64 if x.len() != y.len() {
65 return false;
66 }
67 let mut v: u32 = 0;
68
69 #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
70 {
71 let (mut h1, mut h2) = (0u32, 0u32);
72 for (b1, b2) in x.iter().zip(y.iter()) {
73 h1 ^= (h1 << 5).wrapping_add((h1 >> 2) ^ *b1 as u32);
74 h2 ^= (h2 << 5).wrapping_add((h2 >> 2) ^ *b2 as u32);
75 }
76 v |= h1 ^ h2;
77 }
78 for (a, b) in x.iter().zip(y.iter()) {
79 v |= (a ^ b) as u32;
80 }
81 let v = unsafe { core::ptr::read_volatile(&v) };
82 v == 0
83}
84
85struct W([u32; 16]);
86
87#[derive(Copy, Clone)]
88struct State([u32; 8]);
89
90impl W {
91 fn new(input: &[u8]) -> Self {
92 let mut w = [0u32; 16];
93 for (i, e) in w.iter_mut().enumerate() {
94 *e = load_be(input, i * 4)
95 }
96 W(w)
97 }
98
99 #[inline(always)]
100 fn Ch(x: u32, y: u32, z: u32) -> u32 {
101 (x & y) ^ (!x & z)
102 }
103
104 #[inline(always)]
105 fn Maj(x: u32, y: u32, z: u32) -> u32 {
106 (x & y) ^ (x & z) ^ (y & z)
107 }
108
109 #[inline(always)]
110 fn Sigma0(x: u32) -> u32 {
111 x.rotate_right(2) ^ x.rotate_right(13) ^ x.rotate_right(22)
112 }
113
114 #[inline(always)]
115 fn Sigma1(x: u32) -> u32 {
116 x.rotate_right(6) ^ x.rotate_right(11) ^ x.rotate_right(25)
117 }
118
119 #[inline(always)]
120 fn sigma0(x: u32) -> u32 {
121 x.rotate_right(7) ^ x.rotate_right(18) ^ (x >> 3)
122 }
123
124 #[inline(always)]
125 fn sigma1(x: u32) -> u32 {
126 x.rotate_right(17) ^ x.rotate_right(19) ^ (x >> 10)
127 }
128
129 #[cfg_attr(feature = "opt_size", inline(never))]
130 #[cfg_attr(not(feature = "opt_size"), inline(always))]
131 fn M(&mut self, a: usize, b: usize, c: usize, d: usize) {
132 let w = &mut self.0;
133 w[a] = w[a]
134 .wrapping_add(Self::sigma1(w[b]))
135 .wrapping_add(w[c])
136 .wrapping_add(Self::sigma0(w[d]));
137 }
138
139 #[inline]
140 fn expand(&mut self) {
141 self.M(0, (0 + 14) & 15, (0 + 9) & 15, (0 + 1) & 15);
142 self.M(1, (1 + 14) & 15, (1 + 9) & 15, (1 + 1) & 15);
143 self.M(2, (2 + 14) & 15, (2 + 9) & 15, (2 + 1) & 15);
144 self.M(3, (3 + 14) & 15, (3 + 9) & 15, (3 + 1) & 15);
145 self.M(4, (4 + 14) & 15, (4 + 9) & 15, (4 + 1) & 15);
146 self.M(5, (5 + 14) & 15, (5 + 9) & 15, (5 + 1) & 15);
147 self.M(6, (6 + 14) & 15, (6 + 9) & 15, (6 + 1) & 15);
148 self.M(7, (7 + 14) & 15, (7 + 9) & 15, (7 + 1) & 15);
149 self.M(8, (8 + 14) & 15, (8 + 9) & 15, (8 + 1) & 15);
150 self.M(9, (9 + 14) & 15, (9 + 9) & 15, (9 + 1) & 15);
151 self.M(10, (10 + 14) & 15, (10 + 9) & 15, (10 + 1) & 15);
152 self.M(11, (11 + 14) & 15, (11 + 9) & 15, (11 + 1) & 15);
153 self.M(12, (12 + 14) & 15, (12 + 9) & 15, (12 + 1) & 15);
154 self.M(13, (13 + 14) & 15, (13 + 9) & 15, (13 + 1) & 15);
155 self.M(14, (14 + 14) & 15, (14 + 9) & 15, (14 + 1) & 15);
156 self.M(15, (15 + 14) & 15, (15 + 9) & 15, (15 + 1) & 15);
157 }
158
159 #[cfg_attr(feature = "opt_size", inline(never))]
160 #[cfg_attr(not(feature = "opt_size"), inline(always))]
161 fn F(&mut self, state: &mut State, i: usize, k: u32) {
162 let t = &mut state.0;
163 t[(16 - i + 7) & 7] = t[(16 - i + 7) & 7]
164 .wrapping_add(Self::Sigma1(t[(16 - i + 4) & 7]))
165 .wrapping_add(Self::Ch(
166 t[(16 - i + 4) & 7],
167 t[(16 - i + 5) & 7],
168 t[(16 - i + 6) & 7],
169 ))
170 .wrapping_add(k)
171 .wrapping_add(self.0[i]);
172 t[(16 - i + 3) & 7] = t[(16 - i + 3) & 7].wrapping_add(t[(16 - i + 7) & 7]);
173 t[(16 - i + 7) & 7] = t[(16 - i + 7) & 7]
174 .wrapping_add(Self::Sigma0(t[(16 - i + 0) & 7]))
175 .wrapping_add(Self::Maj(
176 t[(16 - i + 0) & 7],
177 t[(16 - i + 1) & 7],
178 t[(16 - i + 2) & 7],
179 ));
180 }
181
182 fn G(&mut self, state: &mut State, s: usize) {
183 const ROUND_CONSTANTS: [u32; 64] = [
184 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4,
185 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe,
186 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f,
187 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
188 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,
189 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
190 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116,
191 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
192 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7,
193 0xc67178f2,
194 ];
195 let rc = &ROUND_CONSTANTS[s * 16..];
196 self.F(state, 0, rc[0]);
197 self.F(state, 1, rc[1]);
198 self.F(state, 2, rc[2]);
199 self.F(state, 3, rc[3]);
200 self.F(state, 4, rc[4]);
201 self.F(state, 5, rc[5]);
202 self.F(state, 6, rc[6]);
203 self.F(state, 7, rc[7]);
204 self.F(state, 8, rc[8]);
205 self.F(state, 9, rc[9]);
206 self.F(state, 10, rc[10]);
207 self.F(state, 11, rc[11]);
208 self.F(state, 12, rc[12]);
209 self.F(state, 13, rc[13]);
210 self.F(state, 14, rc[14]);
211 self.F(state, 15, rc[15]);
212 }
213}
214
215impl State {
216 fn new() -> Self {
217 const IV: [u8; 32] = [
218 0x6a, 0x09, 0xe6, 0x67, 0xbb, 0x67, 0xae, 0x85, 0x3c, 0x6e, 0xf3, 0x72, 0xa5, 0x4f,
219 0xf5, 0x3a, 0x51, 0x0e, 0x52, 0x7f, 0x9b, 0x05, 0x68, 0x8c, 0x1f, 0x83, 0xd9, 0xab,
220 0x5b, 0xe0, 0xcd, 0x19,
221 ];
222 let mut t = [0u32; 8];
223 for (i, e) in t.iter_mut().enumerate() {
224 *e = load_be(&IV, i * 4)
225 }
226 State(t)
227 }
228
229 #[inline(always)]
230 fn add(&mut self, x: &State) {
231 let sx = &mut self.0;
232 let ex = &x.0;
233 sx[0] = sx[0].wrapping_add(ex[0]);
234 sx[1] = sx[1].wrapping_add(ex[1]);
235 sx[2] = sx[2].wrapping_add(ex[2]);
236 sx[3] = sx[3].wrapping_add(ex[3]);
237 sx[4] = sx[4].wrapping_add(ex[4]);
238 sx[5] = sx[5].wrapping_add(ex[5]);
239 sx[6] = sx[6].wrapping_add(ex[6]);
240 sx[7] = sx[7].wrapping_add(ex[7]);
241 }
242
243 fn store(&self, out: &mut [u8]) {
244 for (i, &e) in self.0.iter().enumerate() {
245 store_be(out, i * 4, e);
246 }
247 }
248
249 fn blocks(&mut self, mut input: &[u8]) -> usize {
250 let mut t = *self;
251 let mut inlen = input.len();
252 while inlen >= 64 {
253 let mut w = W::new(input);
254 w.G(&mut t, 0);
255 w.expand();
256 w.G(&mut t, 1);
257 w.expand();
258 w.G(&mut t, 2);
259 w.expand();
260 w.G(&mut t, 3);
261 t.add(self);
262 self.0 = t.0;
263 input = &input[64..];
264 inlen -= 64;
265 }
266 inlen
267 }
268}
269
270#[derive(Copy, Clone)]
271pub struct Hash {
290 state: State,
291 w: [u8; 64],
292 r: usize,
293 len: usize,
294}
295
296impl Hash {
297 pub fn new() -> Hash {
299 Hash {
300 state: State::new(),
301 r: 0,
302 w: [0u8; 64],
303 len: 0,
304 }
305 }
306
307 fn _update(&mut self, input: impl AsRef<[u8]>) {
308 let input = input.as_ref();
309 let mut n = input.len();
310 self.len += n;
311 let av = 64 - self.r;
312 let tc = ::core::cmp::min(n, av);
313 self.w[self.r..self.r + tc].copy_from_slice(&input[0..tc]);
314 self.r += tc;
315 n -= tc;
316 let pos = tc;
317 if self.r == 64 {
318 self.state.blocks(&self.w);
319 self.r = 0;
320 }
321 if self.r == 0 && n > 0 {
322 let rb = self.state.blocks(&input[pos..]);
323 if rb > 0 {
324 self.w[..rb].copy_from_slice(&input[pos + n - rb..]);
325 self.r = rb;
326 }
327 }
328 }
329
330 pub fn update(&mut self, input: impl AsRef<[u8]>) {
343 self._update(input)
344 }
345
346 pub fn finalize(mut self) -> [u8; 32] {
358 let mut padded = [0u8; 128];
359 padded[..self.r].copy_from_slice(&self.w[..self.r]);
360 padded[self.r] = 0x80;
361 let r = if self.r < 56 { 64 } else { 128 };
362 let bits = self.len * 8;
363 for i in 0..8 {
364 padded[r - 8 + i] = (bits as u64 >> (56 - i * 8)) as u8;
365 }
366 self.state.blocks(&padded[..r]);
367 let mut out = [0u8; 32];
368 self.state.store(&mut out);
369 out
370 }
371
372 pub fn finalize_verify(self, expected: &[u8; 32]) -> bool {
390 let out = self.finalize();
391 verify(&out, expected)
392 }
393
394 pub fn verify(input: impl AsRef<[u8]>, expected: &[u8; 32]) -> bool {
409 let hash = Self::hash(input.as_ref());
410 verify(&hash, expected)
411 }
412
413 pub fn verify_with_ref(self, expected: &[u8]) -> bool {
447 if expected.len() != 32 {
448 return false;
449 }
450 let out = self.finalize();
451 verify(&out, expected)
452 }
453
454 pub fn hash(input: &[u8]) -> [u8; 32] {
464 let mut h = Hash::new();
465 h.update(input);
466 h.finalize()
467 }
468}
469
470impl Default for Hash {
471 fn default() -> Self {
472 Self::new()
473 }
474}
475
476#[derive(Clone)]
477pub struct HMAC {
496 ih: Hash,
497 padded: [u8; 64],
498}
499
500impl HMAC {
501 pub fn mac(input: impl AsRef<[u8]>, k: impl AsRef<[u8]>) -> [u8; 32] {
520 let input = input.as_ref();
521 let k = k.as_ref();
522 let mut hk = [0u8; 32];
523 let k2 = if k.len() > 64 {
524 hk.copy_from_slice(&Hash::hash(k));
525 &hk
526 } else {
527 k
528 };
529 let mut padded = [0x36; 64];
530 for (p, &k) in padded.iter_mut().zip(k2.iter()) {
531 *p ^= k;
532 }
533 let mut ih = Hash::new();
534 ih.update(&padded[..]);
535 ih.update(input);
536
537 for p in padded.iter_mut() {
538 *p ^= 0x6a;
539 }
540 let mut oh = Hash::new();
541 oh.update(&padded[..]);
542 oh.update(ih.finalize());
543 oh.finalize()
544 }
545
546 pub fn new(k: impl AsRef<[u8]>) -> HMAC {
558 let k = k.as_ref();
559 let mut hk = [0u8; 32];
560 let k2 = if k.len() > 64 {
561 hk.copy_from_slice(&Hash::hash(k));
562 &hk
563 } else {
564 k
565 };
566 let mut padded = [0x36; 64];
567 for (p, &k) in padded.iter_mut().zip(k2.iter()) {
568 *p ^= k;
569 }
570 let mut ih = Hash::new();
571 ih.update(&padded[..]);
572 HMAC { ih, padded }
573 }
574
575 pub fn update(&mut self, input: impl AsRef<[u8]>) {
588 self.ih.update(input);
589 }
590
591 pub fn finalize(mut self) -> [u8; 32] {
603 for p in self.padded.iter_mut() {
604 *p ^= 0x6a;
605 }
606 let mut oh = Hash::new();
607 oh.update(&self.padded[..]);
608 oh.update(self.ih.finalize());
609 oh.finalize()
610 }
611
612 pub fn finalize_verify(self, expected: &[u8; 32]) -> bool {
630 let out = self.finalize();
631 verify(&out, expected)
632 }
633
634 pub fn verify(input: impl AsRef<[u8]>, k: impl AsRef<[u8]>, expected: &[u8; 32]) -> bool {
659 let mac = Self::mac(input, k);
660 verify(&mac, expected)
661 }
662}
663
664pub struct HKDF;
685
686impl HKDF {
687 pub fn extract(salt: impl AsRef<[u8]>, ikm: impl AsRef<[u8]>) -> [u8; 32] {
706 HMAC::mac(ikm, salt)
707 }
708
709 pub fn expand(out: &mut [u8], prk: impl AsRef<[u8]>, info: impl AsRef<[u8]>) {
731 let info = info.as_ref();
732 let mut counter: u8 = 1;
733 assert!(out.len() < 0xff * 32);
734 let mut i: usize = 0;
735 while i < out.len() {
736 let mut hmac = HMAC::new(&prk);
737 if i != 0 {
738 hmac.update(&out[i - 32..][..32]);
739 }
740 hmac.update(info);
741 hmac.update([counter]);
742 let left = core::cmp::min(32, out.len() - i);
743 out[i..][..left].copy_from_slice(&hmac.finalize()[..left]);
744 counter += 1;
745 i += 32;
746 }
747 }
748}
749
750#[cfg(feature = "traits010")]
752pub type WrappedHash = digest010::core_api::CoreWrapper<Hash>;
753
754
755#[cfg(feature = "traits010")]
756mod digest_trait010 {
757 use core::fmt;
758
759 use digest010::{
760 block_buffer::Eager,
761 const_oid::{AssociatedOid, ObjectIdentifier},
762 consts::{U32, U64},
763 core_api::{
764 AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, FixedOutputCore,
765 OutputSizeUser, Reset, UpdateCore,
766 },
767 FixedOutput, FixedOutputReset, HashMarker, Output, Update,
768 };
769
770 use super::Hash;
771
772 impl AssociatedOid for Hash {
773 const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.1");
774 }
775
776 impl AlgorithmName for Hash {
777 fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
778 f.write_str("Sha256")
779 }
780 }
781
782 impl HashMarker for Hash {}
783
784 impl BufferKindUser for Hash {
785 type BufferKind = Eager;
786 }
787
788 impl BlockSizeUser for Hash {
789 type BlockSize = U64;
790 }
791
792 impl OutputSizeUser for Hash {
793 type OutputSize = U32;
794 }
795
796 impl UpdateCore for Hash {
797 #[inline]
798 fn update_blocks(&mut self, blocks: &[Block<Self>]) {
799 for block in blocks {
800 self._update(block);
801 }
802 }
803 }
804
805 impl Update for Hash {
806 #[inline]
807 fn update(&mut self, data: &[u8]) {
808 self._update(data);
809 }
810 }
811
812 impl FixedOutputCore for Hash {
813 fn finalize_fixed_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
814 self._update(buffer.get_data());
815 self.finalize_into(out);
816 }
817 }
818
819 impl FixedOutput for Hash {
820 fn finalize_into(self, out: &mut Output<Self>) {
821 let h = self.finalize();
822 out.copy_from_slice(&h);
823 }
824 }
825
826 impl Reset for Hash {
827 fn reset(&mut self) {
828 *self = Self::new()
829 }
830 }
831
832 impl FixedOutputReset for Hash {
833 fn finalize_into_reset(&mut self, out: &mut Output<Self>) {
834 self.finalize_into(out);
835 self.reset();
836 }
837 }
838}
839
840#[cfg(feature = "traits09")]
841mod digest_trait09 {
842 use digest09::consts::{U32, U64};
843 use digest09::{BlockInput, FixedOutputDirty, Output, Reset, Update};
844
845 use super::Hash;
846
847 impl BlockInput for Hash {
848 type BlockSize = U64;
849 }
850
851 impl Update for Hash {
852 fn update(&mut self, input: impl AsRef<[u8]>) {
853 self._update(input)
854 }
855 }
856
857 impl FixedOutputDirty for Hash {
858 type OutputSize = U32;
859
860 fn finalize_into_dirty(&mut self, out: &mut Output<Self>) {
861 let h = self.finalize();
862 out.copy_from_slice(&h);
863 }
864 }
865
866 impl Reset for Hash {
867 fn reset(&mut self) {
868 *self = Self::new()
869 }
870 }
871}
872
873#[cfg(feature = "traits011")]
874mod digest_trait011 {
875 use digest011::{
876 const_oid::{AssociatedOid, ObjectIdentifier},
877 consts::U32,
878 FixedOutput, FixedOutputReset, HashMarker, Output, OutputSizeUser, Reset, Update,
879 };
880
881 use super::Hash;
882
883 impl AssociatedOid for Hash {
884 const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.1");
885 }
886
887 impl HashMarker for Hash {}
888
889 impl OutputSizeUser for Hash {
890 type OutputSize = U32;
891 }
892
893 impl Update for Hash {
894 #[inline]
895 fn update(&mut self, data: &[u8]) {
896 self._update(data);
897 }
898 }
899
900 impl FixedOutput for Hash {
901 fn finalize_into(self, out: &mut Output<Self>) {
902 let h = self.finalize();
903 out.copy_from_slice(&h);
904 }
905 }
906
907 impl Reset for Hash {
908 fn reset(&mut self) {
909 *self = Self::new()
910 }
911 }
912
913 impl FixedOutputReset for Hash {
914 fn finalize_into_reset(&mut self, out: &mut Output<Self>) {
915 let h = self.finalize();
916 out.copy_from_slice(&h);
917 self.reset();
918 }
919 }
920}
921
922#[test]
923fn main() {
924 let h = HMAC::mac([], [0u8; 32]);
925 assert_eq!(
926 &h[..],
927 &[
928 182, 19, 103, 154, 8, 20, 217, 236, 119, 47, 149, 215, 120, 195, 95, 197, 255, 22, 151,
929 196, 147, 113, 86, 83, 198, 199, 18, 20, 66, 146, 197, 173
930 ]
931 );
932
933 let h = HMAC::mac([42u8; 69], []);
934 assert_eq!(
935 &h[..],
936 &[
937 225, 88, 35, 8, 78, 185, 165, 6, 235, 124, 28, 250, 112, 124, 159, 119, 159, 88, 184,
938 61, 7, 37, 166, 229, 71, 154, 83, 153, 151, 181, 182, 72
939 ]
940 );
941
942 let h = HMAC::mac([69u8; 250], [42u8; 50]);
943 assert_eq!(
944 &h[..],
945 &[
946 112, 156, 120, 216, 86, 25, 79, 210, 155, 193, 32, 120, 116, 134, 237, 14, 198, 1, 64,
947 41, 124, 196, 103, 91, 109, 216, 36, 133, 4, 234, 218, 228
948 ]
949 );
950
951 let mut s = HMAC::new([42u8; 50]);
952 s.update([69u8; 150]);
953 s.update([69u8; 100]);
954 let h = s.finalize();
955 assert_eq!(
956 &h[..],
957 &[
958 112, 156, 120, 216, 86, 25, 79, 210, 155, 193, 32, 120, 116, 134, 237, 14, 198, 1, 64,
959 41, 124, 196, 103, 91, 109, 216, 36, 133, 4, 234, 218, 228
960 ]
961 );
962
963 let expected_mac = HMAC::mac([69u8; 250], [42u8; 50]);
965 let mut hmac = HMAC::new([42u8; 50]);
966 hmac.update([69u8; 250]);
967 assert!(hmac.finalize_verify(&expected_mac));
968
969 let mut hmac = HMAC::new([42u8; 50]);
970 hmac.update([69u8; 251]); assert!(!hmac.finalize_verify(&expected_mac));
972
973 assert!(HMAC::verify([69u8; 250], [42u8; 50], &expected_mac));
975 assert!(!HMAC::verify([69u8; 251], [42u8; 50], &expected_mac)); assert!(!HMAC::verify([69u8; 250], [43u8; 50], &expected_mac)); let expected_hash = Hash::hash(&[42u8; 123]);
980 assert!(Hash::verify(&[42u8; 123], &expected_hash));
981 assert!(!Hash::verify(&[42u8; 124], &expected_hash));
982
983 let mut hasher = Hash::new();
985 hasher.update(&[42u8; 123]);
986 assert!(hasher.finalize_verify(&expected_hash));
987
988 let mut hasher = Hash::new();
989 hasher.update(&[42u8; 124]); assert!(!hasher.finalize_verify(&expected_hash));
991
992 let ikm = [0x0bu8; 22];
993 let salt = [
994 0x00u8, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
995 ];
996 let context = [0xf0u8, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9];
997 let prk = HKDF::extract(salt, ikm);
998 let mut k = [0u8; 40];
999 HKDF::expand(&mut k, prk, context);
1000 assert_eq!(
1001 &k[..],
1002 &[
1003 60, 178, 95, 37, 250, 172, 213, 122, 144, 67, 79, 100, 208, 54, 47, 42, 45, 45, 10,
1004 144, 207, 26, 90, 76, 93, 176, 45, 86, 236, 196, 197, 191, 52, 0, 114, 8, 213, 184,
1005 135, 24
1006 ]
1007 );
1008}