Lattigo CKKS Bootstrap
-
lattigo/bootstrap.go at master · tuneinsight/lattigo · GitHub を読む
-
パラメータの用意などは
ckks.bootstrap以下, -
基本,
advanced.EvaluatorにBootstrapの為の高度な演算が実装されていて,Evaluatorにmixinされている
- advanced
- evaluator.go // CtoS, StoC, EvalModの実装
- homomorphic_encoding.go // EncodingMatrix関連
- homomorphic_mod.go // EvalMod関連
- bootstrapping
- bootstrap.go // Bootstrapの大枠の処理
- bootstrapper.go // evkの拡張の定義とか作成処理
- default_params.go // 用意されているbootstrap時のパラメータ
- evaluator.go // 基本演算
func (btp *Bootstrapper) Bootstrapp(ctIn *ckks.Ciphertext) (ctOut *ckks.Ciphertext) {
ctOut = ctIn.CopyNew()
// 省略: レベルとスケールの調整
// Step 1 : Extend the basis from q to Q
ctOut = btp.modUpFromQ0(ctOut)
// SubSum X -> (N/dslots) * Y^dslots
btp.Trace(ctOut, btp.params.LogSlots(), btp.params.LogN()-1, ctOut)
// Step 2 : CoeffsToSlots (Homomorphic encoding)
ctReal, ctImag := btp.CoeffsToSlotsNew(ctOut, btp.ctsMatrices)
// Step 3 : EvalMod (Homomorphic modular reduction)
ctReal = btp.EvalModNew(ctReal, btp.evalModPoly)
ctReal.Scale = btp.params.DefaultScale()
if ctImag != nil {
ctImag = btp.EvalModNew(ctImag, btp.evalModPoly)
ctImag.Scale = btp.params.DefaultScale()
}
// Step 4 : SlotsToCoeffs (Homomorphic decoding)
ctOut = btp.SlotsToCoeffsNew(ctReal, ctImag, btp.stcMatrices)
return
}Model
bootstrapperBase
// Bootstrapper is a struct to store a memory buffer with the plaintext matrices,
// the polynomial approximation, and the keys for the bootstrapping.
type Bootstrapper struct {
advanced.Evaluator
*bootstrapperBase
}
type bootstrapperBase struct {
Parameters
params ckks.Parameters
dslots int // Number of plaintext slots after the re-encoding
logdslots int
evalModPoly advanced.EvalModPoly
stcMatrices advanced.EncodingMatrix
ctsMatrices advanced.EncodingMatrix
q0OverMessageRatio float64
swkDtS *rlwe.SwitchingKey
swkStD *rlwe.SwitchingKey
}
// EvaluationKeys is a type for a CKKS bootstrapping key, which
// regroups the necessary public relinearization and rotation keys.
type EvaluationKeys struct {
rlwe.EvaluationKey
SwkDtS *rlwe.SwitchingKey
SwkStD *rlwe.SwitchingKey
}func newBootstrapperBase(params ckks.Parameters, btpParams Parameters, btpKey EvaluationKeys) (bb *bootstrapperBase) {
bb = new(bootstrapperBase)
bb.params = params
bb.Parameters = btpParams
bb.dslots = params.Slots()
bb.logdslots = params.LogSlots()
if params.LogSlots() < params.MaxLogSlots() {
bb.dslots <<= 1
bb.logdslots++
}
bb.evalModPoly = advanced.NewEvalModPolyFromLiteral(btpParams.EvalModParameters)
scFac := bb.evalModPoly.ScFac()
K := bb.evalModPoly.K() / scFac
n := float64(2 * params.Slots())
// Correcting factor for approximate division by Q
// The second correcting factor for approximate multiplication by Q is included in the coefficients of the EvalMod polynomials
qDiff := bb.evalModPoly.QDiff()
// Q0/|m|
bb.q0OverMessageRatio = math.Exp2(math.Round(math.Log2(params.QiFloat64(0) / bb.evalModPoly.MessageRatio())))
// If the scale used during the EvalMod step is smaller than Q0, then we cannot increase the scale during
// the EvalMod step to get a free division by MessageRatio, and we need to do this division (totally or partly)
// during the CoeffstoSlots step
qDiv := btpParams.EvalModParameters.ScalingFactor / math.Exp2(math.Round(math.Log2(params.QiFloat64(0))))
// Sets qDiv to 1 if there is enough room for the division to happen using scale manipulation.
if qDiv > 1 {
qDiv = 1
}
encoder := ckks.NewEncoder(bb.params)
// CoeffsToSlots vectors
// Change of variable for the evaluation of the Chebyshev polynomial + cancelling factor for the DFT and SubSum + eventual scaling factor for the double angle formula
bb.CoeffsToSlotsParameters.LogN = params.LogN()
bb.CoeffsToSlotsParameters.LogSlots = params.LogSlots()
bb.CoeffsToSlotsParameters.Scaling = qDiv / (K * n * scFac * qDiff)
bb.ctsMatrices = advanced.NewHomomorphicEncodingMatrixFromLiteral(bb.CoeffsToSlotsParameters, encoder)
// SlotsToCoeffs vectors
// Rescaling factor to set the final ciphertext to the desired scale
bb.SlotsToCoeffsParameters.LogN = params.LogN()
bb.SlotsToCoeffsParameters.LogSlots = params.LogSlots()
bb.SlotsToCoeffsParameters.Scaling = bb.params.DefaultScale() / (bb.evalModPoly.ScalingFactor() / bb.evalModPoly.MessageRatio())
bb.stcMatrices = advanced.NewHomomorphicEncodingMatrixFromLiteral(bb.SlotsToCoeffsParameters, encoder)
encoder = nil
return
}NewHomomorphicEncodingMatrixFromLiteral
// NewHomomorphicEncodingMatrixFromLiteral generates the factorized encoding matrix.
// scaling : constant by witch the all the matrices will be multuplied by.
// encoder : ckks.Encoder.
func NewHomomorphicEncodingMatrixFromLiteral(mParams EncodingMatrixLiteral, encoder ckks.Encoder) EncodingMatrix {
logSlots := mParams.LogSlots
slots := 1 << logSlots
depth := mParams.Depth(false)
logdSlots := mParams.LogSlots + 1
if logdSlots == mParams.LogN {
logdSlots--
}
roots := computeRoots(slots << 1)
pow5 := make([]int, (slots<<1)+1)
pow5[0] = 1
for i := 1; i < (slots<<1)+1; i++ {
pow5[i] = pow5[i-1] * 5
pow5[i] &= (slots << 2) - 1
}
ctsLevels := mParams.Levels()
scaling := complex(math.Pow(mParams.Scaling, 1.0/float64(mParams.Depth(false))), 0)
// CoeffsToSlots vectors
matrices := make([]ckks.LinearTransform, len(ctsLevels))
pVecDFT := computeDFTMatrices(logSlots, logdSlots, depth, roots, pow5, scaling, mParams.LinearTransformType, mParams.BitReversed)
cnt := 0
trueDepth := mParams.Depth(true)
for i := range mParams.ScalingFactor {
for j := range mParams.ScalingFactor[trueDepth-i-1] {
matrices[cnt] = ckks.GenLinearTransformBSGS(encoder, pVecDFT[cnt], ctsLevels[cnt], mParams.ScalingFactor[trueDepth-i-1][j], mParams.BSGSRatio, logdSlots)
cnt++
}
}
return EncodingMatrix{EncodingMatrixLiteral: mParams, matrices: matrices}
}EvalModLiteral
// Sin and Cos are the two proposed functions for SineType
const (
Sin = SineType(0) // Standard Chebyshev approximation of (1/2pi) * sin(2pix)
Cos1 = SineType(1) // Special approximation (Han and Ki) of pow((1/2pi), 1/2^r) * cos(2pi(x-0.25)/2^r); this method requires a minimum degree of 2*(K-1).
Cos2 = SineType(2) // Standard Chebyshev approximation of pow((1/2pi), 1/2^r) * cos(2pi(x-0.25)/2^r)
)
// EvalModLiteral a struct for the paramters of the EvalMod step
// of the bootstrapping
type EvalModLiteral struct {
Q uint64 // Q to reduce by during EvalMod
LevelStart int // Starting level of EvalMod
ScalingFactor float64 // Scaling factor used during EvalMod
SineType SineType // Chose betwenn [Sin(2*pi*x)] or [cos(2*pi*x/r) with double angle formula]
MessageRatio float64 // Ratio between Q0 and m, i.e. Q[0]/|m|
K int // K parameter (interpolation in the range -K to K)
SineDeg int // Degree of the interpolation
DoubleAngle int // Number of rescale and double angle formula (only applies for cos)
ArcSineDeg int // Degree of the Taylor arcsine composed with f(2*pi*x) (if zero then not used)
}Sine: のChebychev補間Cos1: 2倍角
EncodingMatrix
// LinearTransformType is a type used to distinguish different linear transformations.
type LinearTransformType int
// CoeffsToSlots and SlotsToCoeffs are two linear transformations.
const (
CoeffsToSlots = LinearTransformType(0) // Homomorphic Encoding
SlotsToCoeffs = LinearTransformType(1) // Homomorphic Decoding
)
type EncodingMatrix struct {
EncodingMatrixLiteral
matrices []ckks.LinearTransform
}
// EncodingMatrixLiteral is a struct storing the parameters to generate the factorized DFT matrix.
type EncodingMatrixLiteral struct {
LinearTransformType LinearTransformType
LogN int // log(RingDegree)
LogSlots int // log(slots)
Scaling float64 // constant by which the matrix is multiplied with
LevelStart int // Encoding level
BitReversed bool // Flag for bit-reverseed input to the DFT (with bit-reversed output), by default false.
BSGSRatio float64 // n1/n2 ratio for the bsgs algo for matrix x vector eval
ScalingFactor [][]float64
}- lvl 1 から max level k まで上げる
func (btp *Bootstrapper) Bootstrapp(ctIn *ckks.Ciphertext) (ctOut *ckks.Ciphertext) {Modup
// Step 1 : Extend the basis from q to Q
ctOut = btp.modUpFromQ0(ctOut)lattigo/bootstrap.go at 8df1d3bed79e315f527c1c5fc9704f5df9de0f11 · tuneinsight/lattigo · GitHub
func (btp *Bootstrapper) modUpFromQ0(ct *ckks.Ciphertext) *ckks.Ciphertext {
if btp.swkDtS != nil {
btp.SwitchKeys(ct, btp.swkDtS, ct)
}
ringQ := btp.params.RingQ()
ringP := btp.params.RingP()
for i := range ct.Value {
ringQ.InvNTTLvl(ct.Level(), ct.Value[i], ct.Value[i])
}
// Extend the ciphertext with zero polynomials.
for u := range ct.Value {
ct.Value[u].Coeffs = append(ct.Value[u].Coeffs, make([][]uint64, btp.params.MaxLevel())...)
for i := 1; i < btp.params.MaxLevel()+1; i++ {
ct.Value[u].Coeffs[i] = make([]uint64, btp.params.N())
}
}
levelQ := btp.params.QCount() - 1
levelP := btp.params.PCount() - 1
Q := ringQ.Modulus
P := ringP.Modulus
q := Q[0]
bredparamsQ := ringQ.BredParams
bredparamsP := ringP.BredParams
var coeff, tmp, pos, neg uint64
// ModUp q->Q for ct[0] centered around q
for j := 0; j < btp.params.N(); j++ {
coeff = ct.Value[0].Coeffs[0][j]
pos, neg = 1, 0
if coeff >= (q >> 1) {
coeff = q - coeff
pos, neg = 0, 1
}
for i := 1; i < levelQ+1; i++ {
tmp = ring.BRedAdd(coeff, Q[i], bredparamsQ[i])
ct.Value[0].Coeffs[i][j] = tmp*pos + (Q[i]-tmp)*neg
}
}
if btp.swkStD != nil {
ks := btp.GetKeySwitcher()
// ModUp q->QP for ct[1] centered around q
for j := 0; j < btp.params.N(); j++ {
coeff = ct.Value[1].Coeffs[0][j]
pos, neg = 1, 0
if coeff > (q >> 1) {
coeff = q - coeff
pos, neg = 0, 1
}
for i := 0; i < levelQ+1; i++ {
tmp = ring.BRedAdd(coeff, Q[i], bredparamsQ[i])
ks.BuffDecompQP[0].Q.Coeffs[i][j] = tmp*pos + (Q[i]-tmp)*neg
}
for i := 0; i < levelP+1; i++ {
tmp = ring.BRedAdd(coeff, P[i], bredparamsP[i])
ks.BuffDecompQP[0].P.Coeffs[i][j] = tmp*pos + (P[i]-tmp)*neg
}
}
for i := len(ks.BuffDecompQP) - 1; i >= 0; i-- {
ringQ.NTTLvl(levelQ, ks.BuffDecompQP[0].Q, ks.BuffDecompQP[i].Q)
}
for i := len(ks.BuffDecompQP) - 1; i >= 0; i-- {
ringP.NTTLvl(levelP, ks.BuffDecompQP[0].P, ks.BuffDecompQP[i].P)
}
ringQ.NTTLvl(levelQ, ct.Value[0], ct.Value[0])
ks.KeyswitchHoisted(levelQ, ks.BuffDecompQP, btp.swkStD, ks.BuffQP[1].Q, ct.Value[1], ks.BuffQP[1].P, ks.BuffQP[2].P)
ringQ.AddLvl(levelQ, ct.Value[0], ks.BuffQP[1].Q, ct.Value[0])
} else {
for j := 0; j < btp.params.N(); j++ {
coeff = ct.Value[1].Coeffs[0][j]
pos, neg = 1, 0
if coeff >= (q >> 1) {
coeff = q - coeff
pos, neg = 0, 1
}
for i := 1; i < levelQ+1; i++ {
tmp = ring.BRedAdd(coeff, Q[i], bredparamsQ[i])
ct.Value[1].Coeffs[i][j] = tmp*pos + (Q[i]-tmp)*neg
}
}
ringQ.NTTLvl(levelQ, ct.Value[0], ct.Value[0])
ringQ.NTTLvl(levelQ, ct.Value[1], ct.Value[1])
}
return ct
}Subsum
// SubSum X -> (N/dslots) * Y^dslots
btp.Trace(ctOut, btp.params.LogSlots(), btp.params.LogN()-1, ctOut)// Trace maps X -> sum((-1)^i * X^{i*n+1}) for 0 <= i < N
// For log(n) = logSlotStart and log(N/2) = logSlotsEnd
// Monomial X^k vanishes if k is not divisible by (N/n), else it is multiplied by (N/n).
// Ciphertext is pre-multiplied by (N/n)^-1 to remove the (N/n) factor.
// Examples of full Trace for [0 + 1X + 2X^2 + 3X^3 + 4X^4 + 5X^5 + 6X^6 + 7X^7]
//
// 1) [1 + 2X + 3X^2 + 4X^3 + 5X^4 + 6X^5 + 7X^6 + 8X^7]
// + [1 - 6X - 3X^2 + 8X^3 + 5X^4 + 2X^5 - 7X^6 - 4X^7] {X-> X^(i * 5^1)}
// = [2 - 4X + 0X^2 +12X^3 +10X^4 + 8X^5 - 0X^6 + 4X^7]
//
// 2) [2 - 4X + 0X^2 +12X^3 +10X^4 + 8X^5 - 0X^6 + 4X^7]
// + [2 + 4X + 0X^2 -12X^3 +10X^4 - 8X^5 + 0X^6 - 4X^7] {X-> X^(i * 5^2)}
// = [4 + 0X + 0X^2 - 0X^3 +20X^4 + 0X^5 + 0X^6 - 0X^7]
//
// 3) [4 + 0X + 0X^2 - 0X^3 +20X^4 + 0X^5 + 0X^6 - 0X^7]
// + [4 + 4X + 0X^2 - 0X^3 -20X^4 + 0X^5 + 0X^6 - 0X^7] {X-> X^(i * -1)}
// = [8 + 0X + 0X^2 - 0X^3 + 0X^4 + 0X^5 + 0X^6 - 0X^7]
func (eval *evaluator) Trace(ctIn *Ciphertext, logSlotsStart, logSlotsEnd int, ctOut *Ciphertext) {
levelQ := utils.MinInt(ctIn.Level(), ctOut.Level())
ctOut.Value[0].Coeffs = ctOut.Value[0].Coeffs[:levelQ+1]
ctOut.Value[1].Coeffs = ctOut.Value[1].Coeffs[:levelQ+1]
ctOut.Scale = ctIn.Scale
n := 1 << (logSlotsEnd - logSlotsStart)
if n > 1 {
ringQ := eval.params.RingQ()
// pre-multiplication by (N/n)^-1
for i := 0; i < levelQ+1; i++ {
Q := ringQ.Modulus[i]
bredParams := ringQ.BredParams[i]
mredparams := ringQ.MredParams[i]
invN := ring.ModExp(uint64(n), Q-2, Q)
invN = ring.MForm(invN, Q, bredParams)
ring.MulScalarMontgomeryVec(ctIn.Value[0].Coeffs[i], ctOut.Value[0].Coeffs[i], invN, Q, mredparams)
ring.MulScalarMontgomeryVec(ctIn.Value[1].Coeffs[i], ctOut.Value[1].Coeffs[i], invN, Q, mredparams)
}
for i := logSlotsStart; i < logSlotsEnd; i++ {
eval.permuteNTT(ctOut, eval.params.GaloisElementForColumnRotationBy(1<<i), eval.buffCt)
ctBuff := &Ciphertext{Ciphertext: eval.buffCt.Ciphertext, Scale: ctOut.Scale}
ctBuff.Value = ctBuff.Value[:2]
eval.Add(ctOut, ctBuff, ctOut)
}
} else {
if ctIn != ctOut {
ctOut.Copy(ctIn)
}
}
}coeffsToSlots
lattigo/bootstrap.go at 8df1d3bed79e315f527c1c5fc9704f5df9de0f11 · tuneinsight/lattigo · GitHub
// Step 2 : CoeffsToSlots (Homomorphic encoding)
ctReal, ctImag := btp.CoeffsToSlotsNew(ctOut, btp.ctsMatrices)lattigo/evaluator.go at 8df1d3bed79e315f527c1c5fc9704f5df9de0f11 · tuneinsight/lattigo · GitHub
func (eval *evaluator) CoeffsToSlots(ctIn *ckks.Ciphertext, ctsMatrices EncodingMatrix, ctReal, ctImag *ckks.Ciphertext) {
zV := ctIn.CopyNew()
eval.dft(ctIn, ctsMatrices.matrices, zV)
eval.Conjugate(zV, ctReal)
var tmp *ckks.Ciphertext
if ctImag != nil {
tmp = ctImag
} else {
tmp = ckks.NewCiphertextAtLevelFromPoly(ctReal.Level(), [2]*ring.Poly{eval.BuffCt().Value[0], eval.BuffCt().Value[1]})
}
// Imag part
eval.Sub(zV, ctReal, tmp)
eval.DivByi(tmp, tmp)
// Real part
eval.Add(ctReal, zV, ctReal)
// If repacking, then ct0 and ct1 right n/2 slots are zero.
if eval.params.LogSlots() < eval.params.LogN()-1 {
eval.Rotate(tmp, eval.params.Slots(), tmp)
eval.Add(ctReal, tmp, ctReal)
}
zV = nil
}EvalMod
// Step 3 : EvalMod (Homomorphic modular reduction)
// ctReal = Ecd(real)
// ctImag = Ecd(imag)
// If n < N/2 then ctReal = Ecd(real|imag)
ctReal = btp.EvalModNew(ctReal, btp.evalModPoly)
ctReal.Scale = btp.params.DefaultScale()
if ctImag != nil {
ctImag = btp.EvalModNew(ctImag, btp.evalModPoly)
ctImag.Scale = btp.params.DefaultScale()
}// EvalModNew applies a homomorphic mod Q on a vector scaled by Delta, scaled down to mod 1 :
//
// 1) Delta * (Q/Delta * I(X) + m(X)) (Delta = scaling factor, I(X) integer poly, m(X) message)
// 2) Delta * (I(X) + Delta/Q * m(X)) (divide by Q/Delta)
// 3) Delta * (Delta/Q * m(X)) (x mod 1)
// 4) Delta * (m(X)) (multiply back by Q/Delta)
//
// Since Q is not a power of two, but Delta is, then does an approximate division by the closest
// power of two to Q instead. Hence, it assumes that the input plaintext is already scaled by
// the correcting factor Q/2^{round(log(Q))}.
//
// !! Assumes that the input is normalized by 1/K for K the range of the approximation.
//
// Scaling back error correction by 2^{round(log(Q))}/Q afterward is included in the polynomial
func (eval *evaluator) EvalModNew(ct *ckks.Ciphertext, evalModPoly EvalModPoly) *ckks.Ciphertext {
if ct.Level() < evalModPoly.LevelStart() {
panic("ct.Level() < evalModPoly.LevelStart")
}
if ct.Level() > evalModPoly.LevelStart() {
eval.DropLevel(ct, ct.Level()-evalModPoly.LevelStart())
}
// Stores default scales
prevScaleCt := ct.Scale
// Normalize the modular reduction to mod by 1 (division by Q)
ct.Scale = evalModPoly.scalingFactor
var err error
// Compute the scales that the ciphertext should have before the double angle
// formula such that after it it has the scale it had before the polynomial
// evaluation
targetScale := ct.Scale
for i := 0; i < evalModPoly.doubleAngle; i++ {
targetScale = math.Sqrt(targetScale * eval.params.QiFloat64(evalModPoly.levelStart-evalModPoly.sinePoly.Depth()-evalModPoly.doubleAngle+i+1))
}
// Division by 1/2^r and change of variable for the Chebysehev evaluation
if evalModPoly.sineType == Cos1 || evalModPoly.sineType == Cos2 {
eval.AddConst(ct, -0.5/(evalModPoly.scFac*(evalModPoly.sinePoly.B-evalModPoly.sinePoly.A)), ct)
}
// Chebyshev evaluation
if ct, err = eval.EvaluatePoly(ct, evalModPoly.sinePoly, targetScale); err != nil {
panic(err)
}
// Double angle
sqrt2pi := evalModPoly.sqrt2Pi
for i := 0; i < evalModPoly.doubleAngle; i++ {
sqrt2pi *= sqrt2pi
eval.MulRelin(ct, ct, ct)
eval.Add(ct, ct, ct)
eval.AddConst(ct, -sqrt2pi, ct)
if err := eval.Rescale(ct, targetScale, ct); err != nil {
panic(err)
}
}
// ArcSine
if evalModPoly.arcSinePoly != nil {
if ct, err = eval.EvaluatePoly(ct, evalModPoly.arcSinePoly, ct.Scale); err != nil {
panic(err)
}
}
// Multiplies back by q
ct.Scale = prevScaleCt
return ct
}SlotsToCoeffs
// Step 4 : SlotsToCoeffs (Homomorphic decoding)
ctOut = btp.SlotsToCoeffsNew(ctReal, ctImag, btp.stcMatrices)// SlotsToCoeffsNew applies the homomorphic decoding and returns the result on the provided ciphertext.
// Homomorphically decodes a real vector of size 2n on a complex vector vReal + i*vImag of size n.
// If the packing is sparse (n < N/2) then ctReal = Ecd(vReal || vImag) and ctImag = nil.
// If the packing is dense (n == N/2), then ctReal = Ecd(vReal) and ctImag = Ecd(vImag).
func (eval *evaluator) SlotsToCoeffs(ctReal, ctImag *ckks.Ciphertext, stcMatrices EncodingMatrix, ctOut *ckks.Ciphertext) {
// If full packing, the repacking can be done directly using ct0 and ct1.
if ctImag != nil {
eval.MultByi(ctImag, ctOut)
eval.Add(ctOut, ctReal, ctOut)
eval.dft(ctOut, stcMatrices.matrices, ctOut)
} else {
eval.dft(ctReal, stcMatrices.matrices, ctOut)
}
return
}BootstrappingParams
- lattigo/default_params.go at 8df1d3bed79e315f527c1c5fc9704f5df9de0f11 · tuneinsight/lattigo · GitHub
N16QP1546H192H32
// N16QP1546H192H32 is a default bootstrapping parameters for a main secret with H=192 and an ephemeral secret with H=32.
// Residual Q : 420 bits.
// Precision : 26.6 bits for 2^{15} slots.
// Failure : 2^{-138.7} for 2^{15} slots.
N16QP1546H192H32 = defaultParametersLiteral{
ckks.ParametersLiteral{...},
Parameters{
EphemeralSecretWeight: 32,
SlotsToCoeffsParameters: advanced.EncodingMatrixLiteral{
LinearTransformType: advanced.SlotsToCoeffs,
LevelStart: 12,
BSGSRatio: 2.0,
BitReversed: false,
ScalingFactor: [][]float64{
{0x7fffe60001},
{0x7fffe40001},
{0x7fffe00001},
},
},
EvalModParameters: advanced.EvalModLiteral{
Q: 0x10000000006e0001,
LevelStart: 20,
SineType: advanced.Cos1,
MessageRatio: 256.0,
K: 16,
SineDeg: 30,
DoubleAngle: 3,
ArcSineDeg: 0,
ScalingFactor: 1 << 60,
},
CoeffsToSlotsParameters: advanced.EncodingMatrixLiteral{
LinearTransformType: advanced.CoeffsToSlots,
LevelStart: 24,
BSGSRatio: 2.0,
BitReversed: false,
ScalingFactor: [][]float64{
{0x100000000060001},
{0xfffffffff00001},
{0xffffffffd80001},
{0x1000000002a0001},
},
},
},
},