• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

moonbitlang / x / 301

10 Dec 2024 06:19AM UTC coverage: 85.204% (-2.6%) from 87.841%
301

Pull #78

github

web-flow
Merge b830031f4 into 91f0fdf48
Pull Request #78: feat: new package encoding

105 of 161 new or added lines in 3 files covered. (65.22%)

124 existing lines in 29 files now uncovered.

1169 of 1372 relevant lines covered (85.2%)

434.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.44
/crypto/sm3.mbt
1
// Copyright 2024 International Digital Economy Academy
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
// A SM3 implementation based on
16
// - [GM/T 0004-2012]    https://www.oscca.gov.cn/sca/xxgk/2010-12/17/1002389/files/302a3ada057c4a73830536d03e683110.pdf
17
// SM3 is as secure as SHA256, providing similar performance. https://doi.org/10.3390/electronics8091033
18

19
///|
20
struct SM3Context {
21
  reg : FixedArray[UInt] // register A B C D E F G H. i.e. digest
22
  mut len : UInt64
23
  mut buf : Bytes
24
  mut buf_index : Int
25
}
26

27
///| Instantiate a SM3 context
28
pub fn SM3Context::new() -> SM3Context {
29
  {
14✔
30
    reg: [
31
      0x7380166F, 0x4914B2B9, 0x172442D7, 0xDA8A0600, 0xA96F30BC, 0x163138AA, 0xE38DEE4D,
32
      0xB0FB0E4E,
33
    ],
34
    len: 0,
35
    buf: Bytes::new(64),
36
    buf_index: 0,
37
  }
38
}
39

40
///|
41
let t : FixedArray[UInt] = [ // pre calculated
42
  0x79cc4519, 0xf3988a32, 0xe7311465, 0xce6228cb, 0x9cc45197, 0x3988a32f, 0x7311465e,
43
  0xe6228cbc, 0xcc451979, 0x988a32f3, 0x311465e7, 0x6228cbce, 0xc451979c, 0x88a32f39,
44
  0x11465e73, 0x228cbce6, 0x9d8a7a87, 0x3b14f50f, 0x7629ea1e, 0xec53d43c, 0xd8a7a879,
45
  0xb14f50f3, 0x629ea1e7, 0xc53d43ce, 0x8a7a879d, 0x14f50f3b, 0x29ea1e76, 0x53d43cec,
46
  0xa7a879d8, 0x4f50f3b1, 0x9ea1e762, 0x3d43cec5, 0x7a879d8a, 0xf50f3b14, 0xea1e7629,
47
  0xd43cec53, 0xa879d8a7, 0x50f3b14f, 0xa1e7629e, 0x43cec53d, 0x879d8a7a, 0x0f3b14f5,
48
  0x1e7629ea, 0x3cec53d4, 0x79d8a7a8, 0xf3b14f50, 0xe7629ea1, 0xcec53d43, 0x9d8a7a87,
49
  0x3b14f50f, 0x7629ea1e, 0xec53d43c, 0xd8a7a879, 0xb14f50f3, 0x629ea1e7, 0xc53d43ce,
50
  0x8a7a879d, 0x14f50f3b, 0x29ea1e76, 0x53d43cec, 0xa7a879d8, 0x4f50f3b1, 0x9ea1e762,
51
  0x3d43cec5,
52
]
53

54
// auxiliary functions
55
// FF_j = | X xor Y xor Z                       where 0 <= j <= 15
56
//        | (X and Y) or (X and Z) or (Y and Z) where 16 <= j <=63
57
///|
58
fn SM3Context::ff_0(x : UInt, y : UInt, z : UInt) -> UInt {
59
  x ^ y ^ z
560✔
60
}
61

62
///|
63
fn SM3Context::ff_1(x : UInt, y : UInt, z : UInt) -> UInt {
64
  (x & y) | (x & z) | (y & z)
5,712✔
65
}
66

67
// GG_j = | X xor Y xor Z           where 0 <= j <= 15
68
//        | (X and Y) or (~X and Z) where 16 <= j <= 63
69
///|
70
fn SM3Context::gg_0(x : UInt, y : UInt, z : UInt) -> UInt {
71
  x ^ y ^ z
560✔
72
}
73

74
///|
75
fn SM3Context::gg_1(x : UInt, y : UInt, z : UInt) -> UInt {
76
  ((y ^ z) & x) ^ z // equivalent of (x & y) | (x.lnot() & z), but faster
5,712✔
77
}
78

79
// P_0 = X xor (X <<< 9) xor (X <<< 17)
80
// P_1 = X xor (X <<< 15) xor (X <<< 23)
81
///|
82
fn SM3Context::p_0(x : UInt) -> UInt {
83
  x ^ rotate_left_u(x, 9) ^ rotate_left_u(x, 17)
2,240✔
84
}
85

