From 0fa5e57841770c3e5d19dfbfab7303c6f545d0c6 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Mon, 5 Sep 2022 16:56:53 +0200 Subject: [PATCH 01/13] feat: update IPNS specification - IPNS Name and Record protobufs, ascii and logical structs - extensible record data in strict CBOR - signatures v2: creation and validation --- IPNS.md | 228 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 177 insertions(+), 51 deletions(-) diff --git a/IPNS.md b/IPNS.md index 44964f70d..472bce909 100644 --- a/IPNS.md +++ b/IPNS.md @@ -1,8 +1,10 @@ -# ![](https://img.shields.io/badge/status-wip-orange.svg?style=flat-square) IPNS - Inter-Planetary Naming System +# ![draft](https://img.shields.io/badge/status-draft-yellow.svg?style=flat-square) IPNS - Inter-Planetary Naming System **Authors(s)**: + - Vasco Santos ([@vasco-santos](https://github.com/vasco-santos)) - Steven Allen ([@Stebalien](https://github.com/Stebalien)) +- Marcin Rataj ([@lidel](https://github.com/lidel)) ----- @@ -10,17 +12,20 @@ IPFS is powered by content-addressed data, which by nature is immutable: changing an object would change its hash, and consequently its address, making it a different object altogether. However, there are several use cases where we benefit from having mutable data. This is where IPNS gets into the equation. -All things considered, the IPFS naming layer is responsible for the creation of: -- mutable pointers to objects -- human-readable names +IPNS records provide cryptographically verifiable, mutable pointers to objects. -# Table of Contents +## Organization of this document - [Introduction](#introduction) +- [IPNS Name](#ipns-name) + - [Text Format](#text-format) + - [Key Types](#key-types) + - [Wire Format](#wire-format) - [IPNS Record](#ipns-record) - [Protocol](#protocol) -- [Overview](#overview) -- [API Spec](#api-spec) + - [Overview](#overview) + - [Record Creation](#record-creation) + - [Record Validation](#record-validation) - [Integration with IPFS](#integration-with-ipfs) ## Introduction @@ -29,54 +34,136 @@ Each time a file is modified, its content address changes. As a consequence, the IPNS is based on [SFS](http://en.wikipedia.org/wiki/Self-certifying_File_System). It consists of a PKI namespace, where a name is simply the hash of a public key. As a result, whoever controls the private key has full control over the name. Accordingly, records are signed by the private key and then distributed across the network (in IPFS, via the routing system). This is an egalitarian way to assign mutable names on the Internet at large, without any centralization whatsoever, or certificate authorities. -## IPNS Record +## IPNS Name -An IPNS record is a data structure containing the following fields: - -- 1. **Value** (bytes) - - It can be any path, such as a path to another IPNS record, a `dnslink` path (eg. `/ipns/example.com`) or an IPFS path (eg. `/ipfs/Qm...`) -- 2. **Validity** (bytes) - - Expiration date of the record using [RFC3339](https://www.ietf.org/rfc/rfc3339.txt) with nanoseconds precision. - - Note: Currently, the expiration date is the only available type of validity. -- 3. **Validity Type** (uint64) - - Allows us to define the conditions under which the record is valid. - - Only supports expiration date with `validityType = 0` for now. -- 4. **Signature** (bytes) - - Concatenate value, validity field and validity type - - Sign the concatenation result with the provided private key - - Note: Once we add new validity types, the signature must be changed. More information on [ipfs/notes#249](https://github.com/ipfs/notes/issues/249) -- 5. **Sequence** (uint64) - - Represents the current version of the record (starts at 0) -- 6. **Public Key** (bytes) - - Public key used to sign this record - - Note: The public key **must** be included if it cannot be extracted from the peer ID (reference [libp2p/specs#100](https://github.com/libp2p/specs/pull/100/files)). -- 7. **ttl** (uint64) - - A hint for how long the record should be cached before going back to, for instance the DHT, in order to check if it has been updated. +### Text Format + +To maximize interop with IPFS tools and wider ecosystem, IPNS Name can be represented as a [CID](https://docs.ipfs.tech/concepts/glossary/#cid) with `libp2p-key` [multicodec](https://docs.ipfs.tech/concepts/glossary/#multicodec) (code `0x72`), and encoded with [Multibase](https://docs.ipfs.io/concepts/glossary/#multibase) as Base32 (or Base36, for use in DNS contexts). + +A good practice is to prefix IPNS Name with `/ipns/` namespace: `/ipns/{ipns-name}` (or `/ipns/{libp2p-key}`). + +### Key Types + +Implementations MUST support Ed25519. Ed25519 signatures MUST follow the [standard from RFC8032](https://www.rfc-editor.org/rfc/rfc8032#section-5.1). + +Implementations MAY support RSA, Secp256k1 and ECDSA for private use, but peers from the public IPFS swarm and DHT may not be able to resolve IPNS records signed by these optional key types. +When implementing support for optional key types, follow signature implementation notes from [PeerID specs](https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#key-types). + +In all cases, the IPNS implementation MAY allow the user to enable/disable specific key types via configuration. Note that disabling support for compulsory key type will hinder IPNS interop. -These records are stored locally, as well as spread across the network, in order to be accessible to everyone. For storing this structured data, we use [Protocol Buffers](https://github.com/google/protobuf), which is a language-neutral, platform neutral extensible mechanism for serializing structured data. +### Wire Format +In the binary form, IPNS Name is a [Multihash](https://docs.ipfs.io/concepts/glossary/#multibase) of a `PublicKey` [Protocol Buffer](https://github.com/google/protobuf) envelope originally defined in [PeerID specs](https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#keys): + +```protobuf +syntax = "proto2"; + +enum KeyType { + RSA = 0; + Ed25519 = 1; + Secp256k1 = 2; + ECDSA = 3; +} + +// PublicKey struct below is often labeled as 'libp2p-key' (multicodec 0x72) +message PublicKey { + required KeyType Type = 1; + required bytes Data = 2; +} + +message PrivateKey { + required KeyType Type = 1; + required bytes Data = 2; +} ``` + +If PeerID specification changes in the future, the protobuf above takes the precedence. + +If `PublicKey` is small (e.g., Ed25519), it can be inlined by using the `identity` Multihash function. + +## IPNS Record + +A logical IPNS record is a data structure containing the following fields: + +- **Value** (bytes) + - It can be any path, such as a `/ipns/{ipns-key}` path to another IPNS record, a [DNSLink](https://dnslink.dev/) path (`/ipns/example.com`) or an immutable IPFS path (`/ipfs/baf...`). + - Implementations MUST include this value in both `IpnsEntry.value` and inside the DAG-CBOR document in `IpnsEntry.data[value]`. +- **Validity Type** (uint64) + - Defines the conditions under which the record is valid. + - The only supported value is `0`, which indicates the `validity` field contains the expiration date after which the IPNS record becomes invalid. + - Implementations MUST support `validityType = 0` and include this value in both `IpnsEntry.validityType` and inside the DAG-CBOR document at `IpnsEntry.data[validityType]`. +- **Validity** (bytes) + - When `validityType = 0` + - Expiration date of the record with nanoseconds precision. + - Represented as an ASCII string that follows notation from [RFC3339](https://www.ietf.org/rfc/rfc3339.txt) (`1970-01-01T00:00:00.000000001Z`). + - Implementations MUST include this value in both `IpnsEntry.validity` and inside the DAG-CBOR document at `IpnsEntry.data[validity]`. +- **Sequence** (uint64) + - Represents the current version of the record (starts at 0). + - Implementations MUST include this value in both `IpnsEntry.sequence` and inside the DAG-CBOR document at `IpnsEntry.data[sequence]`. +- **TTL** (uint64) + - A hint for how long the record should be cached before going back to, for instance the DHT, in order to check if it has been updated. + - Implementations MUST include this value in both `IpnsEntry.ttl` and inside the DAG-CBOR document at `IpnsEntry.data[ttl]`. +- **Public Key** (bytes) + - Public key used to sign this record. + - If public key is small enough to fit in IPNS name (e.g., Ed25519 keys inlined using `identity` multihash), `IpnsEntry.pubKey` field is redundant and MAY be skipped to save space. + - The public key MUST be included if it cannot be extracted from the IPNS name (e.g., legacy RSA keys). Implementers MUST follow key serialization defined in [PeerID specs](https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#key-types). +- **Signature** (bytes) + - Provides the cryptographic proof that the IPNS record was created by the owner of the private key. + - Implementations MUST include this value in `IpnsEntry.signatureV2` and follow signature creation and verification as described in [Record Creation](#record-creation) and [Record Validation](#record-validation). +- **Extensible Data** (DAG-CBOR) + - Extensible record data in [DAG-CBOR](https://ipld.io/specs/codecs/dag-cbor/spec/) format. + - The default set of fields can be augmented with additional information. Implementations are free to leverage this, or simply ignore unexpected fields. + +IPNS records are stored locally, as well as spread across the network, in order to be accessible to everyone. + +For storing this structured data at rest and on the wire, we use `IpnsEntry` encoded as [Protocol Buffer](https://github.com/google/protobuf), which is a language-neutral, platform neutral extensible mechanism for serializing structured data. +The extensible part of IPNS Record is placed in `IpnsEntry.data` field, which itself is encoded using a strict and deterministic subset of CBOR named [DAG-CBOR](https://ipld.io/specs/codecs/dag-cbor/spec/). + +The maximum size of `IpnsEntry` is 2 MiB. Bigger records MUST be ignored by IPNS implementations. + +```protobuf message IpnsEntry { - enum ValidityType { - // setting an EOL says "this record is valid until..." - EOL = 0; - } - required bytes value = 1; - required bytes signature = 2; + enum ValidityType { + // setting an EOL says "this record is valid until..." + EOL = 0; + } + + // deserialized copy of data[value] + optional bytes value = 1; - optional ValidityType validityType = 3; - optional bytes validity = 4; + // unused legacy field, use 'signatureV2' instead + optional bytes signature = 2; - optional uint64 sequence = 5; + // deserialized copies of data[validityType] and data[validity] + optional ValidityType validityType = 3; + optional bytes validity = 4; - optional uint64 ttl = 6; + // deserialized copy of data[sequence] + optional uint64 sequence = 5; - optional bytes pubKey = 7; + // record TTL in nanoseconds, a deserialized copy of data[ttl] + optional uint64 ttl = 6; + + // in order for nodes to properly validate a record upon receipt, they need the public + // key associated with it. For old RSA keys, its easiest if we just send this as part of + // the record itself. For newer Ed25519 keys, the public key can be embedded in the + // IPNS Name itself, making this field unnecessary. + optional bytes pubKey = 7; + + // the signature of the IPNS record + optional bytes signatureV2 = 8; + + // extensible record data in DAG-CBOR format + optional bytes data = 9; } ``` ## Protocol +### Overview + +![](img/ipns-overview.png) + Taking into consideration a p2p network, each peer should be able to publish IPNS records to the network, as well as to resolve the IPNS records published by other peers. When a node intends to publish a record to the network, an IPNS record needs to be created first. The node needs to have a previously generated asymmetric key pair to create the record according to the datastructure previously specified. It is important pointing out that the record needs to be uniquely identified in the network. As a result, the record identifier should be a hash of the public key used to sign the record. @@ -91,24 +178,59 @@ As soon as the node has the most recent record, the signature and the validity m Finally, the network nodes may also republish their records, so that the records in the network continue to be valid to the other nodes. -## Overview - -![](img/ipns-overview.png) - -## API Spec - - - [API_CORE](https://github.com/ipfs/specs/blob/master/API_CORE.md) +### Record Creation + +IPNS record MUST be serialized as `IpnsEntry` protobuf and the raw record data MUST be signed using the private key. + +Creating a new IPNS record MUST follow the below steps: + +1. Create `IpnsEntry` and set `value`, `validity`, `validityType`, `sequence`, and `ttl` + - If you are updating an existing record, remember to increase values in `sequence` and `validity` +2. Create a DAG-CBOR document with the same values for `value`, `validity`, `validityType`, `sequence`, and `ttl` +3. Store DAG-CBOR in `IpnsEntry.data`. + - If you want to store additional metadata in the record, add it under unique keys at `IpnsEntry.data`. + - The order of fields impacts signature verification. If you are using an alternative CBOR implementation, make sure the CBOR field order follows [RFC7049](https://www.rfc-editor.org/rfc/rfc7049) sorting rules: length and then bytewise. The order of fields impacts signature verification. +4. If your public key can't be inlined inside the IPNS Name, include a serialized copy in `IpnsEntry.pubKey` + - This step SHOULD be skipped for Ed25519 keys. +6. Create bytes for signing by concatenating `ipns-signature:` prefix (bytes in hex: `69706e732d7369676e61747572653a`) with raw CBOR bytes from `IpnsEntry.data` +7. Sign bytes from the previous step using the private key, and store the signature in `IpnsEntry.signatureV2` + +### Record Validation + +Implementations MUST resolve IPNS Names using only verified records. +Record's data and signature verification MUST be implemented as outlined below, and fail on the first error. + +1. Before parsing protobuf, confirm `IpnsEntry` size is less than 2 MiB +2. Confirm `IpnsEntry.signatureV2` and `IpnsEntry.data` are present and are not empty +3. Extract public key + - Use `IpnsEntry.pubKey` or a cached entry in the local key store, if present. + - If public key is missing + - Assume the public key is inlined in the IPNS Name itself (e.g., Ed25519 inlined using `identity` multihash) + - Confirm Multihash type is `identity` + - Unmarshall public key from Multihash digest +4. Deserialize `IpnsEntry.data` as a DAG-CBOR document +5. Confirm values in `IpnsEntry` Protobuf match deserialized ones from `IpnsEntry.data`: + - `IpnsEntry.value` must match `IpnsEntry.data[value]` + - `IpnsEntry.validity` must match `IpnsEntry.data[validity]` + - `IpnsEntry.validityType` must match `IpnsEntry.data[validityType]` + - `IpnsEntry.sequence` must match `IpnsEntry.data[sequence]` + - `IpnsEntry.ttl` must match `IpnsEntry.data[ttl]` +6. Create bytes for signature verification by concatenating `ipns-signature:` prefix (bytes in hex: `69706e732d7369676e61747572653a`) with raw CBOR bytes from `IpnsEntry.data` +7. Verify signature in `IpnsEntry.signatureV2` against data from the previous step. ## Implementations - - [js-ipfs](https://github.com/ipfs/js-ipfs/tree/master/packages/ipfs-core/src/ipns) - - [go-namesys](https://github.com/ipfs/go-namesys) +- [js-ipfs](https://github.com/ipfs/js-ipfs/tree/master/packages/ipfs-core/src/ipns) +- [go-namesys](https://github.com/ipfs/go-namesys) ## Integration with IPFS +Below are additional notes for implementers, documenting how IPNS is integrated within IPFS ecosystem. + #### Local record This record is stored in the peer's repo datastore and contains the **latest** version of the IPNS record published by the provided key. This record is useful for republishing, as well as tracking the sequence number. +A legacy convention that implementers MAY want to follow: **Key format:** `/ipns/base32()` @@ -117,7 +239,11 @@ Note: Base32 according to the [RFC4648](https://tools.ietf.org/html/rfc4648). #### Routing record The routing record is spread across the network according to the available routing systems. +The two routing systems currently available in IPFS are the `DHT` and `pubsub`. **Key format:** `/ipns/BINARY_ID` -The two routing systems currently available in IPFS are the `DHT` and `pubsub`. As the `pubsub` topics must be `utf-8` for interoperability among different implementations +- `/ipns/` is the ASCII prefix (bytes in hex: `2f69706e732f) +- `BINARY_ID` is the binary representation of IPNS Name (`libp2p-key` protobuf) + +As the `pubsub` topics must be `utf-8` for interoperability among different implementations, IPNS over PubSub topics use additional wrapping `/record/base64url-unpadded(key)` From f2a56295635322599d7827ec3dd1b23dc33c6b77 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Mon, 5 Sep 2022 21:03:58 +0200 Subject: [PATCH 02/13] chore: editorial --- IPNS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPNS.md b/IPNS.md index 472bce909..d0514153c 100644 --- a/IPNS.md +++ b/IPNS.md @@ -200,7 +200,7 @@ Creating a new IPNS record MUST follow the below steps: Implementations MUST resolve IPNS Names using only verified records. Record's data and signature verification MUST be implemented as outlined below, and fail on the first error. -1. Before parsing protobuf, confirm `IpnsEntry` size is less than 2 MiB +1. Before parsing the protobuf, confirm that `IpnsEntry` is less than 2MiB in size 2. Confirm `IpnsEntry.signatureV2` and `IpnsEntry.data` are present and are not empty 3. Extract public key - Use `IpnsEntry.pubKey` or a cached entry in the local key store, if present. From 6a2deaf64e80d747dc9299a8d875e2dcf9c998df Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Fri, 9 Sep 2022 23:32:44 +0200 Subject: [PATCH 03/13] ipns: separate name and keys sections --- IPNS.md | 130 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 87 insertions(+), 43 deletions(-) diff --git a/IPNS.md b/IPNS.md index d0514153c..ff8c8e219 100644 --- a/IPNS.md +++ b/IPNS.md @@ -17,15 +17,17 @@ IPNS records provide cryptographically verifiable, mutable pointers to objects. ## Organization of this document - [Introduction](#introduction) -- [IPNS Name](#ipns-name) - - [Text Format](#text-format) +- [IPNS Keys](#ipns-name) - [Key Types](#key-types) - - [Wire Format](#wire-format) + - [Key Serialization Format](#key-serialization-format) +- [IPNS Name](#ipns-name) + - [String Representation](#string-representation) - [IPNS Record](#ipns-record) + - [Record Serialization Format](#record-serialization-format) - [Protocol](#protocol) - [Overview](#overview) - [Record Creation](#record-creation) - - [Record Validation](#record-validation) + - [Record Verification](#record-verification) - [Integration with IPFS](#integration-with-ipfs) ## Introduction @@ -34,26 +36,23 @@ Each time a file is modified, its content address changes. As a consequence, the IPNS is based on [SFS](http://en.wikipedia.org/wiki/Self-certifying_File_System). It consists of a PKI namespace, where a name is simply the hash of a public key. As a result, whoever controls the private key has full control over the name. Accordingly, records are signed by the private key and then distributed across the network (in IPFS, via the routing system). This is an egalitarian way to assign mutable names on the Internet at large, without any centralization whatsoever, or certificate authorities. -## IPNS Name - -### Text Format - -To maximize interop with IPFS tools and wider ecosystem, IPNS Name can be represented as a [CID](https://docs.ipfs.tech/concepts/glossary/#cid) with `libp2p-key` [multicodec](https://docs.ipfs.tech/concepts/glossary/#multicodec) (code `0x72`), and encoded with [Multibase](https://docs.ipfs.io/concepts/glossary/#multibase) as Base32 (or Base36, for use in DNS contexts). - -A good practice is to prefix IPNS Name with `/ipns/` namespace: `/ipns/{ipns-name}` (or `/ipns/{libp2p-key}`). +## IPNS Keys ### Key Types -Implementations MUST support Ed25519. Ed25519 signatures MUST follow the [standard from RFC8032](https://www.rfc-editor.org/rfc/rfc8032#section-5.1). +Implementations MUST support Ed25519 with signatures defined in [RFC8032](https://www.rfc-editor.org/rfc/rfc8032#section-5.1). -Implementations MAY support RSA, Secp256k1 and ECDSA for private use, but peers from the public IPFS swarm and DHT may not be able to resolve IPNS records signed by these optional key types. -When implementing support for optional key types, follow signature implementation notes from [PeerID specs](https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#key-types). +Implementations MAY support RSA, Secp256k1 and ECDSA for private use, but peers +from the public IPFS swarm and DHT may not be able to resolve IPNS records +signed by these optional key types. When implementing support for these optional key +types, follow signature implementation notes from [PeerID specs](https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#key-types). In all cases, the IPNS implementation MAY allow the user to enable/disable specific key types via configuration. Note that disabling support for compulsory key type will hinder IPNS interop. -### Wire Format +### Key Serialization Format -In the binary form, IPNS Name is a [Multihash](https://docs.ipfs.io/concepts/glossary/#multibase) of a `PublicKey` [Protocol Buffer](https://github.com/google/protobuf) envelope originally defined in [PeerID specs](https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#keys): +IPNS encodes keys in [protobuf](https://github.com/google/protobuf) +containing a `KeyType` and the encoded key in a `Data` field: ```protobuf syntax = "proto2"; @@ -65,21 +64,52 @@ enum KeyType { ECDSA = 3; } -// PublicKey struct below is often labeled as 'libp2p-key' (multicodec 0x72) +// PublicKey message PublicKey { required KeyType Type = 1; required bytes Data = 2; } +// PrivateKey message PrivateKey { required KeyType Type = 1; required bytes Data = 2; } ``` -If PeerID specification changes in the future, the protobuf above takes the precedence. +Note: + +- `Data` encoding depends on `KeyType` (see [Key Types](#key-types)) + +- Although private keys are not transmitted over the wire, the `PrivateKey` + serialization format used to store keys on disk is also included as a + reference for IPNS implementors who would like to import existing IPNS key + pairs. + +- `PublicKey` and `PrivateKey` structures were originally defined in + [PeerID specification](https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#keys), + and are currently the same in both libp2p and IPNS. If the PeerID + specification ever changes in the future, definition from this file takes the + precedence. + +## IPNS Name + +IPNS Name is a [Multihash](https://docs.ipfs.io/concepts/glossary/#multihash) +of a serialized `PublicKey`. + +If a `PublicKey` is small, it can be inlined inside of a multihash using the `identity` function. +This is the default behavior for Ed25519 keys. + +### String Representation + +IPNS Name should be represented as a +[CIDv1](https://docs.ipfs.tech/concepts/glossary/#cid) with `libp2p-key` +[multicodec](https://docs.ipfs.tech/concepts/glossary/#multicodec) (code `0x72`), +and encoded using case-insensitive +[Multibase](https://docs.ipfs.io/concepts/glossary/#multibase) such as Base36. -If `PublicKey` is small (e.g., Ed25519), it can be inlined by using the `identity` Multihash function. +A good practice is to prefix IPNS Name with `/ipns/` namespace, +and refer to IPNS addresses as `/ipns/{ipns-name}` (or `/ipns/{libp2p-key}`). ## IPNS Record @@ -109,17 +139,17 @@ A logical IPNS record is a data structure containing the following fields: - The public key MUST be included if it cannot be extracted from the IPNS name (e.g., legacy RSA keys). Implementers MUST follow key serialization defined in [PeerID specs](https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#key-types). - **Signature** (bytes) - Provides the cryptographic proof that the IPNS record was created by the owner of the private key. - - Implementations MUST include this value in `IpnsEntry.signatureV2` and follow signature creation and verification as described in [Record Creation](#record-creation) and [Record Validation](#record-validation). + - Implementations MUST include this value in `IpnsEntry.signatureV2` and follow signature creation and verification as described in [Record Creation](#record-creation) and [Record Verification](#record-verification). - **Extensible Data** (DAG-CBOR) - Extensible record data in [DAG-CBOR](https://ipld.io/specs/codecs/dag-cbor/spec/) format. - The default set of fields can be augmented with additional information. Implementations are free to leverage this, or simply ignore unexpected fields. IPNS records are stored locally, as well as spread across the network, in order to be accessible to everyone. -For storing this structured data at rest and on the wire, we use `IpnsEntry` encoded as [Protocol Buffer](https://github.com/google/protobuf), which is a language-neutral, platform neutral extensible mechanism for serializing structured data. -The extensible part of IPNS Record is placed in `IpnsEntry.data` field, which itself is encoded using a strict and deterministic subset of CBOR named [DAG-CBOR](https://ipld.io/specs/codecs/dag-cbor/spec/). +### Record Serialization Format -The maximum size of `IpnsEntry` is 2 MiB. Bigger records MUST be ignored by IPNS implementations. +For storing this structured data at rest and on the wire, we use `IpnsEntry` encoded as [protobuf](https://github.com/google/protobuf), which is a language-neutral, platform neutral extensible mechanism for serializing structured data. +The extensible part of IPNS Record is placed in `IpnsEntry.data` field, which itself is encoded using a strict and deterministic subset of CBOR named [DAG-CBOR](https://ipld.io/specs/codecs/dag-cbor/spec/). ```protobuf message IpnsEntry { @@ -158,44 +188,57 @@ message IpnsEntry { } ``` +Notes: + +- The maximum size of `IpnsEntry` is 2 MiB. Bigger records MUST be ignored by IPNS implementations. + +- For legacy reasons, some values must be stored in both `IpnsEntry` protobuf and `IpnsEntry.data` CBOR. + This should not be ignore, as it impact interoperability with old software. + ## Protocol ### Overview ![](img/ipns-overview.png) -Taking into consideration a p2p network, each peer should be able to publish IPNS records to the network, as well as to resolve the IPNS records published by other peers. +Taking into consideration a p2p network, each peer should be able to publish [IPNS records](#ipns-record) to the network, as well as to resolve the IPNS records published by other peers. -When a node intends to publish a record to the network, an IPNS record needs to be created first. The node needs to have a previously generated asymmetric key pair to create the record according to the datastructure previously specified. It is important pointing out that the record needs to be uniquely identified in the network. As a result, the record identifier should be a hash of the public key used to sign the record. +When a node intends to publish a record to the network, an IPNS record needs to be [created](#record-creation) first. The node needs to have a previously generated asymmetric key pair to create the record according to the datastructure previously specified. It is important pointing out that the record needs to be uniquely identified in the network. As a result, the record identifier should be a hash of the public key used to sign the record. As an IPNS record may be updated during its lifetime, a versioning related logic is needed during the publish process. As a consequence, the record must be stored locally, in order to enable the publisher to understand which is the most recent record published. Accordingly, before creating the record, the node must verify if a previous version of the record exists, and update the sequence value for the new record being created. Once the record is created, it is ready to be spread through the network. This way, a peer can use whatever routing system it supports to make the record accessible to the remaining peers of the network. +The means of distribution are left unspecified. Implementations MAY choose to +publish signed record using multiple routing systems, such as +[libp2p Kademlia DHT](https://github.com/libp2p/specs/tree/master/kad-dht), +[PubSub topic](naming/pubsub.md), or a [Reframe endpoint](reframe/) (see [Routing record](#routing-record)). + On the other side, each peer must be able to get a record published by another node. It only needs to have the unique identifier used to publish the record to the network. Taking into account the routing system being used, we may obtain a set of occurrences of the record from the network. In this case, records can be compared using the sequence number, in order to obtain the most recent one. -As soon as the node has the most recent record, the signature and the validity must be verified, in order to conclude that the record is still valid and not compromised. +As soon as the node has the most recent record, the signature and the validity must be [verified](#record-verification), in order to conclude that the record is still valid and not compromised. Finally, the network nodes may also republish their records, so that the records in the network continue to be valid to the other nodes. ### Record Creation -IPNS record MUST be serialized as `IpnsEntry` protobuf and the raw record data MUST be signed using the private key. +IPNS record MUST be serialized as `IpnsEntry` protobuf and `IpfsEntry.data` MUST be signed using the private key. Creating a new IPNS record MUST follow the below steps: 1. Create `IpnsEntry` and set `value`, `validity`, `validityType`, `sequence`, and `ttl` - If you are updating an existing record, remember to increase values in `sequence` and `validity` 2. Create a DAG-CBOR document with the same values for `value`, `validity`, `validityType`, `sequence`, and `ttl` + - This is paramount: this CBOR will be used for signing. 3. Store DAG-CBOR in `IpnsEntry.data`. - If you want to store additional metadata in the record, add it under unique keys at `IpnsEntry.data`. - The order of fields impacts signature verification. If you are using an alternative CBOR implementation, make sure the CBOR field order follows [RFC7049](https://www.rfc-editor.org/rfc/rfc7049) sorting rules: length and then bytewise. The order of fields impacts signature verification. 4. If your public key can't be inlined inside the IPNS Name, include a serialized copy in `IpnsEntry.pubKey` - - This step SHOULD be skipped for Ed25519 keys. + - This step SHOULD be skipped for Ed25519, and any other key types that are inlined inside of [IPNS Name](#ipns-name) itself. 6. Create bytes for signing by concatenating `ipns-signature:` prefix (bytes in hex: `69706e732d7369676e61747572653a`) with raw CBOR bytes from `IpnsEntry.data` -7. Sign bytes from the previous step using the private key, and store the signature in `IpnsEntry.signatureV2` +7. Sign concatenated bytes from the previous step using the private key, and store the signature in `IpnsEntry.signatureV2` -### Record Validation +### Record Verification Implementations MUST resolve IPNS Names using only verified records. Record's data and signature verification MUST be implemented as outlined below, and fail on the first error. @@ -209,41 +252,42 @@ Record's data and signature verification MUST be implemented as outlined below, - Confirm Multihash type is `identity` - Unmarshall public key from Multihash digest 4. Deserialize `IpnsEntry.data` as a DAG-CBOR document -5. Confirm values in `IpnsEntry` Protobuf match deserialized ones from `IpnsEntry.data`: +5. Confirm values in `IpnsEntry` protobuf match deserialized ones from `IpnsEntry.data`: - `IpnsEntry.value` must match `IpnsEntry.data[value]` - `IpnsEntry.validity` must match `IpnsEntry.data[validity]` - `IpnsEntry.validityType` must match `IpnsEntry.data[validityType]` - `IpnsEntry.sequence` must match `IpnsEntry.data[sequence]` - `IpnsEntry.ttl` must match `IpnsEntry.data[ttl]` 6. Create bytes for signature verification by concatenating `ipns-signature:` prefix (bytes in hex: `69706e732d7369676e61747572653a`) with raw CBOR bytes from `IpnsEntry.data` -7. Verify signature in `IpnsEntry.signatureV2` against data from the previous step. - -## Implementations - -- [js-ipfs](https://github.com/ipfs/js-ipfs/tree/master/packages/ipfs-core/src/ipns) -- [go-namesys](https://github.com/ipfs/go-namesys) +7. Verify signature in `IpnsEntry.signatureV2` against concatenation result from the previous step. ## Integration with IPFS Below are additional notes for implementers, documenting how IPNS is integrated within IPFS ecosystem. -#### Local record +### Local Record This record is stored in the peer's repo datastore and contains the **latest** version of the IPNS record published by the provided key. This record is useful for republishing, as well as tracking the sequence number. -A legacy convention that implementers MAY want to follow: +A legacy convention that implementers MAY want to follow is to store serialized `IpnsEntry` under: **Key format:** `/ipns/base32()` Note: Base32 according to the [RFC4648](https://tools.ietf.org/html/rfc4648). -#### Routing record +### Routing Record The routing record is spread across the network according to the available routing systems. -The two routing systems currently available in IPFS are the `DHT` and `pubsub`. +The two routing systems currently available in IPFS are the [libp2p Kademlia DHT](https://github.com/libp2p/specs/tree/master/kad-dht) and [IPNS over PubSub](naming/pubsub.md). **Key format:** `/ipns/BINARY_ID` -- `/ipns/` is the ASCII prefix (bytes in hex: `2f69706e732f) -- `BINARY_ID` is the binary representation of IPNS Name (`libp2p-key` protobuf) +- `/ipns/` is the ASCII prefix (bytes in hex: `2f69706e732f`) +- `BINARY_ID` is the binary representation of [IPNS Name](#ipns-name) As the `pubsub` topics must be `utf-8` for interoperability among different implementations, IPNS over PubSub topics use additional wrapping `/record/base64url-unpadded(key)` + +### Implementations + +- [js-ipfs](https://github.com/ipfs/js-ipfs/tree/master/packages/ipfs-core/src/ipns) +- [go-namesys](https://github.com/ipfs/go-namesys) + From cfaff45934f9bcfb601b3656548146030a79efcc Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Mon, 12 Sep 2022 13:25:49 +0200 Subject: [PATCH 04/13] ipns: change max record size to 10 kiB --- IPNS.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/IPNS.md b/IPNS.md index ff8c8e219..e7ce9ea96 100644 --- a/IPNS.md +++ b/IPNS.md @@ -190,7 +190,10 @@ message IpnsEntry { Notes: -- The maximum size of `IpnsEntry` is 2 MiB. Bigger records MUST be ignored by IPNS implementations. +- IPNS implementations must support sending and receiving serialized + `IpnsEntry` of size less or equal 10 kiB. Handling records larger than 10 kiB + is not recommended so as to keep compatibility with implementations + and transports which only support up to 10 kiB. - For legacy reasons, some values must be stored in both `IpnsEntry` protobuf and `IpnsEntry.data` CBOR. This should not be ignore, as it impact interoperability with old software. @@ -237,13 +240,14 @@ Creating a new IPNS record MUST follow the below steps: - This step SHOULD be skipped for Ed25519, and any other key types that are inlined inside of [IPNS Name](#ipns-name) itself. 6. Create bytes for signing by concatenating `ipns-signature:` prefix (bytes in hex: `69706e732d7369676e61747572653a`) with raw CBOR bytes from `IpnsEntry.data` 7. Sign concatenated bytes from the previous step using the private key, and store the signature in `IpnsEntry.signatureV2` +8. Confirm that bytes with serialized `IpnsEntry` are less than or equal 10 kiB in size ### Record Verification Implementations MUST resolve IPNS Names using only verified records. Record's data and signature verification MUST be implemented as outlined below, and fail on the first error. -1. Before parsing the protobuf, confirm that `IpnsEntry` is less than 2MiB in size +1. Before parsing the protobuf, confirm that bytes with serialized `IpnsEntry` are less than or equal 10 kiB in size 2. Confirm `IpnsEntry.signatureV2` and `IpnsEntry.data` are present and are not empty 3. Extract public key - Use `IpnsEntry.pubKey` or a cached entry in the local key store, if present. From f085cd5c574cf362b67fac0af164df6c4b3d0a0f Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Mon, 12 Sep 2022 13:47:02 +0200 Subject: [PATCH 05/13] ipns: suggest _ prefix for user-defined fields https://github.com/ipfs/specs/pull/319#discussion_r967753270 --- IPNS.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/IPNS.md b/IPNS.md index e7ce9ea96..b774b13b7 100644 --- a/IPNS.md +++ b/IPNS.md @@ -142,7 +142,11 @@ A logical IPNS record is a data structure containing the following fields: - Implementations MUST include this value in `IpnsEntry.signatureV2` and follow signature creation and verification as described in [Record Creation](#record-creation) and [Record Verification](#record-verification). - **Extensible Data** (DAG-CBOR) - Extensible record data in [DAG-CBOR](https://ipld.io/specs/codecs/dag-cbor/spec/) format. - - The default set of fields can be augmented with additional information. Implementations are free to leverage this, or simply ignore unexpected fields. + - The default set of fields can be augmented with additional information. + - Implementations are free to leverage this, or simply ignore unexpected fields. + - A good practice is to prefix custom field names with `_` to avoid + collisions with any new mandatory fields that may be added in a future + version of this specification. IPNS records are stored locally, as well as spread across the network, in order to be accessible to everyone. From 8918b29f3ffea90bd35eb2d94618637c41a64ad5 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Mon, 12 Sep 2022 15:53:07 +0200 Subject: [PATCH 06/13] ipns: explicit signatureV1 field this removes any confusion around V1 and V2 --- IPNS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPNS.md b/IPNS.md index b774b13b7..d3fc6bdd3 100644 --- a/IPNS.md +++ b/IPNS.md @@ -166,7 +166,7 @@ message IpnsEntry { optional bytes value = 1; // unused legacy field, use 'signatureV2' instead - optional bytes signature = 2; + optional bytes signatureV1 = 2; // deserialized copies of data[validityType] and data[validity] optional ValidityType validityType = 3; From 381a51f4a082566aa889a87e6d39626ff052740f Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 13 Sep 2022 13:11:37 +0200 Subject: [PATCH 07/13] ipns: add Record Size Limit section The size is not mentioned once, making it easier to change in the future. --- IPNS.md | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/IPNS.md b/IPNS.md index d3fc6bdd3..f899571a3 100644 --- a/IPNS.md +++ b/IPNS.md @@ -24,6 +24,7 @@ IPNS records provide cryptographically verifiable, mutable pointers to objects. - [String Representation](#string-representation) - [IPNS Record](#ipns-record) - [Record Serialization Format](#record-serialization-format) + - [Record Size Limit](#record-size-limit) - [Protocol](#protocol) - [Overview](#overview) - [Record Creation](#record-creation) @@ -194,13 +195,17 @@ message IpnsEntry { Notes: -- IPNS implementations must support sending and receiving serialized - `IpnsEntry` of size less or equal 10 kiB. Handling records larger than 10 kiB - is not recommended so as to keep compatibility with implementations - and transports which only support up to 10 kiB. - - For legacy reasons, some values must be stored in both `IpnsEntry` protobuf and `IpnsEntry.data` CBOR. - This should not be ignore, as it impact interoperability with old software. + This should not be ignored, as it impacts interoperability with old software. + +### Record Size Limit + +IPNS implementations MUST support sending and receiving a serialized +`IpnsEntry` less than or equal to **10 KiB** in size. + +Records over the limit MAY be ignored. Handling records larger than the +limit is not recommended so as to keep compatibility with implementations and +transports that follow this specification. ## Protocol @@ -244,14 +249,14 @@ Creating a new IPNS record MUST follow the below steps: - This step SHOULD be skipped for Ed25519, and any other key types that are inlined inside of [IPNS Name](#ipns-name) itself. 6. Create bytes for signing by concatenating `ipns-signature:` prefix (bytes in hex: `69706e732d7369676e61747572653a`) with raw CBOR bytes from `IpnsEntry.data` 7. Sign concatenated bytes from the previous step using the private key, and store the signature in `IpnsEntry.signatureV2` -8. Confirm that bytes with serialized `IpnsEntry` are less than or equal 10 kiB in size +8. Confirm that the serialized `IpnsEntry` bytes sum to less than or equal to [the size limit](#record-size-limit). ### Record Verification Implementations MUST resolve IPNS Names using only verified records. Record's data and signature verification MUST be implemented as outlined below, and fail on the first error. -1. Before parsing the protobuf, confirm that bytes with serialized `IpnsEntry` are less than or equal 10 kiB in size +1. Before parsing the protobuf, confirm that the serialized `IpnsEntry` bytes sum to less than or equal to [the size limit](#record-size-limit). 2. Confirm `IpnsEntry.signatureV2` and `IpnsEntry.data` are present and are not empty 3. Extract public key - Use `IpnsEntry.pubKey` or a cached entry in the local key store, if present. From bc575b85ee2d79222387300677fa4b9cf9d18029 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 13 Sep 2022 13:20:58 +0200 Subject: [PATCH 08/13] ipns: best practices for extending IpnsEntry.data https://github.com/ipfs/specs/pull/319#discussion_r967753270 --- IPNS.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/IPNS.md b/IPNS.md index f899571a3..6d178e380 100644 --- a/IPNS.md +++ b/IPNS.md @@ -145,9 +145,12 @@ A logical IPNS record is a data structure containing the following fields: - Extensible record data in [DAG-CBOR](https://ipld.io/specs/codecs/dag-cbor/spec/) format. - The default set of fields can be augmented with additional information. - Implementations are free to leverage this, or simply ignore unexpected fields. - - A good practice is to prefix custom field names with `_` to avoid - collisions with any new mandatory fields that may be added in a future - version of this specification. + - A good practice is to: + - prefix custom field names with `_` to avoid collisions with any new + mandatory fields that may be added in a future version of this + specification. + - and/or create own namespace by setting value to DAG-CBOR: + `IpnsEntry.data[_namespace][customfield]`. IPNS records are stored locally, as well as spread across the network, in order to be accessible to everyone. From cebad21f09ef373448c90534036227d7ef2ceb52 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Wed, 14 Sep 2022 00:04:49 +0200 Subject: [PATCH 09/13] ipns: mark RSA keys as 'SHOULD' (if legacy matters) https://github.com/ipfs/specs/pull/319#discussion_r967752517 --- IPNS.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/IPNS.md b/IPNS.md index 6d178e380..398335eb9 100644 --- a/IPNS.md +++ b/IPNS.md @@ -42,11 +42,17 @@ IPNS is based on [SFS](http://en.wikipedia.org/wiki/Self-certifying_File_System) ### Key Types Implementations MUST support Ed25519 with signatures defined in [RFC8032](https://www.rfc-editor.org/rfc/rfc8032#section-5.1). +Ed25519 is the current default key type. -Implementations MAY support RSA, Secp256k1 and ECDSA for private use, but peers +Implementations SHOULD support RSA if they wish to interoperate with legacy +IPNS names (RSA was used before Ed25519). + +Implementations MAY support Secp256k1 and ECDSA for private use, but peers from the public IPFS swarm and DHT may not be able to resolve IPNS records -signed by these optional key types. When implementing support for these optional key -types, follow signature implementation notes from [PeerID specs](https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#key-types). +signed by these optional key types. + +When implementing support for key types, follow signature implementation notes +from [PeerID specs](https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#key-types). In all cases, the IPNS implementation MAY allow the user to enable/disable specific key types via configuration. Note that disabling support for compulsory key type will hinder IPNS interop. From 68f685af8860ad7e38c9c385cebb64a319e8ed5c Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Wed, 14 Sep 2022 00:22:53 +0200 Subject: [PATCH 10/13] ipns: note on ignored field --- IPNS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/IPNS.md b/IPNS.md index 398335eb9..11228c118 100644 --- a/IPNS.md +++ b/IPNS.md @@ -283,6 +283,8 @@ Record's data and signature verification MUST be implemented as outlined below, 6. Create bytes for signature verification by concatenating `ipns-signature:` prefix (bytes in hex: `69706e732d7369676e61747572653a`) with raw CBOR bytes from `IpnsEntry.data` 7. Verify signature in `IpnsEntry.signatureV2` against concatenation result from the previous step. +Value in `IpnsEntry.signatureV1` MUST be ignored. + ## Integration with IPFS Below are additional notes for implementers, documenting how IPNS is integrated within IPFS ecosystem. From efcecd5bdf550c8904d0931e44c4607f118cb5f7 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Wed, 14 Sep 2022 14:10:59 +0200 Subject: [PATCH 11/13] ipns: document backward compatibility We have to document legacy signature, because it is the only reason for copying 'data' fields into the main protobuf. Added section about backward compatibility so our approach is more clear. --- IPNS.md | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/IPNS.md b/IPNS.md index 11228c118..8df7d2dc4 100644 --- a/IPNS.md +++ b/IPNS.md @@ -25,6 +25,7 @@ IPNS records provide cryptographically verifiable, mutable pointers to objects. - [IPNS Record](#ipns-record) - [Record Serialization Format](#record-serialization-format) - [Record Size Limit](#record-size-limit) + - [Backward Compatibility](#backward-compatibility) - [Protocol](#protocol) - [Overview](#overview) - [Record Creation](#record-creation) @@ -175,7 +176,7 @@ message IpnsEntry { // deserialized copy of data[value] optional bytes value = 1; - // unused legacy field, use 'signatureV2' instead + // legacy field, verify 'signatureV2' instead optional bytes signatureV1 = 2; // deserialized copies of data[validityType] and data[validity] @@ -216,6 +217,24 @@ Records over the limit MAY be ignored. Handling records larger than the limit is not recommended so as to keep compatibility with implementations and transports that follow this specification. +### Backward Compatibility + +Implementations that want to interop with the public IPFS swarm MUST maintain +backward compatibility for legacy consumers of IPNS records: + + +- A legacy publisher MUST always be able to update to the latest implementation + of this specification without breaking record resolution for legacy consumers. +- A legacy consumer MUST always be able to resolve IPNS name, even when publisher + updated to the latest implementation of this specification. + +This means, for example, that changes made to the `IpnsEntry` protobuf, or +validation logic should always be additive. + +Future changes to this spec should include design decisions that allow legacy +nodes to gracefully ignore new fields and verify compatible records using +legacy logic. + ## Protocol ### Overview @@ -243,8 +262,7 @@ Finally, the network nodes may also republish their records, so that the records ### Record Creation -IPNS record MUST be serialized as `IpnsEntry` protobuf and `IpfsEntry.data` MUST be signed using the private key. - +IPNS record MUST be serialized as `IpnsEntry` protobuf, and `IpfsEntry.data` MUST be signed using the private key. Creating a new IPNS record MUST follow the below steps: 1. Create `IpnsEntry` and set `value`, `validity`, `validityType`, `sequence`, and `ttl` @@ -256,9 +274,13 @@ Creating a new IPNS record MUST follow the below steps: - The order of fields impacts signature verification. If you are using an alternative CBOR implementation, make sure the CBOR field order follows [RFC7049](https://www.rfc-editor.org/rfc/rfc7049) sorting rules: length and then bytewise. The order of fields impacts signature verification. 4. If your public key can't be inlined inside the IPNS Name, include a serialized copy in `IpnsEntry.pubKey` - This step SHOULD be skipped for Ed25519, and any other key types that are inlined inside of [IPNS Name](#ipns-name) itself. -6. Create bytes for signing by concatenating `ipns-signature:` prefix (bytes in hex: `69706e732d7369676e61747572653a`) with raw CBOR bytes from `IpnsEntry.data` -7. Sign concatenated bytes from the previous step using the private key, and store the signature in `IpnsEntry.signatureV2` -8. Confirm that the serialized `IpnsEntry` bytes sum to less than or equal to [the size limit](#record-size-limit). +5. Create `IpnsEntry.signatureV2` + - Create bytes for signing by concatenating `ipns-signature:` prefix (bytes in hex: `69706e732d7369676e61747572653a`) with raw CBOR bytes from `IpnsEntry.data` + - Sign concatenated bytes from the previous step using the private key, and store the signature in `IpnsEntry.signatureV2` +6. Create `IpnsEntry.signatureV1` (backward compatibility, for legacy software) + - Create bytes for signing by concatenating `IpnsEntry.value` + `IpnsEntry.validity` + `string(IpnsEntry.validityType)` + - Sign concatenated bytes from the previous step using the private key, and store the legacy signature in `IpnsEntry.signatureV1` +7. Confirm that the serialized `IpnsEntry` bytes sum to less than or equal to [the size limit](#record-size-limit). ### Record Verification From 9ae100804db3bd5ca6e8cf0b115db333979d5f72 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Wed, 19 Oct 2022 14:48:54 +0200 Subject: [PATCH 12/13] ipns: move to ./ipns --- README.md | 3 ++- IPNS.md => ipns/IPNS.md | 6 +++--- naming/pubsub.md => ipns/IPNS_PUBSUB.md | 13 ++++++++----- 3 files changed, 13 insertions(+), 9 deletions(-) rename IPNS.md => ipns/IPNS.md (98%) rename naming/pubsub.md => ipns/IPNS_PUBSUB.md (87%) diff --git a/README.md b/README.md index d5957e19f..fc5b9e8d1 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,8 @@ The specs contained in this and related repositories are: - **Networking layer:** - [libp2p](https://github.com/libp2p/specs) - libp2p is a modular and extensible network stack, built and use by IPFS, but that it can be reused as a standalone project. Covers: - **Records, Naming and Record Systems:** - - [IPNS](./IPNS.md) - InterPlanetary Naming System + - [IPNS](./ipns/IPNS.md) - InterPlanetary Naming System + - [IPNS over PubSub](./ipns/IPNS_PUBSUB.md) - IPNS over PubSub Router - [DNSLink](https://dnslink.dev) - **Other/related/included:** - [PDD](https://github.com/ipfs/pdd) - Protocol Driven Development diff --git a/IPNS.md b/ipns/IPNS.md similarity index 98% rename from IPNS.md rename to ipns/IPNS.md index 8df7d2dc4..59168efd8 100644 --- a/IPNS.md +++ b/ipns/IPNS.md @@ -1,4 +1,4 @@ -# ![draft](https://img.shields.io/badge/status-draft-yellow.svg?style=flat-square) IPNS - Inter-Planetary Naming System +# ![reliable](https://img.shields.io/badge/status-reliable-green.svg?style=flat-square) IPNS - Inter-Planetary Naming System **Authors(s)**: @@ -252,7 +252,7 @@ Once the record is created, it is ready to be spread through the network. This w The means of distribution are left unspecified. Implementations MAY choose to publish signed record using multiple routing systems, such as [libp2p Kademlia DHT](https://github.com/libp2p/specs/tree/master/kad-dht), -[PubSub topic](naming/pubsub.md), or a [Reframe endpoint](reframe/) (see [Routing record](#routing-record)). +[PubSub topic](./IPNS_PUBSUB.md), or a [Reframe endpoint](../reframe/) (see [Routing record](#routing-record)). On the other side, each peer must be able to get a record published by another node. It only needs to have the unique identifier used to publish the record to the network. Taking into account the routing system being used, we may obtain a set of occurrences of the record from the network. In this case, records can be compared using the sequence number, in order to obtain the most recent one. @@ -323,7 +323,7 @@ Note: Base32 according to the [RFC4648](https://tools.ietf.org/html/rfc4648). ### Routing Record The routing record is spread across the network according to the available routing systems. -The two routing systems currently available in IPFS are the [libp2p Kademlia DHT](https://github.com/libp2p/specs/tree/master/kad-dht) and [IPNS over PubSub](naming/pubsub.md). +The two routing systems currently available in IPFS are the [libp2p Kademlia DHT](https://github.com/libp2p/specs/tree/master/kad-dht) and [IPNS over PubSub](./IPNS_PUBSUB.md). **Key format:** `/ipns/BINARY_ID` diff --git a/naming/pubsub.md b/ipns/IPNS_PUBSUB.md similarity index 87% rename from naming/pubsub.md rename to ipns/IPNS_PUBSUB.md index 3c75c2835..3fc02ecaf 100644 --- a/naming/pubsub.md +++ b/ipns/IPNS_PUBSUB.md @@ -1,4 +1,4 @@ -# ![](https://img.shields.io/badge/status-wip-orange.svg?style=flat-square) IPNS PubSub Router +# ![reliable](https://img.shields.io/badge/status-reliable-green.svg?style=flat-square) IPNS PubSub Router Authors: @@ -10,7 +10,7 @@ Reviewers: # Abstract -[Inter-Planetary Naming System (IPNS)](/README.md) is a naming system responsible for the creating, reading and updating of mutable pointers to data. +[Inter-Planetary Naming System (IPNS)](./IPNS.md) is a naming system responsible for the creating, reading and updating of mutable pointers to data. IPNS consists of a public/private asymmetric cryptographic key pair, a record type and a protocol. Part of the protocol involves a routing layer that is used for the distribution and discovery of new or updated IPNS records. @@ -35,7 +35,7 @@ In this spec we address building a router based on a PubSub system, particularly # PubSub Protocol Overview The protocol has four components: -- [IPNS Records and Validation](/README.md) +- [IPNS Records and Validation](./IPNS.md) - [libp2p PubSub](https://github.com/libp2p/specs/tree/master/pubsub) - Translating an IPNS record name to/from a PubSub topic - Layering persistence onto libp2p PubSub @@ -91,5 +91,8 @@ every 10 seconds) # Implementations - - Kubo: and - +- Kubo + - + - + - + - From 0453b84af663337346ecb98d379087666bcf1947 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Wed, 19 Oct 2022 23:47:35 +0200 Subject: [PATCH 13/13] ipns: ensure old links work Gently point at new location (until we clean up docs.ipfs.tech) --- IPNS.md | 3 +++ ipns/README.md | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 IPNS.md create mode 100644 ipns/README.md diff --git a/IPNS.md b/IPNS.md new file mode 100644 index 000000000..656d7dfec --- /dev/null +++ b/IPNS.md @@ -0,0 +1,3 @@ +# IPNS Specs Moved + +Moved to [./ipns](./ipns/) diff --git a/ipns/README.md b/ipns/README.md new file mode 100644 index 000000000..8fc928e9f --- /dev/null +++ b/ipns/README.md @@ -0,0 +1,16 @@ +# IPNS Specifications + +## About + +**This directory** contains specifications related to IPNS. + +## **Intended audience** + +The goal of this spec is to provide the reference documentation that is +independent of specific language or existing implementation, allowing everyone +to create a compatible IPNS Record Publisher or Resolver. + +# Specification index + +* [IPNS.md](./IPNS.md) ← **START HERE** + * [IPNS_PUBSUB.md](./IPNS.md) - IPNS over PubSub