Home | History | Annotate | Download | only in md5
      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 
     15 package main
     16 
     17 import (
     18 	"bytes"
     19 	"flag"
     20 	"go/format"
     21 	"io/ioutil"
     22 	"log"
     23 	"strings"
     24 	"text/template"
     25 )
     26 
     27 var filename = flag.String("output", "md5block.go", "output file name")
     28 
     29 func 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 
     49 type 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 
     62 var funcs = template.FuncMap{
     63 	"dup":     dup,
     64 	"relabel": relabel,
     65 	"rotate":  rotate,
     66 }
     67 
     68 func 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 
     76 func relabel(s string) string {
     77 	return strings.NewReplacer("a", data.a, "b", data.b, "c", data.c, "d", data.d).Replace(s)
     78 }
     79 
     80 func 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 
     85 func init() {
     86 	flag.BoolVar(&data.Full, "full", false, "complete unrolling")
     87 }
     88 
     89 var 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 
    178 var 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 
    185 package md5
    186 
    187 import (
    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 
    210 const x86 = runtime.GOARCH == "amd64" || runtime.GOARCH == "386"
    211 
    212 var littleEndian bool
    213 
    214 func init() {
    215 	x := uint32(0x04030201)
    216 	y := [4]byte{0x1, 0x2, 0x3, 0x4}
    217 	littleEndian = *(*[4]byte)(unsafe.Pointer(&x)) == y
    218 }
    219 
    220 func 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