Skip to content

v0.4.0

Choose a tag to compare

@devrandom-release-plz devrandom-release-plz released this 05 Jul 13:14
e251e01

Added

  • (#67) [breaking] infallible Matter::to_qb64 in core (text encoding without stream) (#78)
  • (#69) [breaking] type-unified, composable signature verification (#72)

Fixed

  • (#76) [breaking] checked size arithmetic in MatterBuilder variable-size parse (#77)

Other

  • (#33) [breaking] replace terrors::OneOf with domain error enums (#74)
  • fix deep-fuzz workflow (engine-arg parsing + nightly toolchain) (#75)

Changed

  • core (#76): ValidationError gains a new SizeOverflow variant, returned
    when computing a variable-size primitive's full size from its decoded soft field
    overflows usize. As ValidationError is public and not #[non_exhaustive],
    this is breaking (MINOR under 0.x) for downstream exhaustive match on it.
  • error ergonomics (#33): removed the terrors::OneOf error-union layer in
    favour of purpose-built thiserror enums. Breaking (MINOR under 0.x):
    • MatterBuilder::{from_qualified_base64, from_qualified_base2, build} now return
      Result<_, MatterBuildError> (variants Parsing, Validation) instead of
      OneOf<(ParsingError, ValidationError)>.
    • crypto::verify now returns Result<(), VerificationError> (variants
      Signature, CodeMismatch) instead of OneOf<(SignatureError, CodeMismatchError)>.
    • The indexer builder's parse/validation methods (from_qb64, from_qb2,
      with_index, with_indices, with_raw) return the bare IndexerParseError /
      IndexerValidationError (previously wrapped in a single-element OneOf).
    • Consumers matching on these results switch from .take:: / .narrow:: to a
      normal match on the new enums / bare types.
    • SerderError gains a new UnparseablePrimitive variant (see Fixed below).
      As SerderError is public and not #[non_exhaustive], this is breaking for
      downstream exhaustive match on it.
    • The terrors dependency is dropped.
  • core / serder (#67): qb64 text encoding moved to core. Breaking
    (MINOR under 0.x):
    • Matter<C> gains infallible to_qb64() -> String and to_qb64b() -> Vec<u8>;
      encoding a key/digest/signature to text no longer requires the stream feature.
    • stream::encode::matter_to_qb64 removed (use Matter::to_qb64b).
    • serder::primitives::{to_qb64_string, identifier_to_qb64_string} now return
      String instead of Result<String, SerderError>; the internal
      serder::serialize::{seal_to_json, matters_to_json_array} helpers likewise
      became infallible.
    • SerderError loses the Qb64Encoding and Encoding variants (their only
      producers are gone). Breaking for downstream exhaustive match on SerderError.

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
    use checked_mul/checked_add and return ValidationError::SizeOverflow on
    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 at ss=4, so size <= 2^24-1); fixed as a defense-in-depth rule violation.
  • serder (#33): a malformed-but-unparseable field value no longer collapses a
    ParsingError into ValidationError::UnknownMatterCode(..) via string
    formatting; a new SerderError::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
    in stream::parse::parse_matter; the error mapping is now a total match.
  • core (#33): MatterBuilder::from_qualified_base64 no 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
    the deep-fuzz matter_from_qb64 target; 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_indexed produced a Siger but verify only accepted a Cigar. This
    lands as a type-unified verify surface rather than a one-off method:
    • A crypto::Signature trait implemented by both Cigar (non-indexed) and
      Siger (indexed), so a single generic verify covers both — the caller
      never branches on "indexed or not".
    • KeyPair::<A>::verify<S: Signature>(&self, data, &S) -> Result<(), SignatureError>
      — one generic method (was three duplicated verify methods) with per-curve
      crypto dispatched on A at compile time via the new
      Algorithm::verify_bytes. kp.verify(msg, &cigar) and kp.verify(msg, &siger)
      both work.
    • Free crypto::verify<S: Signature>(verfer, data, &S) — the verifier-key-driven
      form (mirrors keripy's siger.verfer.verify(siger.raw, ser)) for verifying
      with only public keys. Composes into lazy iterator chains over stream-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. The Siger index is
      CESR framing metadata and is not part of the signed payload.
    • Also adds Algorithm::owns_indexed and Algorithm::NAME.
      (#69)

Breaking

  • crypto (#69): verification now returns Result<(), _> instead of
    Result<bool, _>. Ok(()) means verified; a cryptographically invalid
    signature is the new SignatureError::Invalid, moved out of the success channel
    so verify(..).is_ok() can no longer mistake a forgery for a valid signature.
    Affects KeyPair::verify and the free crypto::verify. Callers change
    if kp.verify(..)? to kp.verify(..)?; (propagate) or match on the error.
  • crypto (#69): new SignatureError::Invalid and
    SignatureError::CodeMismatch { expected, actual } variants; SignatureError
    is not #[non_exhaustive], so exhaustive downstream matches must add arms.
    The Algorithm trait gains required items (NAME, verify_bytes) — but it is
    sealed, so no external impls are affected.