diff --git a/README.md b/README.md index e966a30..bc00d28 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This project is a C# implementation of the Reed-Solomon error correction algorit ## Description -Creating and maintaining projects can be challenging. This implementation simplifies integration of Reed-Solomon error correction into your applications. Originally used privately, I decided to publish this implementation under the MIT License. +This implementation simplifies integration of Reed-Solomon error correction into your applications. If you find this project helpful, please consider starring it and sharing it with others. @@ -20,54 +20,178 @@ Install-Package Witteborn.ReedSolomon Using the Reed-Solomon library is straightforward. Here's a simple example of how to encode and decode data: -### Example: Encode and Decode +### Managed Example: Byte ```csharp -using Witteborn.ReedSolomon; -using System; -using System.Linq; +Console.WriteLine("Managed Example Byte"); +Console.WriteLine("--------------------"); +const int dataShardCount = 4; +const int parityShardCount = 2; -class Program +// Initialize Reed-Solomon with data shards and parity shards +ReedSolomon rs = new ReedSolomon(dataShardCount, parityShardCount); + +// Example data to encode +byte[] data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; +Console.WriteLine("Data:"); +Console.WriteLine(string.Join(" ", data)); + +// Encode the data using ManagedEncode to produce shards +var shards = rs.ManagedEncode(data, dataShardCount, parityShardCount); + +Console.WriteLine("Encoded Data:"); +foreach (var shard in shards) +{ + Console.WriteLine(string.Join(" ", shard)); +} + +// Simulate loss of one shard +shards[1] = null; + +Console.WriteLine("Encoded with missing Data:"); +foreach (var shard in shards) +{ + if (shard == null) + { + Console.WriteLine("null"); + } + else + { + Console.WriteLine(string.Join(" ", shard)); + } +} + +// Decode the remaining shards using ManagedDecode to recover original data +var decodedData = rs.ManagedDecode(shards, dataShardCount, parityShardCount); + +Console.WriteLine("Decoded data:"); +Console.WriteLine(string.Join(" ", decodedData)); +``` + +### Managed Example: SByte + +```csharp +Console.WriteLine("Managed Example SByte"); +Console.WriteLine("---------------------"); +const int dataShardCount = 4; +const int parityShardCount = 2; + +// Initialize Reed-Solomon with data shards and parity shards +ReedSolomon rs = new ReedSolomon(dataShardCount, parityShardCount); + +// Example data to encode +sbyte[] data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; +Console.WriteLine("Data:"); +Console.WriteLine(string.Join(" ", data)); + +// Encode the data using ManagedEncode to produce shards +var shards = rs.ManagedEncode(data, dataShardCount, parityShardCount); + +Console.WriteLine("Encoded Data:"); + +foreach (var shard in shards) +{ + Console.WriteLine(string.Join(" ", shard)); +} + +// Simulate loss of one shard +shards[1] = null; + +Console.WriteLine("Encoded with missing Data:"); +foreach (var shard in shards) +{ + if (shard == null) + { + Console.WriteLine("null"); + } + else + { + Console.WriteLine(string.Join(" ", shard)); + } +} + +// Decode the remaining shards using ManagedDecode to recover original data +var decodedData = rs.ManagedDecode(shards, dataShardCount, parityShardCount); + +Console.WriteLine("Decoded data:"); +Console.WriteLine(string.Join(" ", decodedData)); +``` + +### Manual Example: SByte + +```csharp +Console.WriteLine("Example SByte"); +Console.WriteLine("-------------"); + +const int dataShardCount = 4; +const int parityShardCount = 2; +const int shardSize = 4; + +// Create the shards array with data and empty parity shards +sbyte[][] shards = +{ + new sbyte[] { 0, 1, 2, 3 }, + new sbyte[] { 4, 5, 6, 7 }, + new sbyte[] { 8, 9, 10, 11 }, + new sbyte[] { 12, 13, 14, 15 }, + new sbyte[shardSize], // Parity shard 1 + new sbyte[shardSize] // Parity shard 2 +}; + +Console.WriteLine("Shards:"); +foreach (var shard in shards) +{ + Console.WriteLine(string.Join(" ", shard)); +} + +// Initialize Reed-Solomon with data shards and parity shards +ReedSolomon rs = new ReedSolomon(dataShardCount, parityShardCount); + +// Encode the data with Reed-Solomon to generate parity shards +rs.EncodeParity(shards, 0, shardSize); + +Console.WriteLine("Encoded data:"); +foreach (var shard in shards) { - static void Main() + Console.WriteLine(string.Join(" ", shard)); +} + +// Simulate loss of one shard (e.g., network transmission loss) +shards[1] = null; // Simulating the shard is lost + +Console.WriteLine("Encoded with missing Data:"); +foreach (var shard in shards) +{ + if (shard == null) + { + Console.WriteLine("null"); + } + else + { + Console.WriteLine(string.join(" ", shard)); + } +} + +bool[] shardPresent = shards.Select(shard => shard != null).ToArray(); + +//Manual null fix +for (int i = 0; i < shards.Length; i++) +{ + if (shards[i] == null) { - const int dataShardCount = 4; - const int parityShardCount = 2; - const int totalShardCount = dataShardCount + parityShardCount; - const int shardSize = 4; - - // Create the shards array with data and empty parity shards - sbyte[][] shards = new sbyte[totalShardCount][] - { - new sbyte[] { 0, 1, 2, 3 }, - new sbyte[] { 4, 5, 6, 7 }, - new sbyte[] { 8, 9, 10, 11 }, - new sbyte[] { 12, 13, 14, 15 }, - new sbyte[shardSize], // Parity shard 1 - new sbyte[shardSize] // Parity shard 2 - }; - - // Initialize Reed-Solomon with data shards and parity shards - ReedSolomon rs = new ReedSolomon(dataShardCount, parityShardCount); - - // Encode the data with Reed-Solomon to generate parity shards - rs.EncodeParity(shards, 0, shardSize); - - // Simulate loss of one shard (e.g., network transmission loss) - shards[1] = null; // Simulating the shard is lost - bool[] shardPresent = shards.Select(shard => shard != null).ToArray(); - - // Decode the remaining shards to recover original data - rs.DecodeMissing(shards, shardPresent, 0, shardSize); - - // Print the decoded data (should match original data) - Console.WriteLine("Decoded data:"); - foreach (var shard in shards.Where(s => s != null)) - { - Console.WriteLine(string.Join(" ", shard)); - } + shards[i] = new sbyte[shardSize]; } } + +// Decode the remaining shards to recover original data +rs.DecodeMissing(shards, shardPresent, 0, shardSize); + +// Print the decoded data (should match original data) +Console.WriteLine("Decoded data:"); +foreach (var shard in shards.Where(s => s != null)) +{ + Console.WriteLine(string.Join(" ", shard)); +} ``` ## Contribution @@ -86,4 +210,4 @@ To report security issues or vulnerabilities, refer to our [Security](./SECURITY - **Backblaze** for the original Java implementation that inspired this project. -And a big **Thank You** to all contributors, issue reporters, and supporters who have helped make this project possible. +And a big **Thank You** to all contributors, issue reporters, and supporters who have helped make this project possible. \ No newline at end of file diff --git a/ReedSolomon/ReadmeExample/Program.cs b/ReedSolomon/ReadmeExample/Program.cs new file mode 100644 index 0000000..2bb5125 --- /dev/null +++ b/ReedSolomon/ReadmeExample/Program.cs @@ -0,0 +1,193 @@ +using Witteborn.ReedSolomon; + +ManagedExample_SByte(); + +Console.WriteLine(); +Console.WriteLine(); + +ManagedExample_Byte(); + +Console.WriteLine(); +Console.WriteLine(); + +Example_SByte(); + + + + +void ManagedExample_SByte() +{ + Console.WriteLine("Managed Example SByte"); + Console.WriteLine("---------------------"); + const int dataShardCount = 4; + const int parityShardCount = 2; + + // Initialize Reed-Solomon with data shards and parity shards + ReedSolomon rs = new ReedSolomon(dataShardCount, parityShardCount); + + // Example data to encode + sbyte[] data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; + Console.WriteLine("Data:"); + Console.WriteLine(string.Join(" ", data)); + + // Encode the data using ManagedEncode to produce shards + var shards = rs.ManagedEncode(data, dataShardCount, parityShardCount); + + Console.WriteLine("Encoded Data:"); + + foreach (var shard in shards) + { + Console.WriteLine(string.Join(" ", shard)); + } + + // Simulate loss of one shard + shards[1] = null; + + Console.WriteLine("Encoded with missing Data:"); + foreach (var shard in shards) + { + if (shard == null) + { + Console.WriteLine("null"); + } + else + { + Console.WriteLine(string.Join(" ", shard)); + } + } + + // Decode the remaining shards using ManagedDecode to recover original data + var decodedData = rs.ManagedDecode(shards, dataShardCount, parityShardCount); + + Console.WriteLine("Decoded data:"); + Console.WriteLine(string.Join(" ", decodedData)); +} + +void Example_SByte() +{ + Console.WriteLine("Example SByte"); + Console.WriteLine("-------------"); + + + const int dataShardCount = 4; + const int parityShardCount = 2; + const int totalShardCount = dataShardCount + parityShardCount; + const int shardSize = 4; + + // Create the shards array with data and empty parity shards + sbyte[][] shards = + [ + [0, 1, 2, 3], + [4, 5, 6, 7], + [8, 9, 10, 11], + [12, 13, 14, 15], + new sbyte[shardSize], // Parity shard 1 + new sbyte[shardSize] // Parity shard 2 + ]; + + Console.WriteLine("Shards:"); + foreach (var shard in shards) + { + Console.WriteLine(string.Join(" ", shard)); + } + + // Initialize Reed-Solomon with data shards and parity shards + ReedSolomon rs = new ReedSolomon(dataShardCount, parityShardCount); + + + + // Encode the data with Reed-Solomon to generate parity shards + rs.EncodeParity(shards, 0, shardSize); + + Console.WriteLine("Encoded data:"); + + foreach (var shard in shards) + { + Console.WriteLine(string.Join(" ", shard)); + } + + // Simulate loss of one shard (e.g., network transmission loss) + shards[1] = null; // Simulating the shard is lost + + Console.WriteLine("Encoded with missing Data:"); + foreach (var shard in shards) + { + if (shard == null) + { + Console.WriteLine("null"); + } + else + { + Console.WriteLine(string.Join(" ", shard)); + } + } + + bool[] shardPresent = shards.Select(shard => shard != null).ToArray(); + + //Manual null fix + for (int i = 0; i < shards.Length; i++) + { + if (shards[i] == null) + { + shards[i] = new sbyte[shardSize]; + } + } + + // Decode the remaining shards to recover original data + rs.DecodeMissing(shards, shardPresent, 0, shardSize); + + // Print the decoded data (should match original data) + Console.WriteLine("Decoded data:"); + foreach (var shard in shards.Where(s => s != null)) + { + Console.WriteLine(string.Join(" ", shard)); + } +} + + +void ManagedExample_Byte() +{ + Console.WriteLine("Managed Example Byte"); + Console.WriteLine("--------------------"); + const int dataShardCount = 4; + const int parityShardCount = 2; + + // Initialize Reed-Solomon with data shards and parity shards + ReedSolomon rs = new ReedSolomon(dataShardCount, parityShardCount); + + // Example data to encode + byte[] data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; + Console.WriteLine("Data:"); + Console.WriteLine(string.Join(" ", data)); + + // Encode the data using ManagedEncode to produce shards + var shards = rs.ManagedEncode(data, dataShardCount, parityShardCount); + + Console.WriteLine("Encoded Data:"); + foreach (var shard in shards) + { + Console.WriteLine(string.Join(" ", shard)); + } + + // Simulate loss of one shard + shards[1] = null; + + Console.WriteLine("Encoded with missing Data:"); + foreach (var shard in shards) + { + if (shard == null) + { + Console.WriteLine("null"); + } + else + { + Console.WriteLine(string.Join(" ", shard)); + } + } + + // Decode the remaining shards using ManagedDecode to recover original data + var decodedData = rs.ManagedDecode(shards, dataShardCount, parityShardCount); + + Console.WriteLine("Decoded data:"); + Console.WriteLine(string.Join(" ", decodedData)); +} \ No newline at end of file diff --git a/ReedSolomon/ReadmeExample/ReadmeExample.csproj b/ReedSolomon/ReadmeExample/ReadmeExample.csproj new file mode 100644 index 0000000..09cde25 --- /dev/null +++ b/ReedSolomon/ReadmeExample/ReadmeExample.csproj @@ -0,0 +1,14 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + diff --git a/ReedSolomon/ReedSolomon.sln b/ReedSolomon/ReedSolomon.sln index 814033b..b7c4207 100644 --- a/ReedSolomon/ReedSolomon.sln +++ b/ReedSolomon/ReedSolomon.sln @@ -3,9 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.7.33711.374 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReedSolomon", "ReedSolomon\ReedSolomon.csproj", "{305A4D2F-A539-4C8D-B6CA-78F7B747A485}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReedSolomon", "ReedSolomon\ReedSolomon.csproj", "{305A4D2F-A539-4C8D-B6CA-78F7B747A485}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReedSolomonTests", "ReedSolomonTests\ReedSolomonTests.csproj", "{A01F9BC0-4E9D-43FA-8965-C08C9C95115D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReedSolomonTests", "ReedSolomonTests\ReedSolomonTests.csproj", "{A01F9BC0-4E9D-43FA-8965-C08C9C95115D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReadmeExample", "ReadmeExample\ReadmeExample.csproj", "{071D3049-0A47-4374-9ADF-01792DC9A356}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -21,6 +23,10 @@ Global {A01F9BC0-4E9D-43FA-8965-C08C9C95115D}.Debug|Any CPU.Build.0 = Debug|Any CPU {A01F9BC0-4E9D-43FA-8965-C08C9C95115D}.Release|Any CPU.ActiveCfg = Release|Any CPU {A01F9BC0-4E9D-43FA-8965-C08C9C95115D}.Release|Any CPU.Build.0 = Release|Any CPU + {071D3049-0A47-4374-9ADF-01792DC9A356}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {071D3049-0A47-4374-9ADF-01792DC9A356}.Debug|Any CPU.Build.0 = Debug|Any CPU + {071D3049-0A47-4374-9ADF-01792DC9A356}.Release|Any CPU.ActiveCfg = Release|Any CPU + {071D3049-0A47-4374-9ADF-01792DC9A356}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ReedSolomon/ReedSolomon/ReedSolomon.cs b/ReedSolomon/ReedSolomon/ReedSolomon.cs index 9df73ef..1be4314 100644 --- a/ReedSolomon/ReedSolomon/ReedSolomon.cs +++ b/ReedSolomon/ReedSolomon/ReedSolomon.cs @@ -1,4 +1,7 @@ -namespace Witteborn.ReedSolomon; +using System.Collections.Generic; +using System.Data.SqlTypes; + +namespace Witteborn.ReedSolomon; /// /// Reed-Solomon Coding over 8-bit values. @@ -29,6 +32,173 @@ public ReedSolomon(int dataShardCount, int parityShardCount) } } + + /// + /// This produces a total amount of shards of dataShards + parityShard. + /// The Shards are already encoded. Note that the result will be bigger than the data input because of the parity shards being added. + /// + /// + /// + /// + /// + public byte[][] ManagedEncode(byte[] data, int dataShards, int parityShards) + { + sbyte[] sbyteData = Array.ConvertAll(data, b => unchecked((sbyte)b)); + var encodedShards = ManagedEncode(sbyteData, dataShards, parityShards); + + var result = new List(); + + for (int i = 0; i < encodedShards.Length; i++) + { + var shard = encodedShards[i]; + byte[] rawShard = Array.ConvertAll(shard, b => unchecked((byte)b)); + result.Add(rawShard); + } + + return result.ToArray(); + } + + /// + /// This produces a total amount of shards of dataShards + parityShard. + /// The Shards are already encoded. Note that the result will be bigger than the data input because of the parity shards being added. + /// + /// + /// + /// + /// + public sbyte[][] ManagedEncode(sbyte[] data, int dataShards, int parityShards) + { + int totalShards = dataShards + parityShards; + + int shardSize = (int)Math.Ceiling((double)data.Length / dataShards); + int totalDataSize = shardSize * dataShards; + + if (totalDataSize > data.Length) + { + Array.Resize(ref data, totalDataSize); + } + + var rs = new ReedSolomon(dataShards, parityShards); + var shardsList = new List(); + + for (int i = 0; i < dataShards; i++) + { + sbyte[] shardData = new sbyte[shardSize]; + Array.Copy(data, i * shardSize, shardData, 0, shardSize); + shardsList.Add(shardData); + } + + for (int i = dataShards; i < totalShards; i++) + { + shardsList.Add(new sbyte[shardSize]); + } + var shards = shardsList.ToArray(); + rs.EncodeParity(shards, 0, shardSize); + + return shards.ToArray(); + } + + /// + /// This produces a total amount of shards of dataShards + parityShard. + /// The Shards are already encoded. Note that the result will be bigger than the data input because of the parity shards being added. + /// + /// + /// + /// + /// + public byte[] ManagedDecode(byte[][] data, int dataShards, int parityShards) + { + int size = 0; + + sbyte[][] sbytes = new sbyte[data.Length][]; + for (int i = 0; i < data.Length; i++) + { + if (size == 0) { + if (data[i] != null) { + size = data[i].Length; + } + } + + if (data[i] == null) { + data[i] = new byte[size]; + } + + sbytes[i] = Array.ConvertAll(data[i], b => unchecked((sbyte)b)); + } + + var result = ManagedDecode(sbytes, dataShards, parityShards); + return Array.ConvertAll(result, b => unchecked((byte)b)); + } + + /// + /// This produces a total amount of shards of dataShards + parityShard. + /// The Shards are already encoded. Note that the result will be bigger than the data input because of the parity shards being added. + /// + /// + /// + /// + /// + public sbyte[] ManagedDecode(sbyte[][] data, int dataShards, int parityShards) + { + ReedSolomon rs = new ReedSolomon(dataShards, parityShards); + int totalShards = dataShards + parityShards; + int shardSize = data[0].Length; + bool[] shardPresent = new bool[totalShards]; + + for (int i = 0; i < data.Length; i++) + { + //if any shard is null, create a new array + if (data[i] == null || data[i].All(d => d == 0)) + { + data[i] = new sbyte[shardSize]; + shardPresent[i] = false; + } + else + { + shardPresent[i] = true; + } + } + + bool atleastOneShardIsMissing = shardPresent.Any(b => b == false); + if (atleastOneShardIsMissing) + { + rs.DecodeMissing(data, shardPresent, 0, data[0].Length); + } + + var output = new List(); + for (int i = 0; i < dataShards; i++) + { + output.AddRange(data[i]); + } + + var outputArray = output.ToArray(); + return outputArray; + } + + /// + /// Encodes parity for a set of data shards. Note that this is slower than using the sbytes directly + /// + /// An array containing data shards followed by parity shards.
+ /// Each shard is a byte array, and they must all be the same size + /// . + /// The index of the first sbyte in each shard to encode. + /// The number of sbytes to encode in each shard. + public void EncodeParity(byte[][] shards, int offset, int byteCount) + { + sbyte[][] sbytes = new sbyte[shards.Length][]; + for (int i = 0; i < shards.Length; i++) + { + sbytes[i] = Array.ConvertAll(shards[i], b => unchecked((sbyte)b)); + } + + EncodeParity(sbytes, offset, byteCount); + + for (int i = 0; i < shards.Length; i++) + { + shards[i] = Array.ConvertAll(sbytes[i], b => unchecked((byte)b)); + } + } + /// /// Encodes parity for a set of data shards. /// diff --git a/ReedSolomon/ReedSolomon/ReedSolomon.csproj b/ReedSolomon/ReedSolomon/ReedSolomon.csproj index f56facd..fefa667 100644 --- a/ReedSolomon/ReedSolomon/ReedSolomon.csproj +++ b/ReedSolomon/ReedSolomon/ReedSolomon.csproj @@ -11,7 +11,7 @@ https://github.com/Witteborn/ReedSolomon https://github.com/Witteborn/ReedSolomon True - + 1.1.0 Witteborn README.md @@ -20,14 +20,14 @@ - - True - \ - - - True - \ - + + True + \ + + + True + \ + diff --git a/ReedSolomon/ReedSolomonTests/ReedSolomonTests.cs b/ReedSolomon/ReedSolomonTests/ReedSolomonTests.cs index d20b362..2c86236 100644 --- a/ReedSolomon/ReedSolomonTests/ReedSolomonTests.cs +++ b/ReedSolomon/ReedSolomonTests/ReedSolomonTests.cs @@ -1,3 +1,4 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; using Witteborn.ReedSolomon; namespace ReedSolomonTests @@ -5,6 +6,103 @@ namespace ReedSolomonTests [TestClass()] public class ReedSolomonTests { + [TestMethod()] + public void ProduceEncodedShardsTest() + { + //Arrange + ReedSolomon rs = new ReedSolomon(dataShardCount: 4, parityShardCount: 2); + + sbyte[] data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + + var shards = rs.ManagedEncode(data, 4, 2); + + //Assert + sbyte[][] expectedShards = + [ + [0, 1, 2, 3], + [4, 5, 6, 7], + [8, 9, 10, 11], + [12, 13, 14, 15], + [16, 17, 18, 19], + [20, 21, 22, 23] + ]; + + for (int i = 0; i < shards.Length; i++) + { + Assert.IsTrue(shards[i].SequenceEqual(expectedShards[i])); + } + } + + [TestMethod()] + public void ProduceEncodedShardsTest2() + { + //Arrange + ReedSolomon rs = new ReedSolomon(dataShardCount: 4, parityShardCount: 2); + + byte[] data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + + //Act + var shards = rs.ManagedEncode(data, 4, 2); + + //Assert + byte[][] expectedShards = + [ + [0, 1, 2, 3], + [4, 5, 6, 7], + [8, 9, 10, 11], + [12, 13, 14, 15], + [16, 17, 18, 19], + [20, 21, 22, 23] + ]; + + for (int i = 0; i < shards.Length; i++) + { + Assert.IsTrue(shards[i].SequenceEqual(expectedShards[i])); + } + } + + [TestMethod()] + public void ConvertedEncodeParityTest() + { + //Arrange + ReedSolomon rs = new ReedSolomon(dataShardCount: 4, parityShardCount: 2); + + byte[] data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + + List shardsList = new(); + for (int i = 0; i < 4; i++) + { + var segment = new ArraySegment(data, data.Length / 4 * i, data.Length / 4); + shardsList.Add(segment.ToArray()); + } + + for (int i = 0; i < 2; i++) + { + shardsList.Add(new byte[data.Length / 4]); + } + + var shards = shardsList.ToArray(); + + //Act + rs.EncodeParity(shards, 0, data.Length / 4); + + //Assert + byte[][] expectedShards = + [ + [0, 1, 2, 3], + [4, 5, 6, 7], + [8, 9, 10, 11], + [12, 13, 14, 15], + [16, 17, 18, 19], + [20, 21, 22, 23] + ]; + + for (int i = 0; i < shards.Length; i++) + { + Assert.IsTrue(shards[i].SequenceEqual(expectedShards[i])); + } + } + [TestMethod()] public void EncodeParityTest() { @@ -47,6 +145,66 @@ public void EncodeParityTest() } } + [TestMethod()] + public void Decode_OneShard_Success_Test() + { + //Arrange + ReedSolomon rs = new ReedSolomon(dataShardCount: 4, parityShardCount: 2); + + sbyte[][] shards = + [ + [0, 1, 2, 3], //Data + [0, 0, 0, 0], //Missing Data + [8, 9, 10, 11], //Data + [12, 13, 14, 15], //Data + [16, 17, 18, 19], //Parity + [20, 21, 22, 23] //Parity + ]; + + + //Act + var result = rs.ManagedDecode(shards, 4, 2); + + //Assert + sbyte[] expected = + [0, 1, 2, 3, //Data + 4, 5, 6, 7, //Data + 8, 9, 10, 11, //Data + 12, 13, 14, 15]; //Data + + Assert.IsTrue(result.SequenceEqual(expected)); + } + + [TestMethod()] + public void Decode_OneShard_Success_Test2() + { + //Arrange + ReedSolomon rs = new ReedSolomon(dataShardCount: 4, parityShardCount: 2); + + byte[][] shards = + [ + [0, 1, 2, 3], //Data + [0, 0, 0, 0], //Missing Data + [8, 9, 10, 11], //Data + [12, 13, 14, 15], //Data + [16, 17, 18, 19], //Parity + [20, 21, 22, 23] //Parity + ]; + + + //Act + var result = rs.ManagedDecode(shards, 4, 2); + + //Assert + byte[] expected = + [0, 1, 2, 3, //Data + 4, 5, 6, 7, //Data + 8, 9, 10, 11, //Data + 12, 13, 14, 15]; //Data + + Assert.IsTrue(result.SequenceEqual(expected)); + } + [TestMethod()] public void DecodeMissing_OneShard_Success_Test() {