• 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

86.96
/crypto/md5.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
// An MD5 message-digest algorithm implementation based on
16
// [RFC1321]       https://www.ietf.org/rfc/rfc1321.txt
17
// [Ron Rivest]    https://people.csail.mit.edu/rivest/Md5.c
18
// [md5-0.7.0]     https://docs.rs/md5/0.7.0/src/md5/lib.rs.html 
19
///|
20
struct MD5Context {
21
  state : FixedArray[UInt] // state 'a' 'b' 'c' 'd'
22
  count : FixedArray[UInt]
23
  buffer : Bytes
24
}
25

26
///|
27
let padding : Bytes = Bytes::make(64, b'\x00')
28

29
///| update the state of given context from new `data` 
30
pub fn MD5Context::update(self : MD5Context, data : Bytes) -> Unit {
UNCOV
31
  md5_update(self, data)
×
32
}
33

34
///| an alias of `MD5Context::compute()`
35
pub fn MD5Context::finalize(self : MD5Context) -> Bytes {
UNCOV
36
  self.md5_compute()
×
37
}
38

39
///| Instantiate a MD5 context
40
pub fn MD5Context::new() -> MD5Context {
41
  padding[0] = b'\x80'
12✔
42
  {
43
    state: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476],
44
    count: [0, 0],
45
    buffer: Bytes::make(64, b'\x00'),
46
  }
47
}
48

49
///| compute MD5 digest from given context
50
fn MD5Context::md5_compute(self : MD5Context) -> Bytes {
51
  let input = FixedArray::make(16, 0U)
12✔
52
  let idx = ((self.count[0] >> 3) & 0x3f).reinterpret_as_int()
53
  input[14] = self.count[0]
54
  input[15] = self.count[1]
55
  let bytes_slice = if idx < 56 {
56
    let bytes_slice = Bytes::make(56 - idx + 1, b'\x00')
10✔
57
    bytes_slice.blit(0, padding, 0, 56 - idx + 1)
58
    bytes_slice
59
  } else {
60
    let bytes_slice = Bytes::make(120 - idx + 1, b'\x00')
2✔
61
    bytes_slice.blit(0, padding, 0, 120 - idx + 1)
62
    bytes_slice
63
  }
64
  md5_update(self, bytes_slice)
65
  let mut j = 0
66
  for i = 0; i < 14; i = i + 1 {
168✔
67
    input[i] = u8_to_u32le(self.buffer, i=j)
168✔
68
    j += 4
69
  }
70
  md5_transform(self.state, input)
71
  let digest = Bytes::make(16, b'\x00')
72
  let mut j = 0
73
  // u32 to u8
74
  for i = 0; i < 4; i = i + 1 {
48✔
75
    digest[j] = (self.state[i] & 0xff).reinterpret_as_int().to_byte()
48✔
76
    digest[j + 1] = ((self.state[i] >> 8) & 0xff).reinterpret_as_int().to_byte()
77
    digest[j + 2] = ((self.state[i] >> 16) & 0xff)
78
      .reinterpret_as_int()
79
      .to_byte()
80
    digest[j + 3] = ((self.state[i] >> 24) & 0xff)
81
      .reinterpret_as_int()
82
      .to_byte()
83
    j += 4
84
  }
85
  digest
86
}
87

88
// no macros, nor inline. basic md5 functions
89
// four auxiliary functions
90
//          F(X,Y,Z) = XY v not(X) Z
91
//          G(X,Y,Z) = XZ v Y not(Z)
92
//          H(X,Y,Z) = X xor Y xor Z
93
//          I(X,Y,Z) = Y xor (X v not(Z))
94
///|
95
fn MD5Context::f(x : UInt, y : UInt, z : UInt) -> UInt {
96
  (x & y) | (x.lnot() & z)
736✔
97
}
98

99
///|
100
fn MD5Context::g(x : UInt, y : UInt, z : UInt) -> UInt {
101
  ((x ^ y) & z) ^ y
736✔
102
}
103

104
///|
105
fn MD5Context::h(x : UInt, y : UInt, z : UInt) -> UInt {
106
  x ^ y ^ z
736✔
107
}
108

109
///|
110
fn MD5Context::i(x : UInt, y : UInt, z : UInt) -> UInt {
111
  y ^ (x | z.lnot())
736✔
112
}
113

114
///|
115
fn md5_update(ctx : MD5Context, data : Bytes) -> Unit {
116
  let input = FixedArray::make(16, 0U)
26✔
117
  let mut idx = ((ctx.count[0] >> 3) & 0x3f).reinterpret_as_int()
118
  let length = data.length()
119
  let mod_length = length.reinterpret_as_uint() << 3
120
  ctx.count[0] += mod_length
121
  if ctx.count[0] < mod_length {
UNCOV
122
    ctx.count[1] += 1
×
123
  }
124
  ctx.count[1] += length.reinterpret_as_uint() >> 29
125
  for i = 0; i < length; i = i + 1 {
2,860✔
126
    ctx.buffer[idx] = data[i]
2,860✔
127
    idx += 1
128
    if idx == 0x40 {
129
      let mut j = 0
34✔
130
      for k = 0; k < 16; k = k + 1 {
544✔
131
        input[k] = u8_to_u32le(ctx.buffer, i=j)
544✔
132
        j += 4
133
      }
134
      md5_transform(ctx.state, input)
135
      idx = 0
136
    }
137
  }
138
}
139

