var validate = function() {
$('#nts-error').attr('hidden', parseInt($('#n').val()) >= parseInt($('#t').val()));
$('#check').prop('disabled', parseInt($('#n').val()) < parseInt($('#t').val()));
};
// the following function is taken from https://rosettacode.org/wiki/Combinations#JavaScript
var combinations = function(arr, k) {
var i,
subI,
ret = [],
sub,
next;
for (i = 0; i < arr.length; i++) {
if (k === 1) {
ret.push([arr[i]]);
} else {
sub = combinations(arr.slice(i + 1, arr.length), k - 1);
for (subI = 0; subI < sub.length; subI++) {
next = sub[subI];
next.unshift(arr[i]);
ret.push(next);
}
}
}
return ret;
};
// The following code is taken from https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing#Javascript_example with the modification that the prime is 251, not 257
var prime = 251;
/* Gives the decomposition of the gcd of a and b. Returns [x,y,z] such that x = gcd(a,b) and y*a + z*b = x */
function gcdD(a, b) {
if (b == 0) return [a, 1, 0];
else {
var n = Math.floor(a / b),
c = a % b,
r = gcdD(b, c);
return [r[0], r[2], r[1] - r[2] * n];
}
}
/* Gives the multiplicative inverse of k mod prime. In other words (k * modInverse(k)) % prime = 1 for all prime > k >= 1 */
function modInverse(k) {
k = k % prime;
var r = (k < 0) ? -gcdD(prime, -k)[2] : gcdD(prime, k)[2];
return (prime + r) % prime;
}
/* Join the shares into a number */
function join(shares) {
var accum, count, formula, startposition, nextposition, value, numerator, denominator;
for (formula = accum = 0; formula < shares.length; formula++) {
/* Multiply the numerator across the top and denominators across the bottom to do Lagrange's interpolation
* Result is x0(2), x1(4), x2(5) -> -4*-5 and (2-4=-2)(2-5=-3), etc for l0, l1, l2...
*/
for (count = 0, numerator = denominator = 1; count < shares.length; count++) {
if (formula == count) continue; // If not the same value
startposition = shares[formula][0];
nextposition = shares[count][0];
numerator = (numerator * -nextposition) % prime;
denominator = (denominator * (startposition - nextposition)) % prime;
}
value = shares[formula][1];
accum = (prime + accum + (value * numerator * modInverse(denominator))) % prime;
}
return accum;
}
$('#check').click(
function() {
var good = true;
var problem = [];
var n = parseInt($('#n').val());
var t = parseInt($('#t').val());
var s = parseInt($('#s').val());
combinations([...Array(n + 1).keys()].slice(1), t).forEach(
function(xArr) {
var xfArr = xArr.map(
function(x) {
return [x, parseInt($('#f' + x).val())];
}
);
var L = join(xfArr);
if (L !== s) {
good = false;
problem.push(xArr);
}
}
);
$('#valid').html(good ? "True" : ("False (problematic secret sets: {" + problem.map(
function(elem) {
return "[" + elem.join(', ') + "]";
}) + "})"));
}
);
$('#n').change(
function() {
var inputHTML = "";
for (var i = 1; i <= parseInt($('#n').val()); i++) {
inputHTML += 'f(' + i + '): <input type="number" min="0" max="250" value="0" id="f' + i + '"><br>\r\n';
}
$('#inputs').html(inputHTML);
validate();
}
);
$('#t').change(
function() {
validate();
}
);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
n:
<input type="number" min="2" max="250" value="6" id="n">t:
<input type="number" min="2" max="250" value="3" id="t">s:
<input type="number" min="0" max="250" value="230" id="s">
<br>
<div id="nts-error" hidden="true">t must be less than or equal to n!</div>
<br>
<br>
<div id="inputs">
f(1):
<input type="number" min="0" max="250" value="35" id="f1">
<br>f(2):
<input type="number" min="0" max="250" value="95" id="f2">
<br>f(3):
<input type="number" min="0" max="250" value="159" id="f3">
<br>f(4):
<input type="number" min="0" max="250" value="227" id="f4">
<br>f(5):
<input type="number" min="0" max="250" value="48" id="f5">
<br>f(6):
<input type="number" min="0" max="250" value="124" id="f6">
</div>
<br>
<input type="submit" id="check" value="Verify">
<br>
<br>Valid:
<div id="valid"></div>
z
和f(z)
吗?如果我f(z)
按顺序打印s 数组,z
则由索引隐含。[[1, 5], [2, 2], [3, 9], [4, 14]]
没有比包含更多的信息[5, 2, 9, 14]
。