Manav.id
Spec

Canonical forms

RFC 8785 JCS and the rules Manav adds on top of it.

Canonical forms

Last updated 24 September 2026

The canonical form is chosen by the object's version field, so a verifier never guesses.

JCS (RFC 8785) — everything from receipt v2 onward

Implementation: core/jcs.php (manav_jcs), js/jcs.js (manavJcs), packages/verify-py/manav_verify/jcs.py. Vectors: tests/vectors/jcs/ (the six RFC 8785 test files plus 37 manav vectors); php tests/jcs-vectors.php, node tests/jcs-vectors.mjs; differential test over generated values in tests/run.php group 10.

Rules on top of RFC 8785:

Signing input for hybrid-signed objects

M = UTF8(object["v"]) || 0x0A || JCS(object without "sig"). The type tag inside the signed bytes prevents cross-type replay (a lease signature can never be presented as a receipt signature). Receipt v2 uses the tag manav-receipt/2 even though its stored v is the integer 2.

Legacy v1 form — frozen

core/canonical.php::manav_canonical_encode_legacy_v1: recursive ksort (byte order) + json_encode(JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES). It is not RFC 8785 and MUST NOT be used for anything new. It exists so that objects signed before 2026-09 keep verifying (tests/corpus/v1, group 17). The v1 revocation list at /v2/revoked also uses it.

← All specification documents