Как получить открытый ключ ECDSA только из подписи Биткойн? SEC1 4.1.6 восстановление ключа для кривых над (mod p) -полями

Обновление: частичное решение доступно на 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. Мне не нужна помощь в этом, мне просто нужна помощь в извлечении битов открытого ключа и проверке подписи.

Вопрос

  1. В каком формате эта подпись в приведенной выше подписи? PKCS10? (Ответ: нет, это проприетарный как описано здесь)

  2. как мне извлечь открытый ключ в Bouncy Castle?

  3. Как правильно проверить подпись? (предположим, что я уже знаю, как преобразовать биты открытого ключа в хеш, равный хешу биткойнов, указанному выше)

Предыдущее исследование

Эта ссылка описывает, как использовать кривые 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 возможных открытых ключа, которые могут создавать подпись, и это закодировано в новых подписях.


person halfbit    schedule 29.10.2013    source источник
comment
@zimdanen, правильно, я не пытаюсь получить информацию из адреса монеты (хеш) Base58 бит. Подпись не является хешем, но также содержит достаточно информации, чтобы я мог определить открытый ключ, а затем преобразовать этот ключ в хеш. Затем я могу сравнить вычисленный хэш с тем, что у меня есть.   -  person halfbit    schedule 29.10.2013
comment
Без проблем. Я добавил пояснение, чтобы другие программы скоростного чтения не делали то же самое.   -  person halfbit    schedule 29.10.2013
comment
Разве точка проверки подписи не состоит в том, чтобы проверить подпись на основе открытого ключа, который вы уже знаете (и полагаете, что он принадлежит подписывающей стороне)? Похоже, что это противоречит цели подписания, если вы собираетесь проверять подпись по открытому ключу, предоставленному в то же время (без проверки известного открытого ключа от подписывающей стороны).   -  person Bruno    schedule 30.10.2013
comment
@ Бруно, да, это учтено. Встроенный миниатюрный открытый ключ после хеширования должен совпадать с хешем сжатого открытого ключа пользователя. Следовательно, если подпись действительна и извлеченный открытый ключ при хешировании в форму Base58 завершен, значит, подпись действительна и от того, от кого вы ожидаете, что она будет.   -  person halfbit    schedule 30.10.2013
comment
Привет, @ makerofthings7, я поражен недостаточным вниманием к этому вопросу. Я работаю над правильным ответом для вас прямо сейчас.   -  person Adam McArthur    schedule 16.11.2013
comment
этот вопрос говорит об извлечении открытого ключа из скриптов?   -  person mulllhausen    schedule 09.01.2014
comment
@mulllhausen Нет, в биткойнах это невозможно. ScriptSig использует другую, более старую версию алгоритма подписи OpenSSL. Это касается функции подписи сообщений   -  person halfbit    schedule 09.01.2014
comment
@ makerofthings7 спасибо за разъяснения!   -  person mulllhausen    schedule 10.01.2014


Ответы (2)


После ссылки на BitcoinJ выясняется, что в некоторых из этих примеров кода отсутствует надлежащая подготовка сообщения, двойное хеширование SHA256 и возможное сжатое кодирование восстановленной общедоступной точки, которая вводится для вычисления адреса.

Для следующего кода нужен только BouncyCastle (возможно, вам понадобится последняя версия с github, не уверен). Он заимствует кое-что у BitcoinJ и делает достаточно для того, чтобы небольшие примеры работали, см. Встроенные комментарии об ограничениях на размер сообщений.

