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  }