I tryed to implement Shamir's Secret Sharing in Java but I have some problem.
When I put K>10 the secret is no more reconstructed. Who can help me? This is what i've done. What's the problem?
Initially I choose N and K, next I have the generation of coefficients, the creation of shares and finally the reconstruction.
import java.math.BigInteger;
import java.util.Random;
public class Main {
public static void main(String[] args){
//INIT
int N = 55;
int K = 11;
BigInteger secret = new BigInteger("123");
modLength = secret.bitLength() + 1;
BigInteger primeNum = genPrime();
BigInteger[] coeff = new BigInteger[K-1];
BigInteger[] partecipants = new BigInteger[K];
for (int i=0;i<K;i++)
partecipants[i] = new BigInteger(Integer.toString(i+1));
System.out.println("Prime Number: "+primeNum);
for (int i=0;i<K-1;i++){
coeff[i] = randomZp(primeNum);
System.out.println("a"+(i+1)+": "+coeff[i]);
}
//SHARES
BigInteger[] shares = new BigInteger[N];
for(int i=0;i<N;i++){
BigInteger toAdd= secret;
for(int j=0;j<K-1;j++){
BigInteger power = new BigInteger(Integer.toString((int)(Math.pow((i+1),(j+1)))));
toAdd=toAdd.add(coeff[j].multiply(power));
}
shares[i] = toAdd.mod(primeNum);
System.out.println("Share n."+(i+1)+": "+shares[i]);
}
//INTERPOLAZIONE
BigInteger secret2= new BigInteger("0");
double term;
for (int i=0;i<K;i++){
term = 1;
BigInteger sharePartecipanteNow = shares[(partecipants[i].intValue())-1];
for (int j=0;j<K;j++){
if (partecipants[i].intValue()!=partecipants[j].intValue()){
BigInteger num = new BigInteger(Integer.toString(partecipants[j].intValue()*(-1)));
BigInteger den = new BigInteger(Integer.toString(partecipants[i].intValue()-partecipants[j].intValue()));
term = term*(num.doubleValue())/(den.doubleValue());
}
}
term = term*sharePartecipanteNow.intValue();
secret2 = secret2.add(new BigInteger(Integer.toString((int)term)));
}
while(secret2.intValue()<0)
secret2 = secret2.add(primeNum);
System.out.println("The secret is: "+secret2.mod(primeNum));
}
private static BigInteger genPrime() {
BigInteger p=null;
boolean ok=false;
do{
p=BigInteger.probablePrime(modLength, new Random());
if(p.isProbablePrime(CERTAINTY))
ok=true;
}while(ok==false);
return p;
}
private static BigInteger randomZp(BigInteger p) {
BigInteger r;
do{
r = new BigInteger(modLength, new Random());
} while (r.compareTo(BigInteger.ZERO) < 0 || r.compareTo(p) >= 0);
return r;
}
private static final int CERTAINTY = 50;
private static int modLength;
}
Secret sharing works by splitting private information into smaller pieces — or shares — and then distributing those shares amongst a group or network. Each individual share is useless on its own but when all the shares are together, they reconstruct an original secret.
Adi Shamir's scheme is a securely encrypted secret sharing scheme that requires some or all participants are needed to reconstruct a secret. Shamir's Secret Sharing allows for a hierarchical schema where some participants may be more trustworthy than another.
Secret sharing schemes are useful because they allow for more secure storage of highly sensitive data, including encryption keys, missile launch codes, and numbered bank accounts. By distributing the data, there is no single point of failure that can lead to its loss.
karbi79's Shamir's Secret Sharing implementation is not valid. It could look like fine answer [basic test works fine], but it's not!
Proper implementation of Shamir Secret Sharing made my friend. It's his code:
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.Random;
public final class Shamir
{
public static SecretShare[] split(final BigInteger secret, int needed, int available, BigInteger prime, Random random)
{
System.out.println("Prime Number: " + prime);
final BigInteger[] coeff = new BigInteger[needed];
coeff[0] = secret;
for (int i = 1; i < needed; i++)
{
BigInteger r;
while (true)
{
r = new BigInteger(prime.bitLength(), random);
if (r.compareTo(BigInteger.ZERO) > 0 && r.compareTo(prime) < 0)
{
break;
}
}
coeff[i] = r;
}
final SecretShare[] shares = new SecretShare[available];
for (int x = 1; x <= available; x++)
{
BigInteger accum = secret;
for (int exp = 1; exp < needed; exp++)
{
accum = accum.add(coeff[exp].multiply(BigInteger.valueOf(x).pow(exp).mod(prime))).mod(prime);
}
shares[x - 1] = new SecretShare(x, accum);
System.out.println("Share " + shares[x - 1]);
}
return shares;
}
public static BigInteger combine(final SecretShare[] shares, final BigInteger prime)
{
BigInteger accum = BigInteger.ZERO;
for(int formula = 0; formula < shares.length; formula++)
{
BigInteger numerator = BigInteger.ONE;
BigInteger denominator = BigInteger.ONE;
for(int count = 0; count < shares.length; count++)
{
if(formula == count)
continue; // If not the same value
int startposition = shares[formula].getNumber();
int nextposition = shares[count].getNumber();
numerator = numerator.multiply(BigInteger.valueOf(nextposition).negate()).mod(prime); // (numerator * -nextposition) % prime;
denominator = denominator.multiply(BigInteger.valueOf(startposition - nextposition)).mod(prime); // (denominator * (startposition - nextposition)) % prime;
}
BigInteger value = shares[formula].getShare();
BigInteger tmp = value.multiply(numerator) . multiply(modInverse(denominator, prime));
accum = prime.add(accum).add(tmp) . mod(prime); // (prime + accum + (value * numerator * modInverse(denominator))) % prime;
}
System.out.println("The secret is: " + accum + "\n");
return accum;
}
private static BigInteger[] gcdD(BigInteger a, BigInteger b)
{
if (b.compareTo(BigInteger.ZERO) == 0)
return new BigInteger[] {a, BigInteger.ONE, BigInteger.ZERO};
else
{
BigInteger n = a.divide(b);
BigInteger c = a.mod(b);
BigInteger[] r = gcdD(b, c);
return new BigInteger[] {r[0], r[2], r[1].subtract(r[2].multiply(n))};
}
}
private static BigInteger modInverse(BigInteger k, BigInteger prime)
{
k = k.mod(prime);
BigInteger r = (k.compareTo(BigInteger.ZERO) == -1) ? (gcdD(prime, k.negate())[2]).negate() : gcdD(prime,k)[2];
return prime.add(r).mod(prime);
}
public static void main(final String[] args)
{
final int CERTAINTY = 256;
final SecureRandom random = new SecureRandom();
final BigInteger secret = new BigInteger("123");
// prime number must be longer then secret number
final BigInteger prime = new BigInteger(secret.bitLength() + 1, CERTAINTY, random);
// 2 - at least 2 secret parts are needed to view secret
// 5 - there are 5 persons that get secret parts
final SecretShare[] shares = Shamir.split(secret, 2, 5, prime, random);
// we can use any combination of 2 or more parts of secret
SecretShare[] sharesToViewSecret = new SecretShare[] {shares[0],shares[1]}; // 0 & 1
BigInteger result = Shamir.combine(sharesToViewSecret, prime);
sharesToViewSecret = new SecretShare[] {shares[1],shares[4]}; // 1 & 4
result = Shamir.combine(sharesToViewSecret, prime);
sharesToViewSecret = new SecretShare[] {shares[0],shares[1],shares[3]}; // 0 & 1 & 3
result = Shamir.combine(sharesToViewSecret, prime);
}
}
SecretShare.java:
import java.math.BigInteger;
public class SecretShare
{
public SecretShare(final int number, final BigInteger share)
{
this.number = number;
this.share = share;
}
public int getNumber()
{
return number;
}
public BigInteger getShare()
{
return share;
}
@Override
public String toString()
{
return "SecretShare [num=" + number + ", share=" + share + "]";
}
private final int number;
private final BigInteger share;
}
Looks like your implementation suffers from numerical errors in secret reconstruction part (using double causes rounding errors).
However there is also a problem in shares generation part, however I'm not able to point it out.
I have rewritten your code using Java example from Shamir's Secret Sharing. This is quick and dirty but correct (I hope).
import java.math.BigInteger;
import java.util.Random;
public final class Shamir {
public final class SecretShare {
public SecretShare(final int num, final BigInteger share) {
this.num = num;
this.share = share;
}
public int getNum() {
return num;
}
public BigInteger getShare() {
return share;
}
@Override
public String toString() {
return "SecretShare [num=" + num + ", share=" + share + "]";
}
private final int num;
private final BigInteger share;
}
public Shamir(final int k, final int n) {
this.k = k;
this.n = n;
random = new Random();
}
public SecretShare[] split(final BigInteger secret) {
final int modLength = secret.bitLength() + 1;
prime = new BigInteger(modLength, CERTAINTY, random);
final BigInteger[] coeff = new BigInteger[k - 1];
System.out.println("Prime Number: " + prime);
for (int i = 0; i < k - 1; i++) {
coeff[i] = randomZp(prime);
System.out.println("a" + (i + 1) + ": " + coeff[i]);
}
final SecretShare[] shares = new SecretShare[n];
for (int i = 1; i <= n; i++) {
BigInteger accum = secret;
for (int j = 1; j < k; j++) {
final BigInteger t1 = BigInteger.valueOf(i).modPow(BigInteger.valueOf(j), prime);
final BigInteger t2 = coeff[j - 1].multiply(t1).mod(prime);
accum = accum.add(t2).mod(prime);
}
shares[i - 1] = new SecretShare(i - 1, accum);
System.out.println("Share " + shares[i - 1]);
}
return shares;
}
public BigInteger getPrime() {
return prime;
}
public BigInteger combine(final SecretShare[] shares, final BigInteger primeNum) {
BigInteger accum = BigInteger.ZERO;
for (int i = 0; i < k; i++) {
BigInteger num = BigInteger.ONE;
BigInteger den = BigInteger.ONE;
for (int j = 0; j < k; j++) {
if (i != j) {
num = num.multiply(BigInteger.valueOf(-j - 1)).mod(primeNum);
den = den.multiply(BigInteger.valueOf(i - j)).mod(primeNum);
}
}
System.out.println("den: " + den + ", num: " + den + ", inv: " + den.modInverse(primeNum));
final BigInteger value = shares[i].getShare();
final BigInteger tmp = value.multiply(num).multiply(den.modInverse(primeNum)).mod(primeNum);
accum = accum.add(primeNum).add(tmp).mod(primeNum);
System.out.println("value: " + value + ", tmp: " + tmp + ", accum: " + accum);
}
System.out.println("The secret is: " + accum);
return accum;
}
private BigInteger randomZp(final BigInteger p) {
while (true) {
final BigInteger r = new BigInteger(p.bitLength(), random);
if (r.compareTo(BigInteger.ZERO) > 0 && r.compareTo(p) < 0) {
return r;
}
}
}
private BigInteger prime;
private final int k;
private final int n;
private final Random random;
private static final int CERTAINTY = 50;
public static void main(final String[] args) {
final Shamir shamir = new Shamir(11, 20);
final BigInteger secret = new BigInteger("1234567890123456789012345678901234567890");
final SecretShare[] shares = shamir.split(secret);
final BigInteger prime = shamir.getPrime();
final Shamir shamir2 = new Shamir(11, 20);
final BigInteger result = shamir2.combine(shares, prime);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With