86
///|
87
fn SM3Context::p_1(x : UInt) -> UInt {
88
  x ^ rotate_left_u(x, 15) ^ rotate_left_u(x, 23)
1,820✔
89
}
90

91
///|
92
fn pad(self : SM3Context) -> Bytes {
93
  let mut cnt = self.buf_index
14✔
94
  self.len += 8UL * cnt.to_uint64()
95
  self.buf[cnt] = b'\x80'
96
  cnt += 1
97
  if cnt > 56 {
98
    let temp_arr = Bytes::new(128)
2✔
99
    temp_arr.blit(0, self.buf, 0, cnt)
100
    self.buf = temp_arr
101
  }
102
  while cnt % 64 != 56 {
668✔
103
    self.buf[cnt] = b'\x00'
654✔
104
    cnt += 1
105
  }
106
  self.buf[cnt] = (self.len >> 56).to_byte()
107
  self.buf[cnt + 1] = (self.len >> 48).to_byte()
108
  self.buf[cnt + 2] = (self.len >> 40).to_byte()
109
  self.buf[cnt + 3] = (self.len >> 32).to_byte()
110
  self.buf[cnt + 4] = (self.len >> 24).to_byte()
111
  self.buf[cnt + 5] = (self.len >> 16).to_byte()
112
  self.buf[cnt + 6] = (self.len >> 8).to_byte()
113
  self.buf[cnt + 7] = (self.len >> 0).to_byte()
114
  return self.buf
115
}
116

117
///|
118
fn transform(
119
  self : SM3Context,
120
  data : Bytes,
121
  offset~ : Int = 0
122
) -> FixedArray[UInt] {
123
  let w_0 = FixedArray::make(68, 0U)
35✔
124
  let w_1 = FixedArray::make(64, 0U)
125
  let mut a = self.reg[0]
126
  let mut b = self.reg[1]
127
  let mut c = self.reg[2]
128
  let mut d = self.reg[3]
129
  let mut e = self.reg[4]
130
  let mut f = self.reg[5]
131
  let mut g = self.reg[6]
132
  let mut h = self.reg[7]
133
  for index = 0; index < 16; index = index + 1 {
560✔
134
    w_0[index] = bytes_u8_to_u32be(data, i=4 * index + offset)
560✔
135
  }
136
  for index = 16; index < 68; index = index + 1 {
1,820✔
137
    w_0[index] = p_1(
1,820✔
138
        w_0[index - 16] ^ w_0[index - 9] ^ rotate_left_u(w_0[index - 3], 15),
139
      ) ^
140
      rotate_left_u(w_0[index - 13], 7) ^
141
      w_0[index - 6]
142
  }
143
  for index = 0; index < 64; index = index + 1 {
2,240✔
144
    w_1[index] = w_0[index] ^ w_0[index + 4]
2,240✔
145
  }
146
  let mut a1 = a
147
  let mut b1 = b
148
  let mut c1 = c
149
  let mut d1 = d
150
  let mut e1 = e
151
  let mut f1 = f
152
  let mut g1 = g
153
  let mut h1 = h
154
  for index = 0; index < 16; index = index + 1 {
560✔
155
    let ss_1 = rotate_left_u(rotate_left_u(a1, 12) + e1 + t[index], 7)
560✔
156
    let ss_2 = ss_1 ^ rotate_left_u(a1, 12)
157
    let tt_1 = ff_0(a1, b1, c1) + d1 + ss_2 + w_1[index]
158
    let tt_2 = gg_0(e1, f1, g1) + h1 + ss_1 + w_0[index]
159
    d1 = c1
160
    c1 = rotate_left_u(b1, 9)
161
    b1 = a1
162
    a1 = tt_1
163
    h1 = g1
164
    g1 = rotate_left_u(f1, 19)
165
    f1 = e1
166
    e1 = p_0(tt_2)
167
  }
168
  for index = 16; index < 64; index = index + 1 {
1,680✔
169
    let ss_1 = rotate_left_u(rotate_left_u(a1, 12) + e1 + t[index], 7)
1,680✔
170
    let ss_2 = ss_1 ^ rotate_left_u(a1, 12)
171
    let tt_1 = ff_1(a1, b1, c1) + d1 + ss_2 + w_1[index]
172
    let tt_2 = gg_1(e1, f1, g1) + h1 + ss_1 + w_0[index]
173
    d1 = c1
174
    c1 = rotate_left_u(b1, 9)
175
    b1 = a1
176
    a1 = tt_1
177
    h1 = g1
178
    g1 = rotate_left_u(f1, 19)
179
    f1 = e1
180
    e1 = p_0(tt_2)
181
  }
182
  a = a ^ a1
183
  b = b ^ b1
184
  c = c ^ c1
185
  d = d ^ d1
186
  e = e ^ e1
187
  f = f ^ f1
188
  g = g ^ g1
189
  h = h ^ h1
190
  let t_arr : FixedArray[UInt] = [a, b, c, d, e, f, g, h]
191
  for index = 0; index < 8; index = index + 1 {
280✔
192
    self.reg[index] = t_arr[index]
280✔
193
  }
194
  return t_arr
195
}
196

