Обновление: частичное решение доступно на Git
РЕДАКТИРОВАТЬ: его скомпилированная версия доступна по адресу https://github.com/makerofthings7/Bitcoin-MessageSignerVerifier < / а>
Обратите внимание, что проверяемое сообщение должно иметь префикс Bitcoin Signed Message:\n
. Source1 Source2
В реализации C # что-то не так, и я, вероятно, смогу исправить это с помощью эта реализация Python
Кажется, у него проблема с тем, чтобы на самом деле найти правильный адрес Base 58.
У меня есть следующее сообщение, подпись и адрес Base58 ниже. Я собираюсь извлечь ключ из подписи, хешировать этот ключ и сравнить хеши Base58.
Моя проблема: как извлечь ключ из подписи? (Отредактируйте Я нашел код C ++ внизу этого поста нужно в Bouncy Castle / или C #)
Сообщение
StackOverflow test 123
Подпись
IB7XjSi9TdBbB3dVUK4+Uzqf2Pqk71XkZ5PUsVUN+2gnb3TaZWJwWW2jt0OjhHc4B++yYYRy1Lg2kl+WaiF+Xsc=
Хэш адреса биткойнов в Base58
1Kb76YK9a4mhrif766m321AMocNvzeQxqV
Поскольку биткойн-адрес Base58 - это просто хэш, я не могу использовать его для проверки биткойн-сообщения. Однако можно извлечь открытый ключ из подписи.
Изменить: я подчеркиваю, что я получаю открытый ключ из самой подписи, а не из хэша открытого ключа Base58. Если я хочу (а я действительно хочу), я смогу преобразовать эти биты открытого ключа в хеш Base58. Мне не нужна помощь в этом, мне просто нужна помощь в извлечении битов открытого ключа и проверке подписи.
Вопрос
В каком формате эта подпись в приведенной выше подписи? PKCS10? (Ответ: нет, это проприетарный как описано здесь)
как мне извлечь открытый ключ в Bouncy Castle?
Как правильно проверить подпись? (предположим, что я уже знаю, как преобразовать биты открытого ключа в хеш, равный хешу биткойнов, указанному выше)
Предыдущее исследование
Эта ссылка описывает, как использовать кривые ECDSA, а следующий код позволит мне преобразовать открытый ключ в объект BC, но я не уверен, как получить точку Q
из подписи.
В примере ниже Q - это жестко закодированное значение
Org.BouncyCastle.Asn1.X9.X9ECParameters ecp = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName("secp256k1");
ECDomainParameters params = new ECDomainParameters(ecp.Curve, ecp.G, ecp.N, ecp.H);
ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(
ecp .curve.decodePoint(Hex.decode("045894609CCECF9A92533F630DE713A958E96C97CCB8F5ABB5A688A238DEED6DC2D9D0C94EBFB7D526BA6A61764175B99CB6011E2047F9F067293F57F5")), // Q
params);
PublicKey pubKey = f.generatePublic(pubKeySpec);
var signer = SignerUtilities.GetSigner("ECDSA"); // possibly similar to SHA-1withECDSA
signer.Init(false, pubKey);
signer.BlockUpdate(plainTextAsBytes, 0, plainTextAsBytes.Length);
return signer.VerifySignature(signature);
Дополнительное исследование:
ЭТО сообщение, которое проверяет биткойн-источник, является источником биткойнов.
После декодирования Base64 подписи, RecoverCompact (хэш сообщения , подпись) называется. Я не программист на C ++, поэтому предполагаю, что мне нужно разобраться, как key.Recover
работает. Это или key.GetPubKey
Это код C ++, который, я думаю, мне нужен на C #, в идеале в надувном замке ... но я возьму все, что работает.
// reconstruct public key from a compact signature
// This is only slightly more CPU intensive than just verifying it.
// If this function succeeds, the recovered public key is guaranteed to be valid
// (the signature is a valid signature of the given data for that key)
bool Recover(const uint256 &hash, const unsigned char *p64, int rec)
{
if (rec<0 || rec>=3)
return false;
ECDSA_SIG *sig = ECDSA_SIG_new();
BN_bin2bn(&p64[0], 32, sig->r);
BN_bin2bn(&p64[32], 32, sig->s);
bool ret = ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), rec, 0) == 1;
ECDSA_SIG_free(sig);
return ret;
}
... код для ECDSA_SIG_recover_key_GFp находится здесь
Пользовательский формат подписи в биткойнах
В этом ответе говорится, что существует 4 возможных открытых ключа, которые могут создавать подпись, и это закодировано в новых подписях.