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 }