Он рассчитывает только хэш RIPEMD-160, и я использовал http://gobittest.appspot.com/Address, чтобы проверить полученный окончательный адрес (к сожалению, этот веб-сайт, похоже, не поддерживает ввод сжатой кодировки для открытого ключа).

    public static void CheckSignedMessage(string message, string sig64)
    {
        byte[] sigBytes = Convert.FromBase64String(sig64);
        byte[] msgBytes = FormatMessageForSigning(message);

        int first = (sigBytes[0] - 27);
        bool comp = (first & 4) != 0;
        int rec = first & 3;

        BigInteger[] sig = ParseSig(sigBytes, 1);
        byte[] msgHash = DigestUtilities.CalculateDigest("SHA-256", DigestUtilities.CalculateDigest("SHA-256", msgBytes));

        ECPoint Q = Recover(msgHash, sig, rec, true);

        byte[] qEnc = Q.GetEncoded(comp);
        Console.WriteLine("Q: " + Hex.ToHexString(qEnc));

        byte[] qHash = DigestUtilities.CalculateDigest("RIPEMD-160", DigestUtilities.CalculateDigest("SHA-256", qEnc));
        Console.WriteLine("RIPEMD-160(SHA-256(Q)): " + Hex.ToHexString(qHash));

        Console.WriteLine("Signature verified correctly: " + VerifySignature(Q, msgHash, sig));
    }

    public static BigInteger[] ParseSig(byte[] sigBytes, int sigOff)
    {
        BigInteger r = new BigInteger(1, sigBytes, sigOff, 32);
        BigInteger s = new BigInteger(1, sigBytes, sigOff + 32, 32);
        return new BigInteger[] { r, s };
    }

    public static ECPoint Recover(byte[] hash, BigInteger[] sig, int recid, bool check)
    {
        X9ECParameters x9 = SecNamedCurves.GetByName("secp256k1");

        BigInteger r = sig[0], s = sig[1];

        FpCurve curve = x9.Curve as FpCurve;
        BigInteger order = x9.N;

        BigInteger x = r;
        if ((recid & 2) != 0)
        {
            x = x.Add(order);
        }

        if (x.CompareTo(curve.Q) >= 0) throw new Exception("X too large");

        byte[] xEnc = X9IntegerConverter.IntegerToBytes(x, X9IntegerConverter.GetByteLength(curve));

        byte[] compEncoding = new byte[xEnc.Length + 1];
        compEncoding[0] = (byte)(0x02 + (recid & 1));
        xEnc.CopyTo(compEncoding, 1);
        ECPoint R = x9.Curve.DecodePoint(compEncoding);

        if (check)
        {
            //EC_POINT_mul(group, O, NULL, R, order, ctx))
            ECPoint O = R.Multiply(order);
            if (!O.IsInfinity) throw new Exception("Check failed");
        }

        BigInteger e = CalculateE(order, hash);

        BigInteger rInv = r.ModInverse(order);
        BigInteger srInv = s.Multiply(rInv).Mod(order);
        BigInteger erInv = e.Multiply(rInv).Mod(order);

        return ECAlgorithms.SumOfTwoMultiplies(R, srInv, x9.G.Negate(), erInv);
    }

    public static bool VerifySignature(ECPoint Q, byte[] hash, BigInteger[] sig)
    {
        X9ECParameters x9 = SecNamedCurves.GetByName("secp256k1");
        ECDomainParameters ec = new ECDomainParameters(x9.Curve, x9.G, x9.N, x9.H, x9.GetSeed());
        ECPublicKeyParameters publicKey = new ECPublicKeyParameters(Q, ec);
        return VerifySignature(publicKey, hash, sig);
    }

    public static bool VerifySignature(ECPublicKeyParameters publicKey, byte[] hash, BigInteger[] sig)
    {
        ECDsaSigner signer = new ECDsaSigner();
        signer.Init(false, publicKey);
        return signer.VerifySignature(hash, sig[0], sig[1]);
    }

    private static BigInteger CalculateE(
        BigInteger n,
        byte[] message)
    {
        int messageBitLength = message.Length * 8;
        BigInteger trunc = new BigInteger(1, message);

        if (n.BitLength < messageBitLength)
        {
            trunc = trunc.ShiftRight(messageBitLength - n.BitLength);
        }

        return trunc;
    }

    public static byte[] FormatMessageForSigning(String message)
    {
        MemoryStream bos = new MemoryStream();
        bos.WriteByte((byte)BITCOIN_SIGNED_MESSAGE_HEADER_BYTES.Length);
        bos.Write(BITCOIN_SIGNED_MESSAGE_HEADER_BYTES, 0, BITCOIN_SIGNED_MESSAGE_HEADER_BYTES.Length);
        byte[] messageBytes = Encoding.UTF8.GetBytes(message);

        //VarInt size = new VarInt(messageBytes.length);
        //bos.write(size.encode());
        // HACK only works for short messages (< 253 bytes)
        bos.WriteByte((byte)messageBytes.Length);

        bos.Write(messageBytes, 0, messageBytes.Length);
        return bos.ToArray();
    }

