github.com/protolambda/zssz@v0.1.5/types/ssz_bitlist.go (about) 1 package types 2 3 import ( 4 "fmt" 5 "github.com/protolambda/zssz/bitfields" 6 . "github.com/protolambda/zssz/dec" 7 . "github.com/protolambda/zssz/enc" 8 . "github.com/protolambda/zssz/htr" 9 "github.com/protolambda/zssz/merkle" 10 . "github.com/protolambda/zssz/pretty" 11 "github.com/protolambda/zssz/util/ptrutil" 12 "reflect" 13 "unsafe" 14 ) 15 16 type SSZBitlist struct { 17 bitLimit uint64 18 byteLimit uint64 // exclusive delimiting bit 19 leafLimit uint64 // exclusive delimiting bit 20 } 21 22 var bitlistMeta = reflect.TypeOf((*bitfields.BitlistMeta)(nil)).Elem() 23 24 func NewSSZBitlist(typ reflect.Type) (*SSZBitlist, error) { 25 if typ.Kind() != reflect.Slice { 26 return nil, fmt.Errorf("typ is not a dynamic-length bytes slice (bitlist requirement)") 27 } 28 if typ.Elem().Kind() != reflect.Uint8 { 29 return nil, fmt.Errorf("typ is not a bytes slice (bitlist requirement)") 30 } 31 bitLimit, err := ReadListLimit(typ) 32 if err != nil { 33 return nil, err 34 } 35 byteLimit := (bitLimit + 7) >> 3 36 res := &SSZBitlist{ 37 bitLimit: bitLimit, 38 byteLimit: byteLimit, 39 leafLimit: (byteLimit + 31) >> 5, 40 } 41 return res, nil 42 } 43 44 // in bytes (rounded up), not bits 45 func (v *SSZBitlist) FuzzMinLen() uint64 { 46 // 8 for a random byte count, 1 for a random leading byte 47 return 8 + 1 48 } 49 50 // in bytes (rounded up), not bits 51 func (v *SSZBitlist) FuzzMaxLen() uint64 { 52 // 8 for a random byte count, limit for maximum fill 53 return 8 + v.byteLimit 54 } 55 56 // in bytes (rounded up), not bits. Includes the delimiting 1 bit. 57 func (v *SSZBitlist) MinLen() uint64 { 58 // leading bit to mark it the 0 length makes it 1 byte. 59 return 1 60 } 61 62 // in bytes (rounded up), not bits 63 func (v *SSZBitlist) MaxLen() uint64 { 64 return (v.bitLimit >> 3) + 1 65 } 66 67 // in bytes (rounded up), not bits 68 func (v *SSZBitlist) FixedLen() uint64 { 69 return 0 70 } 71 72 func (v *SSZBitlist) IsFixed() bool { 73 return false 74 } 75 76 func (v *SSZBitlist) SizeOf(p unsafe.Pointer) uint64 { 77 sh := ptrutil.ReadSliceHeader(p) 78 return uint64(sh.Len) 79 } 80 81 func (v *SSZBitlist) Encode(eb *EncodingWriter, p unsafe.Pointer) error { 82 sh := ptrutil.ReadSliceHeader(p) 83 data := *(*[]byte)(unsafe.Pointer(sh)) 84 return eb.Write(data) 85 } 86 87 func (v *SSZBitlist) Decode(dr *DecodingReader, p unsafe.Pointer) error { 88 var byteLen uint64 89 if dr.IsFuzzMode() { 90 x, err := dr.ReadUint64() 91 if err != nil { 92 return err 93 } 94 // get span to fill with available space 95 span := dr.GetBytesSpan() - 1 96 // respect type limit 97 if span > v.byteLimit { 98 span = v.byteLimit 99 } 100 if span != 0 { 101 byteLen = x % span 102 } 103 // completely empty bitlists are invalid. Need a leading 1 bit. 104 byteLen += 1 105 } else { 106 byteLen = dr.GetBytesSpan() 107 } 108 ptrutil.BytesAllocFn(p, byteLen) 109 data := *(*[]byte)(p) 110 if _, err := dr.Read(data); err != nil { 111 return err 112 } 113 if dr.IsFuzzMode() { 114 // mask last byte to stay within bit-limit 115 data[len(data)-1] &= (1 << (v.bitLimit + 1)) - 1 116 if data[len(data)-1] == 0 { 117 // last byte must not be 0 for bitlist to be valid 118 data[len(data)-1] = 1 119 } 120 } 121 // check if the data is a valid bitvector value (0 bits for unused bits) 122 return bitfields.BitlistCheck(data, v.bitLimit) 123 } 124 125 func (v *SSZBitlist) DryCheck(dr *DecodingReader) error { 126 span := dr.GetBytesSpan() 127 if err := bitfields.BitlistCheckByteLen(span, v.bitLimit); err != nil { 128 return err 129 } 130 // 0 span is already checked by BitlistCheckByteLen 131 if _, err := dr.Skip(span - 1); err != nil { 132 return err 133 } 134 last, err := dr.ReadByte() 135 if err != nil { 136 return err 137 } 138 return bitfields.BitlistCheckLastByte(last, v.bitLimit-((span-1)<<3)) 139 } 140 141 func (v *SSZBitlist) HashTreeRoot(h MerkleFn, p unsafe.Pointer) [32]byte { 142 sh := ptrutil.ReadSliceHeader(p) 143 data := *(*[]byte)(unsafe.Pointer(sh)) 144 bitLen := bitfields.BitlistLen(data) 145 byteLen := (bitLen + 7) >> 3 146 leafCount := (byteLen + 31) >> 5 147 leaf := func(i uint64) []byte { 148 s := i << 5 149 e := (i + 1) << 5 150 // pad the data 151 if e > byteLen { 152 x := [32]byte{} 153 copy(x[:], data[s:byteLen]) 154 if bitLen&7 != 0 && byteLen != 0 { // if we not already cut off the delimiting bit with a bytes boundary 155 // find the index of the length-determining 1 bit (bitlist length == index of this bit) 156 delimitByteIndex := (byteLen - 1) & 31 157 mask := ^(byte(1) << bitfields.BitIndex(x[delimitByteIndex])) 158 // zero out the length bit. 159 x[delimitByteIndex] &= mask 160 } 161 return x[:] 162 } 163 // if the last leaf does not have to be padded, 164 // then the length-determining bitlist bit is already cut off, 165 // i.e. as sole bit in next (ignored) chunk of data. 166 return data[s:e] 167 } 168 return h.MixIn(merkle.Merkleize(h, leafCount, v.leafLimit, leaf), bitLen) 169 } 170 171 func (v *SSZBitlist) Pretty(indent uint32, w *PrettyWriter, p unsafe.Pointer) { 172 w.WriteIndent(indent) 173 sh := ptrutil.ReadSliceHeader(p) 174 data := *(*[]byte)(unsafe.Pointer(sh)) 175 w.Write(fmt.Sprintf("%08b", data)) 176 }