// SHA-256 for MoonVault
// Convert MoonBit String (UTF-16) to UTF-8 Bytes
pub fn str_to_utf8(s : String) -> Bytes {
let len = s.length()
let result : Array[Byte] = Array::make(len * 3, b'\x00')
let mut ri = 0
let mut i = 0
while i < len {
let code = s[i].to_int()
if code < 0x80 {
result[ri] = code.to_byte()
ri = ri + 1
} else if code < 0x800 {
result[ri] = (0xC0 | (code >> 6)).to_byte()
result[ri + 1] = (0x80 | (code & 0x3F)).to_byte()
ri = ri + 2
} else {
result[ri] = (0xE0 | (code >> 12)).to_byte()
result[ri + 1] = (0x80 | ((code >> 6) & 0x3F)).to_byte()
result[ri + 2] = (0x80 | (code & 0x3F)).to_byte()
ri = ri + 3
}
i = i + 1
}
Bytes::from_array(result[0:ri])
}
let k_const : Array[UInt] = [
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
]
struct Sha256 {
state : Array[UInt]
buf : Array[Byte]
mut buf_len : Int
mut total_len : Int64
}
fn rotr32(x : UInt, n : Int) -> UInt {
(x >> n) | (x << (32 - n))
}
pub fn Sha256::new() -> Sha256 {
{
state: [0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19],
buf: Array::make(64, b'\x00'),
buf_len: 0,
total_len: 0L,
}
}
fn Sha256::process_block(self : Sha256, block : Bytes) -> Sha256 {
let w : Array[UInt] = Array::make(64, 0)
let mut i = 0
while i < 16 {
let j = i * 4
w[i] = (block[j].to_uint() << 24) | (block[j+1].to_uint() << 16) | (block[j+2].to_uint() << 8) | block[j+3].to_uint()
i = i + 1
}
i = 16
while i < 64 {
let s0 = rotr32(w[i-15], 7) ^ rotr32(w[i-15], 18) ^ (w[i-15] >> 3)
let s1 = rotr32(w[i-2], 17) ^ rotr32(w[i-2], 19) ^ (w[i-2] >> 10)
w[i] = w[i-16] + s0 + w[i-7] + s1
i = i + 1
}
let mut a = self.state[0]
let mut b = self.state[1]
let mut c = self.state[2]
let mut d = self.state[3]
let mut e = self.state[4]
let mut f = self.state[5]
let mut g = self.state[6]
let mut h = self.state[7]
i = 0
while i < 64 {
let se = rotr32(e, 6) ^ rotr32(e, 11) ^ rotr32(e, 25)
let ch = (e & f) ^ (e.lnot() & g)
let t1 = h + se + ch + k_const[i] + w[i]
let sa = rotr32(a, 2) ^ rotr32(a, 13) ^ rotr32(a, 22)
let maj = (a & b) ^ (a & c) ^ (b & c)
let t2 = sa + maj
h = g; g = f; f = e; e = d + t1
d = c; c = b; b = a; a = t1 + t2
i = i + 1
}
self.state[0] = self.state[0] + a
self.state[1] = self.state[1] + b
self.state[2] = self.state[2] + c
self.state[3] = self.state[3] + d
self.state[4] = self.state[4] + e
self.state[5] = self.state[5] + f
self.state[6] = self.state[6] + g
self.state[7] = self.state[7] + h
self
}
pub fn Sha256::write(self : Sha256, data : Bytes) -> Sha256 {
let mut s = self
s.total_len = s.total_len + data.length().to_int64()
let mut offset = 0
while offset < data.length() {
let rem = 64 - s.buf_len
let cl = if offset + rem <= data.length() { rem } else { data.length() - offset }
let mut j = 0
while j < cl { s.buf[s.buf_len + j] = data[offset + j]; j = j + 1 }
s.buf_len = s.buf_len + cl
offset = offset + cl
if s.buf_len == 64 { s = s.process_block(Bytes::from_array(s.buf)); s.buf_len = 0 }
}
s
}
pub fn Sha256::write_string(self : Sha256, s : String) -> Sha256 {
self.write(str_to_utf8(s))
}
pub fn Sha256::sum(self : Sha256) -> Bytes {
let bit_len = self.total_len * 8L
let rem = (self.total_len + 1L + 8L) % 64L
let pad_len = if rem != 0L { 1 + (64L - rem).to_int() } else { 1 }
let tp = pad_len + 8
let padded : Array[Byte] = Array::make(tp, b'\x00')
padded[0] = b'\x80'
let hi = (bit_len >> 32).to_int()
let lo = (bit_len & 0xFFFFFFFFL).to_int()
padded[pad_len] = ((hi >> 24) & 0xFF).to_byte()
padded[pad_len+1] = ((hi >> 16) & 0xFF).to_byte()
padded[pad_len+2] = ((hi >> 8) & 0xFF).to_byte()
padded[pad_len+3] = (hi & 0xFF).to_byte()
padded[pad_len+4] = ((lo >> 24) & 0xFF).to_byte()
padded[pad_len+5] = ((lo >> 16) & 0xFF).to_byte()
padded[pad_len+6] = ((lo >> 8) & 0xFF).to_byte()
padded[pad_len+7] = (lo & 0xFF).to_byte()
let mut s = self
let mut offset = 0
while offset < tp {
let rem = 64 - s.buf_len
let cl = if offset + rem <= tp { rem } else { tp - offset }
let mut j = 0
while j < cl { s.buf[s.buf_len + j] = padded[offset + j]; j = j + 1 }
s.buf_len = s.buf_len + cl
offset = offset + cl
if s.buf_len == 64 { s = s.process_block(Bytes::from_array(s.buf)); s.buf_len = 0 }
}
let digest : Array[Byte] = Array::make(32, b'\x00')
let mut di = 0
while di < 8 {
let vi = s.state[di].reinterpret_as_int()
digest[di*4] = ((vi >> 24) & 0xFF).to_byte()
digest[di*4+1] = ((vi >> 16) & 0xFF).to_byte()
digest[di*4+2] = ((vi >> 8) & 0xFF).to_byte()
digest[di*4+3] = (vi & 0xFF).to_byte()
di = di + 1
}
Bytes::from_array(digest)
}
pub fn sha256(data : Bytes) -> Bytes {
let h = Sha256::new()
let h = h.write(data)
h.sum()
}
pub fn sha256_hex(s : String) -> String {
let h = Sha256::new()
let h = h.write_string(s)
bytes_to_hex(h.sum())
}
let hex_digits : Array[String] = ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"]
pub fn bytes_to_hex(b : Bytes) -> String {
let mut result = ""
let mut i = 0
while i < b.length() {
let v = b[i].to_int()
result = result + hex_digits[v >> 4] + hex_digits[v & 0xF]
i = i + 1
}
result
}