mirror of
				https://source.quilibrium.com/quilibrium/ceremonyclient.git
				synced 2025-11-04 00:27:41 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			169 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			169 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
//
 | 
						|
// Copyright Coinbase, Inc. All Rights Reserved.
 | 
						|
//
 | 
						|
// SPDX-License-Identifier: Apache-2.0
 | 
						|
//
 | 
						|
 | 
						|
package camshoup
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"math/big"
 | 
						|
 | 
						|
	"git.sr.ht/~sircmpwn/go-bare"
 | 
						|
 | 
						|
	mod "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core"
 | 
						|
)
 | 
						|
 | 
						|
type encryptionKeyMarshal struct {
 | 
						|
	Y1    [][]byte `bare:"y1"`
 | 
						|
	Y2    []byte   `bare:"y2"`
 | 
						|
	Y3    []byte   `bare:"y3"`
 | 
						|
	Group []byte   `bare:"group"`
 | 
						|
}
 | 
						|
 | 
						|
// EncryptionKey encrypts a message to a ciphertext from which
 | 
						|
// zero-knowledge proofs can be derived
 | 
						|
// as described in section 3.2 in <https://shoup.net/papers/verenc.pdf>.
 | 
						|
// n, g are stored in the `PaillierGroup` struct
 | 
						|
type EncryptionKey struct {
 | 
						|
	y1     []*big.Int
 | 
						|
	y2, y3 *big.Int
 | 
						|
	group  *PaillierGroup
 | 
						|
}
 | 
						|
 | 
						|
func NewKeys(numMsgs uint, group *PaillierGroup) (*EncryptionKey, *DecryptionKey, error) {
 | 
						|
	if numMsgs < 1 {
 | 
						|
		return nil, nil, fmt.Errorf("number of messages should be greater than 0")
 | 
						|
	}
 | 
						|
 | 
						|
	x1 := make([]*big.Int, numMsgs)
 | 
						|
	y1 := make([]*big.Int, numMsgs)
 | 
						|
	for i := range x1 {
 | 
						|
		x, err := mod.Rand(group.n2d4)
 | 
						|
		if err != nil {
 | 
						|
			return nil, nil, err
 | 
						|
		}
 | 
						|
		x1[i] = x
 | 
						|
		y1[i] = group.Gexp(x)
 | 
						|
	}
 | 
						|
	x2, err := mod.Rand(group.n2d4)
 | 
						|
	if err != nil {
 | 
						|
		return nil, nil, err
 | 
						|
	}
 | 
						|
	y2 := group.Gexp(x2)
 | 
						|
	x3, err := mod.Rand(group.n2d4)
 | 
						|
	if err != nil {
 | 
						|
		return nil, nil, err
 | 
						|
	}
 | 
						|
	y3 := group.Gexp(x3)
 | 
						|
	dk := &DecryptionKey{
 | 
						|
		x1, x2, x3, group,
 | 
						|
	}
 | 
						|
	ek := &EncryptionKey{
 | 
						|
		y1, y2, y3, group,
 | 
						|
	}
 | 
						|
	return ek, dk, nil
 | 
						|
}
 | 
						|
 | 
						|
// MarshalBinary serializes a key to bytes
 | 
						|
func (ek EncryptionKey) MarshalBinary() ([]byte, error) {
 | 
						|
	tv := new(encryptionKeyMarshal)
 | 
						|
	var err error
 | 
						|
	tv.Group, err = ek.group.MarshalBinary()
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	tv.Y3 = ek.y3.Bytes()
 | 
						|
	tv.Y2 = ek.y2.Bytes()
 | 
						|
	tv.Y1 = make([][]byte, len(ek.y1))
 | 
						|
	for i, y := range ek.y1 {
 | 
						|
		tv.Y1[i] = y.Bytes()
 | 
						|
	}
 | 
						|
	return bare.Marshal(tv)
 | 
						|
}
 | 
						|
 | 
						|
