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

CONIKS hasher #691

Merged
merged 3 commits into from
Jun 27, 2017
Merged

CONIKS hasher #691

merged 3 commits into from
Jun 27, 2017

Conversation

gdbelvin
Copy link
Contributor

@gdbelvin gdbelvin commented Jun 19, 2017

Add treeID, index, and depth to HashLeaf and HashEmtpy.
The fulfills the security requirements and closes #670.

Adds the CONIKS hasher to the set of map hashers.
The next PR will make it available through the command line.

@@ -0,0 +1,89 @@
// Copyright 2016 Google Inc. All Rights Reserved.
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

// Default is the standard CONIKS hasher.
var Default = New(crypto.SHA512_256)

// hasher implements the sparse merkel tree hashing algorithm specified in the CONIKS paper.
Copy link
Contributor

Choose a reason for hiding this comment

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

Same typo as before. Merkle. Please fix where you cut and pasted it from too.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

h := m.New()
h.Write(emptyIdentifier)
binary.Write(h, binary.BigEndian, uint64(treeID))
h.Write(index) // TODO block out the bits that are not part of the index.
Copy link
Contributor

Choose a reason for hiding this comment

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

What are the implications of this TODO. Does it work properly as is?

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 result is that the hashes would be incorrect. Thanks for poking at this.
I've implemented and tested the proper masking function now.

// HashEmpty returns the hash of an empty branch at a given depth.
// A depth of 0 indicates the hash of an empty leaf.
// Empty branches within the tree are plain interior nodes e1 = H(e0, e0) etc.
func (m *hasher) HashEmpty(treeID int64, index []byte, height int) []byte {
Copy link
Contributor

Choose a reason for hiding this comment

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

The comment says 'depth' but the parameter is 'height'. This will cause confusion. If it really is height can you fix it in the interface definition and the other implementation. We've tried to use 'depth' everywhere because of previous confusion.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

After merging this PR, I wouldn't be opposed to changing the tree computation algorithms to all use depth. At the moment though, the algorithms themselves use height and it's a little simpler to hide the height to depth conversion inside this function.

return h.Sum(nil)
}

// HashChildren returns the inner Merkle tree node hash of the the two child nodes l and r.
Copy link
Contributor

Choose a reason for hiding this comment

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

replace 'inner' with 'internal'.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@@ -0,0 +1,47 @@
// Copyright 2016 Google Inc. All Rights Reserved.
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@@ -25,6 +24,8 @@ import (
"github.com/google/trillian/testonly"
)

const treeID = int64(0)
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd suggest something other than zero for the ID. I'd also test that different treeID values result in different hashes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not exactly sure what to do here. The maphasher - which matches the Python / C++ merkle tree code - does not use TreeID and result in different hashes.

We could

  • Change the maphasher to include TreeID and generate new test vectors.
  • Keep the existing ones and add a new test with CONIKS test vectors. But do we really want to make the merkle package dependent on all the sub hashing algorithms?

