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

     1  package bitfields
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"github.com/protolambda/zssz/lists"
     7  )
     8  
     9  type BitlistMeta interface {
    10  	// Length (in bits) of the Bitlist.
    11  	SizedBits
    12  	// BitLimit (in bits) of the Bitlist.
    13  	lists.List
    14  }
    15  
    16  type Bitlist interface {
    17  	Bitfield
    18  	BitlistMeta
    19  }
    20  
    21  // Returns the length of the bitlist.
    22  // And although strictly speaking invalid. a sane default is returned for:
    23  //  - an empty raw bitlist: a default 0 bitlist will be of length 0 too.
    24  //  - a bitlist with a leading 0 byte: return the bitlist raw bit length,
    25  //     excluding the last byte (As if it was full 0 padding).
    26  func BitlistLen(b []byte) uint64 {
    27  	byteLen := uint64(len(b))
    28  	if byteLen == 0 {
    29  		return 0
    30  	}
    31  	last := b[byteLen-1]
    32  	return ((byteLen - 1) << 3) | BitIndex(last)
    33  }
    34  
    35  // Helper function to implement Bitlist with.
    36  // It checks if:
    37  //  0. the raw bitlist is not empty, there must be a 1 bit to determine the length.
    38  //  1. the bitlist has a leading 1 bit in the last byte to determine the length with.
    39  //  2. if b has no more than given limit in bits.
    40  func BitlistCheck(b []byte, limit uint64) error {
    41  	byteLen := uint64(len(b))
    42  	if err := BitlistCheckByteLen(byteLen, limit); err != nil {
    43  		return err
    44  	}
    45  	last := b[byteLen-1]
    46  	return BitlistCheckLastByte(last, limit-((byteLen-1)<<3))
    47  }
    48  
    49  func BitlistCheckByteLen(byteLen uint64, bitLimit uint64) error {
    50  	if byteLen == 0 {
    51  		return errors.New("bitlist is missing length delimit bit")
    52  	}
    53  	// there may not be more bytes than necessary for the N bits, +1 for the delimiting bit. (also rounds up)
    54  	if byteLimitWithDelimiter := (bitLimit >> 3) + 1; byteLen > byteLimitWithDelimiter {
    55  		return fmt.Errorf("got %d bytes, expected no more than %d bytes for bitlist",
    56  			byteLen, byteLimitWithDelimiter)
    57  	}
    58  	return nil
    59  }
    60  
    61  func BitlistCheckLastByte(last byte, limit uint64) error {
    62  	if last == 0 {
    63  		return errors.New("bitlist is invalid, trailing 0 byte")
    64  	}
    65  	if BitIndex(last) > limit {
    66  		return errors.New("bitlist is invalid, too many bits")
    67  	}
    68  	return nil
    69  }