Development

這個未壓縮的公鑰 RipeMD 雜湊的正確 Base58 編碼是什麼,在 31、32 或 33 位中有一個零?

  • September 17, 2018

我的理解是 Base58Checked 總是 34 字節長,即使 RipeMD 的第一個或最後一個字節為零,也不會小於 34 個字節。如果此陳述不正確,則以下問題都不重要。

簡短的問題

以下公鑰的 Base58Checked 地址應該是什麼?

0414C7AB38D5CC0A39B3BF5F970C572736904D40A5879BBB05BBE16911D7F35DD3E25525877587BF91EE801393FACDED26FAFA173E457F5961BA11F602CC08FE5A

這個測試網站說應該是1vwTLMCesc1vijZbscYfnr7naV9MEy8dS,但是,當我查看下面的邏輯時,我認為應該是11vwTLMCesc1vijZbscYfnr7naV9MEy8dS (注意第二個前導)

更多資訊

在這個循環中,numberToShorten當我找出最後幾輪轉換的零時,值會遞減。(例如,“1”表示值為零,“A”表示余數為 9。

以下未壓縮的公鑰是在編碼時留下零供我處理的一個範例:

0414C7AB38D5CC0A39B3BF5F970C572736904D40A5879BBB05BBE16911D7F35DD3E25525877587BF91EE801393FACDED26FAFA173E457F5961BA11F602CC08FE5A

這是我的 C# 程式碼:

   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;
   }

Base58 地址的逐個字元的截斷結構如下所示。問題出在哪裡i=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

我認為您對 Base58 編碼有根本的誤解。Base58checked 不是固定長度;它的長度取決於輸入中前導零字節的數量。

應該只有一個前導“1”表示“主網”地址類型。第二個前導“1”表示公鑰雜湊本身中的整個前導零字節(0x00),這在這種情況下不適用,因為您的 sha256+ripemd-160 是 0a33807d0764e0bc71677fbef234d4989d0c198e。它只有一個前導零半字節。

問題在於我的程式碼對最高有效位 (MSB) 中的零的解釋。我更新了我的程式碼以提供正確的 base58hash 程式碼(由 QT 客戶端驗證)。

鑑於 Base58 檢查編碼始終使用 25 字節(RIPEMD + 網路 + 4 字節校驗和)

以下公鑰的一個 MSB 為零

04EF12BF0C1EC3646CE6828E7D59B4111381EB8A3DF2BBB89D53254AD70BE27498C76F6E2AB3B7FC15A69B0A44AC84659728146E46670E3C66B14222FAB82C8CF6

由於 MSB 有兩個零,因此 Base58 雜湊以一個零為底1EVEDmVcV7iPvTkaw2gk89yVcCzPzaS6B7


以下公鑰的 MSB 為兩個零

04BAE942CC53D51498CD2E1576C1C43F125302DEF76A8A470B818C8D6BB65A82D679232E294E6F2D1C78F35BAA272EF1585F2FFE8B88769B02FBCEDD070CE50D4B

由於 MSB 有兩個零,因此 Base58 雜湊以兩個零為基礎11ujQcjgoMNmbmcBkk8CXLWQy8ZerMtuN


以下公鑰的 MSB 為三個零

04AD8A68DF6A4553BEDD234BF2D7BFB5F0C5830F13C3A5F814AAFC03E2C92602EC1047CFE67F14D499B55F57BBE104D29E9BF6C9849771B4E3AE46FFB76FE3DFCD

由於 MSB 有三個零,因此 Base58 散列三個零 111oeV7wjVNCQttqY63jLFsg817aMEmTw

引用自:https://bitcoin.stackexchange.com/questions/22636