@@ -40,6 +40,11 @@ func VerifyMapInclusionProof(index, leafHash, expectedRoot []byte, proof [][]byt
if got, want := len(leafHash)*8, hBits; got != want {
return fmt.Errorf("invalid leafHash length %d, want %d", got, want)
}
for i, element := range proof {
if got, wanta, wantb := len(element), 0, h.Size(); got != wanta && got != wantb {
return fmt.Errorf("invalid proof: len(proof[%v]) %d, want %d or %d", i, got, wanta, wantb)
Copy link
Contributor

Choose a reason for hiding this comment

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

Should use "got:, want:" formatting in Errorf.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

better?

@@ -24,6 +24,8 @@ import (
"github.com/google/trillian/merkle/rfc6962"
)

const treeID = int64(0)
Copy link
Contributor

Choose a reason for hiding this comment

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

Again, zero is probably not the best choice.

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 subhashers that the test uses don't use treeID

Copy link
Contributor

Choose a reason for hiding this comment

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

OK then as long as hashers that do use it have their own tests.

@@ -56,8 +56,10 @@ var splitTestVector = []struct {
var defaultLogStrata = []int{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}
var defaultMapStrata = []int{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 176}

const treeID = int64(0)
Copy link
Contributor

Choose a reason for hiding this comment

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

Another use of zero.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

same

@Martin2112
Copy link
Contributor

Martin2112 commented Jun 21, 2017 via email

@gdbelvin
Copy link
Contributor Author

I've implemented maskIndex PTAL.

@gdbelvin gdbelvin force-pushed the coniks branch 3 times, most recently from fc2a412 to 5b89ec0 Compare June 26, 2017 09:42
@gdbelvin
Copy link
Contributor Author

Rebased now that #694 has been merged. PTAL

@gdbelvin gdbelvin requested a review from daviddrysdale June 26, 2017 09:48
@gdbelvin gdbelvin force-pushed the coniks branch 3 times, most recently from 00dbf80 to e67184b Compare June 26, 2017 16:08
@vqhuy
Copy link

vqhuy commented Jun 26, 2017

Do you want to hash the treeID, as proposed at coniks-sys/coniks-go#177 (comment)?

}

// maskIndex returns index with only the left depth bits set.
// index must be of size m.Size() and 0 <= depth <= m.BitLen().
Copy link
Contributor

Choose a reason for hiding this comment

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

This could probably be an array. I think including an example in the comment would help here. Maybe also mention that it's only used for the last byte to explain the 0xff in position 0.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I would agree, but different hashers can have different sizes for their indexes, which makes using an array here difficult.

Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure what you mean. It's only used by maskIndex and it's indexed by byte position from 0-7.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ah, yes. -- referring to leftmask?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, leftmask, which should probably also be leftMask.

{index: h2b("FF00000000000000000000000000000000000000"), depth: 5, want: h2b("F800000000000000000000000000000000000000")},
{index: h2b("FF00000000000000000000000000000000000000"), depth: 6, want: h2b("FC00000000000000000000000000000000000000")},
{index: h2b("FF00000000000000000000000000000000000000"), depth: 7, want: h2b("FE00000000000000000000000000000000000000")},
{index: h2b("FF00000000000000000000000000000000000000"), depth: 8, want: h2b("FF00000000000000000000000000000000000000")},
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add a couple of test cases that are less uniform and show the mask being applied across byte boundaries etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Better?

Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure if github is showing me all the latest changes but I'd like to see a depth above 8.

// e.g. 1 -> 0000000000000000000000000000000000000001
func PaddedBytes(i *big.Int, size int) []byte {
b := i.Bytes()
ret := make([]byte, size)
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this work if there is no padding needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added at test for this.

i int64
want []byte
}{
{i: 1, want: h2b("0000000000000000000000000000000000000001")},
Copy link
Contributor

Choose a reason for hiding this comment

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

This would be a good place to add the test for zero padding + possibly others.

Copy link
Contributor Author

@gdbelvin gdbelvin Jun 27, 2017

Choose a reason for hiding this comment

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

yep

@@ -24,6 +24,8 @@ import (
"github.com/google/trillian/merkle/rfc6962"
)

const treeID = int64(0)
Copy link
Contributor

Choose a reason for hiding this comment

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

OK then as long as hashers that do use it have their own tests.

@@ -29,6 +29,7 @@ import (
"github.com/google/trillian/crypto/keys"
"github.com/google/trillian/extension"
_ "github.com/google/trillian/merkle/objhasher" // Load hashers
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 think you need the comments on these imports + in other files. The '_' implies it's being imported for side effects.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

go vet sometimes complains if there isn't a comment on underscore imports.

gdbelvin added 3 commits June 27, 2017 15:47
Add treeID, index, and depth to HashLeaf and HashEmtpy.
Fuffills the security requirements in google#670.
@gdbelvin
Copy link
Contributor Author

Added more tests. PTAL

@gdbelvin gdbelvin merged commit 492f275 into google:master Jun 27, 2017
@gdbelvin gdbelvin deleted the coniks branch June 27, 2017 15:24
@gdbelvin gdbelvin mentioned this pull request Jul 7, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Map: CONIKS map hasher
4 participants