// UnmarshalBinary deserializes a key from bytes
 | 
						|
func (ek *EncryptionKey) UnmarshalBinary(data []byte) error {
 | 
						|
	tv := new(encryptionKeyMarshal)
 | 
						|
	err := bare.Unmarshal(data, tv)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	ek.group = new(PaillierGroup)
 | 
						|
	err = ek.group.UnmarshalBinary(tv.Group)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	ek.y2 = new(big.Int).SetBytes(tv.Y2)
 | 
						|
	ek.y3 = new(big.Int).SetBytes(tv.Y3)
 | 
						|
	ek.y1 = make([]*big.Int, len(tv.Y1))
 | 
						|
	for i, b := range tv.Y1 {
 | 
						|
		ek.y1[i] = new(big.Int).SetBytes(b)
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// Encrypt multiple messages as described in <https://shoup.net/papers/verenc.pdf>
 | 
						|
// `domain` represents a domain separation tag or nonce
 | 
						|
func (ek EncryptionKey) Encrypt(domain []byte, msgs []*big.Int) (*CipherText, error) {
 | 
						|
	if len(msgs) > len(ek.y1) {
 | 
						|
		return nil, fmt.Errorf("number of messages %d is more than supported by this key %d", len(msgs), len(ek.y1))
 | 
						|
	}
 | 
						|
	for i, m := range msgs {
 | 
						|
		if m == nil || m.Cmp(ek.group.n) == 1 {
 | 
						|
			return nil, fmt.Errorf("message %d is not valid", i)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	r, err := ek.group.RandForEncrypt()
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	return ek.encryptWithR(domain, msgs, r)
 | 
						|
}
 | 
						|
 | 
						|
func (ek EncryptionKey) encryptWithR(domain []byte, msgs []*big.Int, r *big.Int) (*CipherText, error) {
 | 
						|
	u := ek.computeU(r)
 | 
						|
	e := ek.computeE(msgs, r)
 | 
						|
 | 
						|
	hs, err := ek.group.Hash(u, e, domain)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	v := ek.computeV(r, hs, true)
 | 
						|
	return &CipherText{u, v, e}, nil
 | 
						|
}
 | 
						|
 | 
						|
func (ek EncryptionKey) computeE(msgs []*big.Int, r *big.Int) []*big.Int {
 | 
						|
	e := make([]*big.Int, len(msgs))
 | 
						|
	for i, m := range msgs {
 | 
						|
		y := ek.group.Exp(ek.y1[i], r)
 | 
						|
		hM := ek.group.Hexp(m)
 | 
						|
		e[i] = ek.group.Mul(y, hM)
 | 
						|
	}
 | 
						|
	return e
 | 
						|
}
 | 
						|
 | 
						|
func (ek EncryptionKey) computeU(r *big.Int) *big.Int {
 | 
						|
	return ek.group.Gexp(r)
 | 
						|
}
 | 
						|
 | 
						|
// computeV computes the `v` value during encryption
 | 
						|
// abs is present for code reuse as during the proof of encryption
 | 
						|
// in the commitment step absolute value is not taken.
 | 
						|
func (ek EncryptionKey) computeV(r, hash *big.Int, abs bool) *big.Int {
 | 
						|
	// y3 ^ h(u, e, L)
 | 
						|
	y3hs := ek.group.Exp(ek.y3, hash)
 | 
						|
 | 
						|
	// y2 * (y3^h(u, e, L))
 | 
						|
	y2y3hs := ek.group.Mul(ek.y2, y3hs)
 | 
						|
 | 
						|
	// (y2y3^h(u, e, L))^r
 | 
						|
	y2y3hsr := ek.group.Exp(y2y3hs, r)
 | 
						|
	if abs {
 | 
						|
		return ek.group.Abs(y2y3hsr)
 | 
						|
	} else {
 | 
						|
		return y2y3hsr
 | 
						|
	}
 | 
						|
}
 |