github.com/insolar/x-crypto@v0.0.0-20191031140942-75fab8a325f6/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  // Code generated by go run gen.go{{if .Full}} -full{{end}} -output md5block.go; DO NOT EDIT.
   183  
   184  package md5
   185  
   186  import (
   187  	"unsafe"
   188  	"runtime"
   189  )
   190  
   191  {{if not .Full}}
   192  	var t1 = [...]uint32{
   193  	{{range .Table1}}{{printf "\t%#x,\n" .}}{{end}}
   194  	}
   195  	
   196  	var t2 = [...]uint32{
   197  	{{range .Table2}}{{printf "\t%#x,\n" .}}{{end}}
   198  	}
   199  	
   200  	var t3 = [...]uint32{
   201  	{{range .Table3}}{{printf "\t%#x,\n" .}}{{end}}
   202  	}
   203  	
   204  	var t4 = [...]uint32{
   205  	{{range .Table4}}{{printf "\t%#x,\n" .}}{{end}}
   206  	}
   207  {{end}}
   208  
   209  const x86 = runtime.GOARCH == "amd64" || runtime.GOARCH == "386"
   210  
   211  var littleEndian bool
   212  
   213  func init() {
   214  	x := uint32(0x04030201)
   215  	y := [4]byte{0x1, 0x2, 0x3, 0x4}
   216  	littleEndian = *(*[4]byte)(unsafe.Pointer(&x)) == y
   217  }
   218  
   219  func blockGeneric(dig *digest, p []byte) {
   220  	a := dig.s[0]
   221  	b := dig.s[1]
   222  	c := dig.s[2]
   223  	d := dig.s[3]
   224  	var X *[16]uint32
   225  	var xbuf [16]uint32
   226  	for len(p) >= chunk {
   227  		aa, bb, cc, dd := a, b, c, d
   228  
   229  		// This is a constant condition - it is not evaluated on each iteration.
   230  		if x86 {
   231  			// MD5 was designed so that x86 processors can just iterate
   232  			// over the block data directly as uint32s, and we generate
   233  			// less code and run 1.3x faster if we take advantage of that.
   234  			// My apologies.
   235  			X = (*[16]uint32)(unsafe.Pointer(&p[0]))
   236  		} else if littleEndian && uintptr(unsafe.Pointer(&p[0]))&(unsafe.Alignof(uint32(0))-1) == 0 {
   237  			X = (*[16]uint32)(unsafe.Pointer(&p[0]))
   238  		} else {
   239  			X = &xbuf
   240  			j := 0
   241  			for i := 0; i < 16; i++ {
   242  				X[i&15] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24
   243  				j += 4
   244  			}
   245  		}
   246  
   247  		{{if .Full}}
   248  			// Round 1.
   249  			{{range $i, $s := dup 4 .Shift1}}
   250  				{{index $.Table1 $i | printf "a += (((c^d)&b)^d) + X[%d] + %d" $i | relabel}}
   251  				{{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}}
   252  				{{rotate}}
   253  			{{end}}
   254  	
   255  			// Round 2.
   256  			{{range $i, $s := dup 4 .Shift2}}
   257  				{{index $.Table2 $i | printf "a += (((b^c)&d)^c) + X[(1+5*%d)&15] + %d" $i | relabel}}
   258  				{{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}}
   259  				{{rotate}}
   260  			{{end}}
   261  	
   262  			// Round 3.
   263  			{{range $i, $s := dup 4 .Shift3}}
   264  				{{index $.Table3 $i | printf "a += (b^c^d) + X[(5+3*%d)&15] + %d" $i | relabel}}
   265  				{{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}}
   266  				{{rotate}}
   267  			{{end}}
   268  	
   269  			// Round 4.
   270  			{{range $i, $s := dup 4 .Shift4}}
   271  				{{index $.Table4 $i | printf "a += (c^(b|^d)) + X[(7*%d)&15] + %d" $i | relabel}}
   272  				{{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}}
   273  				{{rotate}}
   274  			{{end}}
   275  		{{else}}
   276  			// Round 1.
   277  			for i := uint(0); i < 16; {
   278  				{{range $s := .Shift1}}
   279  					{{printf "a += (((c^d)&b)^d) + X[i&15] + t1[i&15]" | relabel}}
   280  					{{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}}
   281  					i++
   282  					{{rotate}}
   283  				{{end}}
   284  			}
   285  	
   286  			// Round 2.
   287  			for i := uint(0); i < 16; {
   288  				{{range $s := .Shift2}}
   289  					{{printf "a += (((b^c)&d)^c) + X[(1+5*i)&15] + t2[i&15]" | relabel}}
   290  					{{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}}
   291  					i++
   292  					{{rotate}}
   293  				{{end}}
   294  			}
   295  	
   296  			// Round 3.
   297  			for i := uint(0); i < 16; {
   298  				{{range $s := .Shift3}}
   299  					{{printf "a += (b^c^d) + X[(5+3*i)&15] + t3[i&15]" | relabel}}
   300  					{{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}}
   301  					i++
   302  					{{rotate}}
   303  				{{end}}
   304  			}
   305  	
   306  			// Round 4.
   307  			for i := uint(0); i < 16; {
   308  				{{range $s := .Shift4}}
   309  					{{printf "a += (c^(b|^d)) + X[(7*i)&15] + t4[i&15]" | relabel}}
   310  					{{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}}
   311  					i++
   312  					{{rotate}}
   313  				{{end}}
   314  			}
   315  		{{end}}
   316  
   317  		a += aa
   318  		b += bb
   319  		c += cc
   320  		d += dd
   321  
   322  		p = p[chunk:]
   323  	}
   324  
   325  	dig.s[0] = a
   326  	dig.s[1] = b
   327  	dig.s[2] = c
   328  	dig.s[3] = d
   329  }
   330  `