Skip to content

Commit

Permalink
Merge pull request #1 from fluorine/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
fluorine committed Aug 26, 2017
2 parents be4e5d5 + 67b615b commit c7e45d8
Show file tree
Hide file tree
Showing 27 changed files with 2,562 additions and 0 deletions.
72 changes: 72 additions & 0 deletions CoolWallet.Core/CoolWallet.Core.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{3326E219-8092-4949-9C3B-DBE619F606D3}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>CoolWallet.Core</RootNamespace>
<AssemblyName>CoolWallet.Core</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Moserware.SecretSplitter, Version=0.12.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Moserware.SecretSplitter.0.12.0.0\lib\net40\Moserware.SecretSplitter.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\Strings.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Strings.resx</DependentUpon>
</Compile>
<Compile Include="CoolWallet\IShortNotationFormat.cs" />
<Compile Include="CoolWallet\IValidable.cs" />
<Compile Include="CoolWallet\IWallet.cs" />
<Compile Include="CoolWallet\IWalletPart.cs" />
<Compile Include="CoolWallet\IWalletSignature.cs" />
<Compile Include="CoolWallet\WalletSignature.cs" />
<Compile Include="CoolWallet\Wallet.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="CoolWallet\WalletPart.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Properties\Strings.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>Strings.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
32 changes: 32 additions & 0 deletions CoolWallet.Core/CoolWallet/IShortNotationFormat.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CoolWallet.Core
{
public interface IShortNotationFormat
{
/// <summary>
/// Get short notation to represent an object
/// with the least text possible. Useful to
/// encode data in QR codes.
/// </summary>
/// <returns>A short notation of the object.
/// Null if object does not have a valid state.
/// </returns>
string GetShortNotation();

/// <summary>
/// Interpret a given short notation for the
/// object to fill key properties.
/// </summary>
/// <param name="shortNotation">Short notation text.</param>
/// <returns>
/// True if short notation was parsed successfully.
/// False otherwise.
/// </returns>
bool InterpretShortNotation(string shortNotation);
}
}
24 changes: 24 additions & 0 deletions CoolWallet.Core/CoolWallet/IValidable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CoolWallet.Core
{
public interface IValidable
{
/// <summary>
/// Check if signature is valid.
/// </summary>
/// <returns>True if valid. False otherwise</returns>
bool IsValid();

/// <summary>
/// Check if signature is valid.
/// </summary>
/// <param name="message">Message explaining why signature is invalid.</param>
/// <returns>True if valid. False otherwise</returns>
bool IsValid(out string message);
}
}
17 changes: 17 additions & 0 deletions CoolWallet.Core/CoolWallet/IWallet.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CoolWallet.Core
{
public interface IWallet : IValidable, IEquatable<IWallet>
{
IWalletSignature Signature { get; }

string PrivateKey { get; }

IEnumerable<IWalletPart> Parts { get; }
}
}
15 changes: 15 additions & 0 deletions CoolWallet.Core/CoolWallet/IWalletPart.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CoolWallet.Core
{
public interface IWalletPart : IShortNotationFormat, IValidable, IEquatable<IWalletPart>
{
IWalletSignature Signature { get; set; }

string Data { get; set; }
}
}
28 changes: 28 additions & 0 deletions CoolWallet.Core/CoolWallet/IWalletSignature.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CoolWallet.Core
{
public interface IWalletSignature : IShortNotationFormat, IValidable, IEquatable<IWalletSignature>
{
/// <summary>
/// Version used to generate the parts of the Cold Wallet.
/// </summary>
int Version { get; }

/// <summary>
/// Numbers of parts required to recompose a Wallet (Private Key).
/// It is a numerator.
/// </summary>
int PartsThreshold { get; }

/// <summary>
/// Total of parts generated from the Wallet (Privete Key).
/// It is a denominator.
/// </summary>
int PartsTotal { get; }
}
}
142 changes: 142 additions & 0 deletions CoolWallet.Core/CoolWallet/Wallet.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
using Moserware.Security.Cryptography;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CoolWallet.Core
{
/// <summary>
/// Full representation of a Shared Cold Wallet.
/// </summary>
public class Wallet : IWallet
{
public IWalletSignature Signature { get; }

public string PrivateKey { get; private set; }

public IEnumerable<IWalletPart> Parts { get; private set; }

private Wallet(IWalletSignature signature)
{
// Validate signature
if(signature == null)
{
throw new ArgumentNullException(nameof(signature));
}

if (!signature.IsValid(out string message))
{
throw new ArgumentException(message);
}

// Add data
Signature = signature;
}

/// <summary>
/// Constructor to create a new wallet using a private key.
/// </summary>
/// <param name="signature">Signature of the wallet.</param>
/// <param name="privateKey">Private key to divide</param>
public Wallet(IWalletSignature signature, string privateKey) : this(signature)
{
// Validate private key
if (string.IsNullOrWhiteSpace(privateKey)) {
throw new ArgumentException($"Argument '{nameof(privateKey)}' is null or white space.");
}

PrivateKey = privateKey;

// Produce wallet parts
ProduceWalletParts();
}

public Wallet(IEnumerable<IWalletPart> parts) : this(parts?.FirstOrDefault()?.Signature)
{
if(parts == null || !parts.Any())
{
throw new ArgumentNullException(nameof(parts));
}

var signature = parts.First().Signature;

// Check if all parts have the same signatures
if(!parts.All(p => p.Signature.Equals(signature)))
{
throw new ArgumentException(Properties.Strings.SharesHaveDifferentSignatures);
}

// Get only unique parts. Discard shares with duplicate data.
var _parts = parts.GroupBy(i => i.Data).Select(i => i.First());

// Check if there are enough parts
if(_parts.Count() < signature.PartsThreshold)
{
throw new ArgumentException(Properties.Strings.NotEnoughShares);
}

// Validate parts
foreach(var part in _parts)
{
if(part.IsValid(out string message)) continue;

throw new ArgumentException("Invalid part: " + message);
}

Parts = _parts;

// Produce private key
var shares = _parts
.Take(signature.PartsThreshold)
.Select(i => i.Data)
.ToArray();

try
{
PrivateKey = SecretCombiner.Combine(shares).RecoveredTextString;
} catch (InvalidChecksumShareException)
{
throw new ArgumentException(Properties.Strings.ChecksumExceptionSharesCorrupt);
}
}

public bool Equals(IWallet other)
{
throw new NotImplementedException();
}

public bool IsValid()
{
return Signature.IsValid() && (PrivateKey != null || (Parts != null && Parts.Any()));
}

public bool IsValid(out string message)
{
throw new NotImplementedException();
}

private void ProduceWalletParts()
{
if (PrivateKey == null || Signature == null) return;

var _parts = new List<WalletPart>(Signature.PartsTotal);

// Generate Parts from the Private Key
var shares = SecretSplitter
.SplitMessage(PrivateKey, Signature.PartsThreshold, Signature.PartsTotal);

foreach(var share in shares)
{
_parts.Add(new WalletPart()
{
Signature = Signature,
Data = share
});
}

Parts = _parts;
}
}
}
Loading

0 comments on commit c7e45d8

Please sign in to comment.