mirror of
https://github.com/luxfi/lattice.git
synced 2026-09-24 00:25:44 +00:00
- Update module path to github.com/luxfi/lattice/v7 - Add GPU acceleration with Metal (macOS) and CUDA backends - Enhance threshold FHE operations - Revert to vanilla Apache 2.0 license (remove tfhe) - Update Go version to 1.25.5 - Merge upstream lattigo improvements
53 lines
2.0 KiB
Go
53 lines
2.0 KiB
Go
package ckks
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/luxfi/lattice/v7/core/rlwe"
|
|
"github.com/luxfi/lattice/v7/ring"
|
|
"github.com/luxfi/lattice/v7/utils"
|
|
)
|
|
|
|
// TraceNew maps X -> sum((-1)^i * X^{i*n+1}) for 0 <= i < N and returns the result on a new ciphertext.
|
|
// For log(n) = logSlots.
|
|
func (eval Evaluator) TraceNew(ctIn *rlwe.Ciphertext, logSlots int) (opOut *rlwe.Ciphertext, err error) {
|
|
opOut = NewCiphertext(*eval.GetParameters(), 1, ctIn.Level())
|
|
return opOut, eval.Trace(ctIn, logSlots, opOut)
|
|
}
|
|
|
|
// Average returns the average of vectors of batchSize elements.
|
|
// The operation assumes that ctIn encrypts SlotCount/batchSize sub-vectors of size batchSize.
|
|
// It then replaces all values of those sub-vectors by the component-wise average between all the sub-vectors.
|
|
// Example for batchSize=4 and slots=8: [{a, b, c, d}, {e, f, g, h}] -> [0.5*{a+e, b+f, c+g, d+h}, 0.5*{a+e, b+f, c+g, d+h}]
|
|
// Operation requires log2(SlotCout/batchSize) rotations.
|
|
// Required rotation keys can be generated with RotationsForInnerSumLog(batchSize, SlotCount/batchSize).
|
|
func (eval Evaluator) Average(ctIn *rlwe.Ciphertext, logBatchSize int, opOut *rlwe.Ciphertext) (err error) {
|
|
|
|
if ctIn.Degree() != 1 || opOut.Degree() != 1 {
|
|
return fmt.Errorf("cannot Average: ctIn.Degree() != 1 or opOut.Degree() != 1")
|
|
}
|
|
|
|
if logBatchSize > ctIn.LogDimensions.Cols {
|
|
return fmt.Errorf("cannot Average: batchSize must be smaller or equal to the number of slots")
|
|
}
|
|
|
|
ringQ := eval.GetParameters().RingQ()
|
|
|
|
level := utils.Min(ctIn.Level(), opOut.Level())
|
|
|
|
n := 1 << (ctIn.LogDimensions.Cols - logBatchSize)
|
|
|
|
// pre-multiplication by n^-1
|
|
for i, s := range ringQ.SubRings[:level+1] {
|
|
|
|
/* #nosec G115 -- n cannot be negative */
|
|
invN := ring.ModExp(uint64(n), s.Modulus-2, s.Modulus)
|
|
invN = ring.MForm(invN, s.Modulus, s.BRedConstant)
|
|
|
|
s.MulScalarMontgomery(ctIn.Value[0].Coeffs[i], invN, opOut.Value[0].Coeffs[i])
|
|
s.MulScalarMontgomery(ctIn.Value[1].Coeffs[i], invN, opOut.Value[1].Coeffs[i])
|
|
}
|
|
|
|
return eval.InnerSum(opOut, 1<<logBatchSize, n, opOut)
|
|
}
|