Skip to content
This repository has been archived by the owner on Jun 26, 2023. It is now read-only.

Commit

Permalink
feat: add PeerId interface and compliance tests (#107)
Browse files Browse the repository at this point in the history
Creates `PeerId` interface and its compliance tests. The discussion was initiated from libp2p/js-libp2p#955 and libp2p/js-peer-id#150 (review)

Co-authored-by: achingbrain <alex@achingbrain.net>
  • Loading branch information
nazarhussain and achingbrain authored Nov 3, 2021
1 parent 44ae09b commit bc88106
Show file tree
Hide file tree
Showing 9 changed files with 656 additions and 34 deletions.
2 changes: 2 additions & 0 deletions packages/compliance-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,10 @@
"it-goodbye": "^3.0.0",
"it-pair": "^1.0.0",
"it-pipe": "^1.1.0",
"libp2p-crypto": "^0.19.5",
"libp2p-interfaces": "^1.2.0",
"multiaddr": "^10.0.0",
"multiformats": "^9.4.9",
"p-defer": "^3.0.0",
"p-limit": "^3.1.0",
"p-wait-for": "^3.2.0",
Expand Down
411 changes: 411 additions & 0 deletions packages/compliance-tests/src/peer-id/index.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions packages/interfaces/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
"dependencies": {
"abort-controller": "^3.0.0",
"abortable-iterator": "^3.0.0",
"cids": "^1.1.9",
"debug": "^4.3.1",
"err-code": "^3.0.1",
"it-length-prefixed": "^5.0.2",
Expand Down
34 changes: 1 addition & 33 deletions packages/interfaces/src/crypto/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import PeerId from 'peer-id'
import { PeerId } from '../peer-id/types'
import { MultiaddrConnection } from '../transport/types'

/**
Expand All @@ -22,35 +22,3 @@ export type SecureOutbound = {
remoteEarlyData: Buffer;
remotePeer: PeerId;
}

export interface PublicKey {
readonly bytes: Uint8Array
verify: (data: Uint8Array, sig: Uint8Array) => Promise<boolean>
marshal: () => Uint8Array
equals: (key: PublicKey) => boolean
hash: () => Promise<Uint8Array>
}

/**
* Generic private key interface
*/
export interface PrivateKey {
readonly public: PublicKey
readonly bytes: Uint8Array
sign: (data: Uint8Array) => Promise<Uint8Array>
marshal: () => Uint8Array
equals: (key: PrivateKey) => boolean
hash: () => Promise<Uint8Array>
/**
* Gets the ID of the key.
*
* The key id is the base58 encoding of the SHA-256 multihash of its public key.
* The public key is a protobuf encoding containing a type and the DER encoding
* of the PKCS SubjectPublicKeyInfo.
*/
id: () => Promise<string>
/**
* Exports the password protected key in the format specified.
*/
export: (password: string, format?: 'pkcs-8' | string) => Promise<string>
}
25 changes: 25 additions & 0 deletions packages/interfaces/src/keys/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# interface-keys <!-- omit in toc -->

> Interfaces for libp2p keys
## Table of Contents <!-- omit in toc -->
- [Using the Test Suite](#using-the-test-suite)

## Using the Test Suite

You can also check out the [internal test suite](../../test/crypto/compliance.spec.js) to see the setup in action.

```js
const tests = require('libp2p-interfaces-compliance-tests/src/keys')
const yourKeys = require('./your-keys')

tests({
setup () {
// Set up your keys if needed, then return it
return yourKeys
},
teardown () {
// Clean up your keys if needed
}
})
```
34 changes: 34 additions & 0 deletions packages/interfaces/src/keys/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

export interface PublicKey {
readonly bytes: Uint8Array
verify: (data: Uint8Array, sig: Uint8Array) => Promise<boolean>
marshal: () => Uint8Array
equals: (key: PublicKey) => boolean
hash: () => Promise<Uint8Array>
}

/**
* Generic private key interface
*/
export interface PrivateKey {
readonly public: PublicKey
readonly bytes: Uint8Array
sign: (data: Uint8Array) => Promise<Uint8Array>
marshal: () => Uint8Array
equals: (key: PrivateKey) => boolean
hash: () => Promise<Uint8Array>
/**
* Gets the ID of the key.
*
* The key id is the base58 encoding of the SHA-256 multihash of its public key.
* The public key is a protobuf encoding containing a type and the DER encoding
* of the PKCS SubjectPublicKeyInfo.
*/
id: () => Promise<string>
/**
* Exports the password protected key in the format specified.
*/
export: (password: string, format?: 'pkcs-8' | string) => Promise<string>
}

export type KeyType = 'Ed25519' | 'RSA' | 'secp256k1'
44 changes: 44 additions & 0 deletions packages/interfaces/src/peer-id/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
interface-peer-id
========================

> A test suite and interface you can use to implement a PeerId module for libp2p.
The primary goal of this module is to enable developers to implement PeerId modules. This module and test suite was heavily inspired by earlier implementation of [PeerId](https://github.com/libp2p/js-peer-id).

Publishing a test suite as a module lets multiple modules all ensure compatibility since they use the same test suite.

The API is presented with both Node.js and Go primitives, however, there is not actual limitations for it to be extended for any other language, pushing forward the cross compatibility and interop through different stacks.

## Modules that implement the interface

- [JavaScript libp2p-peer-id](https://github.com/libp2p/js-peer-id)

Send a PR to add a new one if you happen to find or write one.

## Badge

Include this badge in your readme if you make a new module that uses interface-peer-id API.

![](/img/badge.png)

## Usage

### Node.js

Install `libp2p-interfaces-compliance-tests` as one of the development dependencies of your project and as a test file. Then, using `mocha` (for JavaScript) or a test runner with compatible API, do:

```js
const tests = require('libp2p-interfaces-compliance-tests/src/peer-id')

describe('your peer id', () => {
// use all of the test suits
tests({
setup () {
return YourPeerIdFactory
},
teardown () {
// Clean up any resources created by setup()
}
})
})
```
137 changes: 137 additions & 0 deletions packages/interfaces/src/peer-id/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import type { CID } from 'multiformats/cid'
import type { PublicKey, PrivateKey, KeyType } from '../keys/types'

interface PeerIdJSON {
readonly id: string;
readonly pubKey?: string;
readonly privKey?: string;
}

interface CreateOptions {
bits?: number;
keyType?: KeyType;
}

export interface PeerId {
readonly id: Uint8Array;
privKey: PrivateKey | undefined;
pubKey: PublicKey | undefined;

/**
* Return the protobuf version of the public key, matching go ipfs formatting
*/
marshalPubKey ():Uint8Array | undefined;

/**
* Return the protobuf version of the private key, matching go ipfs formatting
*/
marshalPrivKey (): Uint8Array | undefined;

/**
* Return the protobuf version of the peer-id
*/
marshal (excludePriv?: boolean): Uint8Array;

/**
* String representation
*/
toPrint (): string;

/**
* The jsonified version of the key, matching the formatting of go-ipfs for its config file
*/
toJSON (): PeerIdJSON;

/**
* Encode to hex.
*/
toHexString ():string;

/**
* Return raw id bytes
*/
toBytes () : Uint8Array;

/**
* Encode to base58 string.
*/
toB58String (): string;

/**
* Self-describing String representation
* in default format from RFC 0001: https://github.com/libp2p/specs/pull/209
*/
toString ():string;

/**
* Checks the equality of `this` peer against a given PeerId.
*/
equals (id: Uint8Array|PeerId): boolean | never;

/**
* Check if this PeerId instance is valid (privKey -> pubKey -> Id)
*/
isValid (): boolean;

/**
* Check if the PeerId has an inline public key.
*/
hasInlinePublicKey (): boolean;
}

export interface PeerIdFactory {
/**
* Create a new PeerId.
**/
create (args: CreateOptions): Promise<PeerId>;

/**
* Create PeerId from raw bytes.
*/
createFromBytes (buf: Uint8Array): PeerId;

/**
* Create PeerId from base58-encoded string.
*/
createFromB58String (str: string): PeerId;

/**
* Create PeerId from hex string.
*/
createFromHexString (str: string): PeerId;

/**
* Create PeerId from CID.
*/
createFromCID (cid: CID | Uint8Array | string): PeerId

/**
* Create PeerId from public key.
*/
createFromPubKey (key: Uint8Array | string): Promise<PeerId>;

/**
* Create PeerId from private key.
*/
createFromPrivKey (key: Uint8Array | string): Promise<PeerId>;

/**
* Create PeerId from PeerId JSON formatted object.
*/
createFromJSON (obj: PeerIdJSON): Promise<PeerId>;

/**
* Create PeerId from Protobuf bytes.
*/
createFromProtobuf (buf: Uint8Array | string): Promise<PeerId>;

/**
* Parse PeerId from string, maybe base58btc encoded without multibase prefix
*/
parse (str: string): PeerId

/**
* Checks if a value is an instance of PeerId.
*/
isPeerId (peerId:unknown): boolean;
}
2 changes: 1 addition & 1 deletion packages/interfaces/src/value-store/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type PeerId from 'peer-id'
import type { PeerId } from '../peer-id/types'

export interface GetValueResult {
from: PeerId,
Expand Down

0 comments on commit bc88106

Please sign in to comment.