/// <summary>Encodes a data block by adding <see cref="EccLength"/> error-correction symbols to it.</summary>
        /// <param name="source">The array containing the data block to encode</param>
        /// <param name="srcIndex">The index within <paramref name="source"/> at which the data block begins</param>
        /// <param name="length">The length of the data block. This can be at most 255-<see cref="EccLength"/></param>
        /// <param name="destination">The array into which the encoded block will be written</param>
        /// <param name="destIndex">The index at which the encoded block will be written. The array must have at least
        /// <paramref name="length"/>+<see cref="EccLength"/> bytes available at the index.
        /// </param>
        /// <returns>Returns the number of bytes written to the <paramref name="destination"/> array, which will equal
        /// <paramref name="length"/>+<see cref="EccLength"/>.
        /// </returns>
        public int Encode(byte[] source, int srcIndex, int length, byte[] destination, int destIndex)
        {
            Utility.ValidateRange(source, srcIndex, length);
            Utility.ValidateRange(destination, destIndex, length + EccLength);
            if (source.Length > 255 - EccLength)
            {
                throw new ArgumentException("The source length can be at most 255 - EccLength.");
            }

            if (EccLength != 0)
            {
                int[] coef = new int[length + EccLength];
                for (int i = 0; i < length; i++)
                {
                    coef[i + EccLength] = source[i + srcIndex];
                }
                GF2pPolynomial code = new GF2pPolynomial(Field, coef, false) % Prime;
                for (int i = 0; i < code.data.Length; i++)
                {
                    destination[i + destIndex] = (byte)code.data[i];
                }
            }
            Array.Copy(source, srcIndex, destination, destIndex + EccLength, length);
            return(length + EccLength);
        }
示例#2
0
        public void T05_PolynomialMultiplication()
        {
            GF2pField      field = new GF2pField(8);
            GF2pPolynomial a = new GF2pPolynomial(field, 0, 4, 17, 0, 9), b = new GF2pPolynomial(field, 19, 11, 0, 100);

            Assert.AreEqual(new GF2pPolynomial(field, 0, 76, 18, 187, 6, 57, 0, 99), a * b);
            Assert.AreEqual(a * b, b * a);
            Assert.AreEqual(new GF2pPolynomial(field, 0), new GF2pPolynomial(field, 0) * a);
            Assert.AreEqual(new GF2pPolynomial(field, 0), default(GF2pPolynomial) * b);

            Assert.AreEqual(new GF2pPolynomial(field, 121, 49, 0, 33), b * 7);

            Assert.AreEqual(0, GF2pPolynomial.MultiplyAt(a, b, 0));
            Assert.AreEqual(76, GF2pPolynomial.MultiplyAt(a, b, 1));
            Assert.AreEqual(18, GF2pPolynomial.MultiplyAt(a, b, 2));
            Assert.AreEqual(187, GF2pPolynomial.MultiplyAt(a, b, 3));
            Assert.AreEqual(6, GF2pPolynomial.MultiplyAt(a, b, 4));
            Assert.AreEqual(57, GF2pPolynomial.MultiplyAt(a, b, 5));
            Assert.AreEqual(0, GF2pPolynomial.MultiplyAt(a, b, 6));
            Assert.AreEqual(99, GF2pPolynomial.MultiplyAt(a, b, 7));
            Assert.AreEqual(0, GF2pPolynomial.MultiplyAt(a, b, 8));
            Assert.AreEqual(0, GF2pPolynomial.MultiplyAt(a, b, 9));

            Assert.AreEqual(0, a.MultiplyAt(b, 0));
            Assert.AreEqual(76, a.MultiplyAt(b, 1));
            Assert.AreEqual(18, a.MultiplyAt(b, 2));
            Assert.AreEqual(187, a.MultiplyAt(b, 3));
        }
        /// <include file="documentation.xml" path="/Math/ReedSolomon/DecodeBool/*"/>
        public int Decode(byte[] source, int srcIndex, int length, byte[] destination, int destIndex,
                          int[] errorPositions, bool allErrorsKnown = false)
        {
            if (length < EccLength)
            {
                throw new ArgumentOutOfRangeException("length", "must be at least EccLength");
            }
            Utility.ValidateRange(source, srcIndex, length);
            Utility.ValidateRange(destination, destIndex, length - EccLength);

            GF2pPolynomial message = ToPolynomial(source, srcIndex, length), syndromes = CalculateSyndromes(message, EccLength);

            if (syndromes.IsZero)
            {
                Array.Copy(source, srcIndex + EccLength, destination, destIndex, length - EccLength);
                return(length - EccLength);
            }

            GF2pPolynomial locator = default(GF2pPolynomial), evaluator = default(GF2pPolynomial);

            if (errorPositions != null && errorPositions.Length != 0)
            {
                locator   = CalculateErasureLocator(errorPositions, Field);
                evaluator = CalculateErrorEvaluator(syndromes, locator);
            }
            else if (allErrorsKnown)
            {
                return(-1);
            }

            if (!allErrorsKnown)
            {
                BerlekampMassey(syndromes, locator, evaluator, errorPositions == null ? 0 : errorPositions.Length, out locator, out evaluator);
            }

            int[] allErrorPositions = FindErrors(locator, length);
            if (allErrorPositions == null || allErrorPositions.Length > EccLength)
            {
                return(-1);
            }

            // now return the corrected data. copy the source data to the destination
            Array.Copy(source, srcIndex + EccLength, destination, destIndex, length - EccLength);
            int correctionStart = 0; // skip connections to ECC codes, since we don't return them

            while (correctionStart < allErrorPositions.Length && allErrorPositions[correctionStart] < EccLength)
            {
                correctionStart++;
            }
            if (correctionStart < allErrorPositions.Length)                                    // if there are corrections to the data...
            {
                int[] errorMagnitudes = Forney(evaluator, allErrorPositions, correctionStart); // apply them
                for (int i = 0; i < errorMagnitudes.Length; i++)
                {
                    destination[destIndex + allErrorPositions[i + correctionStart] - EccLength] ^= (byte)errorMagnitudes[i];
                }
            }

            return(length - EccLength);
        }
