github.com/protolambda/zssz@v0.1.5/types/basic_series.go (about) 1 package types 2 3 import ( 4 "fmt" 5 . "github.com/protolambda/zssz/dec" 6 . "github.com/protolambda/zssz/enc" 7 . "github.com/protolambda/zssz/htr" 8 "github.com/protolambda/zssz/merkle" 9 "github.com/protolambda/zssz/util/ptrutil" 10 "reflect" 11 "unsafe" 12 ) 13 14 func GetBasicSSZElemType(kind reflect.Kind) (SSZ, error) { 15 switch kind { 16 case reflect.Bool: 17 return SSZBool{}, nil 18 case reflect.Uint8: 19 return SSZUint8{}, nil 20 case reflect.Uint16: 21 return SSZUint16{}, nil 22 case reflect.Uint32: 23 return SSZUint32{}, nil 24 case reflect.Uint64: 25 return SSZUint64{}, nil 26 default: 27 return nil, fmt.Errorf("kind %d is not a basic type", kind) 28 } 29 } 30 31 // WARNING: for little-endian architectures only, or the elem-length has to be 1 byte 32 func LittleEndianBasicSeriesEncode(eb *EncodingWriter, p unsafe.Pointer, bytesLen uint64) error { 33 bytesSh := ptrutil.GetSliceHeader(p, bytesLen) 34 data := *(*[]byte)(unsafe.Pointer(bytesSh)) 35 return eb.Write(data) 36 } 37 38 // WARNING: for little-endian architectures only, or the elem-length has to be 1 byte 39 func LittleEndianBasicSeriesDecode(dr *DecodingReader, p unsafe.Pointer, bytesLen uint64, bytesLimit uint64, isBoolElem bool) error { 40 if bytesLen > bytesLimit { 41 return fmt.Errorf("got %d bytes, expected no more than %d bytes", bytesLen, bytesLimit) 42 } 43 bytesSh := ptrutil.GetSliceHeader(p, bytesLen) 44 data := *(*[]byte)(unsafe.Pointer(bytesSh)) 45 if _, err := dr.Read(data); err != nil { 46 return err 47 } 48 if isBoolElem { 49 if dr.IsFuzzMode() { 50 // just make it correct where necessary 51 for i := 0; i < len(data); i++ { 52 if data[i] > 1 { 53 data[i] = 1 54 } 55 } 56 } else { 57 for i := 0; i < len(data); i++ { 58 if data[i] > 1 { 59 return fmt.Errorf("byte %d in bool list is not a valid bool value: %d", i, data[i]) 60 } 61 } 62 } 63 } 64 return nil 65 } 66 67 // WARNING: for little-endian architectures only, or the elem-length has to be 1 byte 68 func LittleEndianBasicSeriesHTR(h MerkleFn, p unsafe.Pointer, bytesLen uint64, bytesLimit uint64) [32]byte { 69 bytesSh := ptrutil.GetSliceHeader(p, bytesLen) 70 data := *(*[]byte)(unsafe.Pointer(bytesSh)) 71 72 leaf := func(i uint64) []byte { 73 s := i << 5 74 e := (i + 1) << 5 75 // pad the data 76 if e > bytesLen { 77 d := [32]byte{} 78 copy(d[:], data[s:bytesLen]) 79 return d[:] 80 } 81 return data[s:e] 82 } 83 leafCount := (bytesLen + 31) >> 5 84 leafLimit := (bytesLimit + 31) >> 5 85 return merkle.Merkleize(h, leafCount, leafLimit, leaf) 86 } 87 88 func BigToLittleEndianChunk(data [32]byte, elemSize uint8) (out [32]byte) { 89 // could be better with assembly or more bit-magic. 90 // However, big-endian performance is not prioritized. 91 x := 0 92 for i := uint8(0); i < 32; i += elemSize { 93 for j := elemSize - 1; j >= 1; j-- { 94 out[x] = data[i|j] 95 x++ 96 } 97 out[x] = data[i] 98 x++ 99 } 100 return 101 } 102 103 // counter-part of LittleEndianBasicSeriesHTR 104 func BigEndianBasicSeriesHTR(h MerkleFn, p unsafe.Pointer, bytesLen uint64, bytesLimit uint64, elemSize uint8) [32]byte { 105 bytesSh := ptrutil.GetSliceHeader(p, bytesLen) 106 data := *(*[]byte)(unsafe.Pointer(bytesSh)) 107 108 leaf := func(i uint64) []byte { 109 s := i << 5 110 e := (i + 1) << 5 111 d := [32]byte{} 112 if e > bytesLen { 113 copy(d[:], data[s:bytesLen]) 114 } else { 115 copy(d[:], data[s:e]) 116 } 117 d = BigToLittleEndianChunk(d, elemSize) 118 return d[:] 119 } 120 leafCount := (bytesLen + 31) >> 5 121 leafLimit := (bytesLimit + 31) >> 5 122 return merkle.Merkleize(h, leafCount, leafLimit, leaf) 123 } 124 125 func CallSeries(fn func(i uint64, p unsafe.Pointer), length uint64, elemMemSize uintptr, p unsafe.Pointer) { 126 memOffset := uintptr(0) 127 for i := uint64(0); i < length; i++ { 128 elemPtr := unsafe.Pointer(uintptr(p) + memOffset) 129 memOffset += elemMemSize 130 fn(i, elemPtr) 131 } 132 } 133 134 func BasicSeriesDryCheck(dr *DecodingReader, bytesLen uint64, bytesLimit uint64, isBoolElem bool) error { 135 if bytesLen > bytesLimit { 136 return fmt.Errorf("got %d bytes, expected no more than %d bytes", bytesLen, bytesLimit) 137 } 138 if isBoolElem { 139 for i := uint64(0); i < bytesLen; i++ { 140 if v, err := dr.ReadByte(); err != nil { 141 return err 142 } else if v > 1 { 143 return fmt.Errorf("byte %d in bool list is not a valid bool value: %d", i, v) 144 } 145 } 146 } else { 147 if _, err := dr.Skip(bytesLen); err != nil { 148 return err 149 } 150 } 151 return nil 152 }