forked from tuneinsight/lattigo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
conjugate_invariant.go
74 lines (59 loc) · 2.54 KB
/
conjugate_invariant.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package ring
import (
"github.com/jzhchu/lattigo/utils"
)
// UnfoldConjugateInvariantToStandard maps the compressed representation (N/2 coefficients)
// of Z_Q[X+X^-1]/(X^2N + 1) to full representation in Z_Q[X]/(X^2N+1).
// Requires degree(polyConjugateInvariant) = 2*degree(polyStd).
// Requires that polyStd and polyConjugateInvariant share the same moduli.
func (r *Ring) UnfoldConjugateInvariantToStandard(level int, polyConjugateInvariant, polyStd *Poly) {
if 2*len(polyConjugateInvariant.Coeffs[0]) != len(polyStd.Coeffs[0]) {
panic("cannot UnfoldConjugateInvariantToStandard: Ring degree of polyConjugateInvariant must be twice the ring degree of polyStd")
}
N := len(polyConjugateInvariant.Coeffs[0])
for i := 0; i < level+1; i++ {
tmp2, tmp1 := polyStd.Coeffs[i], polyConjugateInvariant.Coeffs[i]
copy(tmp2, tmp1)
for idx, jdx := N-1, N; jdx < 2*N; idx, jdx = idx-1, jdx+1 {
tmp2[jdx] = tmp1[idx]
}
}
}
// FoldStandardToConjugateInvariant folds [X]/(X^N+1) to [X+X^-1]/(X^N+1) in compressed form (N/2 coefficients).
// Requires degree(polyConjugateInvariant) = 2*degree(polyStd).
// Requires that polyStd and polyConjugateInvariant share the same moduli.
func (r *Ring) FoldStandardToConjugateInvariant(level int, polyStandard *Poly, permuteNTTIndexInv []uint64, polyConjugateInvariant *Poly) {
if len(polyStandard.Coeffs[0]) != 2*len(polyConjugateInvariant.Coeffs[0]) {
panic("cannot FoldStandardToConjugateInvariant: Ring degree of p2 must be 2N and ring degree of p1 must be N")
}
r.PermuteNTTWithIndexLvl(level, polyStandard, permuteNTTIndexInv, polyConjugateInvariant)
for i := 0; i < level+1; i++ {
AddVec(polyConjugateInvariant.Coeffs[i][:r.N], polyStandard.Coeffs[i][:r.N], polyConjugateInvariant.Coeffs[i][:r.N], r.Modulus[i])
}
}
// PadDefaultRingToConjugateInvariant converts a polynomial in Z[X]/(X^N +1) to a polynomial in Z[X+X^-1]/(X^2N+1).
func PadDefaultRingToConjugateInvariant(p1 *Poly, ringQ *Ring, IsNTT bool, p2 *Poly) {
if p1 == p2 {
panic("cannot PadDefaultRingToConjugateInvariant: p1 == p2 but method cannot be used in place")
}
level := utils.MinInt(p1.Level(), p2.Level())
n := len(p1.Coeffs[0])
for i := 0; i < level+1; i++ {
qi := ringQ.Modulus[i]
if len(p2.Coeffs[i]) != 2*len(p1.Coeffs[i]) {
panic("cannot PadDefaultRingToConjugateInvariant: p2 degree must be twice the one of p1")
}
copy(p2.Coeffs[i], p1.Coeffs[i])
tmp := p2.Coeffs[i]
if IsNTT {
for j := 0; j < n; j++ {
tmp[n-j-1] = tmp[j]
}
} else {
tmp[0] = 0
for j := 1; j < n; j++ {
tmp[n-j] = qi - tmp[j]
}
}
}
}