purify
C++ Purify implementation with native circuit and BPP support
Loading...
Searching...
No Matches
field.c
Go to the documentation of this file.
1// Copyright (c) 2026 Judica, Inc.
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or https://opensource.org/license/mit/.
4
5#include "field.h"
6
7#include <string.h>
8
9static const uint64_t kPurifyFieldPrime[4] = {
10#if defined(PURIFY_CBMC_MODEL_SMALL_FIELD)
11 #include "verification/cbmc/model_small_field_constants.h"
12 PURIFY_CBMC_MODEL_FIELD_PRIME_INIT
13#else
14 UINT64_C(0xBFD25E8CD0364141),
15 UINT64_C(0xBAAEDCE6AF48A03B),
16 UINT64_C(0xFFFFFFFFFFFFFFFE),
17 UINT64_C(0xFFFFFFFFFFFFFFFF),
18#endif
19};
20
21static const uint64_t kPurifyU256One[4] = {
22 UINT64_C(1), UINT64_C(0), UINT64_C(0), UINT64_C(0),
23};
24
28
29void purify_fe_set_u64(purify_fe* out, uint64_t value) {
30 purify_scalar_set_u64(&out->value, value);
31}
32
33void purify_fe_set_i64(purify_fe* out, int64_t value) {
34 if (value >= 0) {
35 purify_fe_set_u64(out, (uint64_t)value);
36 return;
37 }
38
39 purify_fe_set_u64(out, (uint64_t)(-(value + 1)) + 1u);
40 purify_fe_negate(out, out);
41}
42
43int purify_fe_set_b32(purify_fe* out, const unsigned char input32[32]) {
44 int overflow = 0;
45 purify_scalar_set_b32(&out->value, input32, &overflow);
46 return overflow == 0;
47}
48
49int purify_fe_set_u256(purify_fe* out, const uint64_t value[4]) {
50 unsigned char bytes[32];
51 purify_u256_to_bytes_be(bytes, value);
52 return purify_fe_set_b32(out, bytes);
53}
54
55void purify_fe_get_b32(unsigned char output32[32], const purify_fe* value) {
56 purify_scalar_get_b32(output32, &value->value);
57}
58
59void purify_fe_get_u256(uint64_t out[4], const purify_fe* value) {
60 unsigned char bytes[32];
61 purify_fe_get_b32(bytes, value);
62 purify_u256_from_bytes_be(out, bytes, sizeof(bytes));
63}
64
65int purify_fe_is_zero(const purify_fe* value) {
66 return purify_scalar_is_zero(&value->value);
67}
68
69int purify_fe_is_one(const purify_fe* value) {
70 return purify_scalar_is_one(&value->value);
71}
72
73int purify_fe_is_odd(const purify_fe* value) {
74 return purify_scalar_is_even(&value->value) == 0;
75}
76
77int purify_fe_eq(const purify_fe* lhs, const purify_fe* rhs) {
78 return purify_scalar_eq(&lhs->value, &rhs->value);
79}
80
81void purify_fe_negate(purify_fe* out, const purify_fe* value) {
82 purify_fe input = *value;
83 purify_scalar_negate(&out->value, &input.value);
84}
85
86void purify_fe_cmov(purify_fe* dst, const purify_fe* src, int flag) {
87 purify_scalar_cmov(&dst->value, &src->value, flag);
88}
89
90void purify_fe_inverse(purify_fe* out, const purify_fe* value) {
91 purify_fe input = *value;
92 purify_scalar_inverse(&out->value, &input.value);
93}
94
95void purify_fe_inverse_var(purify_fe* out, const purify_fe* value) {
96 purify_fe input = *value;
98}
99
100void purify_fe_add(purify_fe* out, const purify_fe* lhs, const purify_fe* rhs) {
101 purify_fe left = *lhs;
102 purify_fe right = *rhs;
103 purify_scalar_add(&out->value, &left.value, &right.value);
104}
105
106void purify_fe_sub(purify_fe* out, const purify_fe* lhs, const purify_fe* rhs) {
107 purify_fe negated;
108 purify_fe_negate(&negated, rhs);
109 purify_fe_add(out, lhs, &negated);
110}
111
112void purify_fe_mul(purify_fe* out, const purify_fe* lhs, const purify_fe* rhs) {
113 purify_fe left = *lhs;
114 purify_fe right = *rhs;
115 purify_scalar_mul(&out->value, &left.value, &right.value);
116}
117
118void purify_fe_square(purify_fe* out, const purify_fe* value) {
119 purify_fe_mul(out, value, value);
120}
121
122void purify_fe_pow(purify_fe* out, const purify_fe* value, const uint64_t exponent[4]) {
123 purify_fe result;
124 size_t bits;
125 size_t i;
126
127 purify_fe_set_u64(&result, 1);
128 bits = purify_u256_bit_length(exponent);
129 for (i = bits; i != 0; --i) {
130 size_t idx = i - 1u;
131 purify_fe_square(&result, &result);
132 if (purify_u256_bit(exponent, idx) != 0) {
133 purify_fe_mul(&result, &result, value);
134 }
135 }
136 *out = result;
137}
138
140 uint64_t exponent[4];
141 purify_fe result;
142
143 if (purify_fe_is_zero(value) != 0) {
144 return 1;
145 }
146
147 memcpy(exponent, kPurifyFieldPrime, sizeof(exponent));
148 purify_u256_try_sub(exponent, kPurifyU256One);
149 purify_u256_shift_right_one(exponent);
150 purify_fe_pow(&result, value, exponent);
151 return purify_fe_is_one(&result);
152}
153
155 if (purify_fe_is_zero(value) != 0) {
156 return 0;
157 }
158 return purify_fe_is_square(value) != 0 ? 1 : -1;
159}
160
161int purify_fe_sqrt(purify_fe* out, const purify_fe* value) {
162 uint64_t q[4];
163 unsigned int s = 0;
164 purify_fe z;
165 purify_fe c;
166 purify_fe x;
167 purify_fe t;
168 purify_fe one;
169
170 if (purify_fe_is_zero(value) != 0) {
172 return 1;
173 }
174 if (purify_fe_is_square(value) == 0) {
175 return 0;
176 }
177
178 memcpy(q, kPurifyFieldPrime, sizeof(q));
179 purify_u256_try_sub(q, kPurifyU256One);
180 while (purify_u256_bit(q, 0) == 0) {
181 purify_u256_shift_right_one(q);
182 ++s;
183 }
184
185 if (s == 1u) {
186 uint64_t exponent[4];
187 memcpy(exponent, q, sizeof(exponent));
188 purify_u256_try_add_small(exponent, 1);
189 purify_u256_shift_right_one(exponent);
190 purify_fe_pow(out, value, exponent);
191 return 1;
192 }
193
194 purify_fe_set_u64(&z, 2);
195 while (purify_fe_legendre_symbol(&z) != -1) {
196 purify_fe next_z;
197 purify_fe_set_u64(&one, 1);
198 purify_fe_add(&next_z, &z, &one);
199 z = next_z;
200 }
201
202 purify_fe_pow(&c, &z, q);
203
204 {
205 uint64_t exponent[4];
206 memcpy(exponent, q, sizeof(exponent));
207 purify_u256_try_add_small(exponent, 1);
208 purify_u256_shift_right_one(exponent);
209 purify_fe_pow(&x, value, exponent);
210 }
211
212 purify_fe_pow(&t, value, q);
213 purify_fe_set_u64(&one, 1);
214
215 while (purify_fe_eq(&t, &one) == 0) {
216 unsigned int i = 1;
217 unsigned int m = s;
218 purify_fe t2i;
219
220 purify_fe_square(&t2i, &t);
221 while (i < m && purify_fe_eq(&t2i, &one) == 0) {
222 purify_fe_square(&t2i, &t2i);
223 ++i;
224 }
225 if (i == m) {
226 return 0;
227 }
228
229 {
230 uint64_t b_exp[4];
231 uint64_t shifted[4];
232 purify_fe b;
233 purify_fe b2;
234
235 purify_u256_set_u64(b_exp, 1);
236 purify_u256_shifted_left(shifted, b_exp, m - i - 1u);
237 memcpy(b_exp, shifted, sizeof(b_exp));
238 purify_fe_pow(&b, &c, b_exp);
239 purify_fe_mul(&x, &x, &b);
240 purify_fe_square(&b2, &b);
241 purify_fe_mul(&t, &t, &b2);
242 c = b2;
243 s = i;
244 }
245 }
246
247 *out = x;
248 return 1;
249}
int purify_fe_is_square(const purify_fe *value)
Definition field.c:139
int purify_fe_legendre_symbol(const purify_fe *value)
Definition field.c:154
void purify_fe_set_zero(purify_fe *out)
Definition field.c:25
int purify_fe_set_u256(purify_fe *out, const uint64_t value[4])
Definition field.c:49
void purify_fe_inverse(purify_fe *out, const purify_fe *value)
Definition field.c:90
int purify_fe_sqrt(purify_fe *out, const purify_fe *value)
Definition field.c:161
static const uint64_t kPurifyU256One[4]
Definition field.c:21
static const uint64_t kPurifyFieldPrime[4]
Definition field.c:9
int purify_fe_is_zero(const purify_fe *value)
Definition field.c:65
void purify_fe_pow(purify_fe *out, const purify_fe *value, const uint64_t exponent[4])
Definition field.c:122
int purify_fe_is_one(const purify_fe *value)
Definition field.c:69
void purify_fe_inverse_var(purify_fe *out, const purify_fe *value)
Definition field.c:95
void purify_fe_get_b32(unsigned char output32[32], const purify_fe *value)
Definition field.c:55
void purify_fe_mul(purify_fe *out, const purify_fe *lhs, const purify_fe *rhs)
Definition field.c:112
void purify_fe_square(purify_fe *out, const purify_fe *value)
Definition field.c:118
void purify_fe_add(purify_fe *out, const purify_fe *lhs, const purify_fe *rhs)
Definition field.c:100
void purify_fe_sub(purify_fe *out, const purify_fe *lhs, const purify_fe *rhs)
Definition field.c:106
int purify_fe_set_b32(purify_fe *out, const unsigned char input32[32])
Definition field.c:43
void purify_fe_set_i64(purify_fe *out, int64_t value)
Definition field.c:33
void purify_fe_cmov(purify_fe *dst, const purify_fe *src, int flag)
Definition field.c:86
void purify_fe_get_u256(uint64_t out[4], const purify_fe *value)
Definition field.c:59
int purify_fe_eq(const purify_fe *lhs, const purify_fe *rhs)
Definition field.c:77
void purify_fe_set_u64(purify_fe *out, uint64_t value)
Definition field.c:29
int purify_fe_is_odd(const purify_fe *value)
Definition field.c:73
void purify_fe_negate(purify_fe *out, const purify_fe *value)
Definition field.c:81
void purify_scalar_mul(purify_scalar *out, const purify_scalar *lhs, const purify_scalar *rhs)
Multiplies two scalars modulo the backend field.
int purify_scalar_is_zero(const purify_scalar *value)
Returns nonzero when the scalar is zero.
int purify_scalar_add(purify_scalar *out, const purify_scalar *lhs, const purify_scalar *rhs)
Adds two scalars modulo the backend field.
void purify_scalar_set_int(purify_scalar *out, unsigned int value)
Initializes a scalar from an unsigned integer.
void purify_scalar_cmov(purify_scalar *dst, const purify_scalar *src, int flag)
Conditionally assigns src into dst when flag is nonzero.
int purify_scalar_is_even(const purify_scalar *value)
Returns nonzero when the scalar is even.
int purify_scalar_is_one(const purify_scalar *value)
Returns nonzero when the scalar is one.
void purify_scalar_inverse(purify_scalar *out, const purify_scalar *value)
Computes the multiplicative inverse of a scalar in constant time.
void purify_scalar_inverse_var(purify_scalar *out, const purify_scalar *value)
Computes the multiplicative inverse of a scalar.
int purify_scalar_eq(const purify_scalar *lhs, const purify_scalar *rhs)
Returns nonzero when two scalars are equal.
void purify_scalar_negate(purify_scalar *out, const purify_scalar *value)
Computes the additive inverse of a scalar.
void purify_scalar_set_u64(purify_scalar *out, uint64_t value)
Initializes a scalar from a 64-bit unsigned integer.
void purify_scalar_get_b32(unsigned char output32[32], const purify_scalar *value)
Serializes a scalar as 32 big-endian bytes.
void purify_scalar_set_b32(purify_scalar *out, const unsigned char input32[32], int *overflow)
Parses a big-endian 32-byte scalar.
purify_scalar value
Definition field.h:17