This repository has been archived by the owner on Nov 21, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Working commit of Nimbus bridge implementation
- Loading branch information
Pedro Pombeiro
committed
Oct 28, 2019
1 parent
1a6c399
commit 30d6fa5
Showing
10 changed files
with
571 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package nimbusbridge | ||
|
||
// https://golang.org/cmd/cgo/ | ||
|
||
/* | ||
#include <stddef.h> | ||
#include <stdbool.h> | ||
#include <stdlib.h> | ||
#include <libnim.h> | ||
*/ | ||
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 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
#include <stdint.h> | ||
#include <stddef.h> | ||
|
||
#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__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
package nimbusbridge | ||
|
||
// https://golang.org/cmd/cgo/ | ||
|
||
/* | ||
#include <stddef.h> | ||
#include <stdbool.h> | ||
#include <stdlib.h> | ||
#include <libnim.h> | ||
*/ | ||
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)) | ||
} |
Oops, something went wrong.