mirror of
https://github.com/luxfi/threshold.git
synced 2026-10-30 15:15:53 +00:00
95 lines
2.3 KiB
Go
95 lines
2.3 KiB
Go
package paillier
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"io"
|
|
|
|
"github.com/cronokirby/saferith"
|
|
"github.com/luxfi/threshold/internal/params"
|
|
"github.com/luxfi/threshold/pkg/math/sample"
|
|
)
|
|
|
|
// Ciphertext represents an integer of the for (1+N)ᵐρᴺ (mod N²), representing the encryption of m ∈ ℤₙˣ.
|
|
type Ciphertext struct {
|
|
c *saferith.Nat
|
|
}
|
|
|
|
// Add sets ct to the homomorphic sum ct ⊕ ct₂.
|
|
// ct ← ct•ct₂ (mod N²).
|
|
func (ct *Ciphertext) Add(pk *PublicKey, ct2 *Ciphertext) *Ciphertext {
|
|
if ct2 == nil {
|
|
return ct
|
|
}
|
|
|
|
ct.c.ModMul(ct.c, ct2.c, pk.nSquared.Modulus)
|
|
|
|
return ct
|
|
}
|
|
|
|
// Mul sets ct to the homomorphic multiplication of k ⊙ ct.
|
|
// ct ← ctᵏ (mod N²).
|
|
func (ct *Ciphertext) Mul(pk *PublicKey, k *saferith.Int) *Ciphertext {
|
|
if k == nil {
|
|
return ct
|
|
}
|
|
|
|
ct.c = pk.nSquared.ExpI(ct.c, k)
|
|
|
|
return ct
|
|
}
|
|
|
|
// Equal check whether ct ≡ ctₐ (mod N²).
|
|
func (ct *Ciphertext) Equal(ctA *Ciphertext) bool {
|
|
return ct.c.Eq(ctA.c) == 1
|
|
}
|
|
|
|
// Clone returns a deep copy of ct.
|
|
func (ct Ciphertext) Clone() *Ciphertext {
|
|
c := new(saferith.Nat)
|
|
c.SetNat(ct.c)
|
|
return &Ciphertext{c: c}
|
|
}
|
|
|
|
// Randomize multiplies the ciphertext's nonce by a newly generated one.
|
|
// ct ← ct ⋅ nonceᴺ (mod N²).
|
|
// If nonce is nil, a random one is generated.
|
|
// The receiver is updated, and the nonce update is returned.
|
|
func (ct *Ciphertext) Randomize(pk *PublicKey, nonce *saferith.Nat) *saferith.Nat {
|
|
if nonce == nil {
|
|
nonce = sample.UnitModN(rand.Reader, pk.n.Modulus)
|
|
}
|
|
// c = c*r^N
|
|
tmp := pk.nSquared.Exp(nonce, pk.nNat)
|
|
ct.c.ModMul(ct.c, tmp, pk.nSquared.Modulus)
|
|
return nonce
|
|
}
|
|
|
|
// WriteTo implements io.WriterTo and should be used within the hash.Hash function.
|
|
func (ct *Ciphertext) WriteTo(w io.Writer) (int64, error) {
|
|
if ct == nil {
|
|
return 0, io.ErrUnexpectedEOF
|
|
}
|
|
buf := make([]byte, params.BytesCiphertext)
|
|
ct.c.FillBytes(buf)
|
|
n, err := w.Write(buf)
|
|
return int64(n), err
|
|
}
|
|
|
|
// Domain implements hash.WriterToWithDomain, and separates this type within hash.Hash.
|
|
func (*Ciphertext) Domain() string {
|
|
return "Paillier Ciphertext"
|
|
}
|
|
|
|
func (ct *Ciphertext) MarshalBinary() ([]byte, error) {
|
|
return ct.c.MarshalBinary()
|
|
}
|
|
|
|
func (ct *Ciphertext) UnmarshalBinary(data []byte) error {
|
|
ct.c = new(saferith.Nat)
|
|
return ct.c.UnmarshalBinary(data)
|
|
}
|
|
|
|
func (ct *Ciphertext) Nat() *saferith.Nat {
|
|
return new(saferith.Nat).SetNat(ct.c)
|
|
}
|