Основной проблемой в реализации анти-пул алгоритма PoW версии 1.0 является то, что при использовании асимметричной криптографии ECDSA на эллиптической кривой secp256k1 невозможно подписать хеш (число) одновариантно и одинаково без потери секурности и безопасности, поскольку число sign_nonce в данной схеме должно быть не только рандомным, но и неизвестным третьим лицам. Иначе очень легко вычислить число R, а затем приватный ключ K из числа S. Поэтому основной задачей для решения вышеописанной проблемы является нахождение такой асимметричной криптографии, которая позволяет подписать хеш (число) достаточно секурно и даёт одновариантный и одинаковый результат.
Для имплементации анти-пул алгоритма PoW версии 2.0 предлагается использовать асимметричную криптографию RSA (Rivest-Shamir-Adleman), широко применяемую, например, в известном приложении PGP (Pretty Good Privacy). В этой криптографии число (хеш), являющееся открытым сообщением M, для повышения секурности прежде подписывания обычно инкапсулируется в другое (большее) число методом Probabilistic Signature Scheme (PSS). По умолчанию в данной схеме используется так называемая "соль", которая является рандомным числом (то есть, по сути, sign_nonce), но этот параметр может быть опущен. Таким образом схема PSS без "соли" при подписывании одного и того же (хеша) числа даёт одновариантный и одинаковый результат. Разумеется, отсутствие "соли" в подписи снижает секурность, но не существенно.
В целях тестирования анти-пул алгоритма PoW версии 2.0 можно использовать, например, известное приложение OpenSSL. В настоящее время в криптографии RSA обычно используются публичная экспонента E, равная 65537, и публичный ключ N длиной 2048 бит (256 байт).
Чтобы сгенерировать пару ключей RSA, необходимо:
1) Создать приватный ключ, являющийся двумя простыми числами P и Q, каждый длиной по 1024 бит (по 128 байт):
openssl genrsa -out private_key.pem 2048
2) Вычислить публичный ключ N длиной 2048 бит (256 байт), являющийся произведением двух чисел P и Q:
openssl rsa -in private_key.pem -outform PEM -pubout -out public_key.pem
Чтобы подписать заголовок хеша блока методом RSA-PSS, необходимо:
1) Вычислить ASIC-устойчивым алгоритмом и записать хеш заголовка блока в текстовый файл, например, "block_header_hash.txt".
2) Подписать хеш заголовка блока и записать сигнатуру в файл "block_header_hash.txt.sig":
openssl dgst -sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:0
-sign private_key.pem -out block_header_hash.txt.sig block_header_hash.txt
Следует отметить, что параметр rsa_pss_saltlen равен нулю, поэтому результат выполнения этой команды при одних и тех же входящих данных файла "block_header_hash.txt" всегда одновариантен и одинаков.
В версии 2.0 структура заголовка блока содержит 7 полей:
- 1) block_version (4 байта)
- 2) previous_block_header_hash (32 байта)
- 3) block_timestamp (8 байт)
- 4) transaction_count (4 байта)
- 5) merkle_root (32 байта)
- 6) required_leading_zero_bit_count_in_rsa_sign (1 байт)
- 7) block_nonce (8 байт)
Затем записывается подпись block_header_hash_rsa_sign_without_salt (256 байт). Итого размер заголовка блока с подписью составляет 89 + 256 = 345 байт.
Для имплементации анти-пул алгоритма PoW версии 2.0 транзакции должны одновременно поддерживать адреса, основанные не только на асимметричной криптографии ECDSA на эллиптической кривой secp256k1, но и на асимметричной криптографии RSA с инкапсуляцией числа (хеша) по схеме PSS. Если рассматривать на примере Bitcoin, то потребуется ввести новый OP_CHECKSIGN_RSA, который верифицирует два последних значения из стека (подпись S и публичный ключ N) по схеме PSS (с "солью") и проверяет валидность входного скрипта транзакции.
openssl dgst -sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1
-sign private_key.pem -out transaction.txt.sig transaction.txt
Параметр rsa_pss_saltlen, равный -1, в данной команде означает, что длина "соли" будет равна длине хеша SHA256, то есть 32 байтам, поэтому секурность и безопасность будут на высоком уровне.
Важно, что валидная COINBASE-транзакция должна содержать один выход и направлять награду за создание нового смайненного блока и все комиссии за включённые в него транзакции на адрес, являющийся публичным ключом RSA. Другие майнеры будут верифицировать подпись хеша заголовка блока, используя этот ключ. Входной скрипт COINBASE-транзакции может использоваться, например, для голосований, объявлений и других отметок.
Выходной скрипт scriptPubKey COINBASE-транзакции должен содержать формат PAY-TO-RSA-PUBKEY:
OP_DUPOP_EQUALVERIFY OP_CHECKSIG_RSA
Соответственно, для того, чтобы в будущем потратить этот выход, во входном скрипте scriptSig последующей транзакции нужно будет указать подпись S и публичный ключ N:
Представленный анти-пул алгоритм PoW версии 2.0 устраняет указанный существенный недостаток версии 1.0, а также добавляет некоторые усовершенствования. Использование в майнинге асимметричной криптографии RSA по схеме PSS без "соли" не даст возможности майнерам перебирать число sign_nonce вместо перебора числа block_nonce, как это было возможно в анти-пул алгоритме PoW версии 1.0, поэтому они будут вынуждены вычислять хеш заголовка блока многократно, при каждой итерации майнинга проходя через ASIC-устойчивый алгоритм. Кроме этого, администраторы ботнетов и вебсайтов, скорее всего, не будут устанавливать скрытые JS-скрипты, поскольку приватный ключ RSA (то есть числа P и Q) необходимы при каждой итерации майнинга.
Описанная схема позволяет обеспечить ASIC-устойчивость, уменьшить централизацию майнинга и, как следствие, ещё более снизить возможности цензурирования транзакций узким кругом лиц.