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
90 lines
2.7 KiB
Go
90 lines
2.7 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/ckks"
|
|
"github.com/luxfi/lattice/v7/utils"
|
|
"github.com/luxfi/lattice/v7/utils/bignum"
|
|
)
|
|
|
|
// simEvaluator is a struct used to pre-compute 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 ckks.Parameters
|
|
levelsConsumedPerRescaling int
|
|
}
|
|
|
|
// PolynomialDepth returns the depth of the polynomial.
|
|
func (d simEvaluator) PolynomialDepth(degree int) int {
|
|
|
|
if degree <= 0 {
|
|
panic(fmt.Errorf("invalid degree: degree=%d should be greater than zero", degree))
|
|
}
|
|
|
|
return d.levelsConsumedPerRescaling * (bits.Len64(uint64(degree)) - 1)
|
|
}
|
|
|
|
// Rescale rescales the target polynomial.SimOperand n times and returns it.
|
|
func (d simEvaluator) Rescale(op0 *polynomial.SimOperand) {
|
|
for i := 0; i < d.levelsConsumedPerRescaling; i++ {
|
|
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)
|
|
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 lead {
|
|
for i := 0; i < d.levelsConsumedPerRescaling; i++ {
|
|
tScaleNew = tScaleNew.Mul(rlwe.NewScale(d.params.Q()[tLevelNew-i]))
|
|
}
|
|
}
|
|
|
|
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()
|
|
|
|
var qi *big.Int
|
|
if lead {
|
|
qi = bignum.NewInt(Q[tLevelOld])
|
|
for i := 1; i < d.levelsConsumedPerRescaling; i++ {
|
|
qi.Mul(qi, bignum.NewInt(Q[tLevelOld-i]))
|
|
}
|
|
} else {
|
|
qi = bignum.NewInt(Q[tLevelOld+d.levelsConsumedPerRescaling])
|
|
for i := 1; i < d.levelsConsumedPerRescaling; i++ {
|
|
qi.Mul(qi, bignum.NewInt(Q[tLevelOld+d.levelsConsumedPerRescaling-i]))
|
|
}
|
|
}
|
|
|
|
tLevelNew = tLevelOld + d.levelsConsumedPerRescaling
|
|
tScaleNew = tScaleOld.Mul(rlwe.NewScale(qi))
|
|
tScaleNew = tScaleNew.Div(xPowScale)
|
|
|
|
return
|
|
}
|