-
Notifications
You must be signed in to change notification settings - Fork 147
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
Conversation
There was a problem hiding this 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
vecComm := make(SharesCommitment, v.s.T+1) | ||
for i, ki := range poly.coeff { | ||
vecComm[i] = v.s.G.NewElement() | ||
vecComm[i].MulGen(ki) |
There was a problem hiding this comment.
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].
b0d84b5
to
bb3e3e4
Compare
There was a problem hiding this 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:
- 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?
- 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.
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. |
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. |
da1ac24
to
1b68fea
Compare
There was a problem hiding this 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 { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
// 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) { |
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
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
secretsharing/ss.go
Outdated
} | ||
|
||
// Shard splits the secret into n shares. | ||
func (s SecretSharing) Shard(rnd io.Reader, secret group.Scalar) []Share { |
There was a problem hiding this comment.
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?
Shard
, which takes as input a secret and a (set of points) at which to produce (a set of) share(s).RandomShard
, which takes randomness as input along with the secret and produces a random share.
That would be more useful for the STAR application.
98bfada
to
b0a42cb
Compare
There was a problem hiding this 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.
- A user wants to share a secret with
n
other users with a recovery threshold oft
. 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. 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?
// Share represents a share of a secret. | ||
type Share struct { | ||
// ID uniquely identifies a share in a secret sharing instance. | ||
ID group.Scalar |
There was a problem hiding this comment.
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
?
The code I just pushed satisfy these cases: For case 2: one solution is that |
b0a42cb
to
bbaa64a
Compare
bbaa64a
to
9c3d94b
Compare
New:
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