purify
C++ Purify implementation with native circuit and BPP support
Loading...
Searching...
No Matches
api.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 <array>
13#include <concepts>
14#include <span>
15#include <type_traits>
16#include <utility>
17
19#include "purify/secret.hpp"
20
21namespace purify {
22
28
31
38struct Bip340Key {
39 Bip340Key() = default;
40 Bip340Key(const Bip340Key&) = delete;
41 Bip340Key& operator=(const Bip340Key&) = delete;
42
43 Bip340Key(Bip340Key&& other) noexcept
44 : seckey(other.seckey), xonly_pubkey(other.xonly_pubkey) {
45 other.clear();
46 }
47
48 Bip340Key& operator=(Bip340Key&& other) noexcept {
49 if (this != &other) {
50 clear();
51 seckey = other.seckey;
52 xonly_pubkey = other.xonly_pubkey;
53 other.clear();
54 }
55 return *this;
56 }
57
59 clear();
60 }
61
62 std::array<unsigned char, 32> seckey{};
63 std::array<unsigned char, 32> xonly_pubkey{};
64
65private:
66 void clear() noexcept {
68 xonly_pubkey.fill(0);
69 }
70};
71
78
85
92
99
104
106template <typename FillRandom>
107concept NoexceptByteFill = requires(FillRandom&& fill, std::span<unsigned char> bytes) {
108 { std::forward<FillRandom>(fill)(bytes) } noexcept -> std::same_as<void>;
109};
110
112template <typename FillRandom>
113concept NoexceptCheckedByteFill = requires(FillRandom&& fill, std::span<unsigned char> bytes) {
114 { std::forward<FillRandom>(fill)(bytes) } noexcept -> std::same_as<Status>;
115};
116
122Status fill_secure_random(std::span<unsigned char> bytes) noexcept;
123
130template <typename FillRandom>
132Result<UInt512> random_below(const UInt512& range, FillRandom&& fill_random) {
133 if (range.is_zero()) {
134 return unexpected_error(ErrorCode::RangeViolation, "random_below:zero_range");
135 }
136 std::size_t bits = range.bit_length();
137 std::size_t bytes_needed = (bits + 7) / 8;
138 std::array<unsigned char, 64> bytes{};
139 std::span<unsigned char> out(bytes.data(), bytes_needed);
140 while (true) {
141 PURIFY_RETURN_IF_ERROR(std::forward<FillRandom>(fill_random)(out), "random_below:fill_random");
142 UInt512 candidate = UInt512::from_bytes_be(bytes.data(), bytes_needed);
143 candidate.mask_bits(bits);
144 if (candidate.compare(range) < 0) {
145 return candidate;
146 }
147 }
148}
149
156template <typename FillRandom>
157requires NoexceptByteFill<FillRandom>
158Result<UInt512> random_below(const UInt512& range, FillRandom&& fill_random) {
159 if (range.is_zero()) {
160 return unexpected_error(ErrorCode::RangeViolation, "random_below:zero_range");
161 }
162 std::size_t bits = range.bit_length();
163 std::size_t bytes_needed = (bits + 7) / 8;
164 std::array<unsigned char, 64> bytes{};
165 std::span<unsigned char> out(bytes.data(), bytes_needed);
166 while (true) {
167 std::forward<FillRandom>(fill_random)(out);
168 UInt512 candidate = UInt512::from_bytes_be(bytes.data(), bytes_needed);
169 candidate.mask_bits(bits);
170 if (candidate.compare(range) < 0) {
171 return candidate;
172 }
173 }
174}
175
181Result<UInt512> random_below(const UInt512& range);
182
187Result<GeneratedKey> generate_key();
188
194Result<GeneratedKey> generate_key(KeySeed seed);
195
201inline Result<GeneratedKey> generate_key(std::span<const unsigned char> seed) {
202 PURIFY_ASSIGN_OR_RETURN(auto checked, KeySeed::try_from(seed), "generate_key:seed_too_short");
203 return generate_key(checked);
204}
205
211template <typename FillRandom>
212requires(NoexceptByteFill<FillRandom> || NoexceptCheckedByteFill<FillRandom>)
213Result<GeneratedKey> generate_key(FillRandom&& fill_random) {
214 PURIFY_ASSIGN_OR_RETURN(const auto& secret, random_below(key_space_size(), std::forward<FillRandom>(fill_random)),
215 "generate_key:random_below_custom");
216 PURIFY_ASSIGN_OR_RETURN(auto owned_secret, SecretKey::from_packed(secret), "generate_key:from_packed_secret");
217 return derive_key(std::move(owned_secret));
218}
219
226Result<FieldElement> eval(const SecretKey& secret, const Bytes& message);
227
234Result<std::string> verifier(const Bytes& message, const UInt512& pubkey);
235
242Result<NativeBulletproofCircuit> verifier_circuit(const Bytes& message, const UInt512& pubkey);
243
250Result<BulletproofWitnessData> prove_assignment_data(const Bytes& message, const SecretKey& secret);
251
258Result<bool> evaluate_verifier_circuit(const Bytes& message, const BulletproofWitnessData& witness);
259
266Result<bool> evaluate_verifier_circuit(const Bytes& message, const SecretKey& secret);
267
274Result<Bytes> prove_assignment(const Bytes& message, const SecretKey& secret);
275
276} // namespace purify
Native Bulletproof-style circuit types and witness serialization helpers.
Purify result carrier that either holds a value or an error.
Definition expected.hpp:64
Field element modulo the backend scalar field used by this implementation.
Definition numeric.hpp:815
Move-only packed Purify secret stored in dedicated heap memory.
Definition secret.hpp:52
static Result< SecretKey > from_packed(const UInt512 &packed)
Constructs a validated secret key from packed Purify secret bytes.
Definition secret.hpp:66
Checked span wrapper that guarantees a minimum runtime length.
Definition common.hpp:129
static Result< SpanAtLeast > try_from(std::span< T > span)
Definition common.hpp:138
Callable concept for byte-fill RNG adapters that cannot fail.
Definition api.hpp:107
Callable concept for byte-fill RNG adapters that report failure via Status.
Definition api.hpp:113
#define PURIFY_RETURN_IF_ERROR(expr, context)
Evaluates an expected-like expression and returns the wrapped error on failure.
Definition error.hpp:329
#define PURIFY_ASSIGN_OR_RETURN(lhs, expr, context)
Evaluates an expected-like expression, binds the value to lhs, and propagates errors.
Definition error.hpp:338
void secure_clear_bytes(void *data, std::size_t size) noexcept
Definition secret.hpp:22
Definition api.hpp:21
constexpr Unexpected< Error > unexpected_error(ErrorCode code, const char *context=nullptr)
Constructs an unexpected Error value from a machine-readable code.
Definition error.hpp:293
Result< std::string > verifier(const Bytes &message, const UInt512 &pubkey)
Builds the legacy serialized verifier description for a message and public key.
Definition api.cpp:190
Result< BulletproofWitnessData > prove_assignment_data(const Bytes &message, const SecretKey &secret)
Computes the native Purify witness for a message and secret.
Definition api.cpp:236
Result< GeneratedKey > generate_key()
Generates a random Purify keypair using the built-in OS RNG.
Definition api.cpp:112
BigUInt< 8 > UInt512
512-bit unsigned integer used for private and packed public keys.
Definition numeric.hpp:802
Result< NativeBulletproofCircuit > verifier_circuit(const Bytes &message, const UInt512 &pubkey)
Builds the native verifier circuit for a message and public key.
Definition api.cpp:204
Result< Bip340Key > derive_bip340_key(const SecretKey &secret, purify_secp_context *secp_context)
Derives a canonical BIP340 signing keypair from an owned Purify secret.
Definition api.cpp:161
Result< Bytes > prove_assignment(const Bytes &message, const SecretKey &secret)
Serializes the witness assignment produced for a message and secret.
Definition api.cpp:294
Result< GeneratedKey > derive_key(const SecretKey &secret)
Derives the packed public key corresponding to a packed secret.
Definition api.cpp:142
std::vector< unsigned char > Bytes
Dynamically sized byte string used for messages, serialized witnesses, and proofs.
Definition common.hpp:99
const UInt512 & packed_secret_key_space_size()
Returns the size of the packed secret-key encoding space.
Definition curve.cpp:224
UInt512 key_space_size()
Returns the size of the packed Purify secret-key space.
Definition api.hpp:101
Result< FieldElement > eval(const SecretKey &secret, const Bytes &message)
Evaluates the Purify PRF for an owned secret key and message.
Definition api.cpp:177
Result< bool > evaluate_verifier_circuit(const Bytes &message, const BulletproofWitnessData &witness)
Evaluates the generated verifier circuit against an explicit witness.
Definition api.cpp:282
SpanAtLeast< 16, const unsigned char > KeySeed
Minimum-length checked wrapper for deterministic key-generation seed material.
Definition api.hpp:30
Result< UInt512 > random_below(const UInt512 &range, FillRandom &&fill_random)
Samples a uniformly random packed secret below a range using a checked byte-fill source.
Definition api.hpp:132
Status fill_secure_random(std::span< unsigned char > bytes) noexcept
Fills a buffer with operating-system randomness.
Definition api.cpp:103
Secret-owning Purify key material wrappers.
std::size_t bit_length() const
Returns the index of the highest set bit plus one.
Definition numeric.hpp:474
static BigUInt from_bytes_be(const unsigned char *data, std::size_t size)
Parses a big-endian byte string into the fixed-width integer.
Definition numeric.hpp:235
bool is_zero() const
Returns true when all limbs are zero.
Definition numeric.hpp:287
int compare(const BigUInt &other) const
Compares two fixed-width integers using unsigned ordering.
Definition numeric.hpp:301
void mask_bits(std::size_t bits)
Clears all bits above the requested width.
Definition numeric.hpp:586
Canonical BIP340 keypair derived deterministically from a packed Purify secret.
Definition api.hpp:38
Bip340Key(const Bip340Key &)=delete
Bip340Key & operator=(Bip340Key &&other) noexcept
Definition api.hpp:48
std::array< unsigned char, 32 > seckey
Definition api.hpp:62
Bip340Key & operator=(const Bip340Key &)=delete
Bip340Key()=default
std::array< unsigned char, 32 > xonly_pubkey
Definition api.hpp:63
Bip340Key(Bip340Key &&other) noexcept
Definition api.hpp:43
Columnar witness assignment compatible with the native Bulletproof circuit layout.
Complete witness bundle for evaluating and proving a Purify instance.
Definition api.hpp:73
BulletproofAssignmentData assignment
Definition api.hpp:76
Derived Purify keypair bundle with an owned packed secret and its matching public key.
Definition api.hpp:24
UInt512 public_key
Definition api.hpp:26
SecretKey secret
Definition api.hpp:25