github.com/protolambda/zssz@v0.1.5/types/ssz_bitvector.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 SSZBitvector struct {
    17  	bitLen  uint64
    18  	byteLen uint64
    19  }
    20  
    21  var bitvectorMeta = reflect.TypeOf((*bitfields.BitvectorMeta)(nil)).Elem()
    22  
    23  func NewSSZBitvector(typ reflect.Type) (*SSZBitvector, error) {
    24  	if typ.Kind() != reflect.Array {
    25  		return nil, fmt.Errorf("typ is not a fixed-length bytes array (bitvector requirement)")
    26  	}
    27  	if typ.Elem().Kind() != reflect.Uint8 {
    28  		return nil, fmt.Errorf("typ is not a bytes array (bitvector requirement)")
    29  	}
    30  	ptrTyp := reflect.PtrTo(typ)
    31  	if !ptrTyp.Implements(bitvectorMeta) {
    32  		return nil, fmt.Errorf("*typ (pointer type) is not a bitvector")
    33  	}
    34  	typedNil := reflect.New(ptrTyp).Elem().Interface().(bitfields.BitvectorMeta)
    35  	bitLen := typedNil.BitLen()
    36  	byteLen := uint64(typ.Len())
    37  	if (bitLen+7)>>3 != byteLen {
    38  		return nil, fmt.Errorf("bitvector type has not the expected %d bytes to cover %d bits", byteLen, bitLen)
    39  	}
    40  	res := &SSZBitvector{bitLen: bitLen, byteLen: byteLen}
    41  	return res, nil
    42  }
    43  
    44  // in bytes (rounded up), not bits
    45  func (v *SSZBitvector) FuzzMinLen() uint64 {
    46  	return v.byteLen
    47  }
    48  
    49  // in bytes (rounded up), not bits
    50  func (v *SSZBitvector) FuzzMaxLen() uint64 {
    51  	return v.byteLen
    52  }
    53  
    54  // in bytes (rounded up), not bits
    55  func (v *SSZBitvector) MinLen() uint64 {
    56  	return v.byteLen
    57  }
    58  
    59  // in bytes (rounded up), not bits
    60  func (v *SSZBitvector) MaxLen() uint64 {
    61  	return v.byteLen
    62  }
    63  
    64  // in bytes (rounded up), not bits
    65  func (v *SSZBitvector) FixedLen() uint64 {
    66  	return v.byteLen
    67  }
    68  
    69  func (v *SSZBitvector) IsFixed() bool {
    70  	return true
    71  }
    72  
    73  func (v *SSZBitvector) SizeOf(p unsafe.Pointer) uint64 {
    74  	return v.byteLen
    75  }
    76  
    77  func (v *SSZBitvector) Encode(eb *EncodingWriter, p unsafe.Pointer) error {
    78  	sh := ptrutil.GetSliceHeader(p, v.byteLen)
    79  	data := *(*[]byte)(unsafe.Pointer(sh))
    80  	return eb.Write(data)
    81  }
    82  
    83  func (v *SSZBitvector) Decode(dr *DecodingReader, p unsafe.Pointer) error {
    84  	sh := ptrutil.GetSliceHeader(p, v.byteLen)
    85  	data := *(*[]byte)(unsafe.Pointer(sh))
    86  	if _, err := dr.Read(data); err != nil {
    87  		return err
    88  	}
    89  	// check if the data is a valid bitvector value (0 bits for unused bits)
    90  	return bitfields.BitvectorCheck(data, v.bitLen)
    91  }
    92  
    93  func (v *SSZBitvector) DryCheck(dr *DecodingReader) error {
    94  	if v.bitLen == 0 {
    95  		return nil
    96  	}
    97  	if v.byteLen > 1 {
    98  		_, err := dr.Skip(v.byteLen - 1)
    99  		if err != nil {
   100  			return err
   101  		}
   102  	}
   103  	last, err := dr.ReadByte()
   104  	if err != nil {
   105  		return err
   106  	}
   107  	return bitfields.BitvectorCheckLastByte(last, v.bitLen)
   108  }
   109  
   110  func (v *SSZBitvector) HashTreeRoot(h MerkleFn, p unsafe.Pointer) [32]byte {
   111  	sh := ptrutil.GetSliceHeader(p, v.byteLen)
   112  	data := *(*[]byte)(unsafe.Pointer(sh))
   113  	leafCount := (v.byteLen + 31) >> 5
   114  	leaf := func(i uint64) []byte {
   115  		s := i << 5
   116  		e := (i + 1) << 5
   117  		// pad the data
   118  		if e > v.byteLen {
   119  			x := [32]byte{}
   120  			copy(x[:], data[s:v.byteLen])
   121  			return x[:]
   122  		}
   123  		return data[s:e]
   124  	}
   125  	return merkle.Merkleize(h, leafCount, leafCount, leaf)
   126  }
   127  
   128  func (v *SSZBitvector) Pretty(indent uint32, w *PrettyWriter, p unsafe.Pointer) {
   129  	w.WriteIndent(indent)
   130  	sh := ptrutil.GetSliceHeader(p, v.byteLen)
   131  	data := *(*[]byte)(unsafe.Pointer(sh))
   132  	w.Write(fmt.Sprintf("%08b", data))
   133  }