ceremonyclient/ferret/ferret.go
Cassandra Heart 12996487c3
v2.1.0.18 (#508)
* experiment: reject bad peer info messages

* v2.1.0.18 preview

* add tagged sync

* Add missing hypergraph changes

* small tweaks to sync

* allow local sync, use it for provers with workers

* missing file

* resolve build error

* resolve sync issue, remove raw sync

* resolve deletion promotion bug

* resolve sync abstraction leak from tree deletion changes

* rearrange prover sync

* remove pruning from sync

* restore removed sync flag

* fix: sync, event stream deadlock, heuristic scoring of better shards

* resolve hanging shutdown + pubsub proxy issue

* further bugfixes: sync (restore old leaf sync), pubsub shutdown, merge events

* fix: clean up rust ffi, background coverage events, and sync tweaks

* fix: linking issue for channel, connectivity test aggression, sync regression, join tests

* fix: disjoint sync, improper application of filter

* resolve sync/reel/validation deadlock

* adjust sync to handle no leaf edge cases, multi-path segment traversal

* use simpler sync

* faster, simpler sync with some debug extras

* migration to recalculate

* don't use batch

* square up the roots

* fix nil pointer

* fix: seniority calculation, sync race condition, migration

* make sync dumber

* fix: tree deletion issue

* fix: missing seniority merge request canonical serialization

* address issues from previous commit test

* stale workers should be cleared

* remove missing gap check

* rearrange collect, reduce sync logging noise

* fix: the disjoint leaf/branch sync case

* nuclear option on sync failures

* v2.1.0.18, finalized
2026-02-08 23:51:51 -06:00

293 lines
6.9 KiB
Go

package ferret
import (
"fmt"
"github.com/pkg/errors"
generated "source.quilibrium.com/quilibrium/monorepo/ferret/generated/ferret"
)
//go:generate ./generate.sh
const (
ALICE = 1
BOB = 2
)
type FerretOT struct {
party int
ferretCOT *generated.FerretCotManager
netio *generated.NetIoManager
}
func NewFerretOT(
party int,
address string,
port int,
threads int,
length uint64,
choices []bool,
malicious bool,
) (*FerretOT, error) {
if threads > 1 {
fmt.Println(
"!!!WARNING!!! THERE BE DRAGONS. RUNNING MULTITHREADED MODE IN SOME " +
"SITUATIONS HAS LEAD TO CRASHES AND OTHER ISSUES. IF YOU STILL WISH " +
"TO DO THIS, YOU WILL NEED TO MANUALLY UPDATE THE BUILD AND REMOVE " +
"THIS CHECK. DO SO AT YOUR OWN RISK",
)
return nil, errors.Wrap(errors.New("invalid thread count"), "new ferret ot")
}
var addr *string
if address != "" {
addrCopy := address
addr = &addrCopy
}
netio := generated.CreateNetioManager(
int32(party),
addr,
int32(port),
)
ferretCOT := generated.CreateFerretCotManager(
int32(party),
int32(threads),
length,
choices,
netio,
malicious,
)
return &FerretOT{
party: party,
ferretCOT: ferretCOT,
netio: netio,
}, nil
}
func (ot *FerretOT) SendCOT() error {
if ot.party != ALICE {
return errors.New("incorrect party")
}
ot.ferretCOT.SendCot()
return nil
}
func (ot *FerretOT) RecvCOT() error {
if ot.party != BOB {
return errors.New("incorrect party")
}
ot.ferretCOT.RecvCot()
return nil
}
func (ot *FerretOT) SendROT() error {
ot.ferretCOT.SendRot()
return nil
}
func (ot *FerretOT) RecvROT() error {
ot.ferretCOT.RecvRot()
return nil
}
func (ot *FerretOT) SenderGetBlockData(choice bool, index uint64) []byte {
c := uint8(0)
if choice {
c = 1
}
return ot.ferretCOT.GetBlockData(c, index)
}
func (ot *FerretOT) ReceiverGetBlockData(index uint64) []byte {
return ot.ferretCOT.GetBlockData(0, index)
}
// FerretBufferOT is a buffer-based Ferret OT that uses message passing
// instead of direct TCP connections. This allows routing OT traffic through
// an external transport (e.g., message channels, proxies).
type FerretBufferOT struct {
party int
ferretCOT *generated.FerretCotBufferManager
bufferIO *generated.BufferIoManager
}
// NewFerretBufferOT creates a new buffer-based Ferret OT.
// Unlike NewFerretOT, this doesn't establish any network connections.
// Instead, the caller is responsible for:
// 1. Calling DrainSend() to get outgoing data
// 2. Transmitting that data to the peer via their own transport
// 3. Receiving data from peer and calling FillRecv() with it
func NewFerretBufferOT(
party int,
threads int,
length uint64,
choices []bool,
malicious bool,
initialBufferCap int64,
) (*FerretBufferOT, error) {
if threads > 1 {
fmt.Println(
"!!!WARNING!!! THERE BE DRAGONS. RUNNING MULTITHREADED MODE IN SOME " +
"SITUATIONS HAS LEAD TO CRASHES AND OTHER ISSUES. IF YOU STILL WISH " +
"TO DO THIS, YOU WILL NEED TO MANUALLY UPDATE THE BUILD AND REMOVE " +
"THIS CHECK. DO SO AT YOUR OWN RISK",
)
return nil, errors.Wrap(errors.New("invalid thread count"), "new ferret buffer ot")
}
bufferIO := generated.CreateBufferIoManager(initialBufferCap)
ferretCOT := generated.CreateFerretCotBufferManager(
int32(party),
int32(threads),
length,
choices,
bufferIO,
malicious,
)
return &FerretBufferOT{
party: party,
ferretCOT: ferretCOT,
bufferIO: bufferIO,
}, nil
}
// FillRecv fills the receive buffer with data from an external transport.
// Call this when you receive data from the peer.
func (ot *FerretBufferOT) FillRecv(data []byte) bool {
return ot.bufferIO.FillRecv(data)
}
// DrainSend drains up to maxLen bytes from the send buffer.
// Call this to get data that needs to be sent to the peer.
func (ot *FerretBufferOT) DrainSend(maxLen uint64) []byte {
return ot.bufferIO.DrainSend(maxLen)
}
// SendSize returns the number of bytes waiting to be sent.
func (ot *FerretBufferOT) SendSize() uint64 {
return ot.bufferIO.SendSize()
}
// RecvAvailable returns the number of bytes available in the receive buffer.
func (ot *FerretBufferOT) RecvAvailable() uint64 {
return ot.bufferIO.RecvAvailable()
}
// SetTimeout sets the timeout for blocking receive operations (in milliseconds).
// Set to -1 for no timeout (blocking forever until data arrives).
func (ot *FerretBufferOT) SetTimeout(timeoutMs int64) {
ot.bufferIO.SetTimeout(timeoutMs)
}
// SetError sets an error state that will cause receive operations to fail.
// Useful for signaling that the connection has been closed.
func (ot *FerretBufferOT) SetError(message string) {
ot.bufferIO.SetError(message)
}
// Clear clears all buffers.
func (ot *FerretBufferOT) Clear() {
ot.bufferIO.Clear()
}
// Setup runs the OT setup protocol. Must be called after both parties have
// their BufferIO message transport active (can send/receive data).
// This is deferred from construction because BufferIO-based OT needs
// the message channel to be ready before setup can exchange data.
// Returns true on success, false on error.
func (ot *FerretBufferOT) Setup() bool {
return ot.ferretCOT.Setup()
}
// IsSetup returns true if the OT setup has been completed.
func (ot *FerretBufferOT) IsSetup() bool {
return ot.ferretCOT.IsSetup()
}
// StateSize returns the size in bytes needed to store the OT state.
func (ot *FerretBufferOT) StateSize() int64 {
return ot.ferretCOT.StateSize()
}
// AssembleState serializes the OT state for persistent storage.
// This allows storing setup data externally instead of in files.
// Returns nil if serialization fails.
func (ot *FerretBufferOT) AssembleState() []byte {
return ot.ferretCOT.AssembleState()
}
// DisassembleState restores the OT state from a buffer (created by AssembleState).
// This must be called INSTEAD of Setup, not after.
// Returns true on success.
func (ot *FerretBufferOT) DisassembleState(data []byte) bool {
return ot.ferretCOT.DisassembleState(data)
}
func (ot *FerretBufferOT) SendCOT() error {
if ot.party != ALICE {
return errors.New("incorrect party")
}
if !ot.ferretCOT.SendCot() {
return errors.New("send COT failed")
}
return nil
}
func (ot *FerretBufferOT) RecvCOT() error {
if ot.party != BOB {
return errors.New("incorrect party")
}
if !ot.ferretCOT.RecvCot() {
return errors.New("recv COT failed")
}
return nil
}
func (ot *FerretBufferOT) SendROT() error {
if !ot.ferretCOT.SendRot() {
return errors.New("send ROT failed")
}
return nil
}
func (ot *FerretBufferOT) RecvROT() error {
if !ot.ferretCOT.RecvRot() {
return errors.New("recv ROT failed")
}
return nil
}
func (ot *FerretBufferOT) SenderGetBlockData(choice bool, index uint64) []byte {
c := uint8(0)
if choice {
c = 1
}
return ot.ferretCOT.GetBlockData(c, index)
}
func (ot *FerretBufferOT) ReceiverGetBlockData(index uint64) []byte {
return ot.ferretCOT.GetBlockData(0, index)
}
func (ot *FerretBufferOT) Destroy() {
if ot.ferretCOT != nil {
ot.ferretCOT.Destroy()
}
if ot.bufferIO != nil {
ot.bufferIO.Destroy()
}
}