From 790e133ff666574d6e8c3c7658066a755008f659 Mon Sep 17 00:00:00 2001 From: lollerfirst Date: Sat, 17 Aug 2024 13:07:57 +0200 Subject: [PATCH 1/6] Introducing outputs signatures to perform SIG_ALL --- src/client/NUT11.ts | 19 +++++++++++++++++++ src/client/index.ts | 1 + 2 files changed, 20 insertions(+) diff --git a/src/client/NUT11.ts b/src/client/NUT11.ts index 23ee3d2..8037ffe 100644 --- a/src/client/NUT11.ts +++ b/src/client/NUT11.ts @@ -4,6 +4,8 @@ import { schnorr } from '@noble/curves/secp256k1'; import { randomBytes } from '@noble/hashes/utils'; import { parseSecret } from '../common/NUT11.js'; import { Proof, Secret } from '../common/index.js'; +import { BlindedMessage, serializeBlindedMessage } from './index.js'; +import { ProjPointType } from '@noble/curves/abstract/weierstrass.js'; export const createP2PKsecret = (pubkey: string): Uint8Array => { const newSecret: Secret = [ @@ -23,6 +25,12 @@ export const signP2PKsecret = (secret: Uint8Array, privateKey: PrivKey) => { return sig; }; +export const signBlindedMessage = (B_: string, privateKey: PrivKey) => { + const msgHash = sha256(B_); + const sig = schnorr.sign(msgHash, privateKey); + return sig; +} + export const getSignedProofs = (proofs: Array, privateKey: string): Array => { return proofs.map((p) => { try { @@ -37,6 +45,17 @@ export const getSignedProofs = (proofs: Array, privateKey: string): Array }); }; +export const getSignedOutput = (output: BlindedMessage, privateKey: PrivKey): BlindedMessage => { + const B_ = output.B_.toHex(true); + const signature = signBlindedMessage(B_, privateKey); + output.witness = { signatures: [bytesToHex(signature)] }; + return output; +} + +export const getSignedOutputs = (outputs: Array, privateKey: string): Array => { + return outputs.map(o => getSignedOutput(o, privateKey)); +} + export const getSignedProof = (proof: Proof, privateKey: PrivKey): Proof => { if (!proof.witness) { proof.witness = { diff --git a/src/client/index.ts b/src/client/index.ts index acf1f93..0cf402c 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -15,6 +15,7 @@ export type BlindedMessage = { B_: ProjPointType; r: bigint; secret: Uint8Array; + witness?: Witness; }; export function createRandomBlindedMessage(): BlindedMessage { From d36dbc83420dea0a412c27a3261a6b72aaf8809f Mon Sep 17 00:00:00 2001 From: lollerfirst Date: Mon, 19 Aug 2024 11:34:27 +0200 Subject: [PATCH 2/6] option for `createRandomBlindedMessage` to specify a private key to sign the messages. --- src/client/index.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/client/index.ts b/src/client/index.ts index 0cf402c..b263d1a 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -10,6 +10,8 @@ import type { } from '../common/index.js'; import { hashToCurve, pointFromHex } from '../common/index.js'; import { Witness } from '../common/index'; +import { PrivKey } from '@noble/curves/abstract/utils.js'; +import { getSignedOutput } from './NUT11.js'; export type BlindedMessage = { B_: ProjPointType; @@ -18,17 +20,23 @@ export type BlindedMessage = { witness?: Witness; }; -export function createRandomBlindedMessage(): BlindedMessage { - return blindMessage(randomBytes(32)); +export function createRandomBlindedMessage(privateKey?: PrivKey): BlindedMessage { + return blindMessage(randomBytes(32), + bytesToNumber(secp256k1.utils.randomPrivateKey()), + privateKey + ); } -export function blindMessage(secret: Uint8Array, r?: bigint): BlindedMessage { +export function blindMessage(secret: Uint8Array, r?: bigint, privateKey?: PrivKey): BlindedMessage { const Y = hashToCurve(secret); if (!r) { r = bytesToNumber(secp256k1.utils.randomPrivateKey()); } const rG = secp256k1.ProjectivePoint.BASE.multiply(r); const B_ = Y.add(rG); + if (privateKey !== undefined) { + return getSignedOutput({ B_, r, secret }, privateKey); + } return { B_, r, secret }; } From 353e5d0b4fb775a097d4dd6bdea69b113e2f1a0a Mon Sep 17 00:00:00 2001 From: lollerfirst Date: Mon, 19 Aug 2024 11:46:14 +0200 Subject: [PATCH 3/6] npm run format --- src/client/NUT11.ts | 13 ++++++++----- src/client/index.ts | 5 +++-- src/common/NUT11.ts | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/client/NUT11.ts b/src/client/NUT11.ts index 8037ffe..c2b2c1d 100644 --- a/src/client/NUT11.ts +++ b/src/client/NUT11.ts @@ -29,7 +29,7 @@ export const signBlindedMessage = (B_: string, privateKey: PrivKey) => { const msgHash = sha256(B_); const sig = schnorr.sign(msgHash, privateKey); return sig; -} +}; export const getSignedProofs = (proofs: Array, privateKey: string): Array => { return proofs.map((p) => { @@ -50,11 +50,14 @@ export const getSignedOutput = (output: BlindedMessage, privateKey: PrivKey): Bl const signature = signBlindedMessage(B_, privateKey); output.witness = { signatures: [bytesToHex(signature)] }; return output; -} +}; -export const getSignedOutputs = (outputs: Array, privateKey: string): Array => { - return outputs.map(o => getSignedOutput(o, privateKey)); -} +export const getSignedOutputs = ( + outputs: Array, + privateKey: string +): Array => { + return outputs.map((o) => getSignedOutput(o, privateKey)); +}; export const getSignedProof = (proof: Proof, privateKey: PrivKey): Proof => { if (!proof.witness) { diff --git a/src/client/index.ts b/src/client/index.ts index b263d1a..3aa6cef 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -21,7 +21,8 @@ export type BlindedMessage = { }; export function createRandomBlindedMessage(privateKey?: PrivKey): BlindedMessage { - return blindMessage(randomBytes(32), + return blindMessage( + randomBytes(32), bytesToNumber(secp256k1.utils.randomPrivateKey()), privateKey ); @@ -82,7 +83,7 @@ export const deserializeProof = (proof: SerializedProof): Proof => { C: pointFromHex(proof.C), id: proof.id, secret: new TextEncoder().encode(proof.secret), - witness: proof.witness?JSON.parse(proof.witness):undefined + witness: proof.witness ? JSON.parse(proof.witness) : undefined }; }; export const serializeBlindedMessage = ( diff --git a/src/common/NUT11.ts b/src/common/NUT11.ts index 57474ce..0660ef9 100644 --- a/src/common/NUT11.ts +++ b/src/common/NUT11.ts @@ -1,4 +1,4 @@ -import { Secret } from "./index.js"; +import { Secret } from './index.js'; export const parseSecret = (secret: string | Uint8Array): Secret => { try { From aedc6ece02ebe106c164f421f7bcab2572fabd17 Mon Sep 17 00:00:00 2001 From: lollerfirst Date: Mon, 19 Aug 2024 16:22:57 +0200 Subject: [PATCH 4/6] test + `verifyP2PKSigOutput` --- src/mint/NUT11.ts | 13 +++++++++++++ test/client/NUT11.test.ts | 8 +++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/mint/NUT11.ts b/src/mint/NUT11.ts index a9abd75..4f6aa87 100644 --- a/src/mint/NUT11.ts +++ b/src/mint/NUT11.ts @@ -2,6 +2,8 @@ import { schnorr } from '@noble/curves/secp256k1'; import { sha256 } from '@noble/hashes/sha256'; import { parseSecret } from '../common/NUT11.js'; import { Proof } from '../common/index.js'; +import { BlindedMessage } from '../client/index.js'; +import { ProjPointType } from '@noble/curves/abstract/weierstrass.js'; export const verifyP2PKSig = (proof: Proof) => { if (!proof.witness) { @@ -42,3 +44,14 @@ export const verifyP2PKSig = (proof: Proof) => { parsedSecret[1].data ); }; + +export const verifyP2PKSigOutput = (output: BlindedMessage, publicKey: string) => { + if (!output.witness) { + throw new Error('could not verify signature, no witness provided'); + } + return schnorr.verify( + output.witness.signatures[0], + sha256(output.B_.toHex(true)), + publicKey + ) +} \ No newline at end of file diff --git a/test/client/NUT11.test.ts b/test/client/NUT11.test.ts index ff69990..debdf5d 100644 --- a/test/client/NUT11.test.ts +++ b/test/client/NUT11.test.ts @@ -3,7 +3,8 @@ import { createP2PKsecret, getSignedProof } from '../../src/client/NUT11.js'; import { bytesToHex } from '@noble/curves/abstract/utils'; import { Proof, pointFromHex } from '../../src/common'; import { parseSecret } from '../../src/common/NUT11.js'; -import { verifyP2PKSig } from '../../src/mint/NUT11.js'; +import { verifyP2PKSig, verifyP2PKSigOutput } from '../../src/mint/NUT11.js'; +import { createRandomBlindedMessage } from '../../src/client/index.js'; const PRIVKEY = schnorr.utils.randomPrivateKey(); const PUBKEY = schnorr.getPublicKey(PRIVKEY); @@ -32,4 +33,9 @@ describe('test create p2pk secret', () => { const verify = verifyP2PKSig(signedProof); expect(verify).toBe(true); }); + test('sign and verify blindedMessage', async() => { + const blindedMessage = createRandomBlindedMessage(PRIVKEY); + const verify = verifyP2PKSigOutput(blindedMessage, bytesToHex(PUBKEY)); + expect(verify).toBe(true); + }); }); From 7053431b10052bce1843abbc66ad3a835a69b1ff Mon Sep 17 00:00:00 2001 From: lollerfirst <43107113+lollerfirst@users.noreply.github.com> Date: Thu, 19 Sep 2024 10:34:57 +0200 Subject: [PATCH 5/6] Update src/client/NUT11.ts Co-authored-by: gandlafbtc <123852829+gandlafbtc@users.noreply.github.com> --- src/client/NUT11.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/NUT11.ts b/src/client/NUT11.ts index c2b2c1d..9bdfccd 100644 --- a/src/client/NUT11.ts +++ b/src/client/NUT11.ts @@ -25,7 +25,7 @@ export const signP2PKsecret = (secret: Uint8Array, privateKey: PrivKey) => { return sig; }; -export const signBlindedMessage = (B_: string, privateKey: PrivKey) => { +export const signBlindedMessage = (B_: string, privateKey: PrivKey): Uint8Array => { const msgHash = sha256(B_); const sig = schnorr.sign(msgHash, privateKey); return sig; From 9373ac94499408e57097e3d3a4007e802834af4b Mon Sep 17 00:00:00 2001 From: lollerfirst <43107113+lollerfirst@users.noreply.github.com> Date: Thu, 19 Sep 2024 10:35:04 +0200 Subject: [PATCH 6/6] Update src/mint/NUT11.ts Co-authored-by: gandlafbtc <123852829+gandlafbtc@users.noreply.github.com> --- src/mint/NUT11.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mint/NUT11.ts b/src/mint/NUT11.ts index 4f6aa87..651c9e1 100644 --- a/src/mint/NUT11.ts +++ b/src/mint/NUT11.ts @@ -45,7 +45,7 @@ export const verifyP2PKSig = (proof: Proof) => { ); }; -export const verifyP2PKSigOutput = (output: BlindedMessage, publicKey: string) => { +export const verifyP2PKSigOutput = (output: BlindedMessage, publicKey: string): boolean => { if (!output.witness) { throw new Error('could not verify signature, no witness provided'); }