Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

group: Implements Shamir and Feldman secret sharing. #348

Merged
merged 1 commit into from
Feb 14, 2024
Merged

Conversation

armfazh
Copy link
Contributor

@armfazh armfazh commented Jul 12, 2022

New:

  • Introduces Lagrange interpolation [1].
  • Shamir's secret sharing [2] on top of the group interface.
  • Feldman's verifiable secret sharing [3] on top of the group interface.

References:
[1] https://mathworld.wolfram.com/LagrangeInterpolatingPolynomial.html
[2] https://dl.acm.org/doi/10.1145/359168.359176
[3] https://ieeexplore.ieee.org/document/4568297

@armfazh armfazh added the new feature New functionality or module label Jul 12, 2022
@armfazh armfazh self-assigned this Jul 12, 2022
Copy link
Contributor

@chris-wood chris-wood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ergonomics of the API seem good, but I think we can do better with the naming. I'm curious to hear what @cjpatton has to say about the names.

group/secretsharing/ss.go Outdated Show resolved Hide resolved
group/secretsharing/ss.go Outdated Show resolved Hide resolved
group/secretsharing/ss.go Outdated Show resolved Hide resolved
group/secretsharing/ss.go Outdated Show resolved Hide resolved
group/secretsharing/ss_test.go Outdated Show resolved Hide resolved
group/secretsharing/poly.go Outdated Show resolved Hide resolved
group/secretsharing/poly.go Outdated Show resolved Hide resolved
group/secretsharing/poly.go Outdated Show resolved Hide resolved
group/secretsharing/poly.go Outdated Show resolved Hide resolved
group/secretsharing/poly.go Outdated Show resolved Hide resolved
group/secretsharing/ss.go Outdated Show resolved Hide resolved
group/secretsharing/ss.go Outdated Show resolved Hide resolved
group/secretsharing/ss.go Outdated Show resolved Hide resolved
group/secretsharing/ss.go Outdated Show resolved Hide resolved
vecComm := make(SharesCommitment, v.s.T+1)
for i, ki := range poly.coeff {
vecComm[i] = v.s.G.NewElement()
vecComm[i].MulGen(ki)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to add a big fat warning. If our secret is a small scalar, it can easily be recovered from the commitment. E.g., it's easy to see if our secret was 2 from vecComm[0].

@armfazh armfazh changed the base branch from main to polynomial July 30, 2022 03:18
secretsharing/ss.go Outdated Show resolved Hide resolved
@bwesterb bwesterb self-requested a review August 1, 2022 08:30
Base automatically changed from polynomial to main August 9, 2022 20:56
@armfazh armfazh force-pushed the secretSharing branch 2 times, most recently from b0d84b5 to bb3e3e4 Compare August 24, 2022 22:58
Copy link
Contributor

@cjpatton cjpatton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First pass focuses on API, I will look at the math next :)

High level questions about math/polynomial:

  1. This is defined around the "scalars" of a "group". Do the operations in this package require the scalars to comprise a finite field, or more specifically, the group to have prime order?
  2. If "yes" to (1.), why not define this package around a generic finite field?

It's a bit odd that constructing a new impl of SecretSharing requires a Group. Shamir's (and Feldman's I imagine, but I haven't checked) is well-defined for any finite field, hence this API is more restrictive than necessary.

If this API is only intended for use with cryptographic protocols built from an implementation of Group, then I would make this very clear in the documentation.

math/polynomial/polynomial.go Show resolved Hide resolved
secretsharing/ss.go Outdated Show resolved Hide resolved
secretsharing/ss.go Outdated Show resolved Hide resolved
secretsharing/ss.go Outdated Show resolved Hide resolved
secretsharing/ss.go Outdated Show resolved Hide resolved
secretsharing/ss.go Outdated Show resolved Hide resolved
secretsharing/ss.go Outdated Show resolved Hide resolved
secretsharing/ss.go Outdated Show resolved Hide resolved
secretsharing/ss.go Outdated Show resolved Hide resolved
secretsharing/ss.go Outdated Show resolved Hide resolved
@armfazh
Copy link
Contributor Author

armfazh commented Aug 26, 2022

  1. This is defined around the "scalars" of a "group". Do the operations in this package require the scalars to comprise a finite field, or more specifically, the group to have prime order?
  2. If "yes" to (1.), why not define this package around a generic finite field?

It's true that secret sharing package can be defined over a finite field. In CIRCL, currently we have no such abstraction. This may require to gather all the field implementations we have in CIRCL.
For the purposes of threshold cryptography, we use ecc groups and its set of scalars. At this point we are covering this use case, but we can accommodate more use cases when needed.

secretsharing/ss.go Outdated Show resolved Hide resolved
secretsharing/ss.go Outdated Show resolved Hide resolved
secretsharing/ss.go Outdated Show resolved Hide resolved
secretsharing/ss.go Outdated Show resolved Hide resolved
secretsharing/ss.go Outdated Show resolved Hide resolved
secretsharing/ss.go Outdated Show resolved Hide resolved
secretsharing/ss.go Show resolved Hide resolved
secretsharing/ss.go Outdated Show resolved Hide resolved
secretsharing/ss.go Show resolved Hide resolved
secretsharing/ss.go Outdated Show resolved Hide resolved
@armfazh
Copy link
Contributor Author

