// Copyright 2024 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package gcmimport ()// gcmFieldElement represents a value in GF(2¹²⁸). In order to reflect the GCM// standard and make binary.BigEndian suitable for marshaling these values, the// bits are stored in big endian order. For example://// the coefficient of x⁰ can be obtained by v.low >> 63.// the coefficient of x⁶³ can be obtained by v.low & 1.// the coefficient of x⁶⁴ can be obtained by v.high >> 63.// the coefficient of x¹²⁷ can be obtained by v.high & 1.type gcmFieldElement struct { low, high uint64}// GHASH is exposed to allow crypto/cipher to implement non-AES GCM modes.// It is not allowed as a stand-alone operation in FIPS mode because it// is not ACVP tested.func ( *[16]byte, ...[]byte) []byte {fips140.RecordNonApproved()var [gcmBlockSize]byteghash(&, , ...)return [:]}// ghash is a variable-time generic implementation of GHASH, which shouldn't// be used on any architecture with hardware support for AES-GCM.//// Each input is zero-padded to 128-bit before being absorbed.func ghash(, *[gcmBlockSize]byte, ...[]byte) {// productTable contains the first sixteen powers of the key, H. // However, they are in bit reversed order.var [16]gcmFieldElement// We precompute 16 multiples of H. However, when we do lookups // into this table we'll be using bits from a field element and // therefore the bits will be in the reverse order. So normally one // would expect, say, 4*H to be in index 4 of the table but due to // this bit ordering it will actually be in index 0010 (base 2) = 2. := gcmFieldElement{byteorder.BEUint64([:8]),byteorder.BEUint64([8:]), } [reverseBits(1)] = for := 2; < 16; += 2 { [reverseBits()] = ghashDouble(&[reverseBits(/2)]) [reverseBits(+1)] = ghashAdd(&[reverseBits()], &) }vargcmFieldElementfor , := range {ghashUpdate(&, &, ) }byteorder.BEPutUint64([:], .low)byteorder.BEPutUint64([8:], .high)}// reverseBits reverses the order of the bits of 4-bit number in i.func reverseBits( int) int { = (( << 2) & 0xc) | (( >> 2) & 0x3) = (( << 1) & 0xa) | (( >> 1) & 0x5)return}// ghashAdd adds two elements of GF(2¹²⁸) and returns the sum.func ghashAdd(, *gcmFieldElement) gcmFieldElement {// Addition in a characteristic 2 field is just XOR.returngcmFieldElement{.low ^ .low, .high ^ .high}}// ghashDouble returns the result of doubling an element of GF(2¹²⁸).func ghashDouble( *gcmFieldElement) ( gcmFieldElement) { := .high&1 == 1// Because of the bit-ordering, doubling is actually a right shift. .high = .high >> 1 .high |= .low << 63 .low = .low >> 1// If the most-significant bit was set before shifting then it, // conceptually, becomes a term of x^128. This is greater than the // irreducible polynomial so the result has to be reduced. The // irreducible polynomial is 1+x+x^2+x^7+x^128. We can subtract that to // eliminate the term at x^128 which also means subtracting the other // four terms. In characteristic 2 fields, subtraction == addition == // XOR.if { .low ^= 0xe100000000000000 }return}var ghashReductionTable = []uint16{0x0000, 0x1c20, 0x3840, 0x2460, 0x7080, 0x6ca0, 0x48c0, 0x54e0,0xe100, 0xfd20, 0xd940, 0xc560, 0x9180, 0x8da0, 0xa9c0, 0xb5e0,}// ghashMul sets y to y*H, where H is the GCM key, fixed during New.func ghashMul( *[16]gcmFieldElement, *gcmFieldElement) {vargcmFieldElementfor := 0; < 2; ++ { := .highif == 1 { = .low }// Multiplication works by multiplying z by 16 and adding in // one of the precomputed multiples of H.for := 0; < 64; += 4 { := .high & 0xf .high >>= 4 .high |= .low << 60 .low >>= 4 .low ^= uint64(ghashReductionTable[]) << 48// the values in |table| are ordered for little-endian bit // positions. See the comment in New. := [&0xf] .low ^= .low .high ^= .high >>= 4 } } * = }// updateBlocks extends y with more polynomial terms from blocks, based on// Horner's rule. There must be a multiple of gcmBlockSize bytes in blocks.func updateBlocks( *[16]gcmFieldElement, *gcmFieldElement, []byte) {forlen() > 0 { .low ^= byteorder.BEUint64() .high ^= byteorder.BEUint64([8:])ghashMul(, ) = [gcmBlockSize:] }}// ghashUpdate extends y with more polynomial terms from data. If data is not a// multiple of gcmBlockSize bytes long then the remainder is zero padded.func ghashUpdate( *[16]gcmFieldElement, *gcmFieldElement, []byte) { := (len() >> 4) << 4updateBlocks(, , [:])iflen() != {var [gcmBlockSize]bytecopy([:], [:])updateBlocks(, , [:]) }}
The pages are generated with Goldsv0.7.3-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.