Разширени ключове
xpub биткойн е разширен публичен ключ: публичен ключ с chain code, който създава дъщерни ключове. Вижте как се строят xpub и xprv и какви са рисковете.
От Dimitar Zurnov · Обновено на 4 ноември 2026
Адаптирано от Learn Me a Bitcoin на Greg Walker.
xpub е разширен публичен ключ: публичен ключ, свързан с 32-байтов chain code, така че може да създава дъщерни ключове. Разширеният ключ е тази двойка, частна или публична, и е единицата, която HD портфейлът предава надолу по дървото. Разширеният частен ключ, записан xprv, създава както частни, така и публични деца. Разширеният публичен ключ, записан xpub, създава само нормални публични деца.
И двете форми се записват като низ в Base58Check, затова започват с фиксирани префикси и са дълги до 111 знака. Тези низове портфейлите импортират, експортират и споделят.
Какво има в разширения ключ?
Разширеният ключ е 78 байта полета плюс 4-байтова контролна сума. Полетата записват къде стои ключът в дървото, а последното поле съдържа самия ключ.
| Поле | Размер | Какво съдържа |
|---|---|---|
| Версия | 4 байта | Префиксът, например 0488ade4 за xprv |
| Дълбочина | 1 байт | Колко стъпки под главния ключ е ключът. За главния е 0. |
| Отпечатък на родителя | 4 байта | Първите 4 байта от HASH160 на публичния ключ на родителя, или 00000000 за главния |
| Номер на дете | 4 байта | Индексът на този ключ под родителя, или 00000000 за главния |
| Chain code | 32 байта | Тайната, която прави децата непредсказуеми |
| Ключ | 33 байта | Частният ключ с байт 00 отпред, или компресираният публичен ключ |
Частният ключ е 32 байта, така че байтът 00 го прави 33, същата дължина като компресиран публичен ключ. И двете форми се сериализират по един и същ начин.
Отпечатъкът и номерът на дете не влияят на аритметиката. Те само показват мястото на ключа, така че софтуерът да свърже дете с родителя си, без да търси в цялото дърво. Четирибайтовият номер на дете е и причината разширен ключ да има най-много 4,294,967,296 деца.
Кои версийни байтове какво означават?
Версийните байтове казват на софтуера какъв вид е ключът и кой вид портфейл го ползва. Ето най-често срещаните.
| Префикс | Версийни байтове | За какво се ползва |
|---|---|---|
xprv |
0488ade4 |
Разширен частен ключ, BIP 32 |
xpub |
0488b21e |
Разширен публичен ключ, BIP 32 |
yprv |
049d7878 |
Разширен частен ключ, BIP 49 (вложен SegWit) |
ypub |
049d7cb2 |
Разширен публичен ключ, BIP 49 |
zprv |
04b2430c |
Разширен частен ключ, BIP 84 (роден SegWit) |
zpub |
04b24746 |
Разширен публичен ключ, BIP 84 |
Префиксите y и z променят само версийните байтове. Ключът и chain code вътре са от същия вид като при xprv или xpub. Taproot, в BIP 86, няма собствен префикс. Неговите ключове ползват xprv и xpub, а типът скрипт се посочва на друго място. Bitcoin Core ползва output descriptors, за да каже за кой тип скрипт служи даден ключ.
Какъв е главният разширен ключ?
Главният ключ идва направо от сийда. HMAC-SHA512 с ключ Bitcoin seed се разделя на главен частен ключ и chain code, както показва страницата за HD портфейлите. Главният ключ има дълбочина 0, нулев отпечатък и нулев номер на дете.
За тестов вектор 1 на BIP 32 главният разширен частен ключ е:
xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi
Неговият разширен публичен ключ е:
xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8
И двата са публикувани в BIP-а, така че са безопасни за копиране при тестване. Никога не ги ползвайте с монети.
Как се създава нормален дъщерен частен ключ?
Нормалното дете има индекс от 0 до 2,147,483,647. Публичният ключ на родителя се подава в HMAC заедно с индекса. Който има xpub на родителя, може да изчисли тази корекция (tweak), но само частният ключ може да довърши частния ключ на детето. Ето стъпките.
- Вземете компресирания публичен ключ на родителя, 33 байта, и добавете индекса като 4 байта, big-endian.
- Изпълнете HMAC-SHA512 върху тези данни, като за ключ ползвате chain code на родителя.
- Разделете 64-байтовия изход. Лявите 32 байта са
IL, а дясните 32 байта са chain code на детето. - Добавете
ILкъм частния ключ на родителя и редуцирайте сбора по модулn, реда на кривата. Резултатът е частният ключ на детето.
За m/0'/1, детето на първия hardened ключ на тестовия вектор, тези стъпки дават частния ключ 3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368. Публичният му ключ е 03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c.
Как се създава нормален дъщерен публичен ключ?
Публичният път ползва същия IL и същия chain code, но работи върху точки, а не върху числа. Публичният ключ е точката от кривата на своя частен ключ, така че прибавянето на IL към частния ключ означава прибавяне на IL пъти генераторната точка към публичния ключ. Публичният път изчислява IL × G и го прибавя към публичния ключ на родителя. Резултатът е публичният ключ от частния път.
Затова xpub може да създава публични ключове без частния ключ. Кодът по-долу извършва двата пътя и извежда и двата резултата. Те трябва да съвпаднат. Аритметиката е същата като при частния път, но работата се върши от публичния ключ.
import hashlib, hmac, struct
N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 # order of the curve
P = 2**256 - 2**32 - 977
G = (0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798,
0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8)
def add(p, q): # point addition on secp256k1
if p is None: return q
if q is None: return p
if p[0] == q[0] and (p[1] + q[1]) % P == 0: return None
if p == q: s = 3 * p[0] * p[0] * pow(2 * p[1], -1, P) % P
else: s = (q[1] - p[1]) * pow(q[0] - p[0], -1, P) % P
x = (s * s - p[0] - q[0]) % P
return x, (s * (p[0] - x) - p[1]) % P
def mul(k, pt=G): # scalar multiplication
r = None
while k:
if k & 1: r = add(r, pt)
pt = add(pt, pt)
k >>= 1
return r
def compress(pt): # 33-byte compressed public key
return bytes([2 + pt[1] % 2]) + pt[0].to_bytes(32, "big")
def tweak(parent_pub, chain, index):
# IL and the child chain code, from HMAC-SHA512 of the parent public key and index
I = hmac.new(chain, parent_pub + struct.pack(">I", index), hashlib.sha512).digest()
return int.from_bytes(I[:32], "big"), I[32:]
# parent m/0' from BIP 32 test vector 1
parent_priv = 0xedb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea
parent_chain = bytes.fromhex("47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141")
parent_point = mul(parent_priv) # the parent public key
il, child_chain = tweak(compress(parent_point), parent_chain, 1)
child_priv = (il + parent_priv) % N # private route: needs the private key
child_point = add(mul(il), parent_point) # public route: needs only the xpub
print(child_priv.to_bytes(32, "big").hex()) # 3c6cb8d0...
print(compress(child_point).hex()) # 03501e45...
Стартирайте кода, за да получите двете стойности от коментарите. Проверете публичния ключ спрямо частния, преди да разчитате на кода.
Как се създава hardened дете?
Hardened детето има индекс от 2,147,483,648 до 4,294,967,295. Входът му за HMAC ползва частния ключ на родителя, а не публичния. Данните са 00, после 32-байтовият частен ключ, после 4-байтовият индекс, общо 37 байта. Останалото е същото: лявата половина от HMAC се добавя към ключа на родителя, а дясната е chain code.
Първото hardened дете на главния ключ, m/0', е примерът от диаграмата с разположението по-горе. Частният му ключ е edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea, който портфейлът би ползвал за подписване на този клон.
Тъй като входът съдържа частния ключ, никой публичен ключ не може да създаде hardened дете. В това е смисълът на hardened деривацията. Публичният ключ на hardened дете не може да бъде изведен от никого, който има само xpub на родителя.
Каква е слабостта на нормалните деца?
Частният ключ на нормалното дете е частният ключ на родителя плюс стойността IL, която всеки с xpub на родителя може да изчисли. Така че ако някой има xpub на родителя и частния ключ на едно нормално дете, може да извади IL и да възстанови частния ключ на родителя:
parent private key = child private key - IL
Публичният ключ и chain code на родителя, които са в xpub, стигат, за да се изчисли IL при всеки индекс. Така се разкрива родителят и всяко нормално дете под него. Можете да проверите тази стъпка с кода по-горе: (child_priv - il) % N връща parent_priv.
От това следват две правила. Никога не разкривайте частния ключ на нормално дете, докато xpub на родителя е публичен. И ползвайте hardened деца на нивото, където започва акаунтът, за да не стигне изтичане по-долу до ключа на акаунта. Пътищата за деривация показват къде е това ниво.
Разширените ключове адреси ли са?
Не. Думата „адрес“ се появява в менюта на някои портфейли, но xpub не е нещо, на което можете да платите. Той е ключ, който създава много ключове. За да получи монети, портфейлът взема xpub, извежда дете и строи платим адрес от публичния ключ или от скрипта на детето. Страницата за адресите обяснява типовете.
Какво да запомните за разширените ключове?
- Разширеният ключ е ключ плюс chain code, сериализиран в 78 байта и записан в Base58Check.
xprvсъздава частни и публични деца, аxpubсъздава само нормални публични деца.- Префиксите
yиzпроменят само версийните байтове, не начина на деривация. - Частният ключ на нормално дете заедно с xpub на родителя разкрива родителя. Hardened децата предотвратяват това.
Следващо прочетете пътищата за деривация, за да видите как портфейлът записва един ключ в дървото, например m/84'/0'/0'/0/0.
В този раздел: Ключове и адреси
Целият курс „Биткойн от нулата“
Нещо не изглежда наред? Кажете ни