Пример вывода исходных данных в вопросе:

Q: 0283437893b491218348bf5ff149325e47eb628ce36f73a1a927ae6cb6021c7ac4
RIPEMD-160(SHA-256(Q)): cbe57ebe20ad59518d14926f8ab47fecc984af49
Signature verified correctly: True

Если мы вставим значение RIPEMD-160 в средство проверки адресов, оно вернет

1Kb76YK9a4mhrif766m321AMocNvzeQxqV

как указано в вопросе.

person Peter Dettman    schedule 05.12.2013
comment
Этот код великолепен и отлично работает с клиентами QT. У меня возникли проблемы с созданием подписи, которую можно проверить с помощью этого кода. Не могли бы вы мне с этим помочь? - person halfbit; 09.02.2014

Боюсь, что с вашими образцами данных есть проблемы. Прежде всего, длина вашего образца Q составляет 61 байт, но открытые ключи Биткойна (с использованием кривой secp256k1) должны быть 65 байтов в несжатом виде. Предоставленный вами Q не подтверждает правильность сообщения, но рассчитанный мной Q, похоже, подтверждает его.

Я написал код, который вычисляет правильный открытый ключ для строки «StackOverflow test 123» и проверяет его с помощью ECDsaSigner. Однако хеш для этого открытого ключа 1HRDe7G7tn925iNxQaeD7R2ZkZiKowN8NW вместо 1Kb76YK9a4mhrif766m321AMocNvzeQxqV.

Не могли бы вы убедиться, что ваши данные верны, и, возможно, дать точный хэш строки сообщения, чтобы мы могли попытаться отладить, неправильный хеш может сильно испортить ситуацию. Я использовал следующий код:

using System;
using System.Text;
using System.Security.Cryptography;

using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto.Signers;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Utilities.Encoders;

public class Bitcoin
{
  public static ECPoint Recover(byte[] hash, byte[] sigBytes, int rec)
  {
    BigInteger r = new BigInteger(1, sigBytes, 0, 32);
    BigInteger s = new BigInteger(1, sigBytes, 32, 32);
    BigInteger[] sig = new BigInteger[]{ r, s };
    ECPoint Q = ECDSA_SIG_recover_key_GFp(sig, hash, rec, true);
    return Q;
  }

