1// Copyright 2012 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5//go:build ignore
6
7// This program generates md5block.go
8// Invoke as
9//
10//	go run gen.go -output md5block.go
11
12package main
13
14import (
15	"bytes"
16	"flag"
17	"go/format"
18	"log"
19	"os"
20	"strings"
21	"text/template"
22)
23
24var filename = flag.String("output", "md5block.go", "output file name")
25
26func main() {
27	flag.Parse()
28
29	var buf bytes.Buffer
30
31	t := template.Must(template.New("main").Funcs(funcs).Parse(program))
32	if err := t.Execute(&buf, data); err != nil {
33		log.Fatal(err)
34	}
35
36	data, err := format.Source(buf.Bytes())
37	if err != nil {
38		log.Fatal(err)
39	}
40	err = os.WriteFile(*filename, data, 0644)
41	if err != nil {
42		log.Fatal(err)
43	}
44}
45
46type Data struct {
47	a, b, c, d string
48	Shift1     []int
49	Shift2     []int
50	Shift3     []int
51	Shift4     []int
52	Table1     []uint32
53	Table2     []uint32
54	Table3     []uint32
55	Table4     []uint32
56}
57
58var funcs = template.FuncMap{
59	"dup":     dup,
60	"relabel": relabel,
61	"rotate":  rotate,
62	"idx":     idx,
63	"seq":     seq,
64}
65
66func dup(count int, x []int) []int {
67	var out []int
68	for i := 0; i < count; i++ {
69		out = append(out, x...)
70	}
71	return out
72}
73
74func relabel(s string) string {
75	return strings.NewReplacer("arg0", data.a, "arg1", data.b, "arg2", data.c, "arg3", data.d).Replace(s)
76}
77
78func rotate() string {
79	data.a, data.b, data.c, data.d = data.d, data.a, data.b, data.c
80	return "" // no output
81}
82
83func idx(round, index int) int {
84	v := 0
85	switch round {
86	case 1:
87		v = index
88	case 2:
89		v = (1 + 5*index) & 15
90	case 3:
91		v = (5 + 3*index) & 15
92	case 4:
93		v = (7 * index) & 15
94	}
95	return v
96}
97
98func seq(i int) []int {
99	s := make([]int, i)
100	for i := range s {
101		s[i] = i
102	}
103	return s
104}
105
106var data = Data{
107	a:      "a",
108	b:      "b",
109	c:      "c",
110	d:      "d",
111	Shift1: []int{7, 12, 17, 22},
112	Shift2: []int{5, 9, 14, 20},
113	Shift3: []int{4, 11, 16, 23},
114	Shift4: []int{6, 10, 15, 21},
115
116	// table[i] = int((1<<32) * abs(sin(i+1 radians))).
117	Table1: []uint32{
118		// round 1
119		0xd76aa478,
120		0xe8c7b756,
121		0x242070db,
122		0xc1bdceee,
123		0xf57c0faf,
124		0x4787c62a,
125		0xa8304613,
126		0xfd469501,
127		0x698098d8,
128		0x8b44f7af,
129		0xffff5bb1,
130		0x895cd7be,
131		0x6b901122,
132		0xfd987193,
133		0xa679438e,
134		0x49b40821,
135	},
136	Table2: []uint32{
137		// round 2
138		0xf61e2562,
139		0xc040b340,
140		0x265e5a51,
141		0xe9b6c7aa,
142		0xd62f105d,
143		0x2441453,
144		0xd8a1e681,
145		0xe7d3fbc8,
146		0x21e1cde6,
147		0xc33707d6,
148		0xf4d50d87,
149		0x455a14ed,
150		0xa9e3e905,
151		0xfcefa3f8,
152		0x676f02d9,
153		0x8d2a4c8a,
154	},
155	Table3: []uint32{
156		// round3
157		0xfffa3942,
158		0x8771f681,
159		0x6d9d6122,
160		0xfde5380c,
161		0xa4beea44,
162		0x4bdecfa9,
163		0xf6bb4b60,
164		0xbebfbc70,
165		0x289b7ec6,
166		0xeaa127fa,
167		0xd4ef3085,
168		0x4881d05,
169		0xd9d4d039,
170		0xe6db99e5,
171		0x1fa27cf8,
172		0xc4ac5665,
173	},
174	Table4: []uint32{
175		// round 4
176		0xf4292244,
177		0x432aff97,
178		0xab9423a7,
179		0xfc93a039,
180		0x655b59c3,
181		0x8f0ccc92,
182		0xffeff47d,
183		0x85845dd1,
184		0x6fa87e4f,
185		0xfe2ce6e0,
186		0xa3014314,
187		0x4e0811a1,
188		0xf7537e82,
189		0xbd3af235,
190		0x2ad7d2bb,
191		0xeb86d391,
192	},
193}
194
195var program = `// Copyright 2013 The Go Authors. All rights reserved.
196// Use of this source code is governed by a BSD-style
197// license that can be found in the LICENSE file.
198
199// Code generated by go run gen.go -output md5block.go; DO NOT EDIT.
200
201package md5
202
203import (
204	"internal/byteorder"
205	"math/bits"
206)
207
208func blockGeneric(dig *digest, p []byte) {
209	// load state
210	a, b, c, d := dig.s[0], dig.s[1], dig.s[2], dig.s[3]
211
212	for i := 0; i <= len(p)-BlockSize; i += BlockSize {
213		// eliminate bounds checks on p
214		q := p[i:]
215		q = q[:BlockSize:BlockSize]
216
217		// save current state
218		aa, bb, cc, dd := a, b, c, d
219
220		// load input block
221		{{range $i := seq 16 -}}
222			{{printf "x%x := byteorder.LeUint32(q[4*%#x:])" $i $i}}
223		{{end}}
224
225		// round 1
226		{{range $i, $s := dup 4 .Shift1 -}}
227			{{printf "arg0 = arg1 + bits.RotateLeft32((((arg2^arg3)&arg1)^arg3)+arg0+x%x+%#08x, %d)" (idx 1 $i) (index $.Table1 $i) $s | relabel}}
228			{{rotate -}}
229		{{end}}
230
231		// round 2
232		{{range $i, $s := dup 4 .Shift2 -}}
233			{{printf "arg0 = arg1 + bits.RotateLeft32((((arg1^arg2)&arg3)^arg2)+arg0+x%x+%#08x, %d)" (idx 2 $i) (index $.Table2 $i) $s | relabel}}
234			{{rotate -}}
235		{{end}}
236
237		// round 3
238		{{range $i, $s := dup 4 .Shift3 -}}
239			{{printf "arg0 = arg1 + bits.RotateLeft32((arg1^arg2^arg3)+arg0+x%x+%#08x, %d)" (idx 3 $i) (index $.Table3 $i) $s | relabel}}
240			{{rotate -}}
241		{{end}}
242
243		// round 4
244		{{range $i, $s := dup 4 .Shift4 -}}
245			{{printf "arg0 = arg1 + bits.RotateLeft32((arg2^(arg1|^arg3))+arg0+x%x+%#08x, %d)" (idx 4 $i) (index $.Table4 $i) $s | relabel}}
246			{{rotate -}}
247		{{end}}
248
249		// add saved state
250		a += aa
251		b += bb
252		c += cc
253		d += dd
254	}
255
256	// save state
257	dig.s[0], dig.s[1], dig.s[2], dig.s[3] = a, b, c, d
258}
259`
260