| // Copyright 2023 The Wuffs Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
| // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your |
| // option. This file may not be copied, modified, or distributed |
| // except according to those terms. |
| // |
| // SPDX-License-Identifier: Apache-2.0 OR MIT |
| |
| // INITIAL_SHA256_H comes from section "5.3.3 SHA-256" of |
| // https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf |
| pri const INITIAL_SHA256_H : roarray[8] base.u32 = [ |
| 0x6A09_E667, 0xBB67_AE85, 0x3C6E_F372, 0xA54F_F53A, |
| 0x510E_527F, 0x9B05_688C, 0x1F83_D9AB, 0x5BE0_CD19, |
| ] |
| |
| // K comes from section "4.2.2 SHA-224 and SHA-256 Constants" of |
| // https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf |
| pri const K : roarray[64] base.u32 = [ |
| 0x428A_2F98, 0x7137_4491, 0xB5C0_FBCF, 0xE9B5_DBA5, |
| 0x3956_C25B, 0x59F1_11F1, 0x923F_82A4, 0xAB1C_5ED5, |
| 0xD807_AA98, 0x1283_5B01, 0x2431_85BE, 0x550C_7DC3, |
| 0x72BE_5D74, 0x80DE_B1FE, 0x9BDC_06A7, 0xC19B_F174, |
| 0xE49B_69C1, 0xEFBE_4786, 0x0FC1_9DC6, 0x240C_A1CC, |
| 0x2DE9_2C6F, 0x4A74_84AA, 0x5CB0_A9DC, 0x76F9_88DA, |
| 0x983E_5152, 0xA831_C66D, 0xB003_27C8, 0xBF59_7FC7, |
| 0xC6E0_0BF3, 0xD5A7_9147, 0x06CA_6351, 0x1429_2967, |
| 0x27B7_0A85, 0x2E1B_2138, 0x4D2C_6DFC, 0x5338_0D13, |
| 0x650A_7354, 0x766A_0ABB, 0x81C2_C92E, 0x9272_2C85, |
| 0xA2BF_E8A1, 0xA81A_664B, 0xC24B_8B70, 0xC76C_51A3, |
| 0xD192_E819, 0xD699_0624, 0xF40E_3585, 0x106A_A070, |
| 0x19A4_C116, 0x1E37_6C08, 0x2748_774C, 0x34B0_BCB5, |
| 0x391C_0CB3, 0x4ED8_AA4A, 0x5B9C_CA4F, 0x682E_6FF3, |
| 0x748F_82EE, 0x78A5_636F, 0x84C8_7814, 0x8CC7_0208, |
| 0x90BE_FFFA, 0xA450_6CEB, 0xBEF9_A3F7, 0xC671_78F2, |
| ] |
| |
| pub struct hasher? implements base.hasher_bitvec256( |
| length_modulo_u64 : base.u64, |
| length_overflows_u64 : base.bool, |
| |
| padding0 : base.u8, |
| padding1 : base.u8, |
| padding2 : base.u8, |
| |
| buf_len : base.u32[..= 64], |
| buf_data : array[64] base.u8, |
| |
| h0 : base.u32, |
| h1 : base.u32, |
| h2 : base.u32, |
| h3 : base.u32, |
| h4 : base.u32, |
| h5 : base.u32, |
| h6 : base.u32, |
| h7 : base.u32, |
| |
| util : base.utility, |
| ) |
| |
| pub func hasher.get_quirk(key: base.u32) base.u64 { |
| return 0 |
| } |
| |
| pub func hasher.set_quirk!(key: base.u32, value: base.u64) base.status { |
| return base."#unsupported option" |
| } |
| |
| pub func hasher.update!(x: roslice base.u8) { |
| var new_lmu : base.u64 |
| |
| if (this.length_modulo_u64 == 0) and not this.length_overflows_u64 { |
| this.h0 = INITIAL_SHA256_H[0] |
| this.h1 = INITIAL_SHA256_H[1] |
| this.h2 = INITIAL_SHA256_H[2] |
| this.h3 = INITIAL_SHA256_H[3] |
| this.h4 = INITIAL_SHA256_H[4] |
| this.h5 = INITIAL_SHA256_H[5] |
| this.h6 = INITIAL_SHA256_H[6] |
| this.h7 = INITIAL_SHA256_H[7] |
| } |
| |
| new_lmu = this.length_modulo_u64 ~mod+ args.x.length() |
| this.length_overflows_u64 = (new_lmu < this.length_modulo_u64) or this.length_overflows_u64 |
| this.length_modulo_u64 = new_lmu |
| |
| // Align to a block boundary before calling this.up. |
| if this.buf_len <> 0 { |
| while this.buf_len < 64 { |
| if args.x.length() <= 0 { |
| return nothing |
| } |
| this.buf_data[this.buf_len] = args.x[0] |
| this.buf_len += 1 |
| args.x = args.x[1 ..] |
| } |
| this.buf_len = 0 |
| this.up!(x: this.buf_data[..]) |
| } |
| |
| this.up!(x: args.x) |
| } |
| |
| pub func hasher.update_bitvec256!(x: roslice base.u8) base.bitvec256 { |
| this.update!(x: args.x) |
| return this.checksum_bitvec256() |
| } |
| |
| pri func hasher.up!(x: roslice base.u8) { |
| var p : roslice base.u8 |
| |
| var w : array[64] base.u32 |
| |
| var w2 : base.u32 |
| var w15 : base.u32 |
| var s0 : base.u32 |
| var s1 : base.u32 |
| var t1 : base.u32 |
| var t2 : base.u32 |
| |
| var a : base.u32 |
| var b : base.u32 |
| var c : base.u32 |
| var d : base.u32 |
| var e : base.u32 |
| var f : base.u32 |
| var g : base.u32 |
| var h : base.u32 |
| |
| var i : base.u32 |
| |
| var buf_len : base.u32[..= 63] |
| |
| a = this.h0 |
| b = this.h1 |
| c = this.h2 |
| d = this.h3 |
| e = this.h4 |
| f = this.h5 |
| g = this.h6 |
| h = this.h7 |
| |
| iterate (p = args.x)(length: 64, advance: 64, unroll: 1) { |
| w[0x00] = ((p[0x00] as base.u32) << 24) | ((p[0x01] as base.u32) << 16) | |
| ((p[0x02] as base.u32) << 8) | ((p[0x03] as base.u32)) |
| w[0x01] = ((p[0x04] as base.u32) << 24) | ((p[0x05] as base.u32) << 16) | |
| ((p[0x06] as base.u32) << 8) | ((p[0x07] as base.u32)) |
| w[0x02] = ((p[0x08] as base.u32) << 24) | ((p[0x09] as base.u32) << 16) | |
| ((p[0x0A] as base.u32) << 8) | ((p[0x0B] as base.u32)) |
| w[0x03] = ((p[0x0C] as base.u32) << 24) | ((p[0x0D] as base.u32) << 16) | |
| ((p[0x0E] as base.u32) << 8) | ((p[0x0F] as base.u32)) |
| w[0x04] = ((p[0x10] as base.u32) << 24) | ((p[0x11] as base.u32) << 16) | |
| ((p[0x12] as base.u32) << 8) | ((p[0x13] as base.u32)) |
| w[0x05] = ((p[0x14] as base.u32) << 24) | ((p[0x15] as base.u32) << 16) | |
| ((p[0x16] as base.u32) << 8) | ((p[0x17] as base.u32)) |
| w[0x06] = ((p[0x18] as base.u32) << 24) | ((p[0x19] as base.u32) << 16) | |
| ((p[0x1A] as base.u32) << 8) | ((p[0x1B] as base.u32)) |
| w[0x07] = ((p[0x1C] as base.u32) << 24) | ((p[0x1D] as base.u32) << 16) | |
| ((p[0x1E] as base.u32) << 8) | ((p[0x1F] as base.u32)) |
| w[0x08] = ((p[0x20] as base.u32) << 24) | ((p[0x21] as base.u32) << 16) | |
| ((p[0x22] as base.u32) << 8) | ((p[0x23] as base.u32)) |
| w[0x09] = ((p[0x24] as base.u32) << 24) | ((p[0x25] as base.u32) << 16) | |
| ((p[0x26] as base.u32) << 8) | ((p[0x27] as base.u32)) |
| w[0x0A] = ((p[0x28] as base.u32) << 24) | ((p[0x29] as base.u32) << 16) | |
| ((p[0x2A] as base.u32) << 8) | ((p[0x2B] as base.u32)) |
| w[0x0B] = ((p[0x2C] as base.u32) << 24) | ((p[0x2D] as base.u32) << 16) | |
| ((p[0x2E] as base.u32) << 8) | ((p[0x2F] as base.u32)) |
| w[0x0C] = ((p[0x30] as base.u32) << 24) | ((p[0x31] as base.u32) << 16) | |
| ((p[0x32] as base.u32) << 8) | ((p[0x33] as base.u32)) |
| w[0x0D] = ((p[0x34] as base.u32) << 24) | ((p[0x35] as base.u32) << 16) | |
| ((p[0x36] as base.u32) << 8) | ((p[0x37] as base.u32)) |
| w[0x0E] = ((p[0x38] as base.u32) << 24) | ((p[0x39] as base.u32) << 16) | |
| ((p[0x3A] as base.u32) << 8) | ((p[0x3B] as base.u32)) |
| w[0x0F] = ((p[0x3C] as base.u32) << 24) | ((p[0x3D] as base.u32) << 16) | |
| ((p[0x3E] as base.u32) << 8) | ((p[0x3F] as base.u32)) |
| |
| i = 16 |
| while i < 64, |
| inv i >= 16, |
| { |
| w2 = w[i - 2] |
| s1 = (w2 >> 10) ^ |
| ((w2 ~mod<< 15) | (w2 >> 17)) ^ |
| ((w2 ~mod<< 13) | (w2 >> 19)) |
| w15 = w[i - 15] |
| s0 = (w15 >> 3) ^ |
| ((w15 ~mod<< 25) | (w15 >> 7)) ^ |
| ((w15 ~mod<< 14) | (w15 >> 18)) |
| w[i] = ((s1 ~mod+ w[i - 7]) ~mod+ s0) ~mod+ w[i - 16] |
| i += 1 |
| } |
| |
| i = 0 |
| while i < 64 { |
| t1 = h |
| t1 ~mod+= ((e ~mod<< 26) | (e >> 6)) ^ |
| ((e ~mod<< 21) | (e >> 11)) ^ |
| ((e ~mod<< 7) | (e >> 25)) |
| t1 ~mod+= (e & f) ^ ((0xFFFF_FFFF ^ e) & g) |
| t1 ~mod+= K[i] |
| t1 ~mod+= w[i] |
| |
| t2 = ((a ~mod<< 30) | (a >> 2)) ^ |
| ((a ~mod<< 19) | (a >> 13)) ^ |
| ((a ~mod<< 10) | (a >> 22)) |
| t2 ~mod+= (a & b) ^ (a & c) ^ (b & c) |
| |
| h = g |
| g = f |
| f = e |
| e = d ~mod+ t1 |
| d = c |
| c = b |
| b = a |
| a = t1 ~mod+ t2 |
| |
| i += 1 |
| } |
| |
| a ~mod+= this.h0 |
| this.h0 = a |
| b ~mod+= this.h1 |
| this.h1 = b |
| c ~mod+= this.h2 |
| this.h2 = c |
| d ~mod+= this.h3 |
| this.h3 = d |
| e ~mod+= this.h4 |
| this.h4 = e |
| f ~mod+= this.h5 |
| this.h5 = f |
| g ~mod+= this.h6 |
| this.h6 = g |
| h ~mod+= this.h7 |
| this.h7 = h |
| |
| } else (length: 1, advance: 1, unroll: 1) { |
| this.buf_data[buf_len] = p[0] |
| buf_len = (buf_len + 1) & 63 |
| } |
| this.buf_len = (args.x.length() & 63) as base.u32 |
| } |
| |
| pub func hasher.checksum_bitvec256() base.bitvec256 { |
| var buf_len : base.u32[..= 64] |
| var buf_data : array[64] base.u8 |
| |
| var length_in_bits : base.u64 |
| |
| var w : array[64] base.u32 |
| |
| var w2 : base.u32 |
| var w15 : base.u32 |
| var s0 : base.u32 |
| var s1 : base.u32 |
| var t1 : base.u32 |
| var t2 : base.u32 |
| |
| var h0 : base.u32 |
| var h1 : base.u32 |
| var h2 : base.u32 |
| var h3 : base.u32 |
| var h4 : base.u32 |
| var h5 : base.u32 |
| var h6 : base.u32 |
| var h7 : base.u32 |
| |
| var a : base.u32 |
| var b : base.u32 |
| var c : base.u32 |
| var d : base.u32 |
| var e : base.u32 |
| var f : base.u32 |
| var g : base.u32 |
| var h : base.u32 |
| |
| var i : base.u32 |
| |
| var final_block : base.bool |
| |
| i = 0 |
| while i < 64 { |
| buf_data[i] = this.buf_data[i] |
| i += 1 |
| } |
| |
| // Pad with a 1 bit and then zero or more 0 bits, until we're at 56 bytes |
| // (448 bits), modulo 64 bytes (512 bits). |
| buf_len = this.buf_len & 63 |
| if buf_len < 56 { |
| buf_data[buf_len] = 0x80 |
| buf_len += 1 |
| while buf_len < 56 { |
| buf_data[buf_len] = 0x00 |
| buf_len += 1 |
| } |
| final_block = true |
| |
| } else { |
| assert buf_len <= 63 |
| buf_data[buf_len] = 0x80 |
| buf_len += 1 |
| while buf_len < 64 { |
| buf_data[buf_len] = 0x00 |
| buf_len += 1 |
| } |
| } |
| |
| h0 = this.h0 |
| a = h0 |
| h1 = this.h1 |
| b = h1 |
| h2 = this.h2 |
| c = h2 |
| h3 = this.h3 |
| d = h3 |
| h4 = this.h4 |
| e = h4 |
| h5 = this.h5 |
| f = h5 |
| h6 = this.h6 |
| g = h6 |
| h7 = this.h7 |
| h = h7 |
| |
| while true { |
| if final_block { |
| // The final block ends with the total length (in bits). |
| length_in_bits = this.length_modulo_u64 ~mod* 8 |
| buf_data[56] = ((length_in_bits >> 56) & 0xFF) as base.u8 |
| buf_data[57] = ((length_in_bits >> 48) & 0xFF) as base.u8 |
| buf_data[58] = ((length_in_bits >> 40) & 0xFF) as base.u8 |
| buf_data[59] = ((length_in_bits >> 32) & 0xFF) as base.u8 |
| buf_data[60] = ((length_in_bits >> 24) & 0xFF) as base.u8 |
| buf_data[61] = ((length_in_bits >> 16) & 0xFF) as base.u8 |
| buf_data[62] = ((length_in_bits >> 8) & 0xFF) as base.u8 |
| buf_data[63] = ((length_in_bits) & 0xFF) as base.u8 |
| } |
| |
| w[0x00] = ((buf_data[0x00] as base.u32) << 24) | ((buf_data[0x01] as base.u32) << 16) | |
| ((buf_data[0x02] as base.u32) << 8) | ((buf_data[0x03] as base.u32)) |
| w[0x01] = ((buf_data[0x04] as base.u32) << 24) | ((buf_data[0x05] as base.u32) << 16) | |
| ((buf_data[0x06] as base.u32) << 8) | ((buf_data[0x07] as base.u32)) |
| w[0x02] = ((buf_data[0x08] as base.u32) << 24) | ((buf_data[0x09] as base.u32) << 16) | |
| ((buf_data[0x0A] as base.u32) << 8) | ((buf_data[0x0B] as base.u32)) |
| w[0x03] = ((buf_data[0x0C] as base.u32) << 24) | ((buf_data[0x0D] as base.u32) << 16) | |
| ((buf_data[0x0E] as base.u32) << 8) | ((buf_data[0x0F] as base.u32)) |
| w[0x04] = ((buf_data[0x10] as base.u32) << 24) | ((buf_data[0x11] as base.u32) << 16) | |
| ((buf_data[0x12] as base.u32) << 8) | ((buf_data[0x13] as base.u32)) |
| w[0x05] = ((buf_data[0x14] as base.u32) << 24) | ((buf_data[0x15] as base.u32) << 16) | |
| ((buf_data[0x16] as base.u32) << 8) | ((buf_data[0x17] as base.u32)) |
| w[0x06] = ((buf_data[0x18] as base.u32) << 24) | ((buf_data[0x19] as base.u32) << 16) | |
| ((buf_data[0x1A] as base.u32) << 8) | ((buf_data[0x1B] as base.u32)) |
| w[0x07] = ((buf_data[0x1C] as base.u32) << 24) | ((buf_data[0x1D] as base.u32) << 16) | |
| ((buf_data[0x1E] as base.u32) << 8) | ((buf_data[0x1F] as base.u32)) |
| w[0x08] = ((buf_data[0x20] as base.u32) << 24) | ((buf_data[0x21] as base.u32) << 16) | |
| ((buf_data[0x22] as base.u32) << 8) | ((buf_data[0x23] as base.u32)) |
| w[0x09] = ((buf_data[0x24] as base.u32) << 24) | ((buf_data[0x25] as base.u32) << 16) | |
| ((buf_data[0x26] as base.u32) << 8) | ((buf_data[0x27] as base.u32)) |
| w[0x0A] = ((buf_data[0x28] as base.u32) << 24) | ((buf_data[0x29] as base.u32) << 16) | |
| ((buf_data[0x2A] as base.u32) << 8) | ((buf_data[0x2B] as base.u32)) |
| w[0x0B] = ((buf_data[0x2C] as base.u32) << 24) | ((buf_data[0x2D] as base.u32) << 16) | |
| ((buf_data[0x2E] as base.u32) << 8) | ((buf_data[0x2F] as base.u32)) |
| w[0x0C] = ((buf_data[0x30] as base.u32) << 24) | ((buf_data[0x31] as base.u32) << 16) | |
| ((buf_data[0x32] as base.u32) << 8) | ((buf_data[0x33] as base.u32)) |
| w[0x0D] = ((buf_data[0x34] as base.u32) << 24) | ((buf_data[0x35] as base.u32) << 16) | |
| ((buf_data[0x36] as base.u32) << 8) | ((buf_data[0x37] as base.u32)) |
| w[0x0E] = ((buf_data[0x38] as base.u32) << 24) | ((buf_data[0x39] as base.u32) << 16) | |
| ((buf_data[0x3A] as base.u32) << 8) | ((buf_data[0x3B] as base.u32)) |
| w[0x0F] = ((buf_data[0x3C] as base.u32) << 24) | ((buf_data[0x3D] as base.u32) << 16) | |
| ((buf_data[0x3E] as base.u32) << 8) | ((buf_data[0x3F] as base.u32)) |
| |
| i = 16 |
| while i < 64, |
| inv i >= 16, |
| { |
| w2 = w[i - 2] |
| s1 = (w2 >> 10) ^ |
| ((w2 ~mod<< 15) | (w2 >> 17)) ^ |
| ((w2 ~mod<< 13) | (w2 >> 19)) |
| w15 = w[i - 15] |
| s0 = (w15 >> 3) ^ |
| ((w15 ~mod<< 25) | (w15 >> 7)) ^ |
| ((w15 ~mod<< 14) | (w15 >> 18)) |
| w[i] = ((s1 ~mod+ w[i - 7]) ~mod+ s0) ~mod+ w[i - 16] |
| i += 1 |
| } |
| |
| i = 0 |
| while i < 64 { |
| t1 = h |
| t1 ~mod+= ((e ~mod<< 26) | (e >> 6)) ^ |
| ((e ~mod<< 21) | (e >> 11)) ^ |
| ((e ~mod<< 7) | (e >> 25)) |
| t1 ~mod+= (e & f) ^ ((0xFFFF_FFFF ^ e) & g) |
| t1 ~mod+= K[i] |
| t1 ~mod+= w[i] |
| |
| t2 = ((a ~mod<< 30) | (a >> 2)) ^ |
| ((a ~mod<< 19) | (a >> 13)) ^ |
| ((a ~mod<< 10) | (a >> 22)) |
| t2 ~mod+= (a & b) ^ (a & c) ^ (b & c) |
| |
| h = g |
| g = f |
| f = e |
| e = d ~mod+ t1 |
| d = c |
| c = b |
| b = a |
| a = t1 ~mod+ t2 |
| |
| i += 1 |
| } |
| |
| a ~mod+= h0 |
| b ~mod+= h1 |
| c ~mod+= h2 |
| d ~mod+= h3 |
| e ~mod+= h4 |
| f ~mod+= h5 |
| g ~mod+= h6 |
| h ~mod+= h7 |
| |
| if final_block { |
| break |
| } |
| final_block = true |
| |
| h0 = a |
| h1 = b |
| h2 = c |
| h3 = d |
| h4 = e |
| h5 = f |
| h6 = g |
| h7 = h |
| |
| buf_len = 0 |
| while buf_len < 56 { |
| buf_data[buf_len] = 0x00 |
| buf_len += 1 |
| } |
| } |
| |
| return this.util.make_bitvec256( |
| e00: (h as base.u64) | ((g as base.u64) << 32), |
| e01: (f as base.u64) | ((e as base.u64) << 32), |
| e02: (d as base.u64) | ((c as base.u64) << 32), |
| e03: (b as base.u64) | ((a as base.u64) << 32)) |
| } |