|
|
|
@ -36,10 +36,6 @@
|
|
|
|
|
#include "cash_addr.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#define PATH_MAX_ACCOUNT 100
|
|
|
|
|
#define PATH_MAX_CHANGE 1
|
|
|
|
|
#define PATH_MAX_ADDRESS_INDEX 1000000
|
|
|
|
|
|
|
|
|
|
uint32_t ser_length(uint32_t len, uint8_t *out) {
|
|
|
|
|
if (len < 253) {
|
|
|
|
|
out[0] = len & 0xFF;
|
|
|
|
@ -508,7 +504,7 @@ bool coin_path_check(const CoinInfo *coin, InputScriptType script_type,
|
|
|
|
|
bool valid = true;
|
|
|
|
|
// m/44' : BIP44 Legacy
|
|
|
|
|
// m / purpose' / coin_type' / account' / change / address_index
|
|
|
|
|
if (address_n_count > 0 && address_n[0] == (0x80000000 + 44)) {
|
|
|
|
|
if (address_n_count > 0 && address_n[0] == (PATH_HARDENED + 44)) {
|
|
|
|
|
if (check_known) {
|
|
|
|
|
valid = valid && (address_n_count == 5);
|
|
|
|
|
} else {
|
|
|
|
@ -520,7 +516,7 @@ bool coin_path_check(const CoinInfo *coin, InputScriptType script_type,
|
|
|
|
|
valid = valid && (!has_multisig);
|
|
|
|
|
}
|
|
|
|
|
if (check_known) {
|
|
|
|
|
valid = valid && ((address_n[2] & 0x80000000) == 0x80000000);
|
|
|
|
|
valid = valid && (address_n[2] & PATH_HARDENED);
|
|
|
|
|
valid = valid && ((address_n[2] & 0x7fffffff) <= PATH_MAX_ACCOUNT);
|
|
|
|
|
valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
|
|
|
|
|
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
|
|
|
|
@ -528,7 +524,7 @@ bool coin_path_check(const CoinInfo *coin, InputScriptType script_type,
|
|
|
|
|
return valid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (address_n_count > 0 && address_n[0] == (0x80000000 + 45)) {
|
|
|
|
|
if (address_n_count > 0 && address_n[0] == (PATH_HARDENED + 45)) {
|
|
|
|
|
if (check_script_type) {
|
|
|
|
|
valid = valid && has_multisig;
|
|
|
|
|
}
|
|
|
|
@ -556,7 +552,7 @@ bool coin_path_check(const CoinInfo *coin, InputScriptType script_type,
|
|
|
|
|
script_type == InputScriptType_SPENDMULTISIG);
|
|
|
|
|
}
|
|
|
|
|
if (check_known) {
|
|
|
|
|
valid = valid && ((address_n[2] & 0x80000000) == 0x80000000);
|
|
|
|
|
valid = valid && (address_n[2] & PATH_HARDENED);
|
|
|
|
|
valid = valid && ((address_n[2] & 0x7fffffff) <= PATH_MAX_ACCOUNT);
|
|
|
|
|
valid = valid && (address_n[3] <= 1000000);
|
|
|
|
|
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
|
|
|
|
@ -566,15 +562,15 @@ bool coin_path_check(const CoinInfo *coin, InputScriptType script_type,
|
|
|
|
|
// future.
|
|
|
|
|
// m/45'/coin_type'/account'/[0-1000000]/change/address_index
|
|
|
|
|
// m/45'/coin_type/account/[0-1000000]/change/address_index
|
|
|
|
|
valid =
|
|
|
|
|
valid && check_cointype(coin, 0x80000000 | address_n[1], check_known);
|
|
|
|
|
valid = valid &&
|
|
|
|
|
check_cointype(coin, PATH_HARDENED | address_n[1], check_known);
|
|
|
|
|
if (check_script_type) {
|
|
|
|
|
valid = valid && (script_type == InputScriptType_SPENDADDRESS ||
|
|
|
|
|
script_type == InputScriptType_SPENDMULTISIG);
|
|
|
|
|
}
|
|
|
|
|
if (check_known) {
|
|
|
|
|
valid = valid &&
|
|
|
|
|
((address_n[1] & 0x80000000) == (address_n[2] & 0x80000000));
|
|
|
|
|
valid = valid && ((address_n[1] & PATH_HARDENED) ==
|
|
|
|
|
(address_n[2] & PATH_HARDENED));
|
|
|
|
|
valid = valid && ((address_n[2] & 0x7fffffff) <= PATH_MAX_ACCOUNT);
|
|
|
|
|
valid = valid && (address_n[3] <= 1000000);
|
|
|
|
|
valid = valid && (address_n[4] <= PATH_MAX_CHANGE);
|
|
|
|
@ -593,7 +589,7 @@ bool coin_path_check(const CoinInfo *coin, InputScriptType script_type,
|
|
|
|
|
// m / purpose' / coin_type' / account' / change / address_index
|
|
|
|
|
// Electrum:
|
|
|
|
|
// m / purpose' / coin_type' / account' / type' / change / address_index
|
|
|
|
|
if (address_n_count > 0 && address_n[0] == (0x80000000 + 48)) {
|
|
|
|
|
if (address_n_count > 0 && address_n[0] == (PATH_HARDENED + 48)) {
|
|
|
|
|
if (check_known) {
|
|
|
|
|
valid = valid && (address_n_count == 5 || address_n_count == 6);
|
|
|
|
|
} else {
|
|
|
|
@ -608,13 +604,13 @@ bool coin_path_check(const CoinInfo *coin, InputScriptType script_type,
|
|
|
|
|
script_type == InputScriptType_SPENDWITNESS);
|
|
|
|
|
}
|
|
|
|
|
if (check_known) {
|
|
|
|
|
valid = valid && ((address_n[2] & 0x80000000) == 0x80000000);
|
|
|
|
|
valid = valid && (address_n[2] & PATH_HARDENED);
|
|
|
|
|
valid = valid && ((address_n[2] & 0x7fffffff) <= PATH_MAX_ACCOUNT);
|
|
|
|
|
if (address_n_count == 5) {
|
|
|
|
|
valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
|
|
|
|
|
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
|
|
|
|
|
} else if (address_n_count == 6) {
|
|
|
|
|
valid = valid && ((address_n[3] & 0x80000000) == 0x80000000);
|
|
|
|
|
valid = valid && (address_n[3] & PATH_HARDENED);
|
|
|
|
|
valid = valid && ((address_n[3] & 0x7fffffff) <= 3);
|
|
|
|
|
valid = valid && (address_n[4] <= PATH_MAX_CHANGE);
|
|
|
|
|
valid = valid && (address_n[5] <= PATH_MAX_ADDRESS_INDEX);
|
|
|
|
@ -627,7 +623,7 @@ bool coin_path_check(const CoinInfo *coin, InputScriptType script_type,
|
|
|
|
|
|
|
|
|
|
// m/49' : BIP49 SegWit
|
|
|
|
|
// m / purpose' / coin_type' / account' / change / address_index
|
|
|
|
|
if (address_n_count > 0 && address_n[0] == (0x80000000 + 49)) {
|
|
|
|
|
if (address_n_count > 0 && address_n[0] == (PATH_HARDENED + 49)) {
|
|
|
|
|
valid = valid && coin->has_segwit;
|
|
|
|
|
if (check_known) {
|
|
|
|
|
valid = valid && (address_n_count == 5);
|
|
|
|
@ -639,7 +635,7 @@ bool coin_path_check(const CoinInfo *coin, InputScriptType script_type,
|
|
|
|
|
valid = valid && (script_type == InputScriptType_SPENDP2SHWITNESS);
|
|
|
|
|
}
|
|
|
|
|
if (check_known) {
|
|
|
|
|
valid = valid && ((address_n[2] & 0x80000000) == 0x80000000);
|
|
|
|
|
valid = valid && (address_n[2] & PATH_HARDENED);
|
|
|
|
|
valid = valid && ((address_n[2] & 0x7fffffff) <= PATH_MAX_ACCOUNT);
|
|
|
|
|
valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
|
|
|
|
|
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
|
|
|
|
@ -649,7 +645,7 @@ bool coin_path_check(const CoinInfo *coin, InputScriptType script_type,
|
|
|
|
|
|
|
|
|
|
// m/84' : BIP84 Native SegWit
|
|
|
|
|
// m / purpose' / coin_type' / account' / change / address_index
|
|
|
|
|
if (address_n_count > 0 && address_n[0] == (0x80000000 + 84)) {
|
|
|
|
|
if (address_n_count > 0 && address_n[0] == (PATH_HARDENED + 84)) {
|
|
|
|
|
valid = valid && coin->has_segwit;
|
|
|
|
|
valid = valid && (coin->bech32_prefix != NULL);
|
|
|
|
|
if (check_known) {
|
|
|
|
@ -662,7 +658,7 @@ bool coin_path_check(const CoinInfo *coin, InputScriptType script_type,
|
|
|
|
|
valid = valid && (script_type == InputScriptType_SPENDWITNESS);
|
|
|
|
|
}
|
|
|
|
|
if (check_known) {
|
|
|
|
|
valid = valid && ((address_n[2] & 0x80000000) == 0x80000000);
|
|
|
|
|
valid = valid && (address_n[2] & PATH_HARDENED);
|
|
|
|
|
valid = valid && ((address_n[2] & 0x7fffffff) <= PATH_MAX_ACCOUNT);
|
|
|
|
|
valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
|
|
|
|
|
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
|
|
|
|
@ -672,7 +668,7 @@ bool coin_path_check(const CoinInfo *coin, InputScriptType script_type,
|
|
|
|
|
|
|
|
|
|
// m/86' : BIP86 Taproot
|
|
|
|
|
// m / purpose' / coin_type' / account' / change / address_index
|
|
|
|
|
if (address_n_count > 0 && address_n[0] == (0x80000000 + 86)) {
|
|
|
|
|
if (address_n_count > 0 && address_n[0] == (PATH_HARDENED + 86)) {
|
|
|
|
|
valid = valid && coin->has_taproot;
|
|
|
|
|
valid = valid && (coin->bech32_prefix != NULL);
|
|
|
|
|
if (check_known) {
|
|
|
|
@ -687,7 +683,7 @@ bool coin_path_check(const CoinInfo *coin, InputScriptType script_type,
|
|
|
|
|
valid = valid && (script_type == InputScriptType_SPENDTAPROOT);
|
|
|
|
|
}
|
|
|
|
|
if (check_known) {
|
|
|
|
|
valid = valid && ((address_n[2] & 0x80000000) == 0x80000000);
|
|
|
|
|
valid = valid && (address_n[2] & PATH_HARDENED);
|
|
|
|
|
valid = valid && ((address_n[2] & 0x7fffffff) <= PATH_MAX_ACCOUNT);
|
|
|
|
|
valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
|
|
|
|
|
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
|
|
|
|
@ -708,11 +704,11 @@ bool coin_path_check(const CoinInfo *coin, InputScriptType script_type,
|
|
|
|
|
|
|
|
|
|
// Green Address compatibility pattern. Will be removed in the future.
|
|
|
|
|
// m / 3' / [1-100]' / [1,4] / address_index
|
|
|
|
|
if (address_n_count > 0 && address_n[0] == (0x80000000 + 3)) {
|
|
|
|
|
if (address_n_count > 0 && address_n[0] == (PATH_HARDENED + 3)) {
|
|
|
|
|
valid = valid && (coin->coin_type == SLIP44_BITCOIN);
|
|
|
|
|
if (check_known) {
|
|
|
|
|
valid = valid && (address_n_count == 4);
|
|
|
|
|
valid = valid && ((address_n[1] & 0x80000000) == 0x80000000);
|
|
|
|
|
valid = valid && (address_n[1] & PATH_HARDENED);
|
|
|
|
|
valid = valid && ((address_n[1] & 0x7fffffff) <= 100);
|
|
|
|
|
valid = valid && (address_n[2] == 1 || address_n[2] == 4);
|
|
|
|
|
valid = valid && (address_n[3] <= PATH_MAX_ADDRESS_INDEX);
|
|
|
|
@ -744,13 +740,13 @@ bool coin_path_check(const CoinInfo *coin, InputScriptType script_type,
|
|
|
|
|
} else {
|
|
|
|
|
valid = valid && (address_n_count >= 2);
|
|
|
|
|
}
|
|
|
|
|
valid =
|
|
|
|
|
valid && check_cointype(coin, 0x80000000 | address_n[1], check_known);
|
|
|
|
|
valid = valid &&
|
|
|
|
|
check_cointype(coin, PATH_HARDENED | address_n[1], check_known);
|
|
|
|
|
if (check_script_type) {
|
|
|
|
|
valid = valid && (script_type == InputScriptType_SPENDP2SHWITNESS);
|
|
|
|
|
}
|
|
|
|
|
if (check_known) {
|
|
|
|
|
valid = valid && ((address_n[1] & 0x80000000) == 0);
|
|
|
|
|
valid = valid && ((address_n[1] & PATH_HARDENED) == 0);
|
|
|
|
|
valid = valid && (address_n[2] <= PATH_MAX_ACCOUNT);
|
|
|
|
|
valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
|
|
|
|
|
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
|
|
|
|
|