purify
C++ Purify implementation with native circuit and BPP support
Loading...
Searching...
No Matches
bulletproof.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 <algorithm>
13#include <array>
14#include <cstddef>
15#include <memory>
16#include <optional>
17#include <span>
18#include <string>
19#include <type_traits>
20#include <utility>
21#include <vector>
22
23#include "purify/curve.hpp"
24#include "purify/expr.hpp"
25
28
29namespace purify {
30
31using BulletproofScalarBytes = std::array<unsigned char, 32>;
32using BulletproofPointBytes = std::array<unsigned char, 33>;
33using BulletproofGeneratorBytes = std::array<unsigned char, 33>;
34
37 std::vector<FieldElement> left;
38 std::vector<FieldElement> right;
39 std::vector<FieldElement> output;
40 std::vector<FieldElement> commitments;
41
44};
45
51
54 std::vector<NativeBulletproofCircuitTerm> entries;
55
57 void add(std::size_t idx, const FieldElement& scalar);
58
66 std::size_t size = 0;
67 std::size_t capacity = 0;
68
69 [[nodiscard]] std::span<const NativeBulletproofCircuitTerm> entries_view() const noexcept {
70 return std::span<const NativeBulletproofCircuitTerm>(data, size);
71 }
72 };
73};
74
83 std::size_t constraint_slack = 0;
84 std::vector<std::size_t> wl;
85 std::vector<std::size_t> wr;
86 std::vector<std::size_t> wo;
87 std::vector<std::size_t> wv;
88 };
89
99 public:
100 PackedWithSlack() = default;
101 PackedWithSlack(const PackedWithSlack& other);
103 PackedWithSlack(PackedWithSlack&& other) noexcept;
104 PackedWithSlack& operator=(PackedWithSlack&& other) noexcept;
105
107 [[nodiscard]] static Result<PackedWithSlack> from_circuit(
108 const NativeBulletproofCircuit& circuit,
109 const PackedSlackPlan& slack);
110
111 [[nodiscard]] std::size_t n_gates() const noexcept {
112 return n_gates_;
113 }
114
115 [[nodiscard]] std::size_t n_commitments() const noexcept {
116 return n_commitments_;
117 }
118
119 [[nodiscard]] std::size_t n_bits() const noexcept {
120 return n_bits_;
121 }
122
123 [[nodiscard]] std::size_t constraint_count() const noexcept {
124 return constraint_size_;
125 }
126
127 [[nodiscard]] std::size_t constraint_capacity() const noexcept {
128 return constraint_capacity_;
129 }
130
131 [[nodiscard]] bool has_valid_shape() const noexcept;
132
134 void reset() noexcept;
135
137 std::size_t add_constraint(const FieldElement& constant = FieldElement::zero());
138
140 void add_left_term(std::size_t gate_idx, std::size_t constraint_idx, const FieldElement& scalar);
141
143 void add_right_term(std::size_t gate_idx, std::size_t constraint_idx, const FieldElement& scalar);
144
146 void add_output_term(std::size_t gate_idx, std::size_t constraint_idx, const FieldElement& scalar);
147
149 void add_commitment_term(std::size_t commitment_idx, std::size_t constraint_idx, const FieldElement& scalar);
150
152 [[nodiscard]] bool evaluate(const BulletproofAssignmentData& assignment) const;
153
155 [[nodiscard]] Result<NativeBulletproofCircuit> unpack() const;
156
158 [[nodiscard]] NativeBulletproofCircuitRow::PackedWithSlack left_row(std::size_t gate_idx) const noexcept;
160 [[nodiscard]] NativeBulletproofCircuitRow::PackedWithSlack right_row(std::size_t gate_idx) const noexcept;
162 [[nodiscard]] NativeBulletproofCircuitRow::PackedWithSlack output_row(std::size_t gate_idx) const noexcept;
164 [[nodiscard]] NativeBulletproofCircuitRow::PackedWithSlack commitment_row(std::size_t commitment_idx) const noexcept;
165
167 [[nodiscard]] std::span<const FieldElement> constants() const noexcept;
168
169 private:
170 struct PackedRowHeader {
171 std::size_t offset = 0;
172 std::size_t size = 0;
173 std::size_t base_size = 0;
174 std::size_t capacity = 0;
175 };
176
177 enum class RowFamily : unsigned char {
178 Left,
179 Right,
180 Output,
182 };
183
184 PackedRowHeader& row_header(RowFamily family, std::size_t idx) noexcept;
185 const PackedRowHeader& row_header(RowFamily family, std::size_t idx) const noexcept;
186 NativeBulletproofCircuitTerm* term_data() noexcept;
187 const NativeBulletproofCircuitTerm* term_data() const noexcept;
188 FieldElement* constant_data() noexcept;
189 const FieldElement* constant_data() const noexcept;
190 unsigned char* raw_storage_bytes() noexcept;
191 const unsigned char* raw_storage_bytes() const noexcept;
192 static bool compute_storage_layout(std::size_t row_count, std::size_t term_capacity,
193 std::size_t constraint_capacity, std::size_t& term_bytes_offset,
194 std::size_t& constant_bytes_offset, std::size_t& storage_bytes) noexcept;
195 static constexpr std::size_t kPackedStorageAlignment =
196 std::max(std::max(alignof(PackedRowHeader), alignof(NativeBulletproofCircuitTerm)),
197 alignof(FieldElement));
198 static std::byte* allocate_storage(std::size_t bytes);
199 void reset_to_empty() noexcept;
200 void start_storage_lifetimes() noexcept;
201 NativeBulletproofCircuitRow::PackedWithSlack row_view(const PackedRowHeader& header) const noexcept;
202 void add_row_term(RowFamily family, std::size_t expected_size, std::size_t row_idx,
203 std::size_t constraint_idx, const FieldElement& scalar);
204
205 struct PackedStorageDeleter {
206 void operator()(std::byte* storage) const noexcept;
207 };
208
209 using PackedStorageOwner = std::unique_ptr<std::byte[], PackedStorageDeleter>;
210
211 std::size_t n_gates_ = 0;
212 std::size_t n_commitments_ = 0;
213 std::size_t n_bits_ = 0;
214 std::size_t constraint_size_ = 0;
215 std::size_t constraint_base_size_ = 0;
216 std::size_t constraint_capacity_ = 0;
217 std::size_t term_capacity_ = 0;
218 std::size_t term_bytes_offset_ = 0;
219 std::size_t constant_bytes_offset_ = 0;
220 std::size_t storage_bytes_ = 0;
221 PackedStorageOwner storage_;
222
223 static_assert(std::is_trivially_copyable_v<PackedRowHeader>,
224 "PackedWithSlack row headers must remain trivially copyable");
225 static_assert(std::is_trivially_destructible_v<PackedRowHeader>,
226 "PackedWithSlack row headers must remain trivially destructible");
227 static_assert(std::is_trivially_copyable_v<NativeBulletproofCircuitTerm>,
228 "PackedWithSlack sparse terms must remain trivially copyable");
229 static_assert(std::is_trivially_destructible_v<NativeBulletproofCircuitTerm>,
230 "PackedWithSlack sparse terms must remain trivially destructible");
231 static_assert(std::is_trivially_copyable_v<FieldElement>,
232 "PackedWithSlack constants must remain trivially copyable");
233 static_assert(std::is_trivially_destructible_v<FieldElement>,
234 "PackedWithSlack constants must remain trivially destructible");
235 static_assert(alignof(PackedRowHeader) <= kPackedStorageAlignment,
236 "PackedWithSlack slab alignment must cover row headers");
237 static_assert(alignof(NativeBulletproofCircuitTerm) <= kPackedStorageAlignment,
238 "PackedWithSlack slab alignment must cover sparse terms");
239 static_assert(alignof(FieldElement) <= kPackedStorageAlignment,
240 "PackedWithSlack slab alignment must cover constants");
241 static_assert(std::is_same_v<decltype(&PackedWithSlack::storage_), PackedStorageOwner PackedWithSlack::*>,
242 "PackedWithSlack must keep its backing storage in one owning slab");
243
244 };
245
246 std::size_t n_gates = 0;
247 std::size_t n_commitments = 0;
248 std::size_t n_bits = 0;
249 std::vector<NativeBulletproofCircuitRow> wl;
250 std::vector<NativeBulletproofCircuitRow> wr;
251 std::vector<NativeBulletproofCircuitRow> wo;
252 std::vector<NativeBulletproofCircuitRow> wv;
253 std::vector<FieldElement> c;
254
256 NativeBulletproofCircuit(std::size_t gates, std::size_t commitments, std::size_t bits = 0);
257
259 void resize(std::size_t gates, std::size_t commitments, std::size_t bits = 0);
260
262 bool has_valid_shape() const;
263
265 std::size_t add_constraint(const FieldElement& constant = FieldElement::zero());
266
268 void add_left_term(std::size_t gate_idx, std::size_t constraint_idx, const FieldElement& scalar);
269
271 void add_right_term(std::size_t gate_idx, std::size_t constraint_idx, const FieldElement& scalar);
272
274 void add_output_term(std::size_t gate_idx, std::size_t constraint_idx, const FieldElement& scalar);
275
277 void add_commitment_term(std::size_t commitment_idx, std::size_t constraint_idx, const FieldElement& scalar);
278
280 bool evaluate(const BulletproofAssignmentData& assignment) const;
281
286
287private:
289 static void add_row_term(std::vector<NativeBulletproofCircuitRow>& rows, std::size_t expected_size,
290 std::size_t row_idx, std::size_t constraint_idx, const FieldElement& scalar);
291};
292
302 static constexpr unsigned char kSerializationVersion = 2;
303
306
307 Result<Bytes> serialize() const;
308 static Result<ExperimentalBulletproofProof> deserialize(std::span<const unsigned char> bytes);
309};
310
341
350public:
352 [[nodiscard]] static NativeBulletproofCircuitTemplate from_parts(
354 Expr p1x,
355 Expr p2x,
356 Expr out);
357
359 Result<bool> partial_evaluate(const BulletproofAssignmentData& assignment) const;
360
362 Result<bool> final_evaluate(const BulletproofAssignmentData& assignment, const UInt512& pubkey) const;
363
365 Result<Bytes> integrity_digest() const;
366
367 Result<NativeBulletproofCircuit::PackedWithSlack> instantiate_packed(const UInt512& pubkey) const;
368 Result<NativeBulletproofCircuit> instantiate(const UInt512& pubkey) const;
369
370private:
372 Expr p1x_;
373 Expr p2x_;
374 Expr out_;
375};
376
385 const NativeBulletproofCircuit& circuit,
386 const BulletproofAssignmentData& assignment,
388 const BulletproofGeneratorBytes& value_generator,
389 purify_secp_context* secp_context,
390 std::span<const unsigned char> statement_binding = {},
391 std::optional<BulletproofScalarBytes> blind = std::nullopt,
392 ExperimentalBulletproofBackendCache* backend_cache = nullptr);
393Result<ExperimentalBulletproofProof> prove_experimental_circuit(
394 const NativeBulletproofCircuit::PackedWithSlack& circuit,
395 const BulletproofAssignmentData& assignment,
397 const BulletproofGeneratorBytes& value_generator,
398 purify_secp_context* secp_context,
399 std::span<const unsigned char> statement_binding = {},
400 std::optional<BulletproofScalarBytes> blind = std::nullopt,
401 ExperimentalBulletproofBackendCache* backend_cache = nullptr);
402
404Result<bool> verify_experimental_circuit(
405 const NativeBulletproofCircuit& circuit,
406 const ExperimentalBulletproofProof& proof,
407 const BulletproofGeneratorBytes& value_generator,
408 purify_secp_context* secp_context,
409 std::span<const unsigned char> statement_binding = {},
410 ExperimentalBulletproofBackendCache* backend_cache = nullptr);
411Result<bool> verify_experimental_circuit(
412 const NativeBulletproofCircuit::PackedWithSlack& circuit,
413 const ExperimentalBulletproofProof& proof,
414 const BulletproofGeneratorBytes& value_generator,
415 purify_secp_context* secp_context,
416 std::span<const unsigned char> statement_binding = {},
417 ExperimentalBulletproofBackendCache* backend_cache = nullptr);
418
420Result<NativeBulletproofCircuitTemplate> verifier_circuit_template(const Bytes& message);
421
426public:
428 void replace_expr_v_with_bp_var(Expr& expr);
429
431 bool replace_and_insert(Expr& expr, Symbol symbol);
432
434 void add_assignment(Symbol symbol, Expr expr);
435
437 Status from_transcript(const Transcript& transcript, std::size_t n_bits);
438
440 Status add_pubkey_and_out(const UInt512& pubkey, Expr p1x, Expr p2x, Expr out);
441
443 std::string to_string() const;
444
446 bool evaluate(const WitnessAssignments& vars, const FieldElement& commitment) const;
447
449 NativeBulletproofCircuit native_circuit() const;
450
452 Result<BulletproofAssignmentData> assignment_data(const WitnessAssignments& vars) const;
453
455 Result<BulletproofAssignmentData> assignment_data(const WitnessAssignments& vars, const FieldElement& commitment) const;
456
458 Result<Bytes> serialize_assignment(const WitnessAssignments& vars) const;
459
460private:
461 struct Assignment {
462 Symbol symbol;
463 Expr expr;
464 bool is_v;
465 };
466
467 static bool is_transcript_var(Symbol symbol);
468 static bool contains_transcript_var(const Expr& expr);
469 Result<BulletproofAssignmentData> assignment_data_impl(const WitnessAssignments& vars, const FieldElement* commitment) const;
470
471 std::vector<Assignment> assignments_;
472 std::vector<std::pair<Expr, Expr>> constraints_;
473 std::vector<std::optional<Symbol>> witness_to_a_;
474 std::vector<std::pair<std::uint32_t, Symbol>> witness_to_a_order_;
475 std::size_t n_witnesses_ = 0;
476 std::size_t n_muls_ = 0;
477 std::size_t n_commitments_ = 1;
478 std::size_t n_bits_ = 0;
479};
480
482Expr circuit_1bit(const std::array<FieldElement, 2>& values, Transcript& transcript, const Expr& x);
483
485Expr circuit_2bit(const std::array<FieldElement, 4>& values, Transcript& transcript, const Expr& x, const Expr& y);
486
488Expr circuit_3bit(const std::array<FieldElement, 8>& values, Transcript& transcript,
489 const Expr& x, const Expr& y, const Expr& z);
490
492using ExprPoint = std::pair<Expr, Expr>;
493
495ExprPoint circuit_1bit_point(const EllipticCurve& curve, const std::array<JacobianPoint, 2>& points,
496 Transcript& transcript, const Expr& b0);
497
499ExprPoint circuit_2bit_point(const EllipticCurve& curve, const std::array<JacobianPoint, 4>& points,
500 Transcript& transcript, const Expr& b0, const Expr& b1);
501
503ExprPoint circuit_3bit_point(const EllipticCurve& curve, const std::array<JacobianPoint, 8>& points,
504 Transcript& transcript, const Expr& b0, const Expr& b1, const Expr& b2);
505
507ExprPoint circuit_optionally_negate_ec(const ExprPoint& point, Transcript& transcript, const Expr& negate_bit);
508
510ExprPoint circuit_ec_add(Transcript& transcript, const ExprPoint& p1, const ExprPoint& p2);
511
513Expr circuit_ec_add_x(Transcript& transcript, const ExprPoint& p1, const ExprPoint& p2);
514
516Expr circuit_ec_multiply_x(const EllipticCurve& curve, Transcript& transcript,
517 const JacobianPoint& point, const std::vector<Expr>& bits);
518
520Expr circuit_combine(Transcript& transcript, const Expr& x1, const Expr& x2);
521
529
532 const std::optional<UInt256>& z1 = std::nullopt,
533 const std::optional<UInt256>& z2 = std::nullopt);
534
535} // namespace purify
Lowering helper that converts a symbolic transcript into native Bulletproof witness and circuit forms...
Minimal elliptic-curve arithmetic over the Purify base field.
Definition curve.hpp:46
Purify result carrier that either holds a value or an error.
Definition expected.hpp:64
Caller-owned cache for reusable legacy Bulletproof backend resources keyed by gate count.
ExperimentalBulletproofBackendCache(const ExperimentalBulletproofBackendCache &)=delete
ExperimentalBulletproofBackendCache & operator=(const ExperimentalBulletproofBackendCache &)=delete
ExperimentalBulletproofBackendCache & operator=(ExperimentalBulletproofBackendCache &&other) noexcept
purify_bulletproof_backend_resources * get_or_create(std::size_t n_gates, purify_secp_context *secp_context)
Returns cached backend resources for this gate count, creating them on first use.
Result< ExperimentalBulletproofBackendCache > clone_for_thread(std::size_t n_gates) const
Clones one warmed backend-resource entry for independent use on another thread.
ExperimentalBulletproofBackendCache(ExperimentalBulletproofBackendCache &&other) noexcept
Symbolic affine expression over indexed variables and field coefficients.
Definition expr.hpp:71
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
Public-key-agnostic native verifier-circuit template.
Resettable packed circuit representation backed by one aligned owning slab.
void add_right_term(std::size_t gate_idx, std::size_t constraint_idx, const FieldElement &scalar)
Adds a coefficient to the right-wire matrix.
PackedWithSlack & operator=(const PackedWithSlack &other)
Result< NativeBulletproofCircuit > unpack() const
Materializes the packed circuit back into the ergonomic row-vector representation.
void add_commitment_term(std::size_t commitment_idx, std::size_t constraint_idx, const FieldElement &scalar)
Adds a coefficient to the commitment matrix using the Bulletproof sign convention.
void add_output_term(std::size_t gate_idx, std::size_t constraint_idx, const FieldElement &scalar)
Adds a coefficient to the output-wire matrix.
void reset() noexcept
Restores the packed circuit to its original base row sizes and constraint count.
NativeBulletproofCircuitRow::PackedWithSlack right_row(std::size_t gate_idx) const noexcept
Returns a read-only packed right-wire row view.
void add_left_term(std::size_t gate_idx, std::size_t constraint_idx, const FieldElement &scalar)
Adds a coefficient to the left-wire matrix.
NativeBulletproofCircuitRow::PackedWithSlack left_row(std::size_t gate_idx) const noexcept
Returns a read-only packed left-wire row view.
NativeBulletproofCircuitRow::PackedWithSlack output_row(std::size_t gate_idx) const noexcept
Returns a read-only packed output-wire row view.
std::span< const FieldElement > constants() const noexcept
Returns the live constraint constants stored in the slab.
NativeBulletproofCircuitRow::PackedWithSlack commitment_row(std::size_t commitment_idx) const noexcept
Returns a read-only packed commitment row view.
std::size_t add_constraint(const FieldElement &constant=FieldElement::zero())
Appends a new linear constraint constant term and returns its index.
static Result< PackedWithSlack > from_circuit(const NativeBulletproofCircuit &circuit, const PackedSlackPlan &slack)
Packs a native circuit into one aligned slab with caller-supplied row and constraint slack.
bool evaluate(const BulletproofAssignmentData &assignment) const
Evaluates the packed circuit directly against a witness assignment.
Mutable transcript used to record symbolic multiplication, division, and boolean constraints.
Definition expr.hpp:213
Elliptic-curve helpers, fixed parameters, and hash-to-curve utilities for Purify.
Symbolic expression and transcript machinery used to derive Purify circuits.
Definition api.hpp:21
ExprPoint circuit_3bit_point(const EllipticCurve &curve, const std::array< JacobianPoint, 8 > &points, Transcript &transcript, const Expr &b0, const Expr &b1, const Expr &b2)
Selects between eight affine point constants using three boolean expression bits.
Result< NativeBulletproofCircuitTemplate > verifier_circuit_template(const Bytes &message)
Builds a reusable public-key-agnostic verifier-circuit template for a message.
Definition api.cpp:210
std::pair< Expr, Expr > ExprPoint
Symbolic affine point represented as independent x and y expressions.
Expr circuit_combine(Transcript &transcript, const Expr &x1, const Expr &x2)
Builds the symbolic Purify output combiner over two x-coordinates.
Result< bool > verify_experimental_circuit(const NativeBulletproofCircuit &circuit, const ExperimentalBulletproofProof &proof, const BulletproofGeneratorBytes &value_generator, purify_secp_context *secp_context, std::span< const unsigned char > statement_binding={}, ExperimentalBulletproofBackendCache *backend_cache=nullptr)
Verifies a proof produced by prove_experimental_circuit against the same one-commitment native circui...
ExprPoint circuit_ec_add(Transcript &transcript, const ExprPoint &p1, const ExprPoint &p2)
Symbolically adds two affine elliptic-curve points.
Expr circuit_ec_add_x(Transcript &transcript, const ExprPoint &p1, const ExprPoint &p2)
Symbolically adds two affine points and returns only the resulting x-coordinate.
Expr circuit_ec_multiply_x(const EllipticCurve &curve, Transcript &transcript, const JacobianPoint &point, const std::vector< Expr > &bits)
Builds the symbolic x-coordinate multiplication gadget for one curve point.
Result< CircuitMainResult > circuit_main(Transcript &transcript, const JacobianPoint &m1, const JacobianPoint &m2, const std::optional< UInt256 > &z1=std::nullopt, const std::optional< UInt256 > &z2=std::nullopt)
Builds the full symbolic Purify circuit from message points and optional witness scalars.
std::vector< unsigned char > Bytes
Dynamically sized byte string used for messages, serialized witnesses, and proofs.
Definition common.hpp:99
std::array< unsigned char, 33 > BulletproofGeneratorBytes
constexpr std::string_view to_string(ErrorCategory category) noexcept
Returns a stable programmatic name for an error category.
Definition error.hpp:146
Result< ExperimentalBulletproofProof > prove_experimental_circuit(const NativeBulletproofCircuit &circuit, const BulletproofAssignmentData &assignment, const BulletproofScalarBytes &nonce, const BulletproofGeneratorBytes &value_generator, purify_secp_context *secp_context, std::span< const unsigned char > statement_binding={}, std::optional< BulletproofScalarBytes > blind=std::nullopt, ExperimentalBulletproofBackendCache *backend_cache=nullptr)
Proves a native circuit with the experimental imported Bulletproof circuit backend.
Expr circuit_1bit(const std::array< FieldElement, 2 > &values, Transcript &transcript, const Expr &x)
Selects one of two field constants using a single boolean expression bit.
std::array< unsigned char, 33 > BulletproofPointBytes
Expr circuit_3bit(const std::array< FieldElement, 8 > &values, Transcript &transcript, const Expr &x, const Expr &y, const Expr &z)
Selects one of eight field constants using three boolean expression bits.
std::array< unsigned char, 32 > BulletproofScalarBytes
ExprPoint circuit_1bit_point(const EllipticCurve &curve, const std::array< JacobianPoint, 2 > &points, Transcript &transcript, const Expr &b0)
Selects between two affine point constants using one boolean expression bit.
ExprPoint circuit_optionally_negate_ec(const ExprPoint &point, Transcript &transcript, const Expr &negate_bit)
Conditionally negates an elliptic-curve point encoded as symbolic affine expressions.
std::vector< std::optional< FieldElement > > WitnessAssignments
Partial witness assignment vector indexed by transcript witness id.
Definition expr.hpp:63
ExprPoint circuit_2bit_point(const EllipticCurve &curve, const std::array< JacobianPoint, 4 > &points, Transcript &transcript, const Expr &b0, const Expr &b1)
Selects between four affine point constants using two boolean expression bits.
Expr circuit_2bit(const std::array< FieldElement, 4 > &values, Transcript &transcript, const Expr &x, const Expr &y)
Selects one of four field constants using two boolean expression bits.
Scalar32 scalar
Definition bppp.cpp:119
Nonce nonce
Definition bppp.cpp:120
Columnar witness assignment compatible with the native Bulletproof circuit layout.
std::vector< FieldElement > output
std::vector< FieldElement > commitments
std::vector< FieldElement > right
Result< Bytes > serialize() const
Serializes the witness columns in the legacy assignment blob format.
std::vector< FieldElement > left
Result bundle returned by the main symbolic Purify circuit construction.
Experimental single-proof wrapper over the imported legacy Bulletproof circuit backend.
static constexpr unsigned char kSerializationVersion
static Result< ExperimentalBulletproofProof > deserialize(std::span< const unsigned char > bytes)
Jacobian point representation used for curve arithmetic.
Definition curve.hpp:17
Non-owning packed row view used by NativeBulletproofCircuit::PackedWithSlack.
const NativeBulletproofCircuitTerm * data
std::span< const NativeBulletproofCircuitTerm > entries_view() const noexcept
One sparse row of circuit coefficients.
void add(std::size_t idx, const FieldElement &scalar)
Appends a sparse coefficient to the row, skipping zero entries.
std::vector< NativeBulletproofCircuitTerm > entries
One sparse matrix entry in a native circuit row.
Native in-memory representation of a Bulletproof-style arithmetic circuit.
std::size_t add_constraint(const FieldElement &constant=FieldElement::zero())
Appends a new linear constraint constant term and returns its index.
std::vector< NativeBulletproofCircuitRow > wv
void resize(std::size_t gates, std::size_t commitments, std::size_t bits=0)
Reinitializes the circuit shape and clears all accumulated constraints.
bool evaluate(const BulletproofAssignmentData &assignment) const
Evaluates the circuit against a witness assignment and checks all gate and row equations.
std::vector< NativeBulletproofCircuitRow > wr
bool has_valid_shape() const
Returns true when the sparse matrix vectors match the declared circuit dimensions.
std::vector< NativeBulletproofCircuitRow > wl
void add_left_term(std::size_t gate_idx, std::size_t constraint_idx, const FieldElement &scalar)
Adds a coefficient to the left-wire matrix.
std::vector< NativeBulletproofCircuitRow > wo
Result< PackedWithSlack > pack_with_slack() const
Packs the circuit into one aligned slab with no additional row or constraint slack.
void add_right_term(std::size_t gate_idx, std::size_t constraint_idx, const FieldElement &scalar)
Adds a coefficient to the right-wire matrix.
void add_output_term(std::size_t gate_idx, std::size_t constraint_idx, const FieldElement &scalar)
Adds a coefficient to the output-wire matrix.
std::vector< FieldElement > c
void add_commitment_term(std::size_t commitment_idx, std::size_t constraint_idx, const FieldElement &scalar)
Adds a coefficient to the commitment matrix using the Bulletproof sign convention.
Compact symbolic variable identifier used inside expressions and transcripts.
Definition expr.hpp:35