197
///|
198
pub fn update_from_iter(self : SM3Context, data : Iter[Byte]) -> Unit {
199
  data.each(
30✔
200
    fn(b) {
201
      self.buf[self.buf_index] = b
64✔
202
      self.buf_index += 1
203
      if self.buf_index == 64 {
204
        self.buf_index = 0
1✔
205
        self.len += 512UL
206
        let _ = self.transform(self.buf)
207

208
      }
209
    },
210
  )
211
}
212

213
///| update the state of given context from new `data` 
214
pub fn update(self : SM3Context, data : Bytes) -> Unit {
215
  let mut offset = 0
78✔
216
  while offset < data.length() {
171✔
217
    let min_len = if 64 - self.buf_index >= data.length() - offset {
93✔
218
      data.length() - offset
77✔
219
    } else {
220
      64 - self.buf_index
16✔
221
    }
222
    self.buf.blit(self.buf_index, data, offset, min_len)
223
    self.buf_index += min_len
224
    if self.buf_index == 64 {
225
      self.len += 512UL
18✔
226
      self.buf_index = 0
227
      let _ = self.transform(self.buf)
228

229
    }
230
    offset += min_len
231
  }
232
}
233

234
///|
235
fn sm3_compute(
236
  self : SM3Context,
237
  data~ : Iter[Byte] = Iter::empty()
238
) -> FixedArray[UInt] {
239
  self.update_from_iter(data)
14✔
240
  let msg = self.pad()
241
  if msg.length() > 64 {
242
    let _ = self.transform(msg)
2✔
243
    self.transform(msg, offset=64)
244
  } else {
245
    self.transform(msg)
12✔
246
  }
247
}
248

249
///| Compute the SM3 digest from given SM3Context
250
pub fn finalize(self : SM3Context) -> Bytes {
251
  arr_u32_to_u8be(self.sm3_compute().iter(), 256)
3✔
252
}
253

254
///| Compute the SM3 digest in `Bytes` of some `data`. Note that SM3 is big-endian.
255
pub fn sm3(data : Bytes) -> Bytes {
256
  let ctx = SM3Context::new()
8✔
257
  let _ = ctx.update(data)
258
  arr_u32_to_u8be(ctx.sm3_compute().iter(), 256)
259
}
260

261
///|
262
pub fn sm3_from_iter(data : Iter[Byte]) -> Bytes {
UNCOV
263
  let ctx = SM3Context::new()
×
264
  let _ = ctx.update_from_iter(data)
265
  arr_u32_to_u8be(ctx.sm3_compute().iter(), 256)
266
}
267

268
test {
269
  fn sm3_u32(data : Bytes) -> FixedArray[UInt] {
270
    let ctx = SM3Context::new()
271
    let _ = ctx.update(data)
272
    ctx.sm3_compute()
273
  }
274

275
  inspect!(
276
    uints_to_hex_string(
277
      sm3_u32(
278
        b"\x61\x62\x63", // abc in utf-8
279
      ).iter(),
280
    ),
281
    content="66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0",
282
  )
283
  inspect!(
284
    uints_to_hex_string(
285
      sm3_u32(
286
        // abcd * 16 in utf-8
287
        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",
288
      ).iter(),
289
    ),
290
    content="debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732",
291
  )
292
  assert_eq!(
293
    bytes_to_hex_string(sm3(b"\x61\x62\x63")),
294
    uints_to_hex_string(sm3_u32(b"\x61\x62\x63").iter()),
295
  )
296
  let hash1 = "66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0"
297
  let ctx = SM3Context::new()
298
  ctx.update(b"\x61")
299
  ctx.update(b"\x62")
300
  ctx.update(b"\x63")
301
  assert_eq!(hash1, bytes_to_hex_string(ctx.finalize()))
302
  let ctx = SM3Context::new()
303
  let data = 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"
304
  for i = 0; i < data.length(); i = i + 1 {
305
    ctx.update(Bytes::make(1, data[i]))
306
  }
307
  assert_eq!(
308
    bytes_to_hex_string(ctx.finalize()),
309
    "debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732",
310
  )
311
  let ctx = SM3Context::new()
312
  for i = 0; i < data.length(); i = i + 4 {
313
    ctx.update_from_iter(b"\x61\x62\x63\x64".iter())
314
  }
315
  assert_eq!(
316
    bytes_to_hex_string(ctx.finalize()),
317
    "debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732",
318
  )
319
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc