/// <summary> /// Encode the length of the packets that are in the data BufferChunk array and place the /// encoded length over GF16 in the 2 first byte of the checksum packets that are in /// the result BufferChunk array /// </summary> /// <param name="data">The BufferChunk array containing the data packets to get the size</param> /// <param name="checksum">The number of checksum packets to generate. /// This number is actually also the number of column of the Vandermonde /// encoding matrix</param> /// <param name="encode">The Vandermonde encoding matrix (size min should be /// Vandermonde #column: checksum, Vandermonde #row: data.Length) /// </param> /// <param name="result">The BufferChunk checksum packets array of containing the encoded length (over GF16) /// in the first 2 bytes</param> private static void EncodeRSLength(BufferChunk[] data, BufferChunk[] result, UInt16[,] encode) { // Get the length once to avoid having the overhead of getting it again inside a inner (performance) // Note that this value is also used outside of this method, so we could have had a parameter too, // but I prefer to get it here to avoid inconsistencies int dataPackets = data.Length; int checksum = result.Length; // Note: The size of the Vandermonde matrix used to encode the length is // Vandermonde #column: checksum, Vandermonde #row: dataPackets // TODO: Validate if Vandermonde # max column >= checksum and // Vandermonde #row >= dataPackets // TODO: Validate that there are no null entries in data and result // TODO: Validate that all the checksum packet have at least 2 bytes // Length encoding for (int encodeColumn = 0; encodeColumn < checksum; encodeColumn++) { UInt16 encodeValue = 0; for (int dataPacket = 0; dataPacket < dataPackets; dataPacket++) { // TODO: performance - lengths of BC don't change between loops, store once? JVE UInt16 dataValue = GF16.Multiply((UInt16)data[dataPacket].Length, encode[encodeColumn, dataPacket]); encodeValue = GF16.Add(encodeValue, dataValue); } result[encodeColumn] += encodeValue; } }
/// <summary> /// Decode to retrieve the missing data packet(s) (null entries) in the data BufferChunk array and place the /// decoded result over GF16 in order in the recovery BufferChunk array /// </summary> /// <param name="data">The data BufferChunk array</param> /// <param name="checksum">The number of checksum packet(s) that were used to encode</param> /// <param name="decode">The decoding GF16 matrix</param> /// <param name="recovery">The recovery BufferChunk array to place the recovered result</param> private static void DecodeRSData(BufferChunk[] data, int checksum, GF16[,] decode, BufferChunk[] recovery) { // Important! For now I assume the following in the firstMatrix: // - The array is always of size data + checksum // - #checksum not null entries = #packet lost // - recovery.length is exactly the number of data packet lost // - checksum param is # checksum packets that were used to encode // Reconstruct data // Get the length once to avoid having the overhead of getting it again inside a inner (performance) // Note that this value is also used outside of this method, so we could have had a parameter too, // but I prefer to get it here to avoid inconsitencies int dataLength = data.Length; // Scan column after column int recoveryColumn = 0; for (int dataColumn = 0; dataColumn < dataLength - checksum; dataColumn++) { // recover only the missing column if (data[dataColumn] == null) { int recoveryRowLength = recovery[recoveryColumn].Length; // For each column fill out the output mtx row after row for (int recoveryRow = 0; recoveryRow < recoveryRowLength; recoveryRow += 2) { int imRowIndex = 0; // nnDataColumn - not null data index for (int nnDataColumn = 0; nnDataColumn < dataLength; nnDataColumn++) { // Perform the core operation mult with add in GF16 // TODO: We could crunch the column so we avoid this test if (data[nnDataColumn] != null) { if (recoveryRow < data[nnDataColumn].Length) { UInt16 currentValue = GF16.Multiply(data[nnDataColumn].GetUInt16(recoveryRow), decode[dataColumn, imRowIndex].Value); currentValue = GF16.Add(recovery[recoveryColumn].GetUInt16(recoveryRow), currentValue); recovery[recoveryColumn].SetUInt16(recoveryRow, currentValue); } imRowIndex++; } } } recoveryColumn++; } } }
/// <summary> /// Encode the packets that are in the data BufferChunk array and place the /// encoded result over GF16 in the checksum packets that are in /// the result BufferChunk array /// </summary> /// <param name="data">The BufferChunk array containing the data packets</param> /// <param name="checksum">The number of checksum packets to generate. /// This number is actually also the number of column of the Vandermonde /// encoding matrix</param> /// <param name="checksum">The BufferChunk checksum packets array of containing the encoded data (over GF16) /// after the first 2 bytes (the first 2 bytes are used to encode the length)</param> /// <param name="encode">The Vandermonde encoding matrix (size min should be /// Vandermonde #column: checksum, Vandermonde #row: data.Length) /// </param> /// <param name="checksumRowsInt16">The number of row (in int 16 chunks) of the checksum packets</param> private static void EncodeRSData(BufferChunk[] data, BufferChunk[] checksum, UInt16[,] encode, int maxDataLength) { // Note: The size of the Vandermonde matrix used to encode the length is // Vandermonde #column: checksumLength, Vandermonde #row: dataPackets // TODO: Validate if Vandermonde # max column >= checksum and // Vandermonde #row >= dataPackets // TODO: Validate that there are no null entries in data and checksum // Get the length once to avoid having the overhead of getting it again inside a inner (performance) int dataPackets = data.Length; int checksumLength = checksum.Length; // Note that we scan column after column, so we generate the checksum packets // one after the other for (int checksumColumn = 0; checksumColumn < checksumLength; checksumColumn++) { // For each column fill out the checksum mtx row after row for (int checksumRow = 0; checksumRow < maxDataLength; checksumRow += 2) { for (int encodeRow = 0; encodeRow < dataPackets; encodeRow++) { // If we pass the size of the current data packet, so no operation are required // if ((checksumRow) < data[encodeRow].Length) { UInt16 currentValue = GF16.Multiply(data[encodeRow].GetUInt16(checksumRow), encode[checksumColumn, encodeRow]); currentValue = GF16.Add(checksum[checksumColumn].GetUInt16(checksumRow), currentValue); checksum[checksumColumn].SetUInt16(checksumRow, currentValue); } } } } }
/// <summary> /// Decode to retrieve the length of the missing data packet(s) (null entries) in the /// data BufferChunk array and set the length of the packets in the recovery BufferChunk array. /// We have to do that because every data packet could have a different length. /// </summary> /// <param name="data">The data BufferChunk array</param> /// <param name="checksum">The number of checksum packet(s) that were used to encode</param> /// <param name="decode">The decoding GF16 matrix</param> /// <param name="recovery">The recovery BufferChunk array to set the length of the recovered packets</param> private static void DecodeRSLength(BufferChunk[] data, int checksum, GF16[,] decode, BufferChunk[] recovery) { // Important! For now I assume the following in the firstMatrix: // - The array is always of size data + checksum // - #checksum not null entries = #packet lost // - recovery.length is exactly the number of data packet lost // - checksum param is # checksum packets that were used to encode // Get the length once to avoid having the overhead of getting it again inside a inner (performance) // Note that this value is also used outside of this method, so we could have had a parameter too, // but I prefer to get it here to avoid inconsitencies int dataLength = data.Length; int recoveryColumn = 0; for (int dataColumn = 0; dataColumn < dataLength - checksum; dataColumn++) { // recover only the missing column if (data[dataColumn] == null) { // Inverted matrix row index int imRowIndex = 0; // length of the recovered buffer UInt16 currentLength = 0; for (int dataIndex = 0; dataIndex < dataLength; dataIndex++) { // Perform the core operation mult with add in GF16 // TODO: We could crunch the column so we avoid this test if (data[dataIndex] != null) { UInt16 length = 0; if (dataIndex < dataLength - checksum) // For the data part, we get the length of the BufferChunk { length = (UInt16)data[dataIndex].Length; } else // For the checksum part, the encoded length is inside the first 2 bytes { length = data[dataIndex].GetUInt16(0); } UInt16 currentValue = GF16.Multiply(length, decode[dataColumn, imRowIndex].Value); currentLength = GF16.Add(currentLength, currentValue); imRowIndex++; } // if } // for column (do elementary operations) BufferChunk bc = recovery[recoveryColumn]; bc.Reset(bc.Index, currentLength); // Reset all of the recovery packets so they have no data // TODO - Temporary workaround for column based approach - JVE 7/6/2004 bc.Clear(); recoveryColumn++; } // if } // for dataColumn }
/// <summary> /// Overload the - operator /// </summary> /// <param name="a">First operande</param> /// <param name="b">Second operande</param> /// <remarks> /// The subtraction is the same as the addition /// because with Galois fields, each number is its /// own negative. So there is no need to have a Sub /// method /// </remarks> /// <returns>Subrtraction of the 2 Galois Fields (XOR)</returns> public static GF16 operator -(GF16 a, GF16 b) { return(GF16.Add(a.Value, b.Value)); }