-
Notifications
You must be signed in to change notification settings - Fork 65
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add vss primitive * Modify some details * Add files via upload * Rename BUILD to BUILD.bazel * Delete BUILD.bazel * Add files via upload * Changes poly.* and vss.*
- Loading branch information
1 parent
ea637f1
commit a4fd33a
Showing
6 changed files
with
611 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
load("//bazel:yacl.bzl", "yacl_cc_library", "yacl_cc_test") | ||
|
||
package(default_visibility = ["//visibility:public"]) | ||
|
||
yacl_cc_library( | ||
name = "poly", | ||
srcs = ["poly.cc"], | ||
hdrs = ["poly.h"], | ||
deps = [ | ||
"//yacl/math/mpint", | ||
], | ||
) | ||
|
||
yacl_cc_library( | ||
name = "vss", | ||
srcs = ["vss.cc"], | ||
hdrs = ["vss.h"], | ||
deps = [ | ||
":poly", | ||
"//yacl/crypto/base/ecc", | ||
"//yacl/math/mpint", | ||
], | ||
) | ||
|
||
yacl_cc_test( | ||
name = "vss_test", | ||
srcs = ["vss_test.cc"], | ||
deps = [ | ||
":poly", | ||
":vss", | ||
"//yacl/crypto/base/ecc", | ||
"//yacl/math/mpint", | ||
], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
#include "yacl/crypto/primitives/vss/poly.h" | ||
|
||
namespace yacl::crypto { | ||
|
||
// Generate a random polynomial with the given zero value, threshold, and | ||
// modulus_. | ||
void Polynomial::CreatePolynomial(const math::MPInt& zero_value, | ||
size_t threshold) { | ||
// Create a vector to hold the polynomial coefficients. | ||
std::vector<math::MPInt> coefficients(threshold); | ||
|
||
// Set the constant term (coefficient[0]) of the polynomial to the given | ||
// zero_value. | ||
coefficients[0] = zero_value; | ||
|
||
// Generate random coefficients for the remaining terms of the polynomial. | ||
for (size_t i = 1; i < threshold; ++i) { | ||
// Create a variable to hold the current coefficient being generated. | ||
math::MPInt coefficient_i; | ||
|
||
// Generate a random integer less than modulus_ and assign it to | ||
// coefficient_i. | ||
math::MPInt::RandomLtN(this->modulus_, &coefficient_i); | ||
|
||
// Set the current coefficient to the generated random value. | ||
coefficients[i] = coefficient_i; | ||
} | ||
|
||
// Set the generated coefficients as the coefficients of the polynomial. | ||
SetCoeffs(coefficients); | ||
} | ||
|
||
// Horner's method for computing the polynomial value at a given x. | ||
void Polynomial::EvaluatePolynomial(const math::MPInt& x, | ||
math::MPInt& result) const { | ||
// Initialize the result to the constant term (coefficient of highest degree) | ||
// of the polynomial. | ||
if (!coeffs_.empty()) { | ||
result = coeffs_.back(); | ||
} else { | ||
// If the coefficients vector is empty, print a warning message. | ||
std::cout << "coeffs_ is empty!!!" << std::endl; | ||
} | ||
|
||
// Evaluate the polynomial using Horner's method. | ||
// Starting from the second highest degree coefficient to the constant term | ||
// (coefficient[0]). | ||
for (int i = coeffs_.size() - 2; i >= 0; --i) { | ||
// Create a duplicate of the given x to avoid modifying it. | ||
// math::MPInt x_dup = x; | ||
|
||
// Multiply the current result with the x value and update the result. | ||
// result = x_dup.MulMod(result, modulus_); | ||
result = x.MulMod(result, modulus_); | ||
// Add the next coefficient to the result. | ||
result = result.AddMod(coeffs_[i], modulus_); | ||
} | ||
} | ||
|
||
// Lagrange Interpolation algorithm for polynomial interpolation. | ||
void Polynomial::LagrangeInterpolation(std::vector<math::MPInt>& xs, | ||
std::vector<math::MPInt>& ys, | ||
math::MPInt& result) const { | ||
// Initialize the accumulator to store the result of the interpolation. | ||
math::MPInt acc(0); | ||
|
||
// Loop over each element in the input points xs and interpolate the | ||
// polynomial. | ||
for (size_t i = 0; i < xs.size(); ++i) { | ||
// Initialize the numerator and denominator for Lagrange interpolation. | ||
math::MPInt num(1); | ||
math::MPInt denum(1); | ||
|
||
// Compute the numerator and denominator for the current interpolation | ||
// point. | ||
for (size_t j = 0; j < xs.size(); ++j) { | ||
if (j != i) { | ||
math::MPInt xj = xs[j]; | ||
|
||
// Update the numerator by multiplying it with the current xj. | ||
num = num.MulMod(xj, modulus_); | ||
|
||
// Compute the difference between the current xj and the current xi | ||
// (xs[i]). | ||
math::MPInt xj_sub_xi = xj.SubMod(xs[i], modulus_); | ||
|
||
// Update the denominator by multiplying it with the difference. | ||
denum = denum.MulMod(xj_sub_xi, modulus_); | ||
} | ||
} | ||
|
||
// Compute the inverse of the denominator modulo the modulus_. | ||
math::MPInt denum_inv = denum.InvertMod(modulus_); | ||
|
||
// Compute the current interpolated value and add it to the accumulator. | ||
acc = ys[i] | ||
.MulMod(num, modulus_) | ||
.MulMod(denum_inv, modulus_) | ||
.AddMod(acc, modulus_); | ||
} | ||
|
||
// Store the final interpolated result in the 'result' variable. | ||
result = acc; | ||
} | ||
} // namespace yacl::crypto |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
#pragma once | ||
|
||
#include "yacl/math/mpint/mp_int.h" | ||
|
||
namespace yacl::crypto { | ||
|
||
// Polynomial class for polynomial manipulation and sharing. | ||
class Polynomial { | ||
public: | ||
/** | ||
* @brief Construct a new Polynomial object with modulus | ||
* | ||
* @param modulus | ||
*/ | ||
Polynomial(math::MPInt modulus) : modulus_(modulus) {} | ||
|
||
/** | ||
* @brief Destroy the Polynomial object | ||
* | ||
*/ | ||
~Polynomial(){}; | ||
|
||
/** | ||
* @brief Creates a random polynomial with the given zero_value, threshold, | ||
* and modulus. | ||
* | ||
* @param zero_value | ||
* @param threshold | ||
* @param modulus | ||
*/ | ||
void CreatePolynomial(const math::MPInt& zero_value, size_t threshold); | ||
|
||
/** | ||
* @brief Horner's method, also known as Horner's rule or Horner's scheme, is | ||
* an algorithm for the efficient evaluation of polynomials. It is used to | ||
* compute the value of a polynomial at a given point without the need for | ||
* repeated multiplication and addition operations. The method is particularly | ||
* useful for high-degree polynomials. | ||
* | ||
* The general form of a polynomial is: | ||
* | ||
* f(x) = a_n * x^n + a_{n-1} * x^{n-1} + ... + a_1 * x + a_0 | ||
* | ||
* Horner's method allows us to compute the value of the polynomial f(x) at a | ||
* specific point x_0 in a more efficient way by factoring out the common | ||
* terms: | ||
* | ||
* f(x_0) = (((a_n * x_0 + a_{n-1}) * x_0 + a_{n-2}) * x_0 + ... + a_1) * x_0 | ||
* + a_0 | ||
* | ||
* The algorithm proceeds iteratively, starting with the coefficient of the | ||
* highest degree term, and at each step, it multiplies the current partial | ||
* result by the input point x_0 and adds the next coefficient. | ||
* | ||
* The advantages of using Horner's method include reducing the number of | ||
* multiplications and additions compared to the straightforward | ||
* | ||
* @param x | ||
* @param modulus | ||
* @param result | ||
*/ | ||
void EvaluatePolynomial(const math::MPInt& x, math::MPInt& result) const; | ||
|
||
/** | ||
* @brief Performs Lagrange interpolation to interpolate the polynomial based | ||
* on the given points. | ||
* | ||
* @param xs | ||
* @param ys | ||
* @param prime | ||
* @param result | ||
*/ | ||
void LagrangeInterpolation(std::vector<math::MPInt>& xs, | ||
std::vector<math::MPInt>& ys, | ||
math::MPInt& result) const; | ||
|
||
/** | ||
* @brief Sets the coefficients of the polynomial to the provided vector of | ||
* MPInt. | ||
* | ||
* @param coefficients | ||
*/ | ||
void SetCoeffs(const std::vector<math::MPInt>& coefficients) { | ||
coeffs_ = coefficients; | ||
} | ||
|
||
/** | ||
* @brief Returns the coefficients of the polynomial as a vector of MPInt. | ||
* | ||
* @return std::vector<math::MPInt> | ||
*/ | ||
std::vector<math::MPInt> GetCoeffs() const { return coeffs_; } | ||
|
||
private: | ||
// Vector to store the coefficients of the polynomial. | ||
std::vector<math::MPInt> coeffs_; | ||
math::MPInt modulus_; | ||
}; | ||
|
||
} // namespace yacl::crypto |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
#include "yacl/crypto/primitives/vss/vss.h" | ||
|
||
namespace yacl::crypto { | ||
|
||
// Generate shares for the Verifiable Secret Sharing scheme. | ||
// Generate shares for the given secret using the provided polynomial. | ||
std::vector<VerifiableSecretSharing::Share> | ||
VerifiableSecretSharing::CreateShare(const math::MPInt& secret, | ||
Polynomial& poly) { | ||
// Create a polynomial with the secret as the constant term and random | ||
// coefficients. | ||
std::vector<math::MPInt> coefficients(this->GetThreshold()); | ||
poly.CreatePolynomial(secret, this->GetThreshold()); | ||
|
||
std::vector<math::MPInt> xs(this->GetTotal()); | ||
std::vector<math::MPInt> ys(this->GetTotal()); | ||
|
||
// Vector to store the generated shares (x, y) for the Verifiable Secret | ||
// Sharing scheme. | ||
std::vector<VerifiableSecretSharing::Share> shares; | ||
|
||
// Generate shares by evaluating the polynomial at random points xs. | ||
for (size_t i = 0; i < this->GetTotal(); i++) { | ||
math::MPInt x_i; | ||
math::MPInt::RandomLtN(this->GetPrime(), &x_i); | ||
|
||
// EvaluatePolynomial uses Horner's method. | ||
// Evaluate the polynomial at the point x_i to compute the share's | ||
// y-coordinate (ys[i]). | ||
poly.EvaluatePolynomial(x_i, ys[i]); | ||
|
||
xs[i] = x_i; | ||
shares.push_back({xs[i], ys[i]}); | ||
} | ||
|
||
return shares; | ||
} | ||
|
||
// Generate shares with commitments for the Verifiable Secret Sharing scheme. | ||
VerifiableSecretSharing::ShareWithCommitsResult | ||
VerifiableSecretSharing::CreateShareWithCommits( | ||
const math::MPInt& secret, | ||
const std::unique_ptr<yacl::crypto::EcGroup>& ecc_group, Polynomial& poly) { | ||
// Create a polynomial with the secret as the constant term and random | ||
// coefficients. | ||
poly.CreatePolynomial(secret, this->threshold_); | ||
|
||
std::vector<math::MPInt> xs(this->total_); | ||
std::vector<math::MPInt> ys(this->total_); | ||
std::vector<VerifiableSecretSharing::Share> shares(this->total_); | ||
|
||
// Generate shares by evaluating the polynomial at random points xs. | ||
for (size_t i = 0; i < this->total_; i++) { | ||
math::MPInt x_i; | ||
math::MPInt::RandomLtN(this->prime_, &x_i); | ||
|
||
poly.EvaluatePolynomial(x_i, ys[i]); | ||
xs[i] = x_i; | ||
shares[i] = {xs[i], ys[i]}; | ||
} | ||
|
||
// Generate commitments for the polynomial coefficients using the elliptic | ||
// curve group. | ||
std::vector<yacl::crypto::EcPoint> commits = | ||
CreateCommits(ecc_group, poly.GetCoeffs()); | ||
|
||
return std::make_pair(shares, commits); | ||
} | ||
|
||
// Recover the secret from the shares using Lagrange interpolation. | ||
math::MPInt VerifiableSecretSharing::RecoverSecret( | ||
absl::Span<const VerifiableSecretSharing::Share> shares) { | ||
YACL_ENFORCE(shares.size() == threshold_); | ||
|
||
math::MPInt secret(0); | ||
std::vector<math::MPInt> xs(shares.size()); | ||
std::vector<math::MPInt> ys(shares.size()); | ||
|
||
// Extract xs and ys from the given shares. | ||
for (size_t i = 0; i < shares.size(); i++) { | ||
xs[i] = shares[i].x; | ||
ys[i] = shares[i].y; | ||
} | ||
|
||
// Use Lagrange interpolation to recover the secret from the shares. | ||
Polynomial poly(this->prime_); | ||
poly.LagrangeInterpolation(xs, ys, secret); | ||
|
||
return secret; | ||
} | ||
|
||
// Generate commitments for the given coefficients using the provided elliptic | ||
// curve group. | ||
std::vector<yacl::crypto::EcPoint> CreateCommits( | ||
const std::unique_ptr<yacl::crypto::EcGroup>& ecc_group, | ||
const std::vector<math::MPInt>& coefficients) { | ||
std::vector<yacl::crypto::EcPoint> commits(coefficients.size()); | ||
for (size_t i = 0; i < coefficients.size(); i++) { | ||
// Commit each coefficient by multiplying it with the base point of the | ||
// group. | ||
commits[i] = ecc_group->MulBase(coefficients[i]); | ||
} | ||
return commits; | ||
} | ||
|
||
// Verify the commitments and shares in the Verifiable Secret Sharing scheme. | ||
bool VerifyCommits(const std::unique_ptr<yacl::crypto::EcGroup>& ecc_group, | ||
const VerifiableSecretSharing::Share& share, | ||
const std::vector<yacl::crypto::EcPoint>& commits, | ||
const math::MPInt& prime) { | ||
// Compute the expected commitment of the share.y by multiplying it with the | ||
// base point. | ||
yacl::crypto::EcPoint expected_gy = ecc_group->MulBase(share.y); | ||
|
||
math::MPInt x_pow_i(1); | ||
yacl::crypto::EcPoint gy = commits[0]; | ||
|
||
// Evaluate the Lagrange polynomial at x = share.x to compute the share.y and | ||
// verify it. | ||
for (size_t i = 1; i < commits.size(); i++) { | ||
x_pow_i = x_pow_i.MulMod(share.x, prime); | ||
gy = ecc_group->Add(gy, ecc_group->Mul(commits[i], x_pow_i)); | ||
} | ||
|
||
// Compare the computed gy with the expected_gy to verify the commitment. | ||
if (ecc_group->PointEqual(expected_gy, gy)) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
} // namespace yacl::crypto |
Oops, something went wrong.