Skip to content

Commit 24aebc8

Browse files
committed
Add Java code.
1 parent caa0293 commit 24aebc8

File tree

5 files changed

+1237
-0
lines changed

5 files changed

+1237
-0
lines changed

com/backblaze/erasure/Galois.java

Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
1+
/**
2+
* 8-bit Galois Field
3+
*
4+
* Copyright 2015, Backblaze, Inc. All rights reserved.
5+
*/
6+
7+
package com.backblaze.erasure;
8+
9+
import java.util.ArrayList;
10+
import java.util.List;
11+
12+
/**
13+
* 8-bit Galois Field
14+
*
15+
* This class implements multiplication, division, addition,
16+
* subtraction, and exponentiation.
17+
*
18+
* The multiplication operation is in the inner loop of
19+
* erasure coding, so it's been optimized. Having the
20+
* class be "final" helps a little, and having the EXP_TABLE
21+
* repeat the data, so there's no need to bound the sum
22+
* of two logarithms to 255 helps a lot.
23+
*/
24+
public final class Galois {
25+
26+
/**
27+
* The number of elements in the field.
28+
*/
29+
30+
public static final int FIELD_SIZE = 256;
31+
32+
/**
33+
* The polynomial used to generate the logarithm table.
34+
*
35+
* There are a number of polynomials that work to generate
36+
* a Galois field of 256 elements. The choice is arbitrary,
37+
* and we just use the first one.
38+
*
39+
* The possibilities are: 29, 43, 45, 77, 95, 99, 101, 105,
40+
* 113, 135, 141, 169, 195, 207, 231, and 245.
41+
*/
42+
43+
public static final int GENERATING_POLYNOMIAL = 29;
44+
45+
/**
46+
* Mapping from members of the Galois Field to their
47+
* integer logarithms. The entry for 0 is meaningless
48+
* because there is no log of 0.
49+
*
50+
* This array is shorts, not bytes, so that they can
51+
* be used directly to index arrays without casting.
52+
* The values (except the non-value at index 0) are
53+
* all really bytes, so they range from 0 to 255.
54+
*
55+
* This table was generated by java_tables.py, and the
56+
* unit tests check it against the Java implementation.
57+
*/
58+
59+
static final public short [] LOG_TABLE = new short [] {
60+
-1, 0, 1, 25, 2, 50, 26, 198,
61+
3, 223, 51, 238, 27, 104, 199, 75,
62+
4, 100, 224, 14, 52, 141, 239, 129,
63+
28, 193, 105, 248, 200, 8, 76, 113,
64+
5, 138, 101, 47, 225, 36, 15, 33,
65+
53, 147, 142, 218, 240, 18, 130, 69,
66+
29, 181, 194, 125, 106, 39, 249, 185,
67+
201, 154, 9, 120, 77, 228, 114, 166,
68+
6, 191, 139, 98, 102, 221, 48, 253,
69+
226, 152, 37, 179, 16, 145, 34, 136,
70+
54, 208, 148, 206, 143, 150, 219, 189,
71+
241, 210, 19, 92, 131, 56, 70, 64,
72+
30, 66, 182, 163, 195, 72, 126, 110,
73+
107, 58, 40, 84, 250, 133, 186, 61,
74+
202, 94, 155, 159, 10, 21, 121, 43,
75+
78, 212, 229, 172, 115, 243, 167, 87,
76+
7, 112, 192, 247, 140, 128, 99, 13,
77+
103, 74, 222, 237, 49, 197, 254, 24,
78+
227, 165, 153, 119, 38, 184, 180, 124,
79+
17, 68, 146, 217, 35, 32, 137, 46,
80+
55, 63, 209, 91, 149, 188, 207, 205,
81+
144, 135, 151, 178, 220, 252, 190, 97,
82+
242, 86, 211, 171, 20, 42, 93, 158,
83+
132, 60, 57, 83, 71, 109, 65, 162,
84+
31, 45, 67, 216, 183, 123, 164, 118,
85+
196, 23, 73, 236, 127, 12, 111, 246,
86+
108, 161, 59, 82, 41, 157, 85, 170,
87+
251, 96, 134, 177, 187, 204, 62, 90,
88+
203, 89, 95, 176, 156, 169, 160, 81,
89+
11, 245, 22, 235, 122, 117, 44, 215,
90+
79, 174, 213, 233, 230, 231, 173, 232,
91+
116, 214, 244, 234, 168, 80, 88, 175
92+
93+
};
94+
95+
/**
96+
* Inverse of the logarithm table. Maps integer logarithms
97+
* to members of the field. There is no entry for 255
98+
* because the highest log is 254.
99+
*
100+
* This table was generated by java_tables.py
101+
*/
102+
103+
static final byte [] EXP_TABLE = new byte [] {
104+
1, 2, 4, 8, 16, 32, 64, -128,
105+
29, 58, 116, -24, -51, -121, 19, 38,
106+
76, -104, 45, 90, -76, 117, -22, -55,
107+
-113, 3, 6, 12, 24, 48, 96, -64,
108+
-99, 39, 78, -100, 37, 74, -108, 53,
109+
106, -44, -75, 119, -18, -63, -97, 35,
110+
70, -116, 5, 10, 20, 40, 80, -96,
111+
93, -70, 105, -46, -71, 111, -34, -95,
112+
95, -66, 97, -62, -103, 47, 94, -68,
113+
101, -54, -119, 15, 30, 60, 120, -16,
114+
-3, -25, -45, -69, 107, -42, -79, 127,
115+
-2, -31, -33, -93, 91, -74, 113, -30,
116+
-39, -81, 67, -122, 17, 34, 68, -120,
117+
13, 26, 52, 104, -48, -67, 103, -50,
118+
-127, 31, 62, 124, -8, -19, -57, -109,
119+
59, 118, -20, -59, -105, 51, 102, -52,
120+
-123, 23, 46, 92, -72, 109, -38, -87,
121+
79, -98, 33, 66, -124, 21, 42, 84,
122+
-88, 77, -102, 41, 82, -92, 85, -86,
123+
73, -110, 57, 114, -28, -43, -73, 115,
124+
-26, -47, -65, 99, -58, -111, 63, 126,
125+
-4, -27, -41, -77, 123, -10, -15, -1,
126+
-29, -37, -85, 75, -106, 49, 98, -60,
127+
-107, 55, 110, -36, -91, 87, -82, 65,
128+
-126, 25, 50, 100, -56, -115, 7, 14,
129+
28, 56, 112, -32, -35, -89, 83, -90,
130+
81, -94, 89, -78, 121, -14, -7, -17,
131+
-61, -101, 43, 86, -84, 69, -118, 9,
132+
18, 36, 72, -112, 61, 122, -12, -11,
133+
-9, -13, -5, -21, -53, -117, 11, 22,
134+
44, 88, -80, 125, -6, -23, -49, -125,
135+
27, 54, 108, -40, -83, 71, -114,
136+
// Repeat the table a second time, so multiply()
137+
// does not have to check bounds.
138+
1, 2, 4, 8, 16, 32, 64, -128,
139+
29, 58, 116, -24, -51, -121, 19, 38,
140+
76, -104, 45, 90, -76, 117, -22, -55,
141+
-113, 3, 6, 12, 24, 48, 96, -64,
142+
-99, 39, 78, -100, 37, 74, -108, 53,
143+
106, -44, -75, 119, -18, -63, -97, 35,
144+
70, -116, 5, 10, 20, 40, 80, -96,
145+
93, -70, 105, -46, -71, 111, -34, -95,
146+
95, -66, 97, -62, -103, 47, 94, -68,
147+
101, -54, -119, 15, 30, 60, 120, -16,
148+
-3, -25, -45, -69, 107, -42, -79, 127,
149+
-2, -31, -33, -93, 91, -74, 113, -30,
150+
-39, -81, 67, -122, 17, 34, 68, -120,
151+
13, 26, 52, 104, -48, -67, 103, -50,
152+
-127, 31, 62, 124, -8, -19, -57, -109,
153+
59, 118, -20, -59, -105, 51, 102, -52,
154+
-123, 23, 46, 92, -72, 109, -38, -87,
155+
79, -98, 33, 66, -124, 21, 42, 84,
156+
-88, 77, -102, 41, 82, -92, 85, -86,
157+
73, -110, 57, 114, -28, -43, -73, 115,
158+
-26, -47, -65, 99, -58, -111, 63, 126,
159+
-4, -27, -41, -77, 123, -10, -15, -1,
160+
-29, -37, -85, 75, -106, 49, 98, -60,
161+
-107, 55, 110, -36, -91, 87, -82, 65,
162+
-126, 25, 50, 100, -56, -115, 7, 14,
163+
28, 56, 112, -32, -35, -89, 83, -90,
164+
81, -94, 89, -78, 121, -14, -7, -17,
165+
-61, -101, 43, 86, -84, 69, -118, 9,
166+
18, 36, 72, -112, 61, 122, -12, -11,
167+
-9, -13, -5, -21, -53, -117, 11, 22,
168+
44, 88, -80, 125, -6, -23, -49, -125,
169+
27, 54, 108, -40, -83, 71, -114
170+
};
171+
172+
/**
173+
* Adds two elements of the field. If you're in an inner loop,
174+
* you should inline this function: it's just XOR.
175+
*/
176+
public static byte add(byte a, byte b) {
177+
return (byte) (a ^ b);
178+
}
179+
180+
/**
181+
* Inverse of addition. If you're in an inner loop,
182+
* you should inline this function: it's just XOR.
183+
*/
184+
public static byte subtract(byte a, byte b) {
185+
return (byte) (a ^ b);
186+
}
187+
188+
/**
189+
* Multiplies to elements of the field.
190+
*/
191+
public static byte multiply(byte a, byte b) {
192+
if (a == 0 || b == 0) {
193+
return 0;
194+
}
195+
else {
196+
int logA = LOG_TABLE[a & 0xFF];
197+
int logB = LOG_TABLE[b & 0xFF];
198+
int logResult = logA + logB;
199+
return EXP_TABLE[logResult];
200+
}
201+
}
202+
203+
/**
204+
* Inverse of multiplication.
205+
*/
206+
public static byte divide(byte a, byte b) {
207+
if (a == 0) {
208+
return 0;
209+
}
210+
if (b == 0) {
211+
throw new IllegalArgumentException("Argument 'divisor' is 0");
212+
}
213+
int logA = LOG_TABLE[a & 0xFF];
214+
int logB = LOG_TABLE[b & 0xFF];
215+
int logResult = logA - logB;
216+
if (logResult < 0) {
217+
logResult += 255;
218+
}
219+
return EXP_TABLE[logResult];
220+
}
221+
222+
/**
223+
* Computes a**n.
224+
*
225+
* The result will be the same as multiplying a times itself n times.
226+
*
227+
* @param a A member of the field.
228+
* @param n A plain-old integer.
229+
* @return The result of multiplying a by itself n times.
230+
*/
231+
public static byte exp(byte a, int n) {
232+
if (n == 0) {
233+
return 1;
234+
}
235+
else if (a == 0) {
236+
return 0;
237+
}
238+
else {
239+
int logA = LOG_TABLE[a & 0xFF];
240+
int logResult = logA * n;
241+
while (255 <= logResult) {
242+
logResult -= 255;
243+
}
244+
return EXP_TABLE[logResult];
245+
}
246+
}
247+
248+
/**
249+
* Generates a logarithm table given a starting polynomial.
250+
*/
251+
public static short [] generateLogTable(int polynomial) {
252+
short [] result = new short[FIELD_SIZE];
253+
for (int i = 0; i < FIELD_SIZE; i++) {
254+
result[i] = -1; // -1 means "not set"
255+
}
256+
int b = 1;
257+
for (int log = 0; log < FIELD_SIZE - 1; log++) {
258+
if (result[b] != -1) {
259+
throw new RuntimeException("BUG: duplicate logarithm (bad polynomial?)");
260+
}
261+
result[b] = (short) log;
262+
b = (b << 1);
263+
if (FIELD_SIZE <= b) {
264+
b = ((b - FIELD_SIZE) ^ polynomial);
265+
}
266+
}
267+
return result;
268+
}
269+
270+
/**
271+
* Generates the inverse log table.
272+
*/
273+
public static byte [] generateExpTable(short [] logTable) {
274+
final byte [] result = new byte [FIELD_SIZE * 2 - 2];
275+
for (int i = 1; i < FIELD_SIZE; i++) {
276+
int log = logTable[i];
277+
result[log] = (byte) i;
278+
result[log + FIELD_SIZE - 1] = (byte) i;
279+
}
280+
return result;
281+
}
282+
283+
/**
284+
* Returns a list of all polynomials that can be used to generate
285+
* the field.
286+
*
287+
* This is never used in the code; it's just here for completeness.
288+
*/
289+
public static Integer [] allPossiblePolynomials() {
290+
List<Integer> result = new ArrayList<Integer>();
291+
for (int i = 0; i < FIELD_SIZE; i++) {
292+
try {
293+
generateLogTable(i);
294+
result.add(i);
295+
}
296+
catch (RuntimeException e) {
297+
// this one didn't work
298+
}
299+
}
300+
return result.toArray(new Integer [result.size()]);
301+
}
302+
303+
}

0 commit comments

Comments
 (0)