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

RandHound 341 #519

Merged
merged 76 commits into from
Oct 13, 2016
Merged

RandHound 341 #519

merged 76 commits into from
Oct 13, 2016

Conversation

Daeinar
Copy link
Member

@Daeinar Daeinar commented Aug 16, 2016

Addresses #341 and #321.

@Daeinar Daeinar self-assigned this Aug 16, 2016
@Daeinar Daeinar changed the title Randhound 341 RandHound 341 Aug 19, 2016
Copy link
Member

@ineiti ineiti left a 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 use range
  • You can use log.ErrFatal or require.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
Copy link
Member

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
Copy link
Member

Choose a reason for hiding this comment

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

s/(XXX: name)/randhound/ ?

Copy link
Member Author

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++ {
Copy link
Member

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) {
Copy link
Member

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?

Copy link
Member Author

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.

Copy link
Contributor

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.

Copy link
Member

@liamsi liamsi Oct 10, 2016

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
Copy link
Member

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))
Copy link
Member

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)
Copy link
Member

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)
Copy link
Member

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++ {
Copy link
Member

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)
Copy link
Member

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?

@Daeinar
Copy link
Member Author

Daeinar commented Oct 4, 2016

@ineiti: Addressed most of your comments. I did not change the format of the return values in Setup(...) though. I guess we can do that when we resolve #624.

for i := range m {
j := int(random.Uint64(prng) % uint64(i+1))
m[i] = m[j]
m[j] = i + 1
Copy link
Contributor

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 ?

Copy link
Member Author

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

Copy link
Contributor

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.

Copy link
Member Author

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
Copy link
Contributor

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 :)

Copy link
Member Author

@Daeinar Daeinar Oct 6, 2016

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
Copy link
Contributor

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 ?

Copy link
Member Author

@Daeinar Daeinar Oct 6, 2016

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 jin 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.

Copy link
Member Author

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. ;)

@nikkolasg
Copy link
Contributor

nikkolasg commented Oct 6, 2016

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 ?

@Daeinar
Copy link
Member Author

Daeinar commented Oct 6, 2016

@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) {
Copy link
Member

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.

Copy link
Member Author

@Daeinar Daeinar Oct 13, 2016

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
Copy link
Member

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...

Copy link
Member Author

@Daeinar Daeinar Oct 13, 2016

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?

Copy link
Member

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

Copy link
Member

@liamsi liamsi Oct 13, 2016

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 ;-)

Copy link
Member Author

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) {
Copy link
Member

@liamsi liamsi Oct 10, 2016

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.

Copy link
Member Author

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) {
Copy link
Member

Choose a reason for hiding this comment

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

// Group information
server [][]*sda.TreeNode // Grouped servers
group [][]int // Grouped server indices
threshold []int // Group thresholds
Copy link
Member

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.

Copy link
Member Author

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.

Copy link
Member

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 ;-)

Copy link
Member Author

@Daeinar Daeinar Oct 13, 2016

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. ;)

Copy link
Member

Choose a reason for hiding this comment

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

+1 for range ;)

@liamsi
Copy link
Member

liamsi commented Oct 10, 2016

Besides a few comments this PR looks good to me. Feel free to decide which are relevant to you (and which not).

@liamsi liamsi merged commit 47375c4 into master Oct 13, 2016
@liamsi liamsi deleted the randhound_341 branch October 13, 2016 14:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants