From 24ca6e2d9d93b378ddf095f9ca5cdb04bc6c7212 Mon Sep 17 00:00:00 2001 From: Evan Gao Date: Fri, 2 Aug 2024 11:00:17 +0800 Subject: [PATCH 1/3] api update for sm3 and md5 --- crypto/README.md | 31 +++++++++++++++++++-- crypto/md5.mbt | 34 ++++++++++++++++++++---- crypto/md5_test.mbt | 4 +-- crypto/sm3.mbt | 65 +++++++++++++++++++++++++++++++++++---------- crypto/sm3_test.mbt | 2 +- crypto/utils.mbt | 17 ++++++++++++ 6 files changed, 129 insertions(+), 24 deletions(-) diff --git a/crypto/README.md b/crypto/README.md index d9eab32..30ad63b 100644 --- a/crypto/README.md +++ b/crypto/README.md @@ -12,12 +12,39 @@ A collection of cryptographic hash functions and utilities. ```moonbit let input = "The quick brown fox jumps over the lazy dog" -println(bytes_to_hex_string(sha1(input.to_bytes()))) // bd136cb58899c93173c33a90dde95ead0d0cf6df +println(bytes_to_hex_string(sha1(input.to_bytes()))) +// => bd136cb58899c93173c33a90dde95ead0d0cf6df ``` ### MD5 ```moonbit let input = "The quick brown fox jumps over the lazy dog" -println(bytes_to_hex_string(md5(input.to_bytes()))) // b0986ae6ee1eefee8a4a399090126837 +println(bytes_to_hex_string(md5sum(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()` +// => ce1473cf80c6b3fda8e3dfc006adc315 +``` + +### SM3 + +```moonbit +let input = "The quick brown fox jumps over the lazy dog" +println(bytes_to_hex_string(sm3sum(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())) +// => 66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0 ``` diff --git a/crypto/md5.mbt b/crypto/md5.mbt index 93f5d36..e217f98 100644 --- a/crypto/md5.mbt +++ b/crypto/md5.mbt @@ -16,7 +16,7 @@ // [RFC1321] https://www.ietf.org/rfc/rfc1321.txt // [Ron Rivest] https://people.csail.mit.edu/rivest/Md5.c // [md5-0.7.0] https://docs.rs/md5/0.7.0/src/md5/lib.rs.html -priv struct MD5Context { +struct MD5Context { state : FixedArray[UInt] // state 'a' 'b' 'c' 'd' count : FixedArray[UInt] buffer : Bytes @@ -24,7 +24,18 @@ priv struct MD5Context { let padding : Bytes = Bytes::make(64, b'\x00') -fn MD5Context::make() -> MD5Context { +/// update the state of given context from new `data` +pub fn MD5Context::update(self : MD5Context, data : Bytes) -> Unit { + md5_update(self, data) +} + +/// an alias of `MD5Context::compute()` +pub fn MD5Context::finalize(self : MD5Context) -> Bytes { + self.compute() +} + +/// Instantiate a MD5 context +pub fn MD5Context::make() -> MD5Context { padding[0] = b'\x80' { state: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476], @@ -33,7 +44,8 @@ fn MD5Context::make() -> MD5Context { } } -fn MD5Context::compute(self : MD5Context) -> Bytes { +/// compute MD5 digest from given context +pub fn MD5Context::compute(self : MD5Context) -> Bytes { let input = FixedArray::make(16, 0U) let idx = (self.count[0].lsr(3) & 0x3f).to_int() input[14] = self.count[0] @@ -219,16 +231,28 @@ 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 md5(data : Bytes) -> Bytes { +pub fn md5sum(data : Bytes) -> Bytes { let ctx = MD5Context::make() md5_update(ctx, data) ctx.compute() } test "md5_wb" { - let hash = md5("The quick brown fox jumps over the lazy dog".to_bytes()) + let hash = md5sum("The quick brown fox jumps over the lazy dog".to_bytes()) inspect!( bytes_to_hex_string(hash), content="b0986ae6ee1eefee8a4a399090126837", ) } + +test { + let ctx = MD5Context::make() + 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() + 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 4549764..4c94589 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.md5(s.to_bytes())) + bytes_to_hex_string(@crypto.md5sum(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.md5(Bytes::from_array(a)) + let hash = @crypto.md5sum(Bytes::from_array(a)) inspect!( bytes_to_hex_string(hash), content="cbecbdb0fdd5cec1e242493b6008cc79", diff --git a/crypto/sm3.mbt b/crypto/sm3.mbt index 93be557..321e95a 100644 --- a/crypto/sm3.mbt +++ b/crypto/sm3.mbt @@ -16,13 +16,14 @@ // - [GM/T 0004-2012] https://www.oscca.gov.cn/sca/xxgk/2010-12/17/1002389/files/302a3ada057c4a73830536d03e683110.pdf // SM3 is as secure as SHA256, providing similar performance. https://doi.org/10.3390/electronics8091033 -priv struct SM3Context { +struct SM3Context { reg : FixedArray[UInt] // register A B C D E F G H. i.e. digest mut len : UInt64 mut msg : Array[Byte] } -fn SM3Context::make() -> SM3Context { +/// Instantiate a SM3 context +pub fn SM3Context::make() -> SM3Context { { reg: [ 0x7380166F, 0x4914B2B9, 0x172442D7, 0xDA8A0600, 0xA96F30BC, 0x163138AA, 0xE38DEE4D, @@ -93,7 +94,7 @@ fn pad(self : SM3Context) -> Array[Byte] { return self.msg } -fn update(self : SM3Context, data : Ref[Array[Byte]]) -> Array[UInt] { +fn transform(self : SM3Context, data : Ref[Array[Byte]]) -> Array[UInt] { let w_0 = FixedArray::make(68, 0U) let w_1 = FixedArray::make(64, 0U) let mut a = self.reg[0] @@ -171,35 +172,56 @@ fn update(self : SM3Context, data : Ref[Array[Byte]]) -> Array[UInt] { return t_arr } -fn compute(self : SM3Context, data : Array[Byte]) -> Unit { +fn sm3_update(self : SM3Context, data : Array[Byte]) -> Unit { self.len += data.length().to_int64().to_uint64() * 8UL let msg = self.msg + data let block_num = msg.length() / 64 let len = msg.length() - block_num * 64 - let _ = self.update(Ref::new(msg)) + let _ = self.transform(Ref::new(msg)) let new_msg = Array::make(len, b'\x00') msg.blit_to(new_msg, ~len, src_offset=block_num * 64) self.msg = new_msg } -fn sum(self : SM3Context, ~data : Array[Byte] = []) -> Array[UInt] { - self.compute(data) +/// update the state of given context from new `data` +pub fn update(self : SM3Context, data : Bytes) -> Unit { + self.sm3_update(data.to_array()) +} + +/// compute SM3 digest from given context +pub fn compute(self : SM3Context) -> Bytes { let msg = self.pad() - self.update(Ref::new(msg)) + arr_u32_to_u8be(self.transform(Ref::new(msg))) } -/// Compute the SM3 digest of some `data` -pub fn sm3(data : Bytes) -> Array[UInt] { +pub fn sm3_compute(self : SM3Context, ~data : Array[Byte] = []) -> Array[UInt] { + self.sm3_update(data) + let msg = self.pad() + self.transform(Ref::new(msg)) +} + +/// Compute the SM3 digest in `UInt[]` of some `data` +pub fn sm3_u32(data : Bytes) -> Array[UInt] { let bytes_data = bytes_to_byte_array(data) let ctx = SM3Context::make() - let _ = ctx.compute(bytes_data) - ctx.sum() + let _ = ctx.sm3_update(bytes_data) + ctx.sm3_compute() +} + +/// Compute the SM3 digest in `Bytes` of some `data`. Note that SM3 is big-endian. +pub fn sm3sum(data : Bytes) -> Bytes { + arr_u32_to_u8be(sm3_u32(data)) +} + +/// an alias of `SM3Context::compute()` +pub fn finalize(self : SM3Context) -> Bytes { + self.compute() } test { inspect!( uints_to_hex_string( - sm3( + sm3_u32( b"\x61\x62\x63", // abc in utf-8 ), ), @@ -207,11 +229,26 @@ test { ) inspect!( uints_to_hex_string( - sm3( + sm3_u32( // abcd * 16 in utf-8 b"\x61\x62\x63\x64\x61\x62\x63\x64\x61\x62\x63\x64\x61\x62\x63\x64\x61\x62\x63\x64\x61\x62\x63\x64\x61\x62\x63\x64\x61\x62\x63\x64\x61\x62\x63\x64\x61\x62\x63\x64\x61\x62\x63\x64\x61\x62\x63\x64\x61\x62\x63\x64\x61\x62\x63\x64\x61\x62\x63\x64\x61\x62\x63\x64", ), ), content="debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732", ) + @test.eq!( + bytes_to_hex_string(sm3sum(b"\x61\x62\x63")), + uints_to_hex_string(sm3_u32(b"\x61\x62\x63")), + ) + let hash1 = "66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0" + let ctx = SM3Context::make() + ctx.update(b"\x61") + ctx.update(b"\x62") + ctx.update(b"\x63") + @test.eq!(hash1, bytes_to_hex_string(ctx.compute())) + println( + uints_to_hex_string( + sm3_u32("The quick brown fox jumps over the lazy dog".to_bytes()), + ), + ) } diff --git a/crypto/sm3_test.mbt b/crypto/sm3_test.mbt index d0a13c8..e155c54 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.uints_to_hex_string(@crypto.sm3(s.to_bytes())) + @crypto.uints_to_hex_string(@crypto.sm3_u32(s.to_bytes())) } // testcases from GM/T 0004-2012 diff --git a/crypto/utils.mbt b/crypto/utils.mbt index d92e5a1..1b8ff19 100644 --- a/crypto/utils.mbt +++ b/crypto/utils.mbt @@ -73,6 +73,23 @@ pub fn arr_u8_to_u32be(x : Array[Byte], ~i : Int = 0) -> UInt { ) } +pub 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() + b[2] = x.lsr(8).to_byte() + b[3] = x.to_byte() + b +} + +pub fn arr_u32_to_u8be(x : Array[UInt]) -> Bytes { + let temp : Array[Byte] = [] + for index = 0; index < x.length(); index = index + 1 { + temp.append(u32_to_u8be(x[index])) + } + Bytes::from_array(temp) +} + pub fn byte_array_to_bytes(s : Array[Byte]) -> Bytes { let bytes = Bytes::make(s.length(), b'\x00') for index = 0; index < s.length(); index = index + 1 { From 6f206bf1efc3355f29ccbe3e1cb73ec02b91f12d Mon Sep 17 00:00:00 2001 From: Evan Gao Date: Mon, 5 Aug 2024 17:24:23 +0800 Subject: [PATCH 2/3] switch to iter[byte] for SM3 internally --- crypto/crypto.mbti | 34 ++++++-- crypto/sm3.mbt | 207 ++++++++++++++++++++++++-------------------- crypto/sm3_test.mbt | 2 +- crypto/utils.mbt | 58 ++++++++----- 4 files changed, 179 insertions(+), 122 deletions(-) diff --git a/crypto/crypto.mbti b/crypto/crypto.mbti index 67f33ba..d32789d 100644 --- a/crypto/crypto.mbti +++ b/crypto/crypto.mbti @@ -1,25 +1,31 @@ package moonbitlang/x/crypto // Values -fn arr_u8_to_u32be(Array[Byte], ~i : Int = ..) -> UInt - -fn byte_array_to_bytes(Array[Byte]) -> Bytes +fn arr_u32_to_u8be(Array[UInt]) -> Bytes -fn bytes_to_byte_array(Bytes) -> Array[Byte] +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 md5(Bytes) -> Bytes +fn md5sum(Bytes) -> Bytes + +fn rotate_left(Int, Int) -> Int fn sha1(Bytes) -> Bytes -fn sm3(Bytes) -> Array[UInt] +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 @@ -28,6 +34,22 @@ fn u8_to_u32le(Bytes, ~i : Int = ..) -> UInt fn uints_to_hex_string(Array[UInt]) -> String // Types and methods +type MD5Context +impl MD5Context { + compute(Self) -> Bytes + finalize(Self) -> Bytes + make() -> Self + update(Self, Bytes) -> Unit +} + +type SM3Context +impl SM3Context { + compute(Self) -> Bytes + finalize(Self) -> Bytes + make() -> Self + update(Self, Bytes) -> Unit + update_from_iter(Self, Iter[Byte]) -> Unit +} // Type aliases diff --git a/crypto/sm3.mbt b/crypto/sm3.mbt index 321e95a..e144247 100644 --- a/crypto/sm3.mbt +++ b/crypto/sm3.mbt @@ -19,7 +19,7 @@ struct SM3Context { reg : FixedArray[UInt] // register A B C D E F G H. i.e. digest mut len : UInt64 - mut msg : Array[Byte] + mut msg : Iter[Byte] } /// Instantiate a SM3 context @@ -30,7 +30,7 @@ pub fn SM3Context::make() -> SM3Context { 0xB0FB0E4E, ], len: 0, - msg: [], + msg: Iter::empty(), } } @@ -78,23 +78,23 @@ fn SM3Context::p_1(x : UInt) -> UInt { x ^ urotate_left(x, 15) ^ urotate_left(x, 23) } -fn pad(self : SM3Context) -> Array[Byte] { - self.msg.push(b'\x80') - while self.msg.length() % 64 != 56 { - self.msg.push(b'\x00') +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') } - self.msg.push(self.len.lsr(56).to_byte()) - self.msg.push(self.len.lsr(48).to_byte()) - self.msg.push(self.len.lsr(40).to_byte()) - self.msg.push(self.len.lsr(32).to_byte()) - self.msg.push(self.len.lsr(24).to_byte()) - self.msg.push(self.len.lsr(16).to_byte()) - self.msg.push(self.len.lsr(8).to_byte()) - self.msg.push(self.len.lsr(0).to_byte()) + 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 } -fn transform(self : SM3Context, data : Ref[Array[Byte]]) -> Array[UInt] { +fn transform(self : SM3Context, data : Iter[Byte]) -> Array[UInt] { let w_0 = FixedArray::make(68, 0U) let w_1 = FixedArray::make(64, 0U) let mut a = self.reg[0] @@ -105,66 +105,75 @@ fn transform(self : SM3Context, data : Ref[Array[Byte]]) -> Array[UInt] { let mut f = self.reg[5] let mut g = self.reg[6] let mut h = self.reg[7] - while data.val.length() >= 64 { - for index = 0; index < 16; index = index + 1 { - w_0[index] = arr_u8_to_u32be(data.val, 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 - let t_arr = Array::make(data.val.length() - 64, b'\x00') - data.val.blit_to(t_arr, len=data.val.length() - 64, src_offset=64) - data.val = t_arr - } + 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 + } + }, + ) 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] @@ -172,47 +181,60 @@ fn transform(self : SM3Context, data : Ref[Array[Byte]]) -> Array[UInt] { return t_arr } -fn sm3_update(self : SM3Context, data : Array[Byte]) -> Unit { - self.len += data.length().to_int64().to_uint64() * 8UL +fn sm3_update(self : SM3Context, data : Iter[Byte]) -> Unit { + self.len += data.count().to_int64().to_uint64() * 8UL let msg = self.msg + data - let block_num = msg.length() / 64 - let len = msg.length() - block_num * 64 - let _ = self.transform(Ref::new(msg)) - let new_msg = Array::make(len, b'\x00') - msg.blit_to(new_msg, ~len, src_offset=block_num * 64) - self.msg = new_msg + 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) } /// update the state of given context from new `data` pub fn update(self : SM3Context, data : Bytes) -> Unit { - self.sm3_update(data.to_array()) + self.sm3_update(bytes_to_iter(data)) +} + +pub fn update_from_iter(self : SM3Context, data : Iter[Byte]) -> Unit { + self.sm3_update(data) } /// compute SM3 digest from given context pub fn compute(self : SM3Context) -> Bytes { let msg = self.pad() - arr_u32_to_u8be(self.transform(Ref::new(msg))) + arr_u32_to_u8be(self.transform(msg)) } -pub fn sm3_compute(self : SM3Context, ~data : Array[Byte] = []) -> Array[UInt] { +fn sm3_compute( + self : SM3Context, + ~data : Iter[Byte] = Iter::empty() +) -> Array[UInt] { self.sm3_update(data) let msg = self.pad() - self.transform(Ref::new(msg)) + self.transform(msg) } /// Compute the SM3 digest in `UInt[]` of some `data` -pub fn sm3_u32(data : Bytes) -> Array[UInt] { - let bytes_data = bytes_to_byte_array(data) +fn sm3_u32_from_iter(data : Iter[Byte]) -> Array[UInt] { let ctx = SM3Context::make() - let _ = ctx.sm3_update(bytes_data) + let _ = ctx.sm3_update(data) ctx.sm3_compute() } +fn sm3_u32(data : Bytes) -> Array[UInt] { + sm3_u32_from_iter(bytes_to_iter(data)) +} + /// Compute the SM3 digest in `Bytes` of some `data`. Note that SM3 is big-endian. pub fn sm3sum(data : Bytes) -> Bytes { arr_u32_to_u8be(sm3_u32(data)) } +pub fn sm3sum_from_iter(data : Iter[Byte]) -> Bytes { + arr_u32_to_u8be(sm3_u32_from_iter(data)) +} + /// an alias of `SM3Context::compute()` pub fn finalize(self : SM3Context) -> Bytes { self.compute() @@ -246,9 +268,4 @@ test { ctx.update(b"\x62") ctx.update(b"\x63") @test.eq!(hash1, bytes_to_hex_string(ctx.compute())) - println( - uints_to_hex_string( - sm3_u32("The quick brown fox jumps over the lazy dog".to_bytes()), - ), - ) } diff --git a/crypto/sm3_test.mbt b/crypto/sm3_test.mbt index e155c54..da73bb8 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.uints_to_hex_string(@crypto.sm3_u32(s.to_bytes())) + @crypto.bytes_to_hex_string(@crypto.sm3sum(s.to_bytes())) } // testcases from GM/T 0004-2012 diff --git a/crypto/utils.mbt b/crypto/utils.mbt index 1b8ff19..fb3d29e 100644 --- a/crypto/utils.mbt +++ b/crypto/utils.mbt @@ -18,6 +18,7 @@ let hex_digits : FixedArray[String] = [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", ] +/// print a sequence of byte in hex representation pub fn bytes_to_hex_string(input : Bytes) -> String { let mut ret = "" for i = input.length() - 1; i >= 0; i = i - 1 { @@ -43,6 +44,7 @@ fn uint_to_hex_string(input : UInt) -> String { ret.fold_left(String::op_add, init="") } +/// print a sequence of uint in hex representation pub fn uints_to_hex_string(input : Array[UInt]) -> String { input.map(uint_to_hex_string).fold_left(String::op_add, init="") } @@ -55,24 +57,34 @@ fn uint32(x : Byte) -> UInt { x.to_int().to_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 { uint32(x[i]) | uint32(x[i + 1]).lsl(8) | uint32(x[i + 2]).lsl(16) | uint32( x[i + 3], ).lsl(24) } +/// 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], ) } +/// 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 { 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] { let b = Array::make(4, b'\x00') b[0] = x.lsr(24).to_byte() @@ -82,34 +94,40 @@ pub fn u32_to_u8be(x : UInt) -> Array[Byte] { b } +/// convert an array of UInt to Bytes in big endian pub fn arr_u32_to_u8be(x : Array[UInt]) -> Bytes { - let temp : Array[Byte] = [] + let temp : Bytes = Bytes::make(x.length() * 4, b'\x00') for index = 0; index < x.length(); index = index + 1 { - temp.append(u32_to_u8be(x[index])) + let u8 = u32_to_u8be(x[index]) + temp[index * 4] = u8[0] + temp[index * 4 + 1] = u8[1] + temp[index * 4 + 2] = u8[2] + temp[index * 4 + 3] = u8[3] } - Bytes::from_array(temp) + temp } -pub fn byte_array_to_bytes(s : Array[Byte]) -> Bytes { - let bytes = Bytes::make(s.length(), b'\x00') - for index = 0; index < s.length(); index = index + 1 { - bytes[index] = s[index] - } - bytes -} - -pub fn bytes_to_byte_array(s : Bytes) -> Array[Byte] { - let byte_array = Array::make(s.length(), b'\x00') - for index = 0; index < s.length(); index = index + 1 { - byte_array[index] = s[index] - } - byte_array -} - -fn rotate_left(x : Int, n : Int) -> Int { +/// rotate a Int `x` left by `n` bit(s) +pub fn rotate_left(x : Int, n : Int) -> Int { x.lsl(n).lor(x.lsr(32 - n)) } +/// rotate a UInt `x` left by `n` bit(s) fn rotate_left_u(x : UInt, n : Int) -> UInt { x.lsl(n) | x.lsr(32 - n) } + +/// temp function for convert bytes_to_iter in absence of `Bytes::iter()`. +pub fn bytes_to_iter(data : Bytes) -> Iter[Byte] { + Iter::new( + fn(yield) { + for i = 0, len = data.length(); i < len; i = i + 1 { + if yield(data[i]) == IterEnd { + break IterEnd + } + } else { + IterContinue + } + }, + ) +} From 87fc5d9098cd3db42921c4c4cd1907c3582d4a88 Mon Sep 17 00:00:00 2001 From: Evan Gao Date: Tue, 6 Aug 2024 15:24:42 +0800 Subject: [PATCH 3/3] optimize sm3 implementation --- crypto/README.md | 26 +++--- crypto/crypto.mbti | 26 ++---- crypto/md5.mbt | 22 ++--- crypto/md5_test.mbt | 4 +- crypto/sm3.mbt | 215 ++++++++++++++++++++++---------------------- crypto/sm3_test.mbt | 2 +- crypto/utils.mbt | 36 +++++--- 7 files changed, 164 insertions(+), 167 deletions(-) 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 d32789d..72dc32e 100644 --- a/crypto/crypto.mbti +++ b/crypto/crypto.mbti @@ -1,52 +1,36 @@ 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 // Types and methods type MD5Context impl MD5Context { - compute(Self) -> Bytes finalize(Self) -> Bytes - make() -> Self + new() -> Self update(Self, Bytes) -> Unit } 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..7800af3 100644 --- a/crypto/md5.mbt +++ b/crypto/md5.mbt @@ -31,11 +31,11 @@ pub fn MD5Context::update(self : MD5Context, data : Bytes) -> Unit { /// an alias of `MD5Context::compute()` pub fn MD5Context::finalize(self : MD5Context) -> Bytes { - self.compute() + self.md5_compute() } /// Instantiate a MD5 context -pub fn MD5Context::make() -> MD5Context { +pub fn MD5Context::new() -> MD5Context { padding[0] = b'\x80' { state: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476], @@ -45,7 +45,7 @@ pub fn MD5Context::make() -> MD5Context { } /// compute MD5 digest from given context -pub fn MD5Context::compute(self : MD5Context) -> Bytes { +fn MD5Context::md5_compute(self : MD5Context) -> Bytes { let input = FixedArray::make(16, 0U) let idx = (self.count[0].lsr(3) & 0x3f).to_int() input[14] = self.count[0] @@ -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() + ctx.md5_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,13 +246,13 @@ 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 res1 = bytes_to_hex_string(ctx.md5_compute()) + let ctx = MD5Context::new() md5_update(ctx, b"\x61\x62\x63") - let res2 = bytes_to_hex_string(ctx.compute()) + let res2 = bytes_to_hex_string(ctx.md5_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..7d26c51 100644 --- a/crypto/sm3.mbt +++ b/crypto/sm3.mbt @@ -19,18 +19,20 @@ struct SM3Context { reg : FixedArray[UInt] // register A B C D E F G H. i.e. digest mut len : UInt64 - mut msg : Iter[Byte] + mut buf : Bytes + mut buf_index : Int } /// Instantiate a SM3 context -pub fn SM3Context::make() -> SM3Context { +pub fn SM3Context::new() -> SM3Context { { reg: [ 0x7380166F, 0x4914B2B9, 0x172442D7, 0xDA8A0600, 0xA96F30BC, 0x163138AA, 0xE38DEE4D, 0xB0FB0E4E, ], len: 0, - msg: Iter::empty(), + buf: Bytes::new(64), + buf_index: 0, } } @@ -78,23 +80,32 @@ 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() + self.buf[cnt] = b'\x80' + cnt += 1 + if cnt > 56 { + let temp_arr = Bytes::new(128) + temp_arr.blit(0, self.buf, 0, cnt) + self.buf = temp_arr } - 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 +116,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 +179,18 @@ 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) + data.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) + + } + }, + ) } /// update the state of given context from new `data` @@ -200,24 +202,23 @@ pub fn update_from_iter(self : SM3Context, data : Iter[Byte]) -> Unit { self.sm3_update(data) } -/// compute SM3 digest from given context -pub fn compute(self : SM3Context) -> Bytes { - let msg = self.pad() - arr_u32_to_u8be(self.transform(msg)) -} - fn sm3_compute( self : SM3Context, ~data : Iter[Byte] = Iter::empty() ) -> Array[UInt] { self.sm3_update(data) let msg = self.pad() - self.transform(msg) + if msg.length() > 64 { + 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,17 +228,17 @@ 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)) } /// an alias of `SM3Context::compute()` pub fn finalize(self : SM3Context) -> Bytes { - self.compute() + arr_u32_to_u8be(self.sm3_compute()) } test { @@ -259,13 +260,13 @@ 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") - @test.eq!(hash1, bytes_to_hex_string(ctx.compute())) + @test.eq!(hash1, bytes_to_hex_string(ctx.finalize())) } 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..967a51f 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 }