/// <summary> /// Makes sure that the stamp format is either 0 or 1, just in case we /// start to support say validating another stamp format but not /// producing it in the same ship. /// </summary> /// <param name="format">A StampFormat instance.</param> private void ValidateStampFormat(StampFormat format) { if ((format != StampFormat.Version0) && (format != StampFormat.Version1)) { throw new NotSupportedException("Only version 0 and version 1 stamps are supported."); } }
public void GenerateAFormatVersionZeroStampWithADenominationOfSeventeenAndEnsureItValidatesUsingTheHashcashReferenceImplementation() { Given("a resource of '*****@*****.**'", x => Resource = "foo123456789") .And("an instance of the Minter class", x => Minter = new Minter()) .And("a denomination of sixteen", x => Denomination = 17) .And("a stamp format version of 1", x => Format = StampFormat.Version0) .When("the Mint method is called", x => Stamp = Minter.Mint(Resource, Denomination, Format)) .Then("it should generate a valid stamp", x => IsValidStamp(Denomination, Resource, Stamp, 0)); }
private static void Main(string[] args) { string resource = args[0]; int denomination = int.Parse(args[1]); StampFormat format = (StampFormat)Enum.Parse(typeof(StampFormat), $"Version{args[2]}"); Minter minter = new Minter(); string stamp = minter.Mint(resource, denomination, DateTimeOffset.UtcNow, format); Console.WriteLine(stamp); Console.WriteLine("Press a key to exit..."); Console.ReadKey(); }
/// <summary> /// Mints a stamp given the input parameters. /// </summary> /// <param name="resource">The resource that the stamp is to be minted for.</param> /// <param name="requiredDenomination">The required denomination of the stamp.</param> /// <param name="date">The date that the stamp is to be minted for.</param> /// <param name="format">The format of the stamp to be produced.</param> /// <returns>A string representation of the hashcash stamp.</returns> public string Mint(string resource, int requiredDenomination, DateTime date, StampFormat format) { this.ValidateResource(resource); this.ValidateRequiredDenomination(requiredDenomination); this.ValidateStampFormat(format); int prefixLength; byte[] blankStamp = this.CreateBlankStamp(resource, requiredDenomination, date, format, out prefixLength); byte[] collisionStamp = this.ComputePartialCollisionStamp(blankStamp, requiredDenomination, format, prefixLength); string stamp = Encoding.ASCII.GetString(collisionStamp); return(stamp); }
public static int Main(string[] args) { int returnCode = 0; try { string resource = args[0]; int denomination = int.Parse(args[1]); StampFormat format = (StampFormat)Enum.Parse(typeof(StampFormat), string.Format("Version{0}", args[2])); NHashcash.Minter minter = new NHashcash.Minter(); string stamp = minter.Mint(resource, denomination, DateTime.Now, format); Console.WriteLine(stamp); } catch (Exception ex) { Console.WriteLine(ex); returnCode = 1; } return(returnCode); }
/// <summary> /// Mints a stamp given the input parameters. /// </summary> /// <param name="resource">The resource that the stamp is to be minted for.</param> /// <param name="requiredDenomination">The required denomination of the stamp.</param> /// <param name="format">The format of the stamp to be produced.</param> /// <returns>A string representation of the hashcash stamp.</returns> public string Mint(string resource, int requiredDenomination, StampFormat format) { return(Mint(resource, requiredDenomination, DateTimeOffset.UtcNow, format)); }
/// <summary> /// Mints a stamp given the input parameters. /// </summary> /// <param name="resource">The resource that the stamp is to be minted for.</param> /// <param name="date">The date that the stamp is to be minted for.</param> /// <param name="format">The format of the stamp to be produced.</param> /// <returns>A string representation of the hashcash stamp.</returns> public string Mint(string resource, DateTimeOffset date, StampFormat format) { return(Mint(resource, DefaultDenomination, date, format)); }
/// <summary> /// Generates the stamp prefix bytes from the inputs. /// </summary> /// <param name="resource">The resource that the stamp is being produced for.</param> /// <param name="requiredDenomination">The required denomination of the stamp.</param> /// <param name="date">The date that the stamp is to be minted for.</param> /// <param name="format">The format of the stamp to be produced.</param> /// <returns>A byte array containing the stamp prefix.</returns> private byte[] GenerateStampPrefixBytes(string resource, int requiredDenomination, DateTimeOffset date, StampFormat format) { string stampPrefix = null; string stampDate = date.ToString("yymmdd"); switch (format) { case StampFormat.Version0: stampPrefix = $"0:{stampDate}:{resource}:"; break; case StampFormat.Version1: stampPrefix = $"1:{requiredDenomination}:{stampDate}:{resource}::"; break; } byte[] stampPrefixBytes = Encoding.ASCII.GetBytes(stampPrefix); return(stampPrefixBytes); }
/// <summary> /// Creates a byte array containing the stamp prefix and is padded out to the required length. /// </summary> /// <param name="resource">The resource that the stamp is being produced for.</param> /// <param name="requiredDenomination">The required denomination of the stamp.</param> /// <param name="date">The date that the stamp is to be minted for.</param> /// <param name="format">The format of the stamp.</param> /// <param name="prefixLength">The length of the stamp prefix after all its elements have been pieced together.</param> /// <returns>A byte array containing the stamp prefix and the required amount of padding.</returns> private byte[] CreateBlankStamp(string resource, int requiredDenomination, DateTimeOffset date, StampFormat format, out int prefixLength) { byte[] stampPrefixBytes = GenerateStampPrefixBytes(resource, requiredDenomination, date, format); prefixLength = stampPrefixBytes.Length; int paddedLength = CalculatePaddedLength(prefixLength); byte[] blankStamp = new byte[paddedLength]; Array.Copy(stampPrefixBytes, blankStamp, stampPrefixBytes.Length); return(blankStamp); }
/// <summary> /// This is the main part of the algorithm. It takes a blank template stamp and randomly replaces the /// characters after the prefix until /// </summary> /// <param name="blankStamp"></param> /// <param name="requiredDenomination"></param> /// <param name="format"></param> /// <param name="prefixLength"></param> /// <returns></returns> private byte[] ComputePartialCollisionStamp(byte[] blankStamp, int requiredDenomination, StampFormat format, int prefixLength) { byte[] collisionStamp = blankStamp; int randomRangeLowerLimit = prefixLength; int randomRangeUpperLimit = collisionStamp.Length; SHA1Managed provider = new SHA1Managed(); int hashCounter = 0; bool collisionFound = false; while (collisionFound == false) { if (format == StampFormat.Version1) { byte[] hashCounterBytes = CreateCounterBasedOnCharacterSet(hashCounter); Array.Copy( hashCounterBytes, 0, collisionStamp, collisionStamp.Length - hashCounterBytes.Length, hashCounterBytes.Length ); randomRangeUpperLimit = collisionStamp.Length - hashCounterBytes.Length - 1; collisionStamp[randomRangeUpperLimit] = 58; } int bytePosition = _numberGenerator.Next(randomRangeLowerLimit, randomRangeUpperLimit); byte characterByte = GetRandomCharacter(); collisionStamp[bytePosition] = characterByte; byte[] collisionStampHash = provider.ComputeHash(collisionStamp); collisionFound = IsCollisionOfRequiredDenomination(collisionStampHash, requiredDenomination); hashCounter++; } return(collisionStamp); }
/// <summary> /// Mints a stamp given the input parameters. /// </summary> /// <param name="resource">The resource that the stamp is to be minted for.</param> /// <param name="requiredDenomination">The required denomination of the stamp.</param> /// <param name="format">The format of the stamp to be produced.</param> /// <returns>A string representation of the hashcash stamp.</returns> public string Mint(string resource, int requiredDenomination, StampFormat format) { return(this.Mint(resource, requiredDenomination, DateTime.Now, format)); }
/// <summary> /// Mints a stamp given the input parameters. /// </summary> /// <param name="resource">The resource that the stamp is to be minted for.</param> /// <param name="date">The date that the stamp is to be minted for.</param> /// <param name="format">The format of the stamp to be produced.</param> /// <returns>A string representation of the hashcash stamp.</returns> public string Mint(string resource, DateTime date, StampFormat format) { return(this.Mint(resource, this.DefaultDenomination, date, format)); }
/// <summary> /// Generates the stamp prefix bytes from the inputs. /// </summary> /// <param name="resource">The resource that the stamp is being produced for.</param> /// <param name="requiredDenomination">The required denomination of the stamp.</param> /// <param name="date">The date that the stamp is to be minted for.</param> /// <param name="format">The format of the stamp to be produced.</param> /// <returns>A byte array containing the stamp prefix.</returns> private byte[] GenerateStampPrefixBytes(string resource, int requiredDenomination, DateTime date, StampFormat format) { string stampPrefix = null; string stampDate = date.ToString("yyMMdd"); switch (format) { case StampFormat.Version0: stampPrefix = string.Format( "0:{0}:{1}:", stampDate, resource ); break; case StampFormat.Version1: stampPrefix = string.Format( "1:{0}:{1}:{2}::", requiredDenomination, stampDate, resource ); break; } byte[] stampPrefixBytes = Encoding.ASCII.GetBytes(stampPrefix); return(stampPrefixBytes); }