From b9e347642015db85395178bd11bf03ee35aca990 Mon Sep 17 00:00:00 2001 From: Project Nayuki Date: Mon, 17 Apr 2017 17:34:21 +0000 Subject: [PATCH] Began writing new port of this library in C by implementing Reed-Solomon functions. --- c/qrcodegen.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 c/qrcodegen.c diff --git a/c/qrcodegen.c b/c/qrcodegen.c new file mode 100644 index 0000000..bf30444 --- /dev/null +++ b/c/qrcodegen.c @@ -0,0 +1,88 @@ +/* + * QR Code generator library (C) + * + * Copyright (c) Project Nayuki + * https://www.nayuki.io/page/qr-code-generator-library + * + * (MIT License) + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * - The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * - The Software is provided "as is", without warranty of any kind, express or + * implied, including but not limited to the warranties of merchantability, + * fitness for a particular purpose and noninfringement. In no event shall the + * authors or copyright holders be liable for any claim, damages or other + * liability, whether in an action of contract, tort or otherwise, arising from, + * out of or in connection with the Software or the use or other dealings in the + * Software. + */ + +#include +#include +#include + + +/*---- Forward declarations for private functions ----*/ + +static void calcReedSolomonGenerator(int degree, uint8_t result[]); +static void calcReedSolomonRemainder(const uint8_t data[], int dataLen, const uint8_t generator[], int degree, uint8_t result[]); +static uint8_t finiteFieldMultiply(uint8_t x, uint8_t y); + + + +/*---- Function implementations ----*/ + +// Calculates the Reed-Solomon generator polynomial of the given degree, storing in result[0 : degree]. +static void calcReedSolomonGenerator(int degree, uint8_t result[]) { + // Start with the monomial x^0 + assert(1 <= degree && degree <= 30); + memset(result, 0, degree * sizeof(result[0])); + result[degree - 1] = 1; + + // 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. + // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D). + int 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], (uint8_t)root); + if (j + 1 < degree) + result[j] ^= result[j + 1]; + } + root = (root << 1) ^ ((root >> 7) * 0x11D); // Multiply by 0x02 mod GF(2^8/0x11D) + } +} + + +// 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]. +static void calcReedSolomonRemainder(const uint8_t data[], int dataLen, const uint8_t generator[], int degree, uint8_t result[]) { + // Perform polynomial division + assert(1 <= degree && degree <= 30); + memset(result, 0, degree * sizeof(result[0])); + for (int i = 0; i < dataLen; i++) { + 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); + } +} + + +// Returns the product of the two given field elements modulo GF(2^8/0x11D). All argument values are valid. +static uint8_t finiteFieldMultiply(uint8_t x, uint8_t y) { + // Russian peasant multiplication + uint8_t z = 0; + for (int i = 7; i >= 0; i--) { + z = (z << 1) ^ ((z >> 7) * 0x11D); + z ^= ((y >> i) & 1) * x; + } + return z; +}