示例#4
0
        public void T02_PolynomialBasics()
        {
            GF2pField field = new GF2pField(8);

            TestHelpers.TestException <ArgumentNullException>(() => new GF2pPolynomial(null, 0));
            TestHelpers.TestException <ArgumentNullException>(() => new GF2pPolynomial(null, new int[0]));
            TestHelpers.TestException <ArgumentOutOfRangeException>("within the field", () => new GF2pPolynomial(field, -1));
            TestHelpers.TestException <ArgumentOutOfRangeException>("within the field", () => new GF2pPolynomial(field, 256));
            TestHelpers.TestException <ArgumentOutOfRangeException>("within the field", () => new GF2pPolynomial(field, new[] { -1 }));
            TestHelpers.TestException <ArgumentOutOfRangeException>("within the field", () => new GF2pPolynomial(field, new[] { 256 }));

            GF2pPolynomial zero = new GF2pPolynomial(field, 0);
            GF2pPolynomial p    = new GF2pPolynomial(field, new[] { 0, 1, 254, 255, 0, 0 });

            Assert.AreEqual(0, p[0]); // test the indexer
            Assert.AreEqual(1, p[1]);
            Assert.AreEqual(254, p[2]);
            Assert.AreEqual(255, p[3]);

            Assert.AreEqual(3, p.Degree); // test various properties
            Assert.AreEqual(-1, zero.Degree);
            Assert.AreEqual(field, zero.Field);
            Assert.AreEqual(field, p.Field);
            Assert.IsTrue(zero.IsZero);
            Assert.IsFalse(p.IsZero);
            Assert.AreEqual(0, zero.Length);
            Assert.AreEqual(4, p.Length);

            Assert.IsTrue(p.Equals((object)(new GF2pPolynomial(field, 0, 1) + new GF2pPolynomial(field, 0, 0, 254, 255)))); // test Equals
            Assert.IsTrue(p.Equals(new GF2pPolynomial(new GF2pField(8), 0, 1, 254, 255)));                                  // check that the field instance can be different
            Assert.IsFalse(p.Equals(new GF2pPolynomial(new GF2pField(8, 333), 0, 1, 254, 255)));                            // but it must be compatible
            Assert.IsFalse(p.Equals(new GF2pPolynomial(field, 0, 1, 3, 4)));
            Assert.IsTrue(p.Equals(p));
            Assert.IsTrue(zero.Equals(zero));
            Assert.IsTrue(zero.Equals(default(GF2pPolynomial)));
            Assert.IsFalse(p.Equals(zero));
            Assert.IsFalse(zero.Equals(p));
            Assert.AreNotEqual(zero.GetHashCode(), p.GetHashCode()); // test GetHashCode. mostly just make sure it doesn't throw
            Assert.IsTrue(p == new GF2pPolynomial(field, 0, 1, 254, 255));
            Assert.IsFalse(p != new GF2pPolynomial(field, 0, 1, 254, 255));
            Assert.IsFalse(p == zero);
            Assert.IsTrue(p != zero);

            TestHelpers.AssertArrayEquals(zero.ToArray(), new int[0]); // test ToArray
            TestHelpers.AssertArrayEquals(p.ToArray(), 0, 1, 254, 255);

            Assert.AreEqual("0", zero.ToString()); // test ToString and Parse
            Assert.AreEqual("17 + 2x", new GF2pPolynomial(field, 17, 2).ToString());
            Assert.AreEqual("x + 254x^2 + 255x^3", p.ToString());
            Assert.AreEqual(zero, GF2pPolynomial.Parse(field, "-0"));
            Assert.AreEqual(p, GF2pPolynomial.Parse(field, "+165x^3- 90 x^3 + x-254x^2"));

            Assert.AreEqual(p, p.Truncate(10)); // test Truncate
            Assert.AreEqual(p, p.Truncate(p.Length));
            Assert.AreEqual(new GF2pPolynomial(field, 0, 1, 254), p.Truncate(3));
            Assert.AreEqual(new GF2pPolynomial(field, 0, 1), p.Truncate(2));
            Assert.AreEqual(new GF2pPolynomial(field, 0), p.Truncate(1));
            Assert.AreEqual(new GF2pPolynomial(field, 0), new GF2pPolynomial(field, 1, 2).Truncate(0));
        }
 static GF2pPolynomial CalculateSyndromes(GF2pPolynomial message, int eccLength)
 {
     int[] syndromes = new int[eccLength]; // add a zero at the front to simply later calculations
     for (int i = 0; i < syndromes.Length; i++)
     {
         syndromes[i] = message.Evaluate(message.Field.Exp(i + 1));                           // add 1 because we assume fcr == 1
     }
     return(new GF2pPolynomial(message.Field, syndromes, false));
 }
        static GF2pPolynomial CreatePrimePolynomial(GF2pField field, int symbolCount)
        {
            GF2pPolynomial poly = new GF2pPolynomial(field, 1);

            for (int i = 1; i <= symbolCount; i++)
            {
                poly *= new GF2pPolynomial(field, new int[] { field.Exp(i), 1 }, false);                         // add 1 because fcr == 1
            }
            return(poly);
        }
