mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-11-14 12:15:18 +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
|
|
}
|
|
}
|