  public static ECPoint ECDSA_SIG_recover_key_GFp(BigInteger[] sig, byte[] hash, int recid, bool check)
  {
    X9ECParameters ecParams = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName("secp256k1");
    int i = recid / 2;

    Console.WriteLine("r: "+ToHex(sig[0].ToByteArrayUnsigned()));
    Console.WriteLine("s: "+ToHex(sig[1].ToByteArrayUnsigned()));

    BigInteger order = ecParams.N;
    BigInteger field = (ecParams.Curve as FpCurve).Q;
    BigInteger x = order.Multiply(new BigInteger(i.ToString())).Add(sig[0]);
    if (x.CompareTo(field) >= 0) throw new Exception("X too large");

    Console.WriteLine("Order: "+ToHex(order.ToByteArrayUnsigned()));
    Console.WriteLine("Field: "+ToHex(field.ToByteArrayUnsigned()));

    byte[] compressedPoint = new Byte[x.ToByteArrayUnsigned().Length+1];
    compressedPoint[0] = (byte) (0x02+(recid%2));
    Buffer.BlockCopy(x.ToByteArrayUnsigned(), 0, compressedPoint, 1, compressedPoint.Length-1);
    ECPoint R = ecParams.Curve.DecodePoint(compressedPoint);

    Console.WriteLine("R: "+ToHex(R.GetEncoded()));

    if (check)
    {
      ECPoint O = R.Multiply(order);
      if (!O.IsInfinity) throw new Exception("Check failed");
    }

    int n = (ecParams.Curve as FpCurve).Q.ToByteArrayUnsigned().Length*8;
    BigInteger e = new BigInteger(1, hash);
    if (8*hash.Length > n)
    {
      e = e.ShiftRight(8-(n & 7));
    }
    e = BigInteger.Zero.Subtract(e).Mod(order);
    BigInteger rr = sig[0].ModInverse(order);
    BigInteger sor = sig[1].Multiply(rr).Mod(order);
    BigInteger eor = e.Multiply(rr).Mod(order);
    ECPoint Q = ecParams.G.Multiply(eor).Add(R.Multiply(sor));

    Console.WriteLine("n: "+n);
    Console.WriteLine("e: "+ToHex(e.ToByteArrayUnsigned()));
    Console.WriteLine("rr: "+ToHex(rr.ToByteArrayUnsigned()));
    Console.WriteLine("sor: "+ToHex(sor.ToByteArrayUnsigned()));
    Console.WriteLine("eor: "+ToHex(eor.ToByteArrayUnsigned()));
    Console.WriteLine("Q: "+ToHex(Q.GetEncoded()));

    return Q;
  }

  public static bool VerifySignature(byte[] pubkey, byte[] hash, byte[] sigBytes)
  {
    X9ECParameters ecParams = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName("secp256k1");
    ECDomainParameters domainParameters = new ECDomainParameters(ecParams.Curve,
                                                                 ecParams.G, ecParams.N, ecParams.H,
                                                                 ecParams.GetSeed());

    BigInteger r = new BigInteger(1, sigBytes, 0, 32);
    BigInteger s = new BigInteger(1, sigBytes, 32, 32);
    ECPublicKeyParameters publicKey = new ECPublicKeyParameters(ecParams.Curve.DecodePoint(pubkey), domainParameters);

    ECDsaSigner signer = new ECDsaSigner();
    signer.Init(false, publicKey);
    return signer.VerifySignature(hash, r, s);
  }



  public static void Main()
  {
    string msg = "StackOverflow test 123";
    string sig = "IB7XjSi9TdBbB3dVUK4+Uzqf2Pqk71XkZ5PUsVUN+2gnb3TaZWJwWW2jt0OjhHc4B++yYYRy1Lg2kl+WaiF+Xsc=";
    string pubkey = "045894609CCECF9A92533F630DE713A958E96C97CCB8F5ABB5A688A238DEED6DC2D9D0C94EBFB7D526BA6A61764175B99CB6011E2047F9F067293F57F5";

    SHA256Managed sha256 = new SHA256Managed();
    byte[] hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(msg), 0, Encoding.UTF8.GetByteCount(msg));
    Console.WriteLine("Hash: "+ToHex(hash));

    byte[] tmpBytes = Convert.FromBase64String(sig);
    byte[] sigBytes = new byte[tmpBytes.Length-1];
    Buffer.BlockCopy(tmpBytes, 1, sigBytes, 0, sigBytes.Length);

    int rec = (tmpBytes[0] - 27) & ~4;
    Console.WriteLine("Rec {0}", rec);

    ECPoint Q = Recover(hash, sigBytes, rec);
    string qstr = ToHex(Q.GetEncoded());
    Console.WriteLine("Q is same as supplied: "+qstr.Equals(pubkey));

