/// <summary> /// Recreate a secret from the specified shares. /// </summary> /// <param name="Shares">The shares to be recombined.</param> public Secret(KeyShare[] Shares) { this.Key = Combine(Shares); }
/// <summary> /// Recreate a secret from shares specified as Base32 encoded strings. /// </summary> /// <param name="Shares">The shares to be recombined.</param> public Secret (string[] Shares) { var KeyShares = new KeyShare[Shares.Length]; int i = 0; foreach (var Share in Shares) { var Bytes = BaseConvert.FromBase32String(Share); KeyShares[i++] = new KeyShare(Bytes); } this.Key = Combine(KeyShares); }
static byte[] CombineNK(KeyShare[] Shares) { var Threshold = Shares[0].Threshold; if (Shares.Length < Threshold) throw new Throw("Not Enough Shares"); var Modulus = BigInteger.Pow(2, 129) - 25; BigInteger Accum = 0; //Console.WriteLine("Modulus = {0} ", Modulus); for (var Formula = 0; Formula < Threshold; Formula++) { var Value = Shares[Formula].Value; //Console.WriteLine("Value = {0} ", Value); BigInteger Numerator = 1, Denominator = 1; for (var Count = 0; Count < Threshold; Count++) { if (Formula == Count) continue; // If not the same value var Start = Shares[Formula].Index; var Next = Shares[Count].Index; Numerator = (Numerator * -Next) % Modulus; Denominator = (Denominator * (Start - Next)) % Modulus; } var InvDenominator = ModInverse(Denominator, Modulus); //Console.WriteLine(" Numerator = {0}", Numerator); //Console.WriteLine(" Denominator = {0}", Denominator); //Console.WriteLine(" InvDenominator = {0}", InvDenominator); Accum = (Modulus + Modulus + Accum + (Value * Numerator * InvDenominator)) % Modulus; if (Accum < 0) { //Console.WriteLine("Accum = {0}\n", Accum); } } //Console.WriteLine("Accum = {0} ", Accum); return GetBytes (Accum); }
static byte[] CombineN(KeyShare[] Shares) { var KeyBytes = Shares[0].Key.Length; byte[] Result = new byte[KeyBytes - 1]; foreach (var Share in Shares) { ArrayXOR1(Result, Share.Key); } return Result; }
static byte[] Combine(KeyShare[] Shares) { //var KeyBytes = 16; //Shares[0].Key.Length; var Threshold = Shares[0].Threshold; foreach (var Share in Shares) { //if (Share.Key.Length != KeyBytes) { // throw new Exception("Keys must be same length"); // } if (Share.Threshold != Threshold) { throw new Throw("Keys must have same threshold"); } } if (Shares[0].Index == 16) { return CombineN(Shares); } else { return CombineNK(Shares); } }
/// <summary> /// Create a set of N key shares with a quorum of N. /// </summary> /// <returns>The key shares created.</returns> public KeyShare[] Split(int N) { var KeyShares = new KeyShare[N]; var Threshold = (16 * N) + 15; var XOR = new byte[KeyBytes]; Array.Copy(Key, XOR, KeyBytes); for (int i = 0; i < N - 1; i++) { var Bytes = CryptoCatalog.GetBytes(KeyBytes); KeyShares[i] = new KeyShare(Threshold, Bytes); ArrayXOR(XOR, Bytes); } KeyShares[N - 1] = new KeyShare(Threshold, XOR); return KeyShares; }
/// <summary> /// Create a set of N key shares with a quorum of K. /// </summary> /// <param name="N">Number of key shares to create (max is 32).</param> /// <param name="K">Quorum of key shares required to reconstruct the secret.</param> /// <returns>The key shares created.</returns> public KeyShare[] Split(int N, int K) { if (K > N) throw new Throw("Quorum can't exceed shares"); if (K < 2) throw new Throw("Quorum must be at least 2"); if (N < 2) throw new Throw("Shares must be at least 2"); if (N > 15) throw new Throw("Too many shares"); if (N == K) return Split(N); if (K > 15) throw new Throw("Degree too high"); var PolyNomial = new BigInteger[K]; PolyNomial[0] = MakePositive(Key); //Console.WriteLine("Key = {0} ", PolyNomial[0]); for (int i = 1; i < K; i++) { var Random = CryptoCatalog.GetBytes(KeyBytes); PolyNomial[i] = MakePositive(Random); } if (KeyBits != 128) throw new Throw("Only 128 bit keys supported right now"); // 2^129-25 is a pseudo Mersene prime var Modulus = BigInteger.Pow(2, 129) - 25; //Console.WriteLine("Modulus = {0} ", Modulus); var KeyShares = new KeyShare[N]; for (int i = 0; i < N; i++) { var D = PolyMod(i + 1, PolyNomial, Modulus); KeyShares[i] = new KeyShare((K * 16) + i, D); //Console.WriteLine("Share {0} = {1}", i, D); } return KeyShares; }