diff --git a/crypto/README.md b/crypto/README.md index 30ad63b..5202a59 100644 --- a/crypto/README.md +++ b/crypto/README.md @@ -20,15 +20,15 @@ println(bytes_to_hex_string(sha1(input.to_bytes()))) ```moonbit let input = "The quick brown fox jumps over the lazy dog" -println(bytes_to_hex_string(md5sum(input.to_bytes()))) +println(bytes_to_hex_string(md5(input.to_bytes()))) // => b0986ae6ee1eefee8a4a399090126837 -// or buffered -let ctx = MD5Context::make() -ctx.update(b"\x61") // 'a' -ctx.update(b"\x62") // 'b' -ctx.update(b"\x63") // 'c' -println(bytes_to_hex_string(ctx.finialize())) // or `ctx.compute()` +// buffered +let ctx = MD5Context::new() +ctx.update(b"a") +ctx.update(b"b") +ctx.update(b"c") +println(bytes_to_hex_string(ctx.finalize())) // or `ctx.compute()` // => ce1473cf80c6b3fda8e3dfc006adc315 ``` @@ -36,15 +36,15 @@ println(bytes_to_hex_string(ctx.finialize())) // or `ctx.compute()` ```moonbit let input = "The quick brown fox jumps over the lazy dog" -println(bytes_to_hex_string(sm3sum(input.to_bytes()))) +println(bytes_to_hex_string(sm3(input.to_bytes()))) // => fc2b31896629e88652ca1e3be449ec7ec93f7e5e29769f273fb973bc1858c66d //buffered -let ctx = SM3Context::make() -ctx.update(b"\x61") // 'a' -ctx.update(b"\x62") // 'b' -ctx.update(b"\x63") // 'c' -println(bytes_to_hex_string(ctx.finialize())) +let ctx = SM3Context::new() +ctx.update(b"a") +ctx.update(b"b") +ctx.update(b"c") +println(bytes_to_hex_string(ctx.finalize())) // => 66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0 ``` diff --git a/crypto/crypto.mbti b/crypto/crypto.mbti index 289d91d..48fe03a 100644 --- a/crypto/crypto.mbti +++ b/crypto/crypto.mbti @@ -1,35 +1,21 @@ package moonbitlang/x/crypto // Values -fn arr_u32_to_u8be(Array[UInt]) -> Bytes - -fn arr_u8_to_u32be(Array[Byte], ~i : Int = ..) -> UInt - fn bytes_to_hex_string(Bytes) -> String -fn bytes_to_iter(Bytes) -> Iter[Byte] - fn chacha12(FixedArray[UInt], UInt, Bytes, ~nonce : UInt = ..) -> Bytes! fn chacha20(FixedArray[UInt], UInt, Bytes, ~nonce : UInt = ..) -> Bytes! fn chacha8(FixedArray[UInt], UInt, Bytes, ~nonce : UInt = ..) -> Bytes! -fn md5sum(Bytes) -> Bytes - -fn rotate_left(Int, Int) -> Int +fn md5(Bytes) -> Bytes fn sha1(Bytes) -> Bytes -fn sm3sum(Bytes) -> Bytes - -fn sm3sum_from_iter(Iter[Byte]) -> Bytes - -fn u32_to_u8be(UInt) -> Array[Byte] - -fn u8_to_u32be(Bytes, ~i : Int = ..) -> UInt +fn sm3(Bytes) -> Bytes -fn u8_to_u32le(Bytes, ~i : Int = ..) -> UInt +fn sm3_from_iter(Iter[Byte]) -> Bytes fn uints_to_hex_string(Array[UInt]) -> String @@ -38,7 +24,7 @@ type MD5Context impl MD5Context { compute(Self) -> Bytes finalize(Self) -> Bytes - make() -> Self + new() -> Self update(Self, Bytes) -> Unit } @@ -46,7 +32,7 @@ type SM3Context impl SM3Context { compute(Self) -> Bytes finalize(Self) -> Bytes - make() -> Self + new() -> Self update(Self, Bytes) -> Unit update_from_iter(Self, Iter[Byte]) -> Unit } diff --git a/crypto/md5.mbt b/crypto/md5.mbt index e217f98..df5bebd 100644 --- a/crypto/md5.mbt +++ b/crypto/md5.mbt @@ -35,7 +35,7 @@ pub fn MD5Context::finalize(self : MD5Context) -> Bytes { } /// Instantiate a MD5 context -pub fn MD5Context::make() -> MD5Context { +pub fn MD5Context::new() -> MD5Context { padding[0] = b'\x80' { state: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476], @@ -231,14 +231,14 @@ fn md5_transform(state : FixedArray[UInt], input : FixedArray[UInt]) -> Unit { /// Compute the MD5 digest of some `data` based on [RFC1321](https://www.ietf.org/rfc/rfc1321.txt). /// - Note that MD5 is considered _cryptographically broken_. /// Unless mandated, more secure alternatives should be preferred. -pub fn md5sum(data : Bytes) -> Bytes { - let ctx = MD5Context::make() +pub fn md5(data : Bytes) -> Bytes { + let ctx = MD5Context::new() md5_update(ctx, data) ctx.compute() } test "md5_wb" { - let hash = md5sum("The quick brown fox jumps over the lazy dog".to_bytes()) + let hash = md5("The quick brown fox jumps over the lazy dog".to_bytes()) inspect!( bytes_to_hex_string(hash), content="b0986ae6ee1eefee8a4a399090126837", @@ -246,12 +246,12 @@ test "md5_wb" { } test { - let ctx = MD5Context::make() + let ctx = MD5Context::new() md5_update(ctx, b"\x61") md5_update(ctx, b"\x62") md5_update(ctx, b"\x63") let res1 = bytes_to_hex_string(ctx.compute()) - let ctx = MD5Context::make() + let ctx = MD5Context::new() md5_update(ctx, b"\x61\x62\x63") let res2 = bytes_to_hex_string(ctx.compute()) @test.eq!(res1, res2) diff --git a/crypto/md5_test.mbt b/crypto/md5_test.mbt index 4c94589..4549764 100644 --- a/crypto/md5_test.mbt +++ b/crypto/md5_test.mbt @@ -13,7 +13,7 @@ // limitations under the License. fn md5test(s : String) -> String { - bytes_to_hex_string(@crypto.md5sum(s.to_bytes())) + bytes_to_hex_string(@crypto.md5(s.to_bytes())) } test "md5_rfc1321" { // testsuites in RFC1321 @@ -46,7 +46,7 @@ test "md5_additional" { // Additional testsuites for index = 0; index < 1000; index = index + 1 { a[index] = (index % 256).to_byte() } - let hash = @crypto.md5sum(Bytes::from_array(a)) + let hash = @crypto.md5(Bytes::from_array(a)) inspect!( bytes_to_hex_string(hash), content="cbecbdb0fdd5cec1e242493b6008cc79", diff --git a/crypto/sm3.mbt b/crypto/sm3.mbt index e144247..21a6888 100644 --- a/crypto/sm3.mbt +++ b/crypto/sm3.mbt @@ -20,10 +20,13 @@ struct SM3Context { reg : FixedArray[UInt] // register A B C D E F G H. i.e. digest mut len : UInt64 mut msg : Iter[Byte] + buf : Bytes + mut buf_index : Int + mut extended_padding : Bool } /// Instantiate a SM3 context -pub fn SM3Context::make() -> SM3Context { +pub fn SM3Context::new() -> SM3Context { { reg: [ 0x7380166F, 0x4914B2B9, 0x172442D7, 0xDA8A0600, 0xA96F30BC, 0x163138AA, 0xE38DEE4D, @@ -31,6 +34,9 @@ pub fn SM3Context::make() -> SM3Context { ], len: 0, msg: Iter::empty(), + buf: Bytes::new(128), + buf_index: 0, + extended_padding: false, } } @@ -78,23 +84,30 @@ fn SM3Context::p_1(x : UInt) -> UInt { x ^ urotate_left(x, 15) ^ urotate_left(x, 23) } -fn pad(self : SM3Context) -> Iter[Byte] { - self.msg = self.msg.append(b'\x80') - while self.msg.count() % 64 != 56 { - self.msg = self.msg.append(b'\x00') +fn pad(self : SM3Context) -> Bytes { + let mut cnt = self.buf_index + self.len += 8UL * cnt.to_int64().to_uint64() // msg here must < 64 + self.buf[cnt] = b'\x80' + cnt += 1 + if cnt > 56 { + self.extended_padding = true } - self.msg = self.msg.append(self.len.lsr(56).to_byte()) - self.msg = self.msg.append(self.len.lsr(48).to_byte()) - self.msg = self.msg.append(self.len.lsr(40).to_byte()) - self.msg = self.msg.append(self.len.lsr(32).to_byte()) - self.msg = self.msg.append(self.len.lsr(24).to_byte()) - self.msg = self.msg.append(self.len.lsr(16).to_byte()) - self.msg = self.msg.append(self.len.lsr(8).to_byte()) - self.msg = self.msg.append(self.len.lsr(0).to_byte()) - return self.msg + while cnt % 64 != 56 { + self.buf[cnt] = b'\x00' + cnt += 1 + } + self.buf[cnt] = self.len.lsr(56).to_byte() + self.buf[cnt + 1] = self.len.lsr(48).to_byte() + self.buf[cnt + 2] = self.len.lsr(40).to_byte() + self.buf[cnt + 3] = self.len.lsr(32).to_byte() + self.buf[cnt + 4] = self.len.lsr(24).to_byte() + self.buf[cnt + 5] = self.len.lsr(16).to_byte() + self.buf[cnt + 6] = self.len.lsr(8).to_byte() + self.buf[cnt + 7] = self.len.lsr(0).to_byte() + return self.buf } -fn transform(self : SM3Context, data : Iter[Byte]) -> Array[UInt] { +fn transform(self : SM3Context, data : Bytes, ~offset : Int = 0) -> Array[UInt] { let w_0 = FixedArray::make(68, 0U) let w_1 = FixedArray::make(64, 0U) let mut a = self.reg[0] @@ -105,75 +118,61 @@ fn transform(self : SM3Context, data : Iter[Byte]) -> Array[UInt] { let mut f = self.reg[5] let mut g = self.reg[6] let mut h = self.reg[7] - let arr = Array::make(64, b'\x00') - let mut arr_index = 0 - data.each( - fn(dat) { - arr[arr_index] = dat - arr_index += 1 - if arr_index == 64 { - arr_index = 0 - for index = 0; index < 16; index = index + 1 { - w_0[index] = arr_u8_to_u32be(arr, i=4 * index) - } - for index = 16; index < 68; index = index + 1 { - w_0[index] = p_1( - w_0[index - 16] ^ w_0[index - 9] ^ urotate_left( - w_0[index - 3], - 15, - ), - ) ^ urotate_left(w_0[index - 13], 7) ^ w_0[index - 6] - } - for index = 0; index < 64; index = index + 1 { - w_1[index] = w_0[index] ^ w_0[index + 4] - } - let mut a1 = a - let mut b1 = b - let mut c1 = c - let mut d1 = d - let mut e1 = e - let mut f1 = f - let mut g1 = g - let mut h1 = h - for index = 0; index < 16; index = index + 1 { - let ss_1 = urotate_left(urotate_left(a1, 12) + e1 + t[index], 7) - let ss_2 = ss_1 ^ urotate_left(a1, 12) - let tt_1 = ff_0(a1, b1, c1) + d1 + ss_2 + w_1[index] - let tt_2 = gg_0(e1, f1, g1) + h1 + ss_1 + w_0[index] - d1 = c1 - c1 = urotate_left(b1, 9) - b1 = a1 - a1 = tt_1 - h1 = g1 - g1 = urotate_left(f1, 19) - f1 = e1 - e1 = p_0(tt_2) - } - for index = 16; index < 64; index = index + 1 { - let ss_1 = urotate_left(urotate_left(a1, 12) + e1 + t[index], 7) - let ss_2 = ss_1 ^ urotate_left(a1, 12) - let tt_1 = ff_1(a1, b1, c1) + d1 + ss_2 + w_1[index] - let tt_2 = gg_1(e1, f1, g1) + h1 + ss_1 + w_0[index] - d1 = c1 - c1 = urotate_left(b1, 9) - b1 = a1 - a1 = tt_1 - h1 = g1 - g1 = urotate_left(f1, 19) - f1 = e1 - e1 = p_0(tt_2) - } - a = a ^ a1 - b = b ^ b1 - c = c ^ c1 - d = d ^ d1 - e = e ^ e1 - f = f ^ f1 - g = g ^ g1 - h = h ^ h1 - } - }, - ) + for index = 0; index < 16; index = index + 1 { + w_0[index] = bytes_u8_to_u32be(data, i=4 * index + offset) + } + for index = 16; index < 68; index = index + 1 { + w_0[index] = p_1( + w_0[index - 16] ^ w_0[index - 9] ^ urotate_left(w_0[index - 3], 15), + ) ^ urotate_left(w_0[index - 13], 7) ^ w_0[index - 6] + } + for index = 0; index < 64; index = index + 1 { + w_1[index] = w_0[index] ^ w_0[index + 4] + } + let mut a1 = a + let mut b1 = b + let mut c1 = c + let mut d1 = d + let mut e1 = e + let mut f1 = f + let mut g1 = g + let mut h1 = h + for index = 0; index < 16; index = index + 1 { + let ss_1 = urotate_left(urotate_left(a1, 12) + e1 + t[index], 7) + let ss_2 = ss_1 ^ urotate_left(a1, 12) + let tt_1 = ff_0(a1, b1, c1) + d1 + ss_2 + w_1[index] + let tt_2 = gg_0(e1, f1, g1) + h1 + ss_1 + w_0[index] + d1 = c1 + c1 = urotate_left(b1, 9) + b1 = a1 + a1 = tt_1 + h1 = g1 + g1 = urotate_left(f1, 19) + f1 = e1 + e1 = p_0(tt_2) + } + for index = 16; index < 64; index = index + 1 { + let ss_1 = urotate_left(urotate_left(a1, 12) + e1 + t[index], 7) + let ss_2 = ss_1 ^ urotate_left(a1, 12) + let tt_1 = ff_1(a1, b1, c1) + d1 + ss_2 + w_1[index] + let tt_2 = gg_1(e1, f1, g1) + h1 + ss_1 + w_0[index] + d1 = c1 + c1 = urotate_left(b1, 9) + b1 = a1 + a1 = tt_1 + h1 = g1 + g1 = urotate_left(f1, 19) + f1 = e1 + e1 = p_0(tt_2) + } + a = a ^ a1 + b = b ^ b1 + c = c ^ c1 + d = d ^ d1 + e = e ^ e1 + f = f ^ f1 + g = g ^ g1 + h = h ^ h1 let t_arr : Array[UInt] = [a, b, c, d, e, f, g, h] for index = 0; index < 8; index = index + 1 { self.reg[index] = t_arr[index] @@ -182,13 +181,21 @@ fn transform(self : SM3Context, data : Iter[Byte]) -> Array[UInt] { } fn sm3_update(self : SM3Context, data : Iter[Byte]) -> Unit { - self.len += data.count().to_int64().to_uint64() * 8UL let msg = self.msg + data - let msg_len = msg.count() - let block_num = msg_len / 64 - // let len = msg_len - block_num * 64 - let _ = self.transform(msg) - self.msg = msg.drop(block_num * 64) + self.buf_index = 0 + msg.each( + fn(b) { + self.buf[self.buf_index] = b + self.buf_index += 1 + if self.buf_index == 64 { + self.buf_index = 0 + self.len += 512UL + let _ = self.transform(self.buf) + + } + }, + ) + self.msg = bytes_to_iter(self.buf, length=self.buf_index) } /// update the state of given context from new `data` @@ -212,12 +219,17 @@ fn sm3_compute( ) -> Array[UInt] { self.sm3_update(data) let msg = self.pad() - self.transform(msg) + if self.extended_padding { + let _ = self.transform(msg) + self.transform(msg, offset=64) + } else { + self.transform(msg) + } } /// Compute the SM3 digest in `UInt[]` of some `data` fn sm3_u32_from_iter(data : Iter[Byte]) -> Array[UInt] { - let ctx = SM3Context::make() + let ctx = SM3Context::new() let _ = ctx.sm3_update(data) ctx.sm3_compute() } @@ -227,11 +239,11 @@ fn sm3_u32(data : Bytes) -> Array[UInt] { } /// Compute the SM3 digest in `Bytes` of some `data`. Note that SM3 is big-endian. -pub fn sm3sum(data : Bytes) -> Bytes { +pub fn sm3(data : Bytes) -> Bytes { arr_u32_to_u8be(sm3_u32(data)) } -pub fn sm3sum_from_iter(data : Iter[Byte]) -> Bytes { +pub fn sm3_from_iter(data : Iter[Byte]) -> Bytes { arr_u32_to_u8be(sm3_u32_from_iter(data)) } @@ -259,11 +271,11 @@ test { content="debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732", ) @test.eq!( - bytes_to_hex_string(sm3sum(b"\x61\x62\x63")), + bytes_to_hex_string(sm3(b"\x61\x62\x63")), uints_to_hex_string(sm3_u32(b"\x61\x62\x63")), ) let hash1 = "66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0" - let ctx = SM3Context::make() + let ctx = SM3Context::new() ctx.update(b"\x61") ctx.update(b"\x62") ctx.update(b"\x63") diff --git a/crypto/sm3_test.mbt b/crypto/sm3_test.mbt index da73bb8..8fe9e63 100644 --- a/crypto/sm3_test.mbt +++ b/crypto/sm3_test.mbt @@ -13,7 +13,7 @@ // limitations under the License. fn sm3test(s : String) -> String { - @crypto.bytes_to_hex_string(@crypto.sm3sum(s.to_bytes())) + @crypto.bytes_to_hex_string(@crypto.sm3(s.to_bytes())) } // testcases from GM/T 0004-2012 diff --git a/crypto/utils.mbt b/crypto/utils.mbt index fb3d29e..8ea4e7c 100644 --- a/crypto/utils.mbt +++ b/crypto/utils.mbt @@ -60,7 +60,7 @@ fn uint32(x : Byte) -> UInt { /// convert 4 bytes a byte sequence to a UInt in little endian /// - `x` : A byte sequence consisting of 4 or more bytes /// - `i` : An offset. e.g. i = 4 will convert `x[4~7]` to a UInt. -pub fn u8_to_u32le(x : Bytes, ~i : Int = 0) -> UInt { +fn u8_to_u32le(x : Bytes, ~i : Int = 0) -> UInt { uint32(x[i]) | uint32(x[i + 1]).lsl(8) | uint32(x[i + 2]).lsl(16) | uint32( x[i + 3], ).lsl(24) @@ -69,23 +69,32 @@ pub fn u8_to_u32le(x : Bytes, ~i : Int = 0) -> UInt { /// convert 4 bytes of a byte sequence to a UInt in big endian /// - `x` : A byte sequence consisting of 4 or more bytes /// - `i` : An offset. e.g. i = 4 will convert `x[4~7]` to a UInt. -pub fn u8_to_u32be(x : Bytes, ~i : Int = 0) -> UInt { - uint32(x[i]).lsl(24) | uint32(x[i + 1]).lsl(16) | uint32(x[i + 2]).lsl(8) | uint32( - x[i + 3], - ) -} + +// fn u8_to_u32be(x : Bytes, ~i : Int = 0) -> UInt { +// uint32(x[i]).lsl(24) | uint32(x[i + 1]).lsl(16) | uint32(x[i + 2]).lsl(8) | uint32( +// x[i + 3], +// ) +// } /// convert 4 bytes of a byte array to a UInt in big endian /// - `x` : A byte sequence consisting of 4 or more bytes /// - `i` : An offset. e.g. i = 4 will convert `x[4~7]` to a UInt. -pub fn arr_u8_to_u32be(x : Array[Byte], ~i : Int = 0) -> UInt { + +// fn arr_u8_to_u32be(x : Array[Byte], ~i : Int = 0) -> UInt { +// uint32(x[i]).lsl(24) | uint32(x[i + 1]).lsl(16) | uint32(x[i + 2]).lsl(8) | uint32( +// x[i + 3], +// ) +// } + +fn bytes_u8_to_u32be(x : Bytes, ~i : Int = 0) -> UInt { uint32(x[i]).lsl(24) | uint32(x[i + 1]).lsl(16) | uint32(x[i + 2]).lsl(8) | uint32( x[i + 3], ) } /// convert a UInt to 4 bytes -pub fn u32_to_u8be(x : UInt) -> Array[Byte] { + +fn u32_to_u8be(x : UInt) -> Array[Byte] { let b = Array::make(4, b'\x00') b[0] = x.lsr(24).to_byte() b[1] = x.lsr(16).to_byte() @@ -95,7 +104,8 @@ pub fn u32_to_u8be(x : UInt) -> Array[Byte] { } /// convert an array of UInt to Bytes in big endian -pub fn arr_u32_to_u8be(x : Array[UInt]) -> Bytes { + +fn arr_u32_to_u8be(x : Array[UInt]) -> Bytes { let temp : Bytes = Bytes::make(x.length() * 4, b'\x00') for index = 0; index < x.length(); index = index + 1 { let u8 = u32_to_u8be(x[index]) @@ -108,7 +118,8 @@ pub fn arr_u32_to_u8be(x : Array[UInt]) -> Bytes { } /// rotate a Int `x` left by `n` bit(s) -pub fn rotate_left(x : Int, n : Int) -> Int { + +fn rotate_left(x : Int, n : Int) -> Int { x.lsl(n).lor(x.lsr(32 - n)) } @@ -118,10 +129,11 @@ fn rotate_left_u(x : UInt, n : Int) -> UInt { } /// temp function for convert bytes_to_iter in absence of `Bytes::iter()`. -pub fn bytes_to_iter(data : Bytes) -> Iter[Byte] { + +fn bytes_to_iter(data : Bytes, ~length: Int = data.length()) -> Iter[Byte] { Iter::new( fn(yield) { - for i = 0, len = data.length(); i < len; i = i + 1 { + for i = 0, len = length; i < len; i = i + 1 { if yield(data[i]) == IterEnd { break IterEnd }