purify
C++ Purify implementation with native circuit and BPP support
Loading...
Searching...
No Matches
expr.hpp
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
10#pragma once
11
12#include <cstdint>
13#include <map>
14#include <optional>
15#include <set>
16#include <string>
17#include <type_traits>
18#include <utility>
19#include <vector>
20
21#include "purify/numeric.hpp"
22
23namespace purify {
24
26enum class SymbolKind : std::uint8_t {
27 Witness = 0,
28 Left = 1,
29 Right = 2,
30 Output = 3,
31 Commitment = 4,
32};
33
35struct Symbol {
37 std::uint32_t index = 0;
38
39 static Symbol witness(std::uint32_t index);
40 static Symbol left(std::uint32_t index);
41 static Symbol right(std::uint32_t index);
42 static Symbol output(std::uint32_t index);
43 static Symbol commitment(std::uint32_t index);
44
45 std::string to_string() const;
46 bool operator==(const Symbol&) const = default;
47};
48
49struct SymbolLess {
50 bool operator()(const Symbol& lhs, const Symbol& rhs) const noexcept {
51 using SymbolRank = std::underlying_type_t<SymbolKind>;
52 const SymbolRank lhs_kind = static_cast<SymbolRank>(lhs.kind);
53 const SymbolRank rhs_kind = static_cast<SymbolRank>(rhs.kind);
54 return lhs_kind < rhs_kind || (lhs_kind == rhs_kind && lhs.index < rhs.index);
55 }
56};
57
58inline bool operator<(const Symbol& lhs, const Symbol& rhs) noexcept {
59 return SymbolLess{}(lhs, rhs);
60}
61
63using WitnessAssignments = std::vector<std::optional<FieldElement>>;
64
71class Expr {
72public:
73 using Term = std::pair<Symbol, FieldElement>;
74
76 Expr();
78 explicit Expr(const FieldElement& value);
80 explicit Expr(std::int64_t value);
81
83 static Expr variable(Symbol symbol);
84
86 const FieldElement& constant() const {
87 return constant_;
88 }
89
91 std::vector<Term>& linear() {
92 return linear_;
93 }
94
96 const std::vector<Term>& linear() const {
97 return linear_;
98 }
99
101 friend Expr operator+(const Expr& lhs, const Expr& rhs);
102
104 friend Expr operator+(const Expr& lhs, std::int64_t rhs);
105
107 friend Expr operator+(std::int64_t lhs, const Expr& rhs);
108
110 friend Expr operator-(const Expr& lhs, const Expr& rhs);
111
113 friend Expr operator-(const Expr& lhs, std::int64_t rhs);
114
116 friend Expr operator-(std::int64_t lhs, const Expr& rhs);
117
119 friend Expr operator-(const Expr& value);
120
122 friend Expr operator*(const Expr& expr, const FieldElement& scalar);
123
125 friend Expr operator*(const FieldElement& scalar, const Expr& expr);
126
128 friend Expr operator*(const Expr& expr, std::int64_t scalar);
129
131 friend Expr operator*(std::int64_t scalar, const Expr& expr);
132
134 friend bool operator==(const Expr& lhs, const Expr& rhs);
135
137 friend bool operator<(const Expr& lhs, const Expr& rhs);
138
140 std::string to_string() const;
141
143 std::optional<FieldElement> evaluate(const WitnessAssignments& values) const;
144
146 std::pair<Expr, Expr> split() const;
147
148private:
150 void push_term(const Term& term);
151
152 FieldElement constant_;
153 std::vector<Term> linear_;
154};
155
156struct ExprLess {
157 bool operator()(const Expr& lhs, const Expr& rhs) const;
158};
159
161 bool operator()(const std::pair<Expr, Expr>& lhs, const std::pair<Expr, Expr>& rhs) const;
162};
163
171public:
173 static ExprBuilder reserved(std::size_t terms);
174
176 ExprBuilder& reserve(std::size_t terms);
177
179 ExprBuilder& add(const FieldElement& value);
180
182 ExprBuilder& add(std::int64_t value);
183
185 ExprBuilder& add_term(Symbol symbol, const FieldElement& scale);
186
188 ExprBuilder& add(const Expr& expr);
189
191 ExprBuilder& subtract(const Expr& expr);
192
194 ExprBuilder& add_scaled(const Expr& expr, const FieldElement& scale);
195
197 ExprBuilder& add_scaled(const Expr& expr, std::int64_t scale);
198
200 Expr build();
201
202private:
203 FieldElement constant_ = FieldElement::zero();
204 std::vector<Expr::Term> terms_;
205};
206
208std::ostream& operator<<(std::ostream& out, const Expr& expr);
209
214public:
216 Expr secret(const std::optional<FieldElement>& value);
217
219 Expr mul(const Expr& lhs, const Expr& rhs);
220
222 Expr div(const Expr& lhs, const Expr& rhs);
223
225 Expr boolean(const Expr& expr);
226
228 void equal(const Expr& lhs, const Expr& rhs);
229
231 std::optional<FieldElement> evaluate(const Expr& expr) const;
232
234 const WitnessAssignments& varmap() const {
235 return varmap_;
236 }
237
244
246 const std::vector<MulConstraint>& muls() const {
247 return muls_;
248 }
249
251 const std::vector<Expr>& eqs() const {
252 return eqs_;
253 }
254
255private:
256 WitnessAssignments varmap_;
257 std::vector<MulConstraint> muls_;
258 std::map<std::pair<Expr, Expr>, Expr, ExprPairLess> mul_cache_;
259 std::map<std::pair<Expr, Expr>, Expr, ExprPairLess> div_cache_;
260 std::set<Expr, ExprLess> bool_cache_;
261 std::vector<Expr> eqs_;
262};
263
264Expr operator+(const Expr& lhs, const Expr& rhs);
265Expr operator+(const Expr& lhs, std::int64_t rhs);
266Expr operator+(std::int64_t lhs, const Expr& rhs);
267Expr operator-(const Expr& lhs, const Expr& rhs);
268Expr operator-(const Expr& lhs, std::int64_t rhs);
269Expr operator-(std::int64_t lhs, const Expr& rhs);
270Expr operator-(const Expr& value);
271Expr operator*(const Expr& expr, const FieldElement& scalar);
272Expr operator*(const FieldElement& scalar, const Expr& expr);
273Expr operator*(const Expr& expr, std::int64_t scalar);
274Expr operator*(std::int64_t scalar, const Expr& expr);
275bool operator==(const Expr& lhs, const Expr& rhs);
276bool operator<(const Expr& lhs, const Expr& rhs);
277
278} // namespace purify
Small runtime builder that flattens affine combinations into one expression.
Definition expr.hpp:170
ExprBuilder & add(const FieldElement &value)
Adds a constant field term to the pending affine expression.
Definition expr.cpp:171
ExprBuilder & add_term(Symbol symbol, const FieldElement &scale)
Adds one scaled symbolic variable term.
Definition expr.cpp:180
static ExprBuilder reserved(std::size_t terms)
Returns a builder with storage reserved for approximately terms linear slots.
Definition expr.cpp:160
Expr build()
Materializes the flattened affine expression.
Definition expr.cpp:242
ExprBuilder & add_scaled(const Expr &expr, const FieldElement &scale)
Adds an existing expression scaled by a field element.
Definition expr.cpp:214
ExprBuilder & subtract(const Expr &expr)
Subtracts an existing expression with implicit coefficient minus one.
Definition expr.cpp:199
ExprBuilder & reserve(std::size_t terms)
Reserves storage for approximately terms linear slots.
Definition expr.cpp:166
Symbolic affine expression over indexed variables and field coefficients.
Definition expr.hpp:71
friend bool operator==(const Expr &lhs, const Expr &rhs)
Compares two affine expressions structurally.
Definition expr.cpp:335
friend Expr operator*(const Expr &expr, const FieldElement &scalar)
Scales an affine expression by a field element.
Definition expr.cpp:311
const FieldElement & constant() const
Returns the constant term of the affine expression.
Definition expr.hpp:86
std::string to_string() const
Formats the expression in a stable human-readable form used for debugging and serialization.
Definition expr.cpp:104
std::vector< Term > & linear()
Returns mutable access to the sorted linear term list.
Definition expr.hpp:91
friend Expr operator+(const Expr &lhs, const Expr &rhs)
Adds two affine expressions and merges like terms.
Definition expr.cpp:265
Expr()
Constructs the zero expression.
Definition expr.cpp:92
friend Expr operator-(const Expr &lhs, const Expr &rhs)
Subtracts one affine expression from another.
Definition expr.cpp:295
std::pair< Symbol, FieldElement > Term
Definition expr.hpp:73
const std::vector< Term > & linear() const
Returns read-only access to the sorted linear term list.
Definition expr.hpp:96
static Expr variable(Symbol symbol)
Returns a single-variable expression with coefficient one.
Definition expr.cpp:98
std::optional< FieldElement > evaluate(const WitnessAssignments &values) const
Evaluates the expression against a possibly partial transcript witness assignment.
Definition expr.cpp:125
friend bool operator<(const Expr &lhs, const Expr &rhs)
Orders affine expressions structurally for cache keys.
Definition expr.cpp:369
std::pair< Expr, Expr > split() const
Splits the expression into a pure constant and a pure linear component.
Definition expr.cpp:140
Field element modulo the backend scalar field used by this implementation.
Definition numeric.hpp:815
static FieldElement zero()
Returns the additive identity of the scalar field.
Definition numeric.cpp:32
Mutable transcript used to record symbolic multiplication, division, and boolean constraints.
Definition expr.hpp:213
const std::vector< Expr > & eqs() const
Returns the linear equality constraints accumulated so far.
Definition expr.hpp:251
Expr secret(const std::optional< FieldElement > &value)
Allocates a new secret witness variable, optionally with a known concrete value.
Definition expr.cpp:378
std::optional< FieldElement > evaluate(const Expr &expr) const
Evaluates an expression against the transcript's current witness vector.
Definition expr.cpp:451
Expr boolean(const Expr &expr)
Constrains an expression to be boolean by adding x * (x - 1) = 0.
Definition expr.cpp:428
const std::vector< MulConstraint > & muls() const
Returns the multiplication and division constraints accumulated so far.
Definition expr.hpp:246
Expr mul(const Expr &lhs, const Expr &rhs)
Allocates or reuses a multiplication witness enforcing lhs * rhs = out.
Definition expr.cpp:386
const WitnessAssignments & varmap() const
Returns the underlying witness assignment vector.
Definition expr.hpp:234
Expr div(const Expr &lhs, const Expr &rhs)
Allocates or reuses a division witness enforcing out * rhs = lhs.
Definition expr.cpp:409
void equal(const Expr &lhs, const Expr &rhs)
Records a linear equality constraint between two expressions.
Definition expr.cpp:442
Definition api.hpp:21
bool operator<(const Symbol &lhs, const Symbol &rhs) noexcept
Definition expr.hpp:58
Expr operator*(const Expr &expr, const FieldElement &scalar)
Definition expr.cpp:311
std::ostream & operator<<(std::ostream &out, const Expr &expr)
Streams the human-readable expression form to an output stream.
Definition expr.cpp:373
SymbolKind
Symbol classes used while deriving witness and Bulletproof wire relations.
Definition expr.hpp:26
bool operator==(const Expr &lhs, const Expr &rhs)
Definition expr.cpp:335
Expr operator-(const Expr &lhs, const Expr &rhs)
Definition expr.cpp:295
std::vector< std::optional< FieldElement > > WitnessAssignments
Partial witness assignment vector indexed by transcript witness id.
Definition expr.hpp:63
Bytes operator+(Bytes lhs, const Bytes &rhs)
Concatenates two byte vectors.
Definition curve.cpp:167
Fixed-width integer and field arithmetic helpers used throughout Purify.
Scalar32 scalar
Definition bppp.cpp:119
bool operator()(const Expr &lhs, const Expr &rhs) const
Definition expr.cpp:339
bool operator()(const std::pair< Expr, Expr > &lhs, const std::pair< Expr, Expr > &rhs) const
Definition expr.cpp:358
bool operator()(const Symbol &lhs, const Symbol &rhs) const noexcept
Definition expr.hpp:50
Compact symbolic variable identifier used inside expressions and transcripts.
Definition expr.hpp:35
bool operator==(const Symbol &) const =default
static Symbol witness(std::uint32_t index)
Definition expr.cpp:55
static Symbol left(std::uint32_t index)
Definition expr.cpp:59
static Symbol output(std::uint32_t index)
Definition expr.cpp:67
std::uint32_t index
Definition expr.hpp:37
std::string to_string() const
Definition expr.cpp:75
static Symbol commitment(std::uint32_t index)
Definition expr.cpp:71
static Symbol right(std::uint32_t index)
Definition expr.cpp:63
SymbolKind kind
Definition expr.hpp:36
One multiplicative relation emitted by the symbolic transcript.
Definition expr.hpp:239