mirror of
				https://source.quilibrium.com/quilibrium/ceremonyclient.git
				synced 2025-11-04 00:27:41 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			157 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			157 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
//
 | 
						|
// Copyright Coinbase, Inc. All Rights Reserved.
 | 
						|
//
 | 
						|
// SPDX-License-Identifier: Apache-2.0
 | 
						|
//
 | 
						|
 | 
						|
package elgamal
 | 
						|
 | 
						|
import (
 | 
						|
	"crypto/aes"
 | 
						|
	"crypto/cipher"
 | 
						|
	crand "crypto/rand"
 | 
						|
	"fmt"
 | 
						|
	"math/big"
 | 
						|
 | 
						|
	"git.sr.ht/~sircmpwn/go-bare"
 | 
						|
 | 
						|
	"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core"
 | 
						|
	"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
 | 
						|
)
 | 
						|
 | 
						|
type encryptionKeyMarshal struct {
 | 
						|
	Value []byte `bare:"value"`
 | 
						|
	Curve string `bare:"curve"`
 | 
						|
}
 | 
						|
 | 
						|
// EncryptParams is all the options for doing verifiable encryption.
 | 
						|
// Message must be supplied and is the value to be encrypted.
 | 
						|
// MessageIsHashed defines whether Message represents an unhashed arbitrary
 | 
						|
// byte sequence or already represents a scalar in the elliptic curve.
 | 
						|
// Domain is an optional domain separation tag and used to generate a separate
 | 
						|
// point for the pedersen commitment in El-Gamal ciphertexts.
 | 
						|
// Blinding is blinding factor (bf) of the El-Gamal ciphertext. If nil
 | 
						|
// a bf is generated at random.
 | 
						|
// GenProof indicates whether to return a proof of encryption correctness to the
 | 
						|
// corresponding public key.
 | 
						|
// ProofNonce is the nonce used to generate the one time proof. This value
 | 
						|
// is required if GenProof is true.
 | 
						|
type EncryptParams struct {
 | 
						|
	MessageIsHashed bool
 | 
						|
	Domain          []byte
 | 
						|
	Blinding        curves.Scalar
 | 
						|
	GenProof        bool
 | 
						|
	ProofNonce      []byte
 | 
						|
}
 | 
						|
 | 
						|
// EncryptionKey encrypts a message to a ciphertext from which
 | 
						|
// zero-knowledge proofs can be derived
 | 
						|
type EncryptionKey struct {
 | 
						|
	Value curves.Point
 | 
						|
}
 | 
						|
 | 
						|
// NewKeys creates a new key pair for El-Gamal encryption
 | 
						|
func NewKeys(curve *curves.Curve) (*EncryptionKey, *DecryptionKey, error) {
 | 
						|
	if curve == nil {
 | 
						|
		return nil, nil, fmt.Errorf("invalid curve")
 | 
						|
	}
 | 
						|
	x := curve.Scalar.Random(crand.Reader)
 | 
						|
	if x == nil {
 | 
						|
		return nil, nil, fmt.Errorf("cannot generate decryption key")
 | 
						|
	}
 | 
						|
	value := curve.Point.Generator().Mul(x)
 | 
						|
	if value == nil {
 | 
						|
		return nil, nil, fmt.Errorf("cannot generate encryption key")
 | 
						|
	}
 | 
						|
	return &EncryptionKey{value}, &DecryptionKey{x}, nil
 | 
						|
}
 | 
						|
 | 
						|
// MarshalBinary serializes a key to bytes
 | 
						|
func (ek EncryptionKey) MarshalBinary() ([]byte, error) {
 | 
						|
	tv := new(encryptionKeyMarshal)
 | 
						|
	tv.Curve = ek.Value.CurveName()
 | 
						|
	tv.Value = ek.Value.ToAffineCompressed()
 | 
						|
	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
 | 
						|
	}
 | 
						|
	curve := curves.GetCurveByName(tv.Curve)
 | 
						|
	if curve == nil {
 | 
						|
		return fmt.Errorf("unknown curve")
 | 
						|
	}
 | 
						|
	value, err := curve.Point.FromAffineCompressed(tv.Value)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	ek.Value = value
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (ek EncryptionKey) HomomorphicEncrypt(msg curves.Scalar) (*HomomorphicCipherText, error) {
 | 
						|
	r := ek.Value.Scalar().Random(crand.Reader)
 | 
						|
	return &HomomorphicCipherText{
 | 
						|
		C1: ek.Value.Generator().Mul(r),
 | 
						|
		C2: ek.Value.Mul(r).Add(ek.Value.Generator().Mul(msg)),
 | 
						|
	}, nil
 | 
						|
}
 | 
						|
 | 
						|
func (ek EncryptionKey) encryptWithRandNonce(msg []byte, msgIsHashed bool, r curves.Scalar, h curves.Point, nonce []byte) (*CipherText, error) {
 | 
						|
	// r * Q
 | 
						|
	t := ek.Value.Mul(r)
 | 
						|
	// Derive AEAD encryption key
 | 
						|
	aeadKey, err := core.FiatShamir(new(big.Int).SetBytes(t.ToAffineCompressed()))
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	block, err := aes.NewCipher(aeadKey)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	aesGcm, err := cipher.NewGCM(block)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	// C1 = r * G
 | 
						|
	c1 := ek.Value.Generator().Mul(r)
 | 
						|
	// C2 = m * H + r * Q
 | 
						|
	msgScalar := r.New(0)
 | 
						|
	if msgIsHashed {
 | 
						|
		msgScalar, err = msgScalar.SetBytes(msg)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		msgScalar = msgScalar.Hash(msg)
 | 
						|
	}
 | 
						|
	c2 := h.Mul(msgScalar).Add(t)
 | 
						|
 | 
						|
	aad := c1.ToAffineUncompressed()
 | 
						|
	aad = append(aad, c2.ToAffineUncompressed()...)
 | 
						|
	// AAD = C1 || C2
 | 
						|
	// this protects them from modifications
 | 
						|
	aead := aesGcm.Seal(nil, nonce, msg, aad)
 | 
						|
 | 
						|
	return &CipherText{
 | 
						|
		c1, c2, nonce, aead, msgIsHashed,
 | 
						|
	}, nil
 | 
						|
}
 | 
						|
 | 
						|
func (ek EncryptionKey) genNonce() []byte {
 | 
						|
	var nonce [12]byte
 | 
						|
	n, err := crand.Read(nonce[:])
 | 
						|
	if err != nil {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
	if n != 12 {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
	return nonce[:]
 | 
						|
}
 |