Network authority family

Cross Acceptor Receipt: settling how widely one authority was used, without naming a single acceptor

The Cross Acceptor Receipt is a signed statement that the issuing service, for a declared authority grouping and accounting window, received the contribution and coverage evidence it describes, verified keyed pseudonym derivations under a committed window salt, and recomputed a distinct acceptor count, a dispersion class, three commitments, a cumulative relation and a coverage class. Principals who grant spending authority, the acceptors who honour it, and anyone asking whether one mandate was quietly used across a whole market need it.

The property that separates it from a spend report is that the acceptors are counted without being named. Each acceptor becomes a pseudonym derived by HMAC under a per authority, per window salt, so the same acceptor collapses to one identity inside a window and is unlinkable across windows. The ceiling, the accumulated amount and the checked action count never appear, even as numbers. What is disclosed is a count, a dispersion bucket and a within or exceeds relation. The receipt states plainly that it cannot know whether every acceptor reported.

The problem

An authority is granted once and then used in many places. A card mandate presented at fifty merchants. An agent credential accepted by twenty services. The per action rule holds at every one of them, and the aggregate picture is invisible to all of them.

This is the structural blind spot of distributed acceptance. Each acceptor sees its own slice, evaluates its own transaction against its own view of the constraint, and approves. No acceptor sees the sum. The principal who granted the authority sees whatever its own systems happened to capture, which is usually its own slice too.

Name the parties. The principal asserts it granted a bounded authority. Each acceptor asserts it honoured a valid presentation. The actor asserts it stayed within what it was given. Somebody downstream discovers that the aggregate was far beyond the bound, and there is no party who was in a position to notice.

Three specific failures.

The first is that per action conformance does not compose. A hundred conforming actions can exceed any cumulative intent. The Mandate Conformance Receipt says so in its own boundary. Aggregating across a single acceptor is straightforward. Aggregating across acceptors that do not talk to each other is the hard case.

The second is that acceptors will not identify each other. Two competing merchants have no interest in a report that tells either of them who else the customer transacts with. An aggregation scheme that requires acceptor identities to be disclosed to a central party, or to each other, is a scheme nobody joins.

The third is that partial reporting is invisible. If eighteen of twenty acceptors report, the aggregate looks like a complete picture unless the report says otherwise. Silence from an acceptor is indistinguishable from that acceptor having no activity.

The confidentiality problem extends to the numbers. The cumulative ceiling is a commercial term between the principal and the actor. The accumulated position is sensitive to both. A report that discloses either in order to prove a relation between them is a report neither party will authorise.

When the actor is autonomous, breadth becomes the dominant risk. A human customer transacts with a handful of merchants. An agent can present the same authority at hundreds of acceptors inside an hour, and dispersion becomes a signal worth measuring in its own right.

What the receipt binds

The schema is at https://thehiveryiq.com/.well-known/schemas/cross-acceptor-v1.json. The signed body has three top level fields: receipt_type fixed to mandate.crossacceptor, schema fixed to r1.0.0, and cross_acceptor_window, plus the boundary. Everything of substance lives in the window object.

FieldMeaning
window_idIdentifier matching cw_ plus 16 to 64 hex characters.
window_start and window_endThe accounting window bounds as UTC instants.
window_indexThe position of this window in its chain.
aggregation_keyThe 64 hex value grouping actions into one accumulation without naming a party.
currencyA three letter code.
pseudonym_algorithmFixed to hmac_sha256_v1.
pseudonym_scopeFixed to per_authority_per_window.
limit_commitmentCommitment to the cumulative ceiling.
aggregated_notional_commitmentCommitment to the accumulated amount.
checked_action_count_commitmentCommitment to the number of actions checked.
salt_commitmentCommitment to the window salt.
contribution_set_digestCanonical digest over the contribution multiset.
coverage_set_digestCanonical digest over the coverage report set.
distinct_acceptor_countHow many distinct acceptors contributed, up to 100000.
reporting_acceptor_countHow many acceptors reported.
expected_acceptor_countHow many were expected, at least one.
dispersion_classOne of no_checked_actions, concentrated, moderately_distributed, distributed, highly_distributed or indeterminate.
coverage_classOne of complete, declared_subset or undeclared_subset.
evidence_access_classOne of confidential_independent, issuer_only or public_commitment_only.
cumulative_relationOne of within_constraint, exceeds_constraint or indeterminate.
prior_windowThe predecessor window link, or null.
closed_byEither schedule or constraint_reached.

