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

@forgesworn/private-equality

v0.1.0

Published

Private equality of a secret, revealing one bit — Socialist Millionaires' Protocol over Ristretto255.

Readme

@forgesworn/private-equality

Nostr: npub1mgvlrnf5hm9yf0n5mf9nqmvarhvxkc6remu5ec3vf8r0txqkuk7su0e7q2

npm CI GitHub Sponsors

Decide "do two parties hold the same secret — yes/no?" via the Socialist Millionaires' Protocol over Ristretto255, revealing nothing else on mismatch.

What it is

@forgesworn/private-equality is a small cryptographic primitive for private equality testing. The consumer derives a canonical secret or codeword, supplies an authenticated channel, and the library runs the Socialist Millionaires' Protocol (OTR's SMP variant, ported to Ristretto255) as a pure state machine, returning a single boolean.

When to use it: any time two parties need to establish "do we share the same value?" without disclosing what the value is. Equal secrets yield match: true; unequal secrets yield match: false with nothing about either secret leaking. This is a general-purpose primitive — the consumer is responsible for deriving the secret and providing the authenticated channel.

This implements the published SMP as specified in the OTR protocol, adapted for the Ristretto255 prime-order group. It is a standard construction, not a novel one.

Use cases

  • Codeword matching — two parties confirm they were given the same codeword without either side revealing theirs
  • Buddy verification — OTR-style contact verification: confirm both ends of an encrypted channel share the same out-of-band secret, defeating an impersonator who doesn't know it
  • Answer checking — confirm a counterparty knows the same answer, PIN, or passphrase without ever transmitting it
  • Deduplication without disclosure — check whether two parties hold the same credential or token, learning only yes/no

Install

npm install @forgesworn/private-equality

Usage

The protocol runs four messages. In production each Uint8Array travels over the consumer's authenticated channel; the example below drives both sides in-process for illustration.

import { initiate, respond } from '@forgesworn/private-equality'

// `sessionBinding` MUST be your authenticated channel's transcript hash
// (e.g. the Noise handshake hash). Both sides must supply the same value.
const binding = new TextEncoder().encode('your-authenticated-channel-transcript-hash')

const alice = initiate('shared-codeword', binding)
const bob = respond('shared-codeword', binding)

let msg = alice.first
const s1 = bob.session.next(msg)         // { send: msg2 }
const s2 = alice.session.next(s1.send!)  // { send: msg3 }
const s3 = bob.session.next(s2.send!)    // { send: msg4, done: true, result }
const s4 = alice.session.next(s3.send!)  // { done: true, result }

console.log(s3.result.match, s4.result.match) // the single bit — identical on both sides

The single bit

Equal secrets produce match: true on both sides. Unequal secrets produce match: false — and on mismatch, neither party learns anything about the other's secret beyond the fact that the two values differ.

API surface

| Export | Description | |---|---| | initiate(secret, sessionBinding) | Start the protocol as the initiating party. Returns { session: SmpSession; first: Uint8Array }. | | respond(secret, sessionBinding) | Start the protocol as the responding party. Returns { session: SmpSession }. | | SmpSession.next(incoming) | Advance the state machine. Returns { send: Uint8Array } for intermediate steps, or { send?: Uint8Array; done: true; result: { match: boolean } } at completion. | | SmpError | Thrown on protocol violations (invalid proof, wrong state, mismatched binding). | | PRIVATE_EQUALITY_VERSION | Library version string. | | Secret | Uint8Array \| string |

Security

Plain SMP is vulnerable to man-in-the-middle attack. This library requires that both sides run over an authenticated channel and binds to it via the sessionBinding parameter (typically the Noise handshake hash or equivalent channel transcript). The library does not provide the authenticated channel — use an off-the-shelf Noise library for that.

Supplying a mismatched or relayed sessionBinding causes the protocol to abort with SmpError.

This library implements the published Socialist Millionaires' Protocol (OTR's SMP) over Ristretto255. It has not had a third-party cryptographic audit. Do not rely on it for a production privacy guarantee, and do not make privacy marketing claims, until it has been audited. It must be run over an authenticated channel (e.g. Noise); it does not provide one.

Licence

MIT — see LICENSE.