|
| 1 | +--- |
| 2 | +title: "IPIP-0428: Allowing V2-Only Records in IPNS" |
| 3 | +date: 2023-07-24 |
| 4 | +ipip: ratified |
| 5 | +editors: |
| 6 | + - name: Marcin Rataj |
| 7 | + github: lidel |
| 8 | + url: https://lidel.org/ |
| 9 | + affiliation: |
| 10 | + name: Protocol Labs |
| 11 | + url: https://protocol.ai/ |
| 12 | + - name: Henrique Dias |
| 13 | + github: hacdias |
| 14 | + url: https://hacdias.com/ |
| 15 | + affiliation: |
| 16 | + name: Protocol Labs |
| 17 | + url: https://protocol.ai/ |
| 18 | +relatedIssues: |
| 19 | + - https://github.com/ipfs/specs/issues/376 |
| 20 | + - https://github.com/ipfs/boxo/pull/339 |
| 21 | + - https://github.com/ipfs/kubo/pull/9932 |
| 22 | + - https://github.com/ipfs/js-ipns/pull/234 |
| 23 | +order: 428 |
| 24 | +tags: ['ipips'] |
| 25 | +--- |
| 26 | + |
| 27 | +## Summary |
| 28 | + |
| 29 | +Introduce support for creation and validation of compact, V2-only IPNS Records. |
| 30 | + |
| 31 | +## Motivation |
| 32 | + |
| 33 | +IPNS record creation and validation is overly complex due to the legacy of |
| 34 | +decisions made in 2021. |
| 35 | + |
| 36 | +The "V1+V2" record creation and validation was reverse-engineered and documented |
| 37 | +the current state in [ipfs/specs#319](https://github.com/ipfs/specs/pull/319), |
| 38 | +which created a base for specifications to improve upon. |
| 39 | + |
| 40 | +A quick refresher on how IPNS Record lifecycle works today (2023 Q2): |
| 41 | + |
| 42 | +- _Record Creation_ produces both V1 and V2 signatures, and the record has |
| 43 | + duplicated values in both top level protobuf AND `data` CBOR field. |
| 44 | + |
| 45 | +- _Record Validation_ only cares about V2 signature, but still requires fields |
| 46 | + related to V1 to be always present in a record and match values from CBOR in |
| 47 | + `data` field, for the record to be considered valid. |
| 48 | + |
| 49 | +We've been producing and expecting these hybrid V1+V2 records [since 2021](https://github.com/ipfs/js-ipns/pull/121). |
| 50 | + |
| 51 | +An unfortunate result is that all mandatory values MUST be duplicated, even |
| 52 | +when both ends use a modern client that only cares about `signatureV2` that |
| 53 | +guards CBOR field, otherwise the record will not be valid. |
| 54 | + |
| 55 | +What this IPIP aims to improve is allow implementations to produce lean, |
| 56 | +V2-only IPNS records and ensure clients will interpret them as valid IPNS. |
| 57 | + |
| 58 | +## Detailed design |
| 59 | + |
| 60 | +Finish V2 story by making V2-Only records possible, namely: |
| 61 | + |
| 62 | +- Record Creation: document and default to lean V2-Only records, keep V1+V2 as legacy |
| 63 | + backward-compatible variant. |
| 64 | + |
| 65 | +- Record Validation: adjust the algorithm to stop requiring V1 fields when there is no |
| 66 | + `signatureV1`. |
| 67 | + |
| 68 | +For details, see the updated :cite[ipns-record] specification. |
| 69 | + |
| 70 | +## Design rationale |
| 71 | + |
| 72 | +For modern IPNS, the outer `IpnsEntry` protobuf should effectively only have |
| 73 | +two required fields: `data` and its `signatureV2`, and such record, as long |
| 74 | +signature is valid, should be accepted as valid. |
| 75 | + |
| 76 | +At the same time, we don't want to break existig software, especially software |
| 77 | +and hardware devices which use IPNS for pulling updates. |
| 78 | + |
| 79 | +We can get to that future in two steps: |
| 80 | + |
| 81 | +1. Reference implementations (boxo/ipns, js-ipns) will keep producing V1+V2 |
| 82 | + records as backward-compatible default, but we adjust validation algorithm |
| 83 | + to allow V2-only records, and support creation of such records as opt-in in |
| 84 | + modern implementations of IPFS+IPNS, like Kubo (GO) and Helia (JS). |
| 85 | + - Namely, only check/require fields to be duplicated in top level protobuf IF |
| 86 | + `signatureV1` is present in the `IpnsEntry` protobuf. |
| 87 | + - IF there is no `signatureV1`, the V1 record would be invalid anyway. |
| 88 | + - IF there is no `signatureV1` but `signatureV2` and `data` fields |
| 89 | + are present and valid, the V2-only record should be considered valid. |
| 90 | + - This will allow people to build V2-only systems that produce records that |
| 91 | + are considered valid. |
| 92 | + |
| 93 | +2. At some point in the future, e.g. when we see the majority of the public |
| 94 | + swarm supports V2-Only records, libraries like boxo/ipns, js-ipns and |
| 95 | + implementations like Kubo will stop producing V1+V2 and switch to publishing |
| 96 | + V2-only records that are protobuf with only two fields: Data |
| 97 | + CBOR+signatureV2. |
| 98 | + |
| 99 | +### User benefit |
| 100 | + |
| 101 | +- End users: the main benefit for end user is the smaller size of IPNS Records and |
| 102 | + less complexity during creation/validation of modern V2-only records. |
| 103 | + |
| 104 | +- Developers interested in IPNS: by making IPNS Record creation as simple as |
| 105 | + "create DAG-CBOR with these fields, and sign it", and validation to |
| 106 | + "signatureV2 should match the DAG-CBOR value and key". We've removed surface |
| 107 | + for bugs, making it easier to reason about for use in greenfield projects. |
| 108 | + |
| 109 | +- IPFS ecosystem: lowering the complexity related to IPNS record creation and |
| 110 | + validation makes it more likely for third-party interoperable IPNS |
| 111 | + implementations to happen. |
| 112 | + |
| 113 | +### Compatibility |
| 114 | + |
| 115 | +- This is backward-compatible, we adjust validation logic to allow V2-only |
| 116 | + records, but all V1+V2 records that are being used in the wild today are |
| 117 | + still valid |
| 118 | + |
| 119 | +- V2-only rollout is not part of this IPIP. |
| 120 | + - Our suggestion is to default to creating V1+V2 records for now, keeping |
| 121 | + backward-compatibility with the old IPNS clients. |
| 122 | + |
| 123 | + - Creation of V2-only records should be introduced as an explicit opt-in. It |
| 124 | + is up to implementations to decide when it is feasible to default to |
| 125 | + creating V2-only records on IPNS publish. |
| 126 | + |
| 127 | +### Security |
| 128 | + |
| 129 | +- `IpnsEntry.signatureV1` (protobuf field) is parsed only by legacy clients, modern ones ignore this value |
| 130 | + |
| 131 | +It is highly advised to implement validation conformance tests using the fixtures |
| 132 | +included at the end of this IPIP. |
| 133 | + |
| 134 | +### Alternatives |
| 135 | + |
| 136 | +Describe alternate designs that were considered and related work. |
| 137 | + |
| 138 | +1. Just switch to V2-only as the new default! |
| 139 | + - No, this would be a breaking change. We have to do this in two steps, |
| 140 | + because we've rushed the way V2 was introduced in 2021, and STILL require |
| 141 | + field copying, even when `signatureV1` is missing. So technically there |
| 142 | + was never "V2", it was more like "V1.5". Only with this IPIP, we finally |
| 143 | + adjust validation to only care about CBOR values when there is no |
| 144 | + `signatureV1`. |
| 145 | + |
| 146 | +2. Why keeping the outer protobuf envelope? Could we make IPNS DAG-CBOR-only? |
| 147 | + - Due to how long it takes for decentralized network nodes to upgrade, we prefer evolution rather than revolution. |
| 148 | + - Protobuf is a useful envelope for two reasons: |
| 149 | + 1. Ensures the opaque V2-only record can be passed and stored in existing infrastructure. |
| 150 | + 2. Allows us to evolve IPNS record ("V3") in the future without impacting existing infrastructure. |
| 151 | + |
| 152 | +## Test fixtures |
| 153 | + |
| 154 | +To make testing easier below are test vectors in form of IPNS records along |
| 155 | +with the expected verification results. These test records are valid for 100 |
| 156 | +years, making them safe for use in CI tests. |
| 157 | + |
| 158 | +1. [V1-only](https://dweb.link/ipfs/bafybeifkipmlz2fehxda6y7x752uolfed7bdd46jzdammpfga5zrnkq33u/k51qzi5uqu5dm4tm0wt8srkg9h9suud4wuiwjimndrkydqm81cqtlb5ak6p7ku_v1.ipns-record) → record invalid |
| 159 | +2. [V1+V2](https://dweb.link/ipfs/bafybeifkipmlz2fehxda6y7x752uolfed7bdd46jzdammpfga5zrnkq33u/k51qzi5uqu5dlkw8pxuw9qmqayfdeh4kfebhmreauqdc6a7c3y7d5i9fi8mk9w_v1-v2.ipns-record) (both signatures valid) → record valid, value points at `/ipfs/bafkqaddwgevxmmraojswg33smq` |
| 160 | +3. [V1+V2](https://dweb.link/ipfs/bafybeifkipmlz2fehxda6y7x752uolfed7bdd46jzdammpfga5zrnkq33u/k51qzi5uqu5dlmit2tuwdvnx4sbnyqgmvbxftl0eo3f33wwtb9gr7yozae9kpw_v1-v2-broken-v1-value.ipns-record) (both signatures valid, but 'value' is different in V1 pb vs V2 CBOR) → record invalid |
| 161 | +4. [V1+V2](https://dweb.link/ipfs/bafybeifkipmlz2fehxda6y7x752uolfed7bdd46jzdammpfga5zrnkq33u/k51qzi5uqu5diamp7qnnvs1p1gzmku3eijkeijs3418j23j077zrkok63xdm8c_v1-v2-broken-signature-v2.ipns-record) (only signatureV1 valid) → record invalid |
| 162 | +5. [V1+V2](https://dweb.link/ipfs/bafybeifkipmlz2fehxda6y7x752uolfed7bdd46jzdammpfga5zrnkq33u/k51qzi5uqu5dilgf7gorsh9vcqqq4myo6jd4zmqkuy9pxyxi5fua3uf7axph4y_v1-v2-broken-signature-v1.ipns-record) (only signatureV2 valid) → record valid, value points at `/ipfs/bafkqahtwgevxmmrao5uxi2bamjzg623fnyqhg2lhnzqxi5lsmuqhmmi` |
| 163 | +6. [V2-only](https://dweb.link/ipfs/bafybeifkipmlz2fehxda6y7x752uolfed7bdd46jzdammpfga5zrnkq33u/k51qzi5uqu5dit2ku9mutlfgwyz8u730on38kd10m97m36bjt66my99hb6103f_v2.ipns-record) (no V1 fields) → record valid |
| 164 | + |
| 165 | +:::note |
| 166 | + |
| 167 | +Implementers can either write own tests against the above test vectors, or run |
| 168 | +[gateway-conformance](https://github.com/ipfs/gateway-conformance/) test suite, |
| 169 | +which includes tests for these vectors since |
| 170 | +[gateway-conformance/pull/157](https://github.com/ipfs/gateway-conformance/pull/157). |
| 171 | + |
| 172 | +::: |
| 173 | + |
| 174 | +### Copyright |
| 175 | + |
| 176 | +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). |
0 commit comments