    Console.WriteLine("Signature verified correctly: "+VerifySignature(Q.GetEncoded(), hash, sigBytes));
  }

  public static string ToHex(byte[] data)
  {
    return BitConverter.ToString(data).Replace("-","");
  }
}

ИЗМЕНИТЬ. Я вижу, что это все еще не прокомментировано и не принято, поэтому я написал полный тест, который генерирует закрытый ключ и открытый ключ, а затем генерирует действительную подпись с использованием закрытого ключа. После этого он извлекает открытый ключ из подписи и хэша и использует этот открытый ключ для проверки подписи сообщения. См. Ниже. Если у вас остались вопросы, дайте мне знать.

  public static void FullSignatureTest(byte[] hash)
  {
    X9ECParameters ecParams = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName("secp256k1");
    ECDomainParameters domainParameters = new ECDomainParameters(ecParams.Curve,
                                                                 ecParams.G, ecParams.N, ecParams.H,
                                                                 ecParams.GetSeed());
    ECKeyGenerationParameters keyGenParams =
      new ECKeyGenerationParameters(domainParameters, new SecureRandom());

    AsymmetricCipherKeyPair keyPair;
    ECKeyPairGenerator generator = new ECKeyPairGenerator();
    generator.Init(keyGenParams);
    keyPair = generator.GenerateKeyPair();

    ECPrivateKeyParameters privateKey = (ECPrivateKeyParameters) keyPair.Private;
    ECPublicKeyParameters publicKey = (ECPublicKeyParameters) keyPair.Public;

    Console.WriteLine("Generated private key: " + ToHex(privateKey.D.ToByteArrayUnsigned()));
    Console.WriteLine("Generated public key: " + ToHex(publicKey.Q.GetEncoded()));

    ECDsaSigner signer = new ECDsaSigner();
    signer.Init(true, privateKey);
    BigInteger[] sig = signer.GenerateSignature(hash);

    int recid = -1;
    for (int rec=0; rec<4; rec++) {
      try
      {
        ECPoint Q = ECDSA_SIG_recover_key_GFp(sig, hash, rec, true);
        if (ToHex(publicKey.Q.GetEncoded()).Equals(ToHex(Q.GetEncoded())))
        {
          recid = rec;
          break;
        }
      }
      catch (Exception)
      {
        continue;
      }
    }
    if (recid < 0) throw new Exception("Did not find proper recid");

    byte[] fullSigBytes = new byte[65];
    fullSigBytes[0] = (byte) (27+recid);
    Buffer.BlockCopy(sig[0].ToByteArrayUnsigned(), 0, fullSigBytes, 1, 32);
    Buffer.BlockCopy(sig[1].ToByteArrayUnsigned(), 0, fullSigBytes, 33, 32);

    Console.WriteLine("Generated full signature: " + Convert.ToBase64String(fullSigBytes));

    byte[] sigBytes = new byte[64];
    Buffer.BlockCopy(sig[0].ToByteArrayUnsigned(), 0, sigBytes, 0, 32);
    Buffer.BlockCopy(sig[1].ToByteArrayUnsigned(), 0, sigBytes, 32, 32);

    ECPoint genQ = ECDSA_SIG_recover_key_GFp(sig, hash, recid, false);
    Console.WriteLine("Generated signature verifies: " + VerifySignature(genQ.GetEncoded(), hash, sigBytes));
  }
