Skip to content

Commit

Permalink
wallet: refactor generateNonce(s) and generateBlind(s)
Browse files Browse the repository at this point in the history
  • Loading branch information
rithvikvibhu committed Nov 29, 2022
1 parent efda192 commit 18328f9
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 60 deletions.
7 changes: 1 addition & 6 deletions lib/wallet/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -1029,12 +1029,7 @@ class HTTP extends Server {
}

const nameHash = rules.hashName(name);
const nonces = await req.wallet.generateNonce(
nameHash,
address,
bid,
true
);
const nonces = await req.wallet.generateNonces(nameHash, address, bid);
const nonce = nonces[0];
const blind = rules.blind(bid, nonce);

Expand Down
6 changes: 4 additions & 2 deletions lib/wallet/rpc.js
Original file line number Diff line number Diff line change
Expand Up @@ -2665,9 +2665,11 @@ class RPC extends RPCBase {
const nameHash = rules.hashName(name);
const address = parseAddress(addr, this.network);

const blind = await wallet.generateBlind(nameHash, address, value, true);
const blinds = await wallet.generateBlinds(nameHash, address, value);

return blind.toString('hex');
// Return only first blind (based on own key)
// to stay backward-compatible
return blinds[0].toString('hex');
}
}

Expand Down
98 changes: 61 additions & 37 deletions lib/wallet/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -1191,17 +1191,14 @@ class Wallet extends EventEmitter {
}

/**
* Generate nonce deterministically
* based on address, name hash, and
* bid value.
* @param {Buffer} nameHash
* Get public keys at index based on
* address and value for nonce generation
* @param {Address} address
* @param {Amount} value
* @param {boolean} forAllKeys
* @returns {Buffer|Buffer[]}
* @returns {Buffer[]} public keys
*/

