153 lines
4.0 KiB
C#
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;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|