From 76127b8bfe368a3f1ff90444ff693b4bb7af28af Mon Sep 17 00:00:00 2001 From: Project Nayuki Date: Sun, 14 Jul 2019 17:09:51 +0000 Subject: [PATCH] Renamed functions and variables, and updated comments, thus synchronizing the C language version with the previous changeset. --- c/qrcodegen-test.c | 48 +++++++++++++++++++++++----------------------- c/qrcodegen.c | 43 +++++++++++++++++++++-------------------- 2 files changed, 46 insertions(+), 45 deletions(-) diff --git a/c/qrcodegen-test.c b/c/qrcodegen-test.c index fb91b75..db48b11 100644 --- a/c/qrcodegen-test.c +++ b/c/qrcodegen-test.c @@ -49,9 +49,9 @@ void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bi void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]); int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl); int getNumRawDataModules(int version); -void calcReedSolomonGenerator(int degree, uint8_t result[]); -void calcReedSolomonRemainder(const uint8_t data[], int dataLen, const uint8_t generator[], int degree, uint8_t result[]); -uint8_t finiteFieldMultiply(uint8_t x, uint8_t y); +void reedSolomonComputeDivisor(int degree, uint8_t result[]); +void reedSolomonComputeRemainder(const uint8_t data[], int dataLen, const uint8_t generator[], int degree, uint8_t result[]); +uint8_t reedSolomonMultiply(uint8_t x, uint8_t y); void initializeFunctionModules(int version, uint8_t qrcode[]); int getAlignmentPatternPositions(int version, uint8_t result[7]); bool getModule(const uint8_t qrcode[], int x, int y); @@ -116,12 +116,12 @@ static uint8_t *addEccAndInterleaveReference(const uint8_t *data, int version, e // Split data into blocks and append ECC to each block uint8_t **blocks = malloc(numBlocks * sizeof(uint8_t*)); uint8_t *generator = malloc(blockEccLen * sizeof(uint8_t)); - calcReedSolomonGenerator(blockEccLen, generator); + reedSolomonComputeDivisor(blockEccLen, generator); for (int i = 0, k = 0; i < numBlocks; i++) { uint8_t *block = malloc((shortBlockLen + 1) * sizeof(uint8_t)); int datLen = shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1); memcpy(block, &data[k], datLen * sizeof(uint8_t)); - calcReedSolomonRemainder(&data[k], datLen, generator, blockEccLen, &block[shortBlockLen + 1 - blockEccLen]); + reedSolomonComputeRemainder(&data[k], datLen, generator, blockEccLen, &block[shortBlockLen + 1 - blockEccLen]); k += datLen; blocks[i] = block; } @@ -235,19 +235,19 @@ static void testGetNumRawDataModules(void) { } -static void testCalcReedSolomonGenerator(void) { +static void testReedSolomonComputeDivisor(void) { uint8_t generator[30]; - calcReedSolomonGenerator(1, generator); + reedSolomonComputeDivisor(1, generator); assert(generator[0] == 0x01); numTestCases++; - calcReedSolomonGenerator(2, generator); + reedSolomonComputeDivisor(2, generator); assert(generator[0] == 0x03); assert(generator[1] == 0x02); numTestCases++; - calcReedSolomonGenerator(5, generator); + reedSolomonComputeDivisor(5, generator); assert(generator[0] == 0x1F); assert(generator[1] == 0xC6); assert(generator[2] == 0x3F); @@ -255,7 +255,7 @@ static void testCalcReedSolomonGenerator(void) { assert(generator[4] == 0x74); numTestCases++; - calcReedSolomonGenerator(30, generator); + reedSolomonComputeDivisor(30, generator); assert(generator[ 0] == 0xD4); assert(generator[ 1] == 0xF6); assert(generator[ 5] == 0xC0); @@ -268,13 +268,13 @@ static void testCalcReedSolomonGenerator(void) { } -static void testCalcReedSolomonRemainder(void) { +static void testReedSolomonComputeRemainder(void) { { uint8_t data[1]; uint8_t generator[3]; uint8_t remainder[ARRAY_LENGTH(generator)]; - calcReedSolomonGenerator(ARRAY_LENGTH(generator), generator); - calcReedSolomonRemainder(data, 0, generator, ARRAY_LENGTH(generator), remainder); + reedSolomonComputeDivisor(ARRAY_LENGTH(generator), generator); + reedSolomonComputeRemainder(data, 0, generator, ARRAY_LENGTH(generator), remainder); assert(remainder[0] == 0); assert(remainder[1] == 0); assert(remainder[2] == 0); @@ -284,8 +284,8 @@ static void testCalcReedSolomonRemainder(void) { uint8_t data[2] = {0, 1}; uint8_t generator[4]; uint8_t remainder[ARRAY_LENGTH(generator)]; - calcReedSolomonGenerator(ARRAY_LENGTH(generator), generator); - calcReedSolomonRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder); + reedSolomonComputeDivisor(ARRAY_LENGTH(generator), generator); + reedSolomonComputeRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder); assert(remainder[0] == generator[0]); assert(remainder[1] == generator[1]); assert(remainder[2] == generator[2]); @@ -296,8 +296,8 @@ static void testCalcReedSolomonRemainder(void) { uint8_t data[5] = {0x03, 0x3A, 0x60, 0x12, 0xC7}; uint8_t generator[5]; uint8_t remainder[ARRAY_LENGTH(generator)]; - calcReedSolomonGenerator(ARRAY_LENGTH(generator), generator); - calcReedSolomonRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder); + reedSolomonComputeDivisor(ARRAY_LENGTH(generator), generator); + reedSolomonComputeRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder); assert(remainder[0] == 0xCB); assert(remainder[1] == 0x36); assert(remainder[2] == 0x16); @@ -315,8 +315,8 @@ static void testCalcReedSolomonRemainder(void) { }; uint8_t generator[30]; uint8_t remainder[ARRAY_LENGTH(generator)]; - calcReedSolomonGenerator(ARRAY_LENGTH(generator), generator); - calcReedSolomonRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder); + reedSolomonComputeDivisor(ARRAY_LENGTH(generator), generator); + reedSolomonComputeRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder); assert(remainder[ 0] == 0xCE); assert(remainder[ 1] == 0xF0); assert(remainder[ 2] == 0x31); @@ -333,7 +333,7 @@ static void testCalcReedSolomonRemainder(void) { } -static void testFiniteFieldMultiply(void) { +static void testReedSolomonMultiply(void) { const uint8_t cases[][3] = { {0x00, 0x00, 0x00}, {0x01, 0x01, 0x01}, @@ -354,7 +354,7 @@ static void testFiniteFieldMultiply(void) { }; for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) { const uint8_t *tc = cases[i]; - assert(finiteFieldMultiply(tc[0], tc[1]) == tc[2]); + assert(reedSolomonMultiply(tc[0], tc[1]) == tc[2]); numTestCases++; } } @@ -1054,9 +1054,9 @@ int main(void) { testAddEccAndInterleave(); testGetNumDataCodewords(); testGetNumRawDataModules(); - testCalcReedSolomonGenerator(); - testCalcReedSolomonRemainder(); - testFiniteFieldMultiply(); + testReedSolomonComputeDivisor(); + testReedSolomonComputeRemainder(); + testReedSolomonMultiply(); testInitializeFunctionModulesEtc(); testGetAlignmentPatternPositions(); testGetSetModule(); diff --git a/c/qrcodegen.c b/c/qrcodegen.c index 84b47c8..d899803 100644 --- a/c/qrcodegen.c +++ b/c/qrcodegen.c @@ -58,10 +58,10 @@ testable void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ec testable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl); testable int getNumRawDataModules(int ver); -testable void calcReedSolomonGenerator(int degree, uint8_t result[]); -testable void calcReedSolomonRemainder(const uint8_t data[], int dataLen, +testable void reedSolomonComputeDivisor(int degree, uint8_t result[]); +testable void reedSolomonComputeRemainder(const uint8_t data[], int dataLen, const uint8_t generator[], int degree, uint8_t result[]); -testable uint8_t finiteFieldMultiply(uint8_t x, uint8_t y); +testable uint8_t reedSolomonMultiply(uint8_t x, uint8_t y); testable void initializeFunctionModules(int version, uint8_t qrcode[]); static void drawWhiteFunctionModules(uint8_t qrcode[], int version); @@ -301,13 +301,13 @@ testable void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ec // Split data into blocks, calculate ECC, and interleave // (not concatenate) the bytes into a single sequence - uint8_t generator[qrcodegen_REED_SOLOMON_DEGREE_MAX]; - calcReedSolomonGenerator(blockEccLen, generator); + uint8_t rsdiv[qrcodegen_REED_SOLOMON_DEGREE_MAX]; + reedSolomonComputeDivisor(blockEccLen, rsdiv); const uint8_t *dat = data; for (int i = 0; i < numBlocks; i++) { int datLen = shortBlockDataLen + (i < numShortBlocks ? 0 : 1); uint8_t *ecc = &data[dataLen]; // Temporary storage - calcReedSolomonRemainder(dat, datLen, generator, blockEccLen, ecc); + reedSolomonComputeRemainder(dat, datLen, rsdiv, blockEccLen, ecc); for (int j = 0, k = i; j < datLen; j++, k += numBlocks) { // Copy data if (j == shortBlockDataLen) k -= numShortBlocks; @@ -350,43 +350,44 @@ testable int getNumRawDataModules(int ver) { /*---- Reed-Solomon ECC generator functions ----*/ -// Calculates the Reed-Solomon generator polynomial of the given degree, storing in result[0 : degree]. -testable void calcReedSolomonGenerator(int degree, uint8_t result[]) { - // Start with the monomial x^0 +// Computes a Reed-Solomon ECC generator polynomial for the given degree, storing in result[0 : degree]. +// This could be implemented as a lookup table over all possible parameter values, instead of as an algorithm. +testable void reedSolomonComputeDivisor(int degree, uint8_t result[]) { assert(1 <= degree && degree <= qrcodegen_REED_SOLOMON_DEGREE_MAX); + // Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1. + // For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}. memset(result, 0, degree * sizeof(result[0])); - result[degree - 1] = 1; + result[degree - 1] = 1; // Start off with the monomial x^0 // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}), - // drop the highest term, and store the rest of the coefficients in order of descending powers. + // drop the highest monomial term which is always 1x^degree. // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D). uint8_t root = 1; for (int i = 0; i < degree; i++) { // Multiply the current product by (x - r^i) for (int j = 0; j < degree; j++) { - result[j] = finiteFieldMultiply(result[j], root); + result[j] = reedSolomonMultiply(result[j], root); if (j + 1 < degree) result[j] ^= result[j + 1]; } - root = finiteFieldMultiply(root, 0x02); + root = reedSolomonMultiply(root, 0x02); } } -// Calculates the remainder of the polynomial data[0 : dataLen] when divided by the generator[0 : degree], where all -// polynomials are in big endian and the generator has an implicit leading 1 term, storing the result in result[0 : degree]. -testable void calcReedSolomonRemainder(const uint8_t data[], int dataLen, +// Computes the Reed-Solomon error correction codeword for the given data and divisor polynomials. +// The remainder when data[0 : dataLen] is divided by divisor[0 : degree] is stored in result[0 : degree]. +// All polynomials are in big endian, and the generator has an implicit leading 1 term. +testable void reedSolomonComputeRemainder(const uint8_t data[], int dataLen, const uint8_t generator[], int degree, uint8_t result[]) { - - // Perform polynomial division assert(1 <= degree && degree <= qrcodegen_REED_SOLOMON_DEGREE_MAX); memset(result, 0, degree * sizeof(result[0])); - for (int i = 0; i < dataLen; i++) { + for (int i = 0; i < dataLen; i++) { // Polynomial division uint8_t factor = data[i] ^ result[0]; memmove(&result[0], &result[1], (degree - 1) * sizeof(result[0])); result[degree - 1] = 0; for (int j = 0; j < degree; j++) - result[j] ^= finiteFieldMultiply(generator[j], factor); + result[j] ^= reedSolomonMultiply(generator[j], factor); } } @@ -395,7 +396,7 @@ testable void calcReedSolomonRemainder(const uint8_t data[], int dataLen, // Returns the product of the two given field elements modulo GF(2^8/0x11D). // All inputs are valid. This could be implemented as a 256*256 lookup table. -testable uint8_t finiteFieldMultiply(uint8_t x, uint8_t y) { +testable uint8_t reedSolomonMultiply(uint8_t x, uint8_t y) { // Russian peasant multiplication uint8_t z = 0; for (int i = 7; i >= 0; i--) {