// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
// This program generates md5block.go
// Invoke as
//
// go run gen.go -output md5block.go
package main
import (
"bytes"
"flag"
"go/format"
"io/ioutil"
"log"
"strings"
"text/template"
)
var filename = flag.String("output", "md5block.go", "output file name")
func main() {
flag.Parse()
var buf bytes.Buffer
t := template.Must(template.New("main").Funcs(funcs).Parse(program))
if err := t.Execute(&buf, data); err != nil {
log.Fatal(err)
}
data, err := format.Source(buf.Bytes())
if err != nil {
log.Fatal(err)
}
err = ioutil.WriteFile(*filename, data, 0644)
if err != nil {
log.Fatal(err)
}
}
type Data struct {
a, b, c, d string
Shift1 []int
Shift2 []int
Shift3 []int
Shift4 []int
Table1 []uint32
Table2 []uint32
Table3 []uint32
Table4 []uint32
}
var funcs = template.FuncMap{
"dup": dup,
"relabel": relabel,
"rotate": rotate,
"idx": idx,
"seq": seq,
}
func dup(count int, x []int) []int {
var out []int
for i := 0; i < count; i++ {
out = append(out, x...)
}
return out
}
func relabel(s string) string {
return strings.NewReplacer("arg0", data.a, "arg1", data.b, "arg2", data.c, "arg3", data.d).Replace(s)
}
func rotate() string {
data.a, data.b, data.c, data.d = data.d, data.a, data.b, data.c
return "" // no output
}
func idx(round, index int) int {
v := 0
switch round {
case 1:
v = index
case 2:
v = (1 + 5*index) & 15
case 3:
v = (5 + 3*index) & 15
case 4:
v = (7 * index) & 15
}
return v
}
func seq(i int) []int {
s := make([]int, i)
for i := range s {
s[i] = i
}
return s
}
var data = Data{
a: "a",
b: "b",
c: "c",
d: "d",
Shift1: []int{7, 12, 17, 22},
Shift2: []int{5, 9, 14, 20},
Shift3: []int{4, 11, 16, 23},
Shift4: []int{6, 10, 15, 21},
// table[i] = int((1<<32) * abs(sin(i+1 radians))).
Table1: []uint32{
// round 1
0xd76aa478,
0xe8c7b756,
0x242070db,
0xc1bdceee,
0xf57c0faf,
0x4787c62a,
0xa8304613,
0xfd469501,
0x698098d8,
0x8b44f7af,
0xffff5bb1,
0x895cd7be,
0x6b901122,
0xfd987193,
0xa679438e,
0x49b40821,
},
Table2: []uint32{
// round 2
0xf61e2562,
0xc040b340,
0x265e5a51,
0xe9b6c7aa,
0xd62f105d,
0x2441453,
0xd8a1e681,
0xe7d3fbc8,
0x21e1cde6,
0xc33707d6,
0xf4d50d87,
0x455a14ed,
0xa9e3e905,
0xfcefa3f8,
0x676f02d9,
0x8d2a4c8a,
},
Table3: []uint32{
// round3
0xfffa3942,
0x8771f681,
0x6d9d6122,
0xfde5380c,
0xa4beea44,
0x4bdecfa9,
0xf6bb4b60,
0xbebfbc70,
0x289b7ec6,
0xeaa127fa,
0xd4ef3085,
0x4881d05,
0xd9d4d039,
0xe6db99e5,
0x1fa27cf8,
0xc4ac5665,
},
Table4: []uint32{
// round 4
0xf4292244,
0x432aff97,
0xab9423a7,
0xfc93a039,
0x655b59c3,
0x8f0ccc92,
0xffeff47d,
0x85845dd1,
0x6fa87e4f,
0xfe2ce6e0,
0xa3014314,
0x4e0811a1,
0xf7537e82,
0xbd3af235,
0x2ad7d2bb,
0xeb86d391,
},
}
var program = `// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Code generated by go run gen.go -output md5block.go; DO NOT EDIT.
package md5
import (
"encoding/binary"
"math/bits"
)
func blockGeneric(dig *digest, p []byte) {
// load state
a, b, c, d := dig.s[0], dig.s[1], dig.s[2], dig.s[3]
for i := 0; i <= len(p)-BlockSize; i += BlockSize {
// eliminate bounds checks on p
q := p[i:]
q = q[:BlockSize:BlockSize]
// save current state
aa, bb, cc, dd := a, b, c, d
// load input block
{{range $i := seq 16 -}}
{{printf "x%x := binary.LittleEndian.Uint32(q[4*%#x:])" $i $i}}
{{end}}
// round 1
{{range $i, $s := dup 4 .Shift1 -}}
{{printf "arg0 = arg1 + bits.RotateLeft32((((arg2^arg3)&arg1)^arg3)+arg0+x%x+%#08x, %d)" (idx 1 $i) (index $.Table1 $i) $s | relabel}}
{{rotate -}}
{{end}}
// round 2
{{range $i, $s := dup 4 .Shift2 -}}
{{printf "arg0 = arg1 + bits.RotateLeft32((((arg1^arg2)&arg3)^arg2)+arg0+x%x+%#08x, %d)" (idx 2 $i) (index $.Table2 $i) $s | relabel}}
{{rotate -}}
{{end}}
// round 3
{{range $i, $s := dup 4 .Shift3 -}}
{{printf "arg0 = arg1 + bits.RotateLeft32((arg1^arg2^arg3)+arg0+x%x+%#08x, %d)" (idx 3 $i) (index $.Table3 $i) $s | relabel}}
{{rotate -}}
{{end}}
// round 4
{{range $i, $s := dup 4 .Shift4 -}}
{{printf "arg0 = arg1 + bits.RotateLeft32((arg2^(arg1|^arg3))+arg0+x%x+%#08x, %d)" (idx 4 $i) (index $.Table4 $i) $s | relabel}}
{{rotate -}}
{{end}}
// add saved state
a += aa
b += bb
c += cc
d += dd
}
// save state
dig.s[0], dig.s[1], dig.s[2], dig.s[3] = a, b, c, d
}
`