【笔记】Solidity计算字符串的MD5值

前言

Solidity计算字符串的MD5值

工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.10;

library MD5 {

function T() internal pure returns (uint32[64] memory t) {
t[0] = 0xd76aa478; t[1] = 0xe8c7b756; t[2] = 0x242070db; t[3] = 0xc1bdceee;
t[4] = 0xf57c0faf; t[5] = 0x4787c62a; t[6] = 0xa8304613; t[7] = 0xfd469501;
t[8] = 0x698098d8; t[9] = 0x8b44f7af; t[10] = 0xffff5bb1; t[11] = 0x895cd7be;
t[12] = 0x6b901122; t[13] = 0xfd987193; t[14] = 0xa679438e; t[15] = 0x49b40821;
t[16] = 0xf61e2562; t[17] = 0xc040b340; t[18] = 0x265e5a51; t[19] = 0xe9b6c7aa;
t[20] = 0xd62f105d; t[21] = 0x02441453; t[22] = 0xd8a1e681; t[23] = 0xe7d3fbc8;
t[24] = 0x21e1cde6; t[25] = 0xc33707d6; t[26] = 0xf4d50d87; t[27] = 0x455a14ed;
t[28] = 0xa9e3e905; t[29] = 0xfcefa3f8; t[30] = 0x676f02d9; t[31] = 0x8d2a4c8a;
t[32] = 0xfffa3942; t[33] = 0x8771f681; t[34] = 0x6d9d6122; t[35] = 0xfde5380c;
t[36] = 0xa4beea44; t[37] = 0x4bdecfa9; t[38] = 0xf6bb4b60; t[39] = 0xbebfbc70;
t[40] = 0x289b7ec6; t[41] = 0xeaa127fa; t[42] = 0xd4ef3085; t[43] = 0x04881d05;
t[44] = 0xd9d4d039; t[45] = 0xe6db99e5; t[46] = 0x1fa27cf8; t[47] = 0xc4ac5665;
t[48] = 0xf4292244; t[49] = 0x432aff97; t[50] = 0xab9423a7; t[51] = 0xfc93a039;
t[52] = 0x655b59c3; t[53] = 0x8f0ccc92; t[54] = 0xffeff47d; t[55] = 0x85845dd1;
t[56] = 0x6fa87e4f; t[57] = 0xfe2ce6e0; t[58] = 0xa3014314; t[59] = 0x4e0811a1;
t[60] = 0xf7537e82; t[61] = 0xbd3af235; t[62] = 0x2ad7d2bb; t[63] = 0xeb86d391;
}

function rotl(uint32 x, uint8 n) private pure returns (uint32) {
unchecked { return (x << n) | (x >> (32 - n)); }
}

function hash(string memory input) internal pure returns (bytes16) {
bytes memory data = bytes(input);
uint256 len = data.length;

bytes memory block64 = new bytes(64);

for (uint256 i = 0; i < len; i++) {
block64[i] = data[i];
}
block64[len] = 0x80;
uint64 bitLen = uint64(len) * 8;
unchecked {
block64[56] = bytes1(uint8(bitLen));
block64[57] = bytes1(uint8(bitLen >> 8));
block64[58] = bytes1(uint8(bitLen >> 16));
block64[59] = bytes1(uint8(bitLen >> 24));
}

uint32[16] memory M;
unchecked {
for (uint256 i = 0; i < 16; i++) {
uint256 off = i * 4;
M[i] = uint32(uint8(block64[off]))
| (uint32(uint8(block64[off + 1])) << 8)
| (uint32(uint8(block64[off + 2])) << 16)
| (uint32(uint8(block64[off + 3])) << 24);
}
}

uint32 a = 0x67452301;
uint32 b = 0xefcdab89;
uint32 c = 0x98badcfe;
uint32 d = 0x10325476;

uint32[64] memory t = T();

// Round 1: F(x,y,z) = (x&y) | (~x&z)
unchecked {
a = b + rotl(a + ((b & c) | (~b & d)) + M[0] + t[0], 7);
d = a + rotl(d + ((a & b) | (~a & c)) + M[1] + t[1], 12);
c = d + rotl(c + ((d & a) | (~d & b)) + M[2] + t[2], 17);
b = c + rotl(b + ((c & d) | (~c & a)) + M[3] + t[3], 22);
a = b + rotl(a + ((b & c) | (~b & d)) + M[4] + t[4], 7);
d = a + rotl(d + ((a & b) | (~a & c)) + M[5] + t[5], 12);
c = d + rotl(c + ((d & a) | (~d & b)) + M[6] + t[6], 17);
b = c + rotl(b + ((c & d) | (~c & a)) + M[7] + t[7], 22);
a = b + rotl(a + ((b & c) | (~b & d)) + M[8] + t[8], 7);
d = a + rotl(d + ((a & b) | (~a & c)) + M[9] + t[9], 12);
c = d + rotl(c + ((d & a) | (~d & b)) + M[10] + t[10], 17);
b = c + rotl(b + ((c & d) | (~c & a)) + M[11] + t[11], 22);
a = b + rotl(a + ((b & c) | (~b & d)) + M[12] + t[12], 7);
d = a + rotl(d + ((a & b) | (~a & c)) + M[13] + t[13], 12);
c = d + rotl(c + ((d & a) | (~d & b)) + M[14] + t[14], 17);
b = c + rotl(b + ((c & d) | (~c & a)) + M[15] + t[15], 22);
}

// Round 2: G(x,y,z) = (x&z) | (y&~z)
unchecked {
a = b + rotl(a + ((b & d) | (c & ~d)) + M[1] + t[16], 5);
d = a + rotl(d + ((a & c) | (b & ~c)) + M[6] + t[17], 9);
c = d + rotl(c + ((d & b) | (a & ~b)) + M[11] + t[18], 14);
b = c + rotl(b + ((c & a) | (d & ~a)) + M[0] + t[19], 20);
a = b + rotl(a + ((b & d) | (c & ~d)) + M[5] + t[20], 5);
d = a + rotl(d + ((a & c) | (b & ~c)) + M[10] + t[21], 9);
c = d + rotl(c + ((d & b) | (a & ~b)) + M[15] + t[22], 14);
b = c + rotl(b + ((c & a) | (d & ~a)) + M[4] + t[23], 20);
a = b + rotl(a + ((b & d) | (c & ~d)) + M[9] + t[24], 5);
d = a + rotl(d + ((a & c) | (b & ~c)) + M[14] + t[25], 9);
c = d + rotl(c + ((d & b) | (a & ~b)) + M[3] + t[26], 14);
b = c + rotl(b + ((c & a) | (d & ~a)) + M[8] + t[27], 20);
a = b + rotl(a + ((b & d) | (c & ~d)) + M[13] + t[28], 5);
d = a + rotl(d + ((a & c) | (b & ~c)) + M[2] + t[29], 9);
c = d + rotl(c + ((d & b) | (a & ~b)) + M[7] + t[30], 14);
b = c + rotl(b + ((c & a) | (d & ~a)) + M[12] + t[31], 20);
}

// Round 3: H(x,y,z) = x ^ y ^ z
unchecked {
a = b + rotl(a + (b ^ c ^ d) + M[5] + t[32], 4);
d = a + rotl(d + (a ^ b ^ c) + M[8] + t[33], 11);
c = d + rotl(c + (d ^ a ^ b) + M[11] + t[34], 16);
b = c + rotl(b + (c ^ d ^ a) + M[14] + t[35], 23);
a = b + rotl(a + (b ^ c ^ d) + M[1] + t[36], 4);
d = a + rotl(d + (a ^ b ^ c) + M[4] + t[37], 11);
c = d + rotl(c + (d ^ a ^ b) + M[7] + t[38], 16);
b = c + rotl(b + (c ^ d ^ a) + M[10] + t[39], 23);
a = b + rotl(a + (b ^ c ^ d) + M[13] + t[40], 4);
d = a + rotl(d + (a ^ b ^ c) + M[0] + t[41], 11);
c = d + rotl(c + (d ^ a ^ b) + M[3] + t[42], 16);
b = c + rotl(b + (c ^ d ^ a) + M[6] + t[43], 23);
a = b + rotl(a + (b ^ c ^ d) + M[9] + t[44], 4);
d = a + rotl(d + (a ^ b ^ c) + M[12] + t[45], 11);
c = d + rotl(c + (d ^ a ^ b) + M[15] + t[46], 16);
b = c + rotl(b + (c ^ d ^ a) + M[2] + t[47], 23);
}

// Round 4: I(x,y,z) = y ^ (x | ~z)
unchecked {
a = b + rotl(a + (c ^ (b | ~d)) + M[0] + t[48], 6);
d = a + rotl(d + (b ^ (a | ~c)) + M[7] + t[49], 10);
c = d + rotl(c + (a ^ (d | ~b)) + M[14] + t[50], 15);
b = c + rotl(b + (d ^ (c | ~a)) + M[5] + t[51], 21);
a = b + rotl(a + (c ^ (b | ~d)) + M[12] + t[52], 6);
d = a + rotl(d + (b ^ (a | ~c)) + M[3] + t[53], 10);
c = d + rotl(c + (a ^ (d | ~b)) + M[10] + t[54], 15);
b = c + rotl(b + (d ^ (c | ~a)) + M[1] + t[55], 21);
a = b + rotl(a + (c ^ (b | ~d)) + M[8] + t[56], 6);
d = a + rotl(d + (b ^ (a | ~c)) + M[15] + t[57], 10);
c = d + rotl(c + (a ^ (d | ~b)) + M[6] + t[58], 15);
b = c + rotl(b + (d ^ (c | ~a)) + M[13] + t[59], 21);
a = b + rotl(a + (c ^ (b | ~d)) + M[4] + t[60], 6);
d = a + rotl(d + (b ^ (a | ~c)) + M[11] + t[61], 10);
c = d + rotl(c + (a ^ (d | ~b)) + M[2] + t[62], 15);
b = c + rotl(b + (d ^ (c | ~a)) + M[9] + t[63], 21);
}

unchecked {
a += 0x67452301;
b += 0xefcdab89;
c += 0x98badcfe;
d += 0x10325476;
}

unchecked {
uint32 ra = (a >> 24) | ((a >> 8) & 0x0000FF00) | ((a << 8) & 0x00FF0000) | (a << 24);
uint32 rb = (b >> 24) | ((b >> 8) & 0x0000FF00) | ((b << 8) & 0x00FF0000) | (b << 24);
uint32 rc = (c >> 24) | ((c >> 8) & 0x0000FF00) | ((c << 8) & 0x00FF0000) | (c << 24);
uint32 rd = (d >> 24) | ((d >> 8) & 0x0000FF00) | ((d << 8) & 0x00FF0000) | (d << 24);
return bytes16(
(bytes32(uint256(ra)) << 224)
| (bytes32(uint256(rb)) << 192)
| (bytes32(uint256(rc)) << 160)
| (bytes32(uint256(rd)) << 128)
);
}
}
}

计算字符串的MD5值

1
2
3
4
5
6
7
8
9
10
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.10;

import "./MD5.sol";

contract Obj {
function computeMD5(string calldata plaintext) external pure returns (bytes16) {
return MD5.hash(plaintext);
}
}

完成