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