From 9f2cd0fbb704cf49c5ce21fbf64d0b0baab49ece Mon Sep 17 00:00:00 2001 From: Harald Wolff Date: Tue, 17 Oct 2017 21:43:06 +0200 Subject: [PATCH] Diverse Updates --- Base58.cs | 44 ++++++ Block.cs | 47 ++++++ BlockTemplate.cs | 22 ++- CryptoNoteAddress.cs | 152 +++++++++++++++++++ CrytoNoteCoin.cs | 12 ++ rpc/Daemon.cs | 22 +-- cryptonote.csproj => sharp.cryptonote.csproj | 31 ++-- streams/ExtendedStreamReader.cs | 51 +++++++ tools/HexString.cs | 20 --- 9 files changed, 356 insertions(+), 45 deletions(-) create mode 100644 Base58.cs create mode 100644 Block.cs create mode 100644 CryptoNoteAddress.cs create mode 100644 CrytoNoteCoin.cs rename cryptonote.csproj => sharp.cryptonote.csproj (70%) create mode 100644 streams/ExtendedStreamReader.cs delete mode 100644 tools/HexString.cs diff --git a/Base58.cs b/Base58.cs new file mode 100644 index 0000000..5af9aaa --- /dev/null +++ b/Base58.cs @@ -0,0 +1,44 @@ +using System; +using System.Text; +namespace sharp.cryptonote +{ + public class Base58 + { + private static string Base58Letters = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; + + public static string encode(UInt64 value){ + StringBuilder sb = new StringBuilder(); + + do + { + sb.Append( Base58Letters[(int)(value % 58)] ); + value /= 58; + } while (value != 0); + + char[] encoded = sb.ToString().PadRight(11,'1').ToCharArray(); + Array.Reverse(encoded); + + return new string(encoded); + } + + public static UInt64 decode(string encoded){ + UInt64 value = 0; + + char[] chars = encoded.ToCharArray(); + //Array.Reverse(chars); + + foreach (char ch in chars){ + uint i = (uint)Base58Letters.IndexOf(ch); + if (i < 0){ + throw new FormatException(String.Format("Illegal Character found in Base58 string: {0}",ch)); + } + value *= 58; + value += i; + } + + return value; + } + + + } +} diff --git a/Block.cs b/Block.cs new file mode 100644 index 0000000..9b4ca51 --- /dev/null +++ b/Block.cs @@ -0,0 +1,47 @@ +using System; +using System.Text; +using System.IO; +using sharp.cryptonote.streams; +using sharp.extensions; +namespace sharp.cryptonote +{ + public class Block + { + Int64 major_version, minor_version, timestamp; + byte[] hash; + UInt32 nonce; + + + public Block(byte[] buffer) + { + decode( new ExtendedStreamReader(new MemoryStream(buffer) ) ); + } + + private void decode(ExtendedStreamReader reader){ + major_version = reader.readVarInt(); + minor_version = reader.readVarInt(); + timestamp = reader.readVarInt(); + hash = reader.readBytes(32); + nonce = reader.readUInt32(); + } + + + + + public byte[] toBytes(){ + return null; + } + + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.AppendFormat("[CryptoNote Block] Version: {0}.{1}, TS: {2} NONCE: {3}\n",major_version,minor_version,timestamp,nonce); + sb.AppendFormat("[CryptoNote Block] Last Blocks Hash: {0}\n",hash.toHexString()); + + return sb.ToString(); + } + + + } +} diff --git a/BlockTemplate.cs b/BlockTemplate.cs index af7b301..ae40d49 100644 --- a/BlockTemplate.cs +++ b/BlockTemplate.cs @@ -1,9 +1,10 @@ using System; -namespace cryptonote + +namespace sharp.cryptonote { public class BlockTemplate { - public BlockTemplate(byte[] blob, Int64 difficulty, Int64 height, string prev_hash, Int64 reserved_offset, Int64 reserve_size) + public BlockTemplate(byte[] blob, UInt64 difficulty, UInt64 height, string prev_hash, Int64 reserved_offset, Int64 reserve_size) { this.Blob = blob; this.Height = height; @@ -11,16 +12,27 @@ namespace cryptonote this.PreviousHash = prev_hash; this.ReservedOffset = reserved_offset; this.ReserveSize = reserve_size; - } public byte[] Blob { get; private set; } - public Int64 Difficulty { get; private set; } - public Int64 Height { get; private set; } + public UInt64 Difficulty { get; private set; } + public UInt64 Height { get; private set; } public Int64 ReservedOffset { get; private set; } public Int64 ReserveSize { get; private set; } public string PreviousHash { get; private set; } + public byte[] generateJobTemplate(byte[] jobbytes){ + byte[] blob = new byte[this.Blob.Length]; + + if (jobbytes.Length > ReserveSize){ + throw new ArgumentException("JobBytes bigger than reserved size!"); + } + + Array.Copy(this.Blob,blob,blob.Length); + Array.Copy(jobbytes, 0, blob, ReservedOffset, jobbytes.Length); + + return blob; + } diff --git a/CryptoNoteAddress.cs b/CryptoNoteAddress.cs new file mode 100644 index 0000000..94250f8 --- /dev/null +++ b/CryptoNoteAddress.cs @@ -0,0 +1,152 @@ +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 configurations = initializeConfigurations(); + + static Dictionary initializeConfigurations(){ + Dictionary r = new Dictionary(); + + 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; + } + } + + } +} diff --git a/CrytoNoteCoin.cs b/CrytoNoteCoin.cs new file mode 100644 index 0000000..4da0595 --- /dev/null +++ b/CrytoNoteCoin.cs @@ -0,0 +1,12 @@ +using System; +namespace sharp.cryptonote +{ + public enum CryptoNoteCoin + { + XMR = 0x12, + AEON = 0xB2 + }; + + + +} diff --git a/rpc/Daemon.cs b/rpc/Daemon.cs index ccf136f..0cbd537 100644 --- a/rpc/Daemon.cs +++ b/rpc/Daemon.cs @@ -1,14 +1,14 @@ -using System; +using System; using System.IO; using System.Net; using System.Net.Http; using System.Collections.Generic; using System.Threading.Tasks; -using JSONRPC; -using cryptonote.tools; +using sharp.jsonrpc; +using sharp.extensions; -namespace cryptonote.rpc +namespace sharp.cryptonote.rpc { public class Daemon { @@ -28,20 +28,20 @@ namespace cryptonote.rpc return -1; } - public BlockTemplate getBlockTemplate(string wallet,uint reserve_size){ + public BlockTemplate getBlockTemplate(CryptoNoteAddress wallet,uint reserve_size){ BlockTemplate bt = null; Response response = this.rpc.Call() - .method("getblocktemplate") - .parameter("wallet_address", wallet) - .parameter("reserve_size", 60) - .execute(); + .method("getblocktemplate") + .parameter("wallet_address", wallet.ToString()) + .parameter("reserve_size", reserve_size) + .execute(); if (response.Success()){ byte[] blob = HexString.toBytes(response.result["blocktemplate_blob"].ToString()); bt = new BlockTemplate( blob, - response.result["difficulty"].ToObject(), - response.result["height"].ToObject(), + response.result["difficulty"].ToObject(), + response.result["height"].ToObject(), response.result["prev_hash"].ToObject(), response.result["reserved_offset"].ToObject(), reserve_size diff --git a/cryptonote.csproj b/sharp.cryptonote.csproj similarity index 70% rename from cryptonote.csproj rename to sharp.cryptonote.csproj index 31b5c12..c11de02 100644 --- a/cryptonote.csproj +++ b/sharp.cryptonote.csproj @@ -5,7 +5,7 @@ AnyCPU {52C68C13-2DC2-438A-9EC1-E8C4953B07DF} Library - cryptonote + sharp.cryptonote cryptonote v4.5 @@ -32,26 +32,39 @@ ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll + - - - - - {DCE6066E-9709-4D12-8994-F7879C3557D6} - JSONRPC - + + + + + - + + + + {DCE6066E-9709-4D12-8994-F7879C3557D6} + sharp.jsonrpc + + + {CCD7C196-B079-4AA7-98AF-5BECAD089CE4} + sharp.hashing + + + {97CA3CA9-98B3-4492-B072-D7A5995B68E9} + sharp.extensions + + diff --git a/streams/ExtendedStreamReader.cs b/streams/ExtendedStreamReader.cs new file mode 100644 index 0000000..b5d7590 --- /dev/null +++ b/streams/ExtendedStreamReader.cs @@ -0,0 +1,51 @@ +using System; +using System.IO; +namespace sharp.cryptonote.streams +{ + public class ExtendedStreamReader + { + Stream stream; + + public ExtendedStreamReader(Stream stream) + { + this.stream = stream; + } + + public Int64 readVarInt(){ + Int64 result = 0; + int t, s; + + s = 0; + + do + { + t = stream.ReadByte(); + if (t == 0){ + break; + } + + //result *= 128; + //result += t & 0x7F; + result |= (t & 0x7F) << s; + s += 7; + + } while (t >= 128); + + return result; + } + + public byte[] readBytes(int len){ + byte[] buffer = new byte[len]; + stream.Read(buffer,0,len); + return buffer; + } + + public UInt32 readUInt32() + { + byte[] t = new byte[4]; + stream.Read(t,0,4); + return BitConverter.ToUInt32(t, 0); + } + + } +} diff --git a/tools/HexString.cs b/tools/HexString.cs deleted file mode 100644 index bb330e4..0000000 --- a/tools/HexString.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -namespace cryptonote.tools -{ - public class HexString - { - public static byte[] toBytes(string hexstring) - { - byte[] bytes = new byte[hexstring.Length >> 1]; - for (int n = 0; n < hexstring.Length >> 1;n++){ - bytes[n] = Convert.ToByte(hexstring.Substring(n << 1, 2), 16); - } - return bytes; - } - - public static String toString(byte[] bytes){ - return BitConverter.ToString(bytes).Replace("-", String.Empty); - } - - } -}