mirror of
				https://source.quilibrium.com/quilibrium/ceremonyclient.git
				synced 2025-11-04 00:27:41 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			535 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			535 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
//
 | 
						|
// Copyright Coinbase, Inc. All Rights Reserved.
 | 
						|
//
 | 
						|
// SPDX-License-Identifier: Apache-2.0
 | 
						|
//
 | 
						|
 | 
						|
package v0
 | 
						|
 | 
						|
import (
 | 
						|
	"crypto/rand"
 | 
						|
	"crypto/sha256"
 | 
						|
	"crypto/subtle"
 | 
						|
	"encoding/gob"
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"math/big"
 | 
						|
 | 
						|
	"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core"
 | 
						|
	"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
 | 
						|
)
 | 
						|
 | 
						|
type (
 | 
						|
	seedOtVerification = [kappa][32]byte
 | 
						|
	seedOtFinal        = [kappa][2][32]byte
 | 
						|
	seedOtTransfer     = [kappa]*curves.EcPoint
 | 
						|
)
 | 
						|
 | 
						|
// seedOTSender stores state for the "sender" role in seed OT. see Protocol 7 in Appendix A of DKLs
 | 
						|
type seedOTSender struct {
 | 
						|
	// Exported fields are marshaled
 | 
						|
	Rho seedOtFinal // this will store the (vectorized) outputs of kappa executions of (random) seed OT.
 | 
						|
 | 
						|
	// Intermediate values that should not be marshaled
 | 
						|
	params *Params
 | 
						|
	b      *big.Int        // discrete log of B, which will be (re)used in _all_ executions of the seed OT.
 | 
						|
	pub    *curves.EcPoint // the public key of b.
 | 
						|
}
 | 
						|
 | 
						|
// seedOTReceiver stores state for the "receiver" role in seed OT. Protocol 7, Appendix A, of DKLs.
 | 
						|
type seedOTReceiver struct {
 | 
						|
	// Exported fields are marshaled
 | 
						|
	Packed [kappa >> 3]byte   // a packed version of the above vector; used later during cOT for performance reasons
 | 
						|
	Rho    seedOtVerification // output of seed OT. for the receiver, there is just 1 output per execution
 | 
						|
 | 
						|
	// Unexported fields don't get marshaled
 | 
						|
	params *Params
 | 
						|
	choice []int              // choice vector represented as compact binary array. Initialed from Packed
 | 
						|
	pub    *curves.EcPoint    // i guess this is "B".
 | 
						|
	xi     seedOtVerification // basically this just has to be kept between rounds for checking purposes, but won't be used outside
 | 
						|
}
 | 
						|
 | 
						|
