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  }