Was ist die korrekte Base58-Codierung für diesen unkomprimierten Public Key RipeMD-Hash mit Nullen in den Bits 31, 32 oder 33?

Mein Verständnis ist, dass Base58Checked immer 34 Bytes lang ist und nicht weniger als 34 Bytes sein wird, selbst wenn die ersten oder letzten Bytes der RipeMD Null sind. Wenn diese Aussage nicht wahr ist, dann ist keine der folgenden Fragen von Bedeutung.

Kurze Frage

Wie sollte die Base58Checked-Adresse für den folgenden öffentlichen Schlüssel lauten?

0414C7AB38D5CC0A39B3BF5F970C572736904D40A5879BBB05BBE16911D7F35DD3E25525877587BF91EE801393FACDED26FAFA173E457F5961BA11F602CC08FE5A

Diese Test-Website sagt, dass es so sein sollte 1vwTLMCesc1vijZbscYfnr7naV9MEy8dS, aber wenn ich mir die Logik unten ansehe, denke ich, dass es so sein sollte 11vwTLMCesc1vijZbscYfnr7naV9MEy8dS(beachten Sie die zweite führende).

Mehr Informationen

In dieser Schleife numberToShortenverringert sich der Wert, wenn ich herausfinde, was in den letzten Runden der Konvertierung Null ist. (z. B. "1" für einen Wert von Null und "A" für einen Rest von neun.

Der folgende unkomprimierte öffentliche Schlüssel ist ein Beispiel für einen, der mir beim Codieren eine Null lässt, mit der ich umgehen muss:

0414C7AB38D5CC0A39B3BF5F970C572736904D40A5879BBB05BBE16911D7F35DD3E25525877587BF91EE801393FACDED26FAFA173E457F5961BA11F602CC08FE5A

Hier ist mein C#-Code:

    public static String sBase58Alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
    public static String EncodeBase58(BigInteger numberToShorten)
    {
        // WARNING: Beware of bignumber implementations that clip leading 0x00 bytes, or prepend extra 0x00 
        // bytes to indicate sign - your code must handle these cases properly or else you may generate valid-looking
        // addresses which can be sent to, but cannot be spent from - which would lead to the permanent loss of coins.)

        const int sizeWalletImportFormat = 51;
          BigInteger base58AlphabetLength = (BigInteger)sBase58Alphabet.Length;

        char[] result = new char[34];

        int i = 0;
        while (result.Length > i && numberToShorten >= 0)
         { 
            var lNumberRemainder = BigInteger.Remainder(numberToShorten, base58AlphabetLength);
            result[result.Length - 1 - i] = sBase58Alphabet[(int)lNumberRemainder];

            if (i == 31 && numberToShorten == 0)
                Console.WriteLine("found one");

            //Console.WriteLine("i = " + i);
            //Console.WriteLine("numberToShorten= " + numberToShorten + " (Divide this by 58 to get the value below)");
            //Console.WriteLine("lNumberRemainder = " + lNumberRemainder + " (Get this position in the Base58Array and append that character)");
            //Console.WriteLine("result = " + new string(result));

            if (numberToShorten == 0)
            {
                if (i != 33)
                {
                    // Debug
                    Console.WriteLine("i = " + i);
                    break;
                }
                break;
            } 

            numberToShorten = numberToShorten / base58AlphabetLength;
            i++;
        }
        var ret = new string(result, 33 - i, result.Length - (33 - i));

        return ret;
    }

    public static DecodedBase58Result DecodeBase58(String base58StringToExpand)
    { 
        DecodedBase58Result ret = new DecodedBase58Result();

        BigInteger base58AlphabetLength = (BigInteger)sBase58Alphabet.Length;

        BigInteger numberToExtend = BigInteger.Zero;
        var charsToDecode = base58StringToExpand.ToCharArray();
        for (int decodePosition = 0; decodePosition <= charsToDecode.Length - 1; decodePosition++)
        {
            char sCurrentCharacter = charsToDecode[decodePosition];
            int index = sBase58Alphabet.IndexOf(sCurrentCharacter);
            if (index == -1)
                throw new Exception("Not a base58 address, " + sCurrentCharacter + " isn't a valid character.");

            numberToExtend = numberToExtend * base58AlphabetLength;
            numberToExtend = numberToExtend + index;

            //Console.WriteLine(" i = " + (base58StringToExpand.Length - decodePosition));
            //Console.WriteLine(" number = " + numberToExtend);
            //Console.WriteLine(" Result = " + ret);
        }

        ret.BigInt = numberToExtend;
        return ret;
    }

Das abgeschnittene Zeichen-für-Zeichen-Gebäude der Base58-Adresse ist unten. Das Problem liegt woi=32

i = 27
numberToShorten= 610398922 (Divide this by 58 to get the value below)
lNumberRemainder = 20 (Get this position in the Base58Array and append that character)
result =       MCesc1vijZbscYfnr7naV9MEy8dS

i = 28
numberToShorten= 10524119 (Divide this by 58 to get the value below)
lNumberRemainder = 19 (Get this position in the Base58Array and append that character)
result =      LMCesc1vijZbscYfnr7naV9MEy8dS

i = 29
numberToShorten= 181450 (Divide this by 58 to get the value below)
lNumberRemainder = 26 (Get this position in the Base58Array and append that character)
result =     TLMCesc1vijZbscYfnr7naV9MEy8dS

i = 30
numberToShorten= 3128 (Divide this by 58 to get the value below)
lNumberRemainder = 54 (Get this position in the Base58Array and append that character)
result =    wTLMCesc1vijZbscYfnr7naV9MEy8dS

i = 31
numberToShorten= 53 (Divide this by 58 to get the value below)
lNumberRemainder = 53 (Get this position in the Base58Array and append that character)
result =   vwTLMCesc1vijZbscYfnr7naV9MEy8dS

i = 32
numberToShorten= 0 (Divide this by 58 to get the value below)
lNumberRemainder = 0 (Get this position in the Base58Array and append that character)
result =  1vwTLMCesc1vijZbscYfnr7naV9MEy8dS

i = 33
numberToShorten= 0 (Divide this by 58 to get the value below)
lNumberRemainder = 0 (Get this position in the Base58Array and append that character)
result = 11vwTLMCesc1vijZbscYfnr7naV9MEy8dS
Deine erste Aussage stimmt nicht. Eine Bitcoin-Adresse muss nicht 34 Zeichen lang sein. Siehe zum Beispiel die ersten paar: directory.io

Antworten (2)

Ich denke, Sie haben ein grundlegendes Missverständnis der Base58-Codierung. Base58checked hat keine feste Länge; seine Länge hängt von der Anzahl der führenden Nullbytes in der Eingabe ab.

Es sollte nur eine führende „1“ vorhanden sein, die den Adresstyp „Hauptnetz“ angibt. Eine zweite führende "1" würde ein ganzes führendes Nullbyte (0x00) im Pubkey-Hash selbst anzeigen, was in diesem Fall nicht zutrifft, da Ihr sha256+ripemd-160 0a33807d0764e0bc71677fbef234d4989d0c198e ist. Es hat nur ein führendes Nullnibble.

Ich spreche von der Null, die Sie in erwähnen 0a33. Diese Null im RipeMD bringt mich durcheinander ... ich bin mir nicht sicher, was ich damit machen soll ...
Ja, das ist nur ein Nibble (4 Nullbits). Sie können "1" am Anfang nur für ganze Nullbytes (8 Nullbits) verwenden.
@makerofthings7 Es ist sehr einfach, die Regeln der Base58-Codierung zu verstehen. Sie zählen zuerst die Anzahl der führenden Null-Bytes, entfernen sie dann, behandeln dann die verbleibenden Bytes als Big-Endian-Ganzzahl und konvertieren sie in Basis-58 und fügen schließlich so viele „1“-Präfixe hinzu, wie die Anzahl der führenden Null-Bytes.
Notiz an mich selbst: Der folgende unkomprimierte öffentliche Schlüssel hat 8 Nullbits, wenn er in Base58 codiert ist04448212C17B6D5FD88E316AFB1D79432D7BC983567CFD5945DFE2E54C2F2A5F69E234588C4C43EB7F1E7285C0F6CBC61A31385FADF7663305A6F4FF494D621F8D

Das Problem liegt in der Interpretation von Nullen in meinem Code in den höchstwertigen Bits (MSB). Ich habe meinen Code aktualisiert, um den korrekten base58hash-Code anzugeben (wie vom QT-Client verifiziert).

Da die Base58-geprüfte Kodierung immer mit 25 Bytes arbeitet (RIPEMD + Network + 4 Byte Checksum)

Der folgende öffentliche Schlüssel hat ein MSB von Null

04EF12BF0C1EC3646CE6828E7D59B4111381EB8A3DF2BBB89D53254AD70BE27498C76F6E2AB3B7FC15A69B0A44AC84659728146E46670E3C66B14222FAB82C8CF6

Da das MSB zwei Nullen hat, basiert der Base58-Hash auf einer Null1EVEDmVcV7iPvTkaw2gk89yVcCzPzaS6B7


Der folgende öffentliche Schlüssel hat ein MSB von zwei Nullen

04BAE942CC53D51498CD2E1576C1C43F125302DEF76A8A470B818C8D6BB65A82D679232E294E6F2D1C78F35BAA272EF1585F2FFE8B88769B02FBCEDD070CE50D4B

Da das MSB zwei Nullen hat, basiert der Base58-Hash auf zwei Nullen11ujQcjgoMNmbmcBkk8CXLWQy8ZerMtuN


Der folgende öffentliche Schlüssel hat ein MSB von drei Nullen

04AD8A68DF6A4553BEDD234BF2D7BFB5F0C5830F13C3A5F814AAFC03E2C92602EC1047CFE67F14D499B55F57BBE104D29E9BF6C9849771B4E3AE46FFB76FE3DFCD

Da das MSB drei Nullen hat, hasht der Base58 drei Nullen111oeV7wjVNCQttqY63jLFsg817aMEmTw