140
///|
141
fn md5_transform(state : FixedArray[UInt], input : FixedArray[UInt]) -> Unit {
142
  let mut a = state[0]
46✔
143
  let mut b = state[1]
144
  let mut c = state[2]
145
  let mut d = state[3]
146

147
  // Round 1
148
  // s[ 0..15] := { 7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22 }
149
  a = b + rotate_left_u(a + f(b, c, d) + input[0] + 0xd76aa478, 7)
150
  d = a + rotate_left_u(d + f(a, b, c) + input[1] + 0xe8c7b756, 12)
151
  c = d + rotate_left_u(c + f(d, a, b) + input[2] + 0x242070db, 17)
152
  b = c + rotate_left_u(b + f(c, d, a) + input[3] + 0xc1bdceee, 22)
153
  a = b + rotate_left_u(a + f(b, c, d) + input[4] + 0xf57c0faf, 7)
154
  d = a + rotate_left_u(d + f(a, b, c) + input[5] + 0x4787c62a, 12)
155
  c = d + rotate_left_u(c + f(d, a, b) + input[6] + 0xa8304613, 17)
156
  b = c + rotate_left_u(b + f(c, d, a) + input[7] + 0xfd469501, 22)
157
  a = b + rotate_left_u(a + f(b, c, d) + input[8] + 0x698098d8, 7)
158
  d = a + rotate_left_u(d + f(a, b, c) + input[9] + 0x8b44f7af, 12)
159
  c = d + rotate_left_u(c + f(d, a, b) + input[10] + 0xffff5bb1, 17)
160
  b = c + rotate_left_u(b + f(c, d, a) + input[11] + 0x895cd7be, 22)
161
  a = b + rotate_left_u(a + f(b, c, d) + input[12] + 0x6b901122, 7)
162
  d = a + rotate_left_u(d + f(a, b, c) + input[13] + 0xfd987193, 12)
163
  c = d + rotate_left_u(c + f(d, a, b) + input[14] + 0xa679438e, 17)
164
  b = c + rotate_left_u(b + f(c, d, a) + input[15] + 0x49b40821, 22)
165

166
  // Round 2
167
  // s[16..31] := { 5,  9, 14, 20,  5,  9, 14, 20,  5,  9, 14, 20,  5,  9, 14, 20 }
168
  a = b + rotate_left_u(a + g(b, c, d) + input[1] + 0xf61e2562, 5)
169
  d = a + rotate_left_u(d + g(a, b, c) + input[6] + 0xc040b340, 9)
170
  c = d + rotate_left_u(c + g(d, a, b) + input[11] + 0x265e5a51, 14)
171
  b = c + rotate_left_u(b + g(c, d, a) + input[0] + 0xe9b6c7aa, 20)
172
  a = b + rotate_left_u(a + g(b, c, d) + input[5] + 0xd62f105d, 5)
173
  d = a + rotate_left_u(d + g(a, b, c) + input[10] + 0x02441453, 9)
174
  c = d + rotate_left_u(c + g(d, a, b) + input[15] + 0xd8a1e681, 14)
175
  b = c + rotate_left_u(b + g(c, d, a) + input[4] + 0xe7d3fbc8, 20)
176
  a = b + rotate_left_u(a + g(b, c, d) + input[9] + 0x21e1cde6, 5)
177
  d = a + rotate_left_u(d + g(a, b, c) + input[14] + 0xc33707d6, 9)
178
  c = d + rotate_left_u(c + g(d, a, b) + input[3] + 0xf4d50d87, 14)
179
  b = c + rotate_left_u(b + g(c, d, a) + input[8] + 0x455a14ed, 20)
180
  a = b + rotate_left_u(a + g(b, c, d) + input[13] + 0xa9e3e905, 5)
181
  d = a + rotate_left_u(d + g(a, b, c) + input[2] + 0xfcefa3f8, 9)
182
  c = d + rotate_left_u(c + g(d, a, b) + input[7] + 0x676f02d9, 14)
183
  b = c + rotate_left_u(b + g(c, d, a) + input[12] + 0x8d2a4c8a, 20)
184

185
  // Round 3
186
  // s[32..47] := { 4, 11, 16, 23,  4, 11, 16, 23,  4, 11, 16, 23,  4, 11, 16, 23 }
187
  a = b + rotate_left_u(a + h(b, c, d) + input[5] + 0xfffa3942, 4)
188
  d = a + rotate_left_u(d + h(a, b, c) + input[8] + 0x8771f681, 11)
189
  c = d + rotate_left_u(c + h(d, a, b) + input[11] + 0x6d9d6122, 16)
190
  b = c + rotate_left_u(b + h(c, d, a) + input[14] + 0xfde5380c, 23)
191
  a = b + rotate_left_u(a + h(b, c, d) + input[1] + 0xa4beea44, 4)
192
  d = a + rotate_left_u(d + h(a, b, c) + input[4] + 0x4bdecfa9, 11)
193
  c = d + rotate_left_u(c + h(d, a, b) + input[7] + 0xf6bb4b60, 16)
194
  b = c + rotate_left_u(b + h(c, d, a) + input[10] + 0xbebfbc70, 23)
195
  a = b + rotate_left_u(a + h(b, c, d) + input[13] + 0x289b7ec6, 4)
196
  d = a + rotate_left_u(d + h(a, b, c) + input[0] + 0xeaa127fa, 11)
197
  c = d + rotate_left_u(c + h(d, a, b) + input[3] + 0xd4ef3085, 16)
198
  b = c + rotate_left_u(b + h(c, d, a) + input[6] + 0x04881d05, 23)
199
  a = b + rotate_left_u(a + h(b, c, d) + input[9] + 0xd9d4d039, 4)
200
  d = a + rotate_left_u(d + h(a, b, c) + input[12] + 0xe6db99e5, 11)
201
  c = d + rotate_left_u(c + h(d, a, b) + input[15] + 0x1fa27cf8, 16)
202
  b = c + rotate_left_u(b + h(c, d, a) + input[2] + 0xc4ac5665, 23)
203

204
  // Round 4
205
  // s[48..63] := { 6, 10, 15, 21,  6, 10, 15, 21,  6, 10, 15, 21,  6, 10, 15, 21 }
206
  a = b + rotate_left_u(a + i(b, c, d) + input[0] + 0xf4292244, 6)
207
  d = a + rotate_left_u(d + i(a, b, c) + input[7] + 0x432aff97, 10)
208
  c = d + rotate_left_u(c + i(d, a, b) + input[14] + 0xab9423a7, 15)
209
  b = c + rotate_left_u(b + i(c, d, a) + input[5] + 0xfc93a039, 21)
210
  a = b + rotate_left_u(a + i(b, c, d) + input[12] + 0x655b59c3, 6)
211
  d = a + rotate_left_u(d + i(a, b, c) + input[3] + 0x8f0ccc92, 10)
212
  c = d + rotate_left_u(c + i(d, a, b) + input[10] + 0xffeff47d, 15)
213
  b = c + rotate_left_u(b + i(c, d, a) + input[1] + 0x85845dd1, 21)
214
  a = b + rotate_left_u(a + i(b, c, d) + input[8] + 0x6fa87e4f, 6)
215
  d = a + rotate_left_u(d + i(a, b, c) + input[15] + 0xfe2ce6e0, 10)
216
  c = d + rotate_left_u(c + i(d, a, b) + input[6] + 0xa3014314, 15)
217
  b = c + rotate_left_u(b + i(c, d, a) + input[13] + 0x4e0811a1, 21)
218
  a = b + rotate_left_u(a + i(b, c, d) + input[4] + 0xf7537e82, 6)
219
  d = a + rotate_left_u(d + i(a, b, c) + input[11] + 0xbd3af235, 10)
220
  c = d + rotate_left_u(c + i(d, a, b) + input[2] + 0x2ad7d2bb, 15)
221
  b = c + rotate_left_u(b + i(c, d, a) + input[9] + 0xeb86d391, 21)
222
  state[0] += a
223
  state[1] += b
224
  state[2] += c
225
  state[3] += d
226
}
227

228
///| Compute the MD5 digest of some `data` based on [RFC1321](https://www.ietf.org/rfc/rfc1321.txt).
229
/// - Note that MD5 is considered _cryptographically broken_.
230
/// Unless mandated, more secure alternatives should be preferred.
231
pub fn md5(data : Bytes) -> Bytes {
232
  let ctx = MD5Context::new()
10✔
233
  md5_update(ctx, data)
234
  ctx.md5_compute()
235
}
236

237
test "md5_wb" {
238
  let hash = md5("The quick brown fox jumps over the lazy dog".to_bytes())
239
  inspect!(
240
    bytes_to_hex_string(hash),
241
    content="b0986ae6ee1eefee8a4a399090126837",
242
  )
243
}
244

245
test {
246
  let ctx = MD5Context::new()
247
  md5_update(ctx, b"\x61")
248
  md5_update(ctx, b"\x62")
249
  md5_update(ctx, b"\x63")
250
  let res1 = bytes_to_hex_string(ctx.md5_compute())
251
  let ctx = MD5Context::new()
252
  md5_update(ctx, b"\x61\x62\x63")
253
  let res2 = bytes_to_hex_string(ctx.md5_compute())
254
  assert_eq!(res1, res2)
255
}
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