github.com/protolambda/zssz@v0.1.5/bitfields/bitvector.go (about)

     1  package bitfields
     2  
     3  import "fmt"
     4  
     5  // Bitvectors should have a pointer-receiver BitLen function to derive its fixed bit-length from.
     6  type BitvectorMeta interface {
     7  	SizedBits
     8  }
     9  
    10  type Bitvector interface {
    11  	Bitfield
    12  	BitvectorMeta
    13  }
    14  
    15  // Helper function to implement Bitvector with.
    16  // It checks if:
    17  //  1. b has the same amount of bytes as necessary for n bits.
    18  //  2. unused bits in b are 0
    19  func BitvectorCheck(b []byte, n uint64) error {
    20  	byteLen := uint64(len(b))
    21  	if err := BitvectorCheckByteLen(byteLen, n); err != nil {
    22  		return err
    23  	}
    24  	if byteLen == 0 {
    25  		// empty bitvector
    26  		return nil
    27  	}
    28  	last := b[byteLen-1]
    29  	return BitvectorCheckLastByte(last, n)
    30  }
    31  
    32  func BitvectorCheckByteLen(byteLen uint64, bitLength uint64) error {
    33  	if expected := (bitLength + 7) >> 3; byteLen != expected {
    34  		return fmt.Errorf("bitvector of %d bytes has not expected length in bytes %d", byteLen, expected)
    35  	}
    36  	return nil
    37  }
    38  
    39  func BitvectorCheckLastByte(last byte, n uint64) error {
    40  	if n == 0 {
    41  		return fmt.Errorf("empty bitvector can not have a last byte")
    42  	}
    43  	if n&7 == 0 {
    44  		// n is a multiple of 8, so last byte fits
    45  		return nil
    46  	}
    47  	// check if it is big enough to hold any non-zero contents in the last byte.
    48  	if expectedBitsLen := n & 7; (last >> expectedBitsLen) != 0 {
    49  		return fmt.Errorf("bitvector last byte 0b%b has not expected %d bits in last byte", last, expectedBitsLen)
    50  	}
    51  	return nil
    52  }