Skip to content

Commit

Permalink
fix qiwallet signing unit test
Browse files Browse the repository at this point in the history
  • Loading branch information
alejoacosta74 authored and rileystephens28 committed Dec 13, 2024
1 parent d089d0a commit 5ec5fc8
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 34 deletions.
30 changes: 18 additions & 12 deletions examples/signing/sign-verify-qi-schnorr.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
const quais = require('../../lib/commonjs/quais');
const {
Mnemonic,
QiHDWallet,
Zone,
QiTransaction,
getBytes,
keccak256,
} = require('../../lib/commonjs/quais');
require('dotenv').config();
const { keccak_256 } = require('@noble/hashes/sha3');

const { schnorr } = require('@noble/curves/secp256k1');

async function main() {
// Create wallet
const mnemonic = quais.Mnemonic.fromPhrase(process.env.MNEMONIC);
const qiWallet = quais.QiHDWallet.fromMnemonic(mnemonic);
const mnemonic = Mnemonic.fromPhrase(process.env.MNEMONIC);
const qiWallet = QiHDWallet.fromMnemonic(mnemonic);

// Get address info
const addressInfo1 = await qiWallet.getNextAddress(0, quais.Zone.Cyprus1);
const addressInfo1 = await qiWallet.getNextAddress(0, Zone.Cyprus1);
const addr1 = addressInfo1.address;
const pubkey1 = addressInfo1.pubKey;

Expand All @@ -23,13 +30,12 @@ async function main() {
denomination: 7,
},
address: addr1,
zone: quais.Zone.Cyprus1,
zone: Zone.Cyprus1,
},
];

// Polulate wallet with outpoints
qiWallet.importOutpoints(outpointsInfo);

// Define tx inputs, outputs for the Qi Tx
let txInputs = [
{
Expand All @@ -47,27 +53,27 @@ async function main() {
];

// Create the Qi Tx to be signed
const tx = new quais.QiTransaction();
const tx = new QiTransaction();
tx.txInputs = txInputs;
tx.txOutputs = txOutputs;

// Calculate the hash of the Qi tx (message to be signed and verified)
const txHash = keccak_256(tx.unsignedSerialized);
const txHash = getBytes(keccak256(tx.unsignedSerialized));

// Sign the tx
const serializedSignedTx = await qiWallet.signTransaction(tx);

// Unmarshall the signed Tx
const signedTx = quais.QiTransaction.from(serializedSignedTx);
const signedTx = QiTransaction.from(serializedSignedTx);

// Get the signature from the signed tx
const signature = signedTx.signature;

// Remove parity byte from pubkey
publicKey = '0x' + pubkey1.slice(4);

// Rerify the schnoor signature
const verified = schnorr.verify(quais.getBytes(signature), txHash, quais.getBytes(publicKey));
// Verify the schnoor signature
const verified = schnorr.verify(getBytes(signature), txHash, getBytes(publicKey));
console.log('Verified:', verified);
}

Expand Down
6 changes: 0 additions & 6 deletions src/_tests/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -344,9 +344,3 @@ export interface TestCaseQiTransaction {
};
signed: string;
}

