Class UnlockedVoucherBlob

java.lang.Object
xyz.tcheeric.cashu.voucher.domain.UnlockedVoucherBlob

public final class UnlockedVoucherBlob extends Object
Reads the voucher inside an UNLOCKED voucher secret's data blob.

Why this exists, and why here

The two voucher kinds keep their fields in different places. A P2PK_VOUCHER carries them as NUT-10 tags, so any verifier can read them straight off the secret. A plain VOUCHER carries them as CBOR inside data, with an EMPTY tag array on the wire.

That asymmetry had a consequence nobody intended. Every check in VoucherMetadata reads tags, so for an unlocked voucher they all found nothing and passed: no signature check, no expiry check, no issuer binding. A verifier could not see the fields even though they were right there in the blob.

It lives in cashu-voucher-domain because reading a voucher is not anybody's private business. The same decode already existed inside imani-gateway-customer's SignedVoucherCodec, where the mint cannot reach it, which is precisely why the mint could not check what it was accepting.

What it does not do

No opinions. It returns the voucher the blob describes, or nothing when the blob cannot be read. Deciding whether that voucher is acceptable belongs to the caller, so a malformed blob and an expired voucher stay distinguishable.

cashu-mint#525.

  • Method Summary

    Modifier and Type
    Method
    Description
    static boolean
    carriesSignature(@NonNull xyz.tcheeric.cashu.common.nut10.WellKnownSecret secret)
    Whether this secret is an unlocked voucher whose blob names an issuer signature.
    static xyz.tcheeric.cashu.common.nut18.VoucherSecret
    read(@NonNull xyz.tcheeric.cashu.common.nut10.WellKnownSecret secret)
    The voucher described by an unlocked voucher secret's blob, or null.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Method Details

    • read

      public static xyz.tcheeric.cashu.common.nut18.VoucherSecret read(@NonNull @NonNull xyz.tcheeric.cashu.common.nut10.WellKnownSecret secret)
      The voucher described by an unlocked voucher secret's blob, or null.

      Returns null rather than throwing, because "this is not a readable unlocked voucher" is an ordinary answer on a path that also sees locked vouchers and plain bearer secrets. A caller that requires one refuses on null.

      Parameters:
      secret - a secret of kind VOUCHER
      Returns:
      the voucher the blob describes, with its signature tags set, or null
    • carriesSignature

      public static boolean carriesSignature(@NonNull @NonNull xyz.tcheeric.cashu.common.nut10.WellKnownSecret secret)
      Whether this secret is an unlocked voucher whose blob names an issuer signature.

      Separate from read(xyz.tcheeric.cashu.common.nut10.WellKnownSecret) so a caller can tell "unsigned" from "unreadable" without inspecting the result, since those two deserve different refusals.