diff --git a/vdaf/prio3/arith/fp64/vector.go b/vdaf/prio3/arith/fp64/vector.go index 608a8f4e..1fae52c5 100644 --- a/vdaf/prio3/arith/fp64/vector.go +++ b/vdaf/prio3/arith/fp64/vector.go @@ -4,6 +4,7 @@ package fp64 import ( "encoding/binary" + "errors" "io" "math/bits" "slices" @@ -183,6 +184,34 @@ func (v Vec) UnmarshalBinary(b []byte) error { return conv.UnmarshalBinary(v, b) } +// ExportRaw serializes the vector as a sequence of raw field elements +func (v Vec) ExportRaw() ([]byte, error) { + buf := make([]byte, Size*len(v)) + for i, f := range v { + // Convert from Montgomery form to standard form + standard := f.fromMont() + // Serialize as little-endian uint64 + binary.LittleEndian.PutUint64(buf[i*Size:(i+1)*Size], standard[0]) + } + return buf, nil +} + +// ImportRaw deserializes the vector from raw field elements +func (v *Vec) ImportRaw(data []byte) error { + if len(data)%Size != 0 { + return errors.New("ImportRaw: data length not a multiple of field size") + } + n := len(data) / Size + *v = make(Vec, n) + for i := 0; i < n; i++ { + // Deserialize as little-endian uint64 + val := binary.LittleEndian.Uint64(data[i*Size:(i+1)*Size]) + // Set the field element and convert to Montgomery form + (*v)[i].SetUint64(val) + } + return nil +} + func (v Vec) Marshal(b *cryptobyte.Builder) error { for i := range v { v[i].Marshal(b) diff --git a/vdaf/prio3/internal/prio3/types.go b/vdaf/prio3/internal/prio3/types.go index 94e49cbb..28fe21ab 100644 --- a/vdaf/prio3/internal/prio3/types.go +++ b/vdaf/prio3/internal/prio3/types.go @@ -1,6 +1,7 @@ package prio3 import ( + "errors" "github.com/cloudflare/circl/internal/conv" "github.com/cloudflare/circl/vdaf/prio3/arith" "golang.org/x/crypto/cryptobyte" @@ -360,6 +361,32 @@ func (s *OutShare[V, E]) Unmarshal(str *cryptobyte.String) bool { return s.share.Unmarshal(str) } +// ExportBytes returns the portable binary encoding of the OutShare. +func (s *OutShare[V, E]) ExportBytes() ([]byte, error) { + return s.MarshalBinary() +} + +// ImportBytes sets the OutShare from a portable binary encoding. +func (s *OutShare[V, E]) ImportBytes(data []byte) error { + return s.UnmarshalBinary(data) +} + +// ExportRaw returns the underlying vector as a byte slice. +func (s *OutShare[V, E]) ExportRaw() ([]byte, error) { + if b, ok := any(s.share).(interface{ ExportRaw() ([]byte, error) }); ok { + return b.ExportRaw() + } + return nil, errors.New("ExportRaw: underlying vector does not support ExportRaw") +} + +// ImportRaw sets the underlying vector from a byte slice. +func (s *OutShare[V, E]) ImportRaw(data []byte) error { + if b, ok := any(&s.share).(interface{ ImportRaw([]byte) error }); ok { + return b.ImportRaw(data) + } + return errors.New("ImportRaw: underlying vector does not support ImportRaw") +} + // AggShare represents the following structure. // // struct {