export interface TestCaseQiSignMessage {
name: string;
mnemonic: string;
message: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,19 @@ import assert from 'assert';

import { loadTests } from '../utils.js';
import { schnorr } from '@noble/curves/secp256k1';
import { keccak_256 } from '@noble/hashes/sha3';
import { MuSigFactory } from '@brandonblack/musig';
import { TestCaseQiSignMessage, TestCaseQiTransaction, TxInput, TxOutput, Zone } from '../types.js';
import { TestCaseQiTransaction, TxInput, TxOutput, Zone } from '../types.js';

import { Mnemonic, QiHDWallet, QiTransaction, getBytes, hexlify, musigCrypto } from '../../index.js';
import {
Mnemonic,
QiHDWallet,
QiTransaction,
getBytes,
hexlify,
musigCrypto,
keccak256,
toUtf8Bytes,
} from '../../index.js';

describe('QiHDWallet: Test transaction signing', function () {
const tests = loadTests<TestCaseQiTransaction>('qi-transaction');
Expand All @@ -23,7 +31,7 @@ describe('QiHDWallet: Test transaction signing', function () {
test.transaction.txInputs,
test.transaction.txOutputs,
);
const digest = keccak_256(qiTx.unsignedSerialized);
const digest = getBytes(keccak256(qiTx.unsignedSerialized));
const signedSerialized = await qiWallet.signTransaction(qiTx);

const signedTx = QiTransaction.from(signedSerialized);
Expand All @@ -41,18 +49,32 @@ describe('QiHDWallet: Test transaction signing', function () {
}
});

interface signMessageTestCase {
mnemonic: string;
data: Array<{
name: string;
message: string;
}>;
}

describe('QiHDWallet: Test sign personal menssage', function () {
const tests = loadTests<TestCaseQiSignMessage>('qi-sign-message');
const tests = loadTests<signMessageTestCase>('qi-sign-message');
for (const test of tests) {
it(`tests signing personal message: ${test.name}`, async function () {
const mnemonic = Mnemonic.fromPhrase(test.mnemonic);
const qiWallet = QiHDWallet.fromMnemonic(mnemonic);
const addrInfo = qiWallet.getNextAddressSync(0, Zone.Cyprus1);
const signature = await qiWallet.signMessage(addrInfo.address, test.message);
const digest = keccak_256(test.message);
const verified = verifySchnorrSignature(signature, digest, addrInfo.pubKey);
assert.equal(verified, true);
});
const mnemonic = Mnemonic.fromPhrase(test.mnemonic);
const qiWallet = QiHDWallet.fromMnemonic(mnemonic);
const addrInfo = qiWallet.getNextAddressSync(0, Zone.Cyprus1);
for (const data of test.data) {
it(`tests signing personal message: ${data.name}`, async function () {
const signature = await qiWallet.signMessage(addrInfo.address, data.message);
const messageBytes =
typeof data.message === 'string'
? getBytes(toUtf8Bytes(data.message)) // Add UTF-8 encoding for strings
: data.message;
const digest = getBytes(keccak256(messageBytes));
const verified = verifySchnorrSignature(signature, digest, addrInfo.pubKey);
assert.equal(verified, true);
});
}
}
});

Expand Down
10 changes: 8 additions & 2 deletions src/wallet/qi-hdwallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import ecc from '@bitcoinerlab/secp256k1';
import { SelectedCoinsResult } from '../transaction/abstract-coinselector.js';
import { QiPerformActionTransaction } from '../providers/abstract-provider.js';
import { ConversionCoinSelector } from '../transaction/coinselector-conversion.js';
import { toUtf8Bytes } from '../quais.js';

/**
* @property {Outpoint} outpoint - The outpoint object.
Expand Down Expand Up @@ -1617,8 +1618,13 @@ export class QiHDWallet extends AbstractHDWallet<QiAddressInfo> {
*/
public async signMessage(address: string, message: string | Uint8Array): Promise<string> {
const privKey = this.getPrivateKey(address);
const digest = keccak256(message);
const signature = schnorr.sign(digest, getBytes(privKey));
const messageBytes =
typeof message === 'string'
? getBytes(toUtf8Bytes(message)) // Add UTF-8 encoding to support arbitrary strings
: message;
const digest = keccak256(messageBytes);
const digestBytes = getBytes(digest);
const signature = schnorr.sign(digestBytes, getBytes(privKey));
return hexlify(signature);
}

Expand Down
Binary file modified testcases/qi-sign-message.json.gz
Binary file not shown.
Binary file modified testcases/qi-transaction.json.gz
Binary file not shown.

0 comments on commit 5ec5fc8

Please sign in to comment.