Check the invoice without seeing it.
Countersign is a registry of invoice fingerprints, pledges and customer confirmations. It is built so that no single party's word is enough, the registry never receives an invoice, and every answer is a receipt anyone can check. Here is how, and how far along each piece is.
Each state is signed by whoever knows it.
No step relies on the lender's word, an AI review, or our database alone.
| State | Signed by | What it proves |
|---|---|---|
| Registered | Supplier, at issue | This invoice existed in this form at this time. |
| Countersigned | Customer (the account debtor) | The customer owes it, unchanged, and to this pay-to account. |
| Pledged | Lender | Who funded it first, without telling other lenders who. |
| Released | Lender, or the payment itself | It's paid or repurchased, so it can't be funded again. |
The registry adds its own signature to every state change through Optima Prime, so the record of who said what, and when, can't be quietly edited later.
Blinded fingerprints.
Building
Invoice fields are low-entropy. A plain hash of a supplier tax ID, an invoice number and an amount can be guessed by brute force in minutes. A shared secret key doesn't fix that either, because every member would need the key and any of them could run the guesses.
Countersign uses an oblivious pseudorandom function (OPRF) over the ristretto255 group. Your side blinds the fields before they leave; the registry applies its secret key to a value it can't read; your side removes the blind. The result is a fingerprint only computable with the registry's help, one rate-limited query at a time.
# on the lender's or supplier's side fields = normalise(supplier_tax_id, customer_tax_id, invoice_no, issue_date, amount_cents, currency, due_date) P = hash_to_group(fields) # ristretto255 point r = random_scalar() B = r * P # blinded; reveals nothing # at the registry (never sees fields or P) Z = k * B # k = registry key # back on your side F = hash(fields, (1/r) * Z) # = hash(fields, k * P) fingerprint = "cs1:" + F
Normalising matters as much as the cryptography: the same invoice must give the same fingerprint whether it came from a PDF, a CSV row or an accounting system. Tax IDs, invoice numbers, dates and amounts each get one canonical form before hashing.
Planned The registry key k is split between independent key holders, so no single party, including us, can compute fingerprints alone.
Exact and partial matches.
Building
One fingerprint can only say "same" or "different". To catch a $180 invoice resubmitted as $9,000, each invoice gets several fingerprints over different groups of fields:
| Fingerprint | Fields | Catches |
|---|---|---|
| full | All core fields | An exact duplicate |
| identity | Supplier, customer, invoice number | The same invoice with a changed amount or date |
| economics | Supplier, customer, amount, issue date | The same invoice under a new number |
A check returns one of: never seen (no record, which is not a pass), registered and unchanged, registered but fields differ, already pledged to another lender, or countersigned by the customer.
The customer countersignature.
Building
Signing at issue stops later changes and double sales. It can't stop a supplier from inventing an invoice. Only the customer knows whether it owes the money, so the customer's confirmation is the core of the product.
- Countersign finds and verifies the customer's payables contact itself. The supplier never supplies it.
- The customer gets a link. No account, no app.
- They confirm with a passkey (WebAuthn: Face ID, Touch ID, Windows Hello or a security key). The passkey signs a challenge built from the invoice fingerprint, the amount and a hash of the pay-to account.
- That signature is attached to the invoice's record and to the lender's receipt.
Because the pay-to account is part of what the customer signs, a later request to send the money somewhere else needs a new countersignature from the customer. Large payables teams can register a hardware security key instead; Optima Prime already verifies those as standard OpenSSH signatures.
An append-only pledge log.
Planned
"Who pledged first" is only worth something if the registry can't reorder or hide entries. Every pledge and release is appended to a Merkle tree, in the style of Certificate Transparency (RFC 6962). The tree's head is signed and time-stamped by an independent RFC 3161 time-stamp authority.
Any member can ask for an inclusion proof (my pledge is in the log) and a consistency proof (today's log extends yesterday's without rewriting it). Entries hold fingerprints and blinded member IDs, so the log can be audited without exposing anyone's book.
Receipts anyone can check.
Done in Optima Prime
Countersign signs through Optima Prime, our signing server. Its /v1/attest endpoint signs a statement that a given key attested a given SHA-256 at a given time, without ever seeing the data behind the hash. That is exactly the shape of an invoice fingerprint.
Every receipt carries two signatures over canonical JSON: Ed25519 and the post-quantum ML-DSA-87, so the evidence stays checkable for the years a dispute can run. The public keys are published, and a receipt can be verified offline with open tools.
{
"statement": "check",
"fingerprint":"cs1:7f3a91c0e24b0d8f55a1c9e73b02aa64",
"result": "fields_differ",
"member": "m_9c2e", // blinded
"time": "2026-10-10T16:42:09Z",
"signatures": { "ed25519": "…", "ml_dsa_87": "…" }
}
Field names above are illustrative. The receipt format is being finalised.
What we store, and what we never get.
| Stored | Never received |
|---|---|
| Fingerprints (blinded, see 02) | The invoice document |
| Pledge and release states | Customer and supplier names |
| Member IDs | Amounts and terms in the clear |
| Signed receipts and countersignatures | Your client list |
A hit tells a lender that a match exists. It never says which lender holds it. Identities are released only with the holder's consent or under legal process, under a written member rulebook.
Stack.
No blockchain. No token.
| Piece | Built with | Status |
|---|---|---|
| Signing and verification | Optima Prime, on our own hardware | Done |
| Registry API and matching | PHP 8.1 and MySQL on our own Ubuntu servers | Building |
| Blinded fingerprints | libsodium ristretto255 | Building |
| Customer countersignature | WebAuthn passkeys | Building |
| Intake | REST API and CSV upload; QuickBooks Online first | Building |
| Pledge log | Merkle tree with RFC 3161 time stamps | Planned |
| Signing keys in a hardware module | HSM-held Optima Prime keys | Planned |
Countersign is closed source. The receipts aren't: their format and the public keys are published, so checking one never depends on trusting our code.
What it can't do.
Countersign informs. It doesn't enforce. A lender that funds without waiting for the customer's confirmation is back to taking the supplier's word.
- If someone inside the customer's payables team is in on the fraud, their countersignature is a lie too. Confirmation history across lenders and matching against actual payments help, but nothing fully stops collusion.
- Detecting a double sale needs the other lender to be a member. An empty network only protects your own book.
- A receipt is evidence. It does not perfect a lien or set legal priority between lenders.