async generateNonce(nameHash, address, value, forAllKeys) {
async _getNoncePublicKeys(address, value) {
const path = await this.getPath(address.hash);

if (!path)
Expand All @@ -1221,57 +1218,84 @@ class Wallet extends EventEmitter {
publicKeys.push(accountKey.derive(index).publicKey);
}

// In case of multisig importnonce, we
// generate nonces for all N public keys
// with the first being own key
if (forAllKeys) {
const nonces = [];
for (const publicKey of publicKeys)
nonces.push(blake2b.multi(address.hash, publicKey, nameHash));
return publicKeys;
}

return nonces;
}
/**
* Generate nonce deterministically
* based on address (smallest pubkey),
* name hash, and bid value.
* @param {Buffer} nameHash
* @param {Address} address
* @param {Amount} value
* @returns {Buffer}
*/

// Use smallest public key by default
async generateNonce(nameHash, address, value) {
const publicKeys = await this._getNoncePublicKeys(address, value);

// Use smallest public key
publicKeys.sort(Buffer.compare);

return blake2b.multi(address.hash, publicKeys[0], nameHash);
}

/**
* Generate nonces deterministically
* for all keys (in multisig).
* @param {Buffer} nameHash
* @param {Address} address
* @param {Amount} value
* @returns {Buffer[]}
*/

async generateNonces(nameHash, address, value) {
const publicKeys = await this._getNoncePublicKeys(address, value);

// Generate nonces for all public keys
// Nonce based on own public key is always first
const nonces = [];
for (const publicKey of publicKeys)
nonces.push(blake2b.multi(address.hash, publicKey, nameHash));

return nonces;
}

/**
* Generate nonce & blind, save nonce.
* @param {Buffer} nameHash
* @param {Address} address
* @param {Amount} value
* @param {boolean} forAllKeys
* @returns {Buffer}
*/

async generateBlind(nameHash, address, value, forAllKeys) {
let nonces = await this.generateNonce(
nameHash,
address,
value,
forAllKeys
);
async generateBlind(nameHash, address, value) {
const nonce = await this.generateNonce(nameHash, address, value);
const blind = rules.blind(value, nonce);

// Coerce into array if only once nonce was generated
if (!Array.isArray(nonces))
nonces = [nonces];
await this.txdb.saveBlind(blind, {value, nonce});
return blind;
}

// Return the first blind to preserve backward compatibility.
// It is either based on
// - smallest key (forAllKeys=false), or
// - on own key (forAllKeys=true)
let firstBlind;
/**
* Generate all nonces & blinds, save nonces.
* @param {Buffer} nameHash
* @param {Address} address
* @param {Amount} value
* @returns {Buffer[]}
*/

async generateBlinds(nameHash, address, value) {
const nonces = await this.generateNonces(nameHash, address, value);

const blinds = [];
for (const nonce of nonces) {
const blind = rules.blind(value, nonce);
await this.txdb.saveBlind(blind, {value, nonce});

if (!firstBlind)
firstBlind = blind;
blinds.push(blind);
}

return firstBlind;
return blinds;
}

/**
Expand Down
6 changes: 2 additions & 4 deletions test/wallet-http-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -469,8 +469,7 @@ describe('Wallet HTTP', function() {
const nameHash = rules.hashName(name);

const primary = node.plugins.walletdb.wdb.primary;
const nonces = await primary.generateNonce(nameHash, address, bid, true);
const nonce = nonces[0];
const nonce = await primary.generateNonce(nameHash, address, bid);
const blind = rules.blind(bid, nonce);

assert.deepStrictEqual(response, {
Expand All @@ -495,8 +494,7 @@ describe('Wallet HTTP', function() {
const nameHash = rules.hashName(name);

const primary = node.plugins.walletdb.wdb.primary;
const nonces = await primary.generateNonce(nameHash, address, bid, true);
const nonce = nonces[0];
const nonce = await primary.generateNonce(nameHash, address, bid);
const blind = rules.blind(bid, nonce);

assert.deepStrictEqual(response, {
Expand Down
22 changes: 11 additions & 11 deletions test/wallet-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3303,12 +3303,12 @@ describe('Wallet', function() {
'hs1qyz8n88g6v5033r6fyj4jxkz29mqk5dgkdv7md7'
);

// Normal generate nonce
// Generate nonce (single nonce)
const nonce = await wallet.generateNonce(nameHash, addr, value);
assert.bufferEqual(nonce, expectedNonce);

// Generate nonce from RPC/HTTP importnonce
const nonces = await wallet.generateNonce(nameHash, addr, value, true);
// Generate all nonces (include all keys in multisig)
const nonces = await wallet.generateNonces(nameHash, addr, value);
assert.strictEqual(nonces.length, 1);
assert.bufferEqual(nonces[0], expectedNonce);
});
Expand Down Expand Up @@ -3367,8 +3367,8 @@ describe('Wallet', function() {
assert.bufferEqual(bobNonce, expectedNonces.alice);

// Generate nonces for all multisig participants
const aliceNonces = await alice.generateNonce(nameHash, addr, value, true);
const bobNonces = await bob.generateNonce(nameHash, addr, value, true);
const aliceNonces = await alice.generateNonces(nameHash, addr, value);
const bobNonces = await bob.generateNonces(nameHash, addr, value);

// Both alice and bob get N nonces
assert.strictEqual(aliceNonces.length, 2);
Expand All @@ -3389,22 +3389,22 @@ describe('Wallet', function() {
// Generate Blind
// --------------

// sanity check: no blinds as saved as of this point
// sanity check: no blinds saved as of this point
assert(!await bob.txdb.hasBlind(expectedBlinds.alice));
assert(!await bob.txdb.hasBlind(expectedBlinds.bob));

// 1) Normal behavior:
// 1) Generate single blind:
const bobBlind = await bob.generateBlind(nameHash, addr, value);
// smallest public key (alice's) is used for blind
assert.bufferEqual(bobBlind, expectedBlinds.alice);
// bob's public key blind isn't stored
assert(await bob.txdb.hasBlind(expectedBlinds.alice));
assert(!await bob.txdb.hasBlind(expectedBlinds.bob));

// 2) ImportNonce (RPC/HTTP) behavior:
const bobBlindAll = await bob.generateBlind(nameHash, addr, value, true);
// own public key is used for blind
assert.bufferEqual(bobBlindAll, expectedBlinds.bob);
// 2) Generate all blinds:
const bobBlinds = await bob.generateBlinds(nameHash, addr, value);
// own public key is used for blind (backwards-compatible)
assert.bufferEqual(bobBlinds[0], expectedBlinds.bob);
// but blinds for all key are saved in db
assert(await bob.txdb.hasBlind(expectedBlinds.alice));
assert(await bob.txdb.hasBlind(expectedBlinds.bob));
Expand Down

0 comments on commit 18328f9

Please sign in to comment.