/*
- * Shamir's secret sharing sharing implementation
+ * Shamir's secret sharing implementation
*
* Copyright (C) 2013 Matt Corallo <git@bluematt.me>
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
+ * This file is part of ASSS (Audit-friendly Shamir's Secret Sharing)
*
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
+ * ASSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
+ * ASSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with ASSS. If not, see
+ * <http://www.gnu.org/licenses/>.
*/
-#include <stdint.h>
-
#ifndef IN_KERNEL
#include <assert.h>
#define CHECKSTATE(x) assert(x)
#else
#include <linux/bug.h>
-#define CHECKSTATE(x) BUG_ON(x)
+#define CHECKSTATE(x) BUG_ON(!(x))
#endif
#include "shamirssecret.h"
+#ifndef noinline
+#define noinline __attribute__((noinline))
+#endif
+
/*
* Calculations across the finite field GF(2^8)
*/
-#ifndef TEST
static uint8_t field_add(uint8_t a, uint8_t b) {
return a ^ b;
}
static uint8_t field_neg(uint8_t a) {
return field_sub(0, a);
}
-#endif
//TODO: Using static tables will very likely create side-channel attacks when measuring cache hits
// Because these are fairly small tables, we can probably get them loaded mostly/fully into
0x4a, 0xed, 0xde, 0xc5, 0x31, 0xfe, 0x18, 0x0d, 0x63, 0x8c, 0x80, 0xc0, 0xf7, 0x70, 0x07};
// We disable lots of optimizations that result in non-constant runtime (+/- branch delays)
-static uint8_t field_mul_ret(uint8_t calc, uint8_t a, uint8_t b) __attribute__((optimize("-O0"))) __attribute__((noinline));
+static uint8_t field_mul_ret(uint8_t calc, uint8_t a, uint8_t b) __attribute__((optimize("-O0"))) noinline;
static uint8_t field_mul_ret(uint8_t calc, uint8_t a, uint8_t b) {
uint8_t ret, ret2;
if (a == 0)
return exp[0xff - log[a]]; // log[1] == 0xff
}
-// We disable lots of optimizations that result in non-constant runtime (+/- branch delays)
-static uint8_t field_pow_ret(uint8_t calc, uint8_t a, uint8_t e) __attribute__((optimize("-O0"))) __attribute__((noinline));
-static uint8_t field_pow_ret(uint8_t calc, uint8_t a, uint8_t e) {
- uint8_t ret, ret2;
- if (a == 0)
- ret2 = 0;
- else
- ret2 = calc;
- if (e == 0)
- ret = 1;
- else
- ret = ret2;
- return ret;
-}
static uint8_t field_pow(uint8_t a, uint8_t e) {
+ uint8_t ret = exp[(log[a] * e) % 255];
#ifndef TEST
- // Although this function works for a==0, its not trivially obvious why,
- // and since we never call with a==0, we just assert a != 0 (except when testing)
+ // We only work for a == 0 by branching (below), but since we
+ // never call with a==0, we just assert a != 0 (except when testing)
CHECKSTATE(a != 0);
+#else
+ if (a == 0 && e != 0)
+ ret = 0;
#endif
- return field_pow_ret(exp[(log[a] * e) % 255], a, e);
+ return ret;
}
#ifdef TEST
for (uint16_t j = 0; j < P; j++)
CHECKSTATE(field_pow(i, j) == field_pow_calc(i, j));
}
+
+ // Test invertibility of add/negate/subtract
+ for (uint16_t i = 0; i < P; i++) {
+ CHECKSTATE(field_neg(field_neg(i)) == i);
+ // Test add/sub commutativity
+ for (uint16_t j = 0; j < P; j++) {
+ CHECKSTATE(field_add(i, j) == field_add(j, i));
+ CHECKSTATE(field_add(i, field_neg(j)) == field_sub(i, j));
+ CHECKSTATE(field_add(field_neg(j), i) == field_sub(i, j));
+ }
+ }
}
#endif // defined(TEST)
* coefficients[0] == secret, the rest are random values
*/
uint8_t calculateQ(uint8_t coefficients[], uint8_t shares_required, uint8_t x) {
+ uint8_t ret = coefficients[0], i;
CHECKSTATE(x != 0); // q(0) == secret, though so does a[0]
- uint8_t ret = coefficients[0];
- for (uint8_t i = 1; i < shares_required; i++) {
+ for (i = 1; i < shares_required; i++) {
ret = field_add(ret, field_mul(coefficients[i], field_pow(x, i)));
}
return ret;
* Derives the secret given a set of shares_required points (x and q coordinates)
*/
uint8_t calculateSecret(uint8_t x[], uint8_t q[], uint8_t shares_required) {
- // Calculate the x^0 term using a derivation of the forumula at
+ // Calculate the x^0 term using a derivation of the formula at
// http://en.wikipedia.org/wiki/Lagrange_polynomial#Example_2
- uint8_t ret = 0;
- for (uint8_t i = 0; i < shares_required; i++) {
+ uint8_t ret = 0, i, j;
+ for (i = 0; i < shares_required; i++) {
uint8_t temp = q[i];
- for (uint8_t j = 0; j < shares_required; j++) {
+ for (j = 0; j < shares_required; j++) {
if (i == j)
continue;
temp = field_mul(temp, field_neg(x[j]));