Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
192 changes: 173 additions & 19 deletions Discreet/Coin/Address.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,20 @@

namespace Discreet.Coin
{
/// <summary>
/// AddressType defines types of addresses, and thus, types of transactions
/// that are handled by those addresses.
/// </summary>
public enum AddressType: byte
{
STEALTH = 0,
TRANSPARENT = 1,
}

/// <summary>
/// IAddress defines methods that are common to all the addresses defined in
/// AddressType.
/// </summary>
public interface IAddress
{
public byte[] Bytes();
Expand All @@ -24,16 +32,18 @@ public interface IAddress
public byte Type();
}

/* standard versioner for addresses */
/// <summary>
/// AddressVersion defines the standard versioner for addresses.
/// </summary>
public static class AddressVersion
{
public static byte VERSION = 1;
}

[StructLayout(LayoutKind.Sequential)]
/**
* TAddress is the Discreet Transparent address class.
*/
/// <summary>
/// TAddress is the Discreet transparent address class.
/// </summary>
public class TAddress: IAddress
{
[MarshalAs(UnmanagedType.U1)]
Expand All @@ -45,6 +55,22 @@ public class TAddress: IAddress
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] checksum;

/// <summary>
/// TAddress initializes the version, hash and checksum of the
/// transparent address.
/// </summary>
public TAddress()
{
version = 0;
hash = new Cipher.RIPEMD160(new byte[20], false);
checksum = new byte[4];
}

/// <summary>
/// TAddress initialize the version, hash and checksum of the
/// transparent address. Uses a public key to generate the hash.
/// </summary>
/// <param name="pk">A public key.</param>
public TAddress(Cipher.Key pk)
{
version = AddressVersion.VERSION;
Expand All @@ -58,13 +84,12 @@ public TAddress(Cipher.Key pk)
checksum = Cipher.Base58.GetCheckSum(chk);
}

public TAddress()
{
version = 0;
hash = new Cipher.RIPEMD160(new byte[20], false);
checksum = new byte[4];
}

/// <summary>
/// TAddress initializes the version, hash and checksum of the
/// transparent address. Uses a byte array to initialize these fields.
/// </summary>
/// <param name="bytes">Byte array containing the version, hash and
/// checksum of a transparent address.</param>
public TAddress(byte[] bytes)
{
version = bytes[0];
Expand All @@ -75,6 +100,15 @@ public TAddress(byte[] bytes)
Array.Copy(bytes, 21, checksum, 0, 4);
}

/// <summary>
/// TAddress initializes the version, hash and checksum of the
/// transparent address. Uses a byte array to initialize these fields,
/// retrieving bytes starting from an offset.
/// </summary>
/// <param name="bytes">Byte array containing the version, hash and
/// checksum.</param>
/// <param name="offset">Offset which indicates from
/// what index we can start reading to find the relevant data.</param>
public TAddress(byte[] bytes, uint offset)
{
version = bytes[offset];
Expand All @@ -85,6 +119,12 @@ public TAddress(byte[] bytes, uint offset)
Array.Copy(bytes, offset + 21, checksum, 0, 4);
}

/// <summary>
/// TAddress initializes the version, hash and checksum of the
/// transparent address. Uses a stream of bytes to initialize these
/// fields.
/// </summary>
/// <param name="s">A stream of bytes.</param>
public TAddress(Stream s)
{
version = (byte)s.ReadByte();
Expand All @@ -95,6 +135,12 @@ public TAddress(Stream s)
s.Read(checksum);
}

/// <summary>
/// TAddress initializes the version, hash and checksum of the
/// transparent address. Uses an address to initialize the version,
/// hash and checksum.
/// </summary>
/// <param name="addr">A string representing an address.</param>
public TAddress(string addr)
{
byte[] bytes = Cipher.Base58.DecodeWhole(addr);
Expand All @@ -114,11 +160,20 @@ public TAddress(string addr)
Array.Copy(bytes, 21, checksum, 0, 4);
}

/// <summary>
/// Size returns the size of the transparent address.
/// </summary>
public uint Size()
{
return 25;
}

/// <summary>
/// Bytes creates a byte array representation of the transparent
/// address, where the first byte is the version, the following 20 bytes
/// are the hash, and the remaining 4 are the checksum.
/// </summary>
/// <returns>The byte array representation of the transparent address.</returns>
public byte[] Bytes()
{
byte[] rv = new byte[Size()];
Expand All @@ -130,6 +185,11 @@ public byte[] Bytes()
return rv;
}

/// <summary>
/// FromBytes initializes the transparent address (version, hash and
/// checksum) from an array of bytes.
/// </summary>
/// <param name="bytes">The byte array representation of the transparent address.</param>
public void FromBytes(byte[] bytes)
{
version = bytes[0];
Expand All @@ -139,26 +199,46 @@ public void FromBytes(byte[] bytes)
Array.Copy(bytes, 21, checksum, 0, 4);
}

/// <summary>
/// ToString generates a string representation of the transparent address.
/// </summary>
/// <returns>A string representation of the transparent address.</returns>
public override string ToString()
{
return Cipher.Base58.EncodeWhole(Bytes());
}

/// <summary>
/// Checksum returns the checksum of the transparent address.
/// </summary>
/// <returns>The checksum.</returns>
public byte[] Checksum()
{
return checksum;
}

/// <summary>
/// Version returns the version of the transparent address.
/// </summary>
/// <returns>The version.</returns>
public byte Version()
{
return version;
}

/// <summary>
/// Type returns the type of this address, which is transparent.
/// </summary>
/// <returns>The type of the address.</returns>
public byte Type()
{
return (byte)AddressType.TRANSPARENT;
}

/// <summary>
/// Verify verifies that the version and checksum of a transparent address are valid.
/// </summary>
/// <returns>An exception, in case of an error, null otherwise.</returns>
public VerifyException Verify()
{
if (version != 1)
Expand All @@ -183,6 +263,12 @@ public VerifyException Verify()
return null;
}

/// <summary>
/// CheckAddressBytes determines if the given public key matches the
/// address of this transparent address.
/// </summary>
/// <param name="pk">A public key.</param>
/// <returns>True if the addresses match, false otherwise.</returns>
public bool CheckAddressBytes(Cipher.Key pk)
{
var pkh = Cipher.RIPEMD160.HashData(Cipher.SHA256.HashData(pk.bytes).Bytes);
Expand All @@ -191,9 +277,9 @@ public bool CheckAddressBytes(Cipher.Key pk)
}

[StructLayout(LayoutKind.Sequential)]
/**
* StealthAddress is the Discreet shielded/private address class (i.e. dual key wallet).
*/
/// <summary>
/// StealthAddress is the Discreet shielded/private address class (i.e. dual key wallet).
/// </summary>
public class StealthAddress : IAddress
{
[MarshalAs(UnmanagedType.U1)]
Expand All @@ -208,6 +294,12 @@ public class StealthAddress : IAddress
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] checksum;

/// <summary>
/// StealthAddress initializes the view and spend keys, as well as the
/// version and checksum of the stealth address.
/// </summary>
/// <param name="vk">A view key.</param>
/// <param name="pk">A spend key.</param>
public StealthAddress(Cipher.Key vk, Cipher.Key sk)
{
version = AddressVersion.VERSION;
Expand All @@ -223,6 +315,13 @@ public StealthAddress(Cipher.Key vk, Cipher.Key sk)
checksum = Cipher.Base58.GetCheckSum(chk);
}

/// <summary>
/// StealthAddress initializes the view and spend keys, as well as the
/// version and checksum of the stealth address. Uses a byte array to
/// initialize these fields.
/// </summary>
/// <param name="bytes">Byte array containing the view and spend keys,
/// version, hash and checksum of a stealth address.</param>
public StealthAddress(byte[] bytes)
{
if (bytes.Length != Size())
Expand All @@ -240,6 +339,15 @@ public StealthAddress(byte[] bytes)
Array.Copy(bytes, 65, checksum, 0, 4);
}

/// <summary>
/// StealthAddress initializes the view and spend keys, as well as the
/// version and checksum of the stealth address. Uses a byte array to
/// initialize these fields, retrieving bytes starting from an offset.
/// </summary>
/// <param name="bytes">Byte array containing the view and spend keys,
/// version, hash and checksum of a stealth address.</param>
/// <param name="offset">Offset which indicates from
/// what index we can start reading to find the relevant data.</param>
public StealthAddress(byte[] bytes, uint offset)
{
version = bytes[offset];
Expand All @@ -253,6 +361,12 @@ public StealthAddress(byte[] bytes, uint offset)
Array.Copy(bytes, offset + 65, checksum, 0, 4);
}

/// <summary>
/// StealthAddress initializes the view and spend keys, as
/// well as the version and checksum of the stealth address. Uses a
/// stream of bytes to initialize these fields.
/// </summary>
/// <param name="bytes">A stream of bytes.</param>
public StealthAddress(Stream s)
{
version = (byte) s.ReadByte();
Expand All @@ -264,6 +378,12 @@ public StealthAddress(Stream s)
s.Read(checksum);
}

/// <summary>
/// StealthAddress initializes the view and spend keys, as
/// well as the version and checksum of the stealth address. Uses an
/// address to initialize the version, hash and checksum.
/// </summary>
/// <param name="bytes">A string representing an address.</param>
public StealthAddress(string data)
{
byte[] bytes = Cipher.Base58.Decode(data);
Expand All @@ -284,11 +404,21 @@ public StealthAddress(string data)
Array.Copy(bytes, 65, checksum, 0, 4);
}

/// <summary>
/// Size returns the size of the stealth address.
/// </summary>
public uint Size()
{
return 69;
}

/// <summary>
/// Bytes creates a byte array representation of the stealth address,
/// where the first byte is the version, the following 32 bytes are the
/// spend key, the next 32 bytes are the view key, and the remaining 4
/// are the checksum.
/// </summary>
/// <returns>The byte array representation of the stealth address.</returns>
public byte[] Bytes()
{
byte[] rv = new byte[Size()];
Expand All @@ -301,21 +431,50 @@ public byte[] Bytes()
return rv;
}

/// <summary>
/// ToString generates a string representation of the stealth address.
/// </summary>
/// <returns>A string representation of the stealth address.</returns>
public override string ToString()
{
return Cipher.Base58.Encode(Bytes());
}

/// <summary>
/// Checksum returns the checksum of the stealth address.
/// </summary>
/// <returns>The checksum.</returns>
public byte[] Checksum()
{
return checksum;
}

/// <summary>
/// Version returns the version of the stealth address.
/// </summary>
/// <returns>The version.</returns>
public byte Version()
{
return version;
}

/// <summary>
/// Type returns the type of this address, which is stealth.
/// </summary>
/// <returns>The type of the address.</returns>
public byte Type()
{
return (byte)AddressType.STEALTH;
}

/// <summary>
/// Verify verifies that the following properties are correct in the stealth address:
/// - The spend and view keys are in the main subgroup.
/// - The address has a valid length.
/// - The version is valid.
/// - The checksum is valid.
/// </summary>
/// <returns>An exception, in case of an error, null otherwise.</returns>
public VerifyException Verify()
{
if (!Cipher.KeyOps.InMainSubgroup(ref spend))
Expand Down Expand Up @@ -357,10 +516,5 @@ public VerifyException Verify()

return null;
}

public byte Type()
{
return (byte)AddressType.STEALTH;
}
}
}
Loading