Skip to content

Commit

Permalink
Merge pull request #4 from lollerfirst/nut11-sign-outputs
Browse files Browse the repository at this point in the history
NUT11 sign outputs
  • Loading branch information
gandlafbtc authored Sep 20, 2024
2 parents 058b0cd + 9373ac9 commit 2620908
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 4 deletions.
22 changes: 22 additions & 0 deletions src/client/NUT11.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand All @@ -23,6 +25,12 @@ export const signP2PKsecret = (secret: Uint8Array, privateKey: PrivKey) => {
return sig;
};

export const signBlindedMessage = (B_: string, privateKey: PrivKey): Uint8Array => {
const msgHash = sha256(B_);
const sig = schnorr.sign(msgHash, privateKey);
return sig;
};

export const getSignedProofs = (proofs: Array<Proof>, privateKey: string): Array<Proof> => {
return proofs.map((p) => {
try {
Expand All @@ -37,6 +45,20 @@ export const getSignedProofs = (proofs: Array<Proof>, 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<BlindedMessage>,
privateKey: string
): Array<BlindedMessage> => {
return outputs.map((o) => getSignedOutput(o, privateKey));
};

export const getSignedProof = (proof: Proof, privateKey: PrivKey): Proof => {
if (!proof.witness) {
proof.witness = {
Expand Down
16 changes: 13 additions & 3 deletions src/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,34 @@ 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<bigint>;
r: bigint;
secret: Uint8Array;
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 };
}

Expand Down
13 changes: 13 additions & 0 deletions src/mint/NUT11.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -42,3 +44,14 @@ export const verifyP2PKSig = (proof: Proof) => {
parsedSecret[1].data
);
};

export const verifyP2PKSigOutput = (output: BlindedMessage, publicKey: string): boolean => {
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
)
}
8 changes: 7 additions & 1 deletion test/client/NUT11.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
});
});

0 comments on commit 2620908

Please sign in to comment.