15317bbafSopenharmony_ci/*
25317bbafSopenharmony_ci * Fast QR Code generator library
35317bbafSopenharmony_ci *
45317bbafSopenharmony_ci * Copyright (c) Project Nayuki. (MIT License)
55317bbafSopenharmony_ci * https://www.nayuki.io/page/fast-qr-code-generator-library
65317bbafSopenharmony_ci *
75317bbafSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy of
85317bbafSopenharmony_ci * this software and associated documentation files (the "Software"), to deal in
95317bbafSopenharmony_ci * the Software without restriction, including without limitation the rights to
105317bbafSopenharmony_ci * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
115317bbafSopenharmony_ci * the Software, and to permit persons to whom the Software is furnished to do so,
125317bbafSopenharmony_ci * subject to the following conditions:
135317bbafSopenharmony_ci * - The above copyright notice and this permission notice shall be included in
145317bbafSopenharmony_ci *   all copies or substantial portions of the Software.
155317bbafSopenharmony_ci * - The Software is provided "as is", without warranty of any kind, express or
165317bbafSopenharmony_ci *   implied, including but not limited to the warranties of merchantability,
175317bbafSopenharmony_ci *   fitness for a particular purpose and noninfringement. In no event shall the
185317bbafSopenharmony_ci *   authors or copyright holders be liable for any claim, damages or other
195317bbafSopenharmony_ci *   liability, whether in an action of contract, tort or otherwise, arising from,
205317bbafSopenharmony_ci *   out of or in connection with the Software or the use or other dealings in the
215317bbafSopenharmony_ci *   Software.
225317bbafSopenharmony_ci */
235317bbafSopenharmony_ci
245317bbafSopenharmony_cipackage io.nayuki.fastqrcodegen;
255317bbafSopenharmony_ci
265317bbafSopenharmony_ciimport java.util.Arrays;
275317bbafSopenharmony_ciimport java.util.Objects;
285317bbafSopenharmony_ci
295317bbafSopenharmony_ci
305317bbafSopenharmony_ci// Computes Reed-Solomon error correction codewords for given data codewords.
315317bbafSopenharmony_cifinal class ReedSolomonGenerator {
325317bbafSopenharmony_ci
335317bbafSopenharmony_ci	// Use this memoizer to get instances of this class.
345317bbafSopenharmony_ci	public static final Memoizer<Integer,ReedSolomonGenerator> MEMOIZER
355317bbafSopenharmony_ci		= new Memoizer<>(ReedSolomonGenerator::new);
365317bbafSopenharmony_ci
375317bbafSopenharmony_ci
385317bbafSopenharmony_ci	// A table of size 256 * degree, where polynomialMultiply[i][j] = multiply(i, coefficients[j]).
395317bbafSopenharmony_ci	// 'coefficients' is the temporary array computed in the constructor.
405317bbafSopenharmony_ci	private byte[][] polynomialMultiply;
415317bbafSopenharmony_ci
425317bbafSopenharmony_ci
435317bbafSopenharmony_ci	// Creates a Reed-Solomon ECC generator polynomial for the given degree.
445317bbafSopenharmony_ci	private ReedSolomonGenerator(int degree) {
455317bbafSopenharmony_ci		if (degree < 1 || degree > 255)
465317bbafSopenharmony_ci			throw new IllegalArgumentException("Degree out of range");
475317bbafSopenharmony_ci
485317bbafSopenharmony_ci		// The divisor polynomial, whose coefficients are stored from highest to lowest power.
495317bbafSopenharmony_ci		// For example, x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}.
505317bbafSopenharmony_ci		byte[] coefficients = new byte[degree];
515317bbafSopenharmony_ci		coefficients[degree - 1] = 1;  // Start off with the monomial x^0
525317bbafSopenharmony_ci
535317bbafSopenharmony_ci		// Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
545317bbafSopenharmony_ci		// and drop the highest monomial term which is always 1x^degree.
555317bbafSopenharmony_ci		// Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).
565317bbafSopenharmony_ci		int root = 1;
575317bbafSopenharmony_ci		for (int i = 0; i < degree; i++) {
585317bbafSopenharmony_ci			// Multiply the current product by (x - r^i)
595317bbafSopenharmony_ci			for (int j = 0; j < coefficients.length; j++) {
605317bbafSopenharmony_ci				coefficients[j] = (byte)multiply(coefficients[j] & 0xFF, root);
615317bbafSopenharmony_ci				if (j + 1 < coefficients.length)
625317bbafSopenharmony_ci					coefficients[j] ^= coefficients[j + 1];
635317bbafSopenharmony_ci			}
645317bbafSopenharmony_ci			root = multiply(root, 0x02);
655317bbafSopenharmony_ci		}
665317bbafSopenharmony_ci
675317bbafSopenharmony_ci		polynomialMultiply = new byte[256][degree];
685317bbafSopenharmony_ci		for (int i = 0; i < polynomialMultiply.length; i++) {
695317bbafSopenharmony_ci			for (int j = 0; j < degree; j++)
705317bbafSopenharmony_ci				polynomialMultiply[i][j] = (byte)multiply(i, coefficients[j] & 0xFF);
715317bbafSopenharmony_ci		}
725317bbafSopenharmony_ci	}
735317bbafSopenharmony_ci
745317bbafSopenharmony_ci
755317bbafSopenharmony_ci	// Returns the error correction codeword for the given data polynomial and this divisor polynomial.
765317bbafSopenharmony_ci	public void getRemainder(byte[] data, int dataOff, int dataLen, byte[] result) {
775317bbafSopenharmony_ci		Objects.requireNonNull(data);
785317bbafSopenharmony_ci		Objects.requireNonNull(result);
795317bbafSopenharmony_ci		int degree = polynomialMultiply[0].length;
805317bbafSopenharmony_ci		assert result.length == degree;
815317bbafSopenharmony_ci
825317bbafSopenharmony_ci		Arrays.fill(result, (byte)0);
835317bbafSopenharmony_ci		for (int i = dataOff, dataEnd = dataOff + dataLen; i < dataEnd; i++) {  // Polynomial division
845317bbafSopenharmony_ci			byte[] table = polynomialMultiply[(data[i] ^ result[0]) & 0xFF];
855317bbafSopenharmony_ci			for (int j = 0; j < degree - 1; j++)
865317bbafSopenharmony_ci				result[j] = (byte)(result[j + 1] ^ table[j]);
875317bbafSopenharmony_ci			result[degree - 1] = table[degree - 1];
885317bbafSopenharmony_ci		}
895317bbafSopenharmony_ci	}
905317bbafSopenharmony_ci
915317bbafSopenharmony_ci
925317bbafSopenharmony_ci	// Returns the product of the two given field elements modulo GF(2^8/0x11D). The arguments and result
935317bbafSopenharmony_ci	// are unsigned 8-bit integers. This could be implemented as a lookup table of 256*256 entries of uint8.
945317bbafSopenharmony_ci	private static int multiply(int x, int y) {
955317bbafSopenharmony_ci		assert x >> 8 == 0 && y >> 8 == 0;
965317bbafSopenharmony_ci		// Russian peasant multiplication
975317bbafSopenharmony_ci		int z = 0;
985317bbafSopenharmony_ci		for (int i = 7; i >= 0; i--) {
995317bbafSopenharmony_ci			z = (z << 1) ^ ((z >>> 7) * 0x11D);
1005317bbafSopenharmony_ci			z ^= ((y >>> i) & 1) * x;
1015317bbafSopenharmony_ci		}
1025317bbafSopenharmony_ci		assert z >>> 8 == 0;
1035317bbafSopenharmony_ci		return z;
1045317bbafSopenharmony_ci	}
1055317bbafSopenharmony_ci
1065317bbafSopenharmony_ci}
107