npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@canvas-js/signed-cid

v0.8.29

Published

This package implements a tiny signed data format for IPLD values. Any [CID](https://docs.ipfs.tech/concepts/content-addressing/) can be signed, and the resulting `Signature` can be passed around as an independent value on its own.

Downloads

155

Readme

@canvas-js/signed-cid

This package implements a tiny signed data format for IPLD values. Any CID can be signed, and the resulting Signature can be passed around as an independent value on its own.

Table of Contents

Overview

import type { CID } from "multiformats/cid"

export type Signature = {
  publicKey: string /** did:key URI */
  signature: Uint8Array
  cid: CID
}

Signatures sign the bytes of the CID, which carries metadata about the encoding format and hashing algorithm in addition to the hash of the encoded value itself. This allows values and their signatures to be re-encoded with different codecs without breaking validation.

did:key URIs are used to encode public keys.

Ed25519 and Secp256k1 signatures are supported, using the audited @noble/curves library. Secp256k1 public keys are always compressed.

The dag-json, dag-cbor, and raw IPLD codecs are supported by default, and others can be used by implementing the Codec interface. Similarly, sha2-256, blake3-256, and blake3-128 multihash digests are supported by default, and others can be used by implementing the Digest interface.

Usage

import { Ed25519Signer, verifySignedValue } from "@canvas-js/signed-cid"

const signer = new Ed25519Signer() // export the private key using `signer.export()`

const value = { foo: "hello world", bar: [1, 2, 3] }
const signature = signer.sign(value)
console.log(signature)
// {
//   publicKey: 'did:key:z6MkoTVvGXtN1Bjjd2dBMnaMNs2HFVzYkDZKNsMvVZCtaBep',
//   signature: Uint8Array(64) [
//     123,  77, 189, 225, 151, 159, 181,   5, 144, 130, 130,
//      58,  36, 189, 147, 133, 197, 194, 119, 116, 167, 215,
//     156,  18, 189,   6, 203, 156,  45,  40,  29, 215,  91,
//      47,  21,  44,  91,   9,  76,  79, 105,  75,  89, 144,
//      63, 198, 222, 175,  61, 131,  94,  20, 124,  91, 230,
//     149, 141,  43,   0, 207, 205,  76,   7,   9
//   ],
//   cid: CID(bafyreibqke43yd2rqll4nwlrbfjfqferamxp3sdia36a6awqvcae3cmm7a)
// }

verifySignedValue(signature, value) // throws an error if the signature is invalid

We can see a detailed breakdown of the CID in the signature with the CID explorer tool here. The prefix bytes of the CID tell us that it carries the sha2-256 hash of a dag-cbor value, and that the hash digest is 0x305139BC0F5182D7C6D9710952581491032EFDC86806FC0F02D0A8804D898CF8.

We can check this by encoding and hashing the value ourselves:

import { encode } from "@ipld/dag-cbor"

const value = encode({ foo: "hello world", bar: [1, 2, 3] })
console.log(value)
// Uint8Array(25) [
//   162,  99,  98,  97, 114, 131,   1,
//     2,   3,  99, 102, 111, 111, 107,
//   104, 101, 108, 108, 111,  32, 119,
//   111, 114, 108, 100
// ]

const hash = crypto.createHash("sha256").update(value).digest()
console.log(hash)
// <Buffer 30 51 39 bc 0f 51 82 d7 c6 d9 71 09 52 58 14 91 03 2e fd c8 68 06 fc 0f 02 d0 a8 80 4d 89 8c f8>

Again, signatures always sign the raw bytes of the entire CID, not just the hash digest.

API

Signing defaults to dag-cbor and sha2-256 if options.codec or options.digest are not provided, respectively.

Ed25519Signer

export declare class Ed25519Signer<T = any> {
  public static type: "ed25519"
  public static code: number

  public readonly uri: string

  /**
   * @param privateKey 32-byte ed25519 private key
   */
  public constructor(privateKey?: Uint8Array)

  public sign(value: T, options?: { codec?: string | Codec; digest?: string | Digest }): Signature

  public export(): { type: "ed25519"; privateKey: Uint8Array }
}

Secp256k1Signer

export declare class Secp256k1Signer<T = any> {
  public static type: "secp256k1"
  public static code: number

  public readonly uri: string

  /**
   * @param privateKey 33-byte secp256k1 private key
   */
  public constructor(privateKey?: Uint8Array)

  public sign(value: T, options?: { codec?: string | Codec; digest?: string | Digest }): Signature

  public export(): { type: "secp256k1"; privateKey: Uint8Array }
}

Verify a signed value

export type SignatureType = "ed25519" | "secp256k1"

/**
 * Verify that the signature is valid, and that signature.cid matches the given value
 */
export declare function verifySignedValue(
  signature: Signature,
  value: any,
  options?: { types: SignatureType[]; codecs?: Codec[]; digests?: Digest[] }
): void

Verify a standalone signature

/**
 * Verify that the signature is valid
 */
export declare function verifySignature(signature: Signature, options?: { types: SignatureType[] }): void

Utility types

Codec and Digest are similar to some existing interfaces in the JavaScript IPLD ecosystem, but are defined the way they are here to support synchronous zero-copy streaming encoders.

Digest

interface Digest {
  name: string
  code: number
  digest: (iter: Iterable<Uint8Array>) => Uint8Array
}

Codec

interface Codec {
  name: string
  code: number
  encode: (value: any) => Iterable<Uint8Array>
}