Note the three counts. Distinct contributing acceptors, reporting acceptors and expected acceptors are separate numbers, and the difference between the last two is exactly what coverage_class reports.

What is deliberately not in the signed body

No acceptor identity, no window salt, no contribution multiset, no checked action count, no exact dispersion ratio, no cumulative constraint and no accumulated amount. The receipt discloses counts, classes and a relation.

Five constructions in src/typed/cross-acceptor.js do the work. Four are HMAC-SHA256 keyed by the raw window salt bytes, over a message built from a domain label followed by each part preceded by a zero byte. The domain labels are distinct and versioned:

  • mandate.crossacceptor/acceptor/v1 over the aggregation key and the acceptor identifier gives an acceptor pseudonym. Because the aggregation key and the salt are both per authority and per window, the same acceptor produces one stable pseudonym inside a window and an unrelated one in the next.
  • mandate.crossacceptor/checked-action-count/v1 over the decimal action count and the aggregation key gives checked_action_count_commitment.
  • mandate.crossacceptor/limit/v1 over the decimal limit in minor units, the currency and the aggregation key gives limit_commitment.
  • mandate.crossacceptor/aggregated-notional/v1 over the decimal accumulated amount, the currency and the aggregation key gives aggregated_notional_commitment.

The fifth is the salt commitment, a plain SHA-256 over the UTF-8 label mandate.crossacceptor/salt/v1, a zero byte, and the raw salt bytes.

Set digests use a different rule. A canonical set digest is SHA-256 over the canonical JSON body of an object holding a domain label and a sorted array of values, serialised under the shared rule of recursively sorted keys, no whitespace and non ASCII escaped as lowercase \uXXXX. Sorting gives one canonical digest per set regardless of the order evidence arrived in.

Dispersion is reported as a bucket derived by integer cross multiplication, with no division and therefore no rounding. Let d be the distinct acceptor count and n the checked action count. With n zero, the class is no_checked_actions when d is zero and indeterminate otherwise. With d zero, or d greater than n, the class is indeterminate. Otherwise: four times d at or below n gives concentrated; two times d at or below n gives moderately_distributed; four times d at or below three times n gives distributed; anything else gives highly_distributed. The exact ratio is never disclosed.

The receipt envelope uses the shared Ed25519 construction over the ASCII string hive-receipt <receipt_id> <payload_sha256> <ts>.

The gates

Verification runs in this order and stops at the first failure.

  1. SCHEMA. Validates the envelope against the cross acceptor v1 schema, including the fixed pseudonym algorithm and scope constants. A failure means the artifact is malformed.
  2. ISSUER_KEY_MATCH. Resolves the envelope key through the trusted resolver. A failure means the signer is not trusted here.
  3. PAYLOAD_DIGEST_VALID. Recomputes the canonical digest of the signed body against payload_sha256. A failure means the body was altered after signing.
  4. SIGNATURE_VALID. Verifies the Ed25519 signature over the signing string. A failure means no available key produced it.
  5. WINDOW_BOUNDS_ORDERED. Requires the window bounds to run forwards and requires every supplied contribution to fall inside them. A failure means a contribution from outside the window was folded in.
  6. WINDOW_LINK. Requires the predecessor reference to be well formed, including its ordinal. A failure means the chain reference is malformed.
  7. WINDOW_PREDECESSOR_INTEGRITY. Requires the named predecessor window to be supplied and to verify. A failure means the previous window is missing or broken.
  8. WINDOW_CONTINUITY. Requires the window chain to be continuous, including agreement on currency across windows. A failure means the chain changed terms between windows.
  9. SALT_BINDING. Requires the disclosed salt to recompute to salt_commitment. A failure means the salt does not open the published commitment.
  10. CONTRIBUTION_SET_INTEGRITY. Recomputes the canonical contribution set digest from the supplied evidence and compares. A failure means the contribution multiset is not the one committed.
  11. CONTRIBUTION_WINDOW_MEMBERSHIP. Recomputes the coverage set digest and checks membership of the contributions in the window. A failure means the coverage evidence does not match.
  12. DISTINCT_ACCEPTOR_COUNT_RECOMPUTE. Recomputes the number of distinct acceptor pseudonyms from the evidence and compares to distinct_acceptor_count. A failure means the count was inflated or understated.
  13. DISPERSION_CLASS_RECOMPUTE. Recomputes the checked action count commitment, then derives the dispersion class from the distinct acceptor count and the checked action count and compares. It fails when the two counts do not produce a determinate class as well as when the declared class differs.
  14. COVERAGE_COHERENCE. Derives the coverage class from the reporting count, the expected count and whether a subset was declared, and compares. A reporting count equal to the expected count gives complete; a positive reporting count below it gives declared_subset when the subset was declared and undeclared_subset when it was not.
  15. CUMULATIVE_COMMITMENT_RECOMPUTE. Recomputes the limit commitment and the aggregated notional commitment from the disclosed evidence and compares both. A failure means the confidential numbers behind the relation are not the numbers committed.
  16. CUMULATIVE_RELATION_RECOMPUTE. Derives the relation from the exact confidential integers, within_constraint when the accumulated amount is at or below the limit and exceeds_constraint otherwise, and compares to the declared relation.
  17. NO_ACCEPTOR_IDENTITY_LEAK. Rejects any acceptor identifier reaching the signed body. A failure means an identity escaped into a field that must carry only pseudonyms and commitments.
  18. CROSSACCEPTOR_BOUNDARY_PRESENT. Requires the boundary text to be present and to match. A failure means the non attestation was edited or removed.

