Извлеките script и control block из нужного input
Prevout — непотраченный output, на который ссылается конкретный input. Базовую связь outpoint и value объясняет модель UTXO и сдача, а форматы адресов Bitcoin относятся только к кодированию получателя; здесь критичен raw scriptPubKey. Сначала возьмите исходный witness: только если в нём не меньше двух элементов и первый byte именно последнего элемента равен 0x50, этот последний элемент считается annex и удаляется. Не ищите 0x50 в более ранних элементах. После такой нормализации для script path должны остаться минимум два элемента: предпоследний — tapscript s, последний — control block c; остальные образуют входной stack.
| Часть | Размер | Роль |
|---|---|---|
| c[0] | 1 byte | leaf version в верхних 7 битах и parity output key в младшем бите |
| c[1:33] | 32 bytes | x-only internal public key p |
| c[33:] | 32 × m bytes | Merkle path, где m — от 0 до 128 |
| Весь c | 33 + 32m bytes | Любая другая длина не соответствует control-block rule |
- Часть
- c[0]
- Размер
- 1 byte
- Роль
- leaf version в верхних 7 битах и parity output key в младшем бите
- Часть
- c[1:33]
- Размер
- 32 bytes
- Роль
- x-only internal public key p
- Часть
- c[33:]
- Размер
- 32 × m bytes
- Роль
- Merkle path, где m — от 0 до 128
- Часть
- Весь c
- Размер
- 33 + 32m bytes
- Роль
- Любая другая длина не соответствует control-block rule
Пересчитайте commitment без направлений left/right
Получите leaf version v = c[0] & 0xfe. Начальный k — tagged hash TapLeaf от v, CompactSize длины tapscript и точных bytes s. Затем для каждого 32-byte элемента e из control block вычисляйте TapBranch от пары min(k,e) || max(k,e) в лексикографическом byte order. Нельзя менять script encoding, декомпилировать opcodes заново или добавлять left/right bits: их нет в доказательстве.
Контрольный расчёт
- 1Привяжите input
Сохраните raw spending transaction, input index, outpoint и raw prevout scriptPubKey.
- 2Нормализуйте witness
Удалите только последний элемент и только при двух условиях вместе: witness содержит минимум два элемента, а last[0] = 0x50. После этого выделите предпоследний tapscript и последний control block.
- 3Разберите c
Проверьте длину, получите parity bit, even leaf version, internal key и path cartridges по 32 bytes.
- 4Вычислите leaf
Используйте tagged hash TapLeaf и CompactSize фактической byte-length script, а не число opcodes.
- 5Сверните path
На каждом шаге сортируйте два 32-byte hash лексикографически и применяйте tagged hash TapBranch.
- 6Сверьте output
Вычислите tweak, точку Q, x-only key и Y parity; сравните их с q prevout и c[0].
Internal key и Merkle root должны дать exact output key
Интерпретируйте p через BIP-340 lift_x; невалидная точка останавливает проверку. Затем t = tagged hash TapTweak(p || MerkleRoot) рассматривают как число и отвергают, если оно не меньше порядка secp256k1. Вычислите Q = P + tG. Успех commitment требует одновременно x(Q) = q из exact prevout и y(Q) mod 2 = c[0] & 1.
| Где расходится | Частая причина | Что делать |
|---|---|---|
| Control-block length | Обрезан witness либо annex не удалён по точному last[0] = 0x50 rule | Снова декодировать исходный witness и только затем выбрать последний element |
| TapLeaf | Изменён script byte, leaf version или CompactSize | Сравнить raw hex без reassembly |
| TapBranch | Неверная byte order или path другого leaf | Логировать k/e до каждого tagged hash |
| Tweak/output key | Не тот internal key, prevout или сеть | Сверить outpoint и 32-byte witness program |
| Parity | Потерян low bit c[0] | Сравнить Y parity Q, не только x-only key |
- Где расходится
- Control-block length
- Частая причина
- Обрезан witness либо annex не удалён по точному last[0] = 0x50 rule
- Что делать
- Снова декодировать исходный witness и только затем выбрать последний element
- Где расходится
- TapLeaf
- Частая причина
- Изменён script byte, leaf version или CompactSize
- Что делать
- Сравнить raw hex без reassembly
- Где расходится
- TapBranch
- Частая причина
- Неверная byte order или path другого leaf
- Что делать
- Логировать k/e до каждого tagged hash
- Где расходится
- Tweak/output key
- Частая причина
- Не тот internal key, prevout или сеть
- Что делать
- Сверить outpoint и 32-byte witness program
- Где расходится
- Parity
- Частая причина
- Потерян low bit c[0]
- Что делать
- Сравнить Y parity Q, не только x-only key
Не подменяйте эту задачу доказательством BIP-322: оно отвечает на вопрос о контроле адреса. Также вынесите nLockTime, CLTV и CSV в отдельную проверку — timelock может находиться внутри совпавшего tapscript, но не влияет на вычисление commitment. При mismatch не подписывайте и не broadcast: сохраните raw prevout, witness и промежуточные hashes, запросите корректный control block у создателя policy/PSBT и повторите расчёт второй реализацией.
Stop-сигналы
- есть tapscript/control block, но неизвестны exact input и prevout scriptPubKey;
- hex script пересобрали из ассемблерного текста и считают тем же byte sequence;
- Merkle siblings складывают по визуальному left/right вместо лексикографической сортировки;
- сравнили только x(Q), но проигнорировали parity bit;
- commitment match выдают за успешное script execution или готовность spend;
- annex удаляют без двух условий BIP-341 или BIP-342 применяют к leaf version не 0xc0;
- для публичного пересчёта требуют private key или seed.
Источники
Мы используем прямые ссылки и фиксируем дату проверки. Полный текст чужих материалов не перепечатывается.
- BIP-341 — Taproot consensus rules Bitcoin BIPs · Проверено 24 августа 2026 г. в 09:25 GMT+5
- BIP-342 — Validation of Taproot Scripts Bitcoin BIPs · Проверено 24 августа 2026 г. в 09:25 GMT+5
- BIP-340 — Schnorr signatures for secp256k1 Bitcoin BIPs · Проверено 24 августа 2026 г. в 09:25 GMT+5
- Bitcoin Core — Taproot interpreter implementation Bitcoin Core · Проверено 24 августа 2026 г. в 09:25 GMT+5
