main
1// Package fp448 provides prime field arithmetic over GF(2^448-2^224-1).
2package fp448
3
4import (
5 "errors"
6
7 "github.com/cloudflare/circl/internal/conv"
8)
9
10// Size in bytes of an element.
11const Size = 56
12
13// Elt is a prime field element.
14type Elt [Size]byte
15
16func (e Elt) String() string { return conv.BytesLe2Hex(e[:]) }
17
18// p is the prime modulus 2^448-2^224-1.
19var p = Elt{
20 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
21 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
22 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
23 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff,
24 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
25 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
26 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
27}
28
29// P returns the prime modulus 2^448-2^224-1.
30func P() Elt { return p }
31
32// ToBytes stores in b the little-endian byte representation of x.
33func ToBytes(b []byte, x *Elt) error {
34 if len(b) != Size {
35 return errors.New("wrong size")
36 }
37 Modp(x)
38 copy(b, x[:])
39 return nil
40}
41
42// IsZero returns true if x is equal to 0.
43func IsZero(x *Elt) bool { Modp(x); return *x == Elt{} }
44
45// IsOne returns true if x is equal to 1.
46func IsOne(x *Elt) bool { Modp(x); return *x == Elt{1} }
47
48// SetOne assigns x=1.
49func SetOne(x *Elt) { *x = Elt{1} }
50
51// One returns the 1 element.
52func One() (x Elt) { x = Elt{1}; return }
53
54// Neg calculates z = -x.
55func Neg(z, x *Elt) { Sub(z, &p, x) }
56
57// Modp ensures that z is between [0,p-1].
58func Modp(z *Elt) { Sub(z, z, &p) }
59
60// InvSqrt calculates z = sqrt(x/y) iff x/y is a quadratic-residue. If so,
61// isQR = true; otherwise, isQR = false, since x/y is a quadratic non-residue,
62// and z = sqrt(-x/y).
63func InvSqrt(z, x, y *Elt) (isQR bool) {
64 // First note that x^(2(k+1)) = x^(p-1)/2 * x = legendre(x) * x
65 // so that's x if x is a quadratic residue and -x otherwise.
66 // Next, y^(6k+3) = y^(4k+2) * y^(2k+1) = y^(p-1) * y^((p-1)/2) = legendre(y).
67 // So the z we compute satisfies z^2 y = x^(2(k+1)) y^(6k+3) = legendre(x)*legendre(y).
68 // Thus if x and y are quadratic residues, then z is indeed sqrt(x/y).
69 t0, t1 := &Elt{}, &Elt{}
70 Mul(t0, x, y) // x*y
71 Sqr(t1, y) // y^2
72 Mul(t1, t0, t1) // x*y^3
73 powPminus3div4(z, t1) // (x*y^3)^k
74 Mul(z, z, t0) // z = x*y*(x*y^3)^k = x^(k+1) * y^(3k+1)
75
76 // Check if x/y is a quadratic residue
77 Sqr(t0, z) // z^2
78 Mul(t0, t0, y) // y*z^2
79 Sub(t0, t0, x) // y*z^2-x
80 return IsZero(t0)
81}
82
83// Inv calculates z = 1/x mod p.
84func Inv(z, x *Elt) {
85 // Calculates z = x^(4k+1) = x^(p-3+1) = x^(p-2) = x^-1, where k = (p-3)/4.
86 t := &Elt{}
87 powPminus3div4(t, x) // t = x^k
88 Sqr(t, t) // t = x^2k
89 Sqr(t, t) // t = x^4k
90 Mul(z, t, x) // z = x^(4k+1)
91}
92
93// powPminus3div4 calculates z = x^k mod p, where k = (p-3)/4.
94func powPminus3div4(z, x *Elt) {
95 x0, x1 := &Elt{}, &Elt{}
96 Sqr(z, x)
97 Mul(z, z, x)
98 Sqr(x0, z)
99 Mul(x0, x0, x)
100 Sqr(z, x0)
101 Sqr(z, z)
102 Sqr(z, z)
103 Mul(z, z, x0)
104 Sqr(x1, z)
105 for i := 0; i < 5; i++ {
106 Sqr(x1, x1)
107 }
108 Mul(x1, x1, z)
109 Sqr(z, x1)
110 for i := 0; i < 11; i++ {
111 Sqr(z, z)
112 }
113 Mul(z, z, x1)
114 Sqr(z, z)
115 Sqr(z, z)
116 Sqr(z, z)
117 Mul(z, z, x0)
118 Sqr(x1, z)
119 for i := 0; i < 26; i++ {
120 Sqr(x1, x1)
121 }
122 Mul(x1, x1, z)
123 Sqr(z, x1)
124 for i := 0; i < 53; i++ {
125 Sqr(z, z)
126 }
127 Mul(z, z, x1)
128 Sqr(z, z)
129 Sqr(z, z)
130 Sqr(z, z)
131 Mul(z, z, x0)
132 Sqr(x1, z)
133 for i := 0; i < 110; i++ {
134 Sqr(x1, x1)
135 }
136 Mul(x1, x1, z)
137 Sqr(z, x1)
138 Mul(z, z, x)
139 for i := 0; i < 223; i++ {
140 Sqr(z, z)
141 }
142 Mul(z, z, x1)
143}
144
145// Cmov assigns y to x if n is 1.
146func Cmov(x, y *Elt, n uint) { cmov(x, y, n) }
147
148// Cswap interchanges x and y if n is 1.
149func Cswap(x, y *Elt, n uint) { cswap(x, y, n) }
150
151// Add calculates z = x+y mod p.
152func Add(z, x, y *Elt) { add(z, x, y) }
153
154// Sub calculates z = x-y mod p.
155func Sub(z, x, y *Elt) { sub(z, x, y) }
156
157// AddSub calculates (x,y) = (x+y mod p, x-y mod p).
158func AddSub(x, y *Elt) { addsub(x, y) }
159
160// Mul calculates z = x*y mod p.
161func Mul(z, x, y *Elt) { mul(z, x, y) }
162
163// Sqr calculates z = x^2 mod p.
164func Sqr(z, x *Elt) { sqr(z, x) }