mirror of
				https://source.quilibrium.com/quilibrium/ceremonyclient.git
				synced 2025-11-04 00:27:41 +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)
 | 
						|
}
 |