|
|
|
@ -487,231 +487,204 @@ static bool check_cointype(const CoinInfo *coin, uint32_t slip44, bool full) {
|
|
|
|
|
|
|
|
|
|
bool coin_path_check(const CoinInfo *coin, InputScriptType script_type,
|
|
|
|
|
uint32_t address_n_count, const uint32_t *address_n,
|
|
|
|
|
bool has_multisig, CoinPathCheckLevel level) {
|
|
|
|
|
// For level BASIC this function checks that a coin without strong replay
|
|
|
|
|
// protection doesn't access paths that are known to be used by another coin.
|
|
|
|
|
// Used by SignTx to ensure that a user cannot be coerced into signing a
|
|
|
|
|
// testnet transaction or a Litecoin transaction which in fact spends Bitcoin.
|
|
|
|
|
// For level KNOWN this function checks that the path is a recognized path for
|
|
|
|
|
// the given coin. Used by GetAddress to prevent ransom attacks where a user
|
|
|
|
|
// could be coerced to use an address with an unenumerable path.
|
|
|
|
|
// For level SCRIPT_TYPE this function makes the same checks as in level
|
|
|
|
|
// KNOWN, but includes script type checks.
|
|
|
|
|
|
|
|
|
|
const bool check_known = (level >= CoinPathCheckLevel_KNOWN);
|
|
|
|
|
const bool check_script_type = (level >= CoinPathCheckLevel_SCRIPT_TYPE);
|
|
|
|
|
bool has_multisig, bool full_check) {
|
|
|
|
|
// This function checks that the path is a recognized path for the given coin.
|
|
|
|
|
// Used by GetAddress to prevent ransom attacks where a user could be coerced
|
|
|
|
|
// to use an address with an unenumerable path and used by SignTx to ensure
|
|
|
|
|
// that a user cannot be coerced into signing a testnet transaction or a
|
|
|
|
|
// Litecoin transaction which in fact spends Bitcoin. If full_check is true,
|
|
|
|
|
// then this function also checks that the path fully matches the script type
|
|
|
|
|
// and coin type. This is used to determine whether a warning should be shown.
|
|
|
|
|
|
|
|
|
|
if (address_n_count == 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool valid = true;
|
|
|
|
|
// m/44' : BIP44 Legacy
|
|
|
|
|
// m / purpose' / coin_type' / account' / change / address_index
|
|
|
|
|
if (address_n_count > 0 && address_n[0] == (PATH_HARDENED + 44)) {
|
|
|
|
|
if (check_known) {
|
|
|
|
|
valid = valid && (address_n_count == 5);
|
|
|
|
|
} else {
|
|
|
|
|
valid = valid && (address_n_count >= 2);
|
|
|
|
|
}
|
|
|
|
|
valid = valid && check_cointype(coin, address_n[1], check_known);
|
|
|
|
|
if (check_script_type) {
|
|
|
|
|
if (address_n[0] == PATH_HARDENED + 44) {
|
|
|
|
|
valid = valid && (address_n_count == 5);
|
|
|
|
|
valid = valid && check_cointype(coin, address_n[1], full_check);
|
|
|
|
|
valid = valid && (address_n[2] & PATH_HARDENED);
|
|
|
|
|
valid = valid && ((address_n[2] & PATH_UNHARDEN_MASK) <= PATH_MAX_ACCOUNT);
|
|
|
|
|
valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
|
|
|
|
|
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
|
|
|
|
|
if (full_check) {
|
|
|
|
|
valid = valid && (script_type == InputScriptType_SPENDADDRESS);
|
|
|
|
|
valid = valid && (!has_multisig);
|
|
|
|
|
}
|
|
|
|
|
if (check_known) {
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
return valid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (address_n_count > 0 && address_n[0] == (PATH_HARDENED + 45)) {
|
|
|
|
|
if (check_script_type) {
|
|
|
|
|
valid = valid && has_multisig;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (address_n[0] == PATH_HARDENED + 45) {
|
|
|
|
|
if (address_n_count == 4) {
|
|
|
|
|
// m/45' - BIP45 Copay Abandoned Multisig P2SH
|
|
|
|
|
// m / purpose' / cosigner_index / change / address_index
|
|
|
|
|
// Patterns without a coin_type field must be treated as Bitcoin paths.
|
|
|
|
|
valid = valid && check_cointype(coin, SLIP44_BITCOIN, check_known);
|
|
|
|
|
if (check_script_type) {
|
|
|
|
|
valid = valid && (script_type == InputScriptType_SPENDMULTISIG);
|
|
|
|
|
}
|
|
|
|
|
if (check_known) {
|
|
|
|
|
valid = valid && (address_n[1] <= 100);
|
|
|
|
|
valid = valid && (address_n[2] <= PATH_MAX_CHANGE);
|
|
|
|
|
valid = valid && (address_n[3] <= PATH_MAX_ADDRESS_INDEX);
|
|
|
|
|
}
|
|
|
|
|
valid = valid && check_cointype(coin, SLIP44_BITCOIN, false);
|
|
|
|
|
valid = valid && (address_n[1] <= 100);
|
|
|
|
|
valid = valid && (address_n[2] <= PATH_MAX_CHANGE);
|
|
|
|
|
valid = valid && (address_n[3] <= PATH_MAX_ADDRESS_INDEX);
|
|
|
|
|
} else if (address_n_count == 5) {
|
|
|
|
|
// Unchained Capital compatibility pattern. Will be removed in the
|
|
|
|
|
// future.
|
|
|
|
|
// m / 45' / coin_type' / account' / [0-1000000] / address_index
|
|
|
|
|
valid = valid && check_cointype(coin, 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[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);
|
|
|
|
|
}
|
|
|
|
|
valid = valid && check_cointype(coin, address_n[1], full_check);
|
|
|
|
|
valid = valid && (address_n[2] & PATH_HARDENED);
|
|
|
|
|
valid =
|
|
|
|
|
valid && ((address_n[2] & PATH_UNHARDEN_MASK) <= PATH_MAX_ACCOUNT);
|
|
|
|
|
valid = valid && (address_n[3] <= 1000000);
|
|
|
|
|
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
|
|
|
|
|
} else if (address_n_count == 6) {
|
|
|
|
|
// Unchained Capital compatibility pattern. Will be removed in the
|
|
|
|
|
// 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, 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] & 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);
|
|
|
|
|
valid = valid && (address_n[5] <= PATH_MAX_ADDRESS_INDEX);
|
|
|
|
|
}
|
|
|
|
|
check_cointype(coin, PATH_HARDENED | address_n[1], full_check);
|
|
|
|
|
valid = valid && ((address_n[1] & PATH_HARDENED) ==
|
|
|
|
|
(address_n[2] & PATH_HARDENED));
|
|
|
|
|
valid =
|
|
|
|
|
valid && ((address_n[2] & PATH_UNHARDEN_MASK) <= PATH_MAX_ACCOUNT);
|
|
|
|
|
valid = valid && (address_n[3] <= 1000000);
|
|
|
|
|
valid = valid && (address_n[4] <= PATH_MAX_CHANGE);
|
|
|
|
|
valid = valid && (address_n[5] <= PATH_MAX_ADDRESS_INDEX);
|
|
|
|
|
} else {
|
|
|
|
|
if (check_known) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (full_check) {
|
|
|
|
|
valid = valid && (script_type == InputScriptType_SPENDADDRESS ||
|
|
|
|
|
script_type == InputScriptType_SPENDMULTISIG);
|
|
|
|
|
valid = valid && has_multisig;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return valid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// m/48' - BIP48 Copay Multisig P2SH
|
|
|
|
|
// 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] == (PATH_HARDENED + 48)) {
|
|
|
|
|
if (check_known) {
|
|
|
|
|
valid = valid && (address_n_count == 5 || address_n_count == 6);
|
|
|
|
|
} else {
|
|
|
|
|
valid = valid && (address_n_count >= 2);
|
|
|
|
|
}
|
|
|
|
|
valid = valid && check_cointype(coin, address_n[1], check_known);
|
|
|
|
|
if (check_script_type) {
|
|
|
|
|
valid = valid && has_multisig;
|
|
|
|
|
// we do not support Multisig with Taproot yet
|
|
|
|
|
valid = valid && (script_type == InputScriptType_SPENDMULTISIG ||
|
|
|
|
|
script_type == InputScriptType_SPENDP2SHWITNESS ||
|
|
|
|
|
script_type == InputScriptType_SPENDWITNESS);
|
|
|
|
|
}
|
|
|
|
|
if (check_known) {
|
|
|
|
|
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] & 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);
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
if (address_n[0] == PATH_HARDENED + 48) {
|
|
|
|
|
valid = valid && (address_n_count == 5 || address_n_count == 6);
|
|
|
|
|
valid = valid && check_cointype(coin, address_n[1], full_check);
|
|
|
|
|
valid = valid && (address_n[2] & PATH_HARDENED);
|
|
|
|
|
valid = valid && ((address_n[2] & PATH_UNHARDEN_MASK) <= PATH_MAX_ACCOUNT);
|
|
|
|
|
if (address_n_count == 5) {
|
|
|
|
|
// [OBSOLETE] m/48' Copay Multisig P2SH
|
|
|
|
|
// m / purpose' / coin_type' / account' / change / address_index
|
|
|
|
|
// NOTE: this pattern is not recognized by trezor-core
|
|
|
|
|
valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
|
|
|
|
|
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
|
|
|
|
|
if (full_check) {
|
|
|
|
|
valid = valid && has_multisig;
|
|
|
|
|
valid = valid && (script_type == InputScriptType_SPENDMULTISIG);
|
|
|
|
|
}
|
|
|
|
|
} else if (address_n_count == 6) {
|
|
|
|
|
// BIP-48:
|
|
|
|
|
// m / purpose' / coin_type' / account' / type' / change / address_index
|
|
|
|
|
valid = valid && (address_n[3] & PATH_HARDENED);
|
|
|
|
|
uint32_t type = address_n[3] & PATH_UNHARDEN_MASK;
|
|
|
|
|
valid = valid && (type <= 2);
|
|
|
|
|
valid = valid && (type == 0 || coin->has_segwit);
|
|
|
|
|
valid = valid && (address_n[4] <= PATH_MAX_CHANGE);
|
|
|
|
|
valid = valid && (address_n[5] <= PATH_MAX_ADDRESS_INDEX);
|
|
|
|
|
if (full_check) {
|
|
|
|
|
valid = valid && has_multisig;
|
|
|
|
|
switch (type) {
|
|
|
|
|
case 0:
|
|
|
|
|
valid = valid && (script_type == InputScriptType_SPENDMULTISIG ||
|
|
|
|
|
script_type == InputScriptType_SPENDADDRESS);
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
valid = valid && (script_type == InputScriptType_SPENDP2SHWITNESS);
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
valid = valid && (script_type == InputScriptType_SPENDWITNESS);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return valid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// m/49' : BIP49 SegWit
|
|
|
|
|
// m / purpose' / coin_type' / account' / change / address_index
|
|
|
|
|
if (address_n_count > 0 && address_n[0] == (PATH_HARDENED + 49)) {
|
|
|
|
|
if (address_n[0] == PATH_HARDENED + 49) {
|
|
|
|
|
valid = valid && coin->has_segwit;
|
|
|
|
|
if (check_known) {
|
|
|
|
|
valid = valid && (address_n_count == 5);
|
|
|
|
|
} else {
|
|
|
|
|
valid = valid && (address_n_count >= 2);
|
|
|
|
|
}
|
|
|
|
|
valid = valid && check_cointype(coin, address_n[1], check_known);
|
|
|
|
|
if (check_script_type) {
|
|
|
|
|
valid = valid && (address_n_count == 5);
|
|
|
|
|
valid = valid && check_cointype(coin, address_n[1], full_check);
|
|
|
|
|
valid = valid && (address_n[2] & PATH_HARDENED);
|
|
|
|
|
valid = valid && ((address_n[2] & PATH_UNHARDEN_MASK) <= PATH_MAX_ACCOUNT);
|
|
|
|
|
valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
|
|
|
|
|
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
|
|
|
|
|
if (full_check) {
|
|
|
|
|
valid = valid && (script_type == InputScriptType_SPENDP2SHWITNESS);
|
|
|
|
|
}
|
|
|
|
|
if (check_known) {
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
return valid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// m/84' : BIP84 Native SegWit
|
|
|
|
|
// m / purpose' / coin_type' / account' / change / address_index
|
|
|
|
|
if (address_n_count > 0 && address_n[0] == (PATH_HARDENED + 84)) {
|
|
|
|
|
if (address_n[0] == PATH_HARDENED + 84) {
|
|
|
|
|
valid = valid && coin->has_segwit;
|
|
|
|
|
valid = valid && (coin->bech32_prefix != NULL);
|
|
|
|
|
if (check_known) {
|
|
|
|
|
valid = valid && (address_n_count == 5);
|
|
|
|
|
} else {
|
|
|
|
|
valid = valid && (address_n_count >= 2);
|
|
|
|
|
}
|
|
|
|
|
valid = valid && check_cointype(coin, address_n[1], check_known);
|
|
|
|
|
if (check_script_type) {
|
|
|
|
|
valid = valid && (address_n_count == 5);
|
|
|
|
|
valid = valid && check_cointype(coin, address_n[1], full_check);
|
|
|
|
|
valid = valid && (address_n[2] & PATH_HARDENED);
|
|
|
|
|
valid = valid && ((address_n[2] & PATH_UNHARDEN_MASK) <= PATH_MAX_ACCOUNT);
|
|
|
|
|
valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
|
|
|
|
|
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
|
|
|
|
|
if (full_check) {
|
|
|
|
|
valid = valid && (script_type == InputScriptType_SPENDWITNESS);
|
|
|
|
|
}
|
|
|
|
|
if (check_known) {
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
return valid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// m/86' : BIP86 Taproot
|
|
|
|
|
// m / purpose' / coin_type' / account' / change / address_index
|
|
|
|
|
if (address_n_count > 0 && address_n[0] == (PATH_HARDENED + 86)) {
|
|
|
|
|
if (address_n[0] == PATH_HARDENED + 86) {
|
|
|
|
|
valid = valid && coin->has_taproot;
|
|
|
|
|
valid = valid && (coin->bech32_prefix != NULL);
|
|
|
|
|
if (check_known) {
|
|
|
|
|
valid = valid && (address_n_count == 5);
|
|
|
|
|
} else {
|
|
|
|
|
valid = valid && (address_n_count >= 2);
|
|
|
|
|
}
|
|
|
|
|
valid = valid && check_cointype(coin, address_n[1], check_known);
|
|
|
|
|
if (check_script_type) {
|
|
|
|
|
valid = valid && (address_n_count == 5);
|
|
|
|
|
valid = valid && check_cointype(coin, address_n[1], full_check);
|
|
|
|
|
valid = valid && (address_n[2] & PATH_HARDENED);
|
|
|
|
|
valid = valid && ((address_n[2] & PATH_UNHARDEN_MASK) <= PATH_MAX_ACCOUNT);
|
|
|
|
|
valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
|
|
|
|
|
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
|
|
|
|
|
if (full_check) {
|
|
|
|
|
// we do not support Multisig with Taproot yet
|
|
|
|
|
valid = valid && !has_multisig;
|
|
|
|
|
valid = valid && (script_type == InputScriptType_SPENDTAPROOT);
|
|
|
|
|
}
|
|
|
|
|
if (check_known) {
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
return valid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Green Address compatibility pattern. Will be removed in the future.
|
|
|
|
|
// m / [1,4] / address_index
|
|
|
|
|
if (address_n_count > 0 && (address_n[0] == 1 || address_n[0] == 4)) {
|
|
|
|
|
if (address_n[0] == 1 || address_n[0] == 4) {
|
|
|
|
|
valid = valid && (coin->coin_type == SLIP44_BITCOIN);
|
|
|
|
|
if (check_known) {
|
|
|
|
|
valid = valid && (address_n_count == 2);
|
|
|
|
|
valid = valid && (address_n[1] <= PATH_MAX_ADDRESS_INDEX);
|
|
|
|
|
valid = valid && (address_n_count == 2);
|
|
|
|
|
valid = valid && (address_n[1] <= PATH_MAX_ADDRESS_INDEX);
|
|
|
|
|
if (full_check) {
|
|
|
|
|
valid = valid && (script_type != InputScriptType_SPENDTAPROOT);
|
|
|
|
|
}
|
|
|
|
|
return valid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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] == (PATH_HARDENED + 3)) {
|
|
|
|
|
if (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] & 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);
|
|
|
|
|
valid = valid && (address_n_count == 4);
|
|
|
|
|
valid = valid && (address_n[1] & PATH_HARDENED);
|
|
|
|
|
valid = valid && ((address_n[1] & PATH_UNHARDEN_MASK) <= 100);
|
|
|
|
|
valid = valid && (address_n[2] == 1 || address_n[2] == 4);
|
|
|
|
|
valid = valid && (address_n[3] <= PATH_MAX_ADDRESS_INDEX);
|
|
|
|
|
if (full_check) {
|
|
|
|
|
valid = valid && (script_type != InputScriptType_SPENDTAPROOT);
|
|
|
|
|
}
|
|
|
|
|
return valid;
|
|
|
|
|
}
|
|
|
|
@ -719,41 +692,36 @@ bool coin_path_check(const CoinInfo *coin, InputScriptType script_type,
|
|
|
|
|
// Green Address compatibility patterns. Will be removed in the future.
|
|
|
|
|
// m / 1195487518
|
|
|
|
|
// m / 1195487518 / 6 / address_index
|
|
|
|
|
if (address_n_count > 0 && address_n[0] == 1195487518) {
|
|
|
|
|
if (address_n[0] == 1195487518) {
|
|
|
|
|
valid = valid && (coin->coin_type == SLIP44_BITCOIN);
|
|
|
|
|
if (check_known) {
|
|
|
|
|
if (address_n_count == 3) {
|
|
|
|
|
valid = valid && (address_n[1] == 6);
|
|
|
|
|
valid = valid && (address_n[2] <= PATH_MAX_ADDRESS_INDEX);
|
|
|
|
|
} else if (address_n_count != 1) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (address_n_count == 3) {
|
|
|
|
|
valid = valid && (address_n[1] == 6);
|
|
|
|
|
valid = valid && (address_n[2] <= PATH_MAX_ADDRESS_INDEX);
|
|
|
|
|
} else if (address_n_count != 1) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (full_check) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return valid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Casa compatibility pattern. Will be removed in the future.
|
|
|
|
|
// m / 49 / coin_type / account / change / address_index
|
|
|
|
|
if (address_n_count > 0 && address_n[0] == 49) {
|
|
|
|
|
if (check_known) {
|
|
|
|
|
valid = valid && (address_n_count == 5);
|
|
|
|
|
} else {
|
|
|
|
|
valid = valid && (address_n_count >= 2);
|
|
|
|
|
}
|
|
|
|
|
valid = valid &&
|
|
|
|
|
check_cointype(coin, PATH_HARDENED | address_n[1], check_known);
|
|
|
|
|
if (check_script_type) {
|
|
|
|
|
if (address_n[0] == 49) {
|
|
|
|
|
valid = valid && (address_n_count == 5);
|
|
|
|
|
valid =
|
|
|
|
|
valid && check_cointype(coin, PATH_HARDENED | address_n[1], full_check);
|
|
|
|
|
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);
|
|
|
|
|
if (full_check) {
|
|
|
|
|
valid = valid && (script_type == InputScriptType_SPENDP2SHWITNESS);
|
|
|
|
|
}
|
|
|
|
|
if (check_known) {
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
return valid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// we allow unknown paths only when a full check is not required
|
|
|
|
|
return level == CoinPathCheckLevel_BASIC;
|
|
|
|
|
// unknown path
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|