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 }