hash256.go (4319B)
1 package types 2 3 import ( 4 "fmt" 5 "strconv" 6 "strings" 7 ) 8 9 // 16 slots of 16 bytes each 10 // See hashing/pdq/README-MIH.md in upstream repo for why not 8x32 or 32x8, etc. 11 const HASH256_NUM_SLOTS = 16 12 const HASH256_HEX_NUM_NYBBLES = 4 * HASH256_NUM_SLOTS 13 14 type Hash256 struct { 15 W [HASH256_NUM_SLOTS]int 16 } 17 18 func (h *Hash256) Clone() Hash256 { 19 rv := Hash256{} 20 for i := 0; i < HASH256_NUM_SLOTS; i++ { 21 rv.W[i] = h.W[i] 22 } 23 return rv 24 } 25 26 func (h *Hash256) String() string { 27 var result []string 28 29 for i := HASH256_NUM_SLOTS - 1; i >= 0; i-- { 30 result = append(result, fmt.Sprintf("%04x", h.W[i]&0xFFFF)) 31 } 32 33 return strings.Join(result, "") 34 } 35 36 func Hash256FromHexString(s string) (*Hash256, error) { 37 if len(s) != HASH256_HEX_NUM_NYBBLES { 38 return nil, fmt.Errorf("incorrect hash length: %s", s) 39 } 40 41 rv := &Hash256{} 42 i := HASH256_NUM_SLOTS 43 for x := 0; x < len(s); x += 4 { 44 i -= 1 45 val, err := strconv.ParseUint(s[x:x+4], 16, 16) 46 if err != nil { 47 return nil, fmt.Errorf("incorrect format: %s", s) 48 } 49 rv.W[i] = int(val) 50 } 51 return rv, nil 52 } 53 54 func (h *Hash256) HammingNorm16(h2 int) int { 55 return BitCount(h2 & 0xFFFF) 56 } 57 58 func BitCount(x int) int { 59 x -= (x >> 1) & 0x55555555 60 x = ((x >> 2) & 0x33333333) + (x & 0x33333333) 61 x = ((x >> 4) + x) & 0x0F0F0F0F 62 x += x >> 8 63 x += x >> 16 64 return x & 0x0000003F 65 } 66 67 func (h *Hash256) ClearAll() { 68 for i := 0; i < HASH256_NUM_SLOTS; i++ { 69 h.W[i] = 0 70 } 71 } 72 73 func (h *Hash256) SetAll() { 74 for i := 0; i < HASH256_NUM_SLOTS; i++ { 75 h.W[i] = 0xFFFF 76 } 77 } 78 79 func (h *Hash256) HammingNorm() int { 80 n := 0 81 82 for i := 0; i < HASH256_NUM_SLOTS; i++ { 83 n += h.HammingNorm16(h.W[i]) 84 } 85 return n 86 } 87 88 func (h *Hash256) HammingDistance(that *Hash256) int { 89 n := 0 90 for i := 0; i < HASH256_NUM_SLOTS; i++ { 91 n += h.HammingNorm16(h.W[i] ^ that.W[i]) 92 } 93 return n 94 } 95 96 func (h *Hash256) HammingDistanceLE(that *Hash256, d int) bool { 97 e := 0 98 for i := 0; i < HASH256_NUM_SLOTS; i++ { 99 e += h.HammingNorm16(h.W[i] ^ that.W[i]) 100 if e > d { 101 return false 102 } 103 } 104 return true 105 } 106 107 func (h *Hash256) SetBit(k int) { 108 h.W[(k&255)>>4] |= 1 << (k & 15) 109 } 110 111 func (h *Hash256) FlipBit(k int) { 112 h.W[(k&255)>>4] ^= 1 << (k & 15) 113 } 114 115 func (h *Hash256) BitwiseXOR(that *Hash256) Hash256 { 116 rv := Hash256{} 117 for i := 0; i < HASH256_NUM_SLOTS; i++ { 118 rv.W[i] = (h.W[i] ^ that.W[i]) 119 } 120 return rv 121 } 122 123 func (h *Hash256) BitwiseAND(that *Hash256) Hash256 { 124 rv := Hash256{} 125 for i := 0; i < HASH256_NUM_SLOTS; i++ { 126 rv.W[i] = (h.W[i] & that.W[i]) 127 } 128 return rv 129 } 130 131 func (h *Hash256) BitwiseOR(that *Hash256) Hash256 { 132 rv := Hash256{} 133 for i := 0; i < HASH256_NUM_SLOTS; i++ { 134 rv.W[i] = (h.W[i] | that.W[i]) 135 } 136 return rv 137 } 138 139 func (h *Hash256) BitwiseNOT() Hash256 { 140 rv := Hash256{} 141 for i := 0; i < HASH256_NUM_SLOTS; i++ { 142 rv.W[i] = (int((^h.W[i])) & 0xFFFF) 143 } 144 return rv 145 } 146 147 func (h *Hash256) DumpBits() string { 148 var str []string 149 150 for i := HASH256_NUM_SLOTS - 1; i >= 0; i-- { 151 word := h.W[i] & 0xFFFF 152 var bits []string 153 for j := 15; j >= 0; j-- { 154 if (word & (1 << uint(j))) != 0 { 155 bits = append(bits, "1") 156 } else { 157 bits = append(bits, "0") 158 } 159 } 160 str = append(str, strings.Join(bits, " ")) 161 } 162 return strings.Join(str, "\n") 163 } 164 165 func (h *Hash256) DumpBitsAcross() string { 166 var str []string 167 168 for i := HASH256_NUM_SLOTS - 1; i >= 0; i-- { 169 word := h.W[i] & 0xFFFF 170 for j := 15; j >= 0; j-- { 171 if (word & (1 << uint(j))) != 0 { 172 str = append(str, "1") 173 } else { 174 str = append(str, "0") 175 } 176 } 177 } 178 return strings.Join(str, " ") 179 } 180 181 func (h *Hash256) DumpWords() string { 182 var words []string 183 184 // Iterate over the reversed list of words 185 for i := len(h.W) - 1; i >= 0; i-- { 186 words = append(words, strconv.Itoa(int(h.W[i]))) 187 } 188 189 // Join the words with commas 190 return strings.Join(words, ",") 191 } 192 193 func (h *Hash256) Eq(other *Hash256) bool { 194 for i := 0; i < HASH256_NUM_SLOTS; i++ { 195 if h.W[i] != other.W[i] { 196 return false 197 } 198 } 199 return true 200 } 201 202 func (h *Hash256) Greater(other *Hash256) bool { 203 for i := 0; i < HASH256_NUM_SLOTS; i++ { 204 if h.W[i] > other.W[i] { 205 return true 206 } else if h.W[i] < other.W[i] { 207 return false 208 } 209 } 210 return false 211 } 212 213 func (h *Hash256) Less(other *Hash256) bool { 214 for i := 0; i < HASH256_NUM_SLOTS; i++ { 215 if h.W[i] < other.W[i] { 216 return true 217 } else if h.W[i] > other.W[i] { 218 return false 219 } 220 } 221 return false 222 }