//Returns enumerator of shares by calculating (x, y) pair points for a given amount of shares public IEnumerable <Share> GetShares(int totalShares) { for (int i = 1; i <= totalShares; ++i) { FFPolynom x = new FFPolynom(_irreduciblePolynom, new BigInteger(i)); FFPolynom y = FFPolynom.HornerEvaluateAt(_allCoefficients, i); yield return(new Share(new FFPoint(x, y))); } }
//Returns whether two finite fields polynoms are equal public override bool Equals(object obj) { FFPolynom fpp = obj as FFPolynom; if (fpp == null) { return(base.Equals(obj)); } bool res = (PrimePolynom == fpp.PrimePolynom) && (PolyValue.Equals(fpp.PolyValue)); return(res); }
//Adjusts the finite field points by removing the high term monomial private static FFPoint AdjustPoint(int total, FFPoint point) { FFPolynom corrector = new FFPolynom(point.Y.PrimePolynom, BigInteger.One); FFPolynom corrFactor = point.X; for (int i = 1; i <= total; i++) { corrector = corrector * corrFactor; } FFPolynom newY = point.Y + corrector; FFPoint newPoint = new FFPoint(point.X, newY); return(newPoint); }
//Checks for matching with Regex and proccess the , and returns FiniteFieldPoint if success; otherwise null. internal static bool TryParse(Match matchedShare, out FFPoint res) { if (!matchedShare.Success) { res = null; return(false); } try { //Parse the share string: x - number by order, y - the string after '.' sign //Gets the string matched by the particular expression. Change to lowcase and apply casing invariant string xStr = matchedShare.Groups["x"].Value.ToLowerInvariant(); string yStr = matchedShare.Groups["y"].Value.ToLowerInvariant(); //Remove initial 0s to compare with ordinal = 4 while (xStr.StartsWith("0", StringComparison.Ordinal)) { xStr = xStr.Substring(1); } // 1hexChar = 4 bits, so degree in bits = degree * 4 int polynomialDegree = yStr.Length * 4; IrreduciblePolynom irp = new IrreduciblePolynom(polynomialDegree); FFPolynom x = new FFPolynom(irp, BigInteger.Parse(xStr)); // Create an array of bites (big endian) with the length in bytes as initial phrase, initialize to 0 byte[] yArr = new byte[yStr.Length / 2]; for (int i = 0; i < yStr.Length; i += 2) { //Convert a hex-string to byte representation (1hex = 4 bits).. that's why i/2 yArr[i / 2] = Byte.Parse(yStr.Substring(i, 2), NumberStyles.HexNumber); } //Convert yArr to BigInteger and create a finite field polynom FFPolynom y = new FFPolynom(irp, yArr.FromBigEndUnsignedBytesToBigInt()); res = new FFPoint(x, y); return(true); } catch (Exception e) { res = null; return(false); } }
//Combine shares to recover the secret by applying Lagrange Interpolation for all FFPoints private RecoveredSecret RecoverImpl(IEnumerable <Share> shares) { Share[] allShares = shares.ToArray(); //Create a collection of finite field points out from generated shares IEnumerable <FFPoint> collection = allShares.Select(s => s.Point); //Recover the secret phrase using the points -> f(0) FFPolynom secretCoeff = LagrangeInterpolation.LagrInterpolate(collection); byte[] secret = secretCoeff.PolyValue.ToUnsignedBigEnd(); RecoveredSecret newRecSecret = new RecoveredSecret(secret); return(newRecSecret); }
//Shares the secret respectfully to number of shares and threshold protected virtual SharedSecret ShareImpl(byte[] secret, int threshold, int numberOfShares) { //Define irred polynom for a secret IrreduciblePolynom irreduciblePolynom = IrreduciblePolynom.GiveFromBytes(secret.Length); BigInteger rawSecret = secret.FromBigEndUnsignedBytesToBigInt(); FFPolynom secretCoeff = new FFPolynom(irreduciblePolynom, rawSecret); //Generate random polynom with corresponding irred. polynom and given threshold IEnumerable <FFPolynom> randPolynom = GenerateRandomPolynom(irreduciblePolynom, threshold - 1); //Construct an array of all coefficients represented as finite field polynoms FFPolynom[] consTerm = new[] { secretCoeff }; //Concatenate previously created random coefficients converting them as an array FFPolynom[] allCoefficients = consTerm.Concat(randPolynom).ToArray(); return(new SharedSecret(threshold, irreduciblePolynom, allCoefficients)); }
//Evaluate polynom of coefficients for certain x using Horner's method http//en.wikipedia.org/wiki/Horner_scheme public static FFPolynom HornerEvaluateAt(FFPolynom[] coefficients, long x) { FFPolynom xPoly = coefficients[0].ReturnValueInField(x); //The coefficient for the highest mono-polynom = 1 FFPolynom resValue = xPoly.DeepCopy(); //For all the coeffs, go thru them and add lowest first coeff, further multiolying by x-polyn //Start backwards for (int i = coefficients.Length - 1; i > 0; i--) { resValue = resValue + coefficients[i]; resValue = resValue * xPoly; } resValue = resValue + coefficients[0]; return(resValue); }
/// <summary> /// /Calculate f(0) in a finite field /// </summary> /// <param name="points"></param> /// <returns></returns> public static FFPolynom LagrInterpolate(IEnumerable <FFPoint> points) { FFPoint[] originalPoints = points.ToArray(); if (originalPoints.Length == 0) { throw new ArgumentOutOfRangeException(); } int threshold = originalPoints.Length; //"Correct" these points by removing the high term monomial FFPoint[] adjustedPoints = originalPoints.Select(p => AdjustPoint(threshold, p)).ToArray(); //Use Lagrange interpolating polynomials ( http//en.wikipedia.org/wiki/Lagrange_polynomial ) //to solve: // (x-x2)(x-x3)...(x-xn) (x-x1)(x-x3)...(x-xn) //P(x) = ------------------------ y1 + -------------------------- y2 + ... + // (x1-x2)(x1-x3)...(x1-xn) (x2-x1)(x2-x3)...(x2-xn-1) //Simplifying things is that x is 0 since we want to find the constant term //Polynomial that belongs to the GF[2] and represents the initially constructed polynom FFPolynom originalPolynom = originalPoints[0].Y; FFPolynom total = originalPolynom.ReturnValueInField(0); for (int iPoint = 0; iPoint < threshold; iPoint++)// where iPoint is currently processing point { FFPolynom processingNumerator = originalPolynom.ReturnValueInField(1); FFPolynom processingDenominator = originalPolynom.ReturnValueInField(1); FFPoint processingPoint = adjustedPoints[iPoint]; for (int tempPoint = 0; tempPoint < threshold; tempPoint++) { //Skip if both are the same if (iPoint == tempPoint) { continue; } //numerator needs multiplied by //(0-x_i) = -x_i = x_i //subtraction and addition are the same in GF[2] processingNumerator *= adjustedPoints[tempPoint].X; processingDenominator *= (processingPoint.X + adjustedPoints[tempPoint].X); } //Dividing is just multiplying by the inverse FFPolynom denomInv = processingDenominator.GetInverse(); FFPolynom fraction = processingNumerator * denomInv; //Multiply the fraction by the corresponding y_i FFPolynom currentTermValue = fraction * processingPoint.Y; total += currentTermValue; } return(total); }
//Constructs the point using two polynoms for x and y dimension respectfully public FFPoint(FFPolynom x, FFPolynom y) { X = x; Y = y; }