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