Shamir'的Java实现;秘密共享

Shamir'的Java实现;秘密共享,java,cryptography,shared-secret,Java,Cryptography,Shared Secret,我试图用Java实现Shamir的秘密共享,但我遇到了一些问题 当我把K>10时,秘密就不再重现了。谁能帮我?这就是我所做的。有什么问题吗 最初我选择N和K,接下来我生成系数,创建共享,最后重建 import java.math.BigInteger; import java.util.Random; public class Main { public static void main(String[] args){ //INIT int N =

我试图用Java实现Shamir的秘密共享,但我遇到了一些问题

当我把K>10时,秘密就不再重现了。谁能帮我?这就是我所做的。有什么问题吗

最初我选择N和K,接下来我生成系数,创建共享,最后重建

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; 
}
import java.math.biginger;
导入java.util.Random;
公共班机{
公共静态void main(字符串[]args){
//初始化
int N=55;
int K=11;
BigInteger secret=新的BigInteger(“123”);
modLength=secret.bitLength()+1;
BigInteger primeNum=genPrime();
BigInteger[]系数=新的BigInteger[K-1];
BigInteger[]参与方=新的BigInteger[K];

for(int i=0;i看起来您的实现在秘密重建部分遇到了数字错误(使用double会导致舍入错误)

然而,在股票生成部分也有一个问题,但是我不能指出

我已经使用中的Java示例重写了您的代码。这既快又脏,但正确(我希望如此)

import java.math.biginger;
导入java.util.Random;
公共期末班{
公开最终类秘密共享{
public SecretShare(final int num,final biginger share){
this.num=num;
这个。份额=份额;
}
公共int getNum(){
返回num;
}
public BigInteger getShare(){
回报份额;
}
@凌驾
公共字符串toString(){
返回“SecretShare[num=“+num+”,share=“+share+”]”;
}
私有最终整数;
私人股本;
}
公共沙米尔(最终整数k,最终整数n){
这个。k=k;
这个,n=n;
随机=新随机();
}
public SecretShare[]拆分(最终BigInteger机密){
final int modLength=secret.bitLength()+1;
prime=新的BigInteger(modLength、确定性、随机);
最终的BigInteger[]系数=新的BigInteger[k-1];
System.out.println(“素数:“+Prime”);
对于(int i=0;i
karbi79的Shamir秘密共享实现无效。 这看起来像是一个很好的答案[基本测试很好],但事实并非如此

沙米尔秘密共享的正确实现让我成为了朋友。这是他的代码:

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);
    }
}

ShareBuilder=newShareBuilder(“我是蝙蝠侠,说真的。”.getBytes(),2512); 列表共享=builder.build(10)

//拿走2份,恢复秘密 List someShares=new ArrayList(); someShares.add(shares.get(2)); someShares.add(shares.get(7)); ShareCombiner combiner=新的ShareCombiner(部分股份); System.err.println(新字符串(combiner.combine())


//omg我是蝙蝠侠

类似的代码,但实现更好(我认为)。现在可以使用字符串机密了

下面是代码,Shamir.java

import javax.swing.*;
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)
    {
        // secret > the Secret.
        // needed > the required Shares.
        // available > the total number of shares.

        //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++) // for each share of the total shares
        {
            BigInteger accum = secret;

            for (int exp = 1; exp < needed; exp++) // for each
            {
                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 String 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;
        }
        String secret = new String (accum.toByteArray ());
        //System.out.println("The secret is: " + secret + "\n");

        return secret;
    }

    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);
    }

    private static String generateShamirShares (String secret, int nedNuShares, int totNuShares)
    {
        final BigInteger bigIntegerPassword = new BigInteger(secret.getBytes ());
        final int CERTAINTY = 256;
        final SecureRandom random = new SecureRandom();
        final BigInteger prime = new BigInteger(bigIntegerPassword.bitLength() + 1, CERTAINTY, random);
        final SecretShare[] shares = Shamir.split (bigIntegerPassword, nedNuShares, totNuShares, prime, random);

        String coPrimeNum = nedNuShares + "P:" + prime;

        StringBuilder primeAndShares = new StringBuilder (coPrimeNum);

        String[] sharei = new String [totNuShares];
        for (SecretShare share: shares)
        {
            String coShare = share.getNumber () + ":" + share.getShare ();
            sharei[share.getNumber ()-1] = coShare;

            primeAndShares.append ("\n").append (coShare);
        }

        return String.valueOf (primeAndShares);
    }

    private static String combineShamirShares (String prime, String[] shares)
    {
        String strNumOfShares = prime.substring (0,prime.indexOf ("P:"));
        int avaSharesNum = Integer.parseInt (strNumOfShares);

        if (shares.length == avaSharesNum)
        {
            SecretShare[] sharesToViewSecret = new SecretShare[avaSharesNum];
            for (int i=0; i<avaSharesNum; i++)
            {
                String coShareStr = shares[i].trim ();
                String shareStr = coShareStr.substring (coShareStr.indexOf (":")+1);
                int shareNum = Integer.parseInt (coShareStr.substring (0,coShareStr.indexOf (":")));
                sharesToViewSecret[i] = new SecretShare (shareNum, new BigInteger (shareStr));
            }
            String coPrimeStr = prime.trim ();
            String primeStr = coPrimeStr.substring (coPrimeStr.indexOf (":")+1);
            //int primeNum = Integer.parseInt (coPrimeStr.substring (0,coPrimeStr.indexOf ("P:")));
            BigInteger bigIntegerPrime = new BigInteger(primeStr);
            String result = Shamir.combine (sharesToViewSecret, bigIntegerPrime);
            return result;
        }
        return ("Sorry, you have to provide " + avaSharesNum + " shares in order to reconstruct your " +
                                   "secret.");
    }


    public static void main(final String[] args)
    {
        System.out.println (generateShamirShares ("Password@123", 4, 12));

        System.out.println (combineShamirShares ("4P:57227141335498039497719664191",
                                                 new String[]{"1:46408014906759654811274101243",
                                                              "5:35533534891431853551600686081",
                                                              "3:56475036329164407840164095940",
                                                              "4:3124698633283214142142432517"}));
    }
}
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 "Share"+ number + ": " + share;
    }

    private final int number;
    private final BigInteger share;
}
4P:66911912727662985127139425997
1:18968774123286583882220506766
2:4799832019998779275182245665
3:38199612445448994408262691940
4:41174116907286121055005905205
5:2641259640822036116095371071
6:45342780336694586746493427143
7:24372767774889679592604707038
8:62472961646045161809391548361
9:14737450730146940043258584729
10:3907974717832861449168153747
11:18902447844414802927803741026
12:48638784345204641379848832177

