Files
lattice/circuits/bgv/polynomial/polynomial_evaluator_sim.go
zeekay eaf864890e feat: release v7.0.0 with GPU acceleration and module update
- 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
2025-12-30 15:37:37 -08:00

105 lines
2.8 KiB
Go

package polynomial
import (
"fmt"
"math/big"
"math/bits"
"github.com/luxfi/lattice/v7/circuits/common/polynomial"
"github.com/luxfi/lattice/v7/core/rlwe"
"github.com/luxfi/lattice/v7/schemes/bgv"
"github.com/luxfi/lattice/v7/utils"
)
// simEvaluator is a struct used to pre-computed the scaling
// factors of the polynomial coefficients used by the inlined
// polynomial evaluation by running the polynomial evaluation
// with dummy operands.
// This struct implements the interface [polynomial.SimEvaluator].
type simEvaluator struct {
params bgv.Parameters
InvariantTensoring bool
}
// PolynomialDepth returns the depth of the polynomial.
func (d simEvaluator) PolynomialDepth(degree int) int {
if d.InvariantTensoring {
return 0
}
if degree <= 0 {
panic(fmt.Errorf("invalid degree: degree=%d should be greater than zero", degree))
}
return bits.Len64(uint64(degree)) - 1
}
// Rescale rescales the target polynomial.SimOperand n times and returns it.
func (d simEvaluator) Rescale(op0 *polynomial.SimOperand) {
if !d.InvariantTensoring {
op0.Scale = op0.Scale.Div(rlwe.NewScale(d.params.Q()[op0.Level]))
op0.Level--
}
}
// MulNew multiplies two polynomial.SimOperand, stores the result the target [polynomial.SimOperand] and returns the result.
func (d simEvaluator) MulNew(op0, op1 *polynomial.SimOperand) (opOut *polynomial.SimOperand) {
opOut = new(polynomial.SimOperand)
opOut.Level = utils.Min(op0.Level, op1.Level)
if d.InvariantTensoring {
opOut.Scale = bgv.MulScaleInvariant(d.params, op0.Scale, op1.Scale, opOut.Level)
} else {
opOut.Scale = op0.Scale.Mul(op1.Scale)
}
return
}
// UpdateLevelAndScaleBabyStep returns the updated level and scale for a baby-step.
func (d simEvaluator) UpdateLevelAndScaleBabyStep(lead bool, tLevelOld int, tScaleOld rlwe.Scale) (tLevelNew int, tScaleNew rlwe.Scale) {
tLevelNew = tLevelOld
tScaleNew = tScaleOld
if !d.InvariantTensoring && lead {
tScaleNew = tScaleOld.Mul(d.params.NewScale(d.params.Q()[tLevelOld]))
}
return
}
// UpdateLevelAndScaleGiantStep returns the updated level and scale for a giant-step.
func (d simEvaluator) UpdateLevelAndScaleGiantStep(lead bool, tLevelOld int, tScaleOld, xPowScale rlwe.Scale) (tLevelNew int, tScaleNew rlwe.Scale) {
Q := d.params.Q()
tLevelNew = tLevelOld
tScaleNew = tScaleOld.Div(xPowScale)
// tScaleNew = targetScale*currentQi/XPow.Scale
if !d.InvariantTensoring {
var currentQi uint64
if lead {
currentQi = Q[tLevelNew]
} else {
currentQi = Q[tLevelNew+1]
}
tScaleNew = tScaleNew.Mul(d.params.NewScale(currentQi))
} else {
T := d.params.PlaintextModulus()
// -Q mod T
qModTNeg := new(big.Int).Mod(d.params.RingQ().ModulusAtLevel[tLevelNew], new(big.Int).SetUint64(T)).Uint64()
qModTNeg = T - qModTNeg
tScaleNew = tScaleNew.Mul(d.params.NewScale(qModTNeg))
}
if !d.InvariantTensoring {
tLevelNew++
}
return
}