From 4294802a4aa4ffcd867dbdff2a92033a2fbf0d43 Mon Sep 17 00:00:00 2001 From: avichalp Date: Fri, 1 Dec 2023 22:52:43 +0800 Subject: [PATCH] Change hashing scheme to ECMH Signed-off-by: avichalp --- internal/app/uploader.go | 13 +++++------- pkg/basinprovider/provider_test.go | 25 +++++++++++++++++++--- pkg/ecmh/ecmh.go | 33 +++++++++++++++++------------- pkg/ecmh/ecmh_test.go | 21 +++++-------------- 4 files changed, 51 insertions(+), 41 deletions(-) diff --git a/internal/app/uploader.go b/internal/app/uploader.go index a231154..6bb878d 100644 --- a/internal/app/uploader.go +++ b/internal/app/uploader.go @@ -7,9 +7,8 @@ import ( "io" "os" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" - "golang.org/x/crypto/sha3" + "github.com/tablelandnetwork/basin-cli/pkg/ecmh" ) // BasinProviderUploader ... @@ -63,28 +62,26 @@ func (bu *BasinUploader) Upload(ctx context.Context, filepath string, progress i // Signer allows you to sign a big stream of bytes by calling Sum multiple times, then Sign. type Signer struct { - state crypto.KeccakState + state *ecmh.MultisetHash privateKey *ecdsa.PrivateKey } // NewSigner creates a new signer. func NewSigner(pk *ecdsa.PrivateKey) *Signer { return &Signer{ - state: sha3.NewLegacyKeccak256().(crypto.KeccakState), + state: ecmh.NewMultisetHash(), privateKey: pk, } } // Sum updates the hash state with a new chunk. func (s *Signer) Sum(chunk []byte) { - s.state.Write(chunk) + s.state.Insert(chunk) } // Sign signs the internal state. func (s *Signer) Sign() ([]byte, error) { - var h common.Hash - _, _ = s.state.Read(h[:]) - signature, err := crypto.Sign(h.Bytes(), s.privateKey) + signature, err := crypto.Sign(s.state.Bytes(), s.privateKey) if err != nil { return []byte{}, fmt.Errorf("sign: %s", err) } diff --git a/pkg/basinprovider/provider_test.go b/pkg/basinprovider/provider_test.go index 860164c..b753df4 100644 --- a/pkg/basinprovider/provider_test.go +++ b/pkg/basinprovider/provider_test.go @@ -15,6 +15,7 @@ import ( "github.com/stretchr/testify/require" "github.com/tablelandnetwork/basin-cli/internal/app" basincapnp "github.com/tablelandnetwork/basin-cli/pkg/capnp" + "github.com/tablelandnetwork/basin-cli/pkg/ecmh" "google.golang.org/grpc/test/bufconn" ) @@ -61,7 +62,13 @@ func TestBasinProvider_Upload(t *testing.T) { ) require.NoError(t, err) require.Equal(t, filedata1, server.uploads["test.test"][0].bytes) - require.Equal(t, "801fb03a3a34fd9d3ac5445f693df74c822d2e8cfa736191e7919e099931d8a51cd0a62fc67da6d8f0aab4302c18aa0cf381c973a8817b7062805f19d03f88ce00", hex.EncodeToString(server.uploads["test.test"][0].sig)) // nolint + require.Equal(t, "1e75e243758ec30e3bbdfa3c48ec5d1f25eccae3e19b81372b5bb18fff70baed5b16436c07b2cf8963b14657b282ee7675efec88feb0c0b934508fd38be1b48f00", hex.EncodeToString(server.uploads["test.test"][0].sig)) // nolint + + // verify signature + h := ecmh.NewMultisetHash() + h.Insert([]byte("hello")) + pubKey := crypto.PubkeyToAddress(privateKey.PublicKey) + crypto.VerifySignature(pubKey.Bytes(), h.Bytes(), server.uploads["test.test"][0].sig) } // Upload data 2 on test2.test2 @@ -71,7 +78,13 @@ func TestBasinProvider_Upload(t *testing.T) { err := client.Upload(context.Background(), "test2", "test2", uint64(5), buf, app.NewSigner(privateKey), bytes.NewBuffer([]byte{}), app.Timestamp{}) // nolint require.NoError(t, err) require.Equal(t, filedata2, server.uploads["test2.test2"][0].bytes) - require.Equal(t, "3ad572a3483971285f3c6dc0e71d234a58543876f98b23183dc4e60008c1a92310f42202858b48ad917588535c2234c85413e124a2dcdd0759df9c555a9f585901", hex.EncodeToString(server.uploads["test2.test2"][0].sig)) // nolint + require.Equal(t, "f58c418ba46fececdd48b7979ca29bc2d200836f2f750e449d67d8c62e23a91a0bfcfbba35773da844bf6afed21cb689ea2b836ee4c88abf15831e6202734fa301", hex.EncodeToString(server.uploads["test2.test2"][0].sig)) // nolint + + // verify signature + h := ecmh.NewMultisetHash() + h.Insert([]byte("World")) + pubKey := crypto.PubkeyToAddress(privateKey.PublicKey) + crypto.VerifySignature(pubKey.Bytes(), h.Bytes(), server.uploads["test2.test2"][0].sig) } // Upload data 3 on test.test @@ -81,7 +94,13 @@ func TestBasinProvider_Upload(t *testing.T) { err := client.Upload(context.Background(), "test", "test", uint64(5), buf, app.NewSigner(privateKey), bytes.NewBuffer([]byte{}), app.Timestamp{}) // nolint require.NoError(t, err) require.Equal(t, filedata3, server.uploads["test.test"][1].bytes) - require.Equal(t, "94dcba2012dd83edf1e379bbdc640e95321ea30d5318e1f5dfd46154603bba4970729b44a71844e3f4e07955dfb529ccf60d31b74a9971649d64fd8c12a32a7d00", hex.EncodeToString(server.uploads["test.test"][1].sig)) // nolint + require.Equal(t, "b0e5f145193a3a53da3cab406058037e96079630c120bd2faa59b545b29c7c060bfc53d7c86b222491d59e361d812c6a36b7f0372abf2bffd0e02aee1c8a731201", hex.EncodeToString(server.uploads["test.test"][1].sig)) // nolint + + // verify signature + h := ecmh.NewMultisetHash() + h.Insert([]byte("WORLD")) + pubKey := crypto.PubkeyToAddress(privateKey.PublicKey) + crypto.VerifySignature(pubKey.Bytes(), h.Bytes(), server.uploads["test.test"][1].sig) } // check latest 2 deals for test2.test2, should return filedata2 diff --git a/pkg/ecmh/ecmh.go b/pkg/ecmh/ecmh.go index c9c6cb6..c2ce29b 100644 --- a/pkg/ecmh/ecmh.go +++ b/pkg/ecmh/ecmh.go @@ -11,9 +11,7 @@ type MultisetHash struct { // NewMultisetHash creates a new multiset hash. func NewMultisetHash() *MultisetHash { p := ristretto.Point{} - // shoud we use SetZero() here? base is the generator - // point - p.SetBase() + p.SetZero() return &MultisetHash{ accumulator: &p, @@ -25,14 +23,20 @@ func (h *MultisetHash) String() string { return h.accumulator.String() } -// Insert inserts a new item (point) into the multiset hash. -func (h *MultisetHash) Insert(p *ristretto.Point) { - h.accumulator.Add(h.accumulator, p) +// Bytes returns the byte representation of the multiset hash. +func (h *MultisetHash) Bytes() []byte { + return h.accumulator.Bytes() } -// InsertAll inserts all items (points) into the multiset hash. -func (h *MultisetHash) InsertAll(ps []*ristretto.Point) { - for _, item := range ps { +// Insert inserts a new item (byte array) into the multiset hash. +func (h *MultisetHash) Insert(item []byte) { + p := ristretto.Point{} + h.accumulator.Add(h.accumulator, p.DeriveDalek(item)) +} + +// InsertAll inserts all items into the multiset hash. +func (h *MultisetHash) InsertAll(items [][]byte) { + for _, item := range items { h.Insert(item) } } @@ -47,14 +51,15 @@ func (h *MultisetHash) Difference(other *MultisetHash) { h.accumulator.Sub(h.accumulator, other.accumulator) } -// Remove removes an item (point) from the multiset hash. -func (h *MultisetHash) Remove(p *ristretto.Point) { - h.accumulator.Sub(h.accumulator, p) +// Remove removes an item (byte array) from the multiset hash. +func (h *MultisetHash) Remove(item []byte) { + p := ristretto.Point{} + h.accumulator.Sub(h.accumulator, p.DeriveDalek(item)) } // RemoveAll removes all items (points) from the multiset hash. -func (h *MultisetHash) RemoveAll(ps []*ristretto.Point) { - for _, item := range ps { +func (h *MultisetHash) RemoveAll(items [][]byte) { + for _, item := range items { h.Remove(item) } } diff --git a/pkg/ecmh/ecmh_test.go b/pkg/ecmh/ecmh_test.go index 42bf5bb..ce420a1 100644 --- a/pkg/ecmh/ecmh_test.go +++ b/pkg/ecmh/ecmh_test.go @@ -1,10 +1,8 @@ package ecmh import ( - "fmt" "testing" - "github.com/bwesterb/go-ristretto" "github.com/stretchr/testify/require" // Register duckdb driver. @@ -25,21 +23,15 @@ func TestECMHInsertRemove(t *testing.T) { for _, tc := range testCases { currentHash := NewMultisetHash() for _, item := range tc.items { - newItem := ristretto.Point{} - currentHash.Insert(newItem.DeriveDalek([]byte(item))) + currentHash.Insert([]byte(item)) } cr1 := currentHash.String() - fmt.Println("cr1", cr1) // check if item is in the set? - newItem := ristretto.Point{} - currentHash.Remove(newItem.DeriveDalek([]byte(tc.items[0]))) - cr2 := currentHash.String() - fmt.Println("cr2", cr2) + currentHash.Remove([]byte(tc.items[0])) - currentHash.Insert(newItem.DeriveDalek([]byte(tc.items[0]))) + currentHash.Insert([]byte(tc.items[0])) cr3 := currentHash.String() - fmt.Println("cr3", cr3) require.Equal(t, cr1, cr3) } } @@ -61,14 +53,12 @@ func TestECMHUnionDiff(t *testing.T) { for _, tc := range testCases { currentHash1 := NewMultisetHash() for _, item := range tc.items1 { - newItem := ristretto.Point{} - currentHash1.Insert(newItem.DeriveDalek([]byte(item))) + currentHash1.Insert([]byte(item)) } currentHash2 := NewMultisetHash() for _, item := range tc.items2 { - newItem := ristretto.Point{} - currentHash2.Insert(newItem.DeriveDalek([]byte(item))) + currentHash2.Insert([]byte(item)) } currentHash1.Union(currentHash2) @@ -78,7 +68,6 @@ func TestECMHUnionDiff(t *testing.T) { currentHash1.Union(currentHash2) cr3 := currentHash1.String() - fmt.Println("cr3", cr3) require.Equal(t, cr1, cr3) } }