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// +build ignore
6
7// This program generates md5block.go
8// Invoke as
9//
10//	go run gen.go [-full] -output md5block.go
11//
12// The -full flag causes the generated code to do a full
13// (16x) unrolling instead of a 4x unrolling.
14
15package main
16
17import (
18	"bytes"
19	"flag"
20	"go/format"
21	"io/ioutil"
22	"log"
23	"strings"
24	"text/template"
25)
26
27var filename = flag.String("output", "md5block.go", "output file name")
28
29func main() {
30	flag.Parse()
31
32	var buf bytes.Buffer
33
34	t := template.Must(template.New("main").Funcs(funcs).Parse(program))
35	if err := t.Execute(&buf, data); err != nil {
36		log.Fatal(err)
37	}
38
39	data, err := format.Source(buf.Bytes())
40	if err != nil {
41		log.Fatal(err)
42	}
43	err = ioutil.WriteFile(*filename, data, 0644)
44	if err != nil {
45		log.Fatal(err)
46	}
47}
48
49type Data struct {
50	a, b, c, d string
51	Shift1     []int
52	Shift2     []int
53	Shift3     []int
54	Shift4     []int
55	Table1     []uint32
56	Table2     []uint32
57	Table3     []uint32
58	Table4     []uint32
59	Full       bool
60}
61
62var funcs = template.FuncMap{
63	"dup":     dup,
64	"relabel": relabel,
65	"rotate":  rotate,
66}
67
68func dup(count int, x []int) []int {
69	var out []int
70	for i := 0; i < count; i++ {
71		out = append(out, x...)
72	}
73	return out
74}
75
76func relabel(s string) string {
77	return strings.NewReplacer("a", data.a, "b", data.b, "c", data.c, "d", data.d).Replace(s)
78}
79
80func rotate() string {
81	data.a, data.b, data.c, data.d = data.d, data.a, data.b, data.c
82	return "" // no output
83}
84
85func init() {
86	flag.BoolVar(&data.Full, "full", false, "complete unrolling")
87}
88
89var data = Data{
90	a:      "a",
91	b:      "b",
92	c:      "c",
93	d:      "d",
94	Shift1: []int{7, 12, 17, 22},
95	Shift2: []int{5, 9, 14, 20},
96	Shift3: []int{4, 11, 16, 23},
97	Shift4: []int{6, 10, 15, 21},
98
99	// table[i] = int((1<<32) * abs(sin(i+1 radians))).
100	Table1: []uint32{
101		// round 1
102		0xd76aa478,
103		0xe8c7b756,
104		0x242070db,
105		0xc1bdceee,
106		0xf57c0faf,
107		0x4787c62a,
108		0xa8304613,
109		0xfd469501,
110		0x698098d8,
111		0x8b44f7af,
112		0xffff5bb1,
113		0x895cd7be,
114		0x6b901122,
115		0xfd987193,
116		0xa679438e,
117		0x49b40821,
118	},
119	Table2: []uint32{
120		// round 2
121		0xf61e2562,
122		0xc040b340,
123		0x265e5a51,
124		0xe9b6c7aa,
125		0xd62f105d,
126		0x2441453,
127		0xd8a1e681,
128		0xe7d3fbc8,
129		0x21e1cde6,
130		0xc33707d6,
131		0xf4d50d87,
132		0x455a14ed,
133		0xa9e3e905,
134		0xfcefa3f8,
135		0x676f02d9,
136		0x8d2a4c8a,
137	},
138	Table3: []uint32{
139		// round3
140		0xfffa3942,
141		0x8771f681,
142		0x6d9d6122,
143		0xfde5380c,
144		0xa4beea44,
145		0x4bdecfa9,
146		0xf6bb4b60,
147		0xbebfbc70,
148		0x289b7ec6,
149		0xeaa127fa,
150		0xd4ef3085,
151		0x4881d05,
152		0xd9d4d039,
153		0xe6db99e5,
154		0x1fa27cf8,
155		0xc4ac5665,
156	},
157	Table4: []uint32{
158		// round 4
159		0xf4292244,
160		0x432aff97,
161		0xab9423a7,
162		0xfc93a039,
163		0x655b59c3,
164		0x8f0ccc92,
165		0xffeff47d,
166		0x85845dd1,
167		0x6fa87e4f,
168		0xfe2ce6e0,
169		0xa3014314,
170		0x4e0811a1,
171		0xf7537e82,
172		0xbd3af235,
173		0x2ad7d2bb,
174		0xeb86d391,
175	},
176}
177
178var program = `// Copyright 2013 The Go Authors. All rights reserved.
179// Use of this source code is governed by a BSD-style
180// license that can be found in the LICENSE file.
181
182// DO NOT EDIT.
183// Generate with: go run gen.go{{if .Full}} -full{{end}} -output md5block.go
184
185package md5
186
187import (
188	"unsafe"
189	"runtime"
190)
191
192{{if not .Full}}
193	var t1 = [...]uint32{
194	{{range .Table1}}{{printf "\t%#x,\n" .}}{{end}}
195	}
196
197	var t2 = [...]uint32{
198	{{range .Table2}}{{printf "\t%#x,\n" .}}{{end}}
199	}
200
201	var t3 = [...]uint32{
202	{{range .Table3}}{{printf "\t%#x,\n" .}}{{end}}
203	}
204
205	var t4 = [...]uint32{
206	{{range .Table4}}{{printf "\t%#x,\n" .}}{{end}}
207	}
208{{end}}
209
210const x86 = runtime.GOARCH == "amd64" || runtime.GOARCH == "386"
211
212var littleEndian bool
213
214func init() {
215	x := uint32(0x04030201)
216	y := [4]byte{0x1, 0x2, 0x3, 0x4}
217	littleEndian = *(*[4]byte)(unsafe.Pointer(&x)) == y
218}
219
220func blockGeneric(dig *digest, p []byte) {
221	a := dig.s[0]
222	b := dig.s[1]
223	c := dig.s[2]
224	d := dig.s[3]
225	var X *[16]uint32
226	var xbuf [16]uint32
227	for len(p) >= chunk {
228		aa, bb, cc, dd := a, b, c, d
229
230		// This is a constant condition - it is not evaluated on each iteration.
231		if x86 {
232			// MD5 was designed so that x86 processors can just iterate
233			// over the block data directly as uint32s, and we generate
234			// less code and run 1.3x faster if we take advantage of that.
235			// My apologies.
236			X = (*[16]uint32)(unsafe.Pointer(&p[0]))
237		} else if littleEndian && uintptr(unsafe.Pointer(&p[0]))&(unsafe.Alignof(uint32(0))-1) == 0 {
238			X = (*[16]uint32)(unsafe.Pointer(&p[0]))
239		} else {
240			X = &xbuf
241			j := 0
242			for i := 0; i < 16; i++ {
243				X[i&15] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24
244				j += 4
245			}
246		}
247
248		{{if .Full}}
249			// Round 1.
250			{{range $i, $s := dup 4 .Shift1}}
251				{{index $.Table1 $i | printf "a += (((c^d)&b)^d) + X[%d] + %d" $i | relabel}}
252				{{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}}
253				{{rotate}}
254			{{end}}
255
256			// Round 2.
257			{{range $i, $s := dup 4 .Shift2}}
258				{{index $.Table2 $i | printf "a += (((b^c)&d)^c) + X[(1+5*%d)&15] + %d" $i | relabel}}
259				{{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}}
260				{{rotate}}
261			{{end}}
262
263			// Round 3.
264			{{range $i, $s := dup 4 .Shift3}}
265				{{index $.Table3 $i | printf "a += (b^c^d) + X[(5+3*%d)&15] + %d" $i | relabel}}
266				{{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}}
267				{{rotate}}
268			{{end}}
269
270			// Round 4.
271			{{range $i, $s := dup 4 .Shift4}}
272				{{index $.Table4 $i | printf "a += (c^(b|^d)) + X[(7*%d)&15] + %d" $i | relabel}}
273				{{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}}
274				{{rotate}}
275			{{end}}
276		{{else}}
277			// Round 1.
278			for i := uint(0); i < 16; {
279				{{range $s := .Shift1}}
280					{{printf "a += (((c^d)&b)^d) + X[i&15] + t1[i&15]" | relabel}}
281					{{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}}
282					i++
283					{{rotate}}
284				{{end}}
285			}
286
287			// Round 2.
288			for i := uint(0); i < 16; {
289				{{range $s := .Shift2}}
290					{{printf "a += (((b^c)&d)^c) + X[(1+5*i)&15] + t2[i&15]" | relabel}}
291					{{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}}
292					i++
293					{{rotate}}
294				{{end}}
295			}
296
297			// Round 3.
298			for i := uint(0); i < 16; {
299				{{range $s := .Shift3}}
300					{{printf "a += (b^c^d) + X[(5+3*i)&15] + t3[i&15]" | relabel}}
301					{{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}}
302					i++
303					{{rotate}}
304				{{end}}
305			}
306
307			// Round 4.
308			for i := uint(0); i < 16; {
309				{{range $s := .Shift4}}
310					{{printf "a += (c^(b|^d)) + X[(7*i)&15] + t4[i&15]" | relabel}}
311					{{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}}
312					i++
313					{{rotate}}
314				{{end}}
315			}
316		{{end}}
317
318		a += aa
319		b += bb
320		c += cc
321		d += dd
322
323		p = p[chunk:]
324	}
325
326	dig.s[0] = a
327	dig.s[1] = b
328	dig.s[2] = c
329	dig.s[3] = d
330}
331`
332