snowbridge_amcl/
hash512.rs

1/*
2Licensed to the Apache Software Foundation (ASF) under one
3or more contributor license agreements.  See the NOTICE file
4distributed with this work for additional information
5regarding copyright ownership.  The ASF licenses this file
6to you under the Apache License, Version 2.0 (the
7"License"); you may not use this file except in compliance
8with the License.  You may obtain a copy of the License at
9
10  http://www.apache.org/licenses/LICENSE-2.0
11
12Unless required by applicable law or agreed to in writing,
13software distributed under the License is distributed on an
14"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15KIND, either express or implied.  See the License for the
16specific language governing permissions and limitations
17under the License.
18*/
19use crate::std::{vec, Vec};
20
21const HASH512_H0: u64 = 0x6a09e667f3bcc908;
22const HASH512_H1: u64 = 0xbb67ae8584caa73b;
23const HASH512_H2: u64 = 0x3c6ef372fe94f82b;
24const HASH512_H3: u64 = 0xa54ff53a5f1d36f1;
25const HASH512_H4: u64 = 0x510e527fade682d1;
26const HASH512_H5: u64 = 0x9b05688c2b3e6c1f;
27const HASH512_H6: u64 = 0x1f83d9abfb41bd6b;
28const HASH512_H7: u64 = 0x5be0cd19137e2179;
29
30const HASH512_K: [u64; 80] = [
31    0x428a2f98d728ae22,
32    0x7137449123ef65cd,
33    0xb5c0fbcfec4d3b2f,
34    0xe9b5dba58189dbbc,
35    0x3956c25bf348b538,
36    0x59f111f1b605d019,
37    0x923f82a4af194f9b,
38    0xab1c5ed5da6d8118,
39    0xd807aa98a3030242,
40    0x12835b0145706fbe,
41    0x243185be4ee4b28c,
42    0x550c7dc3d5ffb4e2,
43    0x72be5d74f27b896f,
44    0x80deb1fe3b1696b1,
45    0x9bdc06a725c71235,
46    0xc19bf174cf692694,
47    0xe49b69c19ef14ad2,
48    0xefbe4786384f25e3,
49    0x0fc19dc68b8cd5b5,
50    0x240ca1cc77ac9c65,
51    0x2de92c6f592b0275,
52    0x4a7484aa6ea6e483,
53    0x5cb0a9dcbd41fbd4,
54    0x76f988da831153b5,
55    0x983e5152ee66dfab,
56    0xa831c66d2db43210,
57    0xb00327c898fb213f,
58    0xbf597fc7beef0ee4,
59    0xc6e00bf33da88fc2,
60    0xd5a79147930aa725,
61    0x06ca6351e003826f,
62    0x142929670a0e6e70,
63    0x27b70a8546d22ffc,
64    0x2e1b21385c26c926,
65    0x4d2c6dfc5ac42aed,
66    0x53380d139d95b3df,
67    0x650a73548baf63de,
68    0x766a0abb3c77b2a8,
69    0x81c2c92e47edaee6,
70    0x92722c851482353b,
71    0xa2bfe8a14cf10364,
72    0xa81a664bbc423001,
73    0xc24b8b70d0f89791,
74    0xc76c51a30654be30,
75    0xd192e819d6ef5218,
76    0xd69906245565a910,
77    0xf40e35855771202a,
78    0x106aa07032bbd1b8,
79    0x19a4c116b8d2d0c8,
80    0x1e376c085141ab53,
81    0x2748774cdf8eeb99,
82    0x34b0bcb5e19b48a8,
83    0x391c0cb3c5c95a63,
84    0x4ed8aa4ae3418acb,
85    0x5b9cca4f7763e373,
86    0x682e6ff3d6b2b8a3,
87    0x748f82ee5defb2fc,
88    0x78a5636f43172f60,
89    0x84c87814a1f0ab72,
90    0x8cc702081a6439ec,
91    0x90befffa23631e28,
92    0xa4506cebde82bde9,
93    0xbef9a3f7b2c67915,
94    0xc67178f2e372532b,
95    0xca273eceea26619c,
96    0xd186b8c721c0c207,
97    0xeada7dd6cde0eb1e,
98    0xf57d4f7fee6ed178,
99    0x06f067aa72176fba,
100    0x0a637dc5a2c898a6,
101    0x113f9804bef90dae,
102    0x1b710b35131c471b,
103    0x28db77f523047d84,
104    0x32caab7b40c72493,
105    0x3c9ebe0a15c9bebc,
106    0x431d67c49c100d4c,
107    0x4cc5d4becb3e42b6,
108    0x597f299cfc657e2a,
109    0x5fcb6fab3ad6faec,
110    0x6c44198c4a475817,
111];
112
113/// The block size of each round.
114pub const BLOCK_SIZE: usize = 128;
115/// Hash Length in Bytes
116pub const HASH_BYTES: usize = 64;
117// Ipad Byte
118const IPAD_BYTE: u8 = 0x36;
119// Opad Byte
120const OPAD_BYTE: u8 = 0x5c;
121
122pub struct HASH512 {
123    length: [u64; 2],
124    h: [u64; 8],
125    w: [u64; 80],
126}
127
128impl HASH512 {
129    fn s(n: u64, x: u64) -> u64 {
130        return ((x) >> n) | ((x) << (64 - n));
131    }
132    fn r(n: u64, x: u64) -> u64 {
133        return (x) >> n;
134    }
135
136    fn ch(x: u64, y: u64, z: u64) -> u64 {
137        return (x & y) ^ (!(x) & z);
138    }
139
140    fn maj(x: u64, y: u64, z: u64) -> u64 {
141        return (x & y) ^ (x & z) ^ (y & z);
142    }
143
144    fn sig0(x: u64) -> u64 {
145        return Self::s(28, x) ^ Self::s(34, x) ^ Self::s(39, x);
146    }
147
148    fn sig1(x: u64) -> u64 {
149        return Self::s(14, x) ^ Self::s(18, x) ^ Self::s(41, x);
150    }
151
152    fn theta0(x: u64) -> u64 {
153        return Self::s(1, x) ^ Self::s(8, x) ^ Self::r(7, x);
154    }
155
156    fn theta1(x: u64) -> u64 {
157        return Self::s(19, x) ^ Self::s(61, x) ^ Self::r(6, x);
158    }
159
160    fn transform(&mut self) {
161        /* basic transformation step */
162        for j in 16..80 {
163            self.w[j] = Self::theta1(self.w[j - 2])
164                .wrapping_add(self.w[j - 7])
165                .wrapping_add(Self::theta0(self.w[j - 15]))
166                .wrapping_add(self.w[j - 16]);
167        }
168        let mut a = self.h[0];
169        let mut b = self.h[1];
170        let mut c = self.h[2];
171        let mut d = self.h[3];
172        let mut e = self.h[4];
173        let mut f = self.h[5];
174        let mut g = self.h[6];
175        let mut hh = self.h[7];
176        for j in 0..80 {
177            /* 64 times - mush it up */
178            let t1 = hh
179                .wrapping_add(Self::sig1(e))
180                .wrapping_add(Self::ch(e, f, g))
181                .wrapping_add(HASH512_K[j])
182                .wrapping_add(self.w[j]);
183            let t2 = Self::sig0(a).wrapping_add(Self::maj(a, b, c));
184            hh = g;
185            g = f;
186            f = e;
187            e = d.wrapping_add(t1);
188            d = c;
189            c = b;
190            b = a;
191            a = t1.wrapping_add(t2);
192        }
193        self.h[0] = self.h[0].wrapping_add(a);
194        self.h[1] = self.h[1].wrapping_add(b);
195        self.h[2] = self.h[2].wrapping_add(c);
196        self.h[3] = self.h[3].wrapping_add(d);
197        self.h[4] = self.h[4].wrapping_add(e);
198        self.h[5] = self.h[5].wrapping_add(f);
199        self.h[6] = self.h[6].wrapping_add(g);
200        self.h[7] = self.h[7].wrapping_add(hh);
201    }
202
203    /* Initialise Hash function */
204    pub fn init(&mut self) {
205        /* initialise */
206        for i in 0..64 {
207            self.w[i] = 0
208        }
209        self.length[0] = 0;
210        self.length[1] = 0;
211        self.h[0] = HASH512_H0;
212        self.h[1] = HASH512_H1;
213        self.h[2] = HASH512_H2;
214        self.h[3] = HASH512_H3;
215        self.h[4] = HASH512_H4;
216        self.h[5] = HASH512_H5;
217        self.h[6] = HASH512_H6;
218        self.h[7] = HASH512_H7;
219    }
220
221    pub fn new() -> Self {
222        let mut nh = Self {
223            length: [0; 2],
224            h: [0; 8],
225            w: [0; 80],
226        };
227        nh.init();
228        return nh;
229    }
230
231    /* process a single byte */
232    pub fn process(&mut self, byt: u8) {
233        /* process the next message byte */
234        let cnt = ((self.length[0] / 64) % 16) as usize;
235        self.w[cnt] <<= 8;
236        self.w[cnt] |= (byt & 0xFF) as u64;
237        self.length[0] += 8;
238        if self.length[0] == 0 {
239            self.length[1] += 1;
240            self.length[0] = 0
241        }
242        if (self.length[0] % 1024) == 0 {
243            self.transform()
244        }
245    }
246
247    /* process an array of bytes */
248
249    pub fn process_array(&mut self, b: &[u8]) {
250        for i in 0..b.len() {
251            self.process(b[i])
252        }
253    }
254
255    /* process a 32-bit integer */
256    pub fn process_num(&mut self, n: i32) {
257        self.process(((n >> 24) & 0xff) as u8);
258        self.process(((n >> 16) & 0xff) as u8);
259        self.process(((n >> 8) & 0xff) as u8);
260        self.process((n & 0xff) as u8);
261    }
262
263    /* Generate 64-byte Hash */
264    pub fn hash(&mut self) -> [u8; 64] {
265        /* pad message and finish - supply digest */
266        let mut digest: [u8; 64] = [0; 64];
267        let len0 = self.length[0];
268        let len1 = self.length[1];
269        self.process(0x80);
270        while (self.length[0] % 1024) != 896 {
271            self.process(0)
272        }
273        self.w[14] = len1;
274        self.w[15] = len0;
275        self.transform();
276        for i in 0..64 {
277            /* convert to bytes */
278            digest[i] = ((self.h[i / 8] >> (8 * (7 - i % 8))) & 0xff) as u8;
279        }
280        self.init();
281        return digest;
282    }
283
284    /// Generate a HMAC
285    ///
286    /// https://tools.ietf.org/html/rfc2104
287    pub fn hmac(key: &[u8], text: &[u8]) -> [u8; 64] {
288        let mut k = key.to_vec();
289
290        // Verify length of key < BLOCK_SIZE
291        if k.len() > BLOCK_SIZE {
292            // Reduce key to 64 bytes by hashing
293            let mut hash512 = Self::new();
294            hash512.init();
295            hash512.process_array(&k);
296            k = hash512.hash().to_vec();
297        }
298
299        // Prepare inner and outer paddings
300        // inner = (ipad XOR k)
301        // outer = (opad XOR k)
302        let mut inner = vec![IPAD_BYTE; BLOCK_SIZE];
303        let mut outer = vec![OPAD_BYTE; BLOCK_SIZE];
304        for (i, byte) in k.iter().enumerate() {
305            inner[i] = inner[i] ^ byte;
306            outer[i] = outer[i] ^ byte;
307        }
308
309        // Concatenate inner with text = (ipad XOR k || text)
310        inner.extend_from_slice(text);
311
312        // hash inner = H(ipad XOR k || text)
313        let mut hash512 = Self::new();
314        hash512.init();
315        hash512.process_array(&inner);
316        let inner = hash512.hash();
317
318        // Concatenate outer with hash of inner = (opad XOR k) || H(ipad XOR k || text)
319        outer.extend_from_slice(&inner);
320
321        // Final hash = H((opad XOR k) || H(ipad XOR k || text))
322        let mut hash512 = Self::new();
323        hash512.init();
324        hash512.process_array(&outer);
325        hash512.hash()
326    }
327
328    /// HKDF-Extract
329    ///
330    /// https://tools.ietf.org/html/rfc5869
331    pub fn hkdf_extract(salt: &[u8], ikm: &[u8]) -> [u8; HASH_BYTES] {
332        Self::hmac(salt, ikm)
333    }
334
335    /// HKDF-Extend
336    ///
337    /// https://tools.ietf.org/html/rfc5869
338    pub fn hkdf_extend(prk: &[u8], info: &[u8], l: u8) -> Vec<u8> {
339        // n = cieling(l / 64)
340        let mut n = l / (HASH_BYTES as u8);
341        if n * (HASH_BYTES as u8) < l {
342            n += 1;
343        }
344
345        let mut okm: Vec<u8> = vec![];
346        let mut previous = vec![]; // T(0) = []
347
348        for i in 0..n as usize {
349            // Concatenate (T(i) || info || i)
350            let mut text: Vec<u8> = previous;
351            text.extend_from_slice(info);
352            text.push((i + 1) as u8); // Note: i <= 254
353
354            // T(i+1) = HMAC(PRK, T(i) || info || i)
355            previous = Self::hmac(prk, &text).to_vec();
356            okm.extend_from_slice(&previous);
357        }
358
359        // Reduce length to size L
360        okm.resize(l as usize, 0);
361        okm
362    }
363}
364
365#[cfg(test)]
366mod tests {
367    use super::*;
368
369    #[test]
370    fn test_hash512_simple() {
371        let text = [0x01];
372        let mut hash512 = HASH512::new();
373        hash512.init();
374        hash512.process_array(&text);
375        let output = hash512.hash().to_vec();
376
377        let expected =
378            hex::decode("7b54b66836c1fbdd13d2441d9e1434dc62ca677fb68f5fe66a464baadecdbd00576f8d6b5ac3bcc80844b7d50b1cc6603444bbe7cfcf8fc0aa1ee3c636d9e339")
379                .unwrap();
380
381        assert_eq!(expected, output);
382    }
383
384    #[test]
385    fn test_hash512_empty() {
386        let text = [];
387        let mut hash512 = HASH512::new();
388        hash512.init();
389        hash512.process_array(&text);
390        let output = hash512.hash().to_vec();
391
392        let expected =
393            hex::decode("cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e")
394                .unwrap();
395
396        assert_eq!(expected, output);
397    }
398
399    #[test]
400    fn test_hash512_long() {
401        let text = hex::decode("cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e01").unwrap();
402        let mut hash512 = HASH512::new();
403        hash512.init();
404        hash512.process_array(&text);
405        let output = hash512.hash().to_vec();
406
407        let expected =
408            hex::decode("ca3088651246c66ac9c7a8afd727539ab2d8ce9234b5e1fec311e1e435d6d9eb152e41e8e9ad953dd737d0271ad2b0299cbd6f4eb9536de34c3a01411766c7be")
409                .unwrap();
410
411        assert_eq!(expected, output);
412    }
413
414    #[test]
415    fn test_hmac_simple() {
416        let text = [0x01];
417        let key = [0x01];
418        let expected =
419            hex::decode("503deb5732606d9595e308c8893fe56923fe470fc57021cf252dacb0ad15de020943e139d7a84e77956d34df3cc78142c090b959049a813cb19627c5b49c5761")
420                .unwrap();
421
422        let output = HASH512::hmac(&key, &text).to_vec();
423        assert_eq!(expected, output);
424    }
425
426    #[test]
427    fn test_hmac_empty() {
428        let text = [];
429        let key = [];
430        let expected =
431            hex::decode("b936cee86c9f87aa5d3c6f2e84cb5a4239a5fe50480a6ec66b70ab5b1f4ac6730c6c515421b327ec1d69402e53dfb49ad7381eb067b338fd7b0cb22247225d47")
432                .unwrap();
433
434        let output = HASH512::hmac(&key, &text).to_vec();
435        assert_eq!(expected, output);
436    }
437
438    #[test]
439    fn test_hmac_long() {
440        let text = hex::decode("cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e01").unwrap();
441        let key = [0x01];
442        let expected =
443            hex::decode("d4a8d1b936eb79e6f56b85306e62dea59a54e81690a616e804eaefe2b1e0d7319eecd68494913b3a7e78755a0e1716bb0f0f3b60a810c65f61a909562811d372")
444                .unwrap();
445
446        let output = HASH512::hmac(&key, &text).to_vec();
447        assert_eq!(expected, output);
448    }
449
450    #[test]
451    fn test_hkdf_case_a() {
452        // From https://www.kullo.net/blog/hkdf-sha-512-test-vectors/
453        let ikm = hex::decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").unwrap();
454        let salt = hex::decode("000102030405060708090a0b0c").unwrap();
455        let expected_prk =
456            hex::decode("665799823737ded04a88e47e54a5890bb2c3d247c7a4254a8e61350723590a26c36238127d8661b88cf80ef802d57e2f7cebcf1e00e083848be19929c61b4237")
457            .unwrap();
458
459        let output_prk = HASH512::hkdf_extract(&salt, &ikm).to_vec();
460        assert_eq!(expected_prk, output_prk);
461
462        let info = hex::decode("f0f1f2f3f4f5f6f7f8f9").unwrap();
463        let l = 42;
464        let expected_okm = hex::decode(
465            "832390086cda71fb47625bb5ceb168e4c8e26a1a16ed34d9fc7fe92c1481579338da362cb8d9f925d7cb",
466        )
467        .unwrap();
468
469        let output_okm = HASH512::hkdf_extend(&expected_prk, &info, l);
470        assert_eq!(expected_okm, output_okm);
471    }
472
473    #[test]
474    fn test_hkdf_case_b() {
475        // From https://www.kullo.net/blog/hkdf-sha-512-test-vectors/
476        let ikm = hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f").unwrap();
477        let salt = hex::decode("606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf").unwrap();
478        let expected_prk =
479            hex::decode("35672542907d4e142c00e84499e74e1de08be86535f924e022804ad775dde27ec86cd1e5b7d178c74489bdbeb30712beb82d4f97416c5a94ea81ebdf3e629e4a")
480            .unwrap();
481
482        let output_prk = HASH512::hkdf_extract(&salt, &ikm).to_vec();
483        assert_eq!(expected_prk, output_prk);
484
485        let info = hex::decode("b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff").unwrap();
486        let l = 82;
487        let expected_okm = hex::decode(
488                "ce6c97192805b346e6161e821ed165673b84f400a2b514b2fe23d84cd189ddf1b695b48cbd1c8388441137b3ce28f16aa64ba33ba466b24df6cfcb021ecff235f6a2056ce3af1de44d572097a8505d9e7a93",
489            )
490            .unwrap();
491
492        let output_okm = HASH512::hkdf_extend(&expected_prk, &info, l);
493        assert_eq!(expected_okm, output_okm);
494    }
495
496    #[test]
497    fn test_hkdf_case_c() {
498        // From https://www.kullo.net/blog/hkdf-sha-512-test-vectors/
499        let ikm = hex::decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").unwrap();
500        let salt = vec![];
501        let expected_prk =
502            hex::decode("fd200c4987ac491313bd4a2a13287121247239e11c9ef82802044b66ef357e5b194498d0682611382348572a7b1611de54764094286320578a863f36562b0df6")
503            .unwrap();
504
505        let output_prk = HASH512::hkdf_extract(&salt, &ikm).to_vec();
506        assert_eq!(expected_prk, output_prk);
507
508        let info = vec![];
509        let l = 42;
510        let expected_okm = hex::decode(
511            "f5fa02b18298a72a8c23898a8703472c6eb179dc204c03425c970e3b164bf90fff22d04836d0e2343bac",
512        )
513        .unwrap();
514
515        let output_okm = HASH512::hkdf_extend(&expected_prk, &info, l);
516        assert_eq!(expected_okm, output_okm);
517    }
518
519    #[test]
520    fn test_hkdf_case_d() {
521        // From https://www.kullo.net/blog/hkdf-sha-512-test-vectors/
522        let ikm = hex::decode("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c").unwrap();
523        let salt = vec![];
524        let expected_prk =
525            hex::decode("5346b376bf3aa9f84f8f6ed5b1c4f489172e244dac303d12f68ecc766ea600aa88495e7fb605803122fa136924a840b1f0719d2d5f68e29b242299d758ed680c")
526            .unwrap();
527
528        let output_prk = HASH512::hkdf_extract(&salt, &ikm).to_vec();
529        assert_eq!(expected_prk, output_prk);
530
531        let info = vec![];
532        let l = 42;
533        let expected_okm = hex::decode(
534            "1407d46013d98bc6decefcfee55f0f90b0c7f63d68eb1a80eaf07e953cfc0a3a5240a155d6e4daa965bb",
535        )
536        .unwrap();
537
538        let output_okm = HASH512::hkdf_extend(&expected_prk, &info, l);
539        assert_eq!(expected_okm, output_okm);
540    }
541}