diff --git a/src/CorrelationVector.sln b/src/CorrelationVector.sln
new file mode 100644
index 0000000..edfa58f
--- /dev/null
+++ b/src/CorrelationVector.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.27130.2027
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CorrelationVector", "Microsoft.CorrelationVector\Microsoft.CorrelationVector.csproj", "{6F211D1F-0E72-4C05-9B9B-4DEC3AF01B38}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CorrelationVector.UnitTests", "Microsoft.CorrelationVector.UnitTests\Microsoft.CorrelationVector.UnitTests.csproj", "{EBE497F1-56EA-4BEA-B834-AEEE261BA6B8}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {6F211D1F-0E72-4C05-9B9B-4DEC3AF01B38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6F211D1F-0E72-4C05-9B9B-4DEC3AF01B38}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6F211D1F-0E72-4C05-9B9B-4DEC3AF01B38}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6F211D1F-0E72-4C05-9B9B-4DEC3AF01B38}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EBE497F1-56EA-4BEA-B834-AEEE261BA6B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {EBE497F1-56EA-4BEA-B834-AEEE261BA6B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EBE497F1-56EA-4BEA-B834-AEEE261BA6B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {EBE497F1-56EA-4BEA-B834-AEEE261BA6B8}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {0421635B-CD1D-4001-8D21-FA1A33F7B83E}
+ EndGlobalSection
+EndGlobal
diff --git a/src/Microsoft.CorrelationVector.UnitTests/CorrelationVectorTests.cs b/src/Microsoft.CorrelationVector.UnitTests/CorrelationVectorTests.cs
new file mode 100644
index 0000000..900cc70
--- /dev/null
+++ b/src/Microsoft.CorrelationVector.UnitTests/CorrelationVectorTests.cs
@@ -0,0 +1,115 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using Microsoft.CorrelationVector;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace Microsoft.CorrelationVector.UnitTests
+{
+ [TestClass]
+ public class CorrelationVectorTests
+ {
+ [TestMethod]
+ public void SimpleCreateCorrelationVectorTest()
+ {
+ var correlationVector = new CorrelationVector();
+ var splitVector = correlationVector.Value.Split('.');
+
+ Assert.AreEqual(2, splitVector.Length, "Correlation Vector should be created with two components separated by a '.'");
+ Assert.AreEqual(16, splitVector[0].Length, "Correlation Vector base should be 16 character long");
+ Assert.AreEqual("0", splitVector[1], "Correlation Vector extension should start with zero");
+ }
+
+ [TestMethod]
+ public void CreateV1CorrelationVectorTest()
+ {
+ var correlationVector = new CorrelationVector(CorrelationVectorVersion.V1);
+ var splitVector = correlationVector.Value.Split('.');
+
+ Assert.AreEqual(2, splitVector.Length, "Correlation Vector should be created with two components separated by a '.'");
+ Assert.AreEqual(16, splitVector[0].Length, "Correlation Vector base should be 16 character long");
+ Assert.AreEqual("0", splitVector[1], "Correlation Vector extension should start with zero");
+ }
+
+ [TestMethod]
+ public void CreateV2CorrelationVectorTest()
+ {
+ var correlationVector = new CorrelationVector(CorrelationVectorVersion.V2);
+ var splitVector = correlationVector.Value.Split('.');
+
+ Assert.AreEqual(2, splitVector.Length, "Correlation Vector should be created with two components separated by a '.'");
+ Assert.AreEqual(22, splitVector[0].Length, "Correlation Vector base should be 22 character long");
+ Assert.AreEqual("0", splitVector[1], "Correlation Vector extension should start with zero");
+ }
+
+ [TestMethod]
+ public void CreateCorrelationVectorFromGuidTest()
+ {
+ var guid = System.Guid.NewGuid();
+ var correlationVector = new CorrelationVector(guid);
+ var splitVector = correlationVector.Value.Split('.');
+
+ Assert.AreEqual(2, splitVector.Length, "Correlation Vector should be created with two components separated by a '.'");
+ Assert.AreEqual(22, splitVector[0].Length, "Correlation Vector base should be 22 character long");
+ Assert.AreEqual("0", splitVector[1], "Correlation Vector extension should start with zero");
+ }
+
+ [TestMethod]
+ public void ParseCorrelationVectorV1Test()
+ {
+ var correlationVector = CorrelationVector.Parse("ifCuqpnwiUimg7Pk.1");
+ var splitVector = correlationVector.Value.Split('.');
+
+ Assert.AreEqual("ifCuqpnwiUimg7Pk", splitVector[0], "Correlation Vector base was not parsed properly");
+ Assert.AreEqual("1", splitVector[1], "Correlation Vector extension was not parsed properly");
+ }
+
+ [TestMethod]
+ public void ParseCorrelationVectorV2Test()
+ {
+ var correlationVector = CorrelationVector.Parse("Y58xO9ov0kmpPvkiuzMUVA.3.4.5");
+ var splitVector = correlationVector.Value.Split('.');
+
+ Assert.AreEqual(4, splitVector.Length, "Correlation Vector was not parsed properly");
+ Assert.AreEqual("Y58xO9ov0kmpPvkiuzMUVA", splitVector[0], "Correlation Vector base was not parsed properly");
+ Assert.AreEqual("3", splitVector[1], "Correlation Vector extension was not parsed properly");
+ Assert.AreEqual("4", splitVector[2], "Correlation Vector extension was not parsed properly");
+ Assert.AreEqual("5", splitVector[3], "Correlation Vector extension was not parsed properly");
+ }
+
+ [TestMethod]
+ public void SimpleIncrementCorrelationVectorTest()
+ {
+ var correlationVector = new CorrelationVector();
+ correlationVector.Increment();
+ var splitVector = correlationVector.Value.Split('.');
+ Assert.AreEqual("1", splitVector[1], "Correlation Vector extension should have been incremented by one");
+ }
+
+ [TestMethod]
+ public void SimpleExtendCorrelationVectorTest()
+ {
+ var correlationVector = new CorrelationVector();
+ var splitVector = correlationVector.Value.Split('.');
+ var vectorBase = splitVector[0];
+ var extension = splitVector[1];
+
+ correlationVector = CorrelationVector.Extend(correlationVector.Value);
+ splitVector = correlationVector.Value.Split('.');
+
+ Assert.AreEqual(3, splitVector.Length, "Correlation Vector should contain 3 components separated by a '.' after extension");
+ Assert.AreEqual(vectorBase, splitVector[0], "Correlation Vector base should contain the same base after extension");
+ Assert.AreEqual(extension, splitVector[1], "Correlation Vector should preserve original ");
+ Assert.AreEqual("0", splitVector[2], "Correlation Vector new extension should start with zero");
+ }
+
+ public void ValidateCreationTest()
+ {
+ CorrelationVector.ValidateCorrelationVectorDuringCreation = true;
+ var correlationVector = new CorrelationVector();
+ correlationVector.Increment();
+ var splitVector = correlationVector.Value.Split('.');
+ Assert.AreEqual("1", splitVector[1], "Correlation Vector extension should have been incremented by one");
+ }
+ }
+}
diff --git a/src/Microsoft.CorrelationVector.UnitTests/Microsoft.CorrelationVector.UnitTests.csproj b/src/Microsoft.CorrelationVector.UnitTests/Microsoft.CorrelationVector.UnitTests.csproj
new file mode 100644
index 0000000..75628a8
--- /dev/null
+++ b/src/Microsoft.CorrelationVector.UnitTests/Microsoft.CorrelationVector.UnitTests.csproj
@@ -0,0 +1,19 @@
+
+
+
+ netcoreapp2.0
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Microsoft.CorrelationVector/CorrelationVector.cs b/src/Microsoft.CorrelationVector/CorrelationVector.cs
new file mode 100644
index 0000000..28091e9
--- /dev/null
+++ b/src/Microsoft.CorrelationVector/CorrelationVector.cs
@@ -0,0 +1,350 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Threading;
+using System.Globalization;
+
+namespace Microsoft.CorrelationVector
+{
+ ///
+ /// This class represents a lightweight vector for identifying and measuring
+ /// causality.
+ ///
+ public sealed partial class CorrelationVector : MarshalByRefObject
+ {
+ private const byte MaxVectorLength = 63;
+ private const byte MaxVectorLengthV2 = 127;
+ private const byte BaseLength = 16;
+ private const byte BaseLengthV2 = 22;
+
+ private readonly string baseVector = null;
+
+ private int extension = 0;
+
+ private static Random rng = new Random();
+
+ ///
+ /// This is the header that should be used between services to pass the correlation
+ /// vector.
+ ///
+ public const string HeaderName = "MS-CV";
+
+ ///
+ /// Gets or sets a value indicating whether or not to validate the correlation
+ /// vector on creation.
+ ///
+ public static bool ValidateCorrelationVectorDuringCreation { get; set; }
+
+ ///
+ /// Creates a new correlation vector by extending an existing value. This should be
+ /// done at the entry point of an operation.
+ ///
+ ///
+ /// Taken from the message header indicated by .
+ ///
+ /// A new correlation vector extended from the current vector.
+ public static CorrelationVector Extend(string correlationVector)
+ {
+ CorrelationVectorVersion version = CorrelationVector.InferVersion(
+ correlationVector, CorrelationVector.ValidateCorrelationVectorDuringCreation);
+
+ if (CorrelationVector.ValidateCorrelationVectorDuringCreation)
+ {
+ CorrelationVector.Validate(correlationVector, version);
+ }
+
+ return new CorrelationVector(correlationVector, 0, version);
+ }
+
+ ///
+ /// Creates a new correlation vector by applying the Spin operator to an existing value.
+ /// This should be done at the entry point of an operation.
+ ///
+ ///
+ /// Taken from the message header indicated by .
+ ///
+ /// A new correlation vector extended from the current vector.
+ public static CorrelationVector Spin(string correlationVector)
+ {
+ SpinParameters defaultParameters = new SpinParameters
+ {
+ Interval = SpinCounterInterval.Coarse,
+ Periodicity = SpinCounterPeriodicity.Short,
+ Entropy = SpinEntropy.Two
+ };
+
+ return CorrelationVector.Spin(correlationVector, defaultParameters);
+ }
+
+ ///
+ /// Creates a new correlation vector by applying the Spin operator to an existing value.
+ /// This should be done at the entry point of an operation.
+ ///
+ ///
+ /// Taken from the message header indicated by .
+ ///
+ ///
+ /// The parameters to use when applying the Spin operator.
+ ///
+ /// A new correlation vector extended from the current vector.
+ public static CorrelationVector Spin(string correlationVector, SpinParameters parameters)
+ {
+ CorrelationVectorVersion version = CorrelationVector.InferVersion(
+ correlationVector, CorrelationVector.ValidateCorrelationVectorDuringCreation);
+
+ if (CorrelationVector.ValidateCorrelationVectorDuringCreation)
+ {
+ CorrelationVector.Validate(correlationVector, version);
+ }
+
+ byte[] entropy = new byte[parameters.EntropyBytes];
+ rng.NextBytes(entropy);
+
+ ulong value = (ulong)(DateTime.UtcNow.Ticks >> parameters.TicksBitsToDrop);
+ for (int i = 0; i < parameters.EntropyBytes; i++)
+ {
+ value = (value << 8) | Convert.ToUInt64(entropy[i]);
+ }
+
+ // Generate a bitmask and mask the lower TotalBits in the value.
+ // The mask is generated by (1 << TotalBits) - 1. We need to handle the edge case
+ // when shifting 64 bits, as it wraps around.
+ value &= (parameters.TotalBits == 64 ? 0 : (ulong)1 << parameters.TotalBits) - 1;
+
+ string s = unchecked((uint)value).ToString();
+ if (parameters.TotalBits > 32)
+ {
+ s = string.Concat((value >> 32).ToString(), ".", s);
+ }
+
+ return new CorrelationVector(string.Concat(correlationVector, ".", s), 0, version);
+ }
+
+ ///
+ /// Creates a new correlation vector by parsing its string representation
+ ///
+ /// correlationVector
+ /// CorrelationVector
+ public static CorrelationVector Parse(string correlationVector)
+ {
+ if (!string.IsNullOrEmpty(correlationVector))
+ {
+ int p = correlationVector.LastIndexOf('.');
+ if (p > 0)
+ {
+ int extension;
+ if (int.TryParse(correlationVector.Substring(p + 1), out extension) && extension >= 0)
+ {
+ return new CorrelationVector(correlationVector.Substring(0, p), extension, CorrelationVector.InferVersion(correlationVector, false));
+ }
+ }
+ }
+
+ return new CorrelationVector();
+ }
+
+ ///
+ /// Initializes a new instance of the class. This
+ /// should only be called when no correlation vector was found in the message
+ /// header.
+ ///
+ public CorrelationVector()
+ : this(CorrelationVectorVersion.V1)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class of the
+ /// given implemenation version. This should only be called when no correlation
+ /// vector was found in the message header.
+ ///
+ /// The correlation vector implemenation version.
+ public CorrelationVector(CorrelationVectorVersion version)
+ : this(CorrelationVector.GetUniqueValue(version), 0, version)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class of the
+ /// V2 implemenation using the given as the vector base.
+ ///
+ /// The to use as a correlation
+ /// vector base.
+ public CorrelationVector(Guid vectorBase)
+ : this(CorrelationVector.GetBaseFromGuid(vectorBase), 0, CorrelationVectorVersion.V2)
+ {
+ }
+
+ ///
+ /// Gets the value of the correlation vector as a string.
+ ///
+ public string Value
+ {
+ get
+ {
+ return string.Concat(this.baseVector, ".", this.extension);
+ }
+ }
+
+ ///
+ /// Increments the current extension by one. Do this before passing the value to an
+ /// outbound message header.
+ ///
+ ///
+ /// The new value as a string that you can add to the outbound message header
+ /// indicated by .
+ ///
+ public string Increment()
+ {
+ int snapshot = 0;
+ int next = 0;
+ do
+ {
+ snapshot = this.extension;
+ if (snapshot == int.MaxValue)
+ {
+ return this.Value;
+ }
+ next = snapshot + 1;
+ int size = baseVector.Length + 1 + (int)Math.Log10(next) + 1;
+ if ((this.Version == CorrelationVectorVersion.V1 &&
+ size > CorrelationVector.MaxVectorLength) ||
+ (this.Version == CorrelationVectorVersion.V2 &&
+ size > CorrelationVector.MaxVectorLengthV2))
+ {
+ return this.Value;
+ }
+ }
+ while (snapshot != Interlocked.CompareExchange(ref this.extension, next, snapshot));
+ return string.Concat(this.baseVector, ".", next);
+ }
+
+ ///
+ /// Gets the version of the correlation vector implementation.
+ ///
+ public CorrelationVectorVersion Version
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Returns a string that represents the current object.
+ ///
+ /// A string that represents the current object.
+ public override string ToString()
+ {
+ return this.Value;
+ }
+
+ ///
+ /// Determines whether two instances of the class
+ /// are equal.
+ ///
+ ///
+ /// The correlation vector you want to compare with the current correlation vector.
+ ///
+ ///
+ /// True if the specified correlation vector is equal to the current correlation
+ /// vector; otherwise, false.
+ ///
+ public bool Equals(CorrelationVector vector)
+ {
+ return string.Equals(this.Value, vector.Value, StringComparison.Ordinal);
+ }
+
+ private CorrelationVector(string baseVector, int extension, CorrelationVectorVersion version)
+ {
+ this.baseVector = baseVector;
+ this.extension = extension;
+ this.Version = version;
+ }
+
+ private static string GetBaseFromGuid(Guid guid)
+ {
+ byte[] bytes = guid.ToByteArray();
+
+ // Removes the base64 padding
+ return Convert.ToBase64String(bytes).Substring(0, CorrelationVector.BaseLengthV2);
+ }
+
+ private static string GetUniqueValue(CorrelationVectorVersion version)
+ {
+ if (CorrelationVectorVersion.V1 == version)
+ {
+ byte[] bytes = Guid.NewGuid().ToByteArray();
+ return Convert.ToBase64String(bytes, 0, 12);
+ }
+ else if (CorrelationVectorVersion.V2 == version)
+ {
+ return CorrelationVector.GetBaseFromGuid(Guid.NewGuid());
+ }
+ else
+ {
+ throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "Unsupported correlation vector version: {0}", version));
+ }
+ }
+
+ private static CorrelationVectorVersion InferVersion(string correlationVector, bool reportErrors)
+ {
+ int index = correlationVector == null ? -1 : correlationVector.IndexOf('.');
+
+ if (CorrelationVector.BaseLength == index)
+ {
+ return CorrelationVectorVersion.V1;
+ }
+ else if (CorrelationVector.BaseLengthV2 == index)
+ {
+ return CorrelationVectorVersion.V2;
+ }
+ else
+ {
+ throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, "Invalid correlation vector {0}", correlationVector));
+ }
+ }
+
+ private static void Validate(string correlationVector, CorrelationVectorVersion version)
+ {
+ byte maxVectorLength;
+ byte baseLength;
+
+ if (CorrelationVectorVersion.V1 == version)
+ {
+ maxVectorLength = CorrelationVector.MaxVectorLength;
+ baseLength = CorrelationVector.BaseLength;
+ }
+ else if (CorrelationVectorVersion.V2 == version)
+ {
+ maxVectorLength = CorrelationVector.MaxVectorLengthV2;
+ baseLength = CorrelationVector.BaseLengthV2;
+ }
+ else
+ {
+ throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "Unsupported correlation vector version: {0}", version));
+ }
+
+ if (string.IsNullOrWhiteSpace(correlationVector) || correlationVector.Length > maxVectorLength)
+ {
+ throw new ArgumentException(string.Format(CultureInfo.InvariantCulture,
+ "The {0} correlation vector can not be null or bigger than {1} characters", version, maxVectorLength));
+ }
+
+ string[] parts = correlationVector.Split('.');
+
+ if (parts.Length < 2 || parts[0].Length != baseLength)
+ {
+ throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Invalid correlation vector {0}. Invalid base value {1}", correlationVector, parts[0]));
+ }
+
+ for (int i = 1; i < parts.Length; i++)
+ {
+ int result;
+ if (int.TryParse(parts[i], out result) == false || result < 0)
+ {
+ throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Invalid correlation vector {0}. Invalid extension value {1}", correlationVector, parts[i]));
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.CorrelationVector/CorrelationVectorVersion.cs b/src/Microsoft.CorrelationVector/CorrelationVectorVersion.cs
new file mode 100644
index 0000000..15f25dd
--- /dev/null
+++ b/src/Microsoft.CorrelationVector/CorrelationVectorVersion.cs
@@ -0,0 +1,11 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+namespace Microsoft.CorrelationVector
+{
+ public enum CorrelationVectorVersion
+ {
+ V1,
+ V2,
+ }
+}
diff --git a/src/Microsoft.CorrelationVector/Microsoft.CorrelationVector.csproj b/src/Microsoft.CorrelationVector/Microsoft.CorrelationVector.csproj
new file mode 100644
index 0000000..5766db6
--- /dev/null
+++ b/src/Microsoft.CorrelationVector/Microsoft.CorrelationVector.csproj
@@ -0,0 +1,7 @@
+
+
+
+ netcoreapp2.0
+
+
+
diff --git a/src/Microsoft.CorrelationVector/SpinParameters.cs b/src/Microsoft.CorrelationVector/SpinParameters.cs
new file mode 100644
index 0000000..34962ef
--- /dev/null
+++ b/src/Microsoft.CorrelationVector/SpinParameters.cs
@@ -0,0 +1,170 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+
+namespace Microsoft.CorrelationVector
+{
+ public enum SpinCounterInterval
+ {
+ ///
+ /// The coarse interval drops the 24 least significant bits in DateTime.Ticks
+ /// resulting in a counter that increments every 1.67 seconds.
+ ///
+ Coarse,
+
+ ///
+ /// The fine interval drops the 16 least significant bits in DateTime.Ticks
+ /// resulting in a counter that increments every 6.5 milliseconds.
+ ///
+ Fine
+ }
+
+ public enum SpinCounterPeriodicity
+ {
+ ///
+ /// Do not store a counter as part of the spin value.
+ ///
+ None,
+
+ ///
+ /// The short periodicity stores the counter using 16 bits.
+ ///
+ Short,
+
+ ///
+ /// The medium periodicity stores the counter using 24 bits.
+ ///
+ Medium,
+
+ ///
+ /// The long periodicity stores the counter using 32 bits.
+ ///
+ Long
+ }
+
+ public enum SpinEntropy
+ {
+ ///
+ /// Do not generate entropy as part of the spin value.
+ ///
+ None = 0,
+
+ ///
+ /// Generate entropy using 8 bits.
+ ///
+ One = 1,
+
+ ///
+ /// Generate entropy using 16 bits.
+ ///
+ Two = 2,
+
+ ///
+ /// Generate entropy using 24 bits.
+ ///
+ Three = 3,
+
+ ///
+ /// Generate entropy using 32 bits.
+ ///
+ Four = 4
+ }
+
+ ///
+ /// This class stores parameters used by the CorrelationVector Spin operator.
+ ///
+ public class SpinParameters : MarshalByRefObject
+ {
+ // Internal value for entropy bytes.
+ private int entropyBytes;
+
+ ///
+ /// The interval (proportional to time) by which the counter increments.
+ ///
+ public SpinCounterInterval Interval { get; set; }
+
+ ///
+ /// How frequently the counter wraps around to zero, as determined by the amount
+ /// of space to store the counter.
+ ///
+ public SpinCounterPeriodicity Periodicity { get; set; }
+
+ ///
+ /// The number of bytes to use for entropy. Valid values from a
+ /// minimum of 0 to a maximum of 4.
+ ///
+ public SpinEntropy Entropy
+ {
+ get
+ {
+ return (SpinEntropy)this.entropyBytes;
+ }
+ set
+ {
+ this.entropyBytes = (int)value;
+ }
+ }
+
+ ///
+ /// The number of least significant bits to drop in DateTime.Ticks when
+ /// computing the counter.
+ ///
+ internal int TicksBitsToDrop
+ {
+ get
+ {
+ switch (this.Interval)
+ {
+ case SpinCounterInterval.Coarse:
+ return 24;
+
+ case SpinCounterInterval.Fine:
+ return 16;
+
+ default:
+ return 24;
+ }
+ }
+ }
+
+ ///
+ /// The number of bytes used to store the entropy.
+ ///
+ internal int EntropyBytes
+ {
+ get
+ {
+ return this.entropyBytes;
+ }
+ }
+
+ internal int TotalBits
+ {
+ get
+ {
+ int counterBits;
+ switch (this.Periodicity)
+ {
+ case SpinCounterPeriodicity.None:
+ counterBits = 0;
+ break;
+ case SpinCounterPeriodicity.Short:
+ counterBits = 16;
+ break;
+ case SpinCounterPeriodicity.Medium:
+ counterBits = 24;
+ break;
+ case SpinCounterPeriodicity.Long:
+ counterBits = 32;
+ break;
+ default:
+ counterBits = 0;
+ break;
+ }
+
+ return counterBits + this.EntropyBytes * 8;
+ }
+ }
+ }
+}