github.com/mad-day/Yawning-crypto@v0.0.0-20190711051033-5a5f8cca32ec/bsaes/ghash/ghash.go (about)

     1  // Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
     2  // Copyright (c) 2017 Yawning Angel <yawning at schwanenlied dot me>
     3  //
     4  // Permission is hereby granted, free of charge, to any person obtaining
     5  // a copy of this software and associated documentation files (the
     6  // "Software"), to deal in the Software without restriction, including
     7  // without limitation the rights to use, copy, modify, merge, publish,
     8  // distribute, sublicense, and/or sell copies of the Software, and to
     9  // permit persons to whom the Software is furnished to do so, subject to
    10  // the following conditions:
    11  //
    12  // The above copyright notice and this permission notice shall be
    13  // included in all copies or substantial portions of the Software.
    14  //
    15  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    16  // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    17  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    18  // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
    19  // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
    20  // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
    21  // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    22  // SOFTWARE.
    23  
    24  // Package ghash is a constant time 64 bit optimized GHASH implementation.
    25  package ghash
    26  
    27  import "encoding/binary"
    28  
    29  const blockSize = 16
    30  
    31  func bmul64(x, y uint64) uint64 {
    32  	x0 := x & 0x1111111111111111
    33  	x1 := x & 0x2222222222222222
    34  	x2 := x & 0x4444444444444444
    35  	x3 := x & 0x8888888888888888
    36  	y0 := y & 0x1111111111111111
    37  	y1 := y & 0x2222222222222222
    38  	y2 := y & 0x4444444444444444
    39  	y3 := y & 0x8888888888888888
    40  	z0 := (x0 * y0) ^ (x1 * y3) ^ (x2 * y2) ^ (x3 * y1)
    41  	z1 := (x0 * y1) ^ (x1 * y0) ^ (x2 * y3) ^ (x3 * y2)
    42  	z2 := (x0 * y2) ^ (x1 * y1) ^ (x2 * y0) ^ (x3 * y3)
    43  	z3 := (x0 * y3) ^ (x1 * y2) ^ (x2 * y1) ^ (x3 * y0)
    44  	z0 &= 0x1111111111111111
    45  	z1 &= 0x2222222222222222
    46  	z2 &= 0x4444444444444444
    47  	z3 &= 0x8888888888888888
    48  	return z0 | z1 | z2 | z3
    49  }
    50  
    51  func rev64(x uint64) uint64 {
    52  	x = ((x & 0x5555555555555555) << 1) | ((x >> 1) & 0x5555555555555555)
    53  	x = ((x & 0x3333333333333333) << 2) | ((x >> 2) & 0x3333333333333333)
    54  	x = ((x & 0x0F0F0F0F0F0F0F0F) << 4) | ((x >> 4) & 0x0F0F0F0F0F0F0F0F)
    55  	x = ((x & 0x00FF00FF00FF00FF) << 8) | ((x >> 8) & 0x00FF00FF00FF00FF)
    56  	x = ((x & 0x0000FFFF0000FFFF) << 16) | ((x >> 16) & 0x0000FFFF0000FFFF)
    57  	return (x << 32) | (x >> 32)
    58  }
    59  
    60  // Ghash calculates the GHASH of data, with key h, and input y, and stores the
    61  // resulting digest in y.
    62  func Ghash(y, h *[blockSize]byte, data []byte) {
    63  	var tmp [blockSize]byte
    64  	var src []byte
    65  
    66  	buf := data
    67  	l := len(buf)
    68  
    69  	y1 := binary.BigEndian.Uint64(y[:])
    70  	y0 := binary.BigEndian.Uint64(y[8:])
    71  	h1 := binary.BigEndian.Uint64(h[:])
    72  	h0 := binary.BigEndian.Uint64(h[8:])
    73  	h0r := rev64(h0)
    74  	h1r := rev64(h1)
    75  	h2 := h0 ^ h1
    76  	h2r := h0r ^ h1r
    77  
    78  	for l > 0 {
    79  		if l >= blockSize {
    80  			src = buf
    81  			buf = buf[blockSize:]
    82  			l -= blockSize
    83  		} else {
    84  			copy(tmp[:], buf)
    85  			src = tmp[:]
    86  			l = 0
    87  		}
    88  		y1 ^= binary.BigEndian.Uint64(src)
    89  		y0 ^= binary.BigEndian.Uint64(src[8:])
    90  
    91  		y0r := rev64(y0)
    92  		y1r := rev64(y1)
    93  		y2 := y0 ^ y1
    94  		y2r := y0r ^ y1r
    95  
    96  		z0 := bmul64(y0, h0)
    97  		z1 := bmul64(y1, h1)
    98  		z2 := bmul64(y2, h2)
    99  		z0h := bmul64(y0r, h0r)
   100  		z1h := bmul64(y1r, h1r)
   101  		z2h := bmul64(y2r, h2r)
   102  		z2 ^= z0 ^ z1
   103  		z2h ^= z0h ^ z1h
   104  		z0h = rev64(z0h) >> 1
   105  		z1h = rev64(z1h) >> 1
   106  		z2h = rev64(z2h) >> 1
   107  
   108  		v0 := z0
   109  		v1 := z0h ^ z2
   110  		v2 := z1 ^ z2h
   111  		v3 := z1h
   112  
   113  		v3 = (v3 << 1) | (v2 >> 63)
   114  		v2 = (v2 << 1) | (v1 >> 63)
   115  		v1 = (v1 << 1) | (v0 >> 63)
   116  		v0 = (v0 << 1)
   117  
   118  		v2 ^= v0 ^ (v0 >> 1) ^ (v0 >> 2) ^ (v0 >> 7)
   119  		v1 ^= (v0 << 63) ^ (v0 << 62) ^ (v0 << 57)
   120  		v3 ^= v1 ^ (v1 >> 1) ^ (v1 >> 2) ^ (v1 >> 7)
   121  		v2 ^= (v1 << 63) ^ (v1 << 62) ^ (v1 << 57)
   122  
   123  		y0 = v2
   124  		y1 = v3
   125  	}
   126  
   127  	binary.BigEndian.PutUint64(y[:], y1)
   128  	binary.BigEndian.PutUint64(y[8:], y0)
   129  }