chore(common): add BTC signet definition
What changed, and why it matters
This commit adds support for Bitcoin Signet, a public testing network for Bitcoin, to Trezor firmware. It is a routine feature addition with no security-relevant code changes. The commit only adds a new coin definition, updates generated coin-info tables, and adjusts internal tooling to treat Signet like the existing Testnet and Regtest networks.
No security action required. Treat as a normal feature/maintenance commit.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change introduces a new coin definition JSON for Bitcoin Signet (address_type 111, P2SH 196, bech32 prefix ‘tb’, SLIP44 1, segwit/taproot enabled) and regenerates the embedded coininfo.py lookup tables across all supported Trezor models. It also updates helper scripts so Signet is classified as a Bitcoin test network rather than an altcoin. No cryptographic, parsing, or authorization logic is modified.
Changed components
common/defs/bitcoin/bitcoin_signet.jsoncommon/defs/support.jsoncommon/tools/coin_info.pycommon/tools/cointool.pycommon/tools/maxfee.pycore/src/apps/bitcoin/common.pycore/src/apps/common/coininfo.pycore/src/apps/common/coininfo.py.makotools/check-bitcoin-onlyInspect captured patch +263 / −7
diff --git a/common/defs/bitcoin/bitcoin_signet.json b/common/defs/bitcoin/bitcoin_signet.json
new file mode 100644
index 00000000..1bce9214
--- /dev/null
+++ b/common/defs/bitcoin/bitcoin_signet.json
@@ -0,0 +1,44 @@
+{
+ "coin_name": "Signet",
+ "coin_shortcut": "SIGNET",
+ "coin_label": "Signet",
+ "website": "https://bitcoin.org",
+ "github": "https://github.com/bitcoin/bitcoin",
+ "maintainer": "Roman Zeyde <roman.zeyde@satoshilabs.com>",
+ "curve_name": "secp256k1",
+ "decimals": 8,
+ "address_type": 111,
+ "address_type_p2sh": 196,
+ "maxfee_kb": 10000000,
+ "minfee_kb": 1000,
+ "signed_message_header": "Bitcoin Signed Message:\n",
+ "hash_genesis_block": "00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6",
+ "xprv_magic": 70615956,
+ "xpub_magic": 70617039,
+ "xpub_magic_segwit_p2sh": 71979618,
+ "xpub_magic_segwit_native": 73342198,
+ "xpub_magic_multisig_segwit_p2sh": 37915119,
+ "xpub_magic_multisig_segwit_native": 39277699,
+ "bech32_prefix": "tb",
+ "cashaddr_prefix": null,
+ "slip44": 1,
+ "segwit": true,
+ "taproot": true,
+ "decred": false,
+ "fork_id": null,
+ "force_bip143": false,
+ "default_fee_b": {
+ "Normal": 10
+ },
+ "dust_limit": 546,
+ "blocktime_seconds": 600,
+ "uri_prefix": "bitcoin",
+ "min_address_length": 27,
+ "max_address_length": 34,
+ "negative_fee": false,
+ "cooldown": 100,
+ "overwintered": false,
+ "extra_data": false,
+ "timestamp": false,
+ "confidential_assets": null
+}
diff --git a/common/defs/bitcoin/bitcoin_signet.png b/common/defs/bitcoin/bitcoin_signet.png
new file mode 100644
index 00000000..7a2399f6
Binary files /dev/null and b/common/defs/bitcoin/bitcoin_signet.png differ
diff --git a/common/defs/support.json b/common/defs/support.json
index bb6edac3..08ad59c7 100644
--- a/common/defs/support.json
+++ b/common/defs/support.json
@@ -30,6 +30,7 @@
"bitcoin:REGTEST": "1.8.2",
"bitcoin:RITO": "1.8.2",
"bitcoin:RVN": "1.7.2",
+ "bitcoin:SIGNET": "1.14.2",
"bitcoin:SMART": "1.7.1",
"bitcoin:SYS": "1.8.4",
"bitcoin:TAZ": "1.8.1",
@@ -145,6 +146,7 @@
"bitcoin:REGTEST": "2.6.1",
"bitcoin:RITO": "2.6.1",
"bitcoin:RVN": "2.6.1",
+ "bitcoin:SIGNET": "2.12.1",
"bitcoin:SMART": "2.6.1",
"bitcoin:SYS": "2.6.1",
"bitcoin:TAZ": "2.6.1",
@@ -270,6 +272,7 @@
"bitcoin:REGTEST": "2.1.1",
"bitcoin:RITO": "2.1.1",
"bitcoin:RVN": "2.0.10",
+ "bitcoin:SIGNET": "2.12.1",
"bitcoin:SMART": "2.0.8",
"bitcoin:SYS": "2.1.8",
"bitcoin:TAZ": "2.1.1",
@@ -385,6 +388,7 @@
"bitcoin:REGTEST": "2.8.1",
"bitcoin:RITO": "2.8.1",
"bitcoin:RVN": "2.8.1",
+ "bitcoin:SIGNET": "2.12.1",
"bitcoin:SMART": "2.8.1",
"bitcoin:SYS": "2.8.1",
"bitcoin:TAZ": "2.8.1",
@@ -505,6 +509,7 @@
"bitcoin:REGTEST": "2.6.1",
"bitcoin:RITO": "2.6.1",
"bitcoin:RVN": "2.6.1",
+ "bitcoin:SIGNET": "2.12.1",
"bitcoin:SMART": "2.6.1",
"bitcoin:SYS": "2.6.1",
"bitcoin:TAZ": "2.6.1",
@@ -625,6 +630,7 @@
"bitcoin:REGTEST": "2.6.1",
"bitcoin:RITO": "2.6.1",
"bitcoin:RVN": "2.6.1",
+ "bitcoin:SIGNET": "2.12.1",
"bitcoin:SMART": "2.6.1",
"bitcoin:SYS": "2.6.1",
"bitcoin:TAZ": "2.6.1",
@@ -746,6 +752,7 @@
"bitcoin:REGTEST": "2.6.1",
"bitcoin:RITO": "2.6.1",
"bitcoin:RVN": "2.6.1",
+ "bitcoin:SIGNET": "2.12.1",
"bitcoin:SMART": "2.6.1",
"bitcoin:SYS": "2.6.1",
"bitcoin:TAZ": "2.6.1",
@@ -867,6 +874,7 @@
"bitcoin:REGTEST": "2.6.1",
"bitcoin:RITO": "2.6.1",
"bitcoin:RVN": "2.6.1",
+ "bitcoin:SIGNET": "2.12.1",
"bitcoin:SMART": "2.6.1",
"bitcoin:SYS": "2.6.1",
"bitcoin:TAZ": "2.6.1",
diff --git a/common/tools/coin_info.py b/common/tools/coin_info.py
index bfa753e6..d3e5c152 100755
--- a/common/tools/coin_info.py
+++ b/common/tools/coin_info.py
@@ -131,7 +131,7 @@ def load_json(*path: str | Path) -> Any:
def get_btc_testnet_status(name: str) -> bool:
- return any((mark in name.lower()) for mark in ("testnet", "regtest"))
+ return any((mark in name.lower()) for mark in ("testnet", "regtest", "signet"))
# ====== CoinsInfo ======
@@ -583,7 +583,7 @@ def fill_blockchain_links(all_coins: CoinsInfo) -> None:
def _btc_sort_key(coin: Coin) -> str:
- if coin["name"] in ("Bitcoin", "Testnet", "Regtest"):
+ if coin["name"] in ("Bitcoin", "Testnet", "Regtest", "Signet"):
return "000000" + coin["name"]
else:
return coin["name"]
diff --git a/common/tools/cointool.py b/common/tools/cointool.py
index 54dbbf96..18dcd7a9 100755
--- a/common/tools/cointool.py
+++ b/common/tools/cointool.py
@@ -899,7 +899,7 @@ def render(
defs["bitcoin"] = [
x
for x in defs["bitcoin"]
- if x["coin_name"] in ("Bitcoin", "Testnet", "Regtest")
+ if x["coin_name"] in ("Bitcoin", "Testnet", "Regtest", "Signet")
]
# munch dicts - make them attribute-accessible
diff --git a/common/tools/maxfee.py b/common/tools/maxfee.py
index 1bcf4685..4999201c 100644
--- a/common/tools/maxfee.py
+++ b/common/tools/maxfee.py
@@ -17,6 +17,7 @@ import marketcap
DEFAULT_SKIP_RE = (
r"^Bitcoin$",
r"^Regtest$",
+ r"^Signet$",
r"Testnet",
)
MAX_DELTA_PERCENT = 25
diff --git a/core/src/apps/bitcoin/common.py b/core/src/apps/bitcoin/common.py
index a0bd8972..b930a2c1 100644
--- a/core/src/apps/bitcoin/common.py
+++ b/core/src/apps/bitcoin/common.py
@@ -21,7 +21,7 @@ else:
IntEnum = object
-BITCOIN_NAMES = ("Bitcoin", "Regtest", "Testnet")
+BITCOIN_NAMES = ("Bitcoin", "Regtest", "Testnet", "Signet")
class SigHashType(IntEnum):
diff --git a/core/src/apps/common/coininfo.py b/core/src/apps/common/coininfo.py
index 53adb113..453852c2 100644
--- a/core/src/apps/common/coininfo.py
+++ b/core/src/apps/common/coininfo.py
@@ -153,6 +153,35 @@ def by_name(name: str) -> CoinInfo:
False, # overwintered
None, # confidential_assets
)
+ if name == "Signet":
+ return CoinInfo(
+ name, # coin_name
+ "SIGNET", # coin_shortcut
+ 8, # decimals
+ 111, # address_type
+ 196, # address_type_p2sh
+ 10000000, # maxfee_kb
+ "Bitcoin Signed Message:\n", # signed_message_header
+ 0x043587cf, # xpub_magic
+ 0x044a5262, # xpub_magic_segwit_p2sh
+ 0x045f1cf6, # xpub_magic_segwit_native
+ 0x024289ef, # xpub_magic_multisig_segwit_p2sh
+ 0x02575483, # xpub_magic_multisig_segwit_native
+ "tb", # bech32_prefix
+ None, # cashaddr_prefix
+ 1, # slip44
+ True, # segwit
+ True, # taproot
+ None, # fork_id
+ False, # force_bip143
+ False, # decred
+ False, # negative_fee
+ 'secp256k1', # curve_name
+ False, # extra_data
+ False, # timestamp
+ False, # overwintered
+ None, # confidential_assets
+ )
if name == "Testnet":
return CoinInfo(
name, # coin_name
@@ -1490,6 +1519,35 @@ def by_name(name: str) -> CoinInfo:
False, # overwintered
None, # confidential_assets
)
+ if name == "Signet":
+ return CoinInfo(
+ name, # coin_name
+ "SIGNET", # coin_shortcut
+ 8, # decimals
+ 111, # address_type
+ 196, # address_type_p2sh
+ 10000000, # maxfee_kb
+ "Bitcoin Signed Message:\n", # signed_message_header
+ 0x043587cf, # xpub_magic
+ 0x044a5262, # xpub_magic_segwit_p2sh
+ 0x045f1cf6, # xpub_magic_segwit_native
+ 0x024289ef, # xpub_magic_multisig_segwit_p2sh
+ 0x02575483, # xpub_magic_multisig_segwit_native
+ "tb", # bech32_prefix
+ None, # cashaddr_prefix
+ 1, # slip44
+ True, # segwit
+ True, # taproot
+ None, # fork_id
+ False, # force_bip143
+ False, # decred
+ False, # negative_fee
+ 'secp256k1', # curve_name
+ False, # extra_data
+ False, # timestamp
+ False, # overwintered
+ None, # confidential_assets
+ )
if name == "Testnet":
return CoinInfo(
name, # coin_name
@@ -3088,6 +3146,35 @@ def by_name(name: str) -> CoinInfo:
False, # overwintered
None, # confidential_assets
)
+ if name == "Signet":
+ return CoinInfo(
+ name, # coin_name
+ "SIGNET", # coin_shortcut
+ 8, # decimals
+ 111, # address_type
+ 196, # address_type_p2sh
+ 10000000, # maxfee_kb
+ "Bitcoin Signed Message:\n", # signed_message_header
+ 0x043587cf, # xpub_magic
+ 0x044a5262, # xpub_magic_segwit_p2sh
+ 0x045f1cf6, # xpub_magic_segwit_native
+ 0x024289ef, # xpub_magic_multisig_segwit_p2sh
+ 0x02575483, # xpub_magic_multisig_segwit_native
+ "tb", # bech32_prefix
+ None, # cashaddr_prefix
+ 1, # slip44
+ True, # segwit
+ True, # taproot
+ None, # fork_id
+ False, # force_bip143
+ False, # decred
+ False, # negative_fee
+ 'secp256k1', # curve_name
+ False, # extra_data
+ False, # timestamp
+ False, # overwintered
+ None, # confidential_assets
+ )
if name == "Testnet":
return CoinInfo(
name, # coin_name
@@ -4425,6 +4512,35 @@ def by_name(name: str) -> CoinInfo:
False, # overwintered
None, # confidential_assets
)
+ if name == "Signet":
+ return CoinInfo(
+ name, # coin_name
+ "SIGNET", # coin_shortcut
+ 8, # decimals
+ 111, # address_type
+ 196, # address_type_p2sh
+ 10000000, # maxfee_kb
+ "Bitcoin Signed Message:\n", # signed_message_header
+ 0x043587cf, # xpub_magic
+ 0x044a5262, # xpub_magic_segwit_p2sh
+ 0x045f1cf6, # xpub_magic_segwit_native
+ 0x024289ef, # xpub_magic_multisig_segwit_p2sh
+ 0x02575483, # xpub_magic_multisig_segwit_native
+ "tb", # bech32_prefix
+ None, # cashaddr_prefix
+ 1, # slip44
+ True, # segwit
+ True, # taproot
+ None, # fork_id
+ False, # force_bip143
+ False, # decred
+ False, # negative_fee
+ 'secp256k1', # curve_name
+ False, # extra_data
+ False, # timestamp
+ False, # overwintered
+ None, # confidential_assets
+ )
if name == "Testnet":
return CoinInfo(
name, # coin_name
@@ -5762,6 +5878,35 @@ def by_name(name: str) -> CoinInfo:
False, # overwintered
None, # confidential_assets
)
+ if name == "Signet":
+ return CoinInfo(
+ name, # coin_name
+ "SIGNET", # coin_shortcut
+ 8, # decimals
+ 111, # address_type
+ 196, # address_type_p2sh
+ 10000000, # maxfee_kb
+ "Bitcoin Signed Message:\n", # signed_message_header
+ 0x043587cf, # xpub_magic
+ 0x044a5262, # xpub_magic_segwit_p2sh
+ 0x045f1cf6, # xpub_magic_segwit_native
+ 0x024289ef, # xpub_magic_multisig_segwit_p2sh
+ 0x02575483, # xpub_magic_multisig_segwit_native
+ "tb", # bech32_prefix
+ None, # cashaddr_prefix
+ 1, # slip44
+ True, # segwit
+ True, # taproot
+ None, # fork_id
+ False, # force_bip143
+ False, # decred
+ False, # negative_fee
+ 'secp256k1', # curve_name
+ False, # extra_data
+ False, # timestamp
+ False, # overwintered
+ None, # confidential_assets
+ )
if name == "Testnet":
return CoinInfo(
name, # coin_name
@@ -7099,6 +7244,35 @@ def by_name(name: str) -> CoinInfo:
False, # overwintered
None, # confidential_assets
)
+ if name == "Signet":
+ return CoinInfo(
+ name, # coin_name
+ "SIGNET", # coin_shortcut
+ 8, # decimals
+ 111, # address_type
+ 196, # address_type_p2sh
+ 10000000, # maxfee_kb
+ "Bitcoin Signed Message:\n", # signed_message_header
+ 0x043587cf, # xpub_magic
+ 0x044a5262, # xpub_magic_segwit_p2sh
+ 0x045f1cf6, # xpub_magic_segwit_native
+ 0x024289ef, # xpub_magic_multisig_segwit_p2sh
+ 0x02575483, # xpub_magic_multisig_segwit_native
+ "tb", # bech32_prefix
+ None, # cashaddr_prefix
+ 1, # slip44
+ True, # segwit
+ True, # taproot
+ None, # fork_id
+ False, # force_bip143
+ False, # decred
+ False, # negative_fee
+ 'secp256k1', # curve_name
+ False, # extra_data
+ False, # timestamp
+ False, # overwintered
+ None, # confidential_assets
+ )
if name == "Testnet":
return CoinInfo(
name, # coin_name
@@ -8436,6 +8610,35 @@ def by_name(name: str) -> CoinInfo:
False, # overwintered
None, # confidential_assets
)
+ if name == "Signet":
+ return CoinInfo(
+ name, # coin_name
+ "SIGNET", # coin_shortcut
+ 8, # decimals
+ 111, # address_type
+ 196, # address_type_p2sh
+ 10000000, # maxfee_kb
+ "Bitcoin Signed Message:\n", # signed_message_header
+ 0x043587cf, # xpub_magic
+ 0x044a5262, # xpub_magic_segwit_p2sh
+ 0x045f1cf6, # xpub_magic_segwit_native
+ 0x024289ef, # xpub_magic_multisig_segwit_p2sh
+ 0x02575483, # xpub_magic_multisig_segwit_native
+ "tb", # bech32_prefix
+ None, # cashaddr_prefix
+ 1, # slip44
+ True, # segwit
+ True, # taproot
+ None, # fork_id
+ False, # force_bip143
+ False, # decred
+ False, # negative_fee
+ 'secp256k1', # curve_name
+ False, # extra_data
+ False, # timestamp
+ False, # overwintered
+ None, # confidential_assets
+ )
if name == "Testnet":
return CoinInfo(
name, # coin_name
diff --git a/core/src/apps/common/coininfo.py.mako b/core/src/apps/common/coininfo.py.mako
index 783e1592..6b3a8284 100644
--- a/core/src/apps/common/coininfo.py.mako
+++ b/core/src/apps/common/coininfo.py.mako
@@ -134,7 +134,7 @@ ATTRIBUTES = (
("confidential_assets", optional_dict),
)
-btc_names = ["Bitcoin", "Testnet", "Regtest"]
+btc_names = ["Bitcoin", "Testnet", "Regtest", "Signet"]
coins = {}
for model in ALL_MODELS:
diff --git a/tools/check-bitcoin-only b/tools/check-bitcoin-only
index 7c0cc7b4..213e06eb 100755
--- a/tools/check-bitcoin-only
+++ b/tools/check-bitcoin-only
@@ -15,8 +15,8 @@ for exception in "${EXCEPTIONS[@]}"; do
GREP_ARGS+=(-e $exception)
done
-# dump all coins except the first 3 (Bitcoin, Testnet, Regtest), exclude names with less than 4 characters
-ALTCOINS=$(./common/tools/cointool.py dump -l -p -t | grep '"name"' | cut -d '"' -f 4 | tail -n +4 | awk 'length($0)>3')
+# dump all coins except the first 4 (Bitcoin, Testnet, Regtest, Signet), exclude names with less than 4 characters
+ALTCOINS=$(./common/tools/cointool.py dump -l -p -t | grep '"name"' | cut -d '"' -f 4 | tail -n +5 | awk 'length($0)>3')
# split on newlines only
OLDIFS=$IFS
IFS="
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.