示例#7
0
        public void T03_PolynomialAddition()
        {
            GF2pField      field = new GF2pField(8);
            GF2pPolynomial zero = new GF2pPolynomial(field, 0);
            GF2pPolynomial a = new GF2pPolynomial(field, 0, 1, 2, 3), b = new GF2pPolynomial(field, 5, 6, 7, 8, 9, 10);

            Assert.AreEqual(new GF2pPolynomial(field, 5 ^ 0, 6 ^ 1, 7 ^ 2, 8 ^ 3, 9, 10), a + b);
            Assert.AreEqual(new GF2pPolynomial(field, 5 ^ 0, 6 ^ 1, 7 ^ 2, 8 ^ 3, 9, 10), b + a);
            Assert.AreEqual(new GF2pPolynomial(field, 5 ^ 0, 6 ^ 1, 7 ^ 2, 8 ^ 3, 9, 10), a - b);
            Assert.AreEqual(new GF2pPolynomial(field, 5 ^ 0, 6 ^ 1, 7 ^ 2, 8 ^ 3, 9, 10), b - a);
            Assert.AreEqual(a, (a + default(GF2pPolynomial)));
            Assert.AreEqual(b, (default(GF2pPolynomial) + b));
            Assert.AreEqual(a.Field, (a + b).Field);
        }
        static GF2pPolynomial CalculateErasureLocator(int[] positions, GF2pField field)
        {
            if (positions == null)
            {
                throw new ArgumentNullException();
            }
            GF2pPolynomial locator = new GF2pPolynomial(field, 1);

            foreach (int position in positions)
            {
                locator *= new GF2pPolynomial(field, new int[] { 1, field.Exp(position) }, false);
            }
            return(locator);
        }
        static void BerlekampMassey(GF2pPolynomial syndromes, GF2pPolynomial erasureLocator, GF2pPolynomial erasureEvaluator, int erasureCount,
                                    out GF2pPolynomial errataLocator, out GF2pPolynomial errataEvaluator)
        {
            GF2pPolynomial locator, prevLocator, evaluator, prevEvaluator, a, b;

            if (erasureCount != 0)
            {
                locator = erasureLocator;
                a       = evaluator = erasureEvaluator;
            }
            else
            {
                evaluator = locator = new GF2pPolynomial(syndromes.Field, 1);
                a         = new GF2pPolynomial(syndromes.Field, 0);
            }
            b = locator;

            int L = 0;

            for (int i = 0, count = syndromes.Length - erasureCount; i < count; i++)
            {
                int k = i + erasureCount, delta = GF2pPolynomial.MultiplyAt(syndromes, locator, k);
                prevLocator   = locator;
                prevEvaluator = evaluator;
                GF2pPolynomial shiftA = a << 1, shiftB = b << 1;
                locator   += shiftB * delta;
                evaluator += shiftA * delta;
                if (delta == 0 || 2 * L > k + erasureCount + 1)
                {
                    b = shiftB;
                    a = shiftA;
                }
                else
                {
                    b = prevLocator / delta;
                    a = prevEvaluator / delta;
                    L = k + 1 - L;
                }
            }

            if (evaluator.Length > locator.Length)
            {
                evaluator = evaluator.Truncate(locator.Length);
            }
            evaluator = CalculateErrorEvaluator(syndromes, locator);

            errataLocator   = locator;
            errataEvaluator = evaluator;
        }
