Releases: devrandom-labs/cesr
Releases · devrandom-labs/cesr
Release list
keri-rs-v0.0.2
cesr-rs-v0.5.0
Added
- (#87) [breaking] K1 KeyState fold + domain model (Authority/Commitment/Establishment) (#136)
- (#87) [breaking] K1 — KeyState + pure key-state fold (sans-io KERI core) (#134)
Other
Added
- Standard derives (
Debug,PartialEq,Eq;CloneonSeqner/Number) on
Matter,Number,Seqner, andDebugonIdentifier— needed bykeri-rs's
KeyState(#87).
Changed (breaking)
- Removed the logic-free
cesr::keri::KeyState(and itscesr::KeyStatere-export).
Computed key state now lives in thekeri-rscrate as a foldedKeyState<'a>(#87). Tholder::satisfyis now index-based:satisfy(indices: impl IntoIterator<Item = u32>)
instead of the count-basedsatisfy(count: u64), and is no longerconst. Weighted
thresholds are positional (each clause owns a run of key positions), so satisfaction
requires the signer index-set, not a bare count — the previous signature could only
ever returnfalseforWeighted. This is the single canonical satisfaction routine
(the complete implementation previously lived inkeri-rs::threshold::satisfied_by,
now removed) (#87).
v0.4.0
Added
- (#67) [breaking] infallible Matter::to_qb64 in core (text encoding without stream) (#78)
- (#69) [breaking] type-unified, composable signature verification (#72)
Fixed
Other
- (#33) [breaking] replace terrors::OneOf with domain error enums (#74)
- fix deep-fuzz workflow (engine-arg parsing + nightly toolchain) (#75)
Changed
- core (#76):
ValidationErrorgains a newSizeOverflowvariant, returned
when computing a variable-size primitive's full size from its decoded soft field
overflowsusize. AsValidationErroris public and not#[non_exhaustive],
this is breaking (MINOR under 0.x) for downstream exhaustivematchon it. - error ergonomics (#33): removed the
terrors::OneOferror-union layer in
favour of purpose-builtthiserrorenums. Breaking (MINOR under 0.x):MatterBuilder::{from_qualified_base64, from_qualified_base2, build}now return
Result<_, MatterBuildError>(variantsParsing,Validation) instead of
OneOf<(ParsingError, ValidationError)>.crypto::verifynow returnsResult<(), VerificationError>(variants
Signature,CodeMismatch) instead ofOneOf<(SignatureError, CodeMismatchError)>.- The indexer builder's parse/validation methods (
from_qb64,from_qb2,
with_index,with_indices,with_raw) return the bareIndexerParseError/
IndexerValidationError(previously wrapped in a single-elementOneOf). - Consumers matching on these results switch from
.take::/.narrow::to a
normalmatchon the new enums / bare types. SerderErrorgains a newUnparseablePrimitivevariant (see Fixed below).
AsSerderErroris public and not#[non_exhaustive], this is breaking for
downstream exhaustivematchon it.- The
terrorsdependency is dropped.
- core / serder (#67): qb64 text encoding moved to
core. Breaking
(MINOR under 0.x):Matter<C>gains infallibleto_qb64() -> Stringandto_qb64b() -> Vec<u8>;
encoding a key/digest/signature to text no longer requires thestreamfeature.stream::encode::matter_to_qb64removed (useMatter::to_qb64b).serder::primitives::{to_qb64_string, identifier_to_qb64_string}now return
Stringinstead ofResult<String, SerderError>; the internal
serder::serialize::{seal_to_json, matters_to_json_array}helpers likewise
became infallible.SerderErrorloses theQb64EncodingandEncodingvariants (their only
producers are gone). Breaking for downstream exhaustivematchonSerderError.
Fixed
- core (#76):
MatterBuilder::{from_qualified_base64, from_qualified_base2}no
longer compute the frame size (fs = size * 4 + cs,bfs = ceil(fs * 3 / 4)) from
the attacker-controlled soft field with unchecked arithmetic. The three sites now
usechecked_mul/checked_addand returnValidationError::SizeOverflowon
overflow, per the arithmetic-safety rule — previously a large declared size would
panic in debug or silently wrap in release (a truncated frame slicing as valid).
Latent, not reachable through the parse API today (variable codes cap the soft
field atss=4, sosize <= 2^24-1); fixed as a defense-in-depth rule violation. - serder (#33): a malformed-but-unparseable field value no longer collapses a
ParsingErrorintoValidationError::UnknownMatterCode(..)via string
formatting; a newSerderError::UnparseablePrimitive { field, source }variant
carries the parsing error in its own failure domain. - stream (#33): removed an
unreachable!()panic on the matter-parse error path
instream::parse::parse_matter; the error mapping is now a totalmatch. - core (#33):
MatterBuilder::from_qualified_base64no longer panics
(range end index N out of range for slice of length 0) on a malformed qb64 whose
decoded buffer is shorter than the code's declared lead size (e.g.5BAA). The
lead-byte slices are now bounds-checked and return
MatterBuildError::Validation(ValidationError::StructuralIntegrityError). Found by
thedeep-fuzzmatter_from_qb64target; the crash input is committed as a fuzz
corpus regression seed.
Added
- crypto/devx (#69): indexed signatures (
Siger, the form attached to KERI
events) can now be verified directly — closing the sign/verify asymmetry where
sign_indexedproduced aSigerbutverifyonly accepted aCigar. This
lands as a type-unified verify surface rather than a one-off method:- A
crypto::Signaturetrait implemented by bothCigar(non-indexed) and
Siger(indexed), so a single genericverifycovers both — the caller
never branches on "indexed or not". KeyPair::<A>::verify<S: Signature>(&self, data, &S) -> Result<(), SignatureError>
— one generic method (was three duplicatedverifymethods) with per-curve
crypto dispatched onAat compile time via the new
Algorithm::verify_bytes.kp.verify(msg, &cigar)andkp.verify(msg, &siger)
both work.- Free
crypto::verify<S: Signature>(verfer, data, &S)— the verifier-key-driven
form (mirrors keripy'ssiger.verfer.verify(siger.raw, ser)) for verifying
with only public keys. Composes into lazy iterator chains overstream-parsed
signature groups:sigers.try_for_each(|s| verify(verfer, msg, s)). - Verification is strict: a signature whose CESR code does not belong to the
key's algorithm is a typed error, not a silent failure. TheSigerindex is
CESR framing metadata and is not part of the signed payload. - Also adds
Algorithm::owns_indexedandAlgorithm::NAME.
(#69)
- A
Breaking
- crypto (#69): verification now returns
Result<(), _>instead of
Result<bool, _>.Ok(())means verified; a cryptographically invalid
signature is the newSignatureError::Invalid, moved out of the success channel
soverify(..).is_ok()can no longer mistake a forgery for a valid signature.
AffectsKeyPair::verifyand the freecrypto::verify. Callers change
if kp.verify(..)?tokp.verify(..)?;(propagate) or match on the error. - crypto (#69): new
SignatureError::Invalidand
SignatureError::CodeMismatch { expected, actual }variants;SignatureError
is not#[non_exhaustive], so exhaustive downstreammatches must add arms.
TheAlgorithmtrait gains required items (NAME,verify_bytes) — but it is
sealed, so no external impls are affected.
v0.3.0
Added
- (#68) [breaking] self-addressing builder prefixes (write/read parity) (#71)
- (#31) prelude + flattened re-exports (#66)
Other
- (#32) runnable examples for the primitive→event walk-through (#70)
- (#64) reproducible concurrent-parse allocation-payoff harness (#65)
- (#30) zero-copy stream parsing + test/coverage/mutation safeguards (#63)
- (#57) kill the utils dumping grounds + cohesive b64 (naming + error de-collision) (#62)
- (#29) add isolated base64-crate baseline; no faster codec found (#61)
- (#57) include stream in the no_std flake build
- (#57) [breaking] split b64 module into int/binary/charset
- (#57) [breaking] rename utils module -> b64, kill utils::utils inception
- (#56) [breaking] make encode_int infallible, fold stream::int_to_b64 into it
- (#56) consolidate base64 alphabet to one canonical table
Added
- api (#68):
SerializedEvent::identifier() -> Option<Identifier<'static>>
bridge for chaining KEL events — hands an inception's self-addressing prefix to
the next builder without re-parsing JSON.
(#68) - api (#68):
CloneforMatter(all primitive aliases) andIdentifier.
(#68) - docs (#68): examples
kel_chain(a realicp -> ixn -> rotself-addressing
chain) anddelegated_inception(a self-addressing delegator), closing #32
examples #5/#6.
(#68) - devx (#31): ergonomic public surface — flagship types are now reachable at
the crate root (cesr::Matter,cesr::Verfer,cesr::CesrGroup, …) and at
their module root (cesr::core::Matter), and a newcesr::preludere-exports
the common traits (CesrEncode,KeriSerialize/KeriDeserialize,Algorithm,
ConfigTrait) plus headliner types foruse cesr::prelude::*;. Purely
additive — existing module paths are unchanged. The one name collision,
CesrVersion, is disambiguated at the root ascesr::CesrVersion(core) and
cesr::StreamCesrVersion(stream). Free functions remain module-qualified
(cesr::b64::encode_int). - bench (#29):
benches/base64.rs— isolatedbase64-crateURL_SAFE_NO_PAD
microbenchmarks at 32/64/1024 B, the reference baseline for the Base64 inner
loop. Investigation outcome: a specialized scalar codec and stack-buffer
allocation removal were both implemented and measured end-to-end, and both
regressed (decode +8–16 %, encode +6 %). At CESR sizes the encode/decode
seams are already overhead-bound on the fastbase64engine plus thread-cached
small allocations — no faster codec is available, so no production change ships.
See #29 for the full measurement table. - test/ci (#30): zero-copy safeguards —
tests/allocation.rs(thread-local
counting allocator) asserting group-iteration allocations stay invariant to
group count, so a regression to per-group copying fails the suite; per-shape
aliasing tests proving parsers slice rather than copy; fullGroupsV2iterator
coverage; astream_parse_scalingbenchmark (N = 1..256 groups);cargo-mutants
in the dev shell for on-demand mutation testing (core stream logic: 100% of
non-equivalent mutants killed); and on-demandllvm-covcoverage via
nix build .#coverageplus a post-merge workflow (mirrors thebombayrepo).
None of these are gating checks.QuadletGroup::to_bytes()— O(1) shared-buffer
accessor. - bench (#64):
examples/concurrent_parse.rs— a reproducible concurrent-parse
allocation-payoff harness (run:cargo run --release --example concurrent_parse --features stream) answering the #30 follow-up "does the allocation reduction
actually pay off?". It pits two real, public production arms parsing the same
16-group stream: copy-oncegroups()(2 allocs/stream) vs aparse_group()
loop that faithfully reproduces the pre-#30 per-group copy (32 allocs/stream,
plus O(N²) remainder re-copying — exactlyorigin/main's behavior). A
single-threaded armed counting allocator self-checks the 1-vs-N invariant before
any timing; the timed passes run disarmed across 1/2/4/8 threads so instrumentation
never perturbs wall-clock. Verdict: VINDICATED. On a 14-core Apple M-series
(release): copy-once/per-group throughput ratio 2.52× / 1.88× / 3.25× / 3.88× at
1/2/4/8 threads — copy-once wins at every thread count and the gap widens under
contention (per-group scales only ~4.2× across an 8× thread increase — the
allocator-contention signature). This does not contradict #30's single-thread
regression note below: that used a 2-group fixture where O(N²)≈O(N) so the copy
savings vanish; the win here needs both a larger group count and the faithful
O(N²)origin/mainbaseline. Numbers are wall-clock and machine-dependent — the
harness is a run-and-read measurement, not a CI gate.
Changed
- api (#68)!:
RotationBuilder::prefix,InteractionBuilder::prefix,
DelegatedInceptionBuilder::delegator, andDelegatedRotationBuilder::prefix
now takeimpl Into<Identifier<'static>>instead ofPrefixer<'static>.
ExistingPrefixercall sites keep compiling; self-addressing (transferable)
prefixes and delegators are now expressible, closing the write-path/read-path
parity gap for both the direct (icp -> ixn -> rot) and delegated
(dip -> drt) KEL chains.
(#68) - perf (#30): stream group parsing now slices a shared
bytes::Bytesinstead
ofBytes::copy_from_slice, trading a small amount of per-parse CPU (Arc
refcounting + a level of indirection) for fewer heap allocations — the
intended benefit for allocator-pressure / fragmentation / no_std. Allocation
count per multi-group message drops from ~N to 1 (0 on the async codec's
non-quadlet decode path, which is now zero-copy on success).unwrap_generic_group
andGroups/GroupsV2slice a once-copied region instead of re-copying. Public
parse_group/parse_group_v2/parse_message/groups/groups_v2
signatures are unchanged — non-breaking. This is not a throughput win.
Measured cost (accepted, since fewer allocations is the goal): parsing is
~22–28 % slower on small streams — CodSpeed on this PR:
controller_idx_sigs_1sig−27.7 %,multi_group_controller_witness−21.7 %; the
fixed overhead amortizes toward parity as stream size grows (per-group cost is
~equal tomainat N≥16 groups). BorrowedMatter<'a>and a parser-combinator
crate were evaluated and deliberately not adopted (see the issue).
(#30)
Changed
- refactor (#57)!: Killed the remaining "utils" dumping grounds.
stream::util
is removed (itsint_to_b64/b64_to_intnow route throughb64::encode_int/
b64::decode_int);core::utils's code-size lookups moved to
core::matter::code::hard;stream::binaryis renamedstream::qb2(public
stream::qb64_to_qb2/qb2_to_qb64paths unchanged). The single Base64 byte
lookup isb64::alphabet::b64_byte_to_index.
Breaking
RotationBuilder::prefix/InteractionBuilder::prefix/
DelegatedInceptionBuilder::delegator/DelegatedRotationBuilder::prefixnow
takeimpl Into<Identifier<'static>>instead ofPrefixer<'static>(#68).b64::decode_to_int→b64::decode_int(input bound widened toAsRef<[u8]>).core::indexer::error::{ParseError, ValidationError}→
{IndexerParseError, IndexerValidationError}.stream::utilmodule removed;stream::binarymodule renamedstream::qb2
(re-exported functions keep theirstream::paths).
v0.2.0
Other
- Merge remote-tracking branch 'origin/main' into perf/p1.1-allocation-audit
- add justfile for a fast, multi-threaded local dev loop
- (stream) [breaking] encode Matter qb64 in-place, ~51% faster
- (deps) realign digest to 0.10 to collapse duplicate crypto stack
Changed
- (stream) BREAKING:
matter_to_qb64now returnsResult<Vec<u8>, ParseError>instead ofVec<u8>. It Base64-encodes directly into the output buffer viaencode_slice, removing an intermediateStringand a padding reallocation, and replaces a release-compiled-outdebug_assertwith a real length-invariant check.SerderErrorgains aQb64Encoding(ParseError)variant. Encode throughput improves ~51% (Ed25519 qb64: 84.7 ns → 41.8 ns, now faster than decode). (#28)
Other
- (deps) realign
digestto 0.10 to collapse a duplicate crypto stack in the shipped tree (dropsdigest 0.11,crypto-common 0.2,hybrid-array)
v0.1.3
Added
- (diff) keripy corpus generator (scripts/keripy_diff_gen.py)
Fixed
- allow empty raw for zero-rawsize Matter codes (#48)
- zero-fill Indexer ondex slot for CurrentOnly codes (#47)
- (diff) embed corpus via include_str! for hermetic nextest
Other
- make CodSpeed perf-gate pass the nix gate (#41)
- add CodSpeed continuous benchmarking
- (diff) include tests/corpus in the crane source filter
- (diff) extract indexer decode/encode helpers under clippy line limit
- (diff) rustfmt the keripy differential harness
- exclude keripy diff corpus from the typos gate
- (diff) nightly keripy differential parity workflow
- (diff) make Matter zero-raw finding a failing bug-probe (#48)
- (diff) composed-stream differential replay vs keripy
- (diff) Indexer differential replay vs keripy
- (diff) Counter v1+v2 differential replay vs keripy
- (diff) Matter differential replay vs keripy
- (diff) checked-in keripy corpus @v2.0.0.dev5 (653 vectors)
- (diff) scaffold keripy differential harness (loader + DiffVector)
- resolve P0.3 codec-entry-point open items + implementation plan
- design spec for P0.3 differential testing vs keripy
v0.1.2
Fixed
- (matter) reject malformed qb2 instead of panicking in from_qualified_base2 (#43)
Other
- exclude release-plz CHANGELOG.md from the typos gate
- fix typo (driveable -> drivable) in fuzzing plan (#26)
- document the fuzzing harness (#26)
- add scheduled nightly deep-fuzz workflow (#26)
- add cesr-fuzz-replay corpus-replay check to the flake gate (#26)
- implementation plan for P0.2 fuzzing harness (#26)
- design spec for P0.2 fuzzing harness (#26)
- drop README-must-be-staged pre-commit enforcement
- Merge branch 'main' into perf/p0.1-benchmark-harness
- Merge branch 'main' into docs/strategy
- add foundation-first development strategy
- lift the API freeze — cesr is now in active development
v0.1.1
Other
- (release) add manual workflow_dispatch to the release workflow
- (deps) tune Dependabot for a frozen-API crate
- fix typos gate on merged main and list hygiene gates in README
- Merge pull request #12 from devrandom-labs/chore/repo-security
- port nexus guidelines to CLAUDE.md and gate releases on src changes
v0.1.0
chore: Release package cesr-rs version 0.1.0