person juhovh    schedule 15.11.2013
comment
Хорошие наблюдения, но это не ответ на вопрос? - person Adam McArthur; 16.11.2013
comment
@AdamMcArthur. Я понял, что последний вопрос: Моя проблема: как мне извлечь ключ из подписи? (Изменить Я нашел код C ++ внизу этого сообщения, он нужен в Bouncy Castle / или C #) Я в основном преобразовал рассматриваемый код C ++ в BouncyCastle и C #, BouncyCastle использует много разных имен для параметров шифрования, чем образец OpenSSL код. На какой вопрос вы отвечаете? - person juhovh; 16.11.2013
comment
Извините, я не видел вашего редактирования. Я просматривал исходный код Биткойна и обнаружил, что на самом деле невозможно получить открытый ключ из подписи? - person Adam McArthur; 16.11.2013
comment
@AdamMcArthur Как упоминалось в ссылке, действительно можно получить открытый ключ из ПОДПИСИ СООБЩЕНИЯ, он содержит 2-битную информацию о том, какая точка является правильным открытым ключом. В последней отредактированной части моего кода я также показываю, как вычисляется эта 2-битная информация, транслируемая непосредственно из источников Биткойн. - person juhovh; 16.11.2013
comment
@AdamMcArthur Для получения дополнительной информации см. Исходный код github.com/bitcoin bitcoin / blob / и различия между CKey :: Sign и CKey :: SignCompact, а также CPubKey :: Verify и CPubKey :: VerifyCompact. Версии Compact - это специальные подписи для сообщений, которые поддерживают восстановление ключа, версии подписи и проверки - это обычные подписи в кодировке DER, широко используемые в сети. - person juhovh; 16.11.2013
comment
Спасибо @juhovh, проверю. - person Adam McArthur; 16.11.2013
comment
Приносим извинения за задержку с принятием и назначением награды. Я принимаю и награждаю, веря, что это работает, и буду тестировать, как только я вернусь (неожиданное путешествие неудобно в тот же день, когда закончилось вознаграждение). Мне очень любопытно, как вы выучили терминологию OpenSSL и BC до такого уровня, что вы можете переводить одно на другое. - person halfbit; 16.11.2013
comment
Нет проблем, если вы обнаружите проблемы с моим кодом, просто дайте мне знать, я никуда не пойду. Могут быть какие-то угловые случаи, которые нужно проверить, но я могу помочь с этим, просто пропустите через него как можно больше данных и попытайтесь сломать его. И я забыл упомянуть, что Биткойн по-другому проверяет подпись. Кажется, он восстанавливает открытый ключ из подписи и сравнивает его с известным открытым ключом. Это не работает в вашем случае, потому что вы не знаете открытый ключ, а только хеш. Поэтому вам нужно проверить, соответствует ли открытый ключ хешу, а затем проверить подпись традиционным способом. - person juhovh; 17.11.2013
comment
Раньше я потратил несколько месяцев на то, чтобы написать библиотеку SSL / TLS с нуля, используя C #, и в ходе этого процесса изучил довольно много кода OpenSSL и использовал BC для всего моего локального тестирования, связанного с ECC. Я также написал немного актуального кода ECC для развлечения, чтобы лучше познакомиться с параметрами. Так что я случайно познакомился с двумя библиотеками. - person juhovh; 17.11.2013
comment
Мне было бы очень интересно увидеть библиотеку SSL / TLS, если вы готовы поделиться ею. - person halfbit; 04.12.2013
comment
Похоже, возникла проблема с преобразованием открытого ключа обратно в адрес Bas58. В вопросе выше я включил полный код для преобразования извлеченного значения Q открытого ключа в хеш-код Base58. - person halfbit; 04.12.2013
comment
Вот интерактивный URL-адрес, который работает точно так же, как мой код в ответе выше. Когда я вставляю извлеченный ключ, данные не соответствуют ожидаемому хешу pubkey gobittest.appspot.com/Address - person halfbit; 04.12.2013
comment
хммм, возможно, это связано со сжатыми клавишами. Я не уверен, что это такое github.com/nanotube-coin-supybot marketmonitor / commit /, а вот общее описание сжатых ключей bitcoin.stackexchange.com/a/11301/ 1878 - person halfbit; 05.12.2013
comment
Извините, я не получил уведомления об этом по электронной почте от stackoverflow, мне нужно проверить свои настройки. Я изучу это как можно скорее. - person juhovh; 18.12.2013