// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
pub fn[Data : ByteSource] sha1(input : Data) -> FixedArray[Byte] {
// Padding
let old_length = input.length()
let bits = old_length.to_uint64() * 8
let mut new_length = (old_length / 64 + 1) * 64
if new_length - old_length < 9 {
new_length += 64
}
let bytes = FixedArray::make(new_length, b'\x00')
input.blit_to(bytes, len=old_length, src_offset=0, dst_offset=0)
bytes[old_length] = (0x80).to_byte()
for i = new_length - 8; i < new_length; i = i + 1 {
bytes[i] = (bits >> (56 - (i - (new_length - 8)) * 8)).to_byte()
}
// Hash
let h : FixedArray[UInt] = [
0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0,
]
let bytes_per_chunk = 512 / 8
let chunk_count = new_length / bytes_per_chunk // `new_length` is a multiple of 512
let words = FixedArray::make(80, 0U)
for chunk = 0; chunk < chunk_count; chunk = chunk + 1 {
parse_be_u32_block_into(bytes, chunk * bytes_per_chunk, words)
for i = 16; i < 80; i = i + 1 {
words[i] = rotate_left_u(
words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16],
1,
)
}
let mut a = h[0]
let mut b = h[1]
let mut c = h[2]
let mut d = h[3]
let mut e = h[4]
for i in 0..<20 {
let f = (b & c) | (b.lnot() & d)
let temp = rotate_left_u(a, 5) + f + e + 0x5A827999 + words[i]
e = d
d = c
c = rotate_left_u(b, 30)
b = a
a = temp
}
for i in 20..<40 {
let f = b ^ c ^ d
let temp = rotate_left_u(a, 5) + f + e + 0x6ED9EBA1 + words[i]
e = d
d = c
c = rotate_left_u(b, 30)
b = a
a = temp
}
for i in 40..<60 {
let f = (b & c) | (b & d) | (c & d)
let temp = rotate_left_u(a, 5) + f + e + 0x8F1BBCDC + words[i]
e = d
d = c
c = rotate_left_u(b, 30)
b = a
a = temp
}
for i in 60..<80 {
let f = b ^ c ^ d
let temp = rotate_left_u(a, 5) + f + e + 0xCA62C1D6 + words[i]
e = d
d = c
c = rotate_left_u(b, 30)
b = a
a = temp
}
h[0] += a
h[1] += b
h[2] += c
h[3] += d
h[4] += e
}
// Digest
let result = FixedArray::make(20, b'\x00')
arr_u32_to_u8be_into(h.iter(), result, 0)
result
}