Longfellow ZK 0290cb32
Loading...
Searching...
No Matches
fp2.h
1// Copyright 2025 Google LLC.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#ifndef PRIVACY_PROOFS_ZK_LIB_ALGEBRA_FP2_H_
16#define PRIVACY_PROOFS_ZK_LIB_ALGEBRA_FP2_H_
17
18#include <stddef.h>
19
20#include <cstdint>
21#include <optional>
22
23#include "util/panic.h"
24
25namespace proofs {
26// Fields of the form a+sqrt(r)*b where a, b \in Fp and
27// r is a quadratic nonresidue in Fp. The special "complex"
28// case r = -1 allows for a faster implementation of multiplication.
29//
30// With slight abuse of terminology, we call "a" the "real" part and
31// "b" the "imaginary" part, and we call the sqrt(r) "i" even when
32// r != -1.
33template <class Field, bool nonresidue_is_mone = true>
34class Fp2 {
35 public:
36 using Scalar = typename Field::Elt;
37 using BaseField = Field;
38 using TypeTag = typename Field::TypeTag;
39
40 // size of the serialization into bytes
41 static constexpr size_t kBytes = 2 * Field::kBytes;
42 static constexpr size_t kBits = 2 * Field::kBits;
43 static constexpr size_t kSubFieldBytes = Field::kBytes;
44 static constexpr bool kCharacteristicTwo = false;
45 const Field& f_;
46
47 struct Elt {
48 Scalar re, im;
49 bool operator==(const Elt& y) const { return re == y.re && im == y.im; }
50 bool operator!=(const Elt& y) const { return !operator==(y); }
51 };
52
53 explicit Fp2(const Field& F, const Scalar& nonresidue)
54 : f_(F), nonresidue_(nonresidue) {
55 if (nonresidue_is_mone) {
56 check(nonresidue == F.mone(), "nonresidue == F.mone()");
57 } else {
58 check(nonresidue != F.mone(), "nonresidue != F.mone()");
59 }
60
61 i_ = Elt{f_.zero(), f_.one()};
62 for (uint64_t i = 0; i < sizeof(k_) / sizeof(k_[0]); ++i) {
63 k_[i] = of_scalar(i);
64 }
65 khalf_ = Elt{f_.half(), f_.zero()};
66 kmone_ = Elt{f_.mone(), f_.zero()};
67 }
68 explicit Fp2(const Field& F) : Fp2(F, F.mone()) {}
69
70 Fp2(const Fp2&) = delete;
71 Fp2& operator=(const Fp2&) = delete;
72
73 const Field& base_field() const { return f_; }
74
75 Scalar real(const Elt& e) const { return e.re; }
76 bool is_real(const Elt& e) const { return e.im == f_.zero(); }
77
78 void add(Elt& a, const Elt& y) const {
79 f_.add(a.re, y.re);
80 f_.add(a.im, y.im);
81 }
82 void sub(Elt& a, const Elt& y) const {
83 f_.sub(a.re, y.re);
84 f_.sub(a.im, y.im);
85 }
86 void mul(Elt& a, const Elt& y) const {
87 auto p0 = f_.mulf(a.re, y.re);
88 auto p1 = f_.mulf(a.im, y.im);
89 auto a01 = f_.addf(a.re, a.im);
90 auto y01 = f_.addf(y.re, y.im);
91 if (nonresidue_is_mone) {
92 a.re = f_.subf(p0, p1);
93 } else {
94 a.re = f_.addf(p0, f_.mulf(p1, nonresidue_));
95 }
96 f_.mul(a01, y01);
97 f_.sub(a01, p0);
98 f_.sub(a01, p1);
99 a.im = a01;
100 }
101 void mul(Elt& a, const Scalar& y) const {
102 f_.mul(a.re, y);
103 f_.mul(a.im, y);
104 }
105 void neg(Elt& x) const {
106 Elt y(k_[0]);
107 sub(y, x);
108 x = y;
109 }
110 void conj(Elt& x) const { f_.neg(x.im); }
111 void invert(Elt& x) const {
112 Scalar denom;
113 if (nonresidue_is_mone) {
114 denom = f_.addf(f_.mulf(x.re, x.re), f_.mulf(x.im, x.im));
115 } else {
116 denom = f_.subf(f_.mulf(x.re, x.re),
117 f_.mulf(nonresidue_, f_.mulf(x.im, x.im)));
118 }
119 f_.invert(denom);
120 conj(x);
121 mul(x, denom);
122 }
123
124 // functional interface
125 Elt addf(Elt a, const Elt& y) const {
126 add(a, y);
127 return a;
128 }
129 Elt subf(Elt a, const Elt& y) const {
130 sub(a, y);
131 return a;
132 }
133 Elt mulf(Elt a, const Elt& y) const {
134 mul(a, y);
135 return a;
136 }
137 Elt mulf(Elt a, const Scalar& y) const {
138 mul(a, y);
139 return a;
140 }
141 Elt negf(Elt a) const {
142 neg(a);
143 return a;
144 }
145 Elt invertf(Elt a) const {
146 invert(a);
147 return a;
148 }
149 Elt conjf(Elt a) const {
150 conj(a);
151 return a;
152 }
153
154 Elt of_scalar(uint64_t a) const { return of_scalar_field(a); }
155 Elt of_scalar(const Scalar& e) const { return of_scalar_field(e); }
156
157 Elt of_scalar_field(const Scalar& e) const { return Elt{e, f_.zero()}; }
158 Elt of_scalar_field(uint64_t a) const {
159 return Elt{f_.of_scalar(a), f_.zero()};
160 }
161 Elt of_scalar_field(uint64_t ar, uint64_t ai) const {
162 return Elt{f_.of_scalar(ar), f_.of_scalar(ai)};
163 }
164
165 template <size_t N>
166 Elt of_string(const char (&s)[N]) const {
167 return Elt{f_.of_string(s), f_.zero()};
168 }
169
170 template <size_t NR, size_t NI>
171 Elt of_string(const char (&sr)[NR], const char (&si)[NI]) const {
172 return Elt{f_.of_string(sr), f_.of_string(si)};
173 }
174
175 std::optional<Elt> of_bytes_field(const uint8_t ab[/* kBytes */]) const {
176 if (auto re = f_.of_bytes_field(ab)) {
177 if (auto im = f_.of_bytes_field(ab + Field::kBytes)) {
178 return Elt{re.value(), im.value()};
179 }
180 }
181 return std::nullopt;
182 }
183
184 void to_bytes_field(uint8_t ab[/* kBytes */], const Elt& x) const {
185 f_.to_bytes_field(ab, x.re);
186 f_.to_bytes_field(ab + Field::kBytes, x.im);
187 }
188
189 bool in_subfield(const Elt& e) const { return is_real(e); }
190
191 std::optional<Elt> of_bytes_subfield(
192 const uint8_t ab[/* kSubFieldBytes */]) const {
193 if (auto re = f_.of_bytes_subfield(ab)) {
194 return of_scalar(re.value());
195 }
196 return std::nullopt;
197 }
198
199 void to_bytes_subfield(uint8_t ab[/* kSubFieldBytes */], const Elt& x) const {
200 check(in_subfield(x), "x not in subfield");
201 f_.to_bytes_subfield(ab, x.re);
202 }
203
204 const Elt& zero() const { return k_[0]; }
205 const Elt& one() const { return k_[1]; }
206 const Elt& two() const { return k_[2]; }
207 const Elt& half() const { return khalf_; }
208 const Elt& mone() const { return kmone_; }
209 const Elt& i() const { return i_; }
210 Elt poly_evaluation_point(size_t i) const {
211 return of_scalar(f_.poly_evaluation_point(i));
212 }
213 Elt newton_denominator(size_t k, size_t i) const {
214 return of_scalar(f_.newton_denominator(k, i));
215 }
216
217 private:
218 Scalar nonresidue_;
219 Elt k_[3]; // small constants
220 Elt i_; // i^2 = -1
221 Elt khalf_;
222 Elt kmone_;
223};
224} // namespace proofs
225
226#endif // PRIVACY_PROOFS_ZK_LIB_ALGEBRA_FP2_H_
Definition fp2.h:47
Definition gf2_128.h:63