func (witness *Witness) LimitReadFrom(r io.Reader, expectedSize int) (int64, error) {
	var buf [4]byte
	if read, err := io.ReadFull(r, buf[:4]); err != nil {
		return int64(read), err
	}
	sliceLen := binary.BigEndian.Uint32(buf[:4])
	if int(sliceLen) != expectedSize {
		return 4, errors.New("invalid witness size")
	}
	if len(*witness) != int(sliceLen) {
		*witness = make([]fr.Element, sliceLen)
	}
	lr := io.LimitReader(r, int64(expectedSize*fr.Limbs*8))
	dec := curve.NewDecoder(lr)
	for i := 0; i < int(sliceLen); i++ {
		if err := dec.Decode(&(*witness)[i]); err != nil {
			return dec.BytesRead() + 4, err
		}
	}
	return dec.BytesRead() + 4, nil
}
LimitReadFrom decodes witness from reader; first 4 bytes (uint32) must equal to expectedSize
this method won't read more than expectedSize * size(fr.Element)
package witness
import (
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"reflect"
	"github.com/consensys/gnark/frontend"
	"github.com/consensys/gnark/internal/backend/compiled"
	"github.com/consensys/gnark/internal/parser"
	"github.com/consensys/gnark-crypto/ecc/bn254/fr"
	curve "github.com/consensys/gnark-crypto/ecc/bn254"
)
type Witness []fr.Element
func (witness *Witness) WriteTo(w io.Writer) (int64, error) {
	if err := binary.Write(w, binary.BigEndian, uint32(len(*witness))); err != nil {
		return 0, err
	}
	enc := curve.NewEncoder(w)
	for i := 0; i < len(*witness); i++ {
		if err := enc.Encode(&(*witness)[i]); err != nil {
			return enc.BytesWritten() + 4, err
		}
	}
	return enc.BytesWritten() + 4, nil
}