sharp-cryptonote-tool/CryptoNoteAddress.cs

153 lines
4.0 KiB
C#

using System;
using sharp.extensions;
using sharp.hashing;
using System.Text;
using System.Collections.Generic;
namespace sharp.cryptonote
{
public class CryptoNoteAddress
{
static IHash keccak256 = Hashes.createKECCAK_256();
static Dictionary<CryptoNoteCoin, CoinConfiguration> configurations = initializeConfigurations();
static Dictionary<CryptoNoteCoin, CoinConfiguration> initializeConfigurations(){
Dictionary<CryptoNoteCoin, CoinConfiguration> r = new Dictionary<CryptoNoteCoin, CoinConfiguration>();
r.Add(CryptoNoteCoin.XMR,new CoinConfiguration(95,4));
r.Add(CryptoNoteCoin.AEON,new CoinConfiguration(97,6));
return r;
}
byte[] address;
public CryptoNoteAddress(string address)
{
if (address.Length < 11){
throw new ArgumentException("Invalid Cryptonote Address, len(..) < 11");
}
byte[] prefix = new byte[8];
base58uint64decode2array(address.Substring(0, 11),prefix,0,8);
CryptoNoteCoin prefixCoin = (CryptoNoteCoin)prefix[0];
if (address.Length != configurations[prefixCoin].PublicAddressLen){
throw new ArgumentException(String.Format("Invalid Cryptonote Address, len(..) != {0}",configurations[prefixCoin].PublicAddressLen));
}
string[] parts = address.splitConstantWidth(11);
byte[] binary = new byte[69];
for (int n = 0; n< 8;n++){
base58uint64decode2array(parts[n], binary, n * 8);
}
base58uint64decode2array(parts[8], binary, 64, 5);
setup(binary);
}
public CryptoNoteAddress(byte[] address){
if (address.Length != 69){
throw new ArgumentException("Invalid Cryptonote Address, binary len(..) != 69");
}
setup(address);
}
public CryptoNoteAddress(CryptoNoteCoin coin){
this.address = new byte[59];
this.address[0] = (byte)coin;
updateChecksum();
}
private void setup(byte[] a){
this.address = a.Segment(0);
byte[] checksum = keccak256.compute(this.address.Segment(0, 65)).Segment(0,4);
if (!checksum.ArrayEquals(this.address.Segment(65,4))){
throw new ArgumentException("CheckSum failed for CryptoNote Address");
}
}
private void updateChecksum(){
byte[] checksum = keccak256.compute(this.address.Segment(0, 65));
Array.Copy(checksum,0,this.address,65,4);
}
public CryptoNoteCoin CryptoNoteCoin {
get { return (CryptoNoteCoin)this.address[0]; }
set { this.address[0] = (byte)value; updateChecksum(); }
}
public byte[] PublicSpendKey {
get { return this.address.Segment(1, 32); }
set {
if (value.Length != 32){
throw new ArgumentException("Invalid SpendKey, len != 32");
}
Array.Copy(value,0,this.address,1,32);
updateChecksum();
}
}
public byte[] PublicViewKey {
get { return this.address.Segment(33, 32); }
set {
if (value.Length != 32){
throw new ArgumentException("Invalid ViewKey, len != 32");
}
Array.Copy(value,0,this.address,33,32);
updateChecksum();
}
}
public byte[] CheckSum {
get { return this.address.Segment(65, 4); }
}
public byte[] toBytes() {
return this.address.Segment(0);
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
for (int n = 0; n < 9;n++){
byte[] part = this.address.Segment(n * 8, n < 8 ? 8 : 5);
if (BitConverter.IsLittleEndian){
Array.Reverse(part);
}
UInt64 ui64 = BitConverter.ToUInt64(part.Extend(8),0);
if (n == 8){
sb.Append( Base58.encode(ui64).Substring(4) );
} else {
sb.Append( Base58.encode(ui64) );
}
}
return sb.ToString();
}
private static bool base58uint64decode2array(string b58, byte[] buffer, int pos, int length = 8)
{
byte[] t = BitConverter.GetBytes(Base58.decode(b58));
if (BitConverter.IsLittleEndian)
{
Array.Reverse(t);
}
Array.Copy(t, t.Length - length, buffer, pos, length);
return true;
}
struct CoinConfiguration {
public readonly int CheckSumSize,
PublicAddressLen;
public CoinConfiguration(int palen,int CheckSumSize){
this.PublicAddressLen = palen;
this.CheckSumSize = CheckSumSize;
}
}
}
}