package filter import ( "bytes" "errors" "fmt" "math/bits" "math/rand" "slices" "testing" ) // golombBits is a test helper that encodes values with the given P and returns // the raw bit string, so bit ordering can be asserted explicitly. func golombBits(values []uint64, p uint) string { var w bitWriter for _, v := range values { w.writeGolomb(v, p) } w.flush() var s string for _, b := range w.buf { s += fmt.Sprintf("%08b", b) } return s } // bitsToBytes converts a string of '0' and '1' characters into packed bytes. func bitsToBytes(t *testing.T, s string) []byte { t.Helper() if len(s)%8 != 0 { t.Fatalf("bit string length %d is not a whole number of bytes", len(s)) } out := make([]byte, len(s)/8) for i := range s { bit := byte(0) switch s[i] { case '0': case '1': bit = 1 default: t.Fatalf("invalid bit %q at %d", s[i], i) } out[i/8] = out[i/8]<<1 | bit } return out } func TestGolombEncoding(t *testing.T) { // BIP158's P=2 table: 0..9 encode as q unary bits followed by the // big-endian remainder. // The 38 bits above are zero-padded to 40 bits (5 bytes). want := "000" + "001" + "010" + "011" + "1000" + "1001" + "1010" + "1011" + "11000" + "11001" + "00" values := make([]uint64, 10) for i := range values { values[i] = uint64(i) } if got := golombBits(values, 2); got != want { t.Fatalf("P=2 encoding = %s, want %s", got, want) } for _, p := range []uint{2, 4, 19} { values := []uint64{0, 1, 2, 3, 7, 8, 15, 1 << p, 1<

> 64 mapping against a big.Int // reference for a few values. func TestHashMapping(t *testing.T) { var hash [32]byte hash[0] = 1 var key [16]byte copy(key[:], hash[:16]) items := [][]byte{[]byte("a"), []byte("b"), []byte("c"), []byte("d")} f := uint64(len(items)) * M for _, item := range items { h := siphash24(key, item) // Compute the top 64 bits of h*F with math/bits, then compare with a // shift/add decomposition that does not use Mul64. hi, lo := bits.Mul64(h, f) if hi != mulHiRef(h, f) || lo != mulLoRef(h, f) { t.Fatalf("mapping for %q mismatch", item) } } } func mulHiRef(a, b uint64) uint64 { // 32-bit limb decomposition of the high 64 bits of a*b. a0, a1 := a&0xffffffff, a>>32 b0, b1 := b&0xffffffff, b>>32 p00 := a0 * b0 p01 := a0 * b1 p10 := a1 * b0 p11 := a1 * b1 mid := (p00 >> 32) + (p01 & 0xffffffff) + (p10 & 0xffffffff) return p11 + (p01 >> 32) + (p10 >> 32) + (mid >> 32) } func mulLoRef(a, b uint64) uint64 { a0, a1 := a&0xffffffff, a>>32 b0, b1 := b&0xffffffff, b>>32 return a0*b0 + ((a0*b1 + a1*b0) << 32) }