The mint path refuses every caller supplied field the service computes, at both the request level and inside the window object. It requires window_salt_hex to be 64 lowercase hex characters, requires contributions and coverage reports to be arrays, requires a cumulative constraint object, and requires each contribution to contain exactly amount_minor, acceptor_id and authorized_at and nothing else. The acceptor pseudonym is derived at mint from the raw identifier, which never enters the receipt.

The boundary

This receipt attests only that the issuing service, for the declared authority grouping and accounting window, receives the contribution and coverage evidence it describes, verifies the stated keyed pseudonym derivations under a committed window salt, recomputes the stated distinct acceptor count, dispersion class, commitments, cumulative relation, and coverage class, and signs that limited result. It does not attest that every action under the authority reaches the issuing service, that every acceptor reports, that a nonreporting acceptor is inactive, that the declared expected acceptor population is complete, that any acceptors are legally or institutionally unrelated, or that any pseudonym reveals an acceptor identity. It does not disclose the window salt, acceptor identities, contribution multiset, checked action count, exact dispersion ratio, cumulative constraint, or accumulated amount. It is not an authorization control and does not prevent, block, reverse, delay, ratify, or validate an underlying action. It does not decide whether an action, authority, constraint, report, acceptor, or actor is valid, authorized, proper, compliant, enforceable, or lawful. It does not deny, resolve, adjudicate, or affect any dispute or right.

The clause about a nonreporting acceptor not being inactive is the one that earns the instrument its credibility. Silence is not evidence of nothing happening. The receipt refuses to convert an absence of reports into an absence of activity, and instead exposes the gap through coverage_class so a reader can see exactly how much of the expected population is represented.

The clause about acceptors not being legally or institutionally unrelated is subtler and just as important. A dispersion class of highly_distributed counts distinct pseudonyms. It does not know that eight of those acceptors are subsidiaries of one group. Somebody reading a dispersion class as evidence of genuine market breadth would be over reading it, and the receipt says so.

Enumerating these makes the artifact more useful in a negotiation. A principal reading a within_constraint relation over complete coverage has something firm. The same relation over undeclared_subset coverage is a much weaker statement, and the receipt makes the difference visible rather than burying it. That is what lets both readings coexist in one instrument without the weak one masquerading as the strong one.

Adversarial cases

From test/cross-acceptor.test.mjs.

An adversarial schema field fails SCHEMA. There is nowhere to add anything.

An untrusted issuer fails ISSUER_KEY_MATCH. A payload digest tamper fails PAYLOAD_DIGEST_VALID. A signature tamper fails SIGNATURE_VALID.

An outside contribution fails WINDOW_BOUNDS_ORDERED. Pulling activity in from a neighbouring window, which is how a total gets shaped, is caught against the declared bounds.

