37 std::vector<FieldElement>
left;
38 std::vector<FieldElement>
right;
54 std::vector<NativeBulletproofCircuitTerm>
entries;
69 [[nodiscard]] std::span<const NativeBulletproofCircuitTerm>
entries_view() const noexcept {
70 return std::span<const NativeBulletproofCircuitTerm>(
data,
size);
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;
111 [[nodiscard]] std::size_t
n_gates() const noexcept {
116 return n_commitments_;
119 [[nodiscard]] std::size_t
n_bits() const noexcept {
124 return constraint_size_;
128 return constraint_capacity_;
134 void reset() noexcept;
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;
177 enum class RowFamily :
unsigned char {
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,
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);
205 struct PackedStorageDeleter {
206 void operator()(std::byte* storage)
const noexcept;
209 using PackedStorageOwner = std::unique_ptr<std::byte[], PackedStorageDeleter>;
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_;
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");
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;
259 void resize(std::size_t gates, std::size_t commitments, std::size_t bits = 0);
289 static void add_row_term(std::vector<NativeBulletproofCircuitRow>& rows, std::size_t expected_size,
322 [[nodiscard]] std::size_t
size() const noexcept;
339 std::unique_ptr<
Impl> impl_;
390 std::span<const unsigned char> statement_binding = {},
391 std::optional<BulletproofScalarBytes> blind = std::nullopt,
394 const NativeBulletproofCircuit::PackedWithSlack& circuit,
395 const BulletproofAssignmentData& assignment,
399 std::span<const unsigned char> statement_binding = {},
400 std::optional<BulletproofScalarBytes> blind = std::nullopt,
405 const NativeBulletproofCircuit& circuit,
406 const ExperimentalBulletproofProof& proof,
409 std::span<const unsigned char> statement_binding = {},
412 const NativeBulletproofCircuit::PackedWithSlack& circuit,
413 const ExperimentalBulletproofProof& proof,
416 std::span<const unsigned char> statement_binding = {},
428 void replace_expr_v_with_bp_var(
Expr& expr);
431 bool replace_and_insert(
Expr& expr,
Symbol symbol);
434 void add_assignment(
Symbol symbol,
Expr expr);
467 static bool is_transcript_var(
Symbol symbol);
468 static bool contains_transcript_var(
const Expr& expr);
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;
532 const std::optional<UInt256>& z1 = std::nullopt,
533 const std::optional<UInt256>& z2 = std::nullopt);
Lowering helper that converts a symbolic transcript into native Bulletproof witness and circuit forms...
Minimal elliptic-curve arithmetic over the Purify base field.
Purify result carrier that either holds a value or an error.
Caller-owned cache for reusable legacy Bulletproof backend resources keyed by gate count.
ExperimentalBulletproofBackendCache()
ExperimentalBulletproofBackendCache(const ExperimentalBulletproofBackendCache &)=delete
ExperimentalBulletproofBackendCache & operator=(const ExperimentalBulletproofBackendCache &)=delete
~ExperimentalBulletproofBackendCache()
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
std::size_t size() const noexcept
Symbolic affine expression over indexed variables and field coefficients.
Field element modulo the backend scalar field used by this implementation.
static FieldElement zero()
Returns the additive identity of the scalar field.
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)
std::size_t constraint_capacity() const noexcept
std::size_t n_commitments() const noexcept
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.
bool has_valid_shape() const noexcept
std::size_t n_gates() const noexcept
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.
std::size_t constraint_count() const noexcept
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.
PackedWithSlack()=default
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.
std::size_t n_bits() const noexcept
Mutable transcript used to record symbolic multiplication, division, and boolean constraints.
Elliptic-curve helpers, fixed parameters, and hash-to-curve utilities for Purify.
Symbolic expression and transcript machinery used to derive Purify circuits.
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.
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.
std::array< unsigned char, 33 > BulletproofGeneratorBytes
constexpr std::string_view to_string(ErrorCategory category) noexcept
Returns a stable programmatic name for an error category.
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.
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.
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.
BulletproofPointBytes commitment
static constexpr unsigned char kSerializationVersion
Result< Bytes > serialize() const
static Result< ExperimentalBulletproofProof > deserialize(std::span< const unsigned char > bytes)
Jacobian point representation used for curve arithmetic.
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.
std::vector< std::size_t > wl
std::vector< std::size_t > wr
std::vector< std::size_t > wv
std::size_t constraint_slack
std::vector< std::size_t > wo
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.
NativeBulletproofCircuit()=default
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
std::size_t n_commitments
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.