github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/src/pkg/crypto/md5/gen.go (about) 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 15 package main 16 17 import ( 18 "flag" 19 "log" 20 "os" 21 "strings" 22 "text/template" 23 ) 24 25 func 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 34 type 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 47 var funcs = template.FuncMap{ 48 "dup": dup, 49 "relabel": relabel, 50 "rotate": rotate, 51 } 52 53 func 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 61 func relabel(s string) string { 62 return strings.NewReplacer("a", data.a, "b", data.b, "c", data.c, "d", data.d).Replace(s) 63 } 64 65 func 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 70 func init() { 71 flag.BoolVar(&data.Full, "full", false, "complete unrolling") 72 } 73 74 var 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 163 var program = `// Copyright 2013 The Go Authors. All rights reserved. 164 // Use of this source code is governed by a BSD-style 165 // license that can be found in the LICENSE file. 166 167 // DO NOT EDIT. 168 // Generate with: go run gen.go{{if .Full}} -full{{end}} | gofmt >md5block.go 169 170 package md5 171 172 import ( 173 "unsafe" 174 "runtime" 175 ) 176 177 {{if not .Full}} 178 var t1 = [...]uint32{ 179 {{range .Table1}}{{printf "\t%#x,\n" .}}{{end}} 180 } 181 182 var t2 = [...]uint32{ 183 {{range .Table2}}{{printf "\t%#x,\n" .}}{{end}} 184 } 185 186 var t3 = [...]uint32{ 187 {{range .Table3}}{{printf "\t%#x,\n" .}}{{end}} 188 } 189 190 var t4 = [...]uint32{ 191 {{range .Table4}}{{printf "\t%#x,\n" .}}{{end}} 192 } 193 {{end}} 194 195 const x86 = runtime.GOARCH == "amd64" || runtime.GOARCH == "386" 196 197 var littleEndian bool 198 199 func init() { 200 x := uint32(0x04030201) 201 y := [4]byte{0x1, 0x2, 0x3, 0x4} 202 littleEndian = *(*[4]byte)(unsafe.Pointer(&x)) == y 203 } 204 205 func blockGeneric(dig *digest, p []byte) { 206 a := dig.s[0] 207 b := dig.s[1] 208 c := dig.s[2] 209 d := dig.s[3] 210 var X *[16]uint32 211 var xbuf [16]uint32 212 for len(p) >= chunk { 213 aa, bb, cc, dd := a, b, c, d 214 215 // This is a constant condition - it is not evaluated on each iteration. 216 if x86 { 217 // MD5 was designed so that x86 processors can just iterate 218 // over the block data directly as uint32s, and we generate 219 // less code and run 1.3x faster if we take advantage of that. 220 // My apologies. 221 X = (*[16]uint32)(unsafe.Pointer(&p[0])) 222 } else if littleEndian && uintptr(unsafe.Pointer(&p[0]))&(unsafe.Alignof(uint32(0))-1) == 0 { 223 X = (*[16]uint32)(unsafe.Pointer(&p[0])) 224 } else { 225 X = &xbuf 226 j := 0 227 for i := 0; i < 16; i++ { 228 X[i&15] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24 229 j += 4 230 } 231 } 232 233 {{if .Full}} 234 // Round 1. 235 {{range $i, $s := dup 4 .Shift1}} 236 {{index $.Table1 $i | printf "a += (((c^d)&b)^d) + X[%d] + %d" $i | relabel}} 237 {{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}} 238 {{rotate}} 239 {{end}} 240 241 // Round 2. 242 {{range $i, $s := dup 4 .Shift2}} 243 {{index $.Table2 $i | printf "a += (((b^c)&d)^c) + X[(1+5*%d)&15] + %d" $i | relabel}} 244 {{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}} 245 {{rotate}} 246 {{end}} 247 248 // Round 3. 249 {{range $i, $s := dup 4 .Shift3}} 250 {{index $.Table3 $i | printf "a += (b^c^d) + X[(5+3*%d)&15] + %d" $i | relabel}} 251 {{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}} 252 {{rotate}} 253 {{end}} 254 255 // Round 4. 256 {{range $i, $s := dup 4 .Shift4}} 257 {{index $.Table4 $i | printf "a += (c^(b|^d)) + X[(7*%d)&15] + %d" $i | relabel}} 258 {{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}} 259 {{rotate}} 260 {{end}} 261 {{else}} 262 // Round 1. 263 for i := uint(0); i < 16; { 264 {{range $s := .Shift1}} 265 {{printf "a += (((c^d)&b)^d) + X[i&15] + t1[i&15]" | relabel}} 266 {{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}} 267 i++ 268 {{rotate}} 269 {{end}} 270 } 271 272 // Round 2. 273 for i := uint(0); i < 16; { 274 {{range $s := .Shift2}} 275 {{printf "a += (((b^c)&d)^c) + X[(1+5*i)&15] + t2[i&15]" | relabel}} 276 {{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}} 277 i++ 278 {{rotate}} 279 {{end}} 280 } 281 282 // Round 3. 283 for i := uint(0); i < 16; { 284 {{range $s := .Shift3}} 285 {{printf "a += (b^c^d) + X[(5+3*i)&15] + t3[i&15]" | relabel}} 286 {{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}} 287 i++ 288 {{rotate}} 289 {{end}} 290 } 291 292 // Round 4. 293 for i := uint(0); i < 16; { 294 {{range $s := .Shift4}} 295 {{printf "a += (c^(b|^d)) + X[(7*i)&15] + t4[i&15]" | relabel}} 296 {{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}} 297 i++ 298 {{rotate}} 299 {{end}} 300 } 301 {{end}} 302 303 a += aa 304 b += bb 305 c += cc 306 d += dd 307 308 p = p[chunk:] 309 } 310 311 dig.s[0] = a 312 dig.s[1] = b 313 dig.s[2] = c 314 dig.s[3] = d 315 } 316 `