diff --git a/ERCS/erc-7730.md b/ERCS/erc-7730.md index 6fea82d3901..ade58fdd882 100644 --- a/ERCS/erc-7730.md +++ b/ERCS/erc-7730.md @@ -2,7 +2,7 @@ eip: 7730 title: Structured Data Clear Signing Format description: JSON format describing how to clear-sign smart contract calls and typed messages. -author: Laurent Castillo (@lcastillo-ledger), Derek Rein (@arein), Pierre Aoun (@paoun-ledger), Arik Galansky (@arikg) +author: Laurent Castillo (@lcastillo-ledger), Derek Rein (@arein), Pierre Aoun (@paoun-ledger), Arik Galansky (@arikg), Bartosz Rozwarski (@llbartekll) discussions-to: https://ethereum-magicians.org/t/eip-7730-proposal-for-a-clear-signing-standard-format-for-wallets/20403 status: Draft type: Standards Track @@ -1281,7 +1281,7 @@ Formats usable for bytes | *Parameters* | --- | | `calleePath` or `callee` | A path reference or a constant value specifying the address of the contract being called. | | `selectorPath` or `selector`| Optional. If omitted, the first 4 bytes of the calldata are used as the selector. | -| `chainIdPath` or `chainId` | Optional. Specifies the chain ID if it differs from the current contract’s chain. | +| `chainIdPath` or `chainId` | Optional. Specifies the chain ID if it differs from the current contract's chain. | | `amountPath` or `amount` | Optional. Specifies the native currency amount associated with the calldata, if applicable. If provided, the ERC-7730 descriptor for this embedded calldata MAY reference this value using the `@.value` container path. | | `spenderPath` or `spender` | Optional. Specifies the spender address associated with the calldata, if applicable. If provided, the ERC-7730 descriptor for this embedded calldata MAY reference this value using the `@.from` container path. | | *Examples* | | @@ -1340,6 +1340,95 @@ Sources values are wallet manufacturer specific. Some example values could be: Wallets MAY extend the specification with wallet specific layout instructions by defining a schema bound to the `display.formats.screens` field. +### ERC-7730: Optional Integrity Field for Descriptor Tamper-Evidence + +#### Abstract + +This amendment introduces an optional top-level `integrity` object that wallets and tooling can use to detect tampering with ERC-7730 descriptors during storage or transport. The mechanism is transport-agnostic, operates offline, and does not influence descriptor interpretation. + +#### Motivation + +Descriptors are frequently distributed from arbitrary locations such as GitHub repositories, content delivery networks, and dapp-hosted domains, which makes byte-level tampering difficult to notice. This amendment focuses solely on byte-integrity so that consumers can surface warnings when the document payload changes; provenance, governance, and trust decisions remain outside its scope. + +#### Specification + +##### Scope + +* The `integrity` object is optional. Absence is not an error. +* Implementations MAY validate `integrity` if present; verification outcome affects wallet and tool user experiences only and MUST NOT alter descriptor semantics. + +##### Hash Input (canonicalization) + +* Let D be the JSON document with the top-level `integrity` key removed. +* Canonicalize D using the RFC 8785 JSON Canonicalization Scheme (JCS) with UTF-8 encoding, lexicographic member ordering, and I-JSON constraints. +* Compute `digest = keccak256(JCS(D))`, where `keccak256` is the Ethereum Keccak-256 function (distinct from FIPS SHA3-256). + +##### Signed Message (exact bytes) + +Implementations MUST construct the exact ASCII (UTF-8) message with line feed newlines, no byte order mark, and no trailing spaces: + +``` +ERC-7730 descriptor +hash=<0x{64 lowercase hex}> +``` + +The following Augmented Backus-Naur form (ABNF) removes ambiguity: + +```abnf +message = "ERC-7730 descriptor" LF + "hash=" "0x" 64HEXDIGIT LF + +LF = %x0A +HEXDIGIT = %x30-39 / %x61-66 ; 0-9 or a-f (lowercase) +64HEXDIGIT = 64*HEXDIGIT +``` + +##### Signature schemes and verification rules + +* `sigType: "eip191"`, `signerType: "eoa"`: + The signer MUST sign the message defined above using [EIP-191](./eip-191.md) personal signing. Verifiers MUST: + 1. apply EIP-191 prefixing (`hashMessage(message)`), + 2. recover an address equal to the account encoded by `integrity.signer`, and + 3. enforce low-s ECDSA and normalize `v in {27,28}`. + +* `signerType: "erc1271"`: + The `integrity.signer` field encodes the account as a CAIP-10 identifier (for example, `eip155:1:0x...`). Verifiers MUST: + 1. parse the CAIP-10 value to obtain the chain namespace, network reference, and account, + 2. compute `keccak256(message)`, and + 3. call [EIP-1271](./eip-1271.md) `isValidSignature(bytes32,bytes)` on that account at the chain specified by the CAIP-10 identifier, requiring the magic value `0x1626ba7e`. + If chain access is unavailable, implementations SHOULD surface "verification unavailable" and continue according to product policy. + +##### Signer identity format (CAIP-10) + +The `signer` field MUST be a CAIP-10 account string (e.g., `eip155:1:0xAbc...`), uniquely binding both the chain reference and the account without requiring separate `chainId` properties. + +##### `integrity` object (JSON schema fragment) + +```json +"integrity": { + "sigType": "eip191", + "signerType": "eoa", // or "erc1271" + "signer": "eip155:1:0xCSA_SIGNER", // CAIP-10 account identifier + "hash": "0x", + "signature": "0x" // ECDSA over EIP-191 message +} +``` + +##### Verifier behavior + +* If `integrity` is present and verification fails (hash mismatch, bad signature, or invalid 1271 response), implementations MUST surface an integrity failure. Whether to block is product policy. +* If `integrity` is present and verification cannot be performed (for example, offline EIP-1271 lookups), implementations SHOULD surface "verification unavailable." +* If `integrity` is absent, implementations MUST NOT treat this as an error. +* Implementations MUST NOT change how they interpret descriptor content based on the verification outcome. + +#### Rationale + +JSON canonicalization via RFC 8785 ensures stable bytes across languages and tooling, while Keccak-256 matches existing Ethereum hashing primitives. The explicit message template and ABNF eliminate newline or casing ambiguities. Separating `sigType` from `signerType` avoids assumptions about available chain connectivity and supports future combinations. Encoding the signer as CAIP-10 binds chain and account in one field, removing auxiliary identifiers. Time-based invalidation features are intentionally excluded to keep the surface minimal, and provenance or governance concerns stay intentionally out of scope. + +#### Security Considerations + +This mechanism only detects tampering of descriptor bytes and does not assert safety or endorsement. Implementations SHOULD reject non-I-JSON inputs (duplicate keys or non-UTF-8 encodings) before canonicalization, MUST enforce low-s ECDSA handling, and MUST ensure the Ethereum Keccak-256 function, not the FIPS SHA3-256 variant, is used throughout verification. + ## Rationale ### Human readability