A javaScript library for signing and verifying Schnorr Signatures.
It can be used for single and multi signatures with and without exposing the public keys individually.
Requirements | Installing | Examples | License | Contributing
- Node: >=16.x, <=20.x
- npm (Node.js package manager) v9.x.x
$ npm install @lorhansohaky/schnorrkel.js
Using yarn:
$ yarn add @lorhansohaky/schnorrkel.js
git clone https://github.com/LorhanSohaky/schnorrkel.js
cd schnorrkel.js
npm install
We refer to Single Signatures as ones that have a single signer.
Sign:
import Schnorrkel from '@lorhansohaky/schnorrkel.js/'
import { generateRandomKeys } from '@lorhansohaky/schnorrkel.js/core'
const keyPair = generateRandomKeys()
const privateKey = randomBytes(32) // Buffer
const msg = 'test message'
const {signature, finalPublicNonce} = Schnorrkel.sign(keyPair.privateKey, msg)
Offchain verification:
const publicKey: Buffer = ... (derived from the privateKey)
// signature and finalPublicNonce come from s
const result = Schnorrkel.verify(signature, msg, finalPublicNonce, publicKey)
You can see the full implementation in tests/schnorrkel/sign.test.ts
and tests/schnorrkel/verify.test.ts
in this repository.
Schnorr multisignatures work on the basis n/n - all of the signers need to sign in order for the signature to be valid. Below are all the steps needed to craft a successful multisig.
Public nonces need to be exchanged between signers before they sign. Normally, the Signer should implement this library as define a getPublicNonces
method that will call the library and return the nonces. For our test example, we're going to call the schnorrkel library directly:
import Schnorrkel from '@lorhansohaky/schnorrkel.js/'
import { generateRandomKeys } from '@lorhansohaky/schnorrkel.js/core'
const schnorrkel = new Schnorrkel()
const keyPair1 = generateRandomKeys()
const keyPair2 = generateRandomKeys()
const publicNonces1 = schnorrkel.generatePublicNonces(keyPair1.privateKey)
const publicNonces2 = schnorrkel.generatePublicNonces(keyPair2.privateKey)
You can see the full implementation in tests/unsafe-schnorrkel/generatePublicNonces.test.ts
in this repository.
After we have them, here is how to sign:
import Schnorrkel from '@lorhansohaky/schnorrkel.js/'
import { generateRandomKeys } from '@lorhansohaky/schnorrkel.js/core'
const schnorrkelOne = new Schnorrkel()
const schnorrkelTwo = new Schnorrkel()
const keyPairOne = generateRandomKeys()
const keyPairTwo = generateRandomKeys()
const publicNoncesOne = schnorrkelOne.generatePublicNonces(keyPairOne.privateKey)
const publicNoncesTwo = schnorrkelTwo.generatePublicNonces(keyPairTwo.privateKey)
const publicKeys = [keyPair1.publicKey, keyPair2.publicKey]
const publicNonces = [publicNoncesOne, publicNoncesTwo]
const combinedPublicKey = schnorrkel.getCombinedPublicKey(publicKeys)
const msg = 'test message'
const signatureOne = schnorrkelOne.multiSigSign(keyPairOne.privateKey, msg, combinedPublicKey, publicNonces)
const signatureTwo = schnorrkelTwo.multiSigSign(keyPairTwo.privateKey, msg, combinedPublicKey, publicNonces)
const signatures = [signatureOne.signature, signatureTwo.signature]
const signaturesSummed = Schnorrkel.sumSigs(signatures)
const result = Schnorrkel.verify(signaturesSummed, msg, signatureTwo.finalPublicNonce, combinedPublicKeyTwo.combinedKey)
You can see the full implementation in tests/schnorrkel/sumSigs.test.ts
, tests/unsafe-schnorrkel/multiSigSign.test.ts
and tests/schnorrkel/verify.test.ts
in this repository.