38 sealed(T value,
digest hash) : value(std::move(value)), hash(hash) {}
43 bool operator==(
const sealed& other)
const {
return hash == other.hash; }
45 auto operator<=>(
const sealed& other)
const {
return hash <=> other.hash; }
52 template<
class Stream>
53 void serialize(Stream& stream)
const {
69 return {std::move(value), hash};
80 auto data =
encode(p.value);
81 proof.insert(
proof.end(), data.begin(), data.end());
82 return std::move(p.value);
97 explicit sealed(
digest hash) : hash(hash) {}
98 friend struct verifier;
111 template<
class Self,
class Stream>
112 void serialize(
this Self& self, Stream& stream) { stream(self.hash); }
118 explicit verifier(std::span<const std::uint8_t> proof)
119 : position(proof.data()), end(proof.subspan(proof.size()).data()) {}
142 auto [value, next] =
decode<T>({position, end});
143 if (
sha256({position, next}) != p.hash)
throw auth_error(
"sealed hash mismatch");
144 if constexpr (std::is_nothrow_move_constructible_v<T>) {
146 return std::move(value);
149 struct advance_on_success {
150 const std::uint8_t*& position;
151 const std::uint8_t* next;
152 int exceptions = std::uncaught_exceptions();
153 ~advance_on_success() {
154 if (std::uncaught_exceptions() == exceptions) position = next;
156 } advance{position, next};
157 return std::move(value);
165 if (position != end)
throw auth_error(
"unused proof bytes");
169 const std::uint8_t* position;
170 const std::uint8_t*
const end;
183export template<
class D>
184concept db =
requires(D& database, std::uint32_t value,
186 { database.seal(value) } ->
188 { database.unseal(std::move(p)) } -> std::same_as<std::uint32_t>;
195export template<db DB,
class T>
typename std::remove_cvref_t< DB >::template sealed< T > sealed
Selects a database's associated sealed type.
A resident value and its digest; copyability follows T.
auto operator<=>(const sealed &other) const
Orders sealed values lexicographically by digest.
bool operator==(const sealed &other) const
Compares digests without comparing resident values.
A copyable digest commitment with no resident payload.
auto operator<=>(const sealed &) const =default
Compares and orders sealed values by digest.
sealed()=default
Initializes an all-zero digest, ready for deserialization.
A database with associated sealed types and seal/unseal operations. D is the database type,...
std::array< std::uint8_t, 32 > digest
The 32 bytes of a SHA-256 digest in hash output order.
digest sha256(std::span< const std::uint8_t > data)
Hashes exactly the supplied bytes with OpenSSL's SHA-256 implementation.
bytes encode(const T &value)
Serializes a value to an owned byte buffer.
std::vector< std::uint8_t > bytes
An owned buffer of serialized bytes.
std::pair< T, const std::uint8_t * > decode(std::span< const std::uint8_t > data)
Decodes one value, leaving subsequent bytes for the caller.
Reports malformed input, invalid proofs, or hashing failures.
Records serialized openings in an owned proof buffer.
T unseal(sealed< T > p)
Appends an opening to the proof and returns its resident value.
bytes proof
Concatenated openings, without external framing.
sealed< T > seal(T value) const
Hashes a value and retains it in a sealed value without changing the proof.
Reads checked fields from borrowed bytes, advancing a byte offset.
verifier(bytes &&)=delete
Rejects a temporary owning buffer that would leave dangling pointers.
verifier(std::span< const std::uint8_t > proof)
Starts replay at the beginning of a borrowed proof.
sealed< T > seal(T value) const
Computes a digest-only sealed value without reading the proof.
void finish() const
Checks that replay consumed every proof byte.
T unseal(sealed< T > p)
Decodes the next value and checks the digest of exactly its consumed bytes.
Appends deterministic, byte-aligned fields to an owned buffer.