Password@123
输出

import javax.swing.*;
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)
    {
        // secret > the Secret.
        // needed > the required Shares.
        // available > the total number of shares.

        //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++) // for each share of the total shares
        {
            BigInteger accum = secret;

            for (int exp = 1; exp < needed; exp++) // for each
            {
                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 String 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;
        }
        String secret = new String (accum.toByteArray ());
        //System.out.println("The secret is: " + secret + "\n");

        return secret;
    }

    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);
    }

    private static String generateShamirShares (String secret, int nedNuShares, int totNuShares)
    {
        final BigInteger bigIntegerPassword = new BigInteger(secret.getBytes ());
        final int CERTAINTY = 256;
        final SecureRandom random = new SecureRandom();
        final BigInteger prime = new BigInteger(bigIntegerPassword.bitLength() + 1, CERTAINTY, random);
        final SecretShare[] shares = Shamir.split (bigIntegerPassword, nedNuShares, totNuShares, prime, random);

        String coPrimeNum = nedNuShares + "P:" + prime;

        StringBuilder primeAndShares = new StringBuilder (coPrimeNum);

        String[] sharei = new String [totNuShares];
        for (SecretShare share: shares)
        {
            String coShare = share.getNumber () + ":" + share.getShare ();
            sharei[share.getNumber ()-1] = coShare;

            primeAndShares.append ("\n").append (coShare);
        }

        return String.valueOf (primeAndShares);
    }

    private static String combineShamirShares (String prime, String[] shares)
    {
        String strNumOfShares = prime.substring (0,prime.indexOf ("P:"));
        int avaSharesNum = Integer.parseInt (strNumOfShares);

        if (shares.length == avaSharesNum)
        {
            SecretShare[] sharesToViewSecret = new SecretShare[avaSharesNum];
            for (int i=0; i<avaSharesNum; i++)
            {
                String coShareStr = shares[i].trim ();
                String shareStr = coShareStr.substring (coShareStr.indexOf (":")+1);
                int shareNum = Integer.parseInt (coShareStr.substring (0,coShareStr.indexOf (":")));
                sharesToViewSecret[i] = new SecretShare (shareNum, new BigInteger (shareStr));
            }
            String coPrimeStr = prime.trim ();
            String primeStr = coPrimeStr.substring (coPrimeStr.indexOf (":")+1);
            //int primeNum = Integer.parseInt (coPrimeStr.substring (0,coPrimeStr.indexOf ("P:")));
            BigInteger bigIntegerPrime = new BigInteger(primeStr);
            String result = Shamir.combine (sharesToViewSecret, bigIntegerPrime);
            return result;
        }
        return ("Sorry, you have to provide " + avaSharesNum + " shares in order to reconstruct your " +
                                   "secret.");
    }


    public static void main(final String[] args)
    {
        System.out.println (generateShamirShares ("Password@123", 4, 12));

        System.out.println (combineShamirShares ("4P:57227141335498039497719664191",
                                                 new String[]{"1:46408014906759654811274101243",
                                                              "5:35533534891431853551600686081",
                                                              "3:56475036329164407840164095940",
                                                              "4:3124698633283214142142432517"}));
    }
}
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 "Share"+ number + ": " + share;
    }

    private final int number;
    private final BigInteger share;
}
4P:66911912727662985127139425997
1:18968774123286583882220506766
2:4799832019998779275182245665
3:38199612445448994408262691940
4:41174116907286121055005905205
5:2641259640822036116095371071
6:45342780336694586746493427143
7:24372767774889679592604707038
8:62472961646045161809391548361
9:14737450730146940043258584729
10:3907974717832861449168153747
11:18902447844414802927803741026
12:48638784345204641379848832177

Password@123

仅当您按生成顺序将至少X个共享传递给“combine”时,它才起作用。对于示例配置“Shamir(11,20)”,“combine”应可用于11个共享的任意组合,但仅当您按生成顺序(共享0-10)传递11个或更多共享的数组时,它才起作用!不幸的是,这是另一个不起作用(真实和简单)SSS实现的示例。wikipedia上的一个也只适用于所需的奇数键。很难找到一个真正起作用的简单实现。代码似乎已经移到这里:modInverse()gcdD()
此处的方法是不必要的,因为可以使用本机方法。