<html>
<head>
<style type="text/css">
+ @media print {
+ #pages > div{
+ page-break-after: always;
+ }
+
+ fieldset{
+ display: none;
+ };
+ }
+
+ @media screen {
+ #pages{
+ display: none;
+ }
+ }
+
td{
text-align: right;
- border-style: solid;
- border-width: 0 0 0 1px;
padding: 10px;
}
+ td:nth-child(2n){
+ background:#ccc;
+ }
+ tr:nth-child(2) td{
+ border-width: 0 0 5px 0;
+ border-style: solid;
+
+ }
+ .half{
+ border: 1px solid black;
+ }
+ .num{
+ width: 40px;
+ }
+
+ #pages span {
+ border: 1px solid gray;
+ display: inline-block;
+ margin: 3px;
+ padding: 3px;
+ }
+ textarea{
+ width: 100%;
+ min-height: 150px;
+ }
+
+
</style>
<script type="text/javascript">
var prime=257;
function e(e,t){return '<'+e+'>'+t+'</'+e+'>';} // html element with content t
-function v(i){return document.getElementById(i).value;} // value of element with id
-function h(i,t){document.getElementById(i).innerHTML=t};
+function g(i){return document.getElementById(i);}
+function h(i,t){g(i).innerHTML=t};
+function v(i){return g(i).value;} // value of element with id
+
+
+/* Split number into the shares */
+function split(number, available, needed) {
+ var coef = [], x, exp, c, accum, shares = [];
+ for(c = 1, coef[0] = number; c < needed; c++) coef[c] = Math.floor(Math.random() * (prime - 1));
+ for(x = 1; x <= available; x++) {
+ for(exp = 1, accum = coef[0]; exp < needed; exp++) accum = (accum + (coef[exp] * (Math.pow(x, exp) % prime) % prime)) % prime;
+ shares[x - 1] = accum;
+ }
+ return shares;
+}
-function s2n(s){
+function share(index,string){
+ this.index=index;
+ this.codes=string.split(' ');
+ this.codeCount=function(){return this.codes.length};
+ this.code=function(i){return this.codes[i];};
+ this.pick=function(i){return [this.index,this.codes[i]]};
+ this.string=function(){
+ return 'Share '+this.index+': '+this.codes.join(' / ');
+ };
+}
+
+function collect(){
+ var divs=document.getElementsByClassName('share');
+ var shares=[],lastValue,div,inputs,num;
+ for (i=0; i<divs.length; i++){
+ div=divs[i];
+ inputs = div.getElementsByTagName('input');
+ num=0;
+ for (var j=0; j<inputs.length;j++){
+ var input = inputs[j];
+ if (input.className == 'num') {
+ num=input.value;
+ } else {
+ lastValue=input.value;
+ if (num>0 && lastValue!='') shares[i]=new share(num,lastValue);
+ }
+ }
+ }
+ if (lastValue!=''){
+ var clone=div.cloneNode(true);
+ var inputs=clone.getElementsByTagName('input');
+ for (var j=0; j<inputs.length; j++) inputs[j].value='';
+ div.parentNode.appendChild(clone);
+ }
+ return shares;
+}
+
+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];
+ }
+}
+
+function modInverse(k) {
+ k = k % prime;
+ var r = (k < 0) ? -gcdD(prime,-k)[2] : gcdD(prime,k)[2];
+ return (prime + r) % prime;
+}
+
+function join(shares) {
+ var accum, count, formula, startposition, nextposition, value, numerator, denominator;
+ for(formula = accum = 0; formula < shares.length; formula++) {
+ 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;
+}
+
+function decode(){
+ var shares=collect(); // fetch shares
+ var codeCount=null;
+ for (var i=0; i<shares.length; i++) codeCount=(codeCount==null)?shares[i].codeCount():Math.min(shares[i].codeCount(),codeCount);
+ var ascii=document.getElementById('ascii');
+ ascii.innerHTML='ascii: ';
+ result.innerHTML='Passphrase: ';
+ for (codeIndex=0; codeIndex<codeCount; codeIndex++){
+ var shareSet=[];
+ for (var i=0; i<shares.length; i++){
+ shareSet[i]=shares[i].pick(codeIndex);
+ }
+ var r=join(shareSet);
+ ascii.innerHTML += r+' ';
+ result.innerHTML+= String.fromCharCode(r);
+ }
+}
+
+function secret2numbers(s){
var i,j,coef,n,x,sum;
var shares = v('shares');
var treshold = v('treshold');
coef=[n];
for (j=1; j<treshold;j++) coef[j]=Math.floor(Math.random()*prime);
- results[i]=[];
-
- for (sum=0,x=0; x<shares; x++){
- for (j in coef) sum+=coef[j]*Math.pow(x+1,j);
- results[i][x]=sum%prime;
- }
+ results[i]=split(n,shares,treshold);
}
var code=e('tr',th)+e('tr',ns);
+ var pages=g('pages');
+ var explanation=v('explanation').replace('%n',v('treshold')).replace(/\n/g,'<br/>');
+ pages.innerHTML='';
for (j=0;j<shares;j++){
var line=e('th','share '+(j+1));
+ var page='';
for (i=0;i<s.length;i++){
line+=e('td',results[i][j]);
+ page+=e('span',results[i][j]);
}
- code+=e('tr',line);
+ code+=e('tr',line);
+ pages.innerHTML+=e('div', e('p',explanation)+e('p','Your share number: '+(j+1))+e('p',page) );
}
h('tab',code);
return n;
</script>
</head>
<body>
-Shares: <input id="shares" value="5"></br>
-Min: <input id="treshold" value="3"></br>
-Secret: <input name="secret" onkeyup="s2n(this.value);">
-<table id="tab">
-</table>
+ <fieldset>
+ <legend>Decode secret from shares</legend>
+ <div>
+ <div class="share">
+ Share #<input class="num" value="1" />: <input class="code" onkeyup="decode();"/>
+ </div>
+ </div>
+ <p id="ascii"></p>
+ <p id="result"></p>
+ </fieldset>
+ <fieldset>
+ <legend>Create shares from secret</legend>
+ Explanation to add:<br/>
+ <textarea id="explanation" name="explanation">
+This document is a PART of a secret passphrase. At least %n of these secret parts are required to reconstruct the original passphrase.
+In the event of (enter condition here), you may meet with other secret-part holders to unite your keys.
+
+To obtain the secret phassphrase:
+<ol>
+ <li>collect at least %n secret shares</li>
+ <li>go to [url of this page]</li>
+ <li>enter the share number and the respective numbers separated by spaces</li>
+</ol>
+The passphrase obtained will give you access to [insert description of secured thing here...].
+
+[More instructions]
+
+Info: These secrets were generated using the "Shamir's Secret Sharing" algorithm.
+ </textarea><br/>
+ Passphrase parts to generate: <input id="shares" value="5" /></br>
+ Minimum nuber of shares required to recreate secret: <input id="treshold" value="3" /></br>
+ Secret: <input name="secret" onkeyup="secret2numbers(this.value);" />
+ <table id="tab"></table>
+ <ol>
+ <li>Set the explanation you want.</li>
+ <li>Enter the number of parts and shares you wish.</li>
+ <li>Enter your secret passphrase</li>
+ <li>Hit Ctrl+P or go to print via the menu</li>
+ </ol>
+ </fieldset>
+ <div id="pages"></div>
</body>
</html>
\ No newline at end of file