P2Pix zkTLS prover
Proves that a BB Pay Pix charge was paid by having a Primus attestor replay
the bank's own GET /solicitacoes/{n} over zkTLS. The attestor signs what
the bank answered: the request URL and five revealed fields (amount, settled
sum, payee, Pix txId, reconciliation code). The P2Pix contract verifies
that signature and the fields in release(lockID, proof). The charge is
bound to P2Pix's convênio only through the numeroConvenio query of the
attested URL, so the contract's URL suffix must be pinned to the URL exactly
as the attestor records it. The prover holds no signing key of its own.
Variáveis de ambiente (.env, ver .env.example)
CLIENT_ID,CLIENT_SECRET,DEV_APP_KEY,CONVENIO: fornecidas pelo Banco do BrasilITP_OAUTH_URL,ITP_API_URL: endpoints BB Pay (homologação ou produção)CLIENT_CRT,CLIENT_KEY: certificado cliente mTLS e sua chave privada (PEM)PRIVATE_KEY: carteira que paga as tarefas Primus (ETH naPRIMUS_CHAIN_ID, Base Sepolia por padrão); o endereço dela é orecipientda atestação e tem que ser oproverconfigurado no contrato
Como rodar
bun install # ou npm install
bun start # ou npm start
DEBUG=true liga os logs, inclusive o registro completo de cada atestação
(request, resolves, data, attConditions, additionParams, verificação).
Endpoints
POST /register
Registra um participante. Chamado pelo vendedor antes do deposit.
curl -X POST http://localhost:5000/register -H 'content-type: application/json' -d '{
"chainID": "11155111", "tipoDocumento": 1, "numeroDocumento": 12345678900,
"numeroConta": 1234567890123456, "numeroAgencia": 123, "tipoConta": 1, "codigoIspb": 0
}'
Retorna a resposta do BB, com numeroParticipante (usado no deposit como <chainId>-<numeroParticipante>).
POST /request
Cria a solicitação de pagamento. Chamado pelo comprador depois do lock.
lockId e chainId viram o código de conciliação <chainId>-<lockId>, que
o contrato exige na prova.
curl -X POST http://localhost:5000/request -H 'content-type: application/json' -d '{
"amount": 100.00, "pixTarget": 123, "lockId": "42", "chainId": "11155111"
}'
Retorna a resposta do BB mais numeroSolicitacao (string) e textoQrCode.
GET /release/{numeroSolicitacao}
Prova de pagamento Pix. Chamado pelo comprador depois de pagar.
402enquanto o banco não confirma o pagamento202enquanto a atestação está sendo produzida (15 s a 1 min)200com a prova502banco ou Primus falharam de forma definitiva;503vale repetir
curl -i http://localhost:5000/release/1408799
{
"numeroSolicitacao": "1408799",
"proof": {
"recipient": "0x…", "attestor": "0x…",
"data": "{\"amount\":\"100\",…}",
"timestamp": 1766377317483,
"additionParams": "{\"algorithmType\":\"proxytls\"}",
"attConditions": "",
"signature": "0x…", "taskId": "0x…", "reportTxHash": "0x…",
"requests": [{ "url": "…", "header": "", "method": "GET", "body": "" }],
"responseResolves": [[…]],
"selfVerified": true, "contractRebuildMatches": true
}
}
release(lockID, proof) takes numeroSolicitacao, recipient, data,
timestamp, additionParams, attConditions, attestor and signature;
the rest is evidence. selfVerified means the signature recovers the
attestor over the returned struct; contractRebuildMatches means the
contract's rebuild rules (empty header and body, GET) reproduce it.
bun run digest-check <release-body.json> recomputes the digest of a saved
answer and prints the URL, header, parseType and data layout the contract
constants are pinned to.
mTLS
CLIENT_CRT is the certificate chain BB has on file for this application and
CLIENT_KEY its private key, both PEM. Register a dedicated client
certificate for the prover; the attested requests run through the Primus
attestor, so the key material should not be the company e-CNPJ. To extract a
key-only PEM from a PKCS#12 file:
umask 077
openssl pkcs12 -in <arquivo>.p12 -legacy -nocerts -noenc -out client.key
openssl pkcs12 -in <arquivo>.p12 -legacy -nokeys -out client.crt
The *.mtls.api.*.bb.com.br hosts present a publicly trusted chain, so no
extra CA is needed; set BB_CA only for hosts signed by BB's own CA.