github.com/protolambda/zssz@v0.1.5/bitfields/bitfield.go (about) 1 package bitfields 2 3 // Note: bitfield indices and lengths are generally all uint32, as this is used in SSZ for lengths too. 4 5 // General base interface for Bitlists and Bitvectors 6 // Note for Bitfields to work with the SSZ functionality: 7 // - Bitlists need to be of kind []byte (packed bits, incl delimiter bit) 8 // - Bitvectors need to be of kind [N]byte (packed bits) 9 type Bitfield interface { 10 Get(i uint64) bool 11 Set(i uint64, v bool) 12 } 13 14 // bitfields implementing this can be checked to be of a valid or not. Useful for untrusted bitfields. 15 // See BitlistCheck and BitvectorCheck to easily implement the validity checks. 16 type CheckedBitfield interface { 17 Check() error 18 } 19 20 // the exact bitlength can be determined for bitfields implementing this method. 21 type SizedBits interface { 22 BitLen() uint64 23 } 24 25 // Get index of left-most 1 bit. 26 // 0 (incl.) to 8 (excl.) 27 func BitIndex(v byte) (out uint64) { 28 // going to be prettier with new Go 1.13 binary constant syntax 29 if v&0xf0 != 0 { // 11110000 30 out |= 4 31 v >>= 4 32 } 33 if v&0x0c != 0 { // 00001100 34 out |= 2 35 v >>= 2 36 } 37 if v&0x02 != 0 { // 00000010 38 out |= 1 39 v >>= 1 40 } 41 return 42 } 43 44 // Helper function to implement Bitfields with. 45 // Assumes i is a valid bit-index to retrieve a bit from bytes b. 46 func GetBit(b []byte, i uint64) bool { 47 return (b[i>>3]>>(i&7))&1 == 1 48 } 49 50 // Helper function to implement Bitfields with. 51 // Assumes i is a valid bit-index to set a bit within bytes b. 52 func SetBit(b []byte, i uint64, v bool) { 53 if bit := byte(1) << (i & 7); v { 54 b[i>>3] |= bit 55 } else { 56 b[i>>3] &^= bit 57 } 58 } 59 60 // Checks if the bitList is fully zeroed (except the leading bit) 61 func IsZeroBitlist(b []byte) bool { 62 end := len(b) 63 if end == 0 { 64 return true 65 } 66 end -= 1 67 if end > 0 { 68 // bytes up to the end byte can be checked efficiently. No need for bit-magic. 69 for i := 0; i < end; i++ { 70 if b[i] != 0 { 71 return false 72 } 73 } 74 } 75 last := b[end] 76 if last == 0 { 77 // invalid bitlist, but reasonably zero 78 return true 79 } 80 // now check the last bit, but ignore the delimiter 1 bit. 81 last ^= byte(1) << BitIndex(last) 82 return last == 0 83 }