mirror of
https://github.com/luxfi/lattice.git
synced 2026-09-24 00:25:44 +00:00
196 lines
7.7 KiB
Go
196 lines
7.7 KiB
Go
package mheint
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/luxfi/lattice/v5/core/rlwe"
|
|
"github.com/luxfi/lattice/v5/he/heint"
|
|
"github.com/luxfi/lattice/v5/mhe"
|
|
"github.com/luxfi/lattice/v5/ring"
|
|
"github.com/luxfi/lattice/v5/utils"
|
|
"github.com/luxfi/lattice/v5/utils/sampling"
|
|
)
|
|
|
|
// EncToShareProtocol is the structure storing the parameters and temporary buffers
|
|
// required by the encryption-to-shares protocol.
|
|
type EncToShareProtocol struct {
|
|
mhe.KeySwitchProtocol
|
|
params heint.Parameters
|
|
|
|
maskSampler *ring.UniformSampler
|
|
encoder *heint.Encoder
|
|
|
|
zero *rlwe.SecretKey
|
|
tmpPlaintextRingT ring.Poly
|
|
tmpPlaintextRingQ ring.Poly
|
|
}
|
|
|
|
func NewAdditiveShare(params heint.Parameters) mhe.AdditiveShare {
|
|
return mhe.NewAdditiveShare(params.RingT())
|
|
}
|
|
|
|
// ShallowCopy creates a shallow copy of EncToShareProtocol in which all the read-only data-structures are
|
|
// shared with the receiver and the temporary buffers are reallocated. The receiver and the returned
|
|
// EncToShareProtocol can be used concurrently.
|
|
func (e2s EncToShareProtocol) ShallowCopy() EncToShareProtocol {
|
|
|
|
params := e2s.params
|
|
|
|
prng, err := sampling.NewPRNG()
|
|
|
|
// Sanity check, this error should not happen.
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return EncToShareProtocol{
|
|
KeySwitchProtocol: e2s.KeySwitchProtocol.ShallowCopy(),
|
|
params: e2s.params,
|
|
maskSampler: ring.NewUniformSampler(prng, params.RingT()),
|
|
encoder: e2s.encoder.ShallowCopy(),
|
|
zero: e2s.zero,
|
|
tmpPlaintextRingT: params.RingT().NewPoly(),
|
|
tmpPlaintextRingQ: params.RingQ().NewPoly(),
|
|
}
|
|
}
|
|
|
|
// NewEncToShareProtocol creates a new EncToShareProtocol struct from the passed heint.Parameters.
|
|
func NewEncToShareProtocol(params heint.Parameters, noiseFlooding ring.DistributionParameters) (EncToShareProtocol, error) {
|
|
e2s := EncToShareProtocol{}
|
|
|
|
var err error
|
|
if e2s.KeySwitchProtocol, err = mhe.NewKeySwitchProtocol(params.Parameters, noiseFlooding); err != nil {
|
|
return EncToShareProtocol{}, err
|
|
}
|
|
|
|
e2s.params = params
|
|
e2s.encoder = heint.NewEncoder(params)
|
|
prng, err := sampling.NewPRNG()
|
|
|
|
// Sanity check, this error should not happen.
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
e2s.maskSampler = ring.NewUniformSampler(prng, params.RingT())
|
|
|
|
e2s.zero = rlwe.NewSecretKey(params.Parameters)
|
|
e2s.tmpPlaintextRingQ = params.RingQ().NewPoly()
|
|
e2s.tmpPlaintextRingT = params.RingT().NewPoly()
|
|
return e2s, nil
|
|
}
|
|
|
|
// AllocateShare allocates a share of the EncToShare protocol
|
|
func (e2s EncToShareProtocol) AllocateShare(level int) (share mhe.KeySwitchShare) {
|
|
return e2s.KeySwitchProtocol.AllocateShare(level)
|
|
}
|
|
|
|
// GenShare generates a party's share in the encryption-to-shares protocol. This share consist in the additive secret-share of the party
|
|
// which is written in secretShareOut and in the public masked-decryption share written in publicShareOut.
|
|
// ct1 is degree 1 element of a rlwe.Ciphertext, i.e. rlwe.Ciphertext.Value[1].
|
|
func (e2s EncToShareProtocol) GenShare(sk *rlwe.SecretKey, ct *rlwe.Ciphertext, secretShareOut *mhe.AdditiveShare, publicShareOut *mhe.KeySwitchShare) {
|
|
level := utils.Min(ct.Level(), publicShareOut.Value.Level())
|
|
e2s.KeySwitchProtocol.GenShare(sk, e2s.zero, ct, publicShareOut)
|
|
e2s.maskSampler.Read(secretShareOut.Value)
|
|
e2s.encoder.RingT2Q(level, true, secretShareOut.Value, e2s.tmpPlaintextRingQ)
|
|
ringQ := e2s.params.RingQ().AtLevel(level)
|
|
ringQ.NTT(e2s.tmpPlaintextRingQ, e2s.tmpPlaintextRingQ)
|
|
ringQ.Sub(publicShareOut.Value, e2s.tmpPlaintextRingQ, publicShareOut.Value)
|
|
}
|
|
|
|
// GetShare is the final step of the encryption-to-share protocol. It performs the masked decryption of the target ciphertext followed by a
|
|
// the removal of the caller's secretShare as generated in the GenShare method.
|
|
// If the caller is not secret-key-share holder (i.e., didn't generate a decryption share), `secretShare` can be set to nil.
|
|
// Therefore, in order to obtain an additive sharing of the message, only one party should call this method, and the other parties should use
|
|
// the secretShareOut output of the GenShare method.
|
|
func (e2s EncToShareProtocol) GetShare(secretShare *mhe.AdditiveShare, aggregatePublicShare mhe.KeySwitchShare, ct *rlwe.Ciphertext, secretShareOut *mhe.AdditiveShare) {
|
|
level := utils.Min(ct.Level(), aggregatePublicShare.Value.Level())
|
|
ringQ := e2s.params.RingQ().AtLevel(level)
|
|
ringQ.Add(aggregatePublicShare.Value, ct.Value[0], e2s.tmpPlaintextRingQ)
|
|
ringQ.INTT(e2s.tmpPlaintextRingQ, e2s.tmpPlaintextRingQ)
|
|
e2s.encoder.RingQ2T(level, true, e2s.tmpPlaintextRingQ, e2s.tmpPlaintextRingT)
|
|
if secretShare != nil {
|
|
e2s.params.RingT().Add(secretShare.Value, e2s.tmpPlaintextRingT, secretShareOut.Value)
|
|
} else {
|
|
secretShareOut.Value.Copy(e2s.tmpPlaintextRingT)
|
|
}
|
|
}
|
|
|
|
// ShareToEncProtocol is the structure storing the parameters and temporary buffers
|
|
// required by the shares-to-encryption protocol.
|
|
type ShareToEncProtocol struct {
|
|
mhe.KeySwitchProtocol
|
|
params heint.Parameters
|
|
|
|
encoder *heint.Encoder
|
|
|
|
zero *rlwe.SecretKey
|
|
tmpPlaintextRingQ ring.Poly
|
|
}
|
|
|
|
// NewShareToEncProtocol creates a new ShareToEncProtocol struct from the passed integer parameters.
|
|
func NewShareToEncProtocol(params heint.Parameters, noiseFlooding ring.DistributionParameters) (ShareToEncProtocol, error) {
|
|
s2e := ShareToEncProtocol{}
|
|
|
|
var err error
|
|
if s2e.KeySwitchProtocol, err = mhe.NewKeySwitchProtocol(params.Parameters, noiseFlooding); err != nil {
|
|
return ShareToEncProtocol{}, err
|
|
}
|
|
|
|
s2e.params = params
|
|
s2e.encoder = heint.NewEncoder(params)
|
|
s2e.zero = rlwe.NewSecretKey(params.Parameters)
|
|
s2e.tmpPlaintextRingQ = params.RingQ().NewPoly()
|
|
return s2e, nil
|
|
}
|
|
|
|
// AllocateShare allocates a share of the ShareToEnc protocol
|
|
func (s2e ShareToEncProtocol) AllocateShare(level int) (share mhe.KeySwitchShare) {
|
|
return s2e.KeySwitchProtocol.AllocateShare(level)
|
|
}
|
|
|
|
// ShallowCopy creates a shallow copy of ShareToEncProtocol in which all the read-only data-structures are
|
|
// shared with the receiver and the temporary buffers are reallocated. The receiver and the returned
|
|
// ShareToEncProtocol can be used concurrently.
|
|
func (s2e ShareToEncProtocol) ShallowCopy() ShareToEncProtocol {
|
|
params := s2e.params
|
|
return ShareToEncProtocol{
|
|
KeySwitchProtocol: s2e.KeySwitchProtocol.ShallowCopy(),
|
|
encoder: s2e.encoder.ShallowCopy(),
|
|
params: params,
|
|
zero: s2e.zero,
|
|
tmpPlaintextRingQ: params.RingQ().NewPoly(),
|
|
}
|
|
}
|
|
|
|
// GenShare generates a party's in the shares-to-encryption protocol given the party's secret-key share `sk`, a common
|
|
// polynomial sampled from the CRS `crp` and the party's secret share of the message.
|
|
func (s2e ShareToEncProtocol) GenShare(sk *rlwe.SecretKey, crp mhe.KeySwitchCRP, secretShare mhe.AdditiveShare, c0ShareOut *mhe.KeySwitchShare) (err error) {
|
|
|
|
if crp.Value.Level() != c0ShareOut.Value.Level() {
|
|
return fmt.Errorf("cannot GenShare: crp and c0ShareOut level must be equal")
|
|
}
|
|
|
|
ct := &rlwe.Ciphertext{}
|
|
ct.Value = []ring.Poly{{}, crp.Value}
|
|
ct.MetaData = &rlwe.MetaData{}
|
|
ct.MetaData.IsNTT = true
|
|
s2e.KeySwitchProtocol.GenShare(s2e.zero, sk, ct, c0ShareOut)
|
|
s2e.encoder.RingT2Q(crp.Value.Level(), true, secretShare.Value, s2e.tmpPlaintextRingQ)
|
|
ringQ := s2e.params.RingQ().AtLevel(crp.Value.Level())
|
|
ringQ.NTT(s2e.tmpPlaintextRingQ, s2e.tmpPlaintextRingQ)
|
|
ringQ.Add(c0ShareOut.Value, s2e.tmpPlaintextRingQ, c0ShareOut.Value)
|
|
return
|
|
}
|
|
|
|
// GetEncryption computes the final encryption of the secret-shared message when provided with the aggregation `c0Agg` of the parties'
|
|
// shares in the protocol and with the common, CRS-sampled polynomial `crp`.
|
|
func (s2e ShareToEncProtocol) GetEncryption(c0Agg mhe.KeySwitchShare, crp mhe.KeySwitchCRP, opOut *rlwe.Ciphertext) (err error) {
|
|
if opOut.Degree() != 1 {
|
|
return fmt.Errorf("cannot GetEncryption: opOut must have degree 1")
|
|
}
|
|
opOut.Value[0].Copy(c0Agg.Value)
|
|
opOut.Value[1].Copy(crp.Value)
|
|
return
|
|
}
|