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