armfazh commented Oct 10, 2022

Hi folks, to move forward with this PR, please leave your comments to the latest changes. And approve if you are ok with the current status.

cc: @bwesterb @chris-wood @cjpatton

Copy link
Contributor

@chris-wood chris-wood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Functionally, this seems correct, but I think we can still improve the API to make it easier to build things like STAR on top of this.

@@ -53,6 +56,15 @@ func (p Polynomial) Evaluate(x group.Scalar) group.Scalar {
return px
}

// Coefficient returns a deep-copy of the n-th polynomial's coefficient.
// Note coefficients are sorted in ascending order with respect to the degree.
func (p Polynomial) Coefficient(n uint) group.Scalar {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems strange that this function takes a uint as input but Degree() outputs an int -- should they use the same type?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The odd case is Degree() returning -1 for the special case of the zero polynomial. We might remove this special case.
@bwesterb what do you think?

secretsharing/ss.go Outdated Show resolved Hide resolved
// A (t,n) secret sharing allows to split a secret into n shares, such that the
// secret can be only recovered from any subset of t+1 shares. Returns an error
// if 0 <= t < n does not hold.
func NewShamirSecretSharing(g group.Group, t, n uint) (SecretSharing, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would only pass t as the input here, and let the caller determine how many shares they need in order to split a secret by invoking Shard as many times as needed (though at least t times).

Copy link
Contributor Author

@armfazh armfazh Oct 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still needs to work on this
done

}

// Shard splits the secret into n shares.
func (s SecretSharing) Shard(rnd io.Reader, secret group.Scalar) []Share {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we split this up into the following two functions?

  1. Shard, which takes as input a secret and a (set of points) at which to produce (a set of) share(s).
  2. RandomShard, which takes randomness as input along with the secret and produces a random share.

That would be more useful for the STAR application.

secretsharing/ss.go Outdated Show resolved Hide resolved
secretsharing/ss.go Show resolved Hide resolved
secretsharing/ss.go Outdated Show resolved Hide resolved
Copy link
Contributor

@chris-wood chris-wood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the interface still isn't quite right, so let me step back and identify the use cases I think are important to solve.

  1. A user wants to share a secret with n other users with a recovery threshold of t. This is the classic secret sharing setting. The caller could provide "IDs," or they could be provided at random. I think it's probably easier if they're generated randomly and then the caller assigns these IDs to each user.
  2. t users want to independently produce random shares of the same secret such that someone else (a collector or combiner) can recover the secret. Each user has to agree on the secret sharing polynomial independently and non-interactively, i.e., without communication, otherwise this doesn't work. This is the STAR use case.

Based on my understanding of this PR, it looks like (1) is partly addressed (though I would make the API somewhat different so as to not require a monotonically increasing selection of share input [x coordinates]), but (2) does not seem to be addressed.

It's fine if we want to address these in separate PRs, but I'd like to understand what the plan is for both. @armfazh, can you please clarify? In particular, if the plan is to do this in two separate PRs, can you please clarify how the use case in (1) is satisfied?

secretsharing/ss.go Outdated Show resolved Hide resolved
// Share represents a share of a secret.
type Share struct {
// ID uniquely identifies a share in a secret sharing instance.
ID group.Scalar
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we rename this to something else? Maybe Input, and maybe rename Value to Output?

@armfazh
Copy link
Contributor Author

armfazh commented Nov 24, 2022

I think the interface still isn't quite right, so let me step back and identify the use cases I think are important to solve.

  1. A user wants to share a secret with n other users with a recovery threshold of t. This is the classic secret sharing setting. The caller could provide "IDs," or they could be provided at random. I think it's probably easier if they're generated randomly and then the caller assigns these IDs to each user.
  2. t users want to independently produce random shares of the same secret such that someone else (a collector or combiner) can recover the secret. Each user has to agree on the secret sharing polynomial independently and non-interactively, i.e., without communication, otherwise this doesn't work. This is the STAR use case.

Based on my understanding of this PR, it looks like (1) is partly addressed (though I would make the API somewhat different so as to not require a monotonically increasing selection of share input [x coordinates]), but (2) does not seem to be addressed.

It's fine if we want to address these in separate PRs, but I'd like to understand what the plan is for both. @armfazh, can you please clarify? In particular, if the plan is to do this in two separate PRs, can you please clarify how the use case in (1) is satisfied?

The code I just pushed satisfy these cases:
a) both textbook Shamir and Feldman secret; and
b) the case when the share is generated with a prescribed ID (case 1).

For case 2: one solution is that rand (the first param of New(rand, ...)) can be passed as a PRNG with a seed, this makes the internals of the secret sharing deterministic (and reproducible).
Other solutions can be adopted later (but not in this PR).

@armfazh armfazh merged commit 2a2b195 into main Feb 14, 2024
@armfazh armfazh deleted the secretSharing branch February 14, 2024 19:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new feature New functionality or module
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants