
До сих пор в этой серии мы разобрали что такое multisig и какой порог выбрать. Обе статьи описывали поведение multisig-кошелька — m из n ключей подписывают, chain проверяет порог, деньги двигаются. Ни одна не говорила много про то, как кошелёк на самом деле собран под капотом. Это та самая статья.
Короткая версия: когда SSP создаёт тебе кошелёк, он не просто генерит два случайных ключа и завершает работу. Он генерит их так, чтобы это следовало документированному стандарту под названием BIP48, чтобы итоговый кошелёк был интероперабельным, восстановимым в софте кроме SSP и предсказуемым при анализе on-chain. Это статья, которая объясняет, что такое BIP48, почему он существует, и почему «этот кошелёк использует BIP48» — одна из самых скучных-и-важных фраз в multisig.
TL;DR
- Путь деривации — это дорога от единственной seed phrase до конкретного ключа (и адреса) в кошельке. Стандартизированные пути вроде BIP44 / BIP48 позволяют разному кошельковому софту прийти к одним и тем же ключам из одного и того же seed.
- BIP48 — это спека специально для multisig-кошельков. Она говорит: вот канонический путь деривации для
mключей, образующих 2-of-3, 3-of-5 и т.д. кошелёк, поверх основных типов выходных скриптов. - SSP использует BIP48. Это значит, что две seed, которые сгенерировал твой SSP-кошелёк, можно использовать из любого другого BIP48-совместимого кошелька (Sparrow, Electrum, descriptors Bitcoin Core) — не только из самого SSP.
- BIP48 чинит проблему, которая была у более ранней multisig-спеки (BIP45): он чисто разделяет ключи для разных типов скриптов (legacy, P2SH-wrapped SegWit, native SegWit, Taproot), чтобы одна seed phrase могла удержать их все без коллизии.
- Тебе не нужно вручную возиться с путями деривации, чтобы пользоваться SSP. Тебе стоит знать, что они есть, чтобы «восстановление кошелька» не казалось магией — и чтобы ты понимал, на что на самом деле отображается твой seed.
30-секундный тур по путям деривации
До того как BIP48 имел какой-либо смысл, нижележащая механика должна была существовать. Эта механика — BIP32: hierarchical deterministic (HD) кошельки. Главная идея — один master-ключ, выведенный из seed phrase, может детерминированно породить бесконечное дерево дочерних ключей. Пройди конкретный путь по дереву — и всегда придёшь к тому же дочернему ключу. Пройди другой — попадёшь в другой.
Пути выглядят так:
m / purpose' / coin_type' / account' / change / index
Например, путь BIP44 m / 44' / 0' / 0' / 0 / 0 достигает первого адреса для приёма первого аккаунта Bitcoin по правилам BIP44. Замени coin_type на 60' и ты в пространстве Ethereum; замени purpose на 84' и ты в пространстве BIP84 (native SegWit); и так далее. Апостроф (') — это hardened-деривация — ребёнка нельзя обратно инвертировать к родителю. Каждый сегмент после master — это 32-битное число, поделённое по конвенции.
Это та часть, которую обычно проскакивают: путь — это метаданные, не секрет. Любой, кто знает твой путь и твой приватный ключ (или extended-ключ), может вывести те же адреса. Путь говорит кошельку куда смотреть. Seed говорит ему что там лежит.
Для дружелюбного освежения, что такое сам seed, пост seed phrase best practices — обязательный.
Что специфицирует BIP48
BIP48 живёт по адресу m / 48' / coin_type' / account' / script_type' / change / index. Интересное добавление — script_type', предпоследний сегмент.
Этот сегмент кодирует, какой тип multisig-выхода обслуживает путь:
0'→ P2SH (legacy multisig)1'→ P2SH-wrapped SegWit (P2WSH-in-P2SH)2'→ native SegWit (P2WSH)3'→ multisig, эквивалентный Taproot (по поправкам к BIP48)
Это важно, потому что на практике один и тот же набор cosigners m-of-n производит разные адреса on-chain в зависимости от того, какой выходной скрипт используется. Без BIP48 один кошелёк мог бы тихо использовать один тип, recovery-софт — предполагать другой, и в результате — два кошелька, которые выглядят, будто должны выводить одни и те же монеты — но не выводят, потому что считают разные адреса.
BIP48 также фиксирует сегмент purpose' равным 48', чтобы multisig-пути не могли столкнуться с single-sig путями BIP44/BIP49/BIP84. Один seed может удерживать single-sig кошелёк под BIP84 и 2-of-2 multisig кошелёк под BIP48, без интерференции. Каждый живёт в собственном поддереве.
Помимо самого пути BIP48 специфицирует, как должны быть упорядочены публичные ключи cosigners («xpubs») при построении multisig-выхода. Каноническое правило — лексикографический порядок публичных ключей перед тем, как они попадут в redeem script. Это снимает неоднозначность — каждый BIP48-совместимый кошелёк, строящий из тех же xpubs, считает тот же адрес. Без этого правила два кошелька могли бы скомбинировать те же ключи в разных порядках и закончить на разных адресах с тем же правилом redeem.
Если хочешь прочесть спеку дословно, она лежит в репо Bitcoin BIPs (bips/bip-0048.mediawiki).
Как SSP использует BIP48 на практике
Когда ты настраиваешь SSP-кошелёк, генерируются две seed phrase — одна в браузерном расширении, одна в мобильном приложении SSP Key. Каждая seed phrase соответствует master-приватному ключу. Из каждого master SSP выводит BIP48-путь для соответствующей сети (Bitcoin, Ethereum, Flux и остальной поддерживаемый SSP набор) при script_type' = 2' (native SegWit на Bitcoin; эквивалентные канонические формы на других сетях, где применимо).
Xpubs обоих подписантов потом обмениваются. Каждая сторона теперь имеет один и тот же набор из двух xpubs, упорядоченных лексикографически по BIP48. Из этой пары каждая сторона независимо считает тот же адрес. Две половины никогда не разделяют приватный ключ — между устройствами движутся только публичные ключи.
Когда ты получаешь деньги, показываемый тебе адрес — это BIP48-выведенный адрес, рассчитанный из обоих xpubs. Когда тратишь, каждое устройство подписывает ту же транзакцию своим собственным приватным ключом. Redeem script on-chain ссылается на оба публичных ключа; сеть проверяет обе подписи. Это весь протокол.
Причина, почему это важно в recovery-сценарии: если бы SSP как продукт исчез завтра, ты всё равно держал бы две BIP48-совместимые seed phrase. Загрузка обоих в Sparrow (или в любой другой кошелёк, способный к multisig, поддерживающий пути BIP48, которые использует SSP) воссоздаёт тот же кошелёк, на тех же адресах, с полной возможностью трат. Кошелёк не живёт внутри SSP — он живёт on-chain, и seed плюс спека BIP48 достаточно, чтобы дотянуться до него откуда угодно.
Это свойство — большая часть того, почему пост self-custody-without-cold-storage трактует 2-of-2 SSP-кошелёк как серьёзный кошелёк, а не как curiosities с custodial-привкусом. Он восстановим из открытых стандартов.
Почему BIP48, а не BIP45 (и не BIP44)
Более ранняя multisig-спека была BIP45. Это была честная первая попытка: m / 45' / cosigner_index' / change / index, где cosigner_index' кодировал, какой именно cosigner ты в кошельке. В ретроспективе у неё было две проблемы.
Во-первых, cosigner_index' запекал порядок в сам путь. Это значило, что порядок, в котором подписанты добавлялись, влиял на деривацию, что делало совместный setup хрупким — перепутаешь порядок — и выведешь не те адреса, что твой cosigner. BIP48 решает это, убирая cosigner-индекс из пути полностью и отдавая это лексикографическому порядку публичных ключей.
Во-вторых, BIP45 не разделял по типу скрипта. Один и тот же путь переиспользовался независимо от того, использовал ли кошелёк legacy P2SH multisig или SegWit-wrapped multisig. Это создавало ту же проблему адресных коллизий-но-не-тех-же-монет, описанную выше.
BIP44, более общая HD-спека, никогда не претендовала покрыть multisig. Попытки перегрузить BIP44 multisig-путями создавали собственные конфликты. BIP48 был явным фиксом: выделенный purpose-номер, явный слот script-type и детерминированный порядок ключей. Сегодня большинство современных multisig-кошельков сходятся на нём; это де-факто стандарт.
Для более глубокой истории, как это связывается со следующей главой multisig — агрегацией Schnorr, где несколько подписей сжимаются в одну — следующая статья этой серии, Schnorr signatures and multisig aggregation, подхватывает нить.
Что это значит для интероперабельности
Самая чистая проверка «действительно ли этот multisig-кошелёк self-custodial?» такая: могу ли я восстановить его без софта кошелька? Если ответ «да» — используя документированные seed, документированный путь деривации и стандартные инструменты — кошелёк действительно твой. Если ответ «нет», у кошелька есть скрытые custodial-элементы.
Соответствие SSP BIP48 — это то, что позволяет нам отвечать да. Seed phrase — BIP39 (стандартный mnemonic), деривация — BIP48, построение адреса — BIP48-каноническое. Любой кошелёк, говорящий на тех же стандартах, может восстановить кошелёк.
Поэтому введение Meet SSP Wallet подаёт SSP как «self-custody с 2-of-2 multisig», а не как управляемый сервис. Стандарты под капотом — это причина, почему такая подача честна.
Что это значит для тебя
Три вывода:
- Тебе не надо запоминать пути, чтобы пользоваться SSP. Число
m/48'/0'/0'/2'/0/0— не то, что нормальный пользователь должен когда-либо вводить. Но знание того, что оно существует, делает «я могу восстановить этот кошелёк без SSP» реальным заявлением вместо маркетингового. - Твои два seed интероперабельны. Если когда-нибудь нужно будет восстановить в multisig-кошелёк третьей стороны, BIP48 плюс твои два BIP39-seed плюс
coin_typeсети — это рецепт. Чек-лист self-custody называет это шагом-репетицией не просто так. - Multisig-кошелёк, который не использует BIP48 (или подобное), стоит сомневаться. Если продукт не может тебе точно сказать, как адреса выводятся из твоих ключей, это не self-custody — это custody с лишними шагами. Соответствие стандартам — это то, что делает заявление «твои ключи, твои монеты» проверяемым.


