Class SignedLockedVoucher

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

public final class SignedLockedVoucher extends Object
A signed voucher that is also P2PK-locked.

The P2PK_VOUCHER counterpart to SignedVoucher. Same job — carry a signed voucher and let a holder verify it — over the composite kind whose lock the mint actually enforces.

Why a separate type rather than widening SignedVoucher

SignedVoucher holds a VoucherSecret, and P2PKVoucherSecret is its SIBLING rather than a subclass — both extend WellKnownSecret. That split is deliberate upstream: a mint must be able to test for the locked kind first, so a broader "is a voucher" branch cannot swallow it and skip the witness check.

Widening SignedVoucher's field to the common supertype would reach 37 call sites that read it as a VoucherSecret, and would let a caller construct one around a secret carrying no voucher metadata at all. Two narrow types, each certain of what it holds, cost one class and remove a whole category of mistake.

The lock is not advisory

A plain VOUCHER that merely NAMES a holder is dispatched by the mint to its voucher condition, which checks the issuer signature and expiry and never looks for a witness — so a thief holding the proof can spend it, and every client-side check is the only thing in the way. Under this kind the mint runs both conditions and the refusal comes from the mint.

See Also:
  • Constructor Summary

    Constructors
    Constructor
    Description
    SignedLockedVoucher(@NonNull xyz.tcheeric.cashu.common.nut11.P2PKVoucherSecret secret)
    Wraps a secret that already carries its signature and public key.
  • Method Summary

    Modifier and Type
    Method
    Description
    createSigned(@NonNull xyz.tcheeric.cashu.common.nut11.P2PKVoucherSecret secret, @NonNull String issuerPrivateKeyHex, @NonNull String issuerPublicKeyHex)
    Signs a locked voucher and wraps the result.
    boolean
    equals(Object other)
     
    The key a spender must produce a witness signature for, hex-encoded.
    xyz.tcheeric.cashu.common.nut11.P2PKVoucherSecret
     
    int
     
    boolean
     
    boolean
    Signed and unexpired.
     
    boolean
    Whether the issuer's signature checks out over this voucher's canonical bytes.

    Methods inherited from class java.lang.Object

    clone, finalize, getClass, notify, notifyAll, wait, wait, wait
  • Constructor Details

    • SignedLockedVoucher

      public SignedLockedVoucher(@NonNull @NonNull xyz.tcheeric.cashu.common.nut11.P2PKVoucherSecret secret)
      Wraps a secret that already carries its signature and public key.
      Parameters:
      secret - a signed P2PK_VOUCHER secret
      Throws:
      IllegalArgumentException - if the secret is unsigned, or carries no lock
  • Method Details

    • createSigned

      public static SignedLockedVoucher createSigned(@NonNull @NonNull xyz.tcheeric.cashu.common.nut11.P2PKVoucherSecret secret, @NonNull @NonNull String issuerPrivateKeyHex, @NonNull @NonNull String issuerPublicKeyHex)
      Signs a locked voucher and wraps the result.

      Goes through VoucherSignatureService.sign(xyz.tcheeric.cashu.common.nut10.WellKnownSecret, java.lang.String) rather than createSigned, because that method takes a VoucherSecret and this kind is not one. The signing itself is already generic: sign accepts any WellKnownSecret, and VoucherCanonicalBytes renders VOUCHER and P2PK_VOUCHER through the same path. So the bytes signed here are produced by the same code that signs an unlocked voucher, which is what keeps the two verifiable by one verifier.

    • getSecret

      public xyz.tcheeric.cashu.common.nut11.P2PKVoucherSecret getSecret()
    • getLockKey

      public String getLockKey()
      The key a spender must produce a witness signature for, hex-encoded.
    • verify

      public boolean verify()
      Whether the issuer's signature checks out over this voucher's canonical bytes.
    • isExpired

      public boolean isExpired()
    • isValid

      public boolean isValid()
      Signed and unexpired.

      The lock is NOT re-checked here, and does not need to be: the constructor refuses a secret with no spending key, so an instance of this type is locked by construction. Saying "plus the lock" here would read as a runtime check that does not exist, and invite someone to delete the constructor guard believing this covered it.

      What this does NOT establish is that the SPENDER holds the key. That is the mint's job, verified against the witness at spend time. A caller treating isValid() as "safe to accept as payment" would be reading it as proof of ownership rather than proof of issuance.

    • equals

      public boolean equals(Object other)
      Overrides:
      equals in class Object
    • hashCode

      public int hashCode()
      Overrides:
      hashCode in class Object
    • toString

      public String toString()
      Overrides:
      toString in class Object