mirror of
https://github.com/luxfi/threshold.git
synced 2026-10-30 15:15:53 +00:00
164 lines
5.7 KiB
Go
164 lines
5.7 KiB
Go
package ot
|
|
|
|
import (
|
|
"github.com/luxfi/threshold/pkg/hash"
|
|
"github.com/luxfi/threshold/pkg/math/curve"
|
|
"github.com/luxfi/threshold/pkg/math/sample"
|
|
"github.com/zeebo/blake3"
|
|
)
|
|
|
|
// AdditiveOTSendRound1Message is the first message by the Sender in the Additive OT protocol.
|
|
type AdditiveOTSendRound1Message struct {
|
|
CombinedPads [][2][]byte
|
|
}
|
|
|
|
// AdditiveOTSendResult is the result of running the Additive OT protocol.
|
|
//
|
|
// The sender receives a collection of random pads.
|
|
type AdditiveOTSendResult [][2]curve.Scalar
|
|
|
|
// AdditiveOTSender holds the Sender's state for the Additive OT Protocol.
|
|
type AdditiveOTSender struct {
|
|
ctxHash *hash.Hash
|
|
group curve.Curve
|
|
// The setup used for the underlying correlated OT.
|
|
setup *CorreOTSendSetup
|
|
// The number of transfers to perform
|
|
batchSize int
|
|
// The constant adjust that will be conditionally added to the pads.
|
|
alpha [2]curve.Scalar
|
|
}
|
|
|
|
// NewAdditiveOTSender initializes the sender of an Additive OT.
|
|
//
|
|
// This follows Protocol 9 of https://eprint.iacr.org/2018/499 to a certain extent.
|
|
// The main difference is that we strictly conform to the underlying extended OT,
|
|
// removing Doerner's modifications to the check.
|
|
//
|
|
// The goal of this protocol is for the Sender to learn random pads, each pad being two scalars,
|
|
// and for the Receiver to receive choice_j * alpha_j - pad_j for each of the pads, and their choices.
|
|
//
|
|
// A single setup can be used for multiple protocol executions, but should be initialized with a nonce.
|
|
func NewAdditiveOTSender(ctxHash *hash.Hash, setup *CorreOTSendSetup, batchSize int, alpha [2]curve.Scalar) *AdditiveOTSender {
|
|
return &AdditiveOTSender{
|
|
ctxHash: ctxHash,
|
|
setup: setup,
|
|
batchSize: batchSize,
|
|
group: alpha[0].Curve(),
|
|
alpha: alpha,
|
|
}
|
|
}
|
|
|
|
func (r *AdditiveOTSender) Round1(msg *AdditiveOTReceiveRound1Message) (*AdditiveOTSendRound1Message, AdditiveOTSendResult, error) {
|
|
extendedResult, err := ExtendedOTSend(r.ctxHash, r.setup, r.batchSize, msg.Msg)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
prg := blake3.New()
|
|
outMsg := new(AdditiveOTSendRound1Message)
|
|
outMsg.CombinedPads = make([][2][]byte, r.batchSize)
|
|
result := make([][2]curve.Scalar, r.batchSize)
|
|
var combinedPads [2]curve.Scalar
|
|
for i := 0; i < r.batchSize; i++ {
|
|
prg.Reset()
|
|
_, _ = prg.Write(extendedResult._V0[i][:])
|
|
digest := prg.Digest()
|
|
result[i][0] = sample.Scalar(digest, r.group)
|
|
result[i][1] = sample.Scalar(digest, r.group)
|
|
|
|
prg.Reset()
|
|
_, _ = prg.Write(extendedResult._V1[i][:])
|
|
digest = prg.Digest()
|
|
combinedPads[0] = sample.Scalar(digest, r.group)
|
|
combinedPads[1] = sample.Scalar(digest, r.group)
|
|
|
|
combinedPads[0].Sub(result[i][0]).Add(r.alpha[0])
|
|
combinedPads[1].Sub(result[i][1]).Add(r.alpha[1])
|
|
|
|
var err error
|
|
outMsg.CombinedPads[i][0], err = combinedPads[0].MarshalBinary()
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
outMsg.CombinedPads[i][1], err = combinedPads[1].MarshalBinary()
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
}
|
|
return outMsg, result, nil
|
|
}
|
|
|
|
// AdditiveOTReceiver holds the Receiver's state for the Additive OT Protocol.
|
|
type AdditiveOTReceiver struct {
|
|
// After setup
|
|
ctxHash *hash.Hash
|
|
group curve.Curve
|
|
setup *CorreOTReceiveSetup
|
|
choices []byte
|
|
// After round 1
|
|
result *ExtendedOTReceiveResult
|
|
}
|
|
|
|
// NewAdditiveOTReceiver initializes the receiver of an Additive OT.
|
|
//
|
|
// This follows Protocol 9 of https://eprint.iacr.org/2018/499 to a certain extent.
|
|
// The main difference is that we strictly conform to the underlying extended OT,
|
|
// removing Doerner's modifications to the check.
|
|
//
|
|
// The goal of this protocol is for the Sender to learn random pads, each pad being two scalars,
|
|
// and for the Receiver to receive choice_j * alpha_j - pad_j for each of the pads, and their choices.
|
|
//
|
|
// A single setup can be used for multiple protocol executions, but should be initialized with a nonce.
|
|
func NewAdditiveOTReceiver(ctxHash *hash.Hash, setup *CorreOTReceiveSetup, group curve.Curve, choices []byte) *AdditiveOTReceiver {
|
|
return &AdditiveOTReceiver{ctxHash: ctxHash, setup: setup, group: group, choices: choices}
|
|
}
|
|
|
|
// AdditiveOTReceiveRound1Message is the first message sent by the Receiver in an Additive OT.
|
|
type AdditiveOTReceiveRound1Message struct {
|
|
Msg *ExtendedOTReceiveMessage
|
|
}
|
|
|
|
// Round1 executes the Receiver's first round of an Additive OT.
|
|
func (r *AdditiveOTReceiver) Round1() *AdditiveOTReceiveRound1Message {
|
|
msg, result := ExtendedOTReceive(r.ctxHash, r.setup, r.choices)
|
|
r.result = result
|
|
return &AdditiveOTReceiveRound1Message{Msg: msg}
|
|
}
|
|
|
|
// AdditiveOTReceiveResult is the Receiver's result for an Additive OT.
|
|
//
|
|
// For each choice_j, we receive choice_j * alpha - pad.
|
|
type AdditiveOTReceiveResult [][2]curve.Scalar
|
|
|
|
// Round2 executes the Receiver's second round of an Additive OT.
|
|
func (r *AdditiveOTReceiver) Round2(msg *AdditiveOTSendRound1Message) (AdditiveOTReceiveResult, error) {
|
|
batchSize := 8 * len(r.choices)
|
|
result := make([][2]curve.Scalar, batchSize)
|
|
prg := blake3.New()
|
|
for i := 0; i < batchSize; i++ {
|
|
mask := -bitAt(i, r.choices)
|
|
prg.Reset()
|
|
_, _ = prg.Write(r.result._VChoices[i][:])
|
|
digest := prg.Digest()
|
|
result[i][0] = sample.Scalar(digest, r.group).Negate()
|
|
result[i][1] = sample.Scalar(digest, r.group).Negate()
|
|
for j := 0; j < len(msg.CombinedPads[j][0]); j++ {
|
|
msg.CombinedPads[i][0][j] &= mask
|
|
}
|
|
for j := 0; j < len(msg.CombinedPads[j][1]); j++ {
|
|
msg.CombinedPads[i][1][j] &= mask
|
|
}
|
|
combinedPad0 := r.group.NewScalar()
|
|
if err := combinedPad0.UnmarshalBinary(msg.CombinedPads[i][0]); err != nil {
|
|
return nil, err
|
|
}
|
|
combinedPad1 := r.group.NewScalar()
|
|
if err := combinedPad1.UnmarshalBinary(msg.CombinedPads[i][1]); err != nil {
|
|
return nil, err
|
|
}
|
|
result[i][0].Add(combinedPad0)
|
|
result[i][1].Add(combinedPad1)
|
|
}
|
|
return result, nil
|
|
}
|