mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-11-11 02:35:18 +00:00
173 lines
6.6 KiB
Go
173 lines
6.6 KiB
Go
|
//
|
||
|
// Copyright Coinbase, Inc. All Rights Reserved.
|
||
|
//
|
||
|
// SPDX-License-Identifier: Apache-2.0
|
||
|
//
|
||
|
|
||
|
package v0
|
||
|
|
||
|
import (
|
||
|
"crypto/rand"
|
||
|
"crypto/subtle"
|
||
|
"io"
|
||
|
"math/big"
|
||
|
|
||
|
"source.quilibrium.com/quilibrium/monorepo/nekryptology/internal"
|
||
|
)
|
||
|
|
||
|
// this implements the _coalesced_ multiplication, in which Alice and Bob perform 2 "parallel" multiplication protocols
|
||
|
// they wind up with additive sharings of the respective two products.
|
||
|
|
||
|
type MultiplySender struct {
|
||
|
sender *cOTSender
|
||
|
TA []*big.Int
|
||
|
|
||
|
multiplicity int
|
||
|
}
|
||
|
|
||
|
type MultiplyReceiver struct {
|
||
|
receiver *cOTReceiver
|
||
|
TB []*big.Int
|
||
|
|
||
|
omega []byte // stashing this here, though ironically the cOT doesn't need to stash it.
|
||
|
multiplicity int
|
||
|
}
|
||
|
|
||
|
func NewMultiplySender(multiplicity int, receiver *seedOTReceiver) *MultiplySender {
|
||
|
sender := newCOTSender(multiplicity, receiver)
|
||
|
return &MultiplySender{
|
||
|
sender: sender,
|
||
|
TA: make([]*big.Int, multiplicity),
|
||
|
multiplicity: multiplicity,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func NewMultiplyReceiver(multiplicity int, sender *seedOTSender) *MultiplyReceiver {
|
||
|
receiver := newCOTReceiver(multiplicity, sender)
|
||
|
return &MultiplyReceiver{
|
||
|
receiver: receiver,
|
||
|
TB: make([]*big.Int, multiplicity),
|
||
|
multiplicity: multiplicity,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Algorithm 5. in DKLs. this "encodes" Bob's secret input scalars `beta` in the right way, using the opts.
|
||
|
// the idea is that if Bob were to just put beta's as the choice vector, then Alice could learn a few of Bob's bits.
|
||
|
// using selective failure attacks. so you subtract random components of a public random vector. see paper for details.
|
||
|
// note that we're using the optimization now where both multiplications get "coalesced".
|
||
|
func (receiver *MultiplyReceiver) encode(beta []*big.Int) ([]byte, error) {
|
||
|
// passing beta by value, so that we can mutate it locally. check that this does what i want.
|
||
|
bytes := make([][]byte, receiver.multiplicity)
|
||
|
params := receiver.receiver.sender.params
|
||
|
result := make([]byte, receiver.receiver.l>>3)
|
||
|
for i := 0; i < receiver.multiplicity; i++ {
|
||
|
bytes[i] = params.Scalar.Bytes(beta[i])
|
||
|
if _, err := rand.Read(result[(1+i*2)*kappa>>3 : (2+i*2)*kappa>>3]); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
}
|
||
|
if _, err := rand.Read(result[2*receiver.multiplicity*kappa>>3 : (2*receiver.multiplicity*kappa+s)>>3]); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
for i := 0; i < receiver.multiplicity; i++ {
|
||
|
for j := 0; j < kappa; j++ {
|
||
|
bit := int(result[((1+2*i)*kappa+j)>>3]) >> (j & 0x07) & 0x01
|
||
|
mask := params.Scalar.Bytes(params.Scalar.Sub(new(big.Int).SetBytes(bytes[i][:]), params.gadget[kappa+j]))
|
||
|
subtle.ConstantTimeCopy(bit, bytes[i][:], mask)
|
||
|
}
|
||
|
// some converting from bytes and back. a bit cumbersome, but in practice this will be negligible
|
||
|
// it'd be simpler to just keep running big ints, which we are subtracting from.
|
||
|
// but we can only `ConstantTimeCopy` byte slices (as opposed to big ints). so keep them as bytes.
|
||
|
for j := 0; j < 2*s; j++ {
|
||
|
bit := int(result[(2*receiver.multiplicity*kappa+j)>>3]) >> (j & 0x07) & 0x01
|
||
|
mask := params.Scalar.Bytes(params.Scalar.Sub(new(big.Int).SetBytes(bytes[i][:]), params.gadget[2*kappa+j]))
|
||
|
subtle.ConstantTimeCopy(bit, bytes[i][:], mask)
|
||
|
}
|
||
|
copy(result[2*i*kappa>>3:(2*i+1)*kappa>>3], internal.ReverseScalarBytes(bytes[i][:]))
|
||
|
}
|
||
|
return result, nil
|
||
|
}
|
||
|
|
||
|
// MultiplyInit Protocol 5., Multiplication, 3). Bob (receiver) encodes beta and initiates the cOT extension!
|
||
|
func (receiver *MultiplyReceiver) MultiplyInit(idExt [32]byte, beta []*big.Int, w io.Writer) error {
|
||
|
var err error
|
||
|
if receiver.omega, err = receiver.encode(beta); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return receiver.receiver.init(idExt, receiver.omega, w)
|
||
|
}
|
||
|
|
||
|
// Multiply Protocol 5., steps 3) 5), 7). Alice _responds_ to Bob's initial cOT message, using a vector of alphas as input.
|
||
|
// doesn't actually send that message yet, only stashes it, and moves onto the next steps of the multiplication protocol
|
||
|
// specifically, Alice can then do step 5) (compute the outputs of the multiplication protocol), also stashes this.
|
||
|
// finishes up by taking care of 7), after that, Alice is totally done with multiplication and has stashed the outputs.
|
||
|
func (sender *MultiplySender) Multiply(idExt [32]byte, alpha []*big.Int, rw io.ReadWriter) error {
|
||
|
inputMain := make([]*big.Int, 2*sender.multiplicity*kappa)
|
||
|
inputOT := [2 * s][]*big.Int{} // inputOT := [2 * s][2 * sender.multiplicity]*big.Int{}
|
||
|
for i := range inputOT {
|
||
|
inputOT[i] = make([]*big.Int, sender.multiplicity)
|
||
|
}
|
||
|
var err error
|
||
|
params := sender.sender.receiver.params
|
||
|
for i := 0; i < sender.multiplicity; i++ {
|
||
|
for j := 0; j < 2*kappa; j++ {
|
||
|
inputMain[kappa*2*i+j] = params.Scalar.Mul(params.gadget[j], alpha[i])
|
||
|
}
|
||
|
for j := 0; j < 2*s; j++ {
|
||
|
inputOT[j][i] = params.Scalar.Mul(params.gadget[j+2*kappa], alpha[i])
|
||
|
}
|
||
|
}
|
||
|
if err = sender.sender.transfer(idExt, inputMain, inputOT, rw); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
scalar := sender.sender.receiver.params.Scalar // stash this just to shorten the expressions
|
||
|
for i := 0; i < sender.multiplicity; i++ {
|
||
|
sender.TA[i] = new(big.Int)
|
||
|
for j := 0; j < 2*kappa; j++ {
|
||
|
sender.TA[i] = scalar.Add(sender.TA[i], sender.sender.tA[2*kappa*i+j])
|
||
|
}
|
||
|
}
|
||
|
for i := 0; i < 2*s; i++ {
|
||
|
for j := 0; j < sender.multiplicity; j++ {
|
||
|
sender.TA[j] = scalar.Add(sender.TA[j], sender.sender.tAOT[i][j])
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// MultiplyTransfer Protocol 5., Multiplication, 3) and 6). Bob finalizes the cOT extension.
|
||
|
// using that and Alice's multiplication message, Bob completes the multiplication protocol, including checks.
|
||
|
// at the end, Bob's values tB_j are populated.
|
||
|
func (receiver *MultiplyReceiver) MultiplyTransfer(r io.Reader) error {
|
||
|
if err := receiver.receiver.transfer(r); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
scalar := receiver.receiver.sender.params.Scalar
|
||
|
for i := 0; i < receiver.multiplicity; i++ {
|
||
|
receiver.TB[i] = new(big.Int)
|
||
|
for j := 0; j < 2*kappa; j++ {
|
||
|
receiver.TB[i] = scalar.Add(receiver.TB[i], receiver.receiver.tB[2*kappa*i+j])
|
||
|
}
|
||
|
}
|
||
|
for i := 0; i < 2*s; i++ {
|
||
|
for j := 0; j < receiver.multiplicity; j++ {
|
||
|
receiver.TB[j] = scalar.Add(receiver.TB[j], receiver.receiver.tBOT[i][j])
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// illustrative helper method which goes through the whole flow for Bob, assuming a channel to pass messages through.
|
||
|
func (receiver *MultiplyReceiver) multiply(idExt [32]byte, beta []*big.Int, rw io.ReadWriter) error {
|
||
|
if err := receiver.MultiplyInit(idExt, beta, rw); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return receiver.MultiplyTransfer(rw)
|
||
|
}
|
||
|
|
||
|
// illustrative helper method which goes through the whole flow for Alice, assuming a channel.
|
||
|
func (sender *MultiplySender) multiply(idExt [32]byte, alpha []*big.Int, rw io.ReadWriter) error {
|
||
|
return sender.Multiply(idExt, alpha, rw)
|
||
|
}
|