# Trust address format A trust address is the textual form of an Ed25519 public key. It is the only identifier the protocol has for an identity. ``` trust1qqak5faue6m2gttz5w5dq2n0p4ek2vs4wuw7ysax8tqy3gvtt8dzj0yfahr \___/\__________________________________________________/\_____/ hrp payload (53 chars) checksum ``` ## Encoding ``` hrp = "trust" payload = version(1 byte) || ed25519 public key(32 bytes) address = bech32m(hrp, convertbits(payload, 8 -> 5, pad = true)) ``` - **Version** is currently `0x00`, denoting a raw 32-byte Ed25519 public key. Because bech32 regroups the payload into 5-bit units, a leading zero byte renders as `q`, which is why every current address reads as `trust1q...`. - **Length** is exactly 65 characters for version 0. - **Case** is lowercase only. bech32 permits an all-uppercase form, but two spellings of one address would violate INV-8, so uppercase input is refused. ## Why bech32m rather than bech32 bech32m (BIP-350) differs from the original bech32 (BIP-173) only in the checksum constant. The original has a known weakness when the final data character can vary in a length-extending way, which is why BIP-350 exists. A trust payload is preceded by a version byte that is intended to change over time, so bech32m is the correct choice. Decoding enforces this exactly. The bech32 constant is recognised and **rejected** with a distinct error, so a downgrade to the weaker checksum or a confusion with a foreign address family is not accepted silently. ## Validation performed on decode Parsing an address is strict, and every rule removes either an alternative spelling or an unusable key: | Check | Rejected because | |---|---| | non-empty, length <= 65 | bounds work done on untrusted input | | lowercase only | two spellings of one address (INV-8) | | bech32m checksum verifies | corruption must never decode to another identity | | checksum constant is bech32m | downgrade or foreign address family | | hrp is `trust` | address belongs to another protocol | | payload is exactly 33 bytes | malformed | | version is `0x00` | unknown protocol version | | 5 to 8 bit regrouping leaves no non-zero padding | alternative spelling | | key is a canonical curve point | non-canonical encodings alias one point | | key is not of small order | universal signature forgery, see below | ## Public key validation The last two rows are a cryptographic requirement, not a formatting one. `crypto/ed25519.Verify` performs no checks on the public key, as RFC 8032 specifies. When the attacker chooses the key this is exploitable: the order-1 point (`0100...00`) has a signature that verifies against **every** message. Anyone who registered such a key would own an identity whose signatures are valid on any claim or approval that anyone cares to construct. Every key is therefore checked to be a canonically encoded point that is not annihilated by multiplication by the cofactor. Honest keys always pass; the degenerate ones can never become an address, and therefore can never become an identity. ## Properties relied on elsewhere - **Bijective.** Every valid key has exactly one address; every valid address yields exactly one key. Verified by fuzzing in both directions. - **Self-validating.** A non-zero `Address` value has already passed every check above, so later code never has to re-validate. - **Corruption-detecting.** Every single-character substitution and every transposition in the data part is rejected. A mistyped address fails to parse rather than resolving to a different identity. - **Fail-closed zero value.** The zero `Address` denotes no identity, does not compare equal to itself, and stringifies to the empty string.