這個未壓縮的公鑰 RipeMD 雜湊的正確 Base58 編碼是什麼,在 31、32 或 33 位中有一個零?
我的理解是 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