func (sender *seedOTSender) pubKey(w io.Writer) error {
 | 
						|
	// returns pub, as well as the schnorr proof. serialized / packed.
 | 
						|
	// since the return type here is exactly the same as DKG datatype, i am going to cheat and reuse that one.
 | 
						|
	enc := gob.NewEncoder(w)
 | 
						|
	var err error // https://github.com/golang/go/issues/6842
 | 
						|
	if sender.b, err = sender.params.Scalar.Random(); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if sender.pub, err = curves.NewScalarBaseMult(sender.params.Curve, sender.b); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	proof := &Schnorr{params: sender.params, Pub: sender.pub}
 | 
						|
	if err = proof.Prove(sender.b); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if err = enc.Encode(proof); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if sender.pub.Y, err = core.Neg(sender.pub.Y, sender.params.Curve.Params().P); err != nil { // using Weierstrass
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	// ^^^ this is basically a trick, we will only "use" B (i.e., pub) from this point forward by subtracting it from A
 | 
						|
	// so just do the negation once and then we can just "add" B from this point forward.
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
func (receiver *seedOTReceiver) pubKey(r io.Reader) error {
 | 
						|
	dec := gob.NewDecoder(r)
 | 
						|
	var err error
 | 
						|
	input := &Schnorr{params: receiver.params}
 | 
						|
	if err = dec.Decode(input); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	receiver.pub = input.Pub
 | 
						|
	if err = input.Verify(); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// Initializes the choice array from the Packed array
 | 
						|
func (receiver *seedOTReceiver) initChoice() {
 | 
						|
	// unpack the random values in Packed into bits in Choice
 | 
						|
	receiver.choice = make([]int, kappa)
 | 
						|
	for i := 0; i < len(receiver.choice); i++ {
 | 
						|
		receiver.choice[i] = int(receiver.Packed[i>>3] >> (i & 0x07) & 0x01)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// padTransfer this is the receiver's "Pad Transfer" phase in seed OT; see p. 16 of https://eprint.iacr.org/2018/499.pdf.
 | 
						|
// note that we "vectorize" this kappa times; all kappa executions are blocked in this function.
 | 
						|
// any error returned by this function will come from "below", as opposed to from this function.
 | 
						|
func (receiver *seedOTReceiver) padTransfer(w io.Writer) error {
 | 
						|
	enc := gob.NewEncoder(w)
 | 
						|
	// fill the seed OT choice vector with random bytes.
 | 
						|
	if _, err := rand.Read(receiver.Packed[:]); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	// And unpack into Choice bits
 | 
						|
	receiver.initChoice()
 | 
						|
 | 
						|
	result := &[kappa]*curves.EcPoint{}
 | 
						|
	for i := 0; i < kappa; i++ {
 | 
						|
		a, err := receiver.params.Scalar.Random()
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		if result[i], err = curves.NewScalarBaseMult(receiver.params.Curve, a); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		temp := result[i].Bytes()
 | 
						|
		if result[i], err = result[i].Add(receiver.pub); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		mask := result[i].Bytes()
 | 
						|
		subtle.ConstantTimeCopy(receiver.choice[i], temp, mask)
 | 
						|
		if result[i], err = curves.PointFromBytesUncompressed(receiver.params.Curve, temp); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		rho, err := receiver.pub.ScalarMult(a)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		receiver.Rho[i] = sha256.Sum256(append(rho.Bytes(), byte(i))) // check whether this cuts it as a "nonce"
 | 
						|
	}
 | 
						|
	return enc.Encode(result)
 | 
						|
}
 | 
						|
 | 
						|
func (sender *seedOTSender) padTransfer(rw io.ReadWriter) error {
 | 
						|
	enc := gob.NewEncoder(rw)
 | 
						|
	dec := gob.NewDecoder(rw)
 | 
						|
	// returns the challenges xi, concated into a block.
 | 
						|
	input := &seedOtTransfer{}
 | 
						|
	if err := dec.Decode(input); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	result := &seedOtVerification{}
 | 
						|
 | 
						|
	for i := 0; i < kappa; i++ {
 | 
						|
		d, err := input[i].ScalarMult(sender.b)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		sender.Rho[i][0] = sha256.Sum256(append(d.Bytes(), byte(i)))
 | 
						|
		if input[i], err = input[i].Add(sender.pub); err != nil {
 | 
						|
			return err
 | 
						|
		} // caution: overwrite
 | 
						|
		d, err = input[i].ScalarMult(sender.b)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		sender.Rho[i][1] = sha256.Sum256(append(d.Bytes(), byte(i)))
 | 
						|
		temp0 := sha256.Sum256(sender.Rho[i][0][:])
 | 
						|
		temp0 = sha256.Sum256(temp0[:])
 | 
						|
		temp1 := sha256.Sum256(sender.Rho[i][1][:])
 | 
						|
		temp1 = sha256.Sum256(temp1[:])
 | 
						|
		for j := 0; j < 32; j++ {
 | 
						|
			result[i][j] = temp0[j] ^ temp1[j]
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return enc.Encode(result)
 | 
						|
}
 | 
						|
 | 
						|
// verification corresponds to initial round of the receiver's "Verification" phase, see p. 16. cf. also "final" below.
 | 
						|
// this is just the start of verification—in this round, the receiver outputs "rho'", which the sender will check.
 | 
						|
func (receiver *seedOTReceiver) verification(rw io.ReadWriter) error {
 | 
						|
	enc := gob.NewEncoder(rw)
 | 
						|
	dec := gob.NewDecoder(rw)
 | 
						|
	if err := dec.Decode(&receiver.xi); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	result := &seedOtVerification{}
 | 
						|
	for i := 0; i < kappa; i++ {
 | 
						|
		temp0 := sha256.Sum256(receiver.Rho[i][:])
 | 
						|
		temp0 = sha256.Sum256(temp0[:])
 | 
						|
		temp1 := [32]byte{}
 | 
						|
		for j := 0; j < 32; j++ {
 | 
						|
			temp1[j] = receiver.xi[i][j] ^ temp0[j]
 | 
						|
		}
 | 
						|
		subtle.ConstantTimeCopy(receiver.choice[i], temp0[:], temp1[:])
 | 
						|
		copy(result[i][:], temp0[:])
 | 
						|
	}
 | 
						|
	return enc.Encode(result) // this is "rho'", all in a block.
 | 
						|
}
 | 
						|
 | 
						|
func (sender *seedOTSender) verification(rw io.ReadWriter) error {
 | 
						|
	// message is rho'. returns H(rho^0) || H(rho^1)
 | 
						|
	enc := gob.NewEncoder(rw)
 | 
						|
	dec := gob.NewDecoder(rw)
 | 
						|
	input := &seedOtVerification{}
 | 
						|
	if err := dec.Decode(&input); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	result := &seedOtFinal{}
 | 
						|
	for i := 0; i < kappa; i++ {
 | 
						|
		temp0 := sha256.Sum256(sender.Rho[i][0][:])
 | 
						|
		temp1 := sha256.Sum256(temp0[:])
 | 
						|
		if subtle.ConstantTimeCompare(temp1[:], input[i][:]) != 1 {
 | 
						|
			return fmt.Errorf("receiver's challenge response didn't match H(H(rho^0))")
 | 
						|
		}
 | 
						|
		temp2 := sha256.Sum256(sender.Rho[i][1][:])
 | 
						|
		copy(result[i][0][:], temp0[:])
 | 
						|
		copy(result[i][1][:], temp2[:])
 | 
						|
	}
 | 
						|
	return enc.Encode(result)
 | 
						|
}
 | 
						|
 | 
						|
// final this is the _last_ part of the "Verification" phase of seed OT; see p. 16 of https://eprint.iacr.org/2018/499.pdf.
 | 
						|
// message is (supposedly) the concatenation of all kappa `H(rho^0) || H(rho^1)`s; we will check them ourselves.
 | 
						|
func (receiver *seedOTReceiver) final(r io.Reader) error {
 | 
						|
	dec := gob.NewDecoder(r)
 | 
						|
	input := &seedOtFinal{}
 | 
						|
	if err := dec.Decode(&input); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	for i := 0; i < kappa; i++ {
 | 
						|
		temp0 := sha256.Sum256(receiver.Rho[i][:])
 | 
						|
		temp1 := [32]byte{}
 | 
						|
		subtle.ConstantTimeCopy(1-receiver.choice[i], temp1[:], input[i][0][:])
 | 
						|
		subtle.ConstantTimeCopy(receiver.choice[i], temp1[:], input[i][1][:])
 | 
						|
		if subtle.ConstantTimeCompare(temp0[:], temp1[:]) != 1 {
 | 
						|
			return fmt.Errorf("sender's supposed H(rho^omega) doesn't match our own")
 | 
						|
		}
 | 
						|
		temp0 = sha256.Sum256(input[i][0][:])
 | 
						|
		temp1 = sha256.Sum256(input[i][1][:])
 | 
						|
		for j := 0; j < 32; j++ {
 | 
						|
			temp0[j] ^= temp1[j]
 | 
						|
		}
 | 
						|
		if subtle.ConstantTimeCompare(temp0[:], receiver.xi[i][:]) != 1 {
 | 
						|
			return fmt.Errorf("sender's openings H(rho^0) and H(rho^1) didn't decommit to its prior message xi")
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (receiver *seedOTReceiver) kosSetup(rw io.ReadWriter) error {
 | 
						|
	// this is an illustrative high-level helper method which goes through the full flow of the KOS seed OT protocol.
 | 
						|
	// all it does it call all the right stages in the right order, and send and receive the messages to the other party
 | 
						|
	if err := receiver.pubKey(rw); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if err := receiver.padTransfer(rw); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if err := receiver.verification(rw); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	return receiver.final(rw)
 | 
						|
}
 | 
						|
 | 
						|
func (sender *seedOTSender) kosSetup(rw io.ReadWriter) error {
 | 
						|
	// again a high-level helper method showing the overall flow, this time for the sender.
 | 
						|
	if err := sender.pubKey(rw); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if err := sender.padTransfer(rw); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	return sender.verification(rw)
 | 
						|
}
 | 
						|
 | 
						|
type cOTReceiver struct {
 | 
						|
	sender       *seedOTSender      // kinda-sorta reversed?!?
 | 
						|
	w            []byte             // storage for choice vector || gamma^{ext}, packed.
 | 
						|
	psi          [][kappa >> 3]byte // transpose of v^0. gets retained between messages
 | 
						|
	tB           []*big.Int         // [2 * Multiplicity]*big.Int
 | 
						|
	tBOT         [2 * s][]*big.Int  // [2 * s][Multiplicity]*big.Int
 | 
						|
	l            int
 | 
						|
	lPrime       int
 | 
						|
	multiplicity int
 | 
						|
}
 | 
						|
 | 
						|
type cOTSender struct {
 | 
						|
	receiver     *seedOTReceiver   // kinda-sorta reversed?!?
 | 
						|
	tA           []*big.Int        // ultimate output received. basically just the "pads"
 | 
						|
	tAOT         [2 * s][]*big.Int // [2 * s][Multiplicity]*big.Int
 | 
						|
	l            int
 | 
						|
	lPrime       int
 | 
						|
	multiplicity int
 | 
						|
}
 | 
						|
 | 
						|
func newCOTReceiver(multiplicity int, sender *seedOTSender) *cOTReceiver {
 | 
						|
	l := 2*multiplicity*kappa + 2*s
 | 
						|
	lPrime := l + kappaOT
 | 
						|
	var tBOT [2 * s][]*big.Int
 | 
						|
	for i := 0; i < 2*s; i++ {
 | 
						|
		tBOT[i] = make([]*big.Int, multiplicity)
 | 
						|
	}
 | 
						|
	return &cOTReceiver{
 | 
						|
		sender:       sender,
 | 
						|
		w:            make([]byte, lPrime>>3),
 | 
						|
		psi:          make([][kappa >> 3]byte, lPrime),
 | 
						|
		tB:           make([]*big.Int, 2*kappa*multiplicity),
 | 
						|
		tBOT:         tBOT,
 | 
						|
		l:            l,
 | 
						|
		lPrime:       lPrime,
 | 
						|
		multiplicity: multiplicity,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func newCOTSender(multiplicity int, receiver *seedOTReceiver) *cOTSender {
 | 
						|
	l := 2*multiplicity*kappa + 2*s
 | 
						|
	lPrime := l + kappaOT
 | 
						|
	var tAOT [2 * s][]*big.Int
 | 
						|
	for i := 0; i < 2*s; i++ {
 | 
						|
		tAOT[i] = make([]*big.Int, multiplicity)
 | 
						|
	}
 | 
						|
	return &cOTSender{
 | 
						|
		receiver:     receiver,
 | 
						|
		tA:           make([]*big.Int, 2*kappa*multiplicity),
 | 
						|
		tAOT:         tAOT,
 | 
						|
		l:            l,
 | 
						|
		lPrime:       lPrime,
 | 
						|
		multiplicity: multiplicity,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type cOTInitStorage struct {
 | 
						|
	WPrime [32]byte
 | 
						|
	VPrime [32]byte
 | 
						|
	U      [kappa][]byte
 | 
						|
}
 | 
						|
 | 
						|
type cOTStorage struct {
 | 
						|
	TauMain []*big.Int
 | 
						|
	TauOT   [2 * s][]*big.Int
 | 
						|
}
 | 
						|
 | 
						|
func (receiver *cOTReceiver) init(idExt [32]byte, choice []byte, w io.Writer) error {
 | 
						|
	// input choice vector is "packed".
 | 
						|
	copy(receiver.w[0:receiver.l>>3], choice[:])                     // write the input choice vector into our local data.
 | 
						|
	if _, err := rand.Read(receiver.w[receiver.l>>3:]); err != nil { // fill the rest with random bytes; this is "gamma^{ext}"
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	hash := sha256.New()    // basically this will contain a hash of the matrix U.
 | 
						|
	v := [2][kappa][]byte{} // kappa * l array of _bits_, in "dense" form. contains _both_ v_0 and v_1.
 | 
						|
	for i := 0; i < 2; i++ {
 | 
						|
		for j := 0; j < kappa; j++ {
 | 
						|
			v[i][j] = make([]byte, receiver.lPrime>>3) // annoying
 | 
						|
		}
 | 
						|
	}
 | 
						|
	result := &cOTInitStorage{}
 | 
						|
	enc := gob.NewEncoder(w)
 | 
						|
	for i := 0; i < kappa; i++ {
 | 
						|
		result.U[i] = make([]byte, receiver.lPrime>>3)
 | 
						|
	}
 | 
						|
	hash.Reset()
 | 
						|
	for i := 0; i < kappa; i++ {
 | 
						|
		for j := 0; j < 2; j++ {
 | 
						|
			row, err := core.ExpandMessageXmd(sha256.New, receiver.sender.Rho[i][j][:], idExt[:], receiver.lPrime>>3)
 | 
						|
			if err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
			// this is the core pseudorandom expansion of the secret OT input seeds s_i^0 and s_i^1
 | 
						|
			// see Extension, 2), in Protocol 9, page 17 of DKLs https://eprint.iacr.org/2018/499.pdf
 | 
						|
			// use the idExt as the "domain separator", and the _secret_ seed rho as the input!
 | 
						|
			copy(v[j][i][:], row) // could easily use a shake3 and "Read" it directly in.
 | 
						|
		}
 | 
						|
		for j := 0; j < receiver.lPrime>>3; j++ {
 | 
						|
			result.U[i][j] = v[0][i][j] ^ v[1][i][j] ^ receiver.w[j]
 | 
						|
			// U := v_i^0 ^ v_i^1 ^ w. note: in step 4) of Prot. 9, i think `w` should be bolded?
 | 
						|
			for k := 0; k < 8; k++ {
 | 
						|
				receiver.psi[j<<3+k][i>>3] |= v[0][i][j] >> k & 0x01 << (i & 0x07)
 | 
						|
				// this is fairly tricky. basically, this is assigning psi to be the transpose of the boolean matrix v_0.
 | 
						|
				// but because both matrices are densely packed (represented as bytes), we have to do some bitwise tricks.
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if _, err := hash.Write(result.U[i][:]); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	digest := hash.Sum(nil) // go ahead and record this, so that we only have to hash the big matrix U once.
 | 
						|
	for j := 0; j < receiver.lPrime; j++ {
 | 
						|
		chiJ := sha256.Sum256(append(digest, byte(j&0x07), byte(j>>3))) // represent j = (j % 8, j // 8) as 2 bytes.
 | 
						|
		wJ := receiver.w[j>>3] >> (j & 0x07) & 0x01                     // extract j^th bit from vector of bytes w.
 | 
						|
		wJ = ^(wJ - 0x01)                                               // convert it into a bitmask (all 1s if true, all 0s if false).
 | 
						|
		for k := 0; k < kappa>>3; k++ {
 | 
						|
			result.WPrime[k] ^= wJ & chiJ[k]
 | 
						|
			result.VPrime[k] ^= receiver.psi[j][k] & chiJ[k]
 | 
						|
		}
 | 
						|
	}
 | 
						|
	// result is the concatenation of WPrime, VPrime, then the entire matrix U (row-flattened).
 | 
						|
	return enc.Encode(result)
 | 
						|
}
 | 
						|
 | 
						|
func (sender *cOTSender) transfer(idExt [32]byte, inputMain []*big.Int, inputOT [2 * s][]*big.Int, rw io.ReadWriter) error {
 | 
						|
	// input message: Bob's values WPrime, VPrime, and U. output: tau.
 | 
						|
	enc := gob.NewEncoder(rw)
 | 
						|
	dec := gob.NewDecoder(rw)
 | 
						|
	input := &cOTInitStorage{}
 | 
						|
	if err := dec.Decode(input); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	z := [kappa][]byte{}
 | 
						|
	for i := 0; i < kappa; i++ {
 | 
						|
		z[i] = make([]byte, sender.lPrime>>3)
 | 
						|
	}
 | 
						|
	zeta := make([][kappa >> 3]byte, sender.lPrime)
 | 
						|
	hash := sha256.New() // basically this will contain a hash of the matrix U.
 | 
						|
 | 
						|
	// Unpack the random bytes in Packed into the choice array in the receiver
 | 
						|
	sender.receiver.initChoice()
 | 
						|
 | 
						|
	for i := 0; i < kappa; i++ {
 | 
						|
		row, err := core.ExpandMessageXmd(sha256.New, sender.receiver.Rho[i][:], idExt[:], sender.lPrime>>3)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		// use the idExt as the domain separator, and the _secret_ seed rho as the input!
 | 
						|
		v := make([]byte, sender.lPrime>>3) // we only need to retain one row of v at a time.
 | 
						|
		copy(v[:], row)
 | 
						|
		mask := byte(^(sender.receiver.choice[i] - 1))
 | 
						|
		for j := 0; j < sender.lPrime>>3; j++ {
 | 
						|
			z[i][j] = v[j] ^ mask&input.U[i][j]
 | 
						|
			// U := v_i^0 ^ v_i^1 ^ w. note: in step 4) of Prot. 9, i think `w` should be bolded?
 | 
						|
			for k := 0; k < 8; k++ {
 | 
						|
				zeta[j<<3+k][i>>3] |= z[i][j] >> k & 0x01 << (i & 0x07)
 | 
						|
				// assigning to zeta the matrix transposition of z. see notes above.
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if _, err = hash.Write(input.U[i][:]); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	digest := hash.Sum(nil) // go ahead and record this, so that we only have to hash the big matrix U once.
 | 
						|
	zPrime := [32]byte{}
 | 
						|
	for j := 0; j < sender.lPrime; j++ {
 | 
						|
		chiJ := sha256.Sum256(append(digest, byte(j&0x07), byte(j>>3))) // represent j = (j % 8, j // 8) as 2 bytes.
 | 
						|
		for k := 0; k < kappa>>3; k++ {
 | 
						|
			zPrime[k] ^= zeta[j][k] & chiJ[k]
 | 
						|
		}
 | 
						|
	}
 | 
						|
	rhs := [32]byte{}
 | 
						|
	for i := 0; i < 32; i++ {
 | 
						|
		rhs[i] = input.VPrime[i] ^ sender.receiver.Packed[i]&input.WPrime[i]
 | 
						|
	}
 | 
						|
	if subtle.ConstantTimeCompare(zPrime[:], rhs[:]) != 1 {
 | 
						|
		return fmt.Errorf("receiver's initial cOT message failed to verify")
 | 
						|
	}
 | 
						|
	result := &cOTStorage{}
 | 
						|
	result.TauMain = make([]*big.Int, 2*kappa*sender.multiplicity)
 | 
						|
	for j := 0; j < 2*kappa*sender.multiplicity; j++ {
 | 
						|
		column := sha256.Sum256(append(zeta[j][:], byte(j&0x07), byte(j>>3)))
 | 
						|
		sender.tA[j] = new(big.Int).SetBytes(column[:]) // not bothering to mod this. shouldn't be necessary.
 | 
						|
		for i := 0; i < 32; i++ {
 | 
						|
			zeta[j][i] ^= sender.receiver.Packed[i] // warning: overwrites zeta_j!!!!!! just using it as a place to store
 | 
						|
		}
 | 
						|
		column = sha256.Sum256(append(zeta[j][:], byte(j&0x07), byte(j>>3)))
 | 
						|
		result.TauMain[j] = new(big.Int).SetBytes(column[:])
 | 
						|
		result.TauMain[j] = sender.receiver.params.Scalar.Sub(result.TauMain[j], sender.tA[j])
 | 
						|
		result.TauMain[j] = sender.receiver.params.Scalar.Add(result.TauMain[j], inputMain[j])
 | 
						|
	}
 | 
						|
	length := 32 * sender.multiplicity
 | 
						|
	for j := 0; j < 2*s; j++ {
 | 
						|
		result.TauOT[j] = make([]*big.Int, sender.multiplicity)
 | 
						|
		column, err := core.ExpandMessageXmd(sha256.New, append(zeta[2*kappa*sender.multiplicity+j][:], byte(j&0x07), byte(j>>3)), []byte("Coinbase_tECDSA"), length)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		for k := 0; k < sender.multiplicity; k++ {
 | 
						|
			sender.tAOT[j][k] = new(big.Int).SetBytes(column[k*32 : (k+1)*32]) // not bothering to mod this. shouldn't be necessary.
 | 
						|
		}
 | 
						|
		for i := 0; i < 32; i++ {
 | 
						|
			zeta[2*kappa*sender.multiplicity+j][i] ^= sender.receiver.Packed[i] // warning: overwrites zeta_j!!!!!! just using it as a place to store
 | 
						|
		}
 | 
						|
		column, err = core.ExpandMessageXmd(sha256.New, append(zeta[2*kappa*sender.multiplicity+j][:], byte(j&0x07), byte(j>>3)), []byte("Coinbase_tECDSA"), length)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		for k := 0; k < sender.multiplicity; k++ {
 | 
						|
			result.TauOT[j][k] = new(big.Int).SetBytes(column[k*32 : (k+1)*32])
 | 
						|
			result.TauOT[j][k] = sender.receiver.params.Scalar.Sub(result.TauOT[j][k], sender.tAOT[j][k])
 | 
						|
			result.TauOT[j][k] = sender.receiver.params.Scalar.Add(result.TauOT[j][k], inputOT[j][k])
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return enc.Encode(result)
 | 
						|
}
 | 
						|
 | 
						|
func (receiver *cOTReceiver) transfer(r io.Reader) error {
 | 
						|
	dec := gob.NewDecoder(r)
 | 
						|
	input := &cOTStorage{}
 | 
						|
	if err := dec.Decode(input); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	for j := 0; j < 2*kappa*receiver.multiplicity; j++ {
 | 
						|
		column := sha256.Sum256(append(receiver.psi[j][:], byte(j&0x07), byte(j>>3)))
 | 
						|
		bit := int(receiver.w[j>>3]) >> (j & 0x07) & 0x01
 | 
						|
		receiver.tB[j] = new(big.Int).SetBytes(column[:])
 | 
						|
		receiver.tB[j] = receiver.sender.params.Scalar.Neg(receiver.tB[j])
 | 
						|
		wj0 := receiver.sender.params.Scalar.Bytes(receiver.tB[j])
 | 
						|
		wj1 := receiver.sender.params.Scalar.Bytes(receiver.sender.params.Scalar.Add(receiver.tB[j], input.TauMain[j]))
 | 
						|
		subtle.ConstantTimeCopy(bit, wj0, wj1)
 | 
						|
		receiver.tB[j].SetBytes(wj0)
 | 
						|
	}
 | 
						|
	length := 32 * receiver.multiplicity
 | 
						|
	for j := 0; j < 2*s; j++ {
 | 
						|
		column, err := core.ExpandMessageXmd(sha256.New, append(receiver.psi[2*kappa*receiver.multiplicity+j][:], byte(j&0x07), byte(j>>3)), []byte("Coinbase_tECDSA"), length)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		bit := int(receiver.w[(2*kappa*receiver.multiplicity+j)>>3]) >> (j & 0x07) & 0x01
 | 
						|
		for k := 0; k < receiver.multiplicity; k++ {
 | 
						|
			receiver.tBOT[j][k] = new(big.Int).SetBytes(column[k*32 : (k+1)*32])
 | 
						|
			receiver.tBOT[j][k] = receiver.sender.params.Scalar.Neg(receiver.tBOT[j][k])
 | 
						|
			wj0 := receiver.sender.params.Scalar.Bytes(receiver.tBOT[j][k])
 | 
						|
			wj1 := receiver.sender.params.Scalar.Bytes(receiver.sender.params.Scalar.Add(receiver.tBOT[j][k], input.TauOT[j][k]))
 | 
						|
			subtle.ConstantTimeCopy(bit, wj0, wj1)
 | 
						|
			receiver.tBOT[j][k].SetBytes(wj0)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (receiver *cOTReceiver) cOT(idExt [32]byte, choice []byte, rw io.ReadWriter) error {
 | 
						|
	if err := receiver.init(idExt, choice, rw); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	return receiver.transfer(rw)
 | 
						|
}
 | 
						|
 | 
						|
func (sender *cOTSender) cOT(idExt [32]byte, input []*big.Int, inputOT [2 * s][]*big.Int, rw io.ReadWriter) error {
 | 
						|
	return sender.transfer(idExt, input, inputOT, rw)
 | 
						|
}
 |