mirror of
https://github.com/pomerium/pomerium.git
synced 2025-06-19 11:12:53 +02:00
This significantly optimizes the (*Policy).RouteID() and (*Policy).Checksum() methods for both speed and memory usage. A new method (*Policy).ChecksumWithID(uint64) can be used to skip a call to RouteID() if the ID is already known. Checksum() is implemented in terms of this new method, and will always recompute the route ID on each call. RouteID() does not allocate heap memory. Checksum() may allocate heap memory, depending on which fields are set. If all of the following are true, Checksum() makes zero allocations: 1. The policy uses redirect or direct-response mode 2. The policy has no sub-policies 3. The policy has no response header rewrite config
221 lines
5.1 KiB
Go
221 lines
5.1 KiB
Go
// Package hashutil provides NON-CRYPTOGRAPHIC utility functions for hashing.
|
|
//
|
|
// http://cyan4973.github.io/xxHash/
|
|
//
|
|
//nolint:errcheck // discarding return values with _ increases inliner cost
|
|
package hashutil
|
|
|
|
import (
|
|
"encoding/binary"
|
|
|
|
"github.com/cespare/xxhash/v2"
|
|
"github.com/mitchellh/hashstructure/v2"
|
|
)
|
|
|
|
// MustHash returns the xxhash of an arbitrary value or struct. Returns 0
|
|
// on error.
|
|
// NOT SUITABLE FOR CRYTOGRAPHIC HASHING.
|
|
func MustHash(v any) uint64 {
|
|
hash, err := Hash(v)
|
|
if err != nil {
|
|
hash = 0
|
|
}
|
|
return hash
|
|
}
|
|
|
|
// Hash returns the xxhash of an arbitrary value or struct.
|
|
// NOT SUITABLE FOR CRYTOGRAPHIC HASHING.
|
|
func Hash(v any) (uint64, error) {
|
|
opts := &hashstructure.HashOptions{
|
|
Hasher: xxhash.New(),
|
|
}
|
|
return hashstructure.Hash(v, hashstructure.FormatV2, opts)
|
|
}
|
|
|
|
// MapHash efficiently computes a non-cryptographic hash of a map of strings.
|
|
func MapHash(iv uint64, m map[string]string) uint64 {
|
|
accum := iv
|
|
var lenBuf [4]byte
|
|
binary.BigEndian.PutUint32(lenBuf[:], uint32(len(m)))
|
|
accum ^= xxhash.Sum64(lenBuf[:])
|
|
var kvBuf [16]byte
|
|
for k, v := range m {
|
|
binary.BigEndian.PutUint64(kvBuf[0:8], xxhash.Sum64String(k))
|
|
binary.BigEndian.PutUint64(kvBuf[8:16], xxhash.Sum64String(v))
|
|
accum ^= xxhash.Sum64(kvBuf[:])
|
|
}
|
|
return accum
|
|
}
|
|
|
|
type Digest struct {
|
|
xxhash.Digest
|
|
}
|
|
|
|
func NewDigest() *Digest {
|
|
var d Digest
|
|
d.Reset()
|
|
return &d
|
|
}
|
|
|
|
// WriteStringWithLen writes the string's length, then its contents to the hash.
|
|
func (d *Digest) WriteStringWithLen(s string) {
|
|
d.WriteInt32(int32(len(s)))
|
|
d.WriteString(s)
|
|
}
|
|
|
|
// WriteStringWithLen writes the byte array's length, then its contents to
|
|
// the hash.
|
|
func (d *Digest) WriteWithLen(b []byte) {
|
|
d.WriteInt32(int32(len(b)))
|
|
d.Write(b)
|
|
}
|
|
|
|
// WriteBool writes a single byte (1 or 0) to the hash.
|
|
func (d *Digest) WriteBool(b bool) {
|
|
if b {
|
|
d.Write([]byte{1})
|
|
} else {
|
|
d.Write([]byte{0})
|
|
}
|
|
}
|
|
|
|
// WriteUint32 writes a uint16 to the hash.
|
|
func (d *Digest) WriteUint16(t uint16) {
|
|
var buf [2]byte
|
|
binary.LittleEndian.PutUint16(buf[:], t)
|
|
d.Write(buf[:])
|
|
}
|
|
|
|
// WriteUint32 writes a uint32 to the hash.
|
|
func (d *Digest) WriteUint32(t uint32) {
|
|
var buf [4]byte
|
|
binary.LittleEndian.PutUint32(buf[:], t)
|
|
d.Write(buf[:])
|
|
}
|
|
|
|
// WriteUint32 writes a uint64 to the hash.
|
|
func (d *Digest) WriteUint64(t uint64) {
|
|
var buf [8]byte
|
|
binary.LittleEndian.PutUint64(buf[:], t)
|
|
d.Write(buf[:])
|
|
}
|
|
|
|
// WriteInt16 writes an int16 to the hash.
|
|
func (d *Digest) WriteInt16(t int16) {
|
|
var buf [2]byte
|
|
binary.LittleEndian.PutUint16(buf[:], uint16(t))
|
|
d.Write(buf[:])
|
|
}
|
|
|
|
// WriteInt32 writes an int32 to the hash.
|
|
func (d *Digest) WriteInt32(t int32) {
|
|
var buf [4]byte
|
|
binary.LittleEndian.PutUint32(buf[:], uint32(t))
|
|
d.Write(buf[:])
|
|
}
|
|
|
|
// WriteInt64 writes an int64 to the hash.
|
|
func (d *Digest) WriteInt64(t int64) {
|
|
var buf [8]byte
|
|
binary.LittleEndian.PutUint64(buf[:], uint64(t))
|
|
d.Write(buf[:])
|
|
}
|
|
|
|
// WriteStringPtr writes one byte (1 or 0) indicating whether the pointer is non-nil,
|
|
// followed by the value if present.
|
|
func (d *Digest) WriteStringPtr(t *string) {
|
|
if t == nil {
|
|
d.Write([]byte{0})
|
|
} else {
|
|
d.Write([]byte{1})
|
|
d.WriteString(*t)
|
|
}
|
|
}
|
|
|
|
// WriteStringPtr writes one byte (1 or 0) indicating whether the pointer is non-nil,
|
|
// followed by the string's length and value, if present.
|
|
func (d *Digest) WriteStringPtrWithLen(t *string) {
|
|
if t == nil {
|
|
d.Write([]byte{0})
|
|
} else {
|
|
d.Write([]byte{1})
|
|
d.WriteStringWithLen(*t)
|
|
}
|
|
}
|
|
|
|
// WriteBoolPtr writes one byte (1 or 0) indicating whether the pointer is non-nil,
|
|
// followed by the value if present.
|
|
func (d *Digest) WriteBoolPtr(t *bool) {
|
|
if t == nil {
|
|
d.Write([]byte{0})
|
|
} else {
|
|
d.Write([]byte{1})
|
|
d.WriteBool(*t)
|
|
}
|
|
}
|
|
|
|
// WriteUint16Ptr writes one byte (1 or 0) indicating whether the pointer is non-nil,
|
|
// followed by the value if present.
|
|
func (d *Digest) WriteUint16Ptr(t *uint16) {
|
|
if t == nil {
|
|
d.Write([]byte{0})
|
|
} else {
|
|
d.Write([]byte{1})
|
|
d.WriteUint16(*t)
|
|
}
|
|
}
|
|
|
|
// WriteUint32Ptr writes one byte (1 or 0) indicating whether the pointer is non-nil,
|
|
// followed by the value if present.
|
|
func (d *Digest) WriteUint32Ptr(t *uint32) {
|
|
if t == nil {
|
|
d.Write([]byte{0})
|
|
} else {
|
|
d.Write([]byte{1})
|
|
d.WriteUint32(*t)
|
|
}
|
|
}
|
|
|
|
// WriteUint64Ptr writes one byte (1 or 0) indicating whether the pointer is non-nil,
|
|
// followed by the value if present.
|
|
func (d *Digest) WriteUint64Ptr(t *uint64) {
|
|
if t == nil {
|
|
d.Write([]byte{0})
|
|
} else {
|
|
d.Write([]byte{1})
|
|
d.WriteUint64(*t)
|
|
}
|
|
}
|
|
|
|
// WriteInt16Ptr writes one byte (1 or 0) indicating whether the pointer is non-nil,
|
|
// followed by the value if present.
|
|
func (d *Digest) WriteInt16Ptr(t *int16) {
|
|
if t == nil {
|
|
d.Write([]byte{0})
|
|
} else {
|
|
d.Write([]byte{1})
|
|
d.WriteInt16(*t)
|
|
}
|
|
}
|
|
|
|
// WriteInt32Ptr writes one byte (1 or 0) indicating whether the pointer is non-nil,
|
|
// followed by the value if present.
|
|
func (d *Digest) WriteInt32Ptr(t *int32) {
|
|
if t == nil {
|
|
d.Write([]byte{0})
|
|
} else {
|
|
d.Write([]byte{1})
|
|
d.WriteInt32(*t)
|
|
}
|
|
}
|
|
|
|
// WriteInt64Ptr writes one byte (1 or 0) indicating whether the pointer is non-nil,
|
|
// followed by the value if present.
|
|
func (d *Digest) WriteInt64Ptr(t *int64) {
|
|
if t == nil {
|
|
d.Write([]byte{0})
|
|
} else {
|
|
d.Write([]byte{1})
|
|
d.WriteInt64(*t)
|
|
}
|
|
}
|