public void encode(int[] toEncode, int ecBytes) { if (ecBytes == 0) { throw new System.ArgumentException("No error correction bytes"); } int dataBytes = toEncode.Length - ecBytes; if (dataBytes <= 0) { throw new System.ArgumentException("No data bytes provided"); } GenericGFPoly generator = buildGenerator(ecBytes); int[] infoCoefficients = new int[dataBytes]; Array.Copy(toEncode, 0, infoCoefficients, 0, dataBytes); GenericGFPoly info = new GenericGFPoly(field, infoCoefficients); info = info.multiplyByMonomial(ecBytes, 1); GenericGFPoly remainder = info.divide(generator)[1]; int[] coefficients = remainder.Coefficients; int numZeroCoefficients = ecBytes - coefficients.Length; for (int i = 0; i < numZeroCoefficients; i++) { toEncode[dataBytes + i] = 0; } Array.Copy(coefficients, 0, toEncode, dataBytes + numZeroCoefficients, coefficients.Length); }
private int[] findErrorLocations(GenericGFPoly errorLocator) { // This is a direct application of Chien's search int numErrors = errorLocator.Degree; if (numErrors == 1) { // shortcut return(new int[] { errorLocator.getCoefficient(1) }); } int[] result = new int[numErrors]; int e = 0; for (int i = 1; i < field.Size && e < numErrors; i++) { if (errorLocator.evaluateAt(i) == 0) { result[e] = field.inverse(i); e++; } } if (e != numErrors) { // throw new ReedSolomonException("Error locator degree does not match number of roots"); return(null); } return(result); }
private int[] findErrorMagnitudes(GenericGFPoly errorEvaluator, int[] errorLocations) { // This is directly applying Forney's Formula int s = errorLocations.Length; int[] result = new int[s]; for (int i = 0; i < s; i++) { int xiInverse = field.inverse(errorLocations[i]); int denominator = 1; for (int j = 0; j < s; j++) { if (i != j) { denominator = field.multiply(denominator, GenericGF.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse))); } } if (denominator == 0) { return(null); } result[i] = field.multiply(errorEvaluator.evaluateAt(xiInverse), field.inverse(denominator)); if (field.GeneratorBase != 0) { result[i] = field.multiply(result[i], xiInverse); } } return(result); }
private int[] findErrorMagnitudes(GenericGFPoly errorEvaluator, int[] errorLocations) { // This is directly applying Forney's Formula int s = errorLocations.Length; int[] result = new int[s]; for (int i = 0; i < s; i++) { int xiInverse = field.inverse(errorLocations[i]); int denominator = 1; for (int j = 0; j < s; j++) { if (i != j) { //denominator = field.multiply(denominator, // GenericGF.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse))); // Above should work but fails on some Apple and Linux JDKs due to a Hotspot bug. // Below is a funny-looking workaround from Steven Parkes int term = field.multiply(errorLocations[j], xiInverse); int termPlus1 = (term & 0x1) == 0 ? term | 1 : term & ~1; denominator = field.multiply(denominator, termPlus1); // removed in java version, not sure if this is right // denominator = field.multiply(denominator, GenericGF.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse))); } } result[i] = field.multiply(errorEvaluator.evaluateAt(xiInverse), field.inverse(denominator)); if (field.GeneratorBase != 0) { result[i] = field.multiply(result[i], xiInverse); } } return(result); }
private GenericGFPoly[] runEuclideanAlgorithm(GenericGFPoly a, GenericGFPoly b, int R) { // Assume a's degree is >= b's if (a.Degree < b.Degree) { GenericGFPoly temp = a; a = b; b = temp; } GenericGFPoly rLast = a; GenericGFPoly r = b; GenericGFPoly tLast = field.Zero; GenericGFPoly t = field.One; // Run Euclidean algorithm until r's degree is less than R/2 while (r.Degree >= R / 2) { GenericGFPoly rLastLast = rLast; GenericGFPoly tLastLast = tLast; rLast = r; tLast = t; // Divide rLastLast by rLast, with quotient in q and remainder in r if (rLast.isZero) { // Oops, Euclidean algorithm already terminated? // throw new ReedSolomonException("r_{i-1} was zero"); return(null); } r = rLastLast; GenericGFPoly q = field.Zero; int denominatorLeadingTerm = rLast.getCoefficient(rLast.Degree); int dltInverse = field.inverse(denominatorLeadingTerm); while (r.Degree >= rLast.Degree && !r.isZero) { int degreeDiff = r.Degree - rLast.Degree; int scale = field.multiply(r.getCoefficient(r.Degree), dltInverse); q = q.addOrSubtract(field.buildMonomial(degreeDiff, scale)); r = r.addOrSubtract(rLast.multiplyByMonomial(degreeDiff, scale)); } t = q.multiply(tLast).addOrSubtract(tLastLast); } int sigmaTildeAtZero = t.getCoefficient(0); if (sigmaTildeAtZero == 0) { // throw new ReedSolomonException("sigmaTilde(0) was zero"); return(null); } int inverse = field.inverse(sigmaTildeAtZero); GenericGFPoly sigma = t.multiply(inverse); GenericGFPoly omega = r.multiply(inverse); return(new GenericGFPoly[] { sigma, omega }); }
internal GenericGFPoly calculateForneySyndromes(GenericGFPoly syndromes, int messageLength) { int[] syndromeCoefficients = new int[syndromes.Coefficients.Length]; Array.Copy(syndromes.Coefficients, 0, syndromeCoefficients, 0, syndromes.Coefficients.Length); GenericGFPoly forneySyndromes = new GenericGFPoly(field, syndromeCoefficients, false); return(forneySyndromes); }
public void testPolynomialString() { Assert.That(FIELD.Zero.ToString(), Is.EqualTo("0")); Assert.That(FIELD.buildMonomial(0, -1).ToString(), Is.EqualTo("-1")); var p = new GenericGFPoly(FIELD, new int[] { 3, 0, -2, 1, 1 }); Assert.That(p.ToString(), Is.EqualTo("a^25x^4 - ax^2 + x + 1")); p = new GenericGFPoly(FIELD, new int[] { 3 }); Assert.That(p.ToString(), Is.EqualTo("a^25")); }
/// <summary> <p>Decodes given set of received codewords, which include both data and error-correction /// codewords. Really, this means it uses Reed-Solomon to detect and correct errors, in-place, /// in the input.</p> /// /// </summary> /// <param name="received">data and error-correction codewords /// </param> /// <param name="twoS">number of error-correction codewords available /// </param> /// <throws> ReedSolomonException if decoding fails for any reason </throws> public bool decode(int[] received, int twoS) { GenericGFPoly poly = new GenericGFPoly(field, received); int[] syndromeCoefficients = new int[twoS]; bool dataMatrix = field.Equals(GenericGF.DATA_MATRIX_FIELD_256); bool noError = true; for (int i = 0; i < twoS; i++) { // Thanks to sanfordsquires for this fix: int eval = poly.evaluateAt(field.exp(dataMatrix ? i + 1 : i)); syndromeCoefficients[syndromeCoefficients.Length - 1 - i] = eval; if (eval != 0) { noError = false; } } if (noError) { return(true); } GenericGFPoly syndrome = new GenericGFPoly(field, syndromeCoefficients); GenericGFPoly[] sigmaOmega = runEuclideanAlgorithm(field.buildMonomial(twoS, 1), syndrome, twoS); if (sigmaOmega == null) { return(false); } GenericGFPoly sigma = sigmaOmega[0]; int[] errorLocations = findErrorLocations(sigma); if (errorLocations == null) { return(false); } GenericGFPoly omega = sigmaOmega[1]; int[] errorMagnitudes = findErrorMagnitudes(omega, errorLocations, dataMatrix); for (int i = 0; i < errorLocations.Length; i++) { int position = received.Length - 1 - field.log(errorLocations[i]); if (position < 0) { // throw new ReedSolomonException("Bad error location"); return(false); } received[position] = GenericGF.addOrSubtract(received[position], errorMagnitudes[i]); } return(true); }
private GenericGFPoly findErrorLocator(int[] errorPositions) { GenericGFPoly errataLocator = new GenericGFPoly(field, new int[] { 1 }, false); foreach (int i in errorPositions) { errataLocator = errataLocator.multiply(new GenericGFPoly(field, new int[] { 1 }, false).addOrSubtract(new GenericGFPoly(field, new int[] { field.exp(i), 0 }, false))); } return(errataLocator); }
/// <summary> /// <p>Decodes given set of received codewords, which include both data and error-correction /// codewords. Really, this means it uses Reed-Solomon to detect and correct errors, in-place, /// in the input.</p> /// </summary> /// <param name="received">data and error-correction codewords</param> /// <param name="twoS">number of error-correction codewords available</param> /// <returns>false: decoding fails</returns> public bool decode(int[] received, int twoS) { var poly = new GenericGFPoly(field, received); var syndromeCoefficients = new int[twoS]; var noError = true; for (var i = 0; i < twoS; i++) { var eval = poly.evaluateAt(field.exp(i + field.GeneratorBase)); syndromeCoefficients[syndromeCoefficients.Length - 1 - i] = eval; if (eval != 0) { noError = false; } } if (noError) { return(true); } var syndrome = new GenericGFPoly(field, syndromeCoefficients); var sigmaOmega = runEuclideanAlgorithm(field.buildMonomial(twoS, 1), syndrome, twoS); if (sigmaOmega == null) { return(false); } var sigma = sigmaOmega[0]; var errorLocations = findErrorLocations(sigma); if (errorLocations == null) { return(false); } var omega = sigmaOmega[1]; var errorMagnitudes = findErrorMagnitudes(omega, errorLocations); for (var i = 0; i < errorLocations.Length; i++) { var position = received.Length - 1 - field.log(errorLocations[i]); if (position < 0) { // throw new ReedSolomonException("Bad error location"); return(false); } received[position] = GenericGF.addOrSubtract(received[position], errorMagnitudes[i]); } return(true); }
private GenericGFPoly findErrorEvaluator(GenericGFPoly syndrome, GenericGFPoly errataLocations) { int[] product = syndrome.multiply(errataLocations).Coefficients; int[] target = new int[errataLocations.Coefficients.Length - 1]; Array.Copy(product, product.Length - errataLocations.Coefficients.Length + 1, target, 0, target.Length); if (target.Length == 0) { return(null); } GenericGFPoly omega = new GenericGFPoly(field, target, false); return(omega); }
/// <summary> <p>Decodes given set of received codewords, which include both data and error-correction /// codewords. Really, this means it uses Reed-Solomon to detect and correct errors, in-place, /// in the input.</p> /// /// </summary> /// <param name="received">data and error-correction codewords /// </param> /// <param name="twoS">number of error-correction codewords available /// </param> /// <throws> ReedSolomonException if decoding fails for any reason </throws> public bool decode(int[] received, int twoS) { GenericGFPoly poly = new GenericGFPoly(field, received); int[] syndromeCoefficients = new int[twoS]; bool dataMatrix = field.Equals(GenericGF.DATA_MATRIX_FIELD_256); bool noError = true; for (int i = 0; i < twoS; i++) { // Thanks to sanfordsquires for this fix: int eval = poly.evaluateAt(field.exp(dataMatrix ? i + 1 : i)); syndromeCoefficients[syndromeCoefficients.Length - 1 - i] = eval; if (eval != 0) { noError = false; } } if (noError) { return true; } GenericGFPoly syndrome = new GenericGFPoly(field, syndromeCoefficients); GenericGFPoly[] sigmaOmega = runEuclideanAlgorithm(field.buildMonomial(twoS, 1), syndrome, twoS); if (sigmaOmega == null) return false; GenericGFPoly sigma = sigmaOmega[0]; int[] errorLocations = findErrorLocations(sigma); if (errorLocations == null) return false; GenericGFPoly omega = sigmaOmega[1]; int[] errorMagnitudes = findErrorMagnitudes(omega, errorLocations, dataMatrix); for (int i = 0; i < errorLocations.Length; i++) { int position = received.Length - 1 - field.log(errorLocations[i]); if (position < 0) { // throw new ReedSolomonException("Bad error location"); return false; } received[position] = GenericGF.addOrSubtract(received[position], errorMagnitudes[i]); } return true; }
/// <summary> /// <p>Decodes given set of received codewords, which include both data and error-correction /// codewords. Really, this means it uses Reed-Solomon to detect and correct errors, in-place, /// in the input.</p> /// </summary> /// <param name="received">data and error-correction codewords</param> /// <param name="twoS">number of error-correction codewords available</param> /// <returns>false: decoding fails</returns> public bool decode(int[] received, int twoS) { var poly = new GenericGFPoly(field, received); var syndromeCoefficients = new int[twoS]; var noError = true; for (var i = 0; i < twoS; i++) { var eval = poly.evaluateAt(field.exp(i + field.GeneratorBase)); syndromeCoefficients[syndromeCoefficients.Length - 1 - i] = eval; if (eval != 0) { noError = false; } } if (noError) { return true; } var syndrome = new GenericGFPoly(field, syndromeCoefficients); var sigmaOmega = runEuclideanAlgorithm(field.buildMonomial(twoS, 1), syndrome, twoS); if (sigmaOmega == null) return false; var sigma = sigmaOmega[0]; var errorLocations = findErrorLocations(sigma); if (errorLocations == null) return false; var omega = sigmaOmega[1]; var errorMagnitudes = findErrorMagnitudes(omega, errorLocations); for (var i = 0; i < errorLocations.Length; i++) { var position = received.Length - 1 - field.log(errorLocations[i]); if (position < 0) { // throw new ReedSolomonException("Bad error location"); return false; } received[position] = GenericGF.addOrSubtract(received[position], errorMagnitudes[i]); } return true; }
internal GenericGFPoly runBerlekampMasseyAlgorithm(GenericGFPoly syndrome) { GenericGFPoly sigma = new GenericGFPoly(field, new int[] { 1 }, false); GenericGFPoly old = new GenericGFPoly(field, new int[] { 1 }, false); for (int i = 0; i < (syndrome.Coefficients.Length); i++) { int delta = syndrome.getCoefficient(i); for (int j = 1; j < sigma.Coefficients.Length; j++) { delta ^= field.multiply(sigma.getCoefficient(j), syndrome.getCoefficient(i - j)); } List <int> oldList = new List <int>(old.Coefficients); oldList.Add(0); old = new GenericGFPoly(field, oldList.ToArray(), false); if (delta != 0) { if (old.Coefficients.Length > sigma.Coefficients.Length) { GenericGFPoly new_loc = old.multiply(delta); old = sigma.multiply(field.inverse(delta)); sigma = new_loc; } sigma = sigma.addOrSubtract(old.multiply(delta)); } } List <int> sigmaList = new List <int>(sigma.Coefficients); while (Convert.ToBoolean(sigmaList.Count) && sigmaList[0] == 0) { sigmaList.RemoveAt(0); } sigma = new GenericGFPoly(field, sigmaList.ToArray(), false); return(sigma); }
public void Encode(int[] toEncode, int ecBytes) { if (toEncode.Length >= field.Size) { throw new ArgumentException("Message is too long for this field", "toEncode"); } if (ecBytes <= 0) { throw new ArgumentException("No error correction bytes provided", "ecBytes"); } var dataBytes = toEncode.Length - ecBytes; if (dataBytes <= 0) { throw new ArgumentException("No data bytes provided", "ecBytes"); } var generator = buildGenerator(ecBytes); var infoCoefficients = new int[dataBytes]; Array.Copy(toEncode, 0, infoCoefficients, 0, dataBytes); var info = new GenericGFPoly(field, infoCoefficients, true); info = info.multiplyByMonomial(ecBytes, 1); var remainder = info.divide(generator)[1]; var coefficients = remainder.Coefficients; var numZeroCoefficients = ecBytes - coefficients.Length; for (var i = 0; i < numZeroCoefficients; i++) { toEncode[dataBytes + i] = 0; } Array.Copy(coefficients, 0, toEncode, dataBytes + numZeroCoefficients, coefficients.Length); }
internal GenericGFPoly[] runEuclideanAlgorithm(GenericGFPoly a, GenericGFPoly b, int R) { // Assume a's degree is >= b's if (a.Degree < b.Degree) { GenericGFPoly temp = a; a = b; b = temp; } GenericGFPoly rLast = a; GenericGFPoly r = b; GenericGFPoly tLast = field.Zero; GenericGFPoly t = field.One; // Run Euclidean algorithm until r's degree is less than R/2 while (r.Degree >= R / 2) { GenericGFPoly rLastLast = rLast; GenericGFPoly tLastLast = tLast; rLast = r; tLast = t; // Divide rLastLast by rLast, with quotient in q and remainder in r if (rLast.isZero) { // Oops, Euclidean algorithm already terminated? // throw new ReedSolomonException("r_{i-1} was zero"); return null; } r = rLastLast; GenericGFPoly q = field.Zero; int denominatorLeadingTerm = rLast.getCoefficient(rLast.Degree); int dltInverse = field.inverse(denominatorLeadingTerm); while (r.Degree >= rLast.Degree && !r.isZero) { int degreeDiff = r.Degree - rLast.Degree; int scale = field.multiply(r.getCoefficient(r.Degree), dltInverse); q = q.addOrSubtract(field.buildMonomial(degreeDiff, scale)); r = r.addOrSubtract(rLast.multiplyByMonomial(degreeDiff, scale)); } t = q.multiply(tLast).addOrSubtract(tLastLast); if (r.Degree >= rLast.Degree) { // throw new IllegalStateException("Division algorithm failed to reduce polynomial?"); return null; } } int sigmaTildeAtZero = t.getCoefficient(0); if (sigmaTildeAtZero == 0) { // throw new ReedSolomonException("sigmaTilde(0) was zero"); return null; } int inverse = field.inverse(sigmaTildeAtZero); GenericGFPoly sigma = t.multiply(inverse); GenericGFPoly omega = r.multiply(inverse); return new GenericGFPoly[] { sigma, omega }; }
private int[] findErrorLocations(GenericGFPoly errorLocator) { // This is a direct application of Chien's search int numErrors = errorLocator.Degree; if (numErrors == 1) { // shortcut return new int[] { errorLocator.getCoefficient(1) }; } int[] result = new int[numErrors]; int e = 0; for (int i = 1; i < field.Size && e < numErrors; i++) { if (errorLocator.evaluateAt(i) == 0) { result[e] = field.inverse(i); e++; } } if (e != numErrors) { // throw new ReedSolomonException("Error locator degree does not match number of roots"); return null; } return result; }
private int[] findErrorMagnitudes(GenericGFPoly errorEvaluator, int[] errorLocations) { // This is directly applying Forney's Formula int s = errorLocations.Length; int[] result = new int[s]; for (int i = 0; i < s; i++) { int xiInverse = field.inverse(errorLocations[i]); int denominator = 1; for (int j = 0; j < s; j++) { if (i != j) { //denominator = field.multiply(denominator, // GenericGF.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse))); // Above should work but fails on some Apple and Linux JDKs due to a Hotspot bug. // Below is a funny-looking workaround from Steven Parkes int term = field.multiply(errorLocations[j], xiInverse); int termPlus1 = (term & 0x1) == 0 ? term | 1 : term & ~1; denominator = field.multiply(denominator, termPlus1); // removed in java version, not sure if this is right // denominator = field.multiply(denominator, GenericGF.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse))); } } result[i] = field.multiply(errorEvaluator.evaluateAt(xiInverse), field.inverse(denominator)); if (field.GeneratorBase != 0) { result[i] = field.multiply(result[i], xiInverse); } } return result; }
public bool Decode(int[] received, int twoS) { if (received.Length >= field.Size) { throw new ArgumentException("Message is too long for this field", "received"); } if (twoS <= 0) { throw new ArgumentException("No error correction bytes provided", "twoS"); } var dataBytes = received.Length - twoS; if (dataBytes <= 0) { throw new ArgumentException("No data bytes provided", "twoS"); } var syndromeCoefficients = new int[twoS]; var noError = true; var poly = new GenericGFPoly(field, received, false); for (var i = 0; i < twoS; i++) { var eval = poly.evaluateAt(field.exp(i + field.GeneratorBase)); syndromeCoefficients[syndromeCoefficients.Length - 1 - i] = eval; if (eval != 0) { noError = false; } } if (noError) { return(true); } var syndrome = new GenericGFPoly(field, syndromeCoefficients, false); var forneySyndrome = calculateForneySyndromes(syndrome, received.Length); var sigma = runBerlekampMasseyAlgorithm(forneySyndrome); if (sigma == null) { return(false); } var errorLocations = findErrorLocations(sigma); if (errorLocations == null) { return(false); } // Prepare errors int[] errorPositions = new int[errorLocations.Length]; for (int i = 0; i < errorLocations.Length; i++) { errorPositions[i] = field.log(errorLocations[i]); } var errorLocator = findErrorLocator(errorPositions); var omega = findErrorEvaluator(syndrome, errorLocator); if (omega == null) { return(false); } int[] errors = new int[errorPositions.Length]; for (int i = 0; i < errorPositions.Length; i++) { errors[i] = field.exp(errorPositions[i]); } var errorMagnitudes = findErrorMagnitudes(omega, errors); if (errorMagnitudes == null) { return(false); } for (var i = 0; i < errors.Length; i++) { var position = received.Length - 1 - field.log(errors[i]); if (position < 0) { // throw new ReedSolomonException("Bad error location"); return(false); } received[position] = GenericGF.addOrSubtract(received[position], errorMagnitudes[i]); } var checkPoly = new GenericGFPoly(field, received, false); var error = false; for (var i = 0; i < twoS; i++) { var eval = checkPoly.evaluateAt(field.exp(i + field.GeneratorBase)); if (eval != 0) { error = true; } } if (error) { return(false); } return(true); }