示例#10
0
 static int[] Forney(GF2pPolynomial evaluator, int[] errorPositions, int startIndex)
 {
     int[] powers = new int[errorPositions.Length], magnitudes = new int[powers.Length - startIndex];
     for (int i = 0; i < powers.Length; i++)
     {
         powers[i] = evaluator.Field.Exp(errorPositions[i]);
     }
     for (int i = 0; i < magnitudes.Length; i++)
     {
         int invPower = evaluator.Field.Invert(powers[i + startIndex]), divisor = 1;
         for (int ei = 0; ei < powers.Length; ei++)
         {
             if (ei != i + startIndex)
             {
                 divisor = evaluator.Field.Multiply(divisor, evaluator.Field.Multiply(powers[ei], invPower) ^ 1);
             }
         }
         magnitudes[i] = evaluator.Field.Divide(evaluator.Evaluate(invPower), divisor);
     }
     return(magnitudes);
 }
示例#11
0
        public void T06_PolynomialDivision()
        {
            Action <GF2pPolynomial, GF2pPolynomial, GF2pPolynomial, GF2pPolynomial> testDivision = (a, b, q, r) =>
            {
                Assert.AreEqual(q, a / b);
                Assert.AreEqual(r, a % b);
                GF2pPolynomial remainder;
                Assert.AreEqual(q, a.DivRem(b, out remainder));
                Assert.AreEqual(r, remainder);
                Assert.AreEqual(q, GF2pPolynomial.DivRem(a, b, out remainder));
                Assert.AreEqual(r, remainder);
            };

            GF2pField      field = new GF2pField(8);
            GF2pPolynomial x = new GF2pPolynomial(field, 0, 4, 17, 0, 9, 1), y = new GF2pPolynomial(field, 19, 11, 0, 100);

            testDivision(x, y, new GF2pPolynomial(field, 136, 24, 185), new GF2pPolynomial(field, 237, 0, 112));
            testDivision(y, x, new GF2pPolynomial(field, 0), y);
            x = new GF2pPolynomial(field, 1, 2, 3, 4);
            testDivision(x, y, new GF2pPolynomial(field, 222), new GF2pPolynomial(field, 31, 195, 3));
            testDivision(y, x, new GF2pPolynomial(field, 25), new GF2pPolynomial(field, 10, 57, 43));
        }
