/** * @packageDocumentation * * An implementation of a peer id * * @example * * ```TypeScript * import { peerIdFromString } from '@libp2p/peer-id' * const peer = peerIdFromString('12D3KooWKnDdG3iXw9eTFijk3EWSunZcFi54Zka4wmtqtt6rPxc8') * * console.log(peer.toCID()) // CID(bafzaa...) * console.log(peer.toString()) // "12D3K..." * ``` */ import { publicKeyFromMultihash } from '@libp2p/crypto/keys' import { InvalidCIDError, InvalidMultihashError, InvalidParametersError, UnsupportedKeyTypeError } from '@libp2p/interface' import { base58btc } from 'multiformats/bases/base58' import { CID } from 'multiformats/cid' import * as Digest from 'multiformats/hashes/digest' import { identity } from 'multiformats/hashes/identity' import { sha256 } from 'multiformats/hashes/sha2' import { toString as uint8ArrayToString } from 'uint8arrays/to-string' import { RSAPeerId as RSAPeerIdClass, Ed25519PeerId as Ed25519PeerIdClass, Secp256k1PeerId as Secp256k1PeerIdClass, URLPeerId as URLPeerIdClass } from './peer-id.ts' import type { Ed25519PeerId, RSAPeerId, URLPeerId, Secp256k1PeerId, PeerId, PublicKey, Ed25519PublicKey, Secp256k1PublicKey, RSAPublicKey, Ed25519PrivateKey, Secp256k1PrivateKey, RSAPrivateKey, PrivateKey } from '@libp2p/interface' import type { MultibaseDecoder } from 'multiformats/cid' import type { MultihashDigest } from 'multiformats/hashes/interface' // these values are from https://github.com/multiformats/multicodec/blob/master/table.csv const LIBP2P_KEY_CODE = 0x72 const TRANSPORT_IPFS_GATEWAY_HTTP_CODE = 0x0920 export function peerIdFromString (str: string, decoder?: MultibaseDecoder): Ed25519PeerId | Secp256k1PeerId | RSAPeerId | URLPeerId { let multihash: MultihashDigest if (str.charAt(0) === '1' || str.charAt(0) === 'Q') { // identity hash ed25519/secp256k1 key or sha2-256 hash of // rsa public key - base58btc encoded either way multihash = Digest.decode(base58btc.decode(`z${str}`)) } else if (str.startsWith('k51qzi5uqu5') || str.startsWith('kzwfwjn5ji4') || str.startsWith('k2k4r8') || str.startsWith('bafz')) { // base36 encoded CIDv1 with libp2p-key and identity hash (for ed25519/secp256k1/rsa) or base32 encoded CIDv1 with libp2p-key and identity hash (for ed25519/secp256k1/rsa) return peerIdFromCID(CID.parse(str)) } else { if (decoder == null) { throw new InvalidParametersError('Please pass a multibase decoder for strings that do not start with "1" or "Q"') } multihash = Digest.decode(decoder.decode(str)) } return peerIdFromMultihash(multihash) } export function peerIdFromPublicKey (publicKey: Ed25519PublicKey): Ed25519PeerId export function peerIdFromPublicKey (publicKey: Secp256k1PublicKey): Secp256k1PeerId export function peerIdFromPublicKey (publicKey: RSAPublicKey): RSAPeerId export function peerIdFromPublicKey (publicKey: PublicKey): PeerId export function peerIdFromPublicKey (publicKey: PublicKey): PeerId { if (publicKey.type === 'Ed25519') { return new Ed25519PeerIdClass({ multihash: publicKey.toCID().multihash, publicKey }) } else if (publicKey.type === 'secp256k1') { return new Secp256k1PeerIdClass({ multihash: publicKey.toCID().multihash, publicKey }) } else if (publicKey.type === 'RSA') { return new RSAPeerIdClass({ multihash: publicKey.toCID().multihash, publicKey }) } throw new UnsupportedKeyTypeError() } export function peerIdFromPrivateKey (privateKey: Ed25519PrivateKey): Ed25519PeerId export function peerIdFromPrivateKey (privateKey: Secp256k1PrivateKey): Secp256k1PeerId export function peerIdFromPrivateKey (privateKey: RSAPrivateKey): RSAPeerId export function peerIdFromPrivateKey (privateKey: PrivateKey): PeerId export function peerIdFromPrivateKey (privateKey: PrivateKey): PeerId { return peerIdFromPublicKey(privateKey.publicKey) } export function peerIdFromMultihash (multihash: MultihashDigest): PeerId { if (isSha256Multihash(multihash)) { return new RSAPeerIdClass({ multihash }) } else if (isIdentityMultihash(multihash)) { try { const publicKey = publicKeyFromMultihash(multihash) if (publicKey.type === 'Ed25519') { return new Ed25519PeerIdClass({ multihash, publicKey }) } else if (publicKey.type === 'secp256k1') { return new Secp256k1PeerIdClass({ multihash, publicKey }) } } catch (err) { // was not Ed or secp key, try URL const url = uint8ArrayToString(multihash.digest) return new URLPeerIdClass(new URL(url)) } } throw new InvalidMultihashError('Supplied PeerID Multihash is invalid') } export function peerIdFromCID (cid: CID): Ed25519PeerId | Secp256k1PeerId | RSAPeerId | URLPeerId { if (cid?.multihash == null || cid.version == null || (cid.version === 1 && (cid.code !== LIBP2P_KEY_CODE) && cid.code !== TRANSPORT_IPFS_GATEWAY_HTTP_CODE)) { throw new InvalidCIDError('Supplied PeerID CID is invalid') } if (cid.code === TRANSPORT_IPFS_GATEWAY_HTTP_CODE) { const url = uint8ArrayToString(cid.multihash.digest) return new URLPeerIdClass(new URL(url)) } return peerIdFromMultihash(cid.multihash) } function isIdentityMultihash (multihash: MultihashDigest): multihash is MultihashDigest<0x0> { return multihash.code === identity.code } function isSha256Multihash (multihash: MultihashDigest): multihash is MultihashDigest<0x12> { return multihash.code === sha256.code }