github.com/insolar/vanilla@v0.0.0-20201023172447-248fdf805322/longbits/long_bits.go (about) 1 // Copyright 2020 Insolar Network Ltd. 2 // All rights reserved. 3 // This material is licensed under the Insolar License version 1.0, 4 // available at https://github.com/insolar/assured-ledger/blob/master/LICENSE.md. 5 6 package longbits 7 8 import ( 9 "bytes" 10 "encoding/binary" 11 "encoding/hex" 12 "fmt" 13 "io" 14 "math/bits" 15 "strings" 16 ) 17 18 var _ FoldableReader = Bits128{} 19 20 const BitsStringPrefix = "0x" 21 22 type Bits64 [8]byte 23 24 func NewBits64(v uint64) Bits64 { 25 r := Bits64{} 26 binary.LittleEndian.PutUint64(r[:], v) 27 return r 28 } 29 30 func (v Bits64) WriteTo(w io.Writer) (int64, error) { 31 n, err := w.Write((v)[:]) 32 return int64(n), err 33 } 34 35 func (v Bits64) CopyTo(p []byte) int { 36 return copy(p, (v)[:]) 37 } 38 39 // TODO test for all ReadAt 40 func (v Bits64) ReadAt(b []byte, off int64) (n int, err error) { 41 if n, err = VerifyReadAt(b, off, len(v)); err != nil || n == 0 { 42 return n, err 43 } 44 return copy(b, v[off:]), nil 45 } 46 47 func (v Bits64) CutOutUint64() uint64 { 48 return binary.LittleEndian.Uint64(v[:]) 49 } 50 51 func (v Bits64) FoldToUint64() uint64 { 52 return binary.LittleEndian.Uint64(v[:]) 53 } 54 55 func (v Bits64) FixedByteSize() int { 56 return len(v) 57 } 58 59 func (v Bits64) AsByteString() ByteString { 60 return ByteString(v[:]) 61 } 62 63 func (v Bits64) String() string { 64 return bitsToStringDefault(v) 65 } 66 67 // deprecated // use longbits.AsBytes() 68 func (v Bits64) AsBytes() []byte { 69 return v[:] 70 } 71 72 func (v Bits64) Compare(other Bits64) int { 73 return bytes.Compare(v[:], other[:]) 74 } 75 76 /* Array size doesnt need to be aligned */ 77 func FoldToBits64(v []byte) (folded Bits64) { 78 if len(v) == 0 { 79 return folded 80 } 81 82 alignedLen := len(v) &^ (len(folded) - 1) // NB! len(folded) MUST be power of 2 83 copy(folded[:], v[alignedLen:]) 84 85 for i := 0; i < alignedLen; i += len(folded) { 86 folded[0] ^= v[i+0] 87 folded[1] ^= v[i+1] 88 folded[2] ^= v[i+2] 89 folded[3] ^= v[i+3] 90 folded[4] ^= v[i+4] 91 folded[5] ^= v[i+5] 92 folded[6] ^= v[i+6] 93 folded[7] ^= v[i+7] 94 } 95 return folded 96 } 97 98 // CutOutBits64 either copies all bytes or picks evenly bytes from (v). Sizes do not need to be aligned. 99 // WARNING! This is NOT compliant with cryptography standards, e.g. FIPS 180‑4 and SP 800-107 100 func CutOutBits64(v []byte) (folded Bits64) { 101 if len(v) <= len(folded) { 102 copy(folded[:], v) 103 return folded 104 } 105 106 for i := range folded { 107 folded[i] = v[i*(len(v)-1)/(len(folded)-1)] 108 } 109 return folded 110 } 111 112 func NewBits128(lo, hi uint64) Bits128 { 113 r := Bits128{} 114 binary.LittleEndian.PutUint64(r[:8], lo) 115 binary.LittleEndian.PutUint64(r[8:], hi) 116 return r 117 } 118 119 type Bits128 [16]byte 120 121 func (v Bits128) WriteTo(w io.Writer) (int64, error) { 122 n, err := w.Write((v)[:]) 123 return int64(n), err 124 } 125 126 func (v Bits128) CopyTo(p []byte) int { 127 return copy(p, (v)[:]) 128 } 129 130 func (v Bits128) ReadAt(b []byte, off int64) (n int, err error) { 131 n, err = VerifyReadAt(b, off, len(v)) 132 if err != nil || n == 0 { 133 return n, err 134 } 135 return copy(b, v[off:]), nil 136 } 137 138 func (v Bits128) CutOutUint64() uint64 { 139 return CutOutUint64(v[:]) 140 } 141 142 func (v Bits128) FoldToUint64() uint64 { 143 return FoldToUint64(v[:]) 144 } 145 146 func (v Bits128) FixedByteSize() int { 147 return len(v) 148 } 149 150 func (v Bits128) String() string { 151 return bitsToStringDefault(v) 152 } 153 154 func (v Bits128) AsByteString() ByteString { 155 return ByteString(v[:]) 156 } 157 158 // deprecated // use longbits.AsBytes() 159 func (v Bits128) AsBytes() []byte { 160 return v[:] 161 } 162 163 func (v Bits128) Compare(other Bits128) int { 164 return bytes.Compare(v[:], other[:]) 165 } 166 167 type Bits224 [28]byte 168 169 func (v Bits224) WriteTo(w io.Writer) (int64, error) { 170 n, err := w.Write((v)[:]) 171 return int64(n), err 172 } 173 174 func (v Bits224) CopyTo(p []byte) int { 175 return copy(p, (v)[:]) 176 } 177 178 func (v Bits224) ReadAt(b []byte, off int64) (n int, err error) { 179 n, err = VerifyReadAt(b, off, len(v)) 180 if err != nil || n == 0 { 181 return n, err 182 } 183 return copy(b, v[off:]), nil 184 } 185 186 func (v Bits224) CutOutUint64() uint64 { 187 return CutOutUint64(v[:]) 188 } 189 190 func (v Bits224) FoldToUint64() uint64 { 191 return FoldToUint64(v[:]) 192 } 193 194 func (v Bits224) FixedByteSize() int { 195 return len(v) 196 } 197 198 func (v Bits224) String() string { 199 return bitsToStringDefault(v) 200 } 201 202 // deprecated // use longbits.AsBytes() 203 func (v Bits224) AsBytes() []byte { 204 return v[:] 205 } 206 207 func (v Bits224) AsByteString() ByteString { 208 return ByteString(v[:]) 209 } 210 211 func (v Bits224) Compare(other Bits224) int { 212 return bytes.Compare(v[:], other[:]) 213 } 214 215 type Bits256 [32]byte 216 217 func (v Bits256) WriteTo(w io.Writer) (int64, error) { 218 n, err := w.Write((v)[:]) 219 return int64(n), err 220 } 221 222 func (v Bits256) CopyTo(p []byte) int { 223 return copy(p, (v)[:]) 224 } 225 226 func (v Bits256) ReadAt(b []byte, off int64) (n int, err error) { 227 n, err = VerifyReadAt(b, off, len(v)) 228 if err != nil || n == 0 { 229 return n, err 230 } 231 return copy(b, v[off:]), nil 232 } 233 234 func (v Bits256) CutOutUint64() uint64 { 235 return CutOutUint64(v[:]) 236 } 237 238 func (v Bits256) FoldToUint64() uint64 { 239 return FoldToUint64(v[:]) 240 } 241 242 func (v Bits256) FoldToBits128() (r Bits128) { 243 for i := range r { 244 r[i] = v[i] ^ v[i+len(r)] 245 } 246 return r 247 } 248 249 func (v Bits256) FoldToBits224() Bits224 { 250 return v.TruncateToBits224() 251 } 252 253 // TruncateToBits224 returns leftmost bits, and it is compliant with cryptography standards, e.g. FIPS 180‑4 and SP 800-107 254 func (v Bits256) TruncateToBits224() (r Bits224) { 255 copy(r[:], v[:]) 256 return r 257 } 258 259 func (v Bits256) FixedByteSize() int { 260 return len(v) 261 } 262 263 func (v Bits256) String() string { 264 return bitsToStringDefault(v) 265 } 266 267 // deprecated // use longbits.AsBytes() 268 func (v Bits256) AsBytes() []byte { 269 return v[:] 270 } 271 272 func (v Bits256) AsByteString() ByteString { 273 return ByteString(v[:]) 274 } 275 276 func (v Bits256) Compare(other Bits256) int { 277 return bytes.Compare(v[:], other[:]) 278 } 279 280 type Bits512 [64]byte 281 282 func (v Bits512) WriteTo(w io.Writer) (int64, error) { 283 n, err := w.Write((v)[:]) 284 return int64(n), err 285 } 286 287 func (v Bits512) CopyTo(p []byte) int { 288 return copy(p, (v)[:]) 289 } 290 291 func (v Bits512) ReadAt(b []byte, off int64) (n int, err error) { 292 n, err = VerifyReadAt(b, off, len(v)) 293 if err != nil || n == 0 { 294 return n, err 295 } 296 return copy(b, v[off:]), nil 297 } 298 299 func (v Bits512) CutOutUint64() uint64 { 300 return CutOutUint64(v[:]) 301 } 302 303 func (v Bits512) FoldToUint64() uint64 { 304 return FoldToUint64(v[:]) 305 } 306 307 func (v Bits512) FoldToBits256() (r Bits256) { 308 for i := range r { 309 r[i] = v[i] ^ v[i+len(r)] 310 } 311 return r 312 } 313 314 func (v Bits512) FoldToBits224() (r Bits224) { 315 for i := range r { 316 r[i] = v[i] ^ v[i+32] 317 } 318 return r 319 } 320 321 func (v Bits512) FixedByteSize() int { 322 return len(v) 323 } 324 325 func (v Bits512) String() string { 326 return bitsToStringDefault(v) 327 } 328 329 // deprecated // use longbits.AsBytes() 330 func (v Bits512) AsBytes() []byte { 331 return v[:] 332 } 333 334 func (v Bits512) AsByteString() ByteString { 335 return ByteString(v[:]) 336 } 337 338 func (v Bits512) Compare(other Bits512) int { 339 return bytes.Compare(v[:], other[:]) 340 } 341 342 func CutOutUint64(v []byte) uint64 { 343 folded := CutOutBits64(v) 344 return folded.CutOutUint64() 345 } 346 347 func FoldToUint64(v []byte) uint64 { 348 folded := FoldToBits64(v) 349 return folded.FoldToUint64() 350 } 351 352 /* 353 This implementation DOES NOT provide secure random! 354 This function has a fixed implementation and MUST remain unchanged as some elements of Consensus rely on identical behavior of this functions. 355 Array size must be aligned to 8 bytes. 356 */ 357 func FillBitsWithStaticNoise(base uint32, v []byte) { 358 359 if bits.OnesCount32(base) < 8 { 360 base ^= 0x6206cc91 // add some noise 361 } 362 363 for i := uint32(0); i < uint32(len(v)); i += 8 { 364 var n = base + i>>3 365 u := uint64((^n) ^ (n << 16)) 366 u |= (u + 1) << 31 367 u ^= u >> 1 368 t := v[i:] 369 binary.LittleEndian.PutUint64(t, u) 370 } 371 } 372 373 func bitsToStringDefault(s FoldableReader) string { 374 return BytesToDigestString(s, BitsStringPrefix) 375 // return BytesToGroupedString(s.AsBytes(), BitsStringPrefix, "_", 8) 376 } 377 378 func BytesToDigestString(s FoldableReader, prefix string) string { 379 return fmt.Sprintf("bits[%d]%s%08x", s.FixedByteSize()*8, prefix, s.FoldToUint64()) 380 } 381 382 func BytesToGroupedString(s []byte, prefix string, separator string, everyN int) string { 383 if everyN == 0 || len(separator) == 0 { 384 return prefix + hex.EncodeToString(s) 385 } 386 387 buf := strings.Builder{} 388 buf.WriteString(prefix) 389 dst := make([]byte, hex.EncodedLen(len(s))) 390 hex.Encode(dst, s) 391 392 i := 0 393 for i < len(s) { 394 if i > 0 { 395 buf.WriteString(separator) 396 } 397 n := i + everyN 398 if i < len(s) { 399 buf.Write(dst[i:n]) 400 } else { 401 buf.Write(dst[i:]) 402 break 403 } 404 i = n 405 } 406 return buf.String() 407 } 408 409 func copyToFixedBits(dst, src []byte, expectedSize int) { 410 size := len(src) 411 if size != expectedSize { 412 panic(fmt.Sprintf("length mismatch, expected: %d, actual: %d", expectedSize, size)) 413 } 414 415 copy(dst, src) 416 } 417 418 func NewBits64FromBytes(bytes []byte) Bits64 { 419 b := Bits64{} 420 copyToFixedBits(b[:], bytes, b.FixedByteSize()) 421 return b 422 } 423 424 func NewBits128FromBytes(bytes []byte) Bits128 { 425 b := Bits128{} 426 copyToFixedBits(b[:], bytes, b.FixedByteSize()) 427 return b 428 } 429 430 func NewBits224FromBytes(bytes []byte) Bits224 { 431 b := Bits224{} 432 copyToFixedBits(b[:], bytes, b.FixedByteSize()) 433 return b 434 } 435 436 func NewBits256FromBytes(bytes []byte) Bits256 { 437 b := Bits256{} 438 copyToFixedBits(b[:], bytes, b.FixedByteSize()) 439 return b 440 } 441 442 func NewBits512FromBytes(bytes []byte) Bits512 { 443 b := Bits512{} 444 copyToFixedBits(b[:], bytes, b.FixedByteSize()) 445 return b 446 }