A malformed predecessor ordinal fails WINDOW_LINK, and a missing predecessor fails WINDOW_PREDECESSOR_INTEGRITY. A window chain with a hole in it cannot be presented as continuous.

A changed continuity currency fails WINDOW_CONTINUITY. Switching currency between windows would make the chained accumulation meaningless.

A mismatched salt commitment fails SALT_BINDING. Salt shopping is the first attack on any pseudonym scheme. A different salt gives different pseudonyms and therefore a different distinct count, and the commitment blocks it.

A changed contribution digest fails CONTRIBUTION_SET_INTEGRITY, and a changed coverage digest fails CONTRIBUTION_WINDOW_MEMBERSHIP. Both evidence sets are digest bound, so the evidence cannot be swapped after the counts are computed.

An inflated contributing count fails DISTINCT_ACCEPTOR_COUNT_RECOMPUTE. This is the direct attack on dispersion. Report more distinct acceptors than the pseudonyms support and the picture looks broader than it was. The count is recomputed from the pseudonym set.

A changed action count commitment fails DISPERSION_CLASS_RECOMPUTE. The other half of the dispersion attack is to change the denominator. The action count is committed, so it cannot be adjusted to move the bucket.

An incomplete class at complete coverage fails COVERAGE_COHERENCE. Understating coverage would be an odd attack, but the gate is symmetric: the class has to be the class the counts produce, in either direction.

A changed limit commitment fails CUMULATIVE_COMMITMENT_RECOMPUTE. Raising the ceiling to turn an exceedance into compliance requires changing a commitment that is recomputed from the disclosed evidence.

A changed cumulative relation fails CUMULATIVE_RELATION_RECOMPUTE. The relation is derived from the exact confidential integers, never read from the body.

A defense in depth identifier leak fails NO_ACCEPTOR_IDENTITY_LEAK, and a defense in depth boundary mismatch fails CROSSACCEPTOR_BOUNDARY_PRESENT. Both of these are named as defense in depth in the tests, which is accurate: the pseudonym derivation should already prevent identifiers appearing, and the gate catches the case where something went wrong upstream.

Two structural tests confirm the design. The receipt contains neither the raw salt nor a raw acceptor identifier, and the mint path refuses every caller supplied computed field.

Performance

From hive-verifier-api/benchmarks/results-latest.json, measured at 2026-08-09T22:28:01.099Z at commit e167719f7d815809c6f55c5dde4495edf1c5615f over 200 iterations:

MeasureValue
Mint p503.129 ms
Mint p956.394 ms
Verify p502.152 ms
Verify p952.461 ms
Artifact size2841 bytes

Local harness measurement on one machine and one Node version, recorded on Node v20.20.1, linux/x64, two Intel Xeon cores at 2.90 GHz. It is a reproducible measurement of this code, not a production latency guarantee.

How to run it

This type has no mint route. It is produced as an export by another route and only verified here, so there is nothing to authenticate against. The verify route takes no credentials.

  • Host: https://thehiveryiq.com/v1
  • Verify route: /verify/cross-acceptor
curl -sS -X POST https://thehiveryiq.com/v1/verify/cross-acceptor -H 'content-type: application/json' -d '{"receipt": <a receipt of this type>}'

Where it sits in the canon

Family: network authority. Category: typed receipt contract.

It answers the question the Mandate Conformance Receipt explicitly disclaims. That receipt evaluates one transaction against a per transaction constraint and states in its boundary that a series of individually conforming transactions may still exceed a spending intent it cannot see. The Cumulative Mandate Receipt sees that intent within one supplied set of conformance receipts. This receipt sees it across acceptors who never share a set, and never share an identity.

It chains to itself through prior_window, so a sequence of accounting windows under one authority is verifiable end to end with continuity checks between them.

It does not replace an authorization control. It observes and reports, and the boundary says so in the signed bytes.

Status

production_deployed.

References for this instrument
Canon entry
Cross Acceptor Receipt in the Hive canon
JSON Schema
https://thehiveryiq.com/.well-known/schemas/cross-acceptor-v1.json
Verify route
POST /verify/cross-acceptor
Canonical type
mandate.crossacceptor
Private by design. Hive does not store your prompts. Every request is already receipted by a one-way SHA-256 fingerprint, not the words. Proof, not surveillance.