-
Notifications
You must be signed in to change notification settings - Fork 106
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
RandHound 341 #519
RandHound 341 #519
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.
Very shallow 1st review.
- Lots of
for
-loops where you can userange
- You can use
log.ErrFatal
orrequire.Nil
in tests
@@ -92,10 +92,10 @@ func HashFileSuite(suite abstract.Suite, file string) ([]byte, error) { | |||
} | |||
|
|||
// HashArgs takes all args and returns the hash. Every arg has to implement | |||
// BinaryMarshaler. | |||
// BinaryMarshaler or will be added using fmt.Sprint |
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.
Sorry, that was my comment - it is incorrect that missing things will be added using fmt.Sprint
.
"github.com/dedis/crypto/random" | ||
) | ||
|
||
// Package (XXX: name) provides functionality to show equality of discrete |
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.
s/(XXX: name)/randhound/ ?
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.
No, since the entire proof.go
file implements PVSS and should be extracted at some point and be put into dedis/crypto
, see #624.
|
||
n := len(g) | ||
base := make([]ProofBase, n) | ||
for i := 0; i < n; i++ { |
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.
for i := range base
|
||
// Setup initializes the proof by randomly selecting a commitment v, | ||
// determining the challenge c = H(xG,xH,vG,vH), and the response r = v - cx. | ||
func (p *Proof) Setup(scalar ...abstract.Scalar) ([]abstract.Point, []abstract.Point, []ProofCore, 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.
Would it make sense to put the []abstract.Point
together in a structure?
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 am not sure. I tried to keep it as simple as possible and I am not sure if you get any benefit of having just []abstract.Point
in a structure. You would probably have to put all the return values into a structure. I guess that's what you mean? Iirc I tried that a while ago and it complicated quite a few things in the other code that uses PVSS. I'll think about it again.
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.
You would probably have to put all the return values into a structure.
Yes, that'd be nice if possible. If you remember which part posed problems, don't hesitate to drop it to us to see if something's possible.
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.
Would it make sense to put the []abstract.Point together in a structure?
If this is only about readability of the code, here is yet another suggestion: You could also consider named return values. The signature of the function could then look like this:
func (p *Proof) Setup(scalar ...abstract.Scalar) (xG, xH []abstract.Point, proofCore []ProofCore, err error) {
or (together with my above comment below) even simpler
func (p *Proof) Setup(scalar ...abstract.Scalar) (xG, xH []abstract.Point, err error) {
return nil, nil, errors.New("Received unexpected number of points") | ||
} | ||
|
||
var good, bad []int |
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 good, the bad, and the ugly.
_ = goodEnc | ||
_ = badEnc | ||
|
||
//log.Lvlf1("Enc: %v %v %v %v %v %v", goodEnc, badEnc, len(X), len(encShare), len(decShare), len(decProof)) |
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 used?
decShare = append(decShare[:k], decShare[k+1:]...) | ||
} | ||
|
||
//log.Lvlf1("Dec: %v %v", goodDec, badDec) |
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.
Is this still used?
return err | ||
} | ||
rnd = rh.Suite().Point().Add(rnd, ps) | ||
//log.Lvlf1("Transcript: %v %v", src, ps) |
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.
Is this still used?
return nil, nil, err | ||
|
||
// Record valid encrypted shares per secret/server | ||
for i := 0; i < len(good); i++ { |
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.
for i, g := range good
and replace good[i]
with g
.
rh.chosenSecret[i] = secret | ||
} | ||
|
||
//log.Lvlf1("Grouping: %v", rh.group) |
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 used? Possible to use log.Lvlf3
?
for i := range m { | ||
j := int(random.Uint64(prng) % uint64(i+1)) | ||
m[i] = m[j] | ||
m[j] = i + 1 |
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 don't know where this comes from but it deviates a bit from the "Fisher Yates " shuffle then derived by Durstenfeld for CS ( see link ).
The part that seems missing is the if i != j { m[i] = m[j] }
. Of course I haven't checked out the recursion proof of the wikipedia algo so I would have to spend more time to check if this impl. is correct.
How did you came up with this implementation ?
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's basically an adaptation of Golang's rand.Perm(...)
function, see here: https://golang.org/src/math/rand/rand.go?s=5071:5103#L164
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.
Sorry, just saw that The condition that checks if j ≠ i may be omitted in languages that have no problems accessing uninitialized array values, and for which assigning is cheaper than comparing.
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.
Ah, yes that makes sense!
hs := rh.Suite().Hash().Size() | ||
rand := make([]byte, hs) | ||
random.Stream.XORKeyStream(rand, rand) | ||
rh.cliRand = rand |
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.
This is already done in dedis/crypto . Even if it's not wrong here, let's try to use the crypto library when it's possible to avoid duplication :)
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.
Ah thanks I wasn't aware of this function in dedis/crypto, I will of course use that instead.
// Check availability of corresponding R2 messages, skip if not there | ||
target := r1.EncShare[j].Target | ||
if _, ok := t.R2s[target]; !ok { | ||
continue OUTER |
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 don't get it. If you go to OUTER you start again with the same data so it will go again to this line and go again to OUTER ?
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.
This is meant to skip all the code in the inner loop in case the R2 message is not there. Meaning when we reach continue OUTER
in the inner loop then we go to the next j
in the outer loop without executing anything that's coming after line 372 for the skipped loop iteration. Here's an analogous example:
for i := 0; i < 3; i++ {
OUTER:
for j := 0; j < 3; j++ {
if i == j {
continue OUTER
}
fmt.Printf("(i,j) = (%v,%v)\n", i, j)
}
}
See also http://relistan.com/continue-statement-with-labels-in-go/ for more information.
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.
@nikkolasg: Okay leaving out the OUTER
also works. ;)
Ok this is a huge PR and I'm not sure to be familiar enough with all the crypto inside to be a really good reviewer for this one. I'd need to read the paper on JVSS and the one you're writing to get a full grasp. I'm planning on this but can't now so on the surface, to me the code looks good :) On a more structural level, I see you coded PVSS yourself in the same package. Would it make sense now / later to decouple that from the randhound code and to integrate that in the crypto library ? I think it would be a real good target for the crypto library, the same way we have jvss & cosi integrated in the crypto library. Of course these were introduced after we coded the protocol so it does not have to be now. What do you think ? |
@nikkolasg: Fully agree on the PVSS part. I've already added an issue on that topic a couple of days ago, see #624. I am not sure how urgent that is though and we maybe first want to focus on other things? |
// a slice of BinaryMarshalers. | ||
func convertToBinaryMarshaler(args ...interface{}) ([]encoding.BinaryMarshaler, error) { | ||
// a slice of BinaryMarshalers | ||
func ConvertToBinaryMarshaler(args ...interface{}) ([]encoding.BinaryMarshaler, 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.
Will this be used externally (would make sense). If not, I think this should remain un-exported.
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 will move all of the stuff from crypto/hash.go
to the crypto library at some point. So I guess this can be addressed later.
p.core[i] = ProofCore{c, r, vG, vH} | ||
} | ||
|
||
return xG, xH, p.core, nil |
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 wonder if it wouldn't make sense to not return p.core
but make p.core
public (or accessible through a "getter" if you prefer that)? The caller has the corresponding Proof
struct anyways...
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 am somewhat undecided on this one. After Setup()
you usually want to do something with the p.core
part of the proof right away, like sending it to some other peer for verification. Not sure what the advantage would be to have a "getter" that you need to call separately every time you do a Setup()
. Would it be better coding style to have a one?
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.
Would it be better coding style to have a "getter"?
I think this depends on your preferences. As p.core
is an array, the returned object (in any case) can be manipulated. So you could as well just make core
a public/exported field:
See here: https://play.golang.org/p/pkZHSVzSgk
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.
And the reason I suggested that isn't about the getter, it's just to make the code more readable by reducing the number of returned objects (as the caller could have access to core
by naming it Core
without returning it and the provided "safety" provided by golang would be the same ). Mainly because the others complained about the number of args returned. But if you don't like it, just keep it like this. It's just a matter of style (and I'm sure many people could have vim vs. emacs like discussion about it ;-)
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.
Okay convinced, I make it public and adapt the rest. :)
|
||
// Verify validates the proof against the given input by checking that | ||
// vG == rG + c(xG) and vH == rH + c(xH). | ||
func (p *Proof) Verify(xG []abstract.Point, xH []abstract.Point) ([]int, []int, 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.
This Verify
function looks like something an external dev/PhD student would use. It would be great if was clearer for the caller when this Proof
is valid or not. From looking into the implementation and the naming of the local vars (good
, bad
) it looks like the proof is valid iff the second returned array is empty? (OK, looking into the tests clarifies this). But you could either use named vars or if you prefer comments, you could add a short comment, when this Proof
is a valid one or not.
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.
Yes good point, I'll fix the comments! Since we are doing threshold crypto here, it is allowed that some proofs fail, which is also the reason for the good
and bad
return values.
} | ||
|
||
// Verify checks that log_H(sH) == log_X(sX) using the given proof. | ||
func (pv *PVSS) Verify(H abstract.Point, X []abstract.Point, sH []abstract.Point, sX []abstract.Point, core []ProofCore) ([]int, []int, 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.
Same comment as https://github.com/dedis/cothority/pull/519/files#r82609495
// Group information | ||
server [][]*sda.TreeNode // Grouped servers | ||
group [][]int // Grouped server indices | ||
threshold []int // Group thresholds |
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.
Nitpicking (as this is only unexported): thresholds
would make more sense. Otherwise one would expect this to be a single int
and not an array.
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 am usually sticking to the singular, so that when you iterate over the variable you have threshold[i]
instead of thresholds[i]
which is more intuitive to me. In the above example the same holds for server[i][j]
etc. I should probably check if there are some Golang coding conventions on that.
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 most idiomatic golang way would be to iterate using range
instead. Like here: https://play.golang.org/p/HtZlb8Ctav
But as I said, this was just nitpicking ;-)
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.
Hmm right. I should get used to that. ;)
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.
+1 for range
;)
Besides a few comments this PR looks good to me. Feel free to decide which are relevant to you (and which not). |
Addresses #341 and #321.