/// <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++;
                }
            }
        }
示例#3
0
        /// <summary>
        /// Create a Vandermonde matrix of size row x column over GF16
        /// </summary>
        /// <remarks>
        /// The Vandermonde matrix is typically used to create the encoding matrix where:
        /// - The number of Columns of the matrix correspond to number of checksum
        /// packets.
        /// - The number of Rows of the matrix correspond to number of data packets.
        /// </remarks>
        /// <param name="columns">The number of columns of the Vandermonde matrix</param>
        /// <param name="rows">The number of rows of the Vandermode matrix</param>
        /// <returns></returns>
        public static UInt16[,] CreateVandermondeMatrix(int columns, int rows)
        {
            // TODO: Add input validation

            // maxChecksumPackets will be the max number of Columns of the encoding static matrix
            // maxDataPackets will be the max number of Rows of the encoding static matrix

            UInt16[,] vandermondeMtx = new UInt16[columns, rows];

            // Creation of the Vandermonde Matrix over GF16 with the following
            // (2^column)^row

            // As an example, a 5 x 3 Vandermonde Matrix over GF16 (5 data packets, 3 checksum packets)
            // would give the following:
            //
            // 1^0 2^0 4^0
            // 1^1 2^1 4^1
            // 1^2 2^2 4^2
            // 1^3 2^3 4^3
            // 1^4 2^4 4^4
            //
            // Which gives:
            //
            // 1   1   1
            // 1   2   4
            // 1   4   16
            // 1   8   64
            // 1   16  256

            for (int col = 0; col < columns; col++)
            {
                // multFactor is the number to multiply to get the value in the next row
                // for a given column of the Vandermonde matrix
                UInt16 multFactor = GF16.Power(2, (uint)col);
                for (int row = 0; row < rows; row++)
                {
                    if (row == 0)
                    {
                        // Special case the first row (power of zero)
                        vandermondeMtx[col, row] = 1;
                    }
                    else
                    {
                        // Each element of the Vandermonde matrix is calculated as (2^column)^row over GF16

                        // This algorithm uses the previous row to compute the next one to improve
                        // the performances (instead of recalculating (2^column)^row)
                        vandermondeMtx[col, row] = GF16.Multiply(vandermondeMtx[col, row - 1], multFactor);
                    }
                }
            }
            return(vandermondeMtx);
        }
        /// <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
        }
示例#6
0
 /// <summary>
 /// Overload the * operator
 /// </summary>
 /// <param name="a">First operande</param>
 /// <param name="b">Second operande</param>
 /// <returns>Multiplication of the 2 Galois Fields</returns>
 public static GF16 operator *(GF16 a, GF16 b)
 {
     return(GF16.Multiply(a.Value, b.Value));
 }