gen.go 6.6 KB

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