示例#12
0
        public void T04_PolynomialShifting()
        {
            GF2pField      field = new GF2pField(8);
            GF2pPolynomial p     = new GF2pPolynomial(field, 0, 1, 0, 2, 0, 3);

            Assert.AreEqual(new GF2pPolynomial(field, 1, 0, 2, 0, 3), p >> 1);
            Assert.AreEqual(new GF2pPolynomial(field, 0, 2, 0, 3), p >> 2);
            Assert.AreEqual(new GF2pPolynomial(field, 2, 0, 3), p >> 3);
            Assert.AreEqual(new GF2pPolynomial(field, 0), p >> 6);
            Assert.AreEqual(new GF2pPolynomial(field, 0), p >> 8);

            Assert.AreEqual(new GF2pPolynomial(field, 1, 0, 2, 0, 3), p << -1);
            Assert.AreEqual(new GF2pPolynomial(field, 0, 2, 0, 3), p << -2);
            Assert.AreEqual(new GF2pPolynomial(field, 2, 0, 3), p << -3);
            Assert.AreEqual(new GF2pPolynomial(field, 0), p << -6);
            Assert.AreEqual(new GF2pPolynomial(field, 0), p << -8);

            Assert.AreEqual(new GF2pPolynomial(field, 0, 0, 1, 0, 2, 0, 3), p << 1);
            Assert.AreEqual(new GF2pPolynomial(field, 0, 0, 0, 1, 0, 2, 0, 3), p << 2);
            Assert.AreEqual(new GF2pPolynomial(field, 0, 0, 1, 0, 2, 0, 3), p >> -1);
            Assert.AreEqual(new GF2pPolynomial(field, 0, 0, 0, 1, 0, 2, 0, 3), p >> -2);
        }
示例#13
0
        static int[] FindErrors(GF2pPolynomial locator, int dataLength)
        { // TODO: ideally we'd use the more efficient Chien's search here rather than this brute-force approach
            int[] errorPositions = new int[locator.Degree];
            int   ei             = 0;

            for (int maxValue = (int)(locator.Field.Order - 1), di = 0; di < dataLength; di++)
            {
                if (locator.Evaluate(locator.Field.Exp(maxValue - di)) == 0)
                {
                    if (ei != errorPositions.Length)
                    {
                        errorPositions[ei++] = di;
                    }
                    else
                    {
                        return(null);
                    }
                }
            }

            return(ei == errorPositions.Length ? errorPositions : null);
        }
示例#14
0
 static GF2pPolynomial CalculateErrorEvaluator(GF2pPolynomial syndromes, GF2pPolynomial locator)
 {
     return((syndromes * locator).Truncate(syndromes.Length) << 1);
 }