Ich versuche, eine Base58-Adresse in C # zu codieren und zu decodieren. Die folgende Funktion ist ein Anfang, hat aber ein paar Probleme:
Dieser Code normalisiert keine führenden Nullen (wie sieht das aus?)
Wenn diese Methode wiederholt in schneller Folge aufgerufen wird, werden viele String-Objekte erstellt, die den GC unter Druck setzen
.NET 4.5-Code
Beachten Sie, dass Sie einen Verweis auf System.Numerics hinzufügen
BigInteger bi = System.Numerics.BigInteger.Parse("00010966776006953D5567439E5E39F86A0D273BEED61967F6", NumberStyles.HexNumber);
string b58 = EncodeBase58(bi);
Console.WriteLine(b58 + Environment.NewLine + "16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM");
/// .... SNIP
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.)
// Base58Check encoding is also used for encoding private keys in the Wallet Import Format. This is formed exactly
// the same as a Bitcoin address, except that 0x80 is used for the version/application byte, and the payload is 32 bytes
// instead of 20 (a private key in Bitcoin is a single 32-byte unsigned big-endian integer). Such encodings will always
// yield a 51-character string that starts with '5', or more specifically, either '5H', '5J', or '5K'. https://en.bitcoin.it/wiki/Base58Check_encoding
const int sizeWalletImportFormat = 51;
char[] result = new char[33];
int i = 0;
while (numberToShorten >= 0 && result.Length > i)
{
var lNumberRemainder = BigInteger.Remainder(numberToShorten, (BigInteger)sBase58Alphabet.Length);
numberToShorten = numberToShorten / (BigInteger)sBase58Alphabet.Length;
result[result.Length - 1- i] = sBase58Alphabet[(int)lNumberRemainder] ;
i++;
}
return new string(result);
}
//public static long DecodeBase58(String base58StringToExpand)
//{
// long lConverted = 0;
// long lTemporaryNumberConverter = 1;
// while (base58StringToExpand.Length > 0)
// {
// String sCurrentCharacter = base58StringToExpand.Substring(base58StringToExpand.Length - 1);
// lConverted = lConverted + (lTemporaryNumberConverter * sBase58Alphabet.IndexOf(sCurrentCharacter));
// lTemporaryNumberConverter = lTemporaryNumberConverter * sBase58Alphabet.Length;
// base58StringToExpand = base58StringToExpand.Substring(0, base58StringToExpand.Length - 1);
// }
//}
Führende Nullen zu normalisieren ist in diesem Link dokumentiert, nämlich in diesem Text ganz unten:
Bei einer standardmäßigen Basiskonvertierung wäre das 0x00-Byte auf der linken Seite irrelevant (wie beim Schreiben von 052 anstelle von 52), aber im BTC-Netzwerk werden die am weitesten links stehenden Nullzeichen durch die Konvertierung getragen. Für jedes 0x00-Byte am linken Ende der Binäradresse hängen wir also ein '1'-Zeichen an die Base58-Adresse an. Aus diesem Grund beginnen die Hauptnetzwerkadressen alle mit 1.
Der folgende Code behebt das GC-Problem mit Überzuweisung und Verwerfen des String-Typs, verarbeitet jedoch die führenden Null-Bytes nicht richtig. Ich muss entweder eine Liste der erwarteten Längen pro Typ oder einen anderen Ansatz finden.
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.)
// Base58Check encoding is also used for encoding private keys in the Wallet Import Format. This is formed exactly
// the same as a Bitcoin address, except that 0x80 is used for the version/application byte, and the payload is 32 bytes
// instead of 20 (a private key in Bitcoin is a single 32-byte unsigned big-endian integer). Such encodings will always
// yield a 51-character string that starts with '5', or more specifically, either '5H', '5J', or '5K'. https://en.bitcoin.it/wiki/Base58Check_encoding
const int sizeWalletImportFormat = 51;
char[] result = new char[33];
Int32 iAlphabetLength = sBase58Alphabet.Length;
BigInteger iAlphabetLength2 = BigInteger.Parse(iAlphabetLength.ToString());
int i = 0;
while (numberToShorten >= 0 && result.Length > i)
{
var lNumberRemainder = BigInteger.Remainder(numberToShorten, iAlphabetLength2);
numberToShorten = numberToShorten / iAlphabetLength;
result[result.Length - 1- i] = sBase58Alphabet[(int)lNumberRemainder] ;
i++;
}
return new string(result);
}
Marc Clement