diff --git a/cryptonote_utils/cryptonote_utils.js b/cryptonote_utils/cryptonote_utils.js index a358698..2777cf8 100644 --- a/cryptonote_utils/cryptonote_utils.js +++ b/cryptonote_utils/cryptonote_utils.js @@ -54,6 +54,7 @@ var cnUtil = function(currencyConfig) var ENCRYPTED_PAYMENT_ID_TAIL = 141; var CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX = config.addressPrefix; var CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX = config.integratedAddressPrefix; + var CRYPTONOTE_PUBLIC_INTEGRATED_SUBADDRESS_BASE58_PREFIX = 42; var UINT64_MAX = new JSBigInt(2).pow(64); var CURRENT_TX_VERSION = 2; var OLD_TX_VERSION = 1; @@ -489,8 +490,9 @@ var cnUtil = function(currencyConfig) var dec = cnBase58.decode(address); var expectedPrefix = this.encode_varint(CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX); var expectedPrefixInt = this.encode_varint(CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX); + var expectedPrefixSub = this.encode_varint(CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX); var prefix = dec.slice(0, expectedPrefix.length); - if (prefix !== expectedPrefix && prefix !== expectedPrefixInt) { + if (prefix !== expectedPrefix && prefix !== expectedPrefixInt && prefix !== expectedPrefixSub) { throw "Invalid address prefix"; } dec = dec.slice(expectedPrefix.length); @@ -520,6 +522,14 @@ var cnUtil = function(currencyConfig) }; } }; + + this.is_subaddress = function(addr) { + var decoded = cnBase58.decode(addr); + var subaddressPrefix = this.encode_varint(CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX); + var prefix = decoded.slice(0, subaddressPrefix.length); + + return (prefix === subaddressPrefix); + }; this.valid_keys = function(view_pub, view_sec, spend_pub, spend_sec) { var expected_view_pub = this.sec_key_to_pub(view_sec); @@ -1623,7 +1633,6 @@ var cnUtil = function(currencyConfig) } else { tx.signatures = []; } - tx.extra = this.add_pub_key_to_extra(tx.extra, txkey.pub); var in_contexts = []; var inputs_money = JSBigInt.ZERO; @@ -1670,7 +1679,23 @@ var cnUtil = function(currencyConfig) throw "dst.amount < 0"; //amount can be zero if no change } dsts[i].keys = this.decode_address(dsts[i].address); - var out_derivation = this.generate_key_derivation(dsts[i].keys.view, txkey.sec); + + // R = rD for subaddresses + if(this.is_subaddress(dsts[i].address)) { + txkey.pub = ge_scalarmult(dsts[i].keys.spend, txkey.sec); + } + + var out_derivation; + + // send change to ourselves + if(dsts[i].keys.view == keys.view.pub) { + out_derivation = this.generate_key_derivation(txkey.pub, keys.view.sec); + } + + else { + out_derivation = this.generate_key_derivation(dsts[i].keys.view, txkey.sec); + } + if (rct) { amountKeys.push(this.derivation_to_scalar(out_derivation, out_index)); } @@ -1687,6 +1712,10 @@ var cnUtil = function(currencyConfig) ++out_index; outputs_money = outputs_money.add(dsts[i].amount); } + + // add pub key to extra after we know whether to use R = rG or R = rD + tx.extra = this.add_pub_key_to_extra(tx.extra, txkey.pub); + if (outputs_money.add(fee_amount).compare(inputs_money) > 0) { throw "outputs money (" + this.formatMoneyFull(outputs_money) + ") + fee (" + this.formatMoneyFull(fee_amount) + ") > inputs money (" + this.formatMoneyFull(inputs_money) + ")"; } @@ -2067,4 +2096,4 @@ var cnUtil = function(currencyConfig) return this; } -exports.cnUtil = cnUtil \ No newline at end of file +exports.cnUtil = cnUtil