///| SHA-1 core implementation (hash package)
///|
let sha1_h0 : Int = 0x67452301
///|
let sha1_h1 : Int = 0xefcdab89
///|
let sha1_h2 : Int = 0x98badcfe
///|
let sha1_h3 : Int = 0x10325476
///|
let sha1_h4 : Int = 0xc3d2e1f0
///|
pub struct Sha1State {
h : FixedArray[Int]
block : FixedArray[Byte]
w : FixedArray[Int]
mut block_len : Int
mut total_len : Int64
}
///|
pub fn Sha1State::new() -> Sha1State {
{
h: [sha1_h0, sha1_h1, sha1_h2, sha1_h3, sha1_h4],
block: FixedArray::make(64, b'\x00'),
w: FixedArray::make(80, 0),
block_len: 0,
total_len: 0L,
}
}
///|
pub fn Sha1State::reset(self : Sha1State) -> Unit {
self.h[0] = sha1_h0
self.h[1] = sha1_h1
self.h[2] = sha1_h2
self.h[3] = sha1_h3
self.h[4] = sha1_h4
self.block_len = 0
self.total_len = 0L
}
///|
pub fn Sha1State::update(self : Sha1State, data : Bytes) -> Unit {
self.update_slice(data, 0, data.length())
}
///|
pub fn Sha1State::update_slice(
self : Sha1State,
data : Bytes,
offset : Int,
len : Int,
) -> Unit {
let mut pos = offset
let end = offset + len
self.total_len += len.to_int64()
while pos < end {
let space = 64 - self.block_len
let to_copy = if end - pos < space { end - pos } else { space }
for i in 0.. Unit {
self.block[self.block_len] = b
self.block_len += 1
self.total_len += 1L
if self.block_len == 64 {
self.process_block()
self.block_len = 0
}
}
///|
pub fn Sha1State::update_string(self : Sha1State, s : String) -> Unit {
self.update(utf8_encode(s))
}
///|
pub fn Sha1State::finish_raw(self : Sha1State) -> FixedArray[Byte] {
let bit_len = self.total_len * 8L
self.block[self.block_len] = b'\x80'
self.block_len += 1
if self.block_len > 56 {
while self.block_len < 64 {
self.block[self.block_len] = b'\x00'
self.block_len += 1
}
self.process_block()
self.block_len = 0
}
while self.block_len < 56 {
self.block[self.block_len] = b'\x00'
self.block_len += 1
}
self.block[56] = ((bit_len >> 56) & 0xffL).to_byte()
self.block[57] = ((bit_len >> 48) & 0xffL).to_byte()
self.block[58] = ((bit_len >> 40) & 0xffL).to_byte()
self.block[59] = ((bit_len >> 32) & 0xffL).to_byte()
self.block[60] = ((bit_len >> 24) & 0xffL).to_byte()
self.block[61] = ((bit_len >> 16) & 0xffL).to_byte()
self.block[62] = ((bit_len >> 8) & 0xffL).to_byte()
self.block[63] = (bit_len & 0xffL).to_byte()
self.process_block()
let result : FixedArray[Byte] = FixedArray::make(20, b'\x00')
for i = 0; i < 5; i = i + 1 {
result[i * 4] = ((self.h[i] >> 24) & 0xff).to_byte()
result[i * 4 + 1] = ((self.h[i] >> 16) & 0xff).to_byte()
result[i * 4 + 2] = ((self.h[i] >> 8) & 0xff).to_byte()
result[i * 4 + 3] = (self.h[i] & 0xff).to_byte()
}
result
}
///|
pub fn sha1_prefix_raw(data : Bytes, len : Int) -> FixedArray[Byte] {
let msg_len = if len < 0 {
0
} else if len > data.length() {
data.length()
} else {
len
}
let state = Sha1State::new()
state.update_slice(data, 0, msg_len)
state.finish_raw()
}
///|
pub fn sha1_array_prefix_raw(data : Array[Byte], len : Int) -> FixedArray[Byte] {
let msg_len = if len < 0 {
0
} else if len > data.length() {
data.length()
} else {
len
}
let state = Sha1State::new()
for i in 0.. FixedArray[Byte] {
sha1_array_prefix_raw(data, data.length())
}