From 30d6fa586237a1cb1a5f4fe8aedabee1a41290fb Mon Sep 17 00:00:00 2001 From: Pedro Pombeiro Date: Mon, 14 Oct 2019 12:19:56 +0200 Subject: [PATCH] Working commit of Nimbus bridge implementation --- bridge/geth/filter.go | 9 +- bridge/geth/whisper.go | 21 ++- bridge/nimbus/filter.go | 84 +++++++++ bridge/nimbus/libnim.h | 66 +++++++ bridge/nimbus/public_whisper_api.go | 143 ++++++++++++++++ bridge/nimbus/whisper.go | 246 +++++++++++++++++++++++++++ transport/whisper/filter.go | 8 +- transport/whisper/types/envelopes.go | 5 + transport/whisper/types/filter.go | 1 + transport/whisper/types/whisper.go | 4 +- 10 files changed, 571 insertions(+), 16 deletions(-) create mode 100644 bridge/nimbus/filter.go create mode 100644 bridge/nimbus/libnim.h create mode 100644 bridge/nimbus/public_whisper_api.go create mode 100644 bridge/nimbus/whisper.go diff --git a/bridge/geth/filter.go b/bridge/geth/filter.go index 413c1fd..2579258 100644 --- a/bridge/geth/filter.go +++ b/bridge/geth/filter.go @@ -9,16 +9,18 @@ import ( type gethFilterWrapper struct { filter *whisper.Filter + id string } // NewGethFilterWrapper returns an object that wraps Geth's Filter in a whispertypes interface -func NewGethFilterWrapper(f *whisper.Filter) whispertypes.Filter { +func NewGethFilterWrapper(f *whisper.Filter, id string) whispertypes.Filter { if f.Messages == nil { panic("Messages should not be nil") } return &gethFilterWrapper{ filter: f, + id: id, } } @@ -27,6 +29,11 @@ func GetGethFilterFrom(f whispertypes.Filter) *whisper.Filter { return f.(*gethFilterWrapper).filter } +// ID returns the filter ID +func (w *gethFilterWrapper) ID() string { + return w.id +} + // KeyAsym returns the private Key of recipient func (w *gethFilterWrapper) KeyAsym() *ecdsa.PrivateKey { return w.filter.KeyAsym diff --git a/bridge/geth/whisper.go b/bridge/geth/whisper.go index 6ba2bb0..b0baa9d 100644 --- a/bridge/geth/whisper.go +++ b/bridge/geth/whisper.go @@ -108,20 +108,29 @@ func (w *gethWhisperWrapper) GetSymKey(id string) ([]byte, error) { return w.whisper.GetSymKey(id) } -func (w *gethWhisperWrapper) Subscribe(f whispertypes.Filter) (string, error) { - return w.whisper.Subscribe(GetGethFilterFrom(f)) +func (w *gethWhisperWrapper) Subscribe(keyAsym *ecdsa.PrivateKey, keySym []byte, pow float64, topics [][]byte) (string, error) { + f, err := w.createFilterWrapper("", keyAsym, keySym, pow, topics) + if err != nil { + return "", err + } + + id, err := w.whisper.Subscribe(GetGethFilterFrom(f)) + if err != nil { + return "", err + } + + f.(*gethFilterWrapper).id = id + return id, nil } func (w *gethWhisperWrapper) GetFilter(id string) whispertypes.Filter { - return NewGethFilterWrapper(w.whisper.GetFilter(id)) + return NewGethFilterWrapper(w.whisper.GetFilter(id), id) } func (w *gethWhisperWrapper) Unsubscribe(id string) error { return w.whisper.Unsubscribe(id) } -func (w *gethWhisperWrapper) createFilterWrapper(id string, keyAsym *ecdsa.PrivateKey, keySym []byte, pow float64, topics [][]byte, messages whispertypes.MessageStore) (whispertypes.Filter, error) { -func (w *gethWhisperWrapper) CreateFilterWrapper(keyAsym *ecdsa.PrivateKey, keySym []byte, pow float64, topics [][]byte, messages whispertypes.MessageStore) whispertypes.Filter { func (w *gethWhisperWrapper) createFilterWrapper(id string, keyAsym *ecdsa.PrivateKey, keySym []byte, pow float64, topics [][]byte) (whispertypes.Filter, error) { return NewGethFilterWrapper(&whisper.Filter{ KeyAsym: keyAsym, @@ -130,7 +139,7 @@ func (w *gethWhisperWrapper) createFilterWrapper(id string, keyAsym *ecdsa.Priva AllowP2P: true, Topics: topics, Messages: whisper.NewMemoryMessageStore(), - }) + }, id), nil } // RequestHistoricMessages sends a message with p2pRequestCode to a specific peer, diff --git a/bridge/nimbus/filter.go b/bridge/nimbus/filter.go new file mode 100644 index 0000000..1fff698 --- /dev/null +++ b/bridge/nimbus/filter.go @@ -0,0 +1,84 @@ +package nimbusbridge + +// https://golang.org/cmd/cgo/ + +/* +#include +#include +#include +#include +*/ +import "C" + +import ( + "crypto/ecdsa" + "unsafe" + + "github.com/ethereum/go-ethereum/crypto" + whispertypes "github.com/status-im/status-protocol-go/transport/whisper/types" +) + +type nimbusFilterWrapper struct { + filter *C.filter + id string + own bool + pk *ecdsa.PrivateKey + keySym [whispertypes.AesKeyLength]byte +} + +// NewNimbusFilterWrapper returns an object that wraps Nimbus's Filter in a whispertypes interface +func NewNimbusFilterWrapper(f *C.filter, id string, own bool) whispertypes.Filter { + key, err := crypto.HexToECDSA(C.GoString(f.keyAsymHex)) + if err != nil { + panic(err) + } + + wrapper := &nimbusFilterWrapper{ + filter: f, + id: id, + own: own, + pk: key, + } + copy(wrapper.keySym[:], C.GoBytes(unsafe.Pointer(f.keySym), whispertypes.AesKeyLength)) + return wrapper +} + +// GetNimbusFilterFrom retrieves the underlying whisper Filter struct from a wrapped Filter interface +func GetNimbusFilterFrom(f whispertypes.Filter) *C.filter { + return f.(*nimbusFilterWrapper).filter +} + +// ID returns the filter ID +func (w *nimbusFilterWrapper) ID() string { + return w.id +} + +// KeyAsym returns the private Key of recipient +func (w *nimbusFilterWrapper) KeyAsym() *ecdsa.PrivateKey { + return w.pk +} + +// KeySym returns the key associated with the Topic +func (w *nimbusFilterWrapper) KeySym() []byte { + return w.keySym[:] +} + +// Free frees the C memory associated with the filter +func (w *nimbusFilterWrapper) Free() { + if !w.own { + panic("native filter is not owned by Go") + } + + if w.filter.topic != nil { + C.free(unsafe.Pointer(w.filter.topic)) + w.filter.topic = nil + } + if w.filter.keyAsymHex != nil { + C.free(unsafe.Pointer(w.filter.keyAsymHex)) + w.filter.keyAsymHex = nil + } + if w.filter.keySym != nil { + C.free(unsafe.Pointer(w.filter.keySym)) + w.filter.keySym = nil + } +} diff --git a/bridge/nimbus/libnim.h b/bridge/nimbus/libnim.h new file mode 100644 index 0000000..1c53268 --- /dev/null +++ b/bridge/nimbus/libnim.h @@ -0,0 +1,66 @@ +#include +#include + +#pragma once + +#ifndef __LIBNIM_H__ +#define __LIBNIM_H__ + +typedef struct { + uint8_t* decoded; + size_t decodedLen; + uint32_t timestamp; + uint32_t ttl; + uint8_t topic[4]; + double pow; + uint8_t hash[32]; +} received_message; + +typedef struct { + const char* keyAsymHex; + const uint8_t* keySym; + double pow; + bool allowP2P; + const uint8_t* topic; +} filter; + +typedef struct { + uint8_t* sig; // Public key who signed this message. + uint8_t* recipientPublicKey; // The recipients public key. + uint32_t ttl; // Time-to-live in seconds. + uint32_t timestamp; // Unix timestamp of the message generation. + uint8_t topic[4]; // 4 Bytes: Message topic. + uint8_t* payload; // Decrypted payload. + uint32_t payloadLength; // Decrypted payload length. + uint8_t* padding; // (Optional) Padding (byte array of arbitrary length). + double pow; // Proof of work value. + uint8_t* hash; // Hash of the enveloped message. +} whisperfiltermessage; + + +typedef void (*received_msg_handler)(const received_message* msg); +// void nimbus_start(uint16_t port); +// void nimbus_poll(); +// void NimMain(); +const char* nimbus_post(const char* payload); +// void nimbus_subscribe(const char* channel, received_msg_handler msg); +// void nimbus_add_peer(const char* nodeId); + +double nimbus_get_min_pow(); +void nimbus_get_bloom_filter(uint8_t* pBloomFilter); + +const char* nimbus_add_keypair(const char* pszHexPK); +bool nimbus_delete_keypair(const char* pszID); +const char* nimbus_get_private_key(const char* pszID); + +const char* nimbus_add_symkey_direct(const uint8_t* pSymKey); +const char* nimbus_add_symkey_from_password(const char* pszPassword); +bool nimbus_get_symkey(const char* pszID, uint8_t* pSymKey); +bool nimbus_delete_symkey(const char* pszID); + +const char* nimbus_subscribe_filter(const filter* pcFilter, received_msg_handler msg); +const filter* nimbus_get_filter(const char* pszID); +bool nimbus_unsubscribe_filter(const char* pszID); +whisperfiltermessage* nimbus_getfiltermessages(const char* pszID, uint32_t* count); + +#endif // __LIBNIM_H__ diff --git a/bridge/nimbus/public_whisper_api.go b/bridge/nimbus/public_whisper_api.go new file mode 100644 index 0000000..1b17d29 --- /dev/null +++ b/bridge/nimbus/public_whisper_api.go @@ -0,0 +1,143 @@ +package nimbusbridge + +// https://golang.org/cmd/cgo/ + +/* +#include +#include +#include +#include +*/ +import "C" + +import ( + "context" + "encoding/hex" + "errors" + "unsafe" + + whispertypes "github.com/status-im/status-protocol-go/transport/whisper/types" + statusproto "github.com/status-im/status-protocol-go/types" +) + +type nimbusPublicWhisperAPIWrapper struct { +} + +// NewNimbusPublicWhisperAPIWrapper returns an object that wraps Nimbus's PublicWhisperAPI in a whispertypes interface +func NewNimbusPublicWhisperAPIWrapper() whispertypes.PublicWhisperAPI { + return &nimbusPublicWhisperAPIWrapper{} +} + +// AddPrivateKey imports the given private key. +func (w *nimbusPublicWhisperAPIWrapper) AddPrivateKey(ctx context.Context, privateKey statusproto.HexBytes) (string, error) { + privKeyHexC := C.CString(statusproto.EncodeHex(privateKey)) + defer C.free(unsafe.Pointer(privKeyHexC)) + + idC := C.nimbus_add_keypair(privKeyHexC) + if idC == nil { + return "", errors.New("failed to add private key to Nimbus") + } + + return C.GoString(idC), nil +} + +// GenerateSymKeyFromPassword derives a key from the given password, stores it, and returns its ID. +func (w *nimbusPublicWhisperAPIWrapper) GenerateSymKeyFromPassword(ctx context.Context, passwd string) (string, error) { + passwordC := C.CString(passwd) + defer C.free(unsafe.Pointer(passwordC)) + + idC := C.nimbus_add_symkey_from_password(passwordC) + if idC == nil { + return "", errors.New("failed to add symkey to Nimbus") + } + + return C.GoString(idC), nil +} + +// DeleteKeyPair removes the key with the given key if it exists. +func (w *nimbusPublicWhisperAPIWrapper) DeleteKeyPair(ctx context.Context, key string) (bool, error) { + keyC := C.CString(key) + defer C.free(unsafe.Pointer(keyC)) + + return bool(C.nimbus_delete_keypair(keyC)), nil +} + +// NewMessageFilter creates a new filter that can be used to poll for +// (new) messages that satisfy the given criteria. +func (w *nimbusPublicWhisperAPIWrapper) NewMessageFilter(req whispertypes.Criteria) (string, error) { + // topics := make([]whisper.TopicType, len(req.Topics)) + // for index, tt := range req.Topics { + // topics[index] = whisper.TopicType(tt) + // } + + // criteria := whisper.Criteria{ + // SymKeyID: req.SymKeyID, + // PrivateKeyID: req.PrivateKeyID, + // Sig: req.Sig, + // MinPow: req.MinPow, + // Topics: topics, + // AllowP2P: req.AllowP2P, + // } + // return w.publicWhisperAPI.NewMessageFilter(criteria) + // TODO + return "", errors.New("not implemented") +} + +// GetFilterMessages returns the messages that match the filter criteria and +// are received between the last poll and now. +func (w *nimbusPublicWhisperAPIWrapper) GetFilterMessages(id string) ([]*whispertypes.Message, error) { + var count uint + var msgs *C.whisperfiltermessage + idC := C.CString(id) + defer C.free(unsafe.Pointer(idC)) + msgs = C.nimbus_getfiltermessages(idC, (*C.uint)(unsafe.Pointer(&count))) + if msgs == nil { + return nil, errors.New("failed to retrieve filter messages from Nimbus") + } + + wrappedMsgs := make([]*whispertypes.Message, count) + index := uint(0) + for index < count { + msg := (*C.whisperfiltermessage)(unsafe.Pointer(uintptr(unsafe.Pointer(msgs)) + unsafe.Sizeof(*msgs))) + topic := whispertypes.TopicType{} + copy(topic[:], C.GoBytes(unsafe.Pointer(&msg.topic[0]), whispertypes.TopicLength)[:whispertypes.TopicLength]) + wrappedMsgs[index] = &whispertypes.Message{ + Sig: C.GoBytes(unsafe.Pointer(msg.sig), whispertypes.AesKeyLength), + TTL: uint32(msg.ttl), + Timestamp: uint32(msg.timestamp), + Topic: topic, + Payload: C.GoBytes(unsafe.Pointer(msg.payload), C.int(msg.payloadLength)), + Padding: C.GoBytes(unsafe.Pointer(msg.padding), whispertypes.AesKeyLength), + PoW: float64(msg.pow), + Hash: C.GoBytes(unsafe.Pointer(msg.hash), statusproto.HashLength), + Dst: C.GoBytes(unsafe.Pointer(msg.recipientPublicKey), whispertypes.AesKeyLength), + P2P: true, + } + } + return wrappedMsgs, nil +} + +// Post posts a message on the Whisper network. +// returns the hash of the message in case of success. +func (w *nimbusPublicWhisperAPIWrapper) Post(ctx context.Context, req whispertypes.NewMessage) ([]byte, error) { + // msg := whisper.NewMessage{ + // SymKeyID: req.SymKeyID, + // PublicKey: req.PublicKey, + // Sig: req.Sig, + // TTL: req.TTL, + // Topic: whisper.TopicType(req.Topic), + // Payload: req.Payload, + // Padding: req.Padding, + // PowTime: req.PowTime, + // PowTarget: req.PowTarget, + // TargetPeer: req.TargetPeer, + // } + payloadC := C.CBytes(req.Payload) + defer C.free(unsafe.Pointer(payloadC)) + + hashC := C.nimbus_post((*C.char)(payloadC)) + if hashC == nil { + return nil, errors.New("Nimbus failed to post message") + } + return hex.DecodeString(C.GoString(hashC)) +} diff --git a/bridge/nimbus/whisper.go b/bridge/nimbus/whisper.go new file mode 100644 index 0000000..9d7481e --- /dev/null +++ b/bridge/nimbus/whisper.go @@ -0,0 +1,246 @@ +package nimbusbridge + +// https://golang.org/cmd/cgo/ + +/* +#include +#include +#include +#include +*/ +import "C" + +import ( + "crypto/ecdsa" + "encoding/hex" + "errors" + "time" + "unsafe" + + "github.com/ethereum/go-ethereum/crypto" + whispertypes "github.com/status-im/status-protocol-go/transport/whisper/types" +) + +type nimbusWhisperWrapper struct { + timesource func() time.Time + filters map[string]whispertypes.Filter +} + +// NewNimbusWhisperWrapper returns an object that wraps Nimbus' Whisper in a whispertypes interface +func NewNimbusWhisperWrapper() whispertypes.Whisper { + return &nimbusWhisperWrapper{ + timesource: func() time.Time { return time.Now() }, + filters: map[string]whispertypes.Filter{}, + } +} + +func (w *nimbusWhisperWrapper) PublicWhisperAPI() whispertypes.PublicWhisperAPI { + return NewNimbusPublicWhisperAPIWrapper() +} + +// MinPow returns the PoW value required by this node. +func (w *nimbusWhisperWrapper) MinPow() float64 { + return float64(C.nimbus_get_min_pow()) +} + +// BloomFilter returns the aggregated bloom filter for all the topics of interest. +// The nodes are required to send only messages that match the advertised bloom filter. +// If a message does not match the bloom, it will tantamount to spam, and the peer will +// be disconnected. +func (w *nimbusWhisperWrapper) BloomFilter() []byte { + // Allocate a buffer for Nimbus to return the bloom filter on + dataC := C.malloc(C.size_t(whispertypes.BloomFilterLength)) + defer C.free(unsafe.Pointer(dataC)) + + C.nimbus_get_bloom_filter((*C.uchar)(unsafe.Pointer(dataC))) + + // Move the returned data into a Go array + data := make([]byte, whispertypes.BloomFilterLength) + copy(data, C.GoBytes(dataC, whispertypes.BloomFilterLength)) + + return data +} + +// GetCurrentTime returns current time. +func (w *nimbusWhisperWrapper) GetCurrentTime() time.Time { + return w.timesource() +} + +// SetTimeSource assigns a particular source of time to a whisper object. +func (w *nimbusWhisperWrapper) SetTimeSource(timesource func() time.Time) { + w.timesource = timesource +} + +func (w *nimbusWhisperWrapper) SubscribeEnvelopeEvents(eventsProxy chan<- whispertypes.EnvelopeEvent) whispertypes.Subscription { + // TODO: when mailserver support is implemented + return nil + // events := make(chan whisper.EnvelopeEvent, 100) // must be buffered to prevent blocking whisper + // go func() { + // for e := range events { + // eventsProxy <- *NewNimbusEnvelopeEventWrapper(&e) + // } + // }() + + // return NewNimbusSubscriptionWrapper(w.whisper.SubscribeEnvelopeEvents(events)) +} + +// SelectedKeyPairID returns the id of currently selected key pair. +// It helps distinguish between different users w/o exposing the user identity itself. +func (w *nimbusWhisperWrapper) SelectedKeyPairID() string { + return "" +} + +func (w *nimbusWhisperWrapper) GetPrivateKey(id string) (*ecdsa.PrivateKey, error) { + idC := C.CString(id) + defer C.free(unsafe.Pointer(idC)) + + privKeyHexC := C.nimbus_get_private_key(idC) + return crypto.HexToECDSA(C.GoString(privKeyHexC)) +} + +// AddKeyPair imports a asymmetric private key and returns a deterministic identifier. +func (w *nimbusWhisperWrapper) AddKeyPair(key *ecdsa.PrivateKey) (string, error) { + privKeyHex := hex.EncodeToString(crypto.FromECDSA(key)) + privKeyHexC := C.CString(privKeyHex) + defer C.free(unsafe.Pointer(privKeyHexC)) + + idC := C.nimbus_add_keypair(privKeyHexC) + if idC == nil { + return "", errors.New("failed to add keypair to Nimbus") + } + + return C.GoString(idC), nil +} + +// DeleteKeyPair deletes the specified key if it exists. +func (w *nimbusWhisperWrapper) DeleteKeyPair(key string) bool { + keyC := C.CString(key) + defer C.free(unsafe.Pointer(keyC)) + + return bool(C.nimbus_delete_keypair(keyC)) +} + +// SelectKeyPair adds cryptographic identity, and makes sure +// that it is the only private key known to the node. +func (w *nimbusWhisperWrapper) SelectKeyPair(key *ecdsa.PrivateKey) error { + return errors.New("not implemented") +} + +func (w *nimbusWhisperWrapper) AddSymKeyDirect(key []byte) (string, error) { + keyC := C.CBytes(key) + defer C.free(unsafe.Pointer(keyC)) + + idC := C.nimbus_add_symkey_direct((*C.uchar)(unsafe.Pointer(keyC))) + if idC == nil { + return "", errors.New("failed to add symkey to Nimbus") + } + + return C.GoString(idC), nil +} + +func (w *nimbusWhisperWrapper) AddSymKeyFromPassword(password string) (string, error) { + passwordC := C.CString(password) + defer C.free(unsafe.Pointer(passwordC)) + + idC := C.nimbus_add_symkey_from_password(passwordC) + if idC == nil { + return "", errors.New("failed to add symkey to Nimbus") + } + + return C.GoString(idC), nil +} + +func (w *nimbusWhisperWrapper) DeleteSymKey(id string) bool { + idC := C.CString(id) + defer C.free(unsafe.Pointer(idC)) + + return bool(C.nimbus_delete_symkey(idC)) +} + +func (w *nimbusWhisperWrapper) GetSymKey(id string) ([]byte, error) { + idC := C.CString(id) + defer C.free(unsafe.Pointer(idC)) + + // Allocate a buffer for Nimbus to return the symkey on + dataC := C.malloc(C.size_t(whispertypes.AesKeyLength)) + defer C.free(unsafe.Pointer(dataC)) + if !C.nimbus_get_symkey(idC, (*C.uchar)(unsafe.Pointer(dataC))) { + return nil, errors.New("symkey not found") + } + + return C.GoBytes(dataC, whispertypes.AesKeyLength), nil +} + +func (w *nimbusWhisperWrapper) Subscribe(keyAsym *ecdsa.PrivateKey, keySym []byte, pow float64, topics [][]byte) (string, error) { + f, err := w.createFilterWrapper("", keyAsym, keySym, pow, topics) + if err != nil { + return "", err + } + + idC := C.nimbus_subscribe_filter(GetNimbusFilterFrom(f), nil) + if idC == nil { + return "", errors.New("failed to subscribe to filter in Nimbus") + } + + f.(*nimbusFilterWrapper).id = C.GoString(idC) + + return f.ID(), nil +} + +func (w *nimbusWhisperWrapper) GetFilter(id string) whispertypes.Filter { + idC := C.CString(id) + defer C.free(unsafe.Pointer(idC)) + + pFilter := C.nimbus_get_filter(idC) + return NewNimbusFilterWrapper(pFilter, id, false) +} + +func (w *nimbusWhisperWrapper) Unsubscribe(id string) error { + idC := C.CString(id) + defer C.free(unsafe.Pointer(idC)) + + if !C.nimbus_unsubscribe_filter(idC) { + return errors.New("filter not found") + } + + if f, ok := w.filters[id]; ok { + f.(*nimbusFilterWrapper).Free() + delete(w.filters, id) + } + + return nil +} + +func (w *nimbusWhisperWrapper) createFilterWrapper(id string, keyAsym *ecdsa.PrivateKey, keySym []byte, pow float64, topics [][]byte) (whispertypes.Filter, error) { + if len(topics) != 1 { + return nil, errors.New("currently only 1 topic is supported by the Nimbus bridge") + } + + filter := C.filter{ + pow: C.double(pow), + allowP2P: true, + topic: (*C.uchar)(unsafe.Pointer(C.CBytes(topics[0]))), + } + if keyAsym != nil { + filter.keyAsymHex = C.CString(hex.EncodeToString(crypto.FromECDSA(keyAsym))) + } + if keySym != nil { + filter.keySym = (*C.uchar)(unsafe.Pointer(C.CBytes(keySym))) + } + + return NewNimbusFilterWrapper(&filter, id, true), nil +} + +// RequestHistoricMessages sends a message with p2pRequestCode to a specific peer, +// which is known to implement MailServer interface, and is supposed to process this +// request and respond with a number of peer-to-peer messages (possibly expired), +// which are not supposed to be forwarded any further. +// The whisper protocol is agnostic of the format and contents of envelope. +func (w *nimbusWhisperWrapper) RequestHistoricMessagesWithTimeout(peerID []byte, envelope whispertypes.Envelope, timeout time.Duration) error { + return errors.New("not implemented") +} + +// SyncMessages can be sent between two Mail Servers and syncs envelopes between them. +func (w *nimbusWhisperWrapper) SyncMessages(peerID []byte, req whispertypes.SyncMailRequest) error { + return errors.New("not implemented") +} diff --git a/transport/whisper/filter.go b/transport/whisper/filter.go index 3d83c34..4482069 100644 --- a/transport/whisper/filter.go +++ b/transport/whisper/filter.go @@ -478,12 +478,10 @@ func (s *filtersManager) addSymmetric(chatID string) (*whisperFilter, error) { } } - f := s.whisper.CreateFilterWrapper( + id, err := s.whisper.Subscribe( nil, symKey, minPow, topics) - - id, err := s.whisper.Subscribe(f) if err != nil { return nil, err } @@ -510,12 +508,10 @@ func (s *filtersManager) addAsymmetric(chatID string, listen bool) (*whisperFilt topic := toTopic(chatID) topics := [][]byte{topic} - f := s.whisper.CreateFilterWrapper( + id, err := s.whisper.Subscribe( s.privateKey, nil, pow, topics) - - id, err := s.whisper.Subscribe(f) if err != nil { return nil, err } diff --git a/transport/whisper/types/envelopes.go b/transport/whisper/types/envelopes.go index ed503aa..8cc96c0 100644 --- a/transport/whisper/types/envelopes.go +++ b/transport/whisper/types/envelopes.go @@ -2,6 +2,11 @@ package whispertypes import statusproto "github.com/status-im/status-protocol-go/types" +const ( + AesKeyLength = 32 // in bytes + BloomFilterLength = 64 // in bytes +) + // Envelope represents a clear-text data packet to transmit through the Whisper // network. Its contents may or may not be encrypted and signed. type Envelope interface { diff --git a/transport/whisper/types/filter.go b/transport/whisper/types/filter.go index a4d11a3..14d2ad9 100644 --- a/transport/whisper/types/filter.go +++ b/transport/whisper/types/filter.go @@ -6,6 +6,7 @@ import ( // Filter represents a Whisper message filter type Filter interface { + ID() string KeyAsym() *ecdsa.PrivateKey // Private Key of recipient KeySym() []byte // Key associated with the Topic } diff --git a/transport/whisper/types/whisper.go b/transport/whisper/types/whisper.go index e3f5603..5bb9b82 100644 --- a/transport/whisper/types/whisper.go +++ b/transport/whisper/types/whisper.go @@ -42,12 +42,10 @@ type Whisper interface { DeleteSymKey(id string) bool GetSymKey(id string) ([]byte, error) - Subscribe(f Filter) (string, error) + Subscribe(keyAsym *ecdsa.PrivateKey, keySym []byte, pow float64, topics [][]byte) (string, error) GetFilter(id string) Filter Unsubscribe(id string) error - CreateFilterWrapper(keyAsym *ecdsa.PrivateKey, keySym []byte, pow float64, topics [][]byte) Filter - // RequestHistoricMessages sends a message with p2pRequestCode to a specific peer, // which is known to implement MailServer interface, and is supposed to process this // request and respond with a number of peer-to-peer messages (possibly expired),