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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@talismn/substrate-vrf

v1.0.0

Published

sr25519 VRF sign/verify in the origin-bound substrate-vrf namespace, as produced by the Talisman wallet's signer.signVrf (built for Orbinum)

Readme

@talismn/substrate-vrf

sr25519 VRF signing and verification in the origin-bound substrate-vrf context namespace — the scheme behind Talisman's injected signer.signVrf.

MIT-licensed with a single dependency (@scure/sr25519, MIT). The namespace is wallet-neutral on purpose, so other wallets can adopt it the way <Bytes> wrapping is shared for signRaw.

npm install @talismn/substrate-vrf

Why a VRF

A VRF signature is output(32) || proof(64): the output is deterministic per (secretKey, effective context, message) — unlike a regular sr25519 signature, whose nonce is random — and the proof lets anyone holding the public key check the output is genuine. That determinism is what makes it usable for deriving stable per-dapp secrets and identities from a wallet account, without ever exposing the account's keys.

Dapp usage

Request a signature through the injected extension, then verify it with your own origin:

import { sr25519VerifyVrf } from "@talismn/substrate-vrf"

const signer = injected.signer
if (typeof signer.signVrf !== "function") throw new Error("wallet does not support signVrf")

// data (and the optional context) are 0x-prefixed hex
const { signature } = await signer.signVrf({ address, data, context })

// publicKey = the account's 32-byte sr25519 public key; hexToBytes = any hex decoder
const valid = sr25519VerifyVrf(hexToBytes(publicKey), hexToBytes(data), hexToBytes(signature), {
  origin: location.origin,
  context: hexToBytes(context),
})

Every output is bound to the requesting site's web origin (scheme://host): no other site can obtain it, and a dapp served from several origins (including http vs https on the same host) derives a different value on each — pin a canonical origin for anything long-lived.

context is the dapp's own domain separator within its origin: different contexts derive independent outputs, so use one context per purpose (e.g. one per derived identity).

Wallet usage

import { sr25519SignVrf } from "@talismn/substrate-vrf"

// origin = the requesting site's web origin (`scheme://host`), never caller-supplied
const signature = sr25519SignVrf(secretKey, message, { origin, context })

The substrate-vrf namespace

The wallet never signs over the caller's raw context. The effective schnorrkel signing context is the frame

"substrate-vrf" || u32_le(origin.len) || utf8(origin) || u32_le(context.len) || context

built by substrateVrfContext(origin, context), and schnorrkel's extra is always empty.

  • The constant tag confines everything the wallet signs for external callers to one namespace: a caller-chosen context can never reproduce another schnorrkel protocol's transcript, so the wallet cannot be used as a VRF oracle against other protocols.
  • origin binds the output to the requesting site. Its length prefix is what makes (origin, context) injective — without it, a caller could pick a context that reconstructs another origin's frame.
  • extra is not exposed: it changes the proof but never the output, so a caller using it as a domain separator would silently derive one identity where it expects several.

The layout is frozen. Outputs are deterministic per effective context, so any change rotates every identity ever derived through the namespace. A revision must be a new opt-in tag, never a replacement.

Interoperability

Signatures are plain schnorrkel vrf_sign_extra signatures. Any schnorrkel implementation, in any language, can produce or verify them: use substrateVrfContext(origin, context) (or rebuild the frame from the layout above) as the signing context, with empty extra. The underlying primitives are byte-compatible with polkadot-js sr25519VrfSign / sr25519VrfVerify.

API

  • sr25519SignVrf(secretKey, message, { origin, context? })Uint8Array — 96-byte output || proof signature in the namespace
  • sr25519VerifyVrf(publicKey, message, signature, { origin, context? })boolean — malformed input returns false, never throws
  • substrateVrfContext(origin, context?)Uint8Array — the effective signing context, for re-implementers and non-JS verifiers
  • SubstrateVrfNamespace{ origin: string; context?: Uint8Array }