- Подписи Шнорра для биткоин-транзакций. Как работает протокол Шнорра в Bitcoin Cash?
- Что такое подписи Шнорра?
- Подписи Шнорра уменьшают размер блока
- Подписи Шнорра улучшают анонимность транзакций
- Почему подписи Шнорра появились именно в Bitcoin Cash, а не в Bitcoin?
- Идеологическая подоплека подписей Шнорра
- Что такое signature bitcoin
- Blockchain на Go. Часть 5: Адреса
- Вступление
- Биткоин-адрес
- Криптосистема с открытым ключом
- Электронная цифровая подпись
- Эллиптическая криптография
- Base58
- Реализация адресов
- Реализация подписей
- Заключение
Подписи Шнорра для биткоин-транзакций. Как работает протокол Шнорра в Bitcoin Cash?
Вокруг Bitcoin Cash (BCH) много разговоров касательно улучшения, называемого «подписями Шнорра». Мы собрали все самые важные особенности и выгоды этого протокола в одной статье и описали их на понятном широкому кругу лиц языке, без сложных терминов и недосказанностей, которыми пестрят существующие на данный момент статьи по подписям Шнорра, представленные в русскоязычном сегменте Интернета.
Навигация по материалу:
Что такое подписи Шнорра?
Подписями Шнорра называют улучшение, которое добавляет новый формат подписи транзакций в Bitcoin Cash (в будущем и в другие криптовалюты). Как известно, каждая транзакция подписывается при помощи приватного ключа, что означает добавление особой метки в качестве доказательства личности подписавшего. Можно сравнить это с гербовой сургучной печатью на старых письмах.
Если у вас есть криптовалютный кошелек, вы воспринимаете его как обычный кожаный кошелек, в котором криптовалюты лежат как бумажные купюры. На самом же деле, правильнее называть криптовалютный кошелек «связкой ключей», а не «кошельком». Слово wallet, которое прочно засело в подсознание масс, не отражает истинной сути и функций подобного софта. «Связка ключей» – вот правильный образ, помогающий сформировать правильное представление.
Для подписи любой транзакции нужна авторизация. Или по другому, нужно взять правильный ключ из «связки ключей» и использовать его для открытия монет, лежащих на том или ином адресе.
Во время транзакции, кошельком (или «связкой») используется один из приватных ключей пользователя, чтобы подписать ее. Каждый адрес BCH содержит свой приватный ключ, отличающийся от приватных ключей других адресов BCH.
Таким образом, если у вас есть приватный ключ от конкретного адреса с монетами, вы можете потратить эти активы, «подписав» транзакцию приватным ключом. В большинстве кошельков процедура подписи заключается в вводе пользователем пароля, подпись же совершается кошельком автоматически.
В рамках протокола Bitcoin (BTC) используются стандартные подписи из стека криптографических протоколов, используемых в военной промышленности, связи, передаче данных по сетям и т.п. Эти подписи зарекомендовали себя как хорошее средство защиты монет, но они не идеальны.
Подписи Шнорра уменьшают размер блока
До недавнего времени, подпись транзакций в сети Bitcoin Cash осуществлялась при помощи стандарта ECDSA, который подразумевает, что каждая подпись равна около 70 байт. Тот же стандарт использует и Bitcoin, а еще – целая куча различных форков вроде Bitcoin Gold, Bitcoin Diamond, Bitcoin Private и так далее. Большинство из этих форков не имеют особого значения для развития индустрии и используются исключительно для рыночной спекуляции. Но это тема для отдельной статьи.
Подпись Шнорра поднимает процесс использования «ключей» на новый уровень.
- Во первых, она занимает лишь 64 байта, когда попадает в блок, что уменьшает занимаемое транзакциями место на 4%. Так как транзакции с подписью Шнорра имеют одинаковый размер, это делает возможным предварительный подсчет общего размера той части блока, что содержит именно такие подписи. А предварительный подсчет размера блока – ключ к его безопасному увеличению в будущем, вне зависимости от того, в какой криптовалюте это применяется.
- Во-вторых, экономится пространство в транзакциях мультиподписи. Мультиподпись – это когда ваш криптовалютный кошелек отправляет транзакцию, для успешного подтверждения которой необходимы несколько «подписей-ключей» (возможно, от нескольких людей), а не только ваша. Эти подписи берутся либо от ваших нескольких собственных адресов отправки. Либо из адресов нескольких людей, участвующих в транзакции. Ранее, транзакция собирала подписи с каждого человека (или с каждого отдельного вашего адреса) по отдельности.
Но если в транзакции задействовать подпись Шнорра, тогда множество подписей от разных лиц объединяется в одну общую «мета-подпись». Бесспорно, одна подпись это меньше чем пять или десять.
Таким образом, значительно уменьшается место, занимаемое подписями в блоке и соответственно блокчейне. Разработчики Bitcoin Cash Омари Сеше и Марк Лундеберг уверены, что при помощи подписей Шнорра можно будет сэкономить 20-25% пространства блока. Такая экономия могла бы быть достигнута и в Bitcoin, если бы подписи Шнорра внедрили еще в 2017 году, когда об этом задумался видный разработчик, Люк Джуниор. Но с тех пор ничего не поменялось, в Bitcoin все еще нет этого стандарта, несмотря на многочисленные обещания.
Подписи Шнорра улучшают анонимность транзакций
Новый тип подписей позволит не только экономить место, но и изменять видимые данные отправителей и получателей: приватный и публичный ключи отправителя или получателя теперь можно умножить на 2, без потери их функционала.
Это изменит их внешний вид, и стороннему наблюдателю не будет известно, какой именно ключ использовался для подписи транзакции – обычный или модифицированный. При этом, пользователь полностью сохраняет за собой право владения и сможет отправлять монеты «по-старинке».
Также становятся доступными к исполнению так называемые «кольцевые подписи», улучшающие приватность. Такие подписи – криптографический инструмент, позволяющий любому человеку или группе людей присоединиться к сету пользователей, затем подписать транзакцию без необходимости раскрывать публике, кто именно из данного сета людей/ботов сделал это, и отправить ее в сеть.
В будущем, можно будет изобретать дополнительные способы использования таких транзакций, но уже сейчас они позволят значительно затруднить отслеживание со стороны хакеров и злоумышленников, пытающихся идентифицировать вас с вашими активами BCH.
Почему подписи Шнорра появились именно в Bitcoin Cash, а не в Bitcoin?
Изначально, продвижение этой идеи вели несколько разработчиков из лагеря Bitcoin Core, такие как Люк Дэш Джуниор, Крис Бельчер и так далее. Кроме них, идеей заинтересовался Омари Сеше, ведущий разработчик Bitcoin Cash клиента «Bitcoin ABC», а также его коллега из лагеря BCH, программист Марк Лундеберг. С 2017 года, в каждом из «лагерей» было как минимум по два заинтересованных программиста. Оба лагеря обещали внедрение подписей Шнорра, так как они являются важной частью развития децентрализованных протоколов.
Но почему разработчики сети Bitcoin Cash справились с задачей внедрения первыми? Несмотря на то, что многие ждали этого от Bitcoin Core, как от более старой и опытной команды программистов.
За последние два года в репозиторий Bitcoin Core были внесены существенные изменения. Но ни одно не касается дальнейшей анонимизации транзакций, точно как и расширения транзакционной способности. Причиной может стать тот факт, что существенные ресурсы Core сейчас направлены на создание и продвижение сторонних решений анонимизации и масштабирования, таких как Liquid, SegWit или Lightning. Занятно, что все эти протоколы до сих пор содержат огромное количество мелких недоработок.
Вполне возможно, что это также связано с неофициальной позицией лидеров мнений в лагере Core. А позиция эта такова, что биткоин уже «перерос» стадию цифровой наличности, и должен восприниматься людьми как «цифровое золото». А золото, как известно, это не наличность. Это неповоротливый актив с низкой степенью использования в качестве средства оплаты.
Средняя комиссия в сети биткоина, время подтверждения транзакций, периодически увеличиваются, что делает первую криптовалюту неудобной в повседневных расчетах. Никогда нельзя угадать, «за сколько часов» подтвердится одна транзакция. Кроме того, в последние месяцы транзакции с низкой комиссией висят по четыре дня без подтверждений, так что использовать биткоин в качестве наличных средств для повседневных расчетов для большинства пользователей было бы слишком неудобным и дорогим занятием.
Идеологическая подоплека подписей Шнорра
Большое количество криптовалютных бирж и онлайн-кошельков стали собирать личные данные пользователей. Они сохраняют в своих базах данных все биткоин-адреса, привязанные к той или иной онлайн личности. Они отслеживают пользователей при помощи cookie-файлов и других технологий, таким образом, изначально анонимная природа криптовалют ставится под существенную угрозу.
Ряд фирм (вроде Chainalysis и Crystal) уже создали комплексный софт для отслеживания транзакций пользователей и ранжирования адресов по уровню «законности» биткоинов на них. Подписи Шнорра помогут вернуть достойный уровень приватности в Bitcoin Cash в тот момент, когда разработчики Bitcoin Core «отвисают в джакузи» и готовятся латать очередные баги своего коммерческого продукта SegWit.
Да, это коммерческий продукт, ведь биржи должны платить разработчикам за консультации по его внедрению. Ничего в этом мире не бывает бесплатно, не стоит верить в идеологию «невиданной щедрости во имя спасения человечества», которой любят прикрываться некоторые из основных участников и мастодонтов разработки BTC.
Дата публикации 14.07.2019
Поделитесь этим материалом в социальных сетях и оставьте свое мнение в комментариях ниже.
Источник
Что такое signature bitcoin
Schnorr Blinded Custody
Note: the previous version of this paper proposes an unsafe protocol for ECDSA from 2014. You can find it here: BitcoinBlindSignatures2014.md.
Protect personal wallet by outsourcing signing to multiple trusted parties, while hiding the public key, signature and the message from them.
Most blind signature protocols focus on making signatures unidentifiable for a given public key, but do not protect public key itself. This is a problem for cryptocurrency transactions where the public key is either unique (one-time keys in Bitcoin) or identifies user’s account (Ethereum, Stellar).
The following protocol uses each party as a «trusted custodian», while keeping them unaware about the published transaction, where both the signature and the public key are not linked to the signer’s data. The only job of a custodian is to correctly authenticate the user and deny signatures to imposters.
The scheme produces signatures compatible with Ed25519 (used in Stellar and some other protocols) and BIP340 (Schnorr signatures proposal for Bitcoin).
Principal is the user holding funds who outsources control to multiple agents (with m-of-n multisig).
Agent is a user providing signing service to the principal.
Together, principal and agent perform the role of a signer in the Schnorr signature protocol
Protocol 1: key generation
Agent generates a key pair x, X = x·G and sends X to Principal. G is a common base point.
Principal chooses a blinding factor b as a uniformly random scalar.
Principal computes the public verification key X’ = X + b·G and uses it for locking funds on a blockchain.
Protocol 2: signing
Principal authenticates itself to its Agent to initiate a signature protocol.
Agent chooses a random nonce scalar r and sends commitment R = r·G to the principal.
Principal chooses two random blinding factors p and q and generates the blinded nonce commitment R’ = p·R + q .
Principal sends blinded nonce commitment to the Verifier who responds with the challenge c’ (in a non-interactive scheme, it is a hash of the protocol transcript).
Principal reverse-blinds challenge c’ with previously generated blinding factor p to produce Agent’s challenge c = p^-1·c’ .
Principal sends reverse-blinded challenge c to Agent.
Agent computes the Schnorr signature s = r + c·x and returns s to Principal.
Principal blinds s as follows: s’ = p·s + q + c’·b .
Now the signature (s’,R’) is a valid Schnorr signature for challenge c’ and verification key X’ :
The blinding factor b can be generated through a scheme similar to BIP32. The agent generates a single public key X , while the principal generates unique b for each «address» they need to send funds to.
Blinding factors p and q could be generated through the similar procedure as agent’s nonce r : a mix of deterministic (based on transcript and blinding factor b ) and auxiliary randomness.
Compatibility with MuSig and threshold signing
TBD: present how MuSig must be adjusted to permit reconstruction of the blinded multikey, where the Principal acts like a Dealer, coordinating the protocol between multiple Agents.
What blinding factors do we need?
Suppose we blind X with two factors a, b . Which factors could we omit, and would it be safe to do so?
Seems to be ok, but not compatible with BIP32 derivation.
Insecure: can learn a/p = c/c’ , then mult it by s’ and get a·s , where a = (c/c’)*s’/s . If a matches, tx is deanonymized.
Insecure: can compute a out of c/c’ and match against X’.
Can compute candidate p as c’/c , but R’ is still protected by q·G , where q is protected by ECDLP.
Seems to be ok. Nice thing is — additive blinding is compatible with BIP32.
In this case c == c’ which identifies the transaction.
Tx is identified by matching (c’/c)R with R’ .
Источник
Blockchain на Go. Часть 5: Адреса
Вступление
В предыдущей статье мы начали реализацию транзакций, а также ознакомились с принципом ее работы: нет учетных записей, личные данные (например, имя или серия и номер паспорта) не требуются и не хранятся нигде в Bitcoin. Но все же должно быть что-то, что идентифицирует вас как владельца выходов транзакции (т. е. владельца монет, заблокированных на выходах). И это то, для чего нужны адреса в Bitcoin. До сих пор мы использовали произвольные строки в качестве адресов, теперь пришло время реализовать реальные адреса, таким образом, каким они реализованы в Bitcoin.
В этой части мы изменим очень много кода, поэтому я не вижу смысла объяснять все подробно. Посетите эту страницу, чтобы увидеть все изменения, по сравнению с прошлой статьей.
Биткоин-адрес
Вот пример Bitcoin-адреса: 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa. Это самый первый Bitcoin-адрес, который якобы принадлежит Сатоши Накамото. Bitcoin-адреса находятся в открытом доступе. Если вы захотите отправить кому-то монеты, вам нужно знать адрес получателя. Но адреса (несмотря на уникальность) не являются идентификатором вас, как владельца «кошелька». Фактически, такие адреса являются открытым ключом. В Bitcoin ваша личность — это пара (или пары) закрытых и открытых ключей, хранящихся на вашем компьютере (или в каком-либо другом месте, к которому у вас есть доступ). Для создания таких ключей используются криптографические алгоритмы, которые гарантируют, что никто другой не сможет получить доступ к вашим монетам без физического доступа к вашим ключам. Давайте рассмотрим, что же это за алгоритмы.
Криптосистема с открытым ключом
Алгоритмы криптосистем с открытым ключом используют пары ключей: открытые и закрытые. Открытые ключи можно сообщить кому угодно. Закрытые ключи, напротив, не должны раскрываться никому: никто, кроме владельца, не должен иметь к ним доступа, поскольку это личные ключи, которые служат идентификатором владельца. Ваше лицо — это ваши закрытые ключи (в мире криптовалюты, конечно).
По сути, Bitcoin-кошелек — это всего лишь пара таких ключей. Когда вы устанавливаете приложение кошелька или используете Bitcoin клиент для создания нового адреса, для вас генерируется пара ключей. Тот, кто контролирует закрытый ключ, контролирует все монеты, которые были на него отправлены.
Закрытые и открытые ключи — это просто случайные последовательности байтов, поэтому они не могут быть напечатаны на экране и прочитаны человеком. Вот почему Bitcoin использует алгоритм для преобразования открытых ключей в удобочитаемую строку.
Если вы когда-нибудь использовали Bitcoin кошелек в виде приложения, вероятно, для вас была создана мнемоническая фраза. Такие фразы используются вместо закрытых ключей и могут быть использованы для их генерации. Этот механизм реализован в BIP-039.
Итак, теперь мы знаем, что идентифицирует пользователей в Bitcoin. Но как Bitcoin проверяет владельца выхода транзакции (и монеты, которые там хранятся)?
Электронная цифровая подпись
В математике и криптографии существует концепция электронной цифровой подписи — алгоритмы, которые гарантируют:
- что данные не были изменены при передаче от отправителя к получателю;
- что данные были созданы определенным отправителем;
- что отправитель не может отрицать то, что именно он отправил эти данные.
Применяя алгоритм электронной цифровой подписи к данным (т. е. подписывая данные), получается подпись, которую впоследствии можно будет проверить. Подпись данных происходит с использованием закрытого ключа, а для проверки требуется открытый ключ.
Чтобы подписать данные, нам понадобится следующее:
- данные для подписи;
- закрытый ключ.
Алгоритм создает подпись, которая хранится во входах транзакции. Чтобы проверить подпись, необходимо следующее:
- данные, которые были подписаны;
- подпись;
- открытый ключ.
Говоря простыми словами, процесс проверки может быть описан так: нам надо убедиться, что подпись получена из этих данных с помощью закрытого ключа, который использовался для генерации открытого ключа.
Цифровые подписи не шифруются, а данные получить из нее невозможно. Это похоже на хеширование: вы преобразуете данные при помощи алгоритма и получаете их уникальное представление. Разница между хешем и подписью — это пары ключей, которые позволяют произвести проверку последней.
Но такие пары ключей также можно использовать и для шифрования данных: для шифрования используется закрытый ключ, а для расшифровки — открытый. Однако же Bitcoin не использует алгоритмы шифрования.
Каждый вход транзакции в Bitcoin подписывается тем, кто создал эту транзакцию. Каждая транзакция в Bitcoin должна быть проверена перед тем, как поместить ее в блок. Верификация означает (помимо других процедур):
- Проверку того, что входы имеют достаточные права на использование выходов из предыдущих транзакций.
- Проверку правильности подписи транзакции.
Схематически, процесс подписи и проверки данных выглядит так:
Давайте рассмотрим полный жизненный цикл транзакции:
- В самом начале содержится блок генезиса с coinbase транзакцией. В транзакциях coinbase нет реальных входов, поэтому подпись не требуется. Вывод транзакции содержит хешированный открытый ключ (используются алгоритмы RIPEMD16(SHA256(PubKey)) ).
- Когда кто-то отправляет монеты, создается транзакция. Входы транзакции будут ссылаться на выходы из предыдущих транзакций. Каждый вход будет хранить открытый ключ (не хешированный) и подпись всей транзакции.
- Другие узлы в сети Bitcoin, которые получат транзакцию, тоже проверят ее. Помимо прочего, здесь происходит сопоставление хеша открытого ключа на входе транзакции с хешом соответствующего выхода, (это гарантирует, что отправитель тратит только принадлежащие ему монеты); подпись правильная (это гарантирует, что транзакция создана реальным владельцем монет).
- Когда узел готов к майнингу нового блока, он поместит транзакцию в блок и начнет добывать ее.
- Когда блок добыт, каждый другой узел в сети получает сообщение о том, что блок добыли и добавляет его в цепь.
- После того, как блок добавлен в цепь, транзакция завершена, теперь на ее выходы можно ссылаться в новых транзакциях.
Эллиптическая криптография
Как мы уже с вами говорили, открытые и закрытые ключи представляют собой последовательности случайных байтов. Мы не хотим генерировать закрытый ключ, принадлежащий кому-то другому, поэтому возникает необходимость в особом алгоритме для генерации последовательностей.
Bitcoin использует эллиптические кривые для генерации секретных ключей. Эллиптические кривые — это сложная математическая концепция, которую мы не будем здесь подробно объяснять (если интересно, можете почитать об этом здесь ПРЕДУПРЕЖДЕНИЕ: очень много математики!). Кривая, используемая Bitcoin, может случайным образом выбирать число между 0 и 2²⁵⁶ (что составляет приблизительно 10⁷⁷, на заметку, атомов в видимой вселенной где-то между 10⁷⁸ и 10⁸²). Такой предел означает, что почти невозможно сгенерировать один и тот же закрытый ключ дважды.
Кроме того, Bitcoin использует (и мы будем) алгоритм ECDSA для подписи транзакций.
Base58
Теперь давайте вернемся к вышеупомянутому адресу 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa. Теперь мы знаем, что это общепринятое для человека представление открытого ключа. И если мы его декодируем, он будет выглядеть примерно так (как последовательность байтов, записанных в шестнадцатеричной системе):
Bitcoin использует алгоритм Base58 для преобразования открытых ключей в читаемый человеком формат. Алгоритм очень похож на известный Base64, но он использует более короткий алфавит: некоторые буквы были удалены из алфавита, чтобы избежать гомографические атаки. В связи с этим, в этом алфавите отсутствуют следующие символы: 0 (ноль), О (заглавная буква «о»), I (заглавная «i»), l (строчная «L») а также знаки «+» и «/».
Примерно так выглядит процесс получения адреса из открытого ключа:
Следуя этой схеме, ключ, который мы привели выше, разделен на три части:
Хорошо, теперь, когда мы собрали все воедино, пришло время писать код! Я надеюсь, что сейчас все, что было непонятным прояснится.
Реализация адресов
Начнем со структуры кошелька Wallet
Кошелек — не что иное, как пара ключей. Нам также понадобится тип Wallets , чтобы хранить коллекцию кошельков, сохранять их в файл и выгружать их из него. В конструкторе Wallet создается новая пара ключей. Функция newKeyPair проста, здесь мы используем ECDSA. Затем создается закрытый ключ с использованием кривой, и открытый ключ генерируется при помощи закрытого ключа. Одно замечание: в алгоритмах на основе эллиптической кривой открытые ключи являются точками на кривой. Таким образом, открытый ключ представляет собой комбинацию координат X, Y. В Bitcoin эти координаты объединяются и образуют открытый ключ.
Теперь, создадим функцию генерации адреса:
Разберем по шагам преобразование открытого ключа в адрес Base58:
- Возьмем открытый ключ и запишем его дважды с помощью алгоритмов хеширования RIPEMD160 (SHA256 (PubKey)) .
- Подготовим версию.
- Вычислим контрольную сумму путем хеширования результата из шага 2 и SHA256 (SHA256 (payload)) . Контрольная сумма — это первые четыре байта полученного хеша.
- Добавим контрольную сумму в комбинацию version+PubKeyHash .
- Зашифруем комбинацию version+PubKeyHash+checksum при помощи Base58.
В результате вы получите настоящий адрес Bitcoin, вы можете даже проверить его баланс на blockchain.info. Но я больше чем уверен, что на счету этого адреса ничего не будет. Вот почему выбор правильного алгоритма шифрования с открытым ключом настолько важен: учитывая, что закрытые ключи являются случайными числами, вероятность генерации одного и того же числа должна быть как можно меньше. В идеале он не должен повторятся вообще.
Обратите внимание, что вам не нужно подключаться к узлу Bitcoin для получения адреса. Алгоритм генерации адресов использует комбинацию алгоритмов, которые уже реализованы во многих стандартных библиотеках популярных языков программирования.
Теперь нам нужно изменить входы и выходы для использования адресов:
Обратите внимание, что мы больше не используем поля ScriptPubKey и ScriptSig , вместо этого ScriptSig разделяется на поля Signature и PubKey , а ScriptPubKey переименован в PubKeyHash . Мы будем реализовывать те же функции блокировки/разблокировки выходов и логику подписей входов, как в Bitcoin, но реализуем мы это при помощи методов.
Метод UsesKey проверяет, что вход использует определенный ключ для разблокировки выхода. Обратите внимание, что входы хранят нехешированные открытые ключи, а функция принимает хешированный. IsLockedWithKey проверяет, был ли использован хеш-ключ открытого ключа для блокировки выхода. Это дополнительная функция для UsesKey , и они обе используются в FindUnspentTransactions для построения соединений между транзакциями.
Lock просто блокирует выход. Когда мы отправляем монеты кому-то, нам известен только адрес, поэтому функция принимает адрес как единственный аргумент. Затем адрес декодируется, а хеш-ключ открытого ключа извлекается из него и сохраняется в поле PubKeyHash .
Теперь давайте проверим, что все работает правильно:
Отлично! Пришла пора реализовать подписи транзакций.
Реализация подписей
Транзакции необходимо подписывать, так как это единственный способ гарантии в Bitcoin надежности транзакций. Если подпись недействительна, транзакция считается недействительной и, следовательно, не может быть добавлена в цепочку.
У нас есть все для реализации подписей к транзакциям, кроме одного: данных для подписи. Какую часть транзакции мы должны подписывать? Или же необходимо подписывать сделку в целом? Выбор данных для подписи очень важен. Дело в том, что данные, которые должны быть подписаны, должны содержать информацию, которая идентифицирует данные уникальным образом. Например, нет смысла подписывать только выходные значения, потому что такая подпись не будет учитывать отправителя и получателя.
Учитывая, что транзакции разблокируют предыдущие выходы, перераспределяют их значения и блокируют новые выходы, должны быть подписаны следующие данные:
- Хеши открытых ключей хранящиеся в разблокированных выходах. Это идентифицирует «отправителя» транзакции.
- Хеши открытых ключей хранящиеся в новых, заблокированных, выходах. Это идентифицирует «получателя» транзакции.
- Значения новых выходов.
В Bitcoin логика блокировки/разблокировки хранится в скриптах, которые хранятся в ScriptSig и ScriptPubKey полей входов и выходов соответственно. Поскольку Bitcoin допускает разные типы таких скриптов, он подписывает все содержимое ScriptPubKey .
В связи с этим в Bitcoin происходит подпись не транзакции, а ее обработанной копии со входами, содержащими ScriptPubKey указанного выхода
Здесь описан подробный процесс обработки копии транзакции. Скорее всего, он устарел, но мне не удалось найти более надежный источник информации.
Все это выглядит достаточно сложным, давайте начнем писать код. А начнем мы с метода Sign :
Метод принимает закрытый ключ и ассоциативный массив предыдущих транзакций. Как уже упоминалось выше, для подписания транзакции нам необходимо получить доступ к выходам, указанным во входах транзакции, поэтому нам нужны транзакции, которые хранят эти выходы.
Давайте внимательнее рассмотрим этот метод:
Coinbase транзакции не подписаны, так как в них нет реальных выходов
Мы подписываем обработанную копию, а не всю транзакцию:
Копия будет включать все входы и выходы, а TXInput.Signature и TXInput.PubKey будут равны nil.
Затем пройдемся по каждому входу в копии:
На каждом входе Signature устанавливается на nil (просто двойная проверка), а PubKey присваиваем ссылку на выход в PubKeyHash . В настоящий момент все транзакции, кроме текущей, являются «пустыми», то есть поля подписи и PubKey равны нулю. Таким образом, входы подписываются отдельно, хотя это необязательно для нашего приложения, но Bitcoin позволяет транзакциям содержать входы, ссылающиеся на различные адреса.
Метод Hash сериализует транзакцию и хеширует ее с помощью алгоритма SHA-256. Результатом являются данные готовые для подписи. После получения хеша мы должны сбросить поле PubKey , чтобы не было влияния на наши дальнейшие итерации.
Мы подписываем txCopy.ID при помощи privKey . Подпись ECDSA представляет собой пару чисел, которые мы объединяем и сохраняем в поле входа Signature .
Рассмотрим функцию верификации:
Метод довольно простой. Для начала получим копию транзакции, как в прошлом методе:
Затем нам понадобится кривая, которая используется для генерации пар ключей:
Затем пройдемся по всем входам и проверим, что они подписаны:
Эта часть идентична той, что используется в методе Sign, так как во время проверки нам нужны те же самые данные, что мы и подписывали
Здесь мы распаковываем значения, хранящиеся в TXInput.Signature и TXInput.PubKey , так как сигнатура представляет собой пару чисел, а открытый ключ — это пара координат. Мы конкатенировали их раньше для хранения, и теперь нам нужно их распаковать для использования в функциях crypto/ecdsa .
Теперь мы создаем ecdsa.PublicKey , используя открытый ключ, который мы берем из входа, и выполняем ecdsa.Verify , передавая подпись, из входа. Если все входы проверены, мы возвращаем true; если хотя бы один вход не прошел проверку, возвращаем false.
Теперь нам нужна функция для получения предыдущих транзакций. Поскольку для этого требуется взаимодействие со всей цепью, мы сделаем его методом Blockchain :
FindTransaction находит транзакцию по идентификатору (для этого требуется итерация по всем блокам в цепи); SignTransaction берет одну транзакцию, находит транзакции, на которые она ссылается, и подписывает ее; VerifyTransaction просто проверяет транзакцию.
Теперь нам нужно подписать и проверить транзакции. Подписывать мы будем в методе NewUTXOTransaction :
Проверка транзакции происходит до того, как она будет добавлена в блок:
Вот и все! Давайте проверим все еще раз:
У нас даже ничего не сломалось, удивительно!
Давайте закомментируем вызов bc.SignTransaction (& tx, wallet.PrivateKey) в NewUTXOTransaction , для гарантии того, что неподписанные транзакции нельзя будет майнить:
Заключение
Мы реализовали почти все ключевые особенности Bitcoin и это потрясающе. А в следующей части мы наконец-таки завершим реализацию транзакций.
Источник