ceremonyclient/bedlam/circuit/garbler.go
Cassandra Heart dbd95bd9e9
v2.1.0 (#439)
* v2.1.0 [omit consensus and adjacent] - this commit will be amended with the full release after the file copy is complete

* 2.1.0 main node rollup
2025-09-30 02:48:15 -05:00

190 lines
4.0 KiB
Go

//
// garbler.go
//
// Copyright (c) 2019-2023 Markku Rossi
//
// All rights reserved.
//
package circuit
import (
"crypto/rand"
"fmt"
"math/big"
"source.quilibrium.com/quilibrium/monorepo/bedlam/ot"
"source.quilibrium.com/quilibrium/monorepo/bedlam/p2p"
)
// FileSize specifies a file (or data transfer) size in bytes.
type FileSize uint64
func (s FileSize) String() string {
if s > 1000*1000*1000*1000 {
return fmt.Sprintf("%dTB", s/(1000*1000*1000*1000))
} else if s > 1000*1000*1000 {
return fmt.Sprintf("%dGB", s/(1000*1000*1000))
} else if s > 1000*1000 {
return fmt.Sprintf("%dMB", s/(1000*1000))
} else if s > 1000 {
return fmt.Sprintf("%dkB", s/1000)
} else {
return fmt.Sprintf("%dB", s)
}
}
// Garbler runs the garbler on the P2P network.
func Garbler(conn *p2p.Conn, oti ot.OT, circ *Circuit, inputs *big.Int,
verbose bool) ([]*big.Int, error) {
timing := NewTiming()
if verbose {
fmt.Printf(" - Garbling...\n")
}
var key [32]byte
_, err := rand.Read(key[:])
if err != nil {
return nil, err
}
garbled, err := circ.Garble(key[:])
if err != nil {
return nil, err
}
timing.Sample("Garble", nil)
// Send program info.
if verbose {
fmt.Printf(" - Sending garbled circuit...\n")
}
if err := conn.SendData(key[:]); err != nil {
return nil, err
}
// Send garbled tables.
if err := conn.SendUint32(len(garbled.Gates)); err != nil {
return nil, err
}
var labelData ot.LabelData
for _, data := range garbled.Gates {
if err := conn.SendUint32(len(data)); err != nil {
return nil, err
}
for _, d := range data {
if err := conn.SendLabel(d, &labelData); err != nil {
return nil, err
}
}
}
if err := conn.Flush(); err != nil {
return nil, err
}
// Select our inputs.
var n1 []ot.Label
for i := 0; i < int(circ.Inputs[0].Type.Bits); i++ {
wire := garbled.Wires[i]
var n ot.Label
if inputs.Bit(i) == 1 {
n = wire.L1
} else {
n = wire.L0
}
n1 = append(n1, n)
}
// Send our inputs.
for idx, i := range n1 {
if verbose && false {
fmt.Printf("N1[%d]:\t%s\n", idx, i)
}
if err := conn.SendLabel(i, &labelData); err != nil {
return nil, err
}
}
ioStats := conn.Stats.Sum()
timing.Sample("Xfer", []string{FileSize(ioStats).String()})
if verbose {
fmt.Printf(" - Processing messages...\n")
}
if err := conn.Flush(); err != nil {
return nil, err
}
// Init oblivious transfer.
err = oti.InitSender(conn)
if err != nil {
return nil, err
}
xfer := conn.Stats.Sum() - ioStats
ioStats = conn.Stats.Sum()
timing.Sample("OT Init", []string{FileSize(xfer).String()})
// Peer OTs its inputs.
offset, err := conn.ReceiveUint32()
if err != nil {
return nil, err
}
count, err := conn.ReceiveUint32()
if err != nil {
return nil, err
}
if offset != int(circ.Inputs[0].Type.Bits) ||
count != int(circ.Inputs[1].Type.Bits) {
return nil, fmt.Errorf("peer can't OT wires [%d...%d[",
offset, offset+count)
}
err = oti.Send(garbled.Wires[offset : offset+count])
if err != nil {
return nil, err
}
xfer = conn.Stats.Sum() - ioStats
ioStats = conn.Stats.Sum()
timing.Sample("OT", []string{FileSize(xfer).String()})
// Resolve result values.
result := big.NewInt(0)
var label ot.Label
for i := 0; i < circ.Outputs.Size(); i++ {
err := conn.ReceiveLabel(&label, &labelData)
if err != nil {
return nil, err
}
if i == 0 {
timing.Sample("Eval", nil)
}
wire := garbled.Wires[circ.NumWires-circ.Outputs.Size()+i]
var bit uint
if label.Equal(wire.L0) {
bit = 0
} else if label.Equal(wire.L1) {
bit = 1
} else {
return nil, fmt.Errorf("unknown label %s for result %d", label, i)
}
result = big.NewInt(0).SetBit(result, i, bit)
}
data := result.Bytes()
if err := conn.SendData(data); err != nil {
return nil, err
}
if err := conn.Flush(); err != nil {
return nil, err
}
xfer = conn.Stats.Sum() - ioStats
timing.Sample("Result", []string{FileSize(xfer).String()})
if verbose {
timing.Print(conn.Stats)
}
return circ.Outputs.Split(result), nil
}