github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/src/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] -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  `