humanproof format specification
16. Revision 2
Since 2026-10-30 the four formats have a revision 2, marked by the member "revisao": 2. It is not a new format: formato is still humanproof/1, humanproof-acesso/1, humanproof-ponto/2 and humanproof-ancoragem/1. An object without revisao is revision 1 and follows sections 6 to 10 and 15; an object with revisao 2 follows sections 16 to 20; any other value of revisao MUST be rejected. Canonicalization, hash and chain (sections 3, 4 and 9) are the same in both revisions, and a chain may hold receipts of both.
Cut-off date: 2026-10-30T05:21:39Z, the instant the Hummand issuer started issuing revision 2. An act receipt without revisao whose ts_concluido is later than that instant MUST be rejected in coherence, even with a valid signature: after the cut-off, revision 1 is not a way around the rules of revision 2. Revision 1 receipts concluded up to the cut-off remain valid.
Checkpoint cut-off date: 2026-11-01T22:51:16Z, the instant the issuer stopped issuing humanproof-ponto/1 and the /2 without revisao. A checkpoint without revisao whose ts is later than that instant, or whose ts is not RFC 3339, MUST be rejected in coherence, even with a valid signature, for the same reason as the receipt: without the cut-off, the revision 1 checkpoint, which has no per-key validity, would be a way around the key revocation of revision 2. It is a different date because the revision 1 checkpoint kept being issued after the receipt cut-off. Checkpoints without revisao issued up to that instant remain valid.
Revision 2 schemas: humanproof-1-revisao-2.schema.json and humanproof-acesso-1-revisao-2.schema.json, closed like those of revision 1.
16.1 Signatures
In revision 2, kid, alg and assinatura leave and assinaturas comes in, a list of { papel, kid, alg, valor }:
- each entry signs the JCS of
{ "recibo": <the object without the assinaturas member>, "assinatura": { "papel", "kid", "alg" } }, so that the role, key and algorithm of each signature are covered by that signature itself, and another signature can be added later without invalidating the earlier ones; valorwith the encoding of section 5;- roles:
emissor, mandatory, and the reservedemissor_complementar,testemunhaandcliente. The verifier MUST require at least oneemissorsignature and MUST check every one present; - the hash of the object (section 4) is still the hash of the JCS of the whole object, signatures included.
The same rule applies to the access receipt and to the revision 2 checkpoint.
16.2 Keys with validity
In revision 2, each JWKS key MAY carry valida_de, valida_ate, estado (ativa, aposentada or comprometida) and, when compromised, comprometida_desde. The verifier MUST reject a signature whose key, at the object’s ts_emitido, was not yet valid, was no longer valid or was compromised; an unknown state is also a rejection. Per-key validity is allowed by the format, not required: a key without these members is always valid, as in revision 1, and having no declared term does not make a key invalid. The issuer’s current key has no declared term. A repeated kid in the JWKS MUST be rejected, because the verifier would have to pick one of the keys. A retired key stays published in the issuer’s JWKS, so that old receipts remain checkable after a key change.
17. The act receipt, revision 2
| Member | Content |
|---|---|
formato, revisao |
"humanproof/1" and 2 |
recibo_id, ato_id |
opaque identifiers |
emissor |
{ id, jwks_uri }: who issued it and where the keys are |
tenant |
{ id, nome_publico } |
tipo |
act type, as in revision 1 |
resultado |
positivo, negativo, expirado, cancelado, falhou or revogado |
motivo |
null when positive; otherwise, a code from that result’s registry (17.1) |
nivel |
{ exigido, atingido }, integers from 0 to 3: what the policy required and what the act reached |
politica |
{ versao, hash }: the version and the hash of the JCS of the policy applied to the type |
sujeito |
ref_compromisso and ref_sal, together or both absent, and referencia when there was a comparison (17.2) |
contexto |
{ hash, chaves_declaradas }, with the keys sorted and without repetition |
consentimentos |
[{ camada, versao, idioma, texto_hash, ts }], with camada in geral, biometrico or escopo (17.3) |
etapas |
[{ nome, resultado, ts, medido }]; medido says whether the instant was measured or inherited from the end of the act |
fontes |
[{ fonte, fornecedor, componente, versao_componente, versao_adaptador, ambiente, certificacao? }]; versao_componente may be nao_informada; certificacao = { esquema, laboratorio, relatorio, data } |
garantias |
humano_vivo, mesma_pessoa_da_referencia, identidade_civil and consentiu, each { valor, sustentada_por }; biometria_retida, always false (17.4) |
evidencia_tecnica |
what the source measured, without a score: deteccao_ataque, deteccao_injecao and dispositivo when present, and politica_de_limiar with the id and hash of the comparison policy, never the calibrated values |
participantes |
[{ papel, ref_compromisso, ref_sal, presenca_recibo_hash? }], with ref_compromisso and ref_sal computed as in 17.2, with papel in sujeito, assistente, mandatario, testemunha, revisor or operador |
revisao_humana |
null or { via, revisor, protocolo, ts } (17.5) |
mandato |
null or exactly one of concessao, uso and revogacao (17.6) |
ingredientes |
[{ papel, alg, hash }]: the displayed term, the attached document, the trigger and other evidence, by hash only |
ts_criado, ts_concluido, ts_emitido |
RFC 3339 in UTC with milliseconds; ts_emitido is the instant of signing |
expira_em |
the deadline of the act |
retencao |
{ ate, base }: until when the issuer keeps the record of the act, and on what basis |
prev_hash |
hash of the tenant’s previous receipt, or the acts genesis (section 4) |
assinaturas |
section 16.1 |
Optional: inclusao, reserved for an inclusion proof in a log; extensoes, a map { "<namespace>": { ... } }; and crit, the list of the extensions the verifier needs to understand. An extension named in crit and absent, or named and unknown to the verifier, MUST be rejected; other extensions MAY be ignored.
17.1 Reasons per result
resultado |
motivo |
|---|---|
positivo |
null |
negativo |
presenca_negada, comparacao_negada, identidade_negada, passkey_negada, consentimento_recusado, revisao_negou, mandato_invalido, mandato_revogado, mandato_vencido, fora_de_escopo |
expirado |
prazo |
cancelado |
cancelado_pelo_cliente, cancelado_pela_pessoa |
falhou |
falha_tecnica_fonte, falha_tecnica_emissor |
revogado |
revogado_pelo_mandante |
17.2 The reference commitment
The receipt does not carry the reference the customer gave the person, such as a national ID, employee number or benefit number. It carries:
ref_sal: 16 random bytes, new for each receipt, as 32 hexadecimal digits;ref_compromisso="sha256:" + hex(HMAC-SHA256(key, bytes(ref_sal) || UTF-8(reference))), wherekeyis the tenant’s 32-byte reference key andbytes(ref_sal)are the 16 bytes the hexadecimal represents.
Without the key, the commitment does not reveal the reference or link two receipts of the same person, because the salt changes; referencia.hash, when present, is the same in receipts that used the same image. With the key, which the customer obtains in the dashboard, the customer recomputes the commitment from the reference and checks on their own that the receipt belongs to that person. referencia, when there was a comparison, is { tipo, origem, hash, anexada_em }: the hash of the reference image used, its origin (api, painel, ato_anterior or base_oficial) and when it was attached. Whoever kept the image checks the hash.
17.3 The consent text
texto_hash is hash(JCS(text)): the SHA-256 of the canonical form of the string of the text the person saw, in the indicated version and language. The texts are published at https://hummand.com.br/en/consentimentos, with the hash of each, and a published text does not change: new wording is a new version. ts is the instant the issuer recorded the acceptance, by its own clock. This is the difference from revision 1, whose texto_hash was the hash of the consent identifier (section 6).
17.4 Who backs each guarantee
valor is true, false or null (the step did not happen). sustentada_por says where the statement comes from: componente (the source’s technical component), revisao (human review), declaracao_cliente, base_oficial or mandato; it is null exactly when valor is null.
17.5 Human review
via is emissor or cliente. In a review by the issuer, revisor is the hash of the receipt in which the reviewer proved their own presence; in a review by the customer, it is apikey:<id>, the key with which the integration decided. The review decides the act, not presence: no biometric guarantee is backed by revisao.
17.6 Mandate
concessao:{ escopo, mandatario }, in the typesmandato.pessoaandmandato.agente.escopocarriesacoes, typedlimites({ valor, unidade, moeda?, janela? }),validade_ateandrevogavel;mandatariocarriestipo(pessoaoragente, consistent with the act type),ref_compromissoandref_sal, computed as in 17.2, and MAY carrychave_agente.uso:{ mandato_recibo_hash, acao, valores_hash, executor, nonce, expira_em, chave_agente?, verificacao }, in the typeato.delegado, withverificacao={ valido, dentro_escopo, dentro_validade, revogado }.revogacao:{ mandato_recibo_hash }, in the resultrevogado.
The mandate is referenced by the hash of the grant receipt, not by an id: whoever has both receipts checks that one points to the other.
18. Coherence of revision 2
Beyond the schema and the signatures (16.1 and 16.2), the verifier MUST apply:
motivoisnullexactly when positive, and from the result’s registry otherwise (17.1).- Positive requires
nivel.atingido≥nivel.exigidoand every stepok. - Positive at level 2 or above, outside
ato.delegado, requires apresencastepokandhumano_vivotrue backed bycomponente, with the sourcehummand.presencadeclared. Withsujeito.referencia, it also requires acomparacaostepokandmesma_pessoa_da_referenciatrue backed bycomponente. - Positive at level 3 requires
identidade_civiltrue backed bybase_oficial. Positive at level 1 requires apasskeystepok. ato.delegadois always level 0: there is no new human.- A
nullguarantee has nosustentada_por, and an asserted guarantee has one. No biometric guarantee is backed byrevisao. - A biometric step (
presenca,comparacao) requires a consent of layerbiometricobefore it andconsentiutrue. - No repeated step;
ts_criado≤ts_concluido≤ts_emitido; steps and consents not later thants_concluido; steps in non-decreasing order. contexto.chaves_declaradassorted and without repetition;ref_compromissoandref_saltogether.revisao_humanaonly in positive or negative; by the issuer, with the hash of a receipt; by the customer, withapikey:.operador.dupla: dual approval is two chained positions, and only the one that closes the pair lists operators. When the receipt lists two or moreoperadorparticipants, there are at most two, with differentref_compromisso(distinct people), and the first carriespresenca_recibo_hash, the hash of the receipt of the previous position; the second is the act itself and carries no presence. With fewer than two operators listed (the first position), the rule does not apply.- Mandate: each variant in the types of 17.6;
ato.delegadorequiresuso; the use is positive exactly when the check authorizes (the first three statements true andrevogadofalse), withmotivobacked by it, and does not conclude positive afterexpira_em; the grant hasvalidade_atelater thants_criado. critas in section 17.
As in revision 1, coherence is the absence of internal contradiction, not external confirmation.
19. Access and checkpoint, revision 2
Access receipt. The same role as in section 8, with revisao 2, emissor, ts_emitido and assinaturas (16.1), and:
ato_recibo_hash: the hash of the act receipt whose evidence was opened, besidesato_id;motivo_hash=hash(JCS({ "motivo": <text>, "sal": <motivo_sal> })), withmotivo_salin the receipt itself: without the salt, the same reason would give the same hash in every access;- each component also carries
conteudo_hash, the hash of what was delivered, andmodo,telaorarquivo; each may benull.
The coherence of section 8 applies unchanged.
Checkpoint. The revision 2 humanproof-ponto/2 gains revisao, emissor, assinaturas and ponto_anterior_hash, the hash of the same tenant’s previous checkpoint (null for the first): a tenant’s checkpoints form a chain, and a checkpoint removed from the middle becomes visible to whoever kept its neighbours. cadeias becomes an open map, in which atos and acessos are mandatory and other chains may be added later. ts is in milliseconds. Checking a batch against the checkpoint is as in section 10.
20. Anchoring, revision 2
The revision 2 humanproof-ancoragem/1 proof carries, besides what section 15 describes, revisao, arvore, tamanho and cabeca_anterior:
- Padded tree. The real leaves, checkpoints and receipts as in section 15, are followed by padding leaves up to
tamanho, the smallest power of two that is both ≥ 1024 and ≥ the number of real leaves. Padding leafiisSHA-256(0x00 || "humanproof-ancoragem/1:preenchimento:" || i), withiin decimal. So the size of the tree does not reveal how many customers and receipts there were in the cycle.arvoreis the root of that tree, and the path has exactly log2(tamanho) siblings. - Chained head. The TSA timestamp covers the head, not the tree:
head = SHA-256(0x02 || previous head || arvore || tamanho), with the previous head as 32 bytes (32 zeros in the first cycle) andtamanhoas 8 bytes big-endian.raizis that head, andcabeca_anterioris the previous cycle’s, ornull. - Public list. The issuer publishes the heads of the cycles at
https://gateway.hummand.com.br/v1/ancoragens/cabecas, with the tree, size, previous head and timestamp of each. Whoever keeps the list sees that each cycle covers the previous one and that the issuer did not timestamp two histories.
Checking a revision 2 proof: the steps of section 15, with the leaf climbing to arvore instead of raiz; the path with the length of the full tree; tamanho a power of two and ≥ 1024; and raiz equal to the head computed from cabeca_anterior, arvore and tamanho.
State in production. Anchoring is not yet active in production; the list exists and stays empty until then.