mirror of
https://github.com/status-im/go-waku.git
synced 2025-01-12 14:54:19 +00:00
feat: js-noise / go-noise interop
This commit is contained in:
parent
77ace0d772
commit
627fbbab6e
@ -125,7 +125,6 @@ require (
|
||||
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef // indirect
|
||||
github.com/waku-org/go-discover v0.0.0-20221209174356-61c833f34d98 // indirect
|
||||
github.com/waku-org/go-zerokit-rln v0.1.7-wakuorg // indirect
|
||||
github.com/waku-org/noise v1.0.2 // indirect
|
||||
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
|
@ -1435,7 +1435,7 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
@ -1481,8 +1481,6 @@ github.com/waku-org/go-discover v0.0.0-20221209174356-61c833f34d98 h1:xwY0kW5XZF
|
||||
github.com/waku-org/go-discover v0.0.0-20221209174356-61c833f34d98/go.mod h1:eBHgM6T4EG0RZzxpxKy+rGz/6Dw2Nd8DWxS0lm9ESDw=
|
||||
github.com/waku-org/go-zerokit-rln v0.1.7-wakuorg h1:2vVIBCtBih2w1K9ll8YnToTDZvbxcgbsClsPlJS/kkg=
|
||||
github.com/waku-org/go-zerokit-rln v0.1.7-wakuorg/go.mod h1:GlyaVeEWNEBxVJrWC6jFTvb4LNb9d9qnjdS6EiWVUvk=
|
||||
github.com/waku-org/noise v1.0.2 h1:7WmlhpJ0eliBzwzKz6SoTqQznaEU2IuebHF3oCekqqs=
|
||||
github.com/waku-org/noise v1.0.2/go.mod h1:emThr8WZLeAtKqFW+/nXfHn9VucuXTh8aHap03UXP84=
|
||||
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee h1:lYbXeSvJi5zk5GLKVuid9TVjS9a0OmLIDKTfoZBL6Ow=
|
||||
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg=
|
||||
github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"github.com/waku-org/go-waku/waku/v2/node"
|
||||
"github.com/waku-org/go-waku/waku/v2/payload"
|
||||
"github.com/waku-org/go-waku/waku/v2/protocol"
|
||||
"github.com/waku-org/go-waku/waku/v2/protocol/pb"
|
||||
"github.com/waku-org/go-waku/waku/v2/utils"
|
||||
@ -87,9 +88,9 @@ func write(ctx context.Context, wakuNode *node.WakuNode, msgContent string) {
|
||||
var version uint32 = 0
|
||||
var timestamp int64 = utils.GetUnixEpoch(wakuNode.Timesource())
|
||||
|
||||
p := new(node.Payload)
|
||||
p := new(payload.Payload)
|
||||
p.Data = []byte(wakuNode.ID() + ": " + msgContent)
|
||||
p.Key = &node.KeyInfo{Kind: node.None}
|
||||
p.Key = &payload.KeyInfo{Kind: payload.None}
|
||||
|
||||
payload, err := p.Encode(version)
|
||||
if err != nil {
|
||||
@ -125,7 +126,7 @@ func readLoop(ctx context.Context, wakuNode *node.WakuNode) {
|
||||
}
|
||||
|
||||
for value := range sub.C {
|
||||
payload, err := node.DecodePayload(value.Message(), &node.KeyInfo{Kind: node.None})
|
||||
payload, err := payload.DecodePayload(value.Message(), &payload.KeyInfo{Kind: payload.None})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
"github.com/waku-org/go-waku/waku/v2/dnsdisc"
|
||||
"github.com/waku-org/go-waku/waku/v2/node"
|
||||
"github.com/waku-org/go-waku/waku/v2/payload"
|
||||
"github.com/waku-org/go-waku/waku/v2/protocol"
|
||||
"github.com/waku-org/go-waku/waku/v2/protocol/filter"
|
||||
"github.com/waku-org/go-waku/waku/v2/protocol/lightpush"
|
||||
@ -261,18 +262,18 @@ func (c *Chat) publish(ctx context.Context, message string) error {
|
||||
|
||||
var version uint32
|
||||
var timestamp int64 = utils.GetUnixEpochFrom(c.node.Timesource().Now())
|
||||
var keyInfo *node.KeyInfo = &node.KeyInfo{}
|
||||
var keyInfo *payload.KeyInfo = &payload.KeyInfo{}
|
||||
|
||||
if c.options.UsePayloadV1 { // Use WakuV1 encryption
|
||||
keyInfo.Kind = node.Symmetric
|
||||
keyInfo.Kind = payload.Symmetric
|
||||
keyInfo.SymKey = generateSymKey(c.options.ContentTopic)
|
||||
version = 1
|
||||
} else {
|
||||
keyInfo.Kind = node.None
|
||||
keyInfo.Kind = payload.None
|
||||
version = 0
|
||||
}
|
||||
|
||||
p := new(node.Payload)
|
||||
p := new(payload.Payload)
|
||||
p.Data = msgBytes
|
||||
p.Key = keyInfo
|
||||
|
||||
@ -318,15 +319,15 @@ func (c *Chat) publish(ctx context.Context, message string) error {
|
||||
}
|
||||
|
||||
func decodeMessage(useV1Payload bool, contentTopic string, wakumsg *wpb.WakuMessage) (*pb.Chat2Message, error) {
|
||||
var keyInfo *node.KeyInfo = &node.KeyInfo{}
|
||||
var keyInfo *payload.KeyInfo = &payload.KeyInfo{}
|
||||
if useV1Payload { // Use WakuV1 encryption
|
||||
keyInfo.Kind = node.Symmetric
|
||||
keyInfo.Kind = payload.Symmetric
|
||||
keyInfo.SymKey = generateSymKey(contentTopic)
|
||||
} else {
|
||||
keyInfo.Kind = node.None
|
||||
keyInfo.Kind = payload.None
|
||||
}
|
||||
|
||||
payload, err := node.DecodePayload(wakumsg, keyInfo)
|
||||
payload, err := payload.DecodePayload(wakumsg, keyInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -142,7 +142,6 @@ require (
|
||||
github.com/tklauser/numcpus v0.2.2 // indirect
|
||||
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef // indirect
|
||||
github.com/waku-org/go-discover v0.0.0-20221209174356-61c833f34d98 // indirect
|
||||
github.com/waku-org/noise v1.0.2 // indirect
|
||||
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
|
@ -1470,7 +1470,7 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
@ -1518,8 +1518,6 @@ github.com/waku-org/go-discover v0.0.0-20221209174356-61c833f34d98 h1:xwY0kW5XZF
|
||||
github.com/waku-org/go-discover v0.0.0-20221209174356-61c833f34d98/go.mod h1:eBHgM6T4EG0RZzxpxKy+rGz/6Dw2Nd8DWxS0lm9ESDw=
|
||||
github.com/waku-org/go-zerokit-rln v0.1.7-wakuorg h1:2vVIBCtBih2w1K9ll8YnToTDZvbxcgbsClsPlJS/kkg=
|
||||
github.com/waku-org/go-zerokit-rln v0.1.7-wakuorg/go.mod h1:GlyaVeEWNEBxVJrWC6jFTvb4LNb9d9qnjdS6EiWVUvk=
|
||||
github.com/waku-org/noise v1.0.2 h1:7WmlhpJ0eliBzwzKz6SoTqQznaEU2IuebHF3oCekqqs=
|
||||
github.com/waku-org/noise v1.0.2/go.mod h1:emThr8WZLeAtKqFW+/nXfHn9VucuXTh8aHap03UXP84=
|
||||
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee h1:lYbXeSvJi5zk5GLKVuid9TVjS9a0OmLIDKTfoZBL6Ow=
|
||||
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg=
|
||||
github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||
|
@ -125,7 +125,6 @@ require (
|
||||
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef // indirect
|
||||
github.com/waku-org/go-discover v0.0.0-20221209174356-61c833f34d98 // indirect
|
||||
github.com/waku-org/go-zerokit-rln v0.1.7-wakuorg // indirect
|
||||
github.com/waku-org/noise v1.0.2 // indirect
|
||||
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
|
@ -1435,7 +1435,7 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
@ -1481,8 +1481,6 @@ github.com/waku-org/go-discover v0.0.0-20221209174356-61c833f34d98 h1:xwY0kW5XZF
|
||||
github.com/waku-org/go-discover v0.0.0-20221209174356-61c833f34d98/go.mod h1:eBHgM6T4EG0RZzxpxKy+rGz/6Dw2Nd8DWxS0lm9ESDw=
|
||||
github.com/waku-org/go-zerokit-rln v0.1.7-wakuorg h1:2vVIBCtBih2w1K9ll8YnToTDZvbxcgbsClsPlJS/kkg=
|
||||
github.com/waku-org/go-zerokit-rln v0.1.7-wakuorg/go.mod h1:GlyaVeEWNEBxVJrWC6jFTvb4LNb9d9qnjdS6EiWVUvk=
|
||||
github.com/waku-org/noise v1.0.2 h1:7WmlhpJ0eliBzwzKz6SoTqQznaEU2IuebHF3oCekqqs=
|
||||
github.com/waku-org/noise v1.0.2/go.mod h1:emThr8WZLeAtKqFW+/nXfHn9VucuXTh8aHap03UXP84=
|
||||
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee h1:lYbXeSvJi5zk5GLKVuid9TVjS9a0OmLIDKTfoZBL6Ow=
|
||||
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg=
|
||||
github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"github.com/waku-org/go-waku/waku/v2/node"
|
||||
"github.com/waku-org/go-waku/waku/v2/payload"
|
||||
"github.com/waku-org/go-waku/waku/v2/protocol"
|
||||
"github.com/waku-org/go-waku/waku/v2/protocol/filter"
|
||||
"github.com/waku-org/go-waku/waku/v2/protocol/pb"
|
||||
@ -145,9 +146,9 @@ func write(ctx context.Context, wakuNode *node.WakuNode, msgContent string) {
|
||||
var version uint32 = 0
|
||||
var timestamp int64 = utils.GetUnixEpoch(wakuNode.Timesource())
|
||||
|
||||
p := new(node.Payload)
|
||||
p := new(payload.Payload)
|
||||
p.Data = []byte(wakuNode.ID() + ": " + msgContent)
|
||||
p.Key = &node.KeyInfo{Kind: node.None}
|
||||
p.Key = &payload.KeyInfo{Kind: payload.None}
|
||||
|
||||
payload, _ := p.Encode(version)
|
||||
|
||||
@ -180,7 +181,7 @@ func readLoop(ctx context.Context, wakuNode *node.WakuNode) {
|
||||
}
|
||||
|
||||
for value := range sub.C {
|
||||
payload, err := node.DecodePayload(value.Message(), &node.KeyInfo{Kind: node.None})
|
||||
payload, err := payload.DecodePayload(value.Message(), &payload.KeyInfo{Kind: payload.None})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
|
6
examples/noise/Makefile
Normal file
6
examples/noise/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
.PHONY: all build
|
||||
|
||||
build:
|
||||
go build -o build/noise .
|
||||
|
||||
all: build
|
30
examples/noise/README.md
Normal file
30
examples/noise/README.md
Normal file
@ -0,0 +1,30 @@
|
||||
# Using the `noise` application
|
||||
|
||||
## Background
|
||||
|
||||
The `noise` application is an example that shows how to do pairing between js-waku and go-waku
|
||||
|
||||
## Preparation
|
||||
```
|
||||
make
|
||||
```
|
||||
|
||||
Also clone https://github.com/waku-org/js-noise and execute the following commands:
|
||||
```
|
||||
git clone https://github.com/waku-org/js-noise
|
||||
cd js-noise
|
||||
npm install
|
||||
npm run build
|
||||
cd example
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
|
||||
## Basic application usage
|
||||
|
||||
To start the `noise` application run the following from the project directory
|
||||
|
||||
```
|
||||
./build/noise
|
||||
```
|
||||
The app will display a QR and a link that will open the js-noise example in the browser. The handshake process will start afterwards
|
165
examples/noise/chat2.pb.go
Normal file
165
examples/noise/chat2.pb.go
Normal file
@ -0,0 +1,165 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.14.0
|
||||
// source: chat2.proto
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type Chat2Message struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Timestamp uint64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
|
||||
Nick string `protobuf:"bytes,2,opt,name=nick,proto3" json:"nick,omitempty"`
|
||||
Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Chat2Message) Reset() {
|
||||
*x = Chat2Message{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_chat2_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Chat2Message) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Chat2Message) ProtoMessage() {}
|
||||
|
||||
func (x *Chat2Message) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_chat2_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Chat2Message.ProtoReflect.Descriptor instead.
|
||||
func (*Chat2Message) Descriptor() ([]byte, []int) {
|
||||
return file_chat2_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *Chat2Message) GetTimestamp() uint64 {
|
||||
if x != nil {
|
||||
return x.Timestamp
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Chat2Message) GetNick() string {
|
||||
if x != nil {
|
||||
return x.Nick
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Chat2Message) GetPayload() []byte {
|
||||
if x != nil {
|
||||
return x.Payload
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_chat2_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_chat2_proto_rawDesc = []byte{
|
||||
0x0a, 0x0b, 0x63, 0x68, 0x61, 0x74, 0x32, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70,
|
||||
0x62, 0x22, 0x5a, 0x0a, 0x0c, 0x43, 0x68, 0x61, 0x74, 0x32, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
|
||||
0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12,
|
||||
0x12, 0x0a, 0x04, 0x6e, 0x69, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e,
|
||||
0x69, 0x63, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x62, 0x06, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_chat2_proto_rawDescOnce sync.Once
|
||||
file_chat2_proto_rawDescData = file_chat2_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_chat2_proto_rawDescGZIP() []byte {
|
||||
file_chat2_proto_rawDescOnce.Do(func() {
|
||||
file_chat2_proto_rawDescData = protoimpl.X.CompressGZIP(file_chat2_proto_rawDescData)
|
||||
})
|
||||
return file_chat2_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_chat2_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_chat2_proto_goTypes = []interface{}{
|
||||
(*Chat2Message)(nil), // 0: pb.Chat2Message
|
||||
}
|
||||
var file_chat2_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_chat2_proto_init() }
|
||||
func file_chat2_proto_init() {
|
||||
if File_chat2_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_chat2_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Chat2Message); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_chat2_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_chat2_proto_goTypes,
|
||||
DependencyIndexes: file_chat2_proto_depIdxs,
|
||||
MessageInfos: file_chat2_proto_msgTypes,
|
||||
}.Build()
|
||||
File_chat2_proto = out.File
|
||||
file_chat2_proto_rawDesc = nil
|
||||
file_chat2_proto_goTypes = nil
|
||||
file_chat2_proto_depIdxs = nil
|
||||
}
|
9
examples/noise/chat2.proto
Normal file
9
examples/noise/chat2.proto
Normal file
@ -0,0 +1,9 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package main;
|
||||
|
||||
message Chat2Message {
|
||||
uint64 timestamp = 1;
|
||||
string nick = 2;
|
||||
bytes payload = 3;
|
||||
}
|
147
examples/noise/go.mod
Normal file
147
examples/noise/go.mod
Normal file
@ -0,0 +1,147 @@
|
||||
module noise
|
||||
|
||||
go 1.18
|
||||
|
||||
replace github.com/waku-org/go-waku => ../..
|
||||
|
||||
replace github.com/ethereum/go-ethereum v1.10.25 => github.com/status-im/go-ethereum v1.10.4-status.2
|
||||
|
||||
require (
|
||||
github.com/ipfs/go-log/v2 v2.5.1
|
||||
github.com/multiformats/go-multiaddr v0.7.0
|
||||
github.com/waku-org/go-noise v0.0.4
|
||||
github.com/waku-org/go-waku v0.2.3-0.20221109195301-b2a5a68d28ba
|
||||
go.uber.org/zap v1.23.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect
|
||||
github.com/VictoriaMetrics/fastcache v1.6.0 // indirect
|
||||
github.com/beevik/ntp v0.3.0 // indirect
|
||||
github.com/benbjohnson/clock v1.3.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/btcsuite/btcd v0.20.1-beta // indirect
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.2.1 // indirect
|
||||
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/containerd/cgroups v1.0.4 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.4.0 // indirect
|
||||
github.com/cruxic/go-hmac-drbg v0.0.0-20170206035330-84c46983886d // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
|
||||
github.com/deckarep/golang-set v1.8.0 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/edsrzf/mmap-go v1.0.0 // indirect
|
||||
github.com/elastic/gosigar v0.14.2 // indirect
|
||||
github.com/ethereum/go-ethereum v1.10.25 // indirect
|
||||
github.com/flynn/noise v1.0.0 // indirect
|
||||
github.com/francoispqt/gojay v1.2.13 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect
|
||||
github.com/go-ole/go-ole v1.2.1 // indirect
|
||||
github.com/go-stack/stack v1.8.0 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-migrate/migrate/v4 v4.15.2 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/gopacket v1.1.19 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
|
||||
github.com/holiman/uint256 v1.2.0 // indirect
|
||||
github.com/huin/goupnp v1.0.3 // indirect
|
||||
github.com/ipfs/go-cid v0.3.2 // indirect
|
||||
github.com/ipfs/go-log v1.0.5 // indirect
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
|
||||
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
|
||||
github.com/karalabe/usb v0.0.2 // indirect
|
||||
github.com/klauspost/compress v1.15.10 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.1.1 // indirect
|
||||
github.com/koron/go-ssdp v0.0.3 // indirect
|
||||
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
|
||||
github.com/libp2p/go-cidranger v1.1.0 // indirect
|
||||
github.com/libp2p/go-flow-metrics v0.1.0 // indirect
|
||||
github.com/libp2p/go-libp2p v0.23.2 // indirect
|
||||
github.com/libp2p/go-libp2p-asn-util v0.2.0 // indirect
|
||||
github.com/libp2p/go-libp2p-pubsub v0.8.1 // indirect
|
||||
github.com/libp2p/go-mplex v0.7.0 // indirect
|
||||
github.com/libp2p/go-msgio v0.2.0 // indirect
|
||||
github.com/libp2p/go-nat v0.1.0 // indirect
|
||||
github.com/libp2p/go-netroute v0.2.0 // indirect
|
||||
github.com/libp2p/go-openssl v0.1.0 // indirect
|
||||
github.com/libp2p/go-reuseport v0.2.0 // indirect
|
||||
github.com/libp2p/go-yamux/v4 v4.0.0 // indirect
|
||||
github.com/lucas-clemente/quic-go v0.29.1 // indirect
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.2 // indirect
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.0 // indirect
|
||||
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
github.com/mattn/go-pointer v0.0.1 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.15 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||
github.com/miekg/dns v1.1.50 // indirect
|
||||
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
|
||||
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
|
||||
github.com/minio/sha256-simd v1.0.0 // indirect
|
||||
github.com/mr-tron/base58 v1.2.0 // indirect
|
||||
github.com/multiformats/go-base32 v0.1.0 // indirect
|
||||
github.com/multiformats/go-base36 v0.1.0 // indirect
|
||||
github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect
|
||||
github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect
|
||||
github.com/multiformats/go-multibase v0.1.1 // indirect
|
||||
github.com/multiformats/go-multicodec v0.6.0 // indirect
|
||||
github.com/multiformats/go-multihash v0.2.1 // indirect
|
||||
github.com/multiformats/go-multistream v0.3.3 // indirect
|
||||
github.com/multiformats/go-varint v0.0.6 // indirect
|
||||
github.com/nxadm/tail v1.4.8 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
|
||||
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/prometheus/client_golang v1.13.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
github.com/prometheus/tsdb v0.7.1 // indirect
|
||||
github.com/raulk/go-watchdog v1.3.0 // indirect
|
||||
github.com/rjeczalik/notify v0.9.1 // indirect
|
||||
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
|
||||
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 // indirect
|
||||
github.com/status-im/status-go/extkeys v1.1.2 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.5 // indirect
|
||||
github.com/tklauser/numcpus v0.2.2 // indirect
|
||||
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef // indirect
|
||||
github.com/waku-org/go-discover v0.0.0-20221209174356-61c833f34d98 // indirect
|
||||
github.com/waku-org/go-zerokit-rln v0.1.7-wakuorg // indirect
|
||||
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/multierr v1.8.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect
|
||||
golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/net v0.0.0-20220920183852-bf014ff85ad5 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect
|
||||
golang.org/x/text v0.4.0 // indirect
|
||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
|
||||
golang.org/x/tools v0.1.12 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
lukechampine.com/blake3 v1.1.7 // indirect
|
||||
)
|
2369
examples/noise/go.sum
Normal file
2369
examples/noise/go.sum
Normal file
File diff suppressed because it is too large
Load Diff
227
examples/noise/main.go
Normal file
227
examples/noise/main.go
Normal file
@ -0,0 +1,227 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
n "github.com/waku-org/go-noise"
|
||||
"github.com/waku-org/go-waku/waku/v2/dnsdisc"
|
||||
"github.com/waku-org/go-waku/waku/v2/node"
|
||||
"github.com/waku-org/go-waku/waku/v2/protocol/noise"
|
||||
"github.com/waku-org/go-waku/waku/v2/timesource"
|
||||
"github.com/waku-org/go-waku/waku/v2/utils"
|
||||
"go.uber.org/zap"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
var log = logging.Logger("noise")
|
||||
|
||||
func main() {
|
||||
// Removing noisy logs
|
||||
lvl, err := logging.LevelFromString("error")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
logging.SetAllLoggers(lvl)
|
||||
|
||||
hostAddr, _ := net.ResolveTCPAddr("tcp", fmt.Sprint("0.0.0.0:0"))
|
||||
|
||||
wakuNode, err := node.New(context.Background(),
|
||||
node.WithHostAddress(hostAddr),
|
||||
node.WithNTP(),
|
||||
node.WithWakuRelay(),
|
||||
)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := wakuNode.Start(); err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
discoverFleetNodes(wakuNode)
|
||||
|
||||
myStaticKey, _ := n.DH25519.GenerateKeypair()
|
||||
myEphemeralKey, _ := n.DH25519.GenerateKeypair()
|
||||
|
||||
relayMessenger, err := noise.NewWakuRelayMessenger(context.Background(), wakuNode.Relay(), nil, timesource.NewDefaultClock())
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
pairingObj, err := noise.NewPairing(myStaticKey, myEphemeralKey, noise.WithDefaultResponderParameters(), relayMessenger, utils.Logger())
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
qrString, qrMessageNameTag := pairingObj.PairingInfo()
|
||||
qrURL := url.QueryEscape(hex.EncodeToString(qrMessageNameTag[:]) + ":" + qrString)
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
// Execute in separate go routine
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||
defer cancel()
|
||||
err := pairingObj.Execute(ctx)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
// Confirmation is done by manually
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
authCode := <-pairingObj.AuthCode()
|
||||
fmt.Println("=============================================")
|
||||
fmt.Println("TODO: ask to confirm pairing. Automaticaly confirming authcode", authCode)
|
||||
fmt.Println("=============================================")
|
||||
err := pairingObj.ConfirmAuthCode(true)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
fmt.Println("=============================================================================")
|
||||
fmt.Printf("Browse http://localhost:8080/?%s\n", qrURL)
|
||||
fmt.Println("=============================================================================")
|
||||
|
||||
wg.Wait()
|
||||
|
||||
// Securely transferring messages
|
||||
if pairingObj.HandshakeComplete() {
|
||||
go writeLoop(context.Background(), wakuNode, pairingObj)
|
||||
go readLoop(context.Background(), wakuNode, pairingObj)
|
||||
}
|
||||
|
||||
// Wait for a SIGINT or SIGTERM signal
|
||||
ch := make(chan os.Signal, 1)
|
||||
signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-ch
|
||||
fmt.Println("\n\n\nReceived signal, shutting down...")
|
||||
|
||||
// shut the node down
|
||||
wakuNode.Stop()
|
||||
|
||||
}
|
||||
|
||||
func discoverFleetNodes(wakuNode *node.WakuNode) error {
|
||||
log.Info("Connecting to test fleet...")
|
||||
|
||||
dnsDiscoveryUrl := "enrtree://AOGECG2SPND25EEFMAJ5WF3KSGJNSGV356DSTL2YVLLZWIV6SAYBM@test.waku.nodes.status.im"
|
||||
nodes, err := dnsdisc.RetrieveNodes(context.Background(), dnsDiscoveryUrl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var nodeList []multiaddr.Multiaddr
|
||||
for _, n := range nodes {
|
||||
nodeList = append(nodeList, n.Addresses...)
|
||||
}
|
||||
|
||||
log.Info(fmt.Sprintf("Discovered and connecting to %v ", nodeList))
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(len(nodeList))
|
||||
for _, n := range nodeList {
|
||||
go func(addr multiaddr.Multiaddr) {
|
||||
defer wg.Done()
|
||||
|
||||
peerID, err := addr.ValueForProtocol(multiaddr.P_P2P)
|
||||
if err != nil {
|
||||
log.Error("error obtaining peerID", zap.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(10)*time.Second)
|
||||
defer cancel()
|
||||
err = wakuNode.DialPeerWithMultiAddress(ctx, addr)
|
||||
if err != nil {
|
||||
log.Error("could not connect", zap.String("peerID", peerID), zap.Error(err))
|
||||
} else {
|
||||
log.Info("Connected", zap.String("peerID", peerID))
|
||||
}
|
||||
}(n)
|
||||
|
||||
}
|
||||
wg.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeLoop(ctx context.Context, wakuNode *node.WakuNode, pairingObj *noise.Pairing) {
|
||||
for {
|
||||
time.Sleep(4 * time.Second)
|
||||
|
||||
chatMessage := &Chat2Message{
|
||||
Timestamp: uint64(wakuNode.Timesource().Now().Unix()),
|
||||
Nick: "go-waku",
|
||||
Payload: []byte("Hello World!"),
|
||||
}
|
||||
|
||||
chatMessageBytes, err := proto.Marshal(chatMessage)
|
||||
if err != nil {
|
||||
log.Error("Error encoding message: ", zap.Error(err))
|
||||
continue
|
||||
}
|
||||
|
||||
msg, err := pairingObj.Encrypt(chatMessageBytes)
|
||||
if err != nil {
|
||||
log.Error("error encrypting message", zap.Error(err))
|
||||
continue
|
||||
}
|
||||
|
||||
msg.Timestamp = wakuNode.Timesource().Now().UnixNano()
|
||||
|
||||
_, err = wakuNode.Relay().Publish(ctx, msg)
|
||||
if err != nil {
|
||||
log.Error("Error sending a message", zap.Error(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func readLoop(ctx context.Context, wakuNode *node.WakuNode, pairingObj *noise.Pairing) {
|
||||
sub, err := wakuNode.Relay().Subscribe(ctx)
|
||||
if err != nil {
|
||||
log.Error("Could not subscribe: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
for value := range sub.C {
|
||||
if value.Message().ContentTopic != pairingObj.ContentTopic {
|
||||
continue
|
||||
}
|
||||
|
||||
msgBytes, err := pairingObj.Decrypt(value.Message())
|
||||
if err != nil {
|
||||
log.Debug("Error decoding a message", zap.Error(err))
|
||||
continue
|
||||
}
|
||||
|
||||
msg := &Chat2Message{}
|
||||
if err := proto.Unmarshal(msgBytes, msg); err != nil {
|
||||
log.Error("Error decoding a message", zap.Error(err))
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Println("Received msg from ", msg.Nick, " - "+string(msg.Payload))
|
||||
}
|
||||
}
|
7
go.mod
7
go.mod
@ -21,7 +21,7 @@ require (
|
||||
github.com/mattn/go-sqlite3 v1.14.15
|
||||
github.com/multiformats/go-multiaddr v0.7.0
|
||||
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||
github.com/stretchr/testify v1.8.0
|
||||
github.com/stretchr/testify v1.8.1
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect
|
||||
github.com/urfave/cli/v2 v2.20.2
|
||||
go.opencensus.io v0.23.0
|
||||
@ -33,10 +33,11 @@ require (
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/waku-org/go-discover v0.0.0-20221209174356-61c833f34d98
|
||||
github.com/waku-org/go-zerokit-rln v0.1.7-wakuorg
|
||||
github.com/waku-org/noise v1.0.3
|
||||
golang.org/x/text v0.4.0
|
||||
)
|
||||
|
||||
require github.com/waku-org/go-noise v0.0.4
|
||||
|
||||
require (
|
||||
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect
|
||||
github.com/VictoriaMetrics/fastcache v1.6.0 // indirect
|
||||
@ -149,7 +150,7 @@ require (
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/multierr v1.8.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e
|
||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect
|
||||
golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/net v0.0.0-20220920183852-bf014ff85ad5 // indirect
|
||||
|
8
go.sum
8
go.sum
@ -1462,6 +1462,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
@ -1472,8 +1473,9 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
@ -1520,10 +1522,10 @@ github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1
|
||||
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||
github.com/waku-org/go-discover v0.0.0-20221209174356-61c833f34d98 h1:xwY0kW5XZFimdqfZb9cZwT1S3VJP9j3AE6bdNd9boXM=
|
||||
github.com/waku-org/go-discover v0.0.0-20221209174356-61c833f34d98/go.mod h1:eBHgM6T4EG0RZzxpxKy+rGz/6Dw2Nd8DWxS0lm9ESDw=
|
||||
github.com/waku-org/go-noise v0.0.4 h1:ZfQDcCw8pazm89EBl5SXY7GGAnzDQb9AHFXlw3Ktbvk=
|
||||
github.com/waku-org/go-noise v0.0.4/go.mod h1:+PWRfs2eSOVwKrPcQlfhwDngSh3faL/1QoxvoqggEKc=
|
||||
github.com/waku-org/go-zerokit-rln v0.1.7-wakuorg h1:2vVIBCtBih2w1K9ll8YnToTDZvbxcgbsClsPlJS/kkg=
|
||||
github.com/waku-org/go-zerokit-rln v0.1.7-wakuorg/go.mod h1:GlyaVeEWNEBxVJrWC6jFTvb4LNb9d9qnjdS6EiWVUvk=
|
||||
github.com/waku-org/noise v1.0.3 h1:BIecnRG0J0JlZmqcZTHphQ8yUeqqwkIaUAVk2JNK9VQ=
|
||||
github.com/waku-org/noise v1.0.3/go.mod h1:emThr8WZLeAtKqFW+/nXfHn9VucuXTh8aHap03UXP84=
|
||||
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee h1:lYbXeSvJi5zk5GLKVuid9TVjS9a0OmLIDKTfoZBL6Ow=
|
||||
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg=
|
||||
github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||
|
@ -1,15 +0,0 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"crypto/sha256"
|
||||
)
|
||||
|
||||
// CommitPublicKey commits a public key pk for randomness r as H(pk || s)
|
||||
func CommitPublicKey(publicKey ed25519.PublicKey, r []byte) []byte {
|
||||
input := []byte{}
|
||||
input = append(input, []byte(publicKey)...)
|
||||
input = append(input, r...)
|
||||
res := sha256.Sum256(input)
|
||||
return res[:]
|
||||
}
|
@ -1,408 +0,0 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
n "github.com/waku-org/noise"
|
||||
"golang.org/x/crypto/hkdf"
|
||||
)
|
||||
|
||||
// WakuNoiseProtocolID indicates the protocol ID defined according to https://rfc.vac.dev/spec/35/#specification
|
||||
type WakuNoiseProtocolID = byte
|
||||
|
||||
var (
|
||||
None = WakuNoiseProtocolID(0)
|
||||
Noise_K1K1_25519_ChaChaPoly_SHA256 = WakuNoiseProtocolID(10)
|
||||
Noise_XK1_25519_ChaChaPoly_SHA256 = WakuNoiseProtocolID(11)
|
||||
Noise_XX_25519_ChaChaPoly_SHA256 = WakuNoiseProtocolID(12)
|
||||
Noise_XXpsk0_25519_ChaChaPoly_SHA256 = WakuNoiseProtocolID(13)
|
||||
Noise_WakuPairing_25519_ChaChaPoly_SHA256 = WakuNoiseProtocolID(14)
|
||||
ChaChaPoly = WakuNoiseProtocolID(30)
|
||||
)
|
||||
|
||||
const NoisePaddingBlockSize = 248
|
||||
|
||||
var ErrorHandshakeComplete = errors.New("handshake complete")
|
||||
|
||||
// All protocols share same cipher suite
|
||||
var cipherSuite = n.NewCipherSuite(n.DH25519, n.CipherChaChaPoly, n.HashSHA256)
|
||||
|
||||
func newHandshakeState(pattern n.HandshakePattern, initiator bool, staticKeypair n.DHKey, ephemeralKeyPair n.DHKey, prologue []byte, presharedKey []byte, peerStatic []byte, peerEphemeral []byte) (hs *n.HandshakeState, err error) {
|
||||
defer func() {
|
||||
if rerr := recover(); rerr != nil {
|
||||
err = fmt.Errorf("panic in Noise handshake: %s", rerr)
|
||||
}
|
||||
}()
|
||||
|
||||
cfg := n.Config{
|
||||
CipherSuite: cipherSuite,
|
||||
Pattern: pattern,
|
||||
Initiator: initiator,
|
||||
StaticKeypair: staticKeypair,
|
||||
EphemeralKeypair: ephemeralKeyPair,
|
||||
Prologue: prologue,
|
||||
PresharedKey: presharedKey,
|
||||
PeerStatic: peerStatic,
|
||||
PeerEphemeral: peerEphemeral,
|
||||
}
|
||||
|
||||
return n.NewHandshakeState(cfg)
|
||||
}
|
||||
|
||||
type Handshake struct {
|
||||
protocolID WakuNoiseProtocolID
|
||||
pattern n.HandshakePattern
|
||||
state *n.HandshakeState
|
||||
|
||||
hsBuff []byte
|
||||
|
||||
enc *n.CipherState
|
||||
dec *n.CipherState
|
||||
nametagsInbound *MessageNametagBuffer
|
||||
nametagsOutbound *MessageNametagBuffer
|
||||
|
||||
initiator bool
|
||||
shouldWrite bool
|
||||
}
|
||||
|
||||
// HandshakeStepResult stores the intermediate result of processing messages patterns
|
||||
type HandshakeStepResult struct {
|
||||
Payload2 PayloadV2
|
||||
TransportMessage []byte
|
||||
}
|
||||
|
||||
func getHandshakePattern(protocol WakuNoiseProtocolID) (n.HandshakePattern, error) {
|
||||
switch protocol {
|
||||
case Noise_K1K1_25519_ChaChaPoly_SHA256:
|
||||
return HandshakeK1K1, nil
|
||||
case Noise_XK1_25519_ChaChaPoly_SHA256:
|
||||
return HandshakeXK1, nil
|
||||
case Noise_XX_25519_ChaChaPoly_SHA256:
|
||||
return HandshakeXX, nil
|
||||
case Noise_XXpsk0_25519_ChaChaPoly_SHA256:
|
||||
return HandshakeXXpsk0, nil
|
||||
case Noise_WakuPairing_25519_ChaChaPoly_SHA256:
|
||||
return HandshakeWakuPairing, nil
|
||||
default:
|
||||
return n.HandshakePattern{}, errors.New("unsupported handshake pattern")
|
||||
}
|
||||
}
|
||||
|
||||
// NewHandshake creates a new handshake using aa WakuNoiseProtocolID that is maped to a handshake pattern.
|
||||
func NewHandshake(protocolID WakuNoiseProtocolID, initiator bool, staticKeypair n.DHKey, ephemeralKeyPair n.DHKey, prologue []byte, presharedKey []byte, peerStatic []byte, peerEphemeral []byte) (*Handshake, error) {
|
||||
hsPattern, err := getHandshakePattern(protocolID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hsState, err := newHandshakeState(hsPattern, initiator, staticKeypair, ephemeralKeyPair, prologue, presharedKey, peerStatic, peerEphemeral)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Handshake{
|
||||
protocolID: protocolID,
|
||||
pattern: hsPattern,
|
||||
initiator: initiator,
|
||||
shouldWrite: initiator,
|
||||
state: hsState,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (hs *Handshake) Hash() hash.Hash {
|
||||
return hs.state.Hash()
|
||||
}
|
||||
|
||||
func (hs *Handshake) H() []byte {
|
||||
return hs.state.H()
|
||||
}
|
||||
|
||||
func (hs *Handshake) RS() []byte {
|
||||
return hs.state.RS()
|
||||
}
|
||||
|
||||
// Step advances a step in the handshake. Each user in a handshake alternates writing and reading of handshake messages.
|
||||
// If the user is writing the handshake message, the transport message (if not empty) has to be passed to transportMessage and readPayloadV2 can be left to its default value
|
||||
// It the user is reading the handshake message, the read payload v2 has to be passed to readPayloadV2 and the transportMessage can be left to its default values.
|
||||
// TODO: this might be refactored into a separate `sendHandshakeMessage` and `receiveHandshakeMessage`.
|
||||
// The messageNameTag is an optional value and can be used to identify missing messages
|
||||
func (hs *Handshake) Step(readPayloadV2 *PayloadV2, transportMessage []byte, messageNametag *MessageNametag) (*HandshakeStepResult, error) {
|
||||
if hs.enc != nil || hs.dec != nil {
|
||||
return nil, ErrorHandshakeComplete
|
||||
}
|
||||
|
||||
var cs1 *n.CipherState
|
||||
var cs2 *n.CipherState
|
||||
var err error
|
||||
var msg []byte
|
||||
var noisePubKeys [][]byte
|
||||
|
||||
result := HandshakeStepResult{}
|
||||
|
||||
if hs.shouldWrite {
|
||||
// We initialize a payload v2 and we set proper protocol ID (if supported)
|
||||
result.Payload2.ProtocolId = hs.protocolID
|
||||
|
||||
payload, err := PKCS7_Pad(transportMessage, NoisePaddingBlockSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var mtag MessageNametag
|
||||
if messageNametag != nil {
|
||||
mtag = *messageNametag
|
||||
}
|
||||
|
||||
msg, noisePubKeys, cs1, cs2, err = hs.state.WriteMessageAndGetPK(hs.hsBuff, [][]byte{}, payload, mtag[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hs.shouldWrite = false
|
||||
|
||||
if messageNametag != nil {
|
||||
result.Payload2.MessageNametag = *messageNametag
|
||||
}
|
||||
|
||||
result.Payload2.TransportMessage = msg
|
||||
for _, npk := range noisePubKeys {
|
||||
result.Payload2.HandshakeMessage = append(result.Payload2.HandshakeMessage, byteToNoisePublicKey(npk))
|
||||
}
|
||||
|
||||
} else {
|
||||
if readPayloadV2 == nil {
|
||||
return nil, errors.New("readPayloadV2 is required")
|
||||
}
|
||||
|
||||
var mtag MessageNametag
|
||||
if messageNametag != nil {
|
||||
mtag = *messageNametag
|
||||
if !bytes.Equal(readPayloadV2.MessageNametag[:], mtag[:]) {
|
||||
return nil, ErrNametagNotExpected
|
||||
}
|
||||
}
|
||||
|
||||
readTMessage := readPayloadV2.TransportMessage
|
||||
|
||||
// We retrieve and store the (decrypted) received transport message by passing the messageNametag as extra additional data
|
||||
|
||||
// Since we only read, nothing meanigful (i.e. public keys) is returned. (hsBuffer is not affected)
|
||||
msg, cs1, cs2, err = hs.state.ReadMessage(nil, readTMessage, mtag[:]...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hs.shouldWrite = true
|
||||
|
||||
// We retrieve, and store the (unpadded decrypted) received transport message
|
||||
|
||||
payload, err := PKCS7_Unpad(msg, NoisePaddingBlockSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result.TransportMessage = payload
|
||||
}
|
||||
|
||||
if cs1 != nil && cs2 != nil {
|
||||
err = hs.setCipherStates(cs1, cs2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// HandshakeComplete indicates whether the handshake process is complete or not
|
||||
func (hs *Handshake) HandshakeComplete() bool {
|
||||
return hs.enc != nil && hs.dec != nil
|
||||
}
|
||||
|
||||
// This is called when the final handshake message is processed
|
||||
func (hs *Handshake) setCipherStates(cs1, cs2 *n.CipherState) error {
|
||||
// Optional: We derive a secret for the nametag derivation
|
||||
nms1, nms2, err := hs.messageNametagSecrets()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if hs.initiator {
|
||||
hs.enc = cs1
|
||||
hs.dec = cs2
|
||||
// and nametags secrets
|
||||
hs.nametagsInbound = NewMessageNametagBuffer(nms1)
|
||||
hs.nametagsOutbound = NewMessageNametagBuffer(nms2)
|
||||
} else {
|
||||
hs.enc = cs2
|
||||
hs.dec = cs1
|
||||
// and nametags secrets
|
||||
hs.nametagsInbound = NewMessageNametagBuffer(nms2)
|
||||
hs.nametagsOutbound = NewMessageNametagBuffer(nms1)
|
||||
}
|
||||
|
||||
// We initialize the message nametags inbound/outbound buffers
|
||||
hs.nametagsInbound.Init()
|
||||
hs.nametagsOutbound.Init()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Encrypt calls the cipher's encryption. It encrypts the provided plaintext and returns a PayloadV2
|
||||
func (hs *Handshake) Encrypt(plaintext []byte, outboundMessageNametagBuffer ...*MessageNametagBuffer) (*PayloadV2, error) {
|
||||
if hs.enc == nil {
|
||||
return nil, errors.New("cannot encrypt, handshake incomplete")
|
||||
}
|
||||
|
||||
if len(plaintext) == 0 {
|
||||
return nil, errors.New("tried to encrypt empty plaintext")
|
||||
}
|
||||
|
||||
paddedTransportMessage, err := PKCS7_Pad(plaintext, NoisePaddingBlockSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// We set the message nametag using the input buffer
|
||||
var messageNametag MessageNametag
|
||||
if len(outboundMessageNametagBuffer) != 0 {
|
||||
messageNametag = outboundMessageNametagBuffer[0].Pop()
|
||||
} else {
|
||||
messageNametag = hs.nametagsOutbound.Pop()
|
||||
}
|
||||
|
||||
cyphertext, err := hs.enc.Encrypt(nil, messageNametag[:], paddedTransportMessage)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// According to 35/WAKU2-NOISE RFC, no Handshake protocol information is sent when exchanging messages
|
||||
// This correspond to setting protocol-id to 0 (None)
|
||||
return &PayloadV2{
|
||||
ProtocolId: None,
|
||||
TransportMessage: cyphertext,
|
||||
MessageNametag: messageNametag,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Decrypt calls the cipher's decryption. It decrypts the provided payload and returns the message in plaintext
|
||||
func (hs *Handshake) Decrypt(payload *PayloadV2, inboundMessageNametagBuffer ...*MessageNametagBuffer) ([]byte, error) {
|
||||
if hs.dec == nil {
|
||||
return nil, errors.New("cannot decrypt, handshake incomplete")
|
||||
}
|
||||
|
||||
if payload == nil {
|
||||
return nil, errors.New("no payload to decrypt")
|
||||
}
|
||||
|
||||
// If the message nametag does not correspond to the nametag expected in the inbound message nametag buffer
|
||||
// an error is raised (to be handled externally, i.e. re-request lost messages, discard, etc.)
|
||||
if len(inboundMessageNametagBuffer) != 0 {
|
||||
err := inboundMessageNametagBuffer[0].CheckNametag(payload.MessageNametag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
err := hs.nametagsInbound.CheckNametag(payload.MessageNametag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if len(payload.TransportMessage) == 0 {
|
||||
return nil, errors.New("tried to decrypt empty ciphertext")
|
||||
}
|
||||
|
||||
// Decryption is done with messageNametag as associated data
|
||||
paddedMessage, err := hs.dec.Decrypt(nil, payload.MessageNametag[:], payload.TransportMessage)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// The message successfully decrypted, we can delete the first element of the inbound Message Nametag Buffer
|
||||
hs.nametagsInbound.Delete(1)
|
||||
|
||||
return PKCS7_Unpad(paddedMessage, NoisePaddingBlockSize)
|
||||
}
|
||||
|
||||
func getHKDF(h func() hash.Hash, ck []byte, ikm []byte, numBytes int) ([]byte, error) {
|
||||
hkdf := hkdf.New(h, ikm, ck, nil)
|
||||
result := make([]byte, numBytes)
|
||||
if _, err := io.ReadFull(hkdf, result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Generates an 8 decimal digits authorization code using HKDF and the handshake state
|
||||
func (hs *Handshake) Authcode() (string, error) {
|
||||
output0, err := getHKDF(hs.Hash, hs.H(), nil, 8)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
bn := new(big.Int)
|
||||
bn.SetBytes(output0)
|
||||
code := new(big.Int)
|
||||
code.Mod(bn, big.NewInt(100_000_000))
|
||||
return fmt.Sprintf("'%08s'", code.String()), nil
|
||||
}
|
||||
|
||||
func (hs *Handshake) messageNametagSecrets() (nms1 []byte, nms2 []byte, err error) {
|
||||
output, err := getHKDF(hs.Hash, hs.H(), nil, 64)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
nms1 = output[0:32]
|
||||
nms2 = output[32:]
|
||||
return
|
||||
}
|
||||
|
||||
// Uses the cryptographic information stored in the input handshake state to generate a random message nametag
|
||||
// In current implementation the messageNametag = HKDF(handshake hash value), but other derivation mechanisms can be implemented
|
||||
func (hs *Handshake) ToMessageNametag() (MessageNametag, error) {
|
||||
output, err := getHKDF(hs.Hash, hs.H(), nil, 32)
|
||||
if err != nil {
|
||||
return [16]byte{}, err
|
||||
}
|
||||
return BytesToMessageNametag(output), nil
|
||||
}
|
||||
|
||||
// NewHandshake_XX_25519_ChaChaPoly_SHA256 creates a handshake where the initiator and receiver are not aware of each other static keys
|
||||
func NewHandshake_XX_25519_ChaChaPoly_SHA256(staticKeypair n.DHKey, initiator bool, prologue []byte) (*Handshake, error) {
|
||||
return NewHandshake(Noise_XX_25519_ChaChaPoly_SHA256, initiator, staticKeypair, n.DHKey{}, prologue, nil, nil, nil)
|
||||
}
|
||||
|
||||
// NewHandshake_XXpsk0_25519_ChaChaPoly_SHA256 creates a handshake where the initiator and receiver are not aware of each other static keys
|
||||
// and use a preshared secret to strengthen their mutual authentication
|
||||
func NewHandshake_XXpsk0_25519_ChaChaPoly_SHA256(staticKeypair n.DHKey, initiator bool, presharedKey []byte, prologue []byte) (*Handshake, error) {
|
||||
return NewHandshake(Noise_XXpsk0_25519_ChaChaPoly_SHA256, initiator, staticKeypair, n.DHKey{}, prologue, presharedKey, nil, nil)
|
||||
}
|
||||
|
||||
// NewHandshake_K1K1_25519_ChaChaPoly_SHA256 creates a handshake where both initiator and recever know each other handshake. Only ephemeral keys
|
||||
// are exchanged. This handshake is useful in case the initiator needs to instantiate a new separate encrypted communication
|
||||
// channel with the receiver
|
||||
func NewHandshake_K1K1_25519_ChaChaPoly_SHA256(staticKeypair n.DHKey, initiator bool, peerStaticKey []byte, prologue []byte) (*Handshake, error) {
|
||||
return NewHandshake(Noise_K1K1_25519_ChaChaPoly_SHA256, initiator, staticKeypair, n.DHKey{}, prologue, nil, peerStaticKey, nil)
|
||||
}
|
||||
|
||||
// NewHandshake_XK1_25519_ChaChaPoly_SHA256 creates a handshake where the initiator knows the receiver public static key. Within this handshake,
|
||||
// the initiator and receiver reciprocally authenticate their static keys using ephemeral keys. We note that while the receiver's
|
||||
// static key is assumed to be known to Alice (and hence is not transmitted), The initiator static key is sent to the
|
||||
// receiver encrypted with a key derived from both parties ephemeral keys and the receiver's static key.
|
||||
func NewHandshake_XK1_25519_ChaChaPoly_SHA256(staticKeypair n.DHKey, initiator bool, peerStaticKey []byte, prologue []byte) (*Handshake, error) {
|
||||
if !initiator && len(peerStaticKey) != 0 {
|
||||
return nil, errors.New("recipient shouldnt know initiator key")
|
||||
}
|
||||
return NewHandshake(Noise_XK1_25519_ChaChaPoly_SHA256, initiator, staticKeypair, n.DHKey{}, prologue, nil, peerStaticKey, nil)
|
||||
}
|
||||
|
||||
// NewHandshake_WakuPairing_25519_ChaChaPoly_SHA256
|
||||
func NewHandshake_WakuPairing_25519_ChaChaPoly_SHA256(staticKeypair n.DHKey, ephemeralKeyPair n.DHKey, initiator bool, prologue []byte, presharedKey []byte) (*Handshake, error) {
|
||||
peerEphemeral := presharedKey[0:32]
|
||||
return NewHandshake(Noise_WakuPairing_25519_ChaChaPoly_SHA256, initiator, staticKeypair, ephemeralKeyPair, prologue, presharedKey, nil, peerEphemeral)
|
||||
}
|
@ -1,137 +0,0 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
)
|
||||
|
||||
type MessageNametag [MessageNametagLength]byte
|
||||
|
||||
const MessageNametagLength = 16
|
||||
const MessageNametagBufferSize = 50
|
||||
|
||||
var (
|
||||
ErrNametagNotFound = errors.New("message nametag not found in buffer")
|
||||
ErrNametagNotExpected = errors.New("message nametag is present in buffer but is not the next expected nametag. One or more messages were probably lost")
|
||||
)
|
||||
|
||||
// Converts a sequence or array (arbitrary size) to a MessageNametag
|
||||
func BytesToMessageNametag(input []byte) MessageNametag {
|
||||
var result MessageNametag
|
||||
copy(result[:], input)
|
||||
return result
|
||||
}
|
||||
|
||||
func (t MessageNametag) String() string {
|
||||
return hex.EncodeToString(t[:])
|
||||
}
|
||||
|
||||
type MessageNametagBuffer struct {
|
||||
buffer []MessageNametag
|
||||
counter uint64
|
||||
secret []byte
|
||||
}
|
||||
|
||||
func NewMessageNametagBuffer(secret []byte) *MessageNametagBuffer {
|
||||
return &MessageNametagBuffer{
|
||||
secret: secret,
|
||||
}
|
||||
}
|
||||
|
||||
// Initializes the empty Message nametag buffer. The n-th nametag is equal to HKDF( secret || n )
|
||||
func (m *MessageNametagBuffer) Init() {
|
||||
// We default the counter and buffer fields
|
||||
m.counter = 0
|
||||
m.buffer = make([]MessageNametag, MessageNametagBufferSize)
|
||||
if len(m.secret) != 0 {
|
||||
for i := range m.buffer {
|
||||
counterBytesLE := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(counterBytesLE, m.counter)
|
||||
toHash := []byte{}
|
||||
toHash = append(toHash, m.secret...)
|
||||
toHash = append(toHash, counterBytesLE...)
|
||||
d := sha256.Sum256(toHash)
|
||||
m.buffer[i] = BytesToMessageNametag(d[:])
|
||||
m.counter++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MessageNametagBuffer) Pop() MessageNametag {
|
||||
// Note that if the input MessageNametagBuffer is set to default, an all 0 messageNametag is returned
|
||||
if len(m.buffer) == 0 {
|
||||
var m MessageNametag
|
||||
return m
|
||||
} else {
|
||||
messageNametag := m.buffer[0]
|
||||
m.Delete(1)
|
||||
return messageNametag
|
||||
}
|
||||
}
|
||||
|
||||
// Checks if the input messageNametag is contained in the input MessageNametagBuffer
|
||||
func (m *MessageNametagBuffer) CheckNametag(messageNametag MessageNametag) error {
|
||||
if len(m.buffer) != MessageNametagBufferSize {
|
||||
return nil
|
||||
}
|
||||
|
||||
index := -1
|
||||
for i, x := range m.buffer {
|
||||
if bytes.Equal(x[:], messageNametag[:]) {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if index == -1 {
|
||||
return ErrNametagNotFound
|
||||
} else if index > 0 {
|
||||
return ErrNametagNotExpected
|
||||
}
|
||||
|
||||
// index is 0, hence the read message tag is the next expected one
|
||||
return nil
|
||||
}
|
||||
|
||||
func rotateLeft(elems []MessageNametag, k int) []MessageNametag {
|
||||
if k < 0 || len(elems) == 0 {
|
||||
return elems
|
||||
}
|
||||
r := len(elems) - k%len(elems)
|
||||
|
||||
result := elems[r:]
|
||||
result = append(result, elems[:r]...)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Deletes the first n elements in buffer and appends n new ones
|
||||
func (m *MessageNametagBuffer) Delete(n int) {
|
||||
if n <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// We ensure n is at most MessageNametagBufferSize (the buffer will be fully replaced)
|
||||
if n > MessageNametagBufferSize {
|
||||
n = MessageNametagBufferSize
|
||||
}
|
||||
|
||||
// We update the last n values in the array if a secret is set
|
||||
// Note that if the input MessageNametagBuffer is set to default, nothing is done here
|
||||
if len(m.secret) != 0 {
|
||||
m.buffer = rotateLeft(m.buffer, n)
|
||||
for i := 0; i < n; i++ {
|
||||
counterBytesLE := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(counterBytesLE, m.counter)
|
||||
toHash := []byte{}
|
||||
toHash = append(toHash, m.secret...)
|
||||
toHash = append(toHash, counterBytesLE...)
|
||||
d := sha256.Sum256(toHash)
|
||||
m.buffer[len(m.buffer)-n+i] = BytesToMessageNametag(d[:])
|
||||
m.counter++
|
||||
}
|
||||
}
|
||||
}
|
@ -1,205 +0,0 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"crypto/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/waku-org/noise"
|
||||
)
|
||||
|
||||
func generateRandomBytes(t *testing.T, n int) []byte {
|
||||
b := make([]byte, n)
|
||||
_, err := rand.Read(b)
|
||||
require.NoError(t, err)
|
||||
return b
|
||||
}
|
||||
|
||||
func TestSerialization(t *testing.T) {
|
||||
handshakeMessages := make([]*NoisePublicKey, 2)
|
||||
|
||||
pk1, _, _ := ed25519.GenerateKey(rand.Reader)
|
||||
|
||||
pk2, _, _ := ed25519.GenerateKey(rand.Reader)
|
||||
|
||||
handshakeMessages[0] = Ed25519PubKeyToNoisePublicKey(pk1)
|
||||
handshakeMessages[1] = Ed25519PubKeyToNoisePublicKey(pk2)
|
||||
|
||||
p1 := &PayloadV2{
|
||||
ProtocolId: Noise_K1K1_25519_ChaChaPoly_SHA256,
|
||||
HandshakeMessage: handshakeMessages,
|
||||
TransportMessage: []byte{9, 8, 7, 6, 5, 4, 3, 2, 1},
|
||||
}
|
||||
|
||||
serializedPayload, err := p1.Serialize()
|
||||
require.NoError(t, err)
|
||||
|
||||
deserializedPayload, err := DeserializePayloadV2(serializedPayload)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, p1, deserializedPayload)
|
||||
}
|
||||
|
||||
func handshakeTest(t *testing.T, hsAlice *Handshake, hsBob *Handshake) {
|
||||
// ###############
|
||||
// # 1st step
|
||||
// ###############
|
||||
|
||||
// By being the handshake initiator, Alice writes a Waku2 payload v2 containing her handshake message
|
||||
// and the (encrypted) transport message
|
||||
sentTransportMessage := generateRandomBytes(t, 32)
|
||||
aliceStep, err := hsAlice.Step(nil, sentTransportMessage, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Bob reads Alice's payloads, and returns the (decrypted) transport message Alice sent to him
|
||||
bobStep, err := hsBob.Step(&aliceStep.Payload2, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// check:
|
||||
require.Equal(t, sentTransportMessage, bobStep.TransportMessage)
|
||||
|
||||
// ###############
|
||||
// # 2nd step
|
||||
// ###############
|
||||
|
||||
// At this step, Bob writes and returns a payload
|
||||
sentTransportMessage = generateRandomBytes(t, 32)
|
||||
bobStep, err = hsBob.Step(nil, sentTransportMessage, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// While Alice reads and returns the (decrypted) transport message
|
||||
aliceStep, err = hsAlice.Step(&bobStep.Payload2, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// check:
|
||||
require.Equal(t, sentTransportMessage, aliceStep.TransportMessage)
|
||||
|
||||
// ###############
|
||||
// # 3rd step
|
||||
// ###############
|
||||
|
||||
// Similarly as in first step, Alice writes a Waku2 payload containing the handshake message and the (encrypted) transport message
|
||||
sentTransportMessage = generateRandomBytes(t, 32)
|
||||
aliceStep, err = hsAlice.Step(nil, sentTransportMessage, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Bob reads Alice's payloads, and returns the (decrypted) transport message Alice sent to him
|
||||
bobStep, err = hsBob.Step(&aliceStep.Payload2, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// check:
|
||||
require.Equal(t, sentTransportMessage, bobStep.TransportMessage)
|
||||
|
||||
// Note that for this handshake pattern, no more message patterns are left for processing
|
||||
// We test that extra calls to stepHandshake do not affect parties' handshake states
|
||||
require.True(t, hsAlice.HandshakeComplete())
|
||||
require.True(t, hsBob.HandshakeComplete())
|
||||
|
||||
_, err = hsAlice.Step(nil, generateRandomBytes(t, 32), nil)
|
||||
require.ErrorIs(t, err, ErrorHandshakeComplete)
|
||||
|
||||
_, err = hsBob.Step(nil, generateRandomBytes(t, 32), nil)
|
||||
require.ErrorIs(t, err, ErrorHandshakeComplete)
|
||||
|
||||
// #########################
|
||||
// After Handshake
|
||||
// #########################
|
||||
|
||||
// We test read/write of random messages exchanged between Alice and Bob
|
||||
|
||||
defaultMessageNametagBuffer := NewMessageNametagBuffer(nil)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
// Alice writes to Bob
|
||||
message := generateRandomBytes(t, 32)
|
||||
|
||||
encryptedPayload, err := hsAlice.Encrypt(message, defaultMessageNametagBuffer)
|
||||
require.NoError(t, err)
|
||||
|
||||
plaintext, err := hsBob.Decrypt(encryptedPayload, defaultMessageNametagBuffer)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, message, plaintext)
|
||||
|
||||
// Bob writes to Alice
|
||||
message = generateRandomBytes(t, 32)
|
||||
|
||||
encryptedPayload, err = hsBob.Encrypt(message, defaultMessageNametagBuffer)
|
||||
require.NoError(t, err)
|
||||
|
||||
plaintext, err = hsAlice.Decrypt(encryptedPayload, defaultMessageNametagBuffer)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, message, plaintext)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoiseXXHandshakeRoundtrip(t *testing.T) {
|
||||
aliceKP, _ := noise.DH25519.GenerateKeypair(rand.Reader)
|
||||
bobKP, _ := noise.DH25519.GenerateKeypair(rand.Reader)
|
||||
|
||||
hsAlice, err := NewHandshake_XX_25519_ChaChaPoly_SHA256(aliceKP, true, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
hsBob, err := NewHandshake_XX_25519_ChaChaPoly_SHA256(bobKP, false, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
handshakeTest(t, hsAlice, hsBob)
|
||||
}
|
||||
|
||||
func TestNoiseXXpsk0HandshakeRoundtrip(t *testing.T) {
|
||||
aliceKP, _ := noise.DH25519.GenerateKeypair(rand.Reader)
|
||||
bobKP, _ := noise.DH25519.GenerateKeypair(rand.Reader)
|
||||
|
||||
// We generate a random psk
|
||||
psk := generateRandomBytes(t, 32)
|
||||
|
||||
hsAlice, err := NewHandshake_XXpsk0_25519_ChaChaPoly_SHA256(aliceKP, true, psk, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
hsBob, err := NewHandshake_XXpsk0_25519_ChaChaPoly_SHA256(bobKP, false, psk, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
handshakeTest(t, hsAlice, hsBob)
|
||||
}
|
||||
|
||||
func TestNoiseK1K1HandshakeRoundtrip(t *testing.T) {
|
||||
aliceKP, _ := noise.DH25519.GenerateKeypair(rand.Reader)
|
||||
bobKP, _ := noise.DH25519.GenerateKeypair(rand.Reader)
|
||||
|
||||
hsAlice, err := NewHandshake_K1K1_25519_ChaChaPoly_SHA256(aliceKP, true, bobKP.Public, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
hsBob, err := NewHandshake_K1K1_25519_ChaChaPoly_SHA256(bobKP, false, aliceKP.Public, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
handshakeTest(t, hsAlice, hsBob)
|
||||
}
|
||||
|
||||
func TestNoiseXK1HandshakeRoundtrip(t *testing.T) {
|
||||
aliceKP, _ := noise.DH25519.GenerateKeypair(rand.Reader)
|
||||
bobKP, _ := noise.DH25519.GenerateKeypair(rand.Reader)
|
||||
|
||||
hsAlice, err := NewHandshake_XK1_25519_ChaChaPoly_SHA256(aliceKP, true, bobKP.Public, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
hsBob, err := NewHandshake_XK1_25519_ChaChaPoly_SHA256(bobKP, false, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
handshakeTest(t, hsAlice, hsBob)
|
||||
}
|
||||
|
||||
func TestPKCSPaddingUnpadding(t *testing.T) {
|
||||
maxMessageLength := 3 * NoisePaddingBlockSize
|
||||
for messageLen := 0; messageLen <= maxMessageLength; messageLen++ {
|
||||
message := generateRandomBytes(t, messageLen)
|
||||
padded, err := PKCS7_Pad(message, NoisePaddingBlockSize)
|
||||
require.NoError(t, err)
|
||||
unpadded, err := PKCS7_Unpad(padded, NoisePaddingBlockSize)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Greater(t, len(padded), 0)
|
||||
require.Equal(t, len(padded)%NoisePaddingBlockSize, 0)
|
||||
require.Equal(t, message, unpadded)
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
// PKCS7_Pad pads a payload according to PKCS#7 as per
|
||||
// RFC 5652 https://datatracker.ietf.org/doc/html/rfc5652#section-6.3
|
||||
func PKCS7_Pad(payload []byte, paddingSize int) ([]byte, error) {
|
||||
if paddingSize >= 256 {
|
||||
return nil, errors.New("invalid padding size")
|
||||
}
|
||||
|
||||
k := paddingSize - (len(payload) % paddingSize)
|
||||
|
||||
var padVal int
|
||||
if k != 0 {
|
||||
padVal = k
|
||||
} else {
|
||||
padVal = paddingSize
|
||||
}
|
||||
|
||||
padding := make([]byte, padVal)
|
||||
for i := range padding {
|
||||
padding[i] = byte(padVal)
|
||||
}
|
||||
|
||||
return append(payload, padding...), nil
|
||||
}
|
||||
|
||||
// PKCS7_Unpad unpads a payload according to PKCS#7 as per
|
||||
// RFC 5652 https://datatracker.ietf.org/doc/html/rfc5652#section-6.3
|
||||
func PKCS7_Unpad(payload []byte, paddingSize int) ([]byte, error) {
|
||||
if paddingSize >= 256 {
|
||||
return nil, errors.New("invalid padding size")
|
||||
}
|
||||
|
||||
if len(payload) == 0 {
|
||||
return nil, nil // empty payload
|
||||
}
|
||||
|
||||
high := len(payload) - 1
|
||||
k := payload[high]
|
||||
|
||||
unpadded := payload[0:(high + 1 - int(k))]
|
||||
|
||||
return unpadded, nil
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
n "github.com/waku-org/noise"
|
||||
)
|
||||
|
||||
/*
|
||||
K1K1:
|
||||
|
||||
-> s
|
||||
<- s
|
||||
...
|
||||
-> e
|
||||
<- e, ee, es
|
||||
-> se
|
||||
*/
|
||||
var HandshakeK1K1 = n.HandshakePattern{
|
||||
Name: "K1K1",
|
||||
InitiatorPreMessages: []n.MessagePattern{n.MessagePatternS},
|
||||
ResponderPreMessages: []n.MessagePattern{n.MessagePatternS},
|
||||
Messages: [][]n.MessagePattern{
|
||||
{n.MessagePatternE},
|
||||
{n.MessagePatternE, n.MessagePatternDHEE, n.MessagePatternDHES},
|
||||
{n.MessagePatternDHSE},
|
||||
},
|
||||
}
|
||||
|
||||
/*
|
||||
XK1:
|
||||
|
||||
<- s
|
||||
...
|
||||
-> e
|
||||
<- e, ee, es
|
||||
-> s, se
|
||||
*/
|
||||
var HandshakeXK1 = n.HandshakePattern{
|
||||
Name: "XK1",
|
||||
ResponderPreMessages: []n.MessagePattern{n.MessagePatternS},
|
||||
Messages: [][]n.MessagePattern{
|
||||
{n.MessagePatternE},
|
||||
{n.MessagePatternE, n.MessagePatternDHEE, n.MessagePatternDHES},
|
||||
{n.MessagePatternS, n.MessagePatternDHSE},
|
||||
},
|
||||
}
|
||||
|
||||
/*
|
||||
XX:
|
||||
|
||||
-> e
|
||||
<- e, ee, s, es
|
||||
-> s, se
|
||||
*/
|
||||
var HandshakeXX = n.HandshakePattern{
|
||||
Name: "XX",
|
||||
Messages: [][]n.MessagePattern{
|
||||
{n.MessagePatternE},
|
||||
{n.MessagePatternE, n.MessagePatternDHEE, n.MessagePatternS, n.MessagePatternDHES},
|
||||
{n.MessagePatternS, n.MessagePatternDHSE},
|
||||
},
|
||||
}
|
||||
|
||||
/*
|
||||
XXpsk0:
|
||||
|
||||
-> psk, e
|
||||
<- e, ee, s, es
|
||||
-> s, se
|
||||
*/
|
||||
var HandshakeXXpsk0 = n.HandshakePattern{
|
||||
Name: "XXpsk0",
|
||||
Messages: [][]n.MessagePattern{
|
||||
{n.MessagePatternPSK, n.MessagePatternE},
|
||||
{n.MessagePatternE, n.MessagePatternDHEE, n.MessagePatternS, n.MessagePatternDHES},
|
||||
{n.MessagePatternS, n.MessagePatternDHSE},
|
||||
},
|
||||
}
|
||||
|
||||
var HandshakeWakuPairing = n.HandshakePattern{
|
||||
Name: "WakuPairing",
|
||||
ResponderPreMessages: []n.MessagePattern{n.MessagePatternE},
|
||||
Messages: [][]n.MessagePattern{
|
||||
{n.MessagePatternE, n.MessagePatternDHEE},
|
||||
{n.MessagePatternS, n.MessagePatternDHES},
|
||||
{n.MessagePatternS, n.MessagePatternDHSE, n.MessagePatternDHSS},
|
||||
},
|
||||
}
|
@ -1,343 +0,0 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ed25519"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
|
||||
"github.com/waku-org/go-waku/waku/v2/protocol/pb"
|
||||
n "github.com/waku-org/noise"
|
||||
)
|
||||
|
||||
const MaxUint8 = 1<<8 - 1
|
||||
|
||||
// This follows https://rfc.vac.dev/spec/35/#public-keys-serialization
|
||||
// pk contains the X coordinate of the public key, if unencrypted (this implies flag = 0)
|
||||
// or the encryption of the X coordinate concatenated with the authorization tag, if encrypted (this implies flag = 1)
|
||||
// Note: besides encryption, flag can be used to distinguish among multiple supported Elliptic Curves
|
||||
type NoisePublicKey struct {
|
||||
Flag byte
|
||||
PubKey []byte
|
||||
}
|
||||
|
||||
func byteToNoisePublicKey(input []byte) *NoisePublicKey {
|
||||
flag := byte(0)
|
||||
if len(input) > n.DH25519.DHLen() {
|
||||
flag = 1
|
||||
}
|
||||
|
||||
return &NoisePublicKey{
|
||||
Flag: flag,
|
||||
PubKey: input,
|
||||
}
|
||||
}
|
||||
|
||||
// EcdsaPubKeyToNoisePublicKey converts a Elliptic Curve public key
|
||||
// to an unencrypted Noise public key
|
||||
func Ed25519PubKeyToNoisePublicKey(pk ed25519.PublicKey) *NoisePublicKey {
|
||||
return &NoisePublicKey{
|
||||
Flag: 0,
|
||||
PubKey: pk,
|
||||
}
|
||||
}
|
||||
|
||||
// Equals checks equality between two Noise public keys
|
||||
func (pk *NoisePublicKey) Equals(pk2 *NoisePublicKey) bool {
|
||||
return pk.Flag == pk2.Flag && bytes.Equal(pk.PubKey, pk2.PubKey)
|
||||
}
|
||||
|
||||
type SerializedNoisePublicKey []byte
|
||||
|
||||
// Serialize converts a Noise public key to a stream of bytes as in
|
||||
// https://rfc.vac.dev/spec/35/#public-keys-serialization
|
||||
func (pk *NoisePublicKey) Serialize() SerializedNoisePublicKey {
|
||||
// Public key is serialized as (flag || pk)
|
||||
// Note that pk contains the X coordinate of the public key if unencrypted
|
||||
// or the encryption concatenated with the authorization tag if encrypted
|
||||
serializedPK := make([]byte, len(pk.PubKey)+1)
|
||||
serializedPK[0] = pk.Flag
|
||||
copy(serializedPK[1:], pk.PubKey)
|
||||
|
||||
return serializedPK
|
||||
}
|
||||
|
||||
// Unserialize converts a serialized Noise public key to a NoisePublicKey object as in
|
||||
// https://rfc.vac.dev/spec/35/#public-keys-serialization
|
||||
func (s SerializedNoisePublicKey) Unserialize() (*NoisePublicKey, error) {
|
||||
if len(s) <= 1 {
|
||||
return nil, errors.New("invalid serialized public key length")
|
||||
}
|
||||
|
||||
pubk := &NoisePublicKey{}
|
||||
pubk.Flag = s[0]
|
||||
if !(pubk.Flag == 0 || pubk.Flag == 1) {
|
||||
return nil, errors.New("invalid flag in serialized public key")
|
||||
}
|
||||
|
||||
pubk.PubKey = s[1:]
|
||||
|
||||
return pubk, nil
|
||||
}
|
||||
|
||||
// Encrypt encrypts a Noise public key using a Cipher State
|
||||
func (pk *NoisePublicKey) Encrypt(state *n.CipherState) error {
|
||||
if pk.Flag == 0 {
|
||||
// Authorization tag is appended to output
|
||||
encPk, err := state.Encrypt(nil, nil, pk.PubKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pk.Flag = 1
|
||||
pk.PubKey = encPk
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decrypts decrypts a Noise public key using a Cipher State
|
||||
func (pk *NoisePublicKey) Decrypt(state *n.CipherState) error {
|
||||
if pk.Flag == 1 {
|
||||
decPk, err := state.Decrypt(nil, nil, pk.PubKey) // encrypted pk should contain the auth tag
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pk.Flag = 0
|
||||
pk.PubKey = decPk
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PayloadV2 defines an object for Waku payloads with version 2 as in
|
||||
// https://rfc.vac.dev/spec/35/#public-keys-serialization
|
||||
// It contains a protocol ID field, the handshake message (for Noise handshakes) and
|
||||
// a transport message (for Noise handshakes and ChaChaPoly encryptions)
|
||||
type PayloadV2 struct {
|
||||
ProtocolId byte
|
||||
HandshakeMessage []*NoisePublicKey
|
||||
TransportMessage []byte
|
||||
MessageNametag MessageNametag
|
||||
}
|
||||
|
||||
// Checks equality between two PayloadsV2 objects
|
||||
func (p *PayloadV2) Equals(p2 *PayloadV2) bool {
|
||||
if p.ProtocolId != p2.ProtocolId || !bytes.Equal(p.TransportMessage, p2.TransportMessage) {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, p1 := range p.HandshakeMessage {
|
||||
for _, p2 := range p2.HandshakeMessage {
|
||||
if !p1.Equals(p2) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Serializes a PayloadV2 object to a byte sequences according to https://rfc.vac.dev/spec/35/
|
||||
// The output serialized payload concatenates the input PayloadV2 object fields as
|
||||
// payload = ( protocolId || serializedHandshakeMessageLen || serializedHandshakeMessage || transportMessageLen || transportMessage)
|
||||
// The output can be then passed to the payload field of a WakuMessage https://rfc.vac.dev/spec/14/
|
||||
func (p *PayloadV2) Serialize() ([]byte, error) {
|
||||
// We collect public keys contained in the handshake message
|
||||
|
||||
// According to https://rfc.vac.dev/spec/35/, the maximum size for the handshake message is 256 bytes, that is
|
||||
// the handshake message length can be represented with 1 byte only. (its length can be stored in 1 byte)
|
||||
// However, to ease public keys length addition operation, we declare it as int and later cast to uit8
|
||||
serializedHandshakeMessageLen := 0
|
||||
// This variables will store the concatenation of the serializations of all public keys in the handshake message
|
||||
serializedHandshakeMessage := make([]byte, 0, 256)
|
||||
serializedHandshakeMessageBuffer := bytes.NewBuffer(serializedHandshakeMessage)
|
||||
|
||||
for _, pk := range p.HandshakeMessage {
|
||||
serializedPK := pk.Serialize()
|
||||
serializedHandshakeMessageLen += len(serializedPK)
|
||||
if _, err := serializedHandshakeMessageBuffer.Write(serializedPK); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if serializedHandshakeMessageLen > MaxUint8 {
|
||||
return nil, errors.New("too many public keys in handshake message")
|
||||
}
|
||||
}
|
||||
|
||||
// The output payload as in https://rfc.vac.dev/spec/35/. We concatenate all the PayloadV2 fields as
|
||||
// payload = ( protocolId || serializedHandshakeMessageLen || serializedHandshakeMessage || transportMessageLen || transportMessage)
|
||||
|
||||
// We declare it as a byte sequence of length accordingly to the PayloadV2 information read
|
||||
payload := make([]byte, 0, MessageNametagLength+
|
||||
1+ // 1 byte for protocol ID
|
||||
1+ // 1 byte for length of serializedHandshakeMessage field
|
||||
serializedHandshakeMessageLen+ // serializedHandshakeMessageLen bytes for serializedHandshakeMessage
|
||||
8+ // 8 bytes for transportMessageLen
|
||||
len(p.TransportMessage), // transportMessageLen bytes for transportMessage
|
||||
)
|
||||
|
||||
payloadBuf := bytes.NewBuffer(payload)
|
||||
|
||||
if _, err := payloadBuf.Write(p.MessageNametag[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// The protocol ID (1 byte) and handshake message length (1 byte) can be directly casted to byte to allow direct copy to the payload byte sequence
|
||||
if err := payloadBuf.WriteByte(p.ProtocolId); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := payloadBuf.WriteByte(byte(serializedHandshakeMessageLen)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := payloadBuf.Write(serializedHandshakeMessageBuffer.Bytes()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
TransportMessageLen := uint64(len(p.TransportMessage))
|
||||
if err := binary.Write(payloadBuf, binary.LittleEndian, TransportMessageLen); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := payloadBuf.Write(p.TransportMessage); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return payloadBuf.Bytes(), nil
|
||||
}
|
||||
|
||||
func isProtocolIDSupported(protocolID WakuNoiseProtocolID) bool {
|
||||
return protocolID == Noise_K1K1_25519_ChaChaPoly_SHA256 ||
|
||||
protocolID == Noise_XK1_25519_ChaChaPoly_SHA256 ||
|
||||
protocolID == Noise_XX_25519_ChaChaPoly_SHA256 ||
|
||||
protocolID == Noise_XXpsk0_25519_ChaChaPoly_SHA256 ||
|
||||
protocolID == ChaChaPoly ||
|
||||
protocolID == Noise_WakuPairing_25519_ChaChaPoly_SHA256 ||
|
||||
protocolID == None
|
||||
}
|
||||
|
||||
const ChaChaPolyTagSize = byte(16)
|
||||
|
||||
// Deserializes a byte sequence to a PayloadV2 object according to https://rfc.vac.dev/spec/35/.
|
||||
// The input serialized payload concatenates the output PayloadV2 object fields as
|
||||
// payload = ( protocolId || serializedHandshakeMessageLen || serializedHandshakeMessage || transportMessageLen || transportMessage)
|
||||
func DeserializePayloadV2(payload []byte) (*PayloadV2, error) {
|
||||
payloadBuf := bytes.NewBuffer(payload)
|
||||
|
||||
result := &PayloadV2{}
|
||||
|
||||
// We start by reading the messageNametag
|
||||
if err := binary.Read(payloadBuf, binary.BigEndian, &result.MessageNametag); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// We read the Protocol ID
|
||||
if err := binary.Read(payloadBuf, binary.BigEndian, &result.ProtocolId); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !isProtocolIDSupported(result.ProtocolId) {
|
||||
return nil, errors.New("unsupported protocol")
|
||||
}
|
||||
|
||||
// We read the Handshake Message length (1 byte)
|
||||
var handshakeMessageLen byte
|
||||
if err := binary.Read(payloadBuf, binary.BigEndian, &handshakeMessageLen); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if handshakeMessageLen > MaxUint8 {
|
||||
return nil, errors.New("too many public keys in handshake message")
|
||||
}
|
||||
|
||||
written := byte(0)
|
||||
var handshakeMessages []*NoisePublicKey
|
||||
for written < handshakeMessageLen {
|
||||
// We obtain the current Noise Public key encryption flag
|
||||
flag, err := payloadBuf.ReadByte()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if flag == 0 {
|
||||
// If the key is unencrypted, we only read the X coordinate of the EC public key and we deserialize into a Noise Public Key
|
||||
pkLen := ed25519.PublicKeySize
|
||||
var pkBytes SerializedNoisePublicKey = make([]byte, pkLen)
|
||||
if err := binary.Read(payloadBuf, binary.BigEndian, &pkBytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
serializedPK := SerializedNoisePublicKey(make([]byte, ed25519.PublicKeySize+1))
|
||||
serializedPK[0] = flag
|
||||
copy(serializedPK[1:], pkBytes)
|
||||
|
||||
pk, err := serializedPK.Unserialize()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
handshakeMessages = append(handshakeMessages, pk)
|
||||
written += uint8(1 + pkLen)
|
||||
} else if flag == 1 {
|
||||
// If the key is encrypted, we only read the encrypted X coordinate and the authorization tag, and we deserialize into a Noise Public Key
|
||||
pkLen := ed25519.PublicKeySize + ChaChaPolyTagSize
|
||||
// TODO: duplicated code: ==============
|
||||
|
||||
var pkBytes SerializedNoisePublicKey = make([]byte, pkLen)
|
||||
if err := binary.Read(payloadBuf, binary.BigEndian, &pkBytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
serializedPK := SerializedNoisePublicKey(make([]byte, ed25519.PublicKeySize+1))
|
||||
serializedPK[0] = flag
|
||||
copy(serializedPK[1:], pkBytes)
|
||||
|
||||
pk, err := serializedPK.Unserialize()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
handshakeMessages = append(handshakeMessages, pk)
|
||||
written += uint8(1 + pkLen)
|
||||
// TODO: duplicated
|
||||
} else {
|
||||
return nil, errors.New("invalid flag for Noise public key")
|
||||
}
|
||||
}
|
||||
|
||||
result.HandshakeMessage = handshakeMessages
|
||||
|
||||
var TransportMessageLen uint64
|
||||
if err := binary.Read(payloadBuf, binary.LittleEndian, &TransportMessageLen); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result.TransportMessage = make([]byte, TransportMessageLen)
|
||||
if err := binary.Read(payloadBuf, binary.BigEndian, &result.TransportMessage); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Decodes a WakuMessage to a PayloadV2
|
||||
// Currently, this is just a wrapper over deserializePayloadV2 and encryption/decryption is done on top (no KeyInfo)
|
||||
func DecodePayloadV2(message *pb.WakuMessage) (*PayloadV2, error) {
|
||||
if message.Version != 2 {
|
||||
return nil, errors.New("wrong message version while decoding payload")
|
||||
}
|
||||
return DeserializePayloadV2(message.Payload)
|
||||
}
|
||||
|
||||
// Encodes a PayloadV2 to a WakuMessage
|
||||
// Currently, this is just a wrapper over serializePayloadV2 and encryption/decryption is done on top (no KeyInfo)
|
||||
func EncodePayloadV2(payload2 *PayloadV2) (*pb.WakuMessage, error) {
|
||||
serializedPayload2, err := payload2.Serialize()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pb.WakuMessage{
|
||||
Payload: serializedPayload2,
|
||||
Version: 2,
|
||||
}, nil
|
||||
}
|
@ -1,209 +0,0 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
n "github.com/waku-org/noise"
|
||||
)
|
||||
|
||||
func TestWakuPairing(t *testing.T) {
|
||||
// Pairing Phase
|
||||
// ==========
|
||||
|
||||
// Alice static/ephemeral key initialization and commitment
|
||||
aliceStaticKey, _ := n.DH25519.GenerateKeypair(rand.Reader)
|
||||
aliceEphemeralKey, _ := n.DH25519.GenerateKeypair(rand.Reader)
|
||||
s := generateRandomBytes(t, 32)
|
||||
aliceCommittedStaticKey := CommitPublicKey(aliceStaticKey.Public, s)
|
||||
|
||||
// Bob static/ephemeral key initialization and commitment
|
||||
bobStaticKey, _ := n.DH25519.GenerateKeypair(rand.Reader)
|
||||
bobEphemeralKey, _ := n.DH25519.GenerateKeypair(rand.Reader)
|
||||
r := generateRandomBytes(t, 32)
|
||||
bobCommittedStaticKey := CommitPublicKey(bobStaticKey.Public, r)
|
||||
|
||||
// Content topic information
|
||||
applicationName := "waku-noise-sessions"
|
||||
applicationVersion := "0.1"
|
||||
shardId := "10"
|
||||
qrMessageNameTag := BytesToMessageNametag(generateRandomBytes(t, MessageNametagLength))
|
||||
|
||||
// Out-of-band Communication
|
||||
|
||||
// Bob prepares the QR and sends it out-of-band to Alice
|
||||
qr := NewQR(applicationName, applicationVersion, shardId, bobEphemeralKey.Public, bobCommittedStaticKey)
|
||||
|
||||
// Alice deserializes the QR code
|
||||
readQR, err := StringToQR(qr.String())
|
||||
require.NoError(t, err)
|
||||
|
||||
// We check if QR serialization/deserialization works
|
||||
require.Equal(t, applicationName, readQR.applicationName)
|
||||
require.Equal(t, applicationVersion, readQR.applicationVersion)
|
||||
require.Equal(t, shardId, readQR.shardId)
|
||||
require.True(t, bytes.Equal(bobEphemeralKey.Public, readQR.ephemeralPublicKey))
|
||||
require.True(t, bytes.Equal(bobCommittedStaticKey[:], readQR.committedStaticKey[:]))
|
||||
|
||||
// Pre-handshake message
|
||||
// <- eB {H(sB||r), contentTopicParams, messageNametag}
|
||||
preMessagePKs := bobEphemeralKey.Public
|
||||
|
||||
// We initialize the Handshake states.
|
||||
// Note that we pass the whole qr serialization as prologue information
|
||||
|
||||
aliceHS, err := NewHandshake_WakuPairing_25519_ChaChaPoly_SHA256(aliceStaticKey, aliceEphemeralKey, true, qr.Bytes(), preMessagePKs)
|
||||
require.NoError(t, err)
|
||||
|
||||
bobHS, err := NewHandshake_WakuPairing_25519_ChaChaPoly_SHA256(bobStaticKey, bobEphemeralKey, false, qr.Bytes(), preMessagePKs)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Pairing Handshake
|
||||
// ==========
|
||||
|
||||
// Write and read calls alternate between Alice and Bob: the handhshake progresses by alternatively calling stepHandshake for each user
|
||||
|
||||
// 1st step
|
||||
// -> eA, eAeB {H(sA||s)} [authcode]
|
||||
|
||||
// The messageNametag for the first handshake message is randomly generated and exchanged out-of-band
|
||||
// and corresponds to qrMessageNametag
|
||||
|
||||
// We set the transport message to be H(sA||s)
|
||||
sentTransportMessage := aliceCommittedStaticKey
|
||||
|
||||
// By being the handshake initiator, Alice writes a Waku2 payload v2 containing her handshake message
|
||||
// and the (encrypted) transport message
|
||||
// The message is sent with a messageNametag equal to the one received through the QR code
|
||||
aliceStep, err := aliceHS.Step(nil, sentTransportMessage, &qrMessageNameTag)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Bob reads Alice's payloads, and returns the (decrypted) transport message Alice sent to him
|
||||
// Note that Bob verifies if the received payloadv2 has the expected messageNametag set
|
||||
bobStep, err := bobHS.Step(&aliceStep.Payload2, nil, &qrMessageNameTag)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.True(t, bytes.Equal(bobStep.TransportMessage, sentTransportMessage))
|
||||
|
||||
// We generate an authorization code using the handshake state
|
||||
aliceAuthcode, err := aliceHS.Authcode()
|
||||
require.NoError(t, err)
|
||||
|
||||
bobAuthcode, err := bobHS.Authcode()
|
||||
require.NoError(t, err)
|
||||
|
||||
// We check that they are equal. Note that this check has to be confirmed with a user interaction.
|
||||
require.Equal(t, aliceAuthcode, bobAuthcode)
|
||||
|
||||
// 2nd step
|
||||
// <- sB, eAsB {r}
|
||||
|
||||
// Alice and Bob update their local next messageNametag using the available handshake information
|
||||
// During the handshake, messageNametag = HKDF(h), where h is the handshake hash value at the end of the last processed message
|
||||
aliceMessageNametag, err := aliceHS.ToMessageNametag()
|
||||
require.NoError(t, err)
|
||||
|
||||
bobMessageNametag, err := bobHS.ToMessageNametag()
|
||||
require.NoError(t, err)
|
||||
|
||||
// We set as a transport message the commitment randomness r
|
||||
sentTransportMessage = r
|
||||
|
||||
// At this step, Bob writes and returns a payload
|
||||
bobStep, err = bobHS.Step(nil, sentTransportMessage, &bobMessageNametag)
|
||||
require.NoError(t, err)
|
||||
|
||||
// While Alice reads and returns the (decrypted) transport message
|
||||
aliceStep, err = aliceHS.Step(&bobStep.Payload2, nil, &aliceMessageNametag)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, aliceStep.TransportMessage, sentTransportMessage)
|
||||
|
||||
// Alice further checks if Bob's commitment opens to Bob's static key she just received
|
||||
expectedBobCommittedStaticKey := CommitPublicKey(aliceHS.RS(), aliceStep.TransportMessage)
|
||||
require.True(t, bytes.Equal(expectedBobCommittedStaticKey, bobCommittedStaticKey))
|
||||
|
||||
// 3rd step
|
||||
// -> sA, sAeB, sAsB {s}
|
||||
|
||||
// Alice and Bob update their local next messageNametag using the available handshake information
|
||||
aliceMessageNametag, err = aliceHS.ToMessageNametag()
|
||||
require.NoError(t, err)
|
||||
|
||||
bobMessageNametag, err = bobHS.ToMessageNametag()
|
||||
require.NoError(t, err)
|
||||
|
||||
// We set as a transport message the commitment randomness s
|
||||
sentTransportMessage = s
|
||||
|
||||
// Similarly as in first step, Alice writes a Waku2 payload containing the handshake message and the (encrypted) transport message
|
||||
aliceStep, err = aliceHS.Step(nil, sentTransportMessage, &aliceMessageNametag)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Bob reads Alice's payloads, and returns the (decrypted) transport message Alice sent to him
|
||||
bobStep, err = bobHS.Step(&aliceStep.Payload2, nil, &bobMessageNametag)
|
||||
require.NoError(t, err)
|
||||
require.True(t, bytes.Equal(bobStep.TransportMessage, sentTransportMessage))
|
||||
|
||||
// Bob further checks if Alice's commitment opens to Alice's static key he just received
|
||||
expectedAliceCommittedStaticKey := CommitPublicKey(bobHS.RS(), bobStep.TransportMessage)
|
||||
|
||||
require.True(t, bytes.Equal(expectedAliceCommittedStaticKey, aliceCommittedStaticKey))
|
||||
|
||||
// Secure Transfer Phase
|
||||
// ==========
|
||||
|
||||
// We test read/write of random messages exchanged between Alice and Bob
|
||||
// Note that we exchange more than the number of messages contained in the nametag buffer to test if they are filled correctly as the communication proceeds
|
||||
for i := 0; i < 10*MessageNametagBufferSize; i++ {
|
||||
// Alice writes to Bob
|
||||
message := generateRandomBytes(t, 32)
|
||||
payload, err := aliceHS.Encrypt(message)
|
||||
require.NoError(t, err)
|
||||
|
||||
readMessage, err := bobHS.Decrypt(payload)
|
||||
require.NoError(t, err)
|
||||
require.True(t, bytes.Equal(message, readMessage))
|
||||
|
||||
// Bob writes to Alice
|
||||
message = generateRandomBytes(t, 32)
|
||||
payload, err = bobHS.Encrypt(message)
|
||||
require.NoError(t, err)
|
||||
|
||||
readMessage, err = aliceHS.Decrypt(payload)
|
||||
require.NoError(t, err)
|
||||
require.True(t, bytes.Equal(message, readMessage))
|
||||
}
|
||||
|
||||
// We test how nametag buffers help in detecting lost messages
|
||||
// Alice writes two messages to Bob, but only the second is received
|
||||
message := generateRandomBytes(t, 32)
|
||||
_, err = aliceHS.Encrypt(message)
|
||||
require.NoError(t, err)
|
||||
|
||||
message = generateRandomBytes(t, 32)
|
||||
payload2, err := aliceHS.Encrypt(message)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = bobHS.Decrypt(payload2)
|
||||
require.Error(t, err)
|
||||
require.ErrorIs(t, err, ErrNametagNotExpected)
|
||||
|
||||
// We adjust bob nametag buffer for next test (i.e. the missed message is correctly recovered)
|
||||
bobHS.nametagsInbound.Delete(2)
|
||||
message = generateRandomBytes(t, 32)
|
||||
payload2, err = bobHS.Encrypt(message)
|
||||
require.NoError(t, err)
|
||||
readMessage, err := aliceHS.Decrypt(payload2)
|
||||
require.NoError(t, err)
|
||||
require.True(t, bytes.Equal(message, readMessage))
|
||||
|
||||
// We test if a missing nametag is correctly detected
|
||||
message = generateRandomBytes(t, 32)
|
||||
payload2, err = aliceHS.Encrypt(message)
|
||||
require.NoError(t, err)
|
||||
bobHS.nametagsInbound.Delete(1)
|
||||
_, err = bobHS.Decrypt(payload2)
|
||||
require.ErrorIs(t, err, ErrNametagNotFound)
|
||||
}
|
@ -5,18 +5,19 @@ import (
|
||||
"context"
|
||||
"crypto/ed25519"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
n "github.com/waku-org/go-noise"
|
||||
"github.com/waku-org/go-waku/waku/v2/protocol/pb"
|
||||
n "github.com/waku-org/noise"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var ErrPairingTimeout = errors.New("pairing has timed out")
|
||||
|
||||
type Sender interface {
|
||||
Publish(ctx context.Context, contentTopic string, payload PayloadV2) error
|
||||
Publish(ctx context.Context, contentTopic string, payload *n.PayloadV2) error
|
||||
}
|
||||
|
||||
type Receiver interface {
|
||||
@ -31,7 +32,7 @@ type Pairing struct {
|
||||
randomFixLenVal []byte
|
||||
myCommittedStaticKey []byte
|
||||
params PairingParameters
|
||||
handshake *Handshake
|
||||
handshake *n.Handshake
|
||||
authCode string
|
||||
authCodeEmitted chan string
|
||||
authCodeConfirmed chan bool
|
||||
@ -40,11 +41,12 @@ type Pairing struct {
|
||||
|
||||
started bool
|
||||
completed bool
|
||||
hsResult *n.HandshakeResult
|
||||
}
|
||||
|
||||
type PairingParameterOption func(*PairingParameters) error
|
||||
|
||||
func WithInitiatorParameters(qrString string, qrMessageNametag MessageNametag) PairingParameterOption {
|
||||
func WithInitiatorParameters(qrString string, qrMessageNametag n.MessageNametag) PairingParameterOption {
|
||||
return func(params *PairingParameters) error {
|
||||
params.initiator = true
|
||||
qr, err := StringToQR(qrString)
|
||||
@ -57,16 +59,16 @@ func WithInitiatorParameters(qrString string, qrMessageNametag MessageNametag) P
|
||||
}
|
||||
}
|
||||
|
||||
func WithResponderParameters(applicationName, applicationVersion, shardId string, qrMessageNameTag *MessageNametag) PairingParameterOption {
|
||||
func WithResponderParameters(applicationName, applicationVersion, shardId string, qrMessageNameTag *n.MessageNametag) PairingParameterOption {
|
||||
return func(params *PairingParameters) error {
|
||||
params.initiator = false
|
||||
if qrMessageNameTag == nil {
|
||||
b := make([]byte, MessageNametagLength)
|
||||
b := make([]byte, n.MessageNametagLength)
|
||||
_, err := rand.Read(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params.qrMessageNametag = BytesToMessageNametag(b)
|
||||
params.qrMessageNametag = n.BytesToMessageNametag(b)
|
||||
} else {
|
||||
params.qrMessageNametag = *qrMessageNameTag
|
||||
}
|
||||
@ -88,17 +90,17 @@ type PairingParameters struct {
|
||||
ephemeralPublicKey ed25519.PublicKey
|
||||
initiator bool
|
||||
qr QR
|
||||
qrMessageNametag MessageNametag
|
||||
qrMessageNametag n.MessageNametag
|
||||
}
|
||||
|
||||
func NewPairing(myStaticKey n.DHKey, myEphemeralKey n.DHKey, opts PairingParameterOption, messenger NoiseMessenger, logger *zap.Logger) (*Pairing, error) {
|
||||
func NewPairing(myStaticKey n.Keypair, myEphemeralKey n.Keypair, opts PairingParameterOption, messenger NoiseMessenger, logger *zap.Logger) (*Pairing, error) {
|
||||
b := make([]byte, 32)
|
||||
_, err := rand.Read(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
myCommitedStaticKey := CommitPublicKey(myStaticKey.Public, b)
|
||||
myCommitedStaticKey := n.CommitPublicKey(sha256.New, myStaticKey.Public, b)
|
||||
|
||||
var params PairingParameters
|
||||
params.myCommitedStaticKey = myCommitedStaticKey
|
||||
@ -108,8 +110,7 @@ func NewPairing(myStaticKey n.DHKey, myEphemeralKey n.DHKey, opts PairingParamet
|
||||
return nil, err
|
||||
}
|
||||
|
||||
preMessagePKs := params.qr.ephemeralPublicKey
|
||||
hs, err := NewHandshake_WakuPairing_25519_ChaChaPoly_SHA256(myStaticKey, myEphemeralKey, params.initiator, params.qr.Bytes(), preMessagePKs)
|
||||
hs, err := n.NewHandshake_WakuPairing_25519_ChaChaPoly_SHA256(myStaticKey, myEphemeralKey, params.initiator, params.qr.Bytes(), params.qr.ephemeralPublicKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -133,7 +134,7 @@ func NewPairing(myStaticKey n.DHKey, myEphemeralKey n.DHKey, opts PairingParamet
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *Pairing) PairingInfo() (qrString string, qrMessageNametag MessageNametag) {
|
||||
func (p *Pairing) PairingInfo() (qrString string, qrMessageNametag n.MessageNametag) {
|
||||
p.RLock()
|
||||
defer p.RUnlock()
|
||||
return p.params.qr.String(), p.params.qrMessageNametag
|
||||
@ -180,7 +181,7 @@ func (p *Pairing) isAuthCodeConfirmed(ctx context.Context) (bool, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Pairing) executeReadStepWithNextMessage(ctx context.Context, nextMsgChan <-chan *pb.WakuMessage, messageNametag MessageNametag) (*HandshakeStepResult, error) {
|
||||
func (p *Pairing) executeReadStepWithNextMessage(ctx context.Context, nextMsgChan <-chan *pb.WakuMessage, messageNametag n.MessageNametag) (*n.HandshakeStepResult, error) {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
@ -191,9 +192,9 @@ func (p *Pairing) executeReadStepWithNextMessage(ctx context.Context, nextMsgCha
|
||||
return nil, err
|
||||
}
|
||||
|
||||
step, err := p.handshake.Step(payload, nil, &messageNametag)
|
||||
step, err := p.handshake.Step(payload, nil, messageNametag)
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrNametagNotExpected) {
|
||||
if errors.Is(err, n.ErrNametagNotExpected) || errors.Is(err, n.ErrUnexpectedMessageNametag) {
|
||||
p.logger.Debug(err.Error())
|
||||
continue
|
||||
} else {
|
||||
@ -210,11 +211,10 @@ func (p *Pairing) initiatorHandshake(ctx context.Context, msgCh <-chan *pb.WakuM
|
||||
|
||||
go func() {
|
||||
defer close(doneCh)
|
||||
|
||||
// The handshake initiator writes a Waku2 payload v2 containing the handshake message
|
||||
// and the (encrypted) transport message
|
||||
// The message is sent with a messageNametag equal to the one received through the QR code
|
||||
hsStep, err := p.handshake.Step(nil, p.myCommittedStaticKey, &p.params.qrMessageNametag)
|
||||
hsStep, err := p.handshake.Step(nil, p.myCommittedStaticKey, p.params.qrMessageNametag)
|
||||
if err != nil {
|
||||
doneCh <- err
|
||||
return
|
||||
@ -222,12 +222,11 @@ func (p *Pairing) initiatorHandshake(ctx context.Context, msgCh <-chan *pb.WakuM
|
||||
|
||||
// We prepare a message from initiator's payload2
|
||||
// At this point wakuMsg is sent over the Waku network to receiver content topic
|
||||
err = p.messenger.Publish(ctx, p.ContentTopic, hsStep.Payload2)
|
||||
err = p.messenger.Publish(ctx, p.ContentTopic, hsStep.PayloadV2)
|
||||
if err != nil {
|
||||
doneCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
// We generate an authorization code using the handshake state
|
||||
// this check has to be confirmed with a user interaction, comparing auth codes in both ends
|
||||
authCode, err := p.handshake.Authcode()
|
||||
@ -270,7 +269,7 @@ func (p *Pairing) initiatorHandshake(ctx context.Context, msgCh <-chan *pb.WakuM
|
||||
}
|
||||
|
||||
// Initiator further checks if receiver's commitment opens to receiver's static key received
|
||||
expectedReceiverCommittedStaticKey := CommitPublicKey(p.handshake.RS(), hsStep.TransportMessage)
|
||||
expectedReceiverCommittedStaticKey := n.CommitPublicKey(sha256.New, p.handshake.RemoteStaticPublicKey(), hsStep.TransportMessage)
|
||||
if !bytes.Equal(expectedReceiverCommittedStaticKey, p.params.qr.committedStaticKey) {
|
||||
doneCh <- errors.New("expected committed static key does not match the receiver actual committed static key")
|
||||
return
|
||||
@ -285,25 +284,32 @@ func (p *Pairing) initiatorHandshake(ctx context.Context, msgCh <-chan *pb.WakuM
|
||||
return
|
||||
}
|
||||
|
||||
hsStep, err = p.handshake.Step(nil, p.randomFixLenVal, &hsMessageNametag)
|
||||
hsStep, err = p.handshake.Step(nil, p.randomFixLenVal, hsMessageNametag)
|
||||
if err != nil {
|
||||
doneCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
err = p.messenger.Publish(ctx, p.ContentTopic, hsStep.Payload2)
|
||||
err = p.messenger.Publish(ctx, p.ContentTopic, hsStep.PayloadV2)
|
||||
if err != nil {
|
||||
doneCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
hsResult, err := p.handshake.FinalizeHandshake()
|
||||
if err != nil {
|
||||
doneCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
// Secure Transfer Phase
|
||||
if !p.handshake.HandshakeComplete() {
|
||||
if !p.handshake.IsComplete() {
|
||||
doneCh <- errors.New("handshake is in undefined state")
|
||||
return
|
||||
}
|
||||
|
||||
p.Lock()
|
||||
p.hsResult = hsResult
|
||||
p.completed = true
|
||||
p.Unlock()
|
||||
}()
|
||||
@ -363,14 +369,14 @@ func (p *Pairing) responderHandshake(ctx context.Context, msgCh <-chan *pb.WakuM
|
||||
return
|
||||
}
|
||||
|
||||
hsStep, err = p.handshake.Step(nil, p.randomFixLenVal, &hsMessageNametag)
|
||||
hsStep, err = p.handshake.Step(nil, p.randomFixLenVal, hsMessageNametag)
|
||||
if err != nil {
|
||||
doneCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
// We prepare a Waku message from receiver's payload2
|
||||
err = p.messenger.Publish(ctx, p.ContentTopic, hsStep.Payload2)
|
||||
err = p.messenger.Publish(ctx, p.ContentTopic, hsStep.PayloadV2)
|
||||
if err != nil {
|
||||
doneCh <- err
|
||||
return
|
||||
@ -392,20 +398,27 @@ func (p *Pairing) responderHandshake(ctx context.Context, msgCh <-chan *pb.WakuM
|
||||
}
|
||||
|
||||
// The receiver further checks if the initiator's commitment opens to the initiator's static key received
|
||||
expectedInitiatorCommittedStaticKey := CommitPublicKey(p.handshake.RS(), hsStep.TransportMessage)
|
||||
expectedInitiatorCommittedStaticKey := n.CommitPublicKey(sha256.New, p.handshake.RemoteStaticPublicKey(), hsStep.TransportMessage)
|
||||
if !bytes.Equal(expectedInitiatorCommittedStaticKey, initiatorCommittedStaticKey) {
|
||||
doneCh <- errors.New("expected committed static key does not match the initiator actual committed static key")
|
||||
return
|
||||
}
|
||||
|
||||
hsResult, err := p.handshake.FinalizeHandshake()
|
||||
if err != nil {
|
||||
doneCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
// Secure Transfer Phase
|
||||
if !p.handshake.HandshakeComplete() {
|
||||
if !p.handshake.IsComplete() {
|
||||
doneCh <- errors.New("handshake is in undefined state")
|
||||
return
|
||||
}
|
||||
|
||||
p.Lock()
|
||||
p.completed = true
|
||||
p.hsResult = hsResult
|
||||
p.Unlock()
|
||||
}()
|
||||
return doneCh
|
||||
@ -419,20 +432,39 @@ func (p *Pairing) HandshakeComplete() bool {
|
||||
|
||||
// Returns a WakuMessage with version 2 and encrypted payload
|
||||
func (p *Pairing) Encrypt(plaintext []byte) (*pb.WakuMessage, error) {
|
||||
payload, err := p.handshake.Encrypt(plaintext)
|
||||
p.RLock()
|
||||
defer p.RUnlock()
|
||||
if !p.completed {
|
||||
return nil, errors.New("pairing is not complete")
|
||||
}
|
||||
|
||||
payload, err := p.hsResult.WriteMessage(plaintext, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return EncodePayloadV2(payload)
|
||||
encodedPayload, err := EncodePayloadV2(payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
encodedPayload.ContentTopic = p.ContentTopic
|
||||
|
||||
return encodedPayload, nil
|
||||
}
|
||||
|
||||
func (p *Pairing) Decrypt(msg *pb.WakuMessage) ([]byte, error) {
|
||||
p.RLock()
|
||||
defer p.RUnlock()
|
||||
if !p.completed {
|
||||
return nil, errors.New("pairing is not complete")
|
||||
}
|
||||
|
||||
payload, err := DecodePayloadV2(msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p.handshake.Decrypt(payload)
|
||||
return p.hsResult.ReadMessage(payload, nil)
|
||||
}
|
||||
|
||||
func (p *Pairing) ConfirmAuthCode(confirmed bool) error {
|
@ -3,6 +3,7 @@ package noise
|
||||
import (
|
||||
"context"
|
||||
|
||||
n "github.com/waku-org/go-noise"
|
||||
v2 "github.com/waku-org/go-waku/waku/v2"
|
||||
"github.com/waku-org/go-waku/waku/v2/protocol"
|
||||
"github.com/waku-org/go-waku/waku/v2/protocol/pb"
|
||||
@ -110,9 +111,9 @@ func (r *NoiseWakuRelay) Subscribe(ctx context.Context, contentTopic string) <-c
|
||||
return sub.msgChan
|
||||
}
|
||||
|
||||
func (r *NoiseWakuRelay) Publish(ctx context.Context, contentTopic string, payload PayloadV2) error {
|
||||
func (r *NoiseWakuRelay) Publish(ctx context.Context, contentTopic string, payload *n.PayloadV2) error {
|
||||
|
||||
message, err := EncodePayloadV2(&payload)
|
||||
message, err := EncodePayloadV2(payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
@ -11,12 +11,12 @@ import (
|
||||
"github.com/libp2p/go-libp2p/core/host"
|
||||
"github.com/libp2p/go-libp2p/core/peerstore"
|
||||
"github.com/stretchr/testify/require"
|
||||
n "github.com/waku-org/go-noise"
|
||||
"github.com/waku-org/go-waku/tests"
|
||||
v2 "github.com/waku-org/go-waku/waku/v2"
|
||||
"github.com/waku-org/go-waku/waku/v2/protocol/relay"
|
||||
"github.com/waku-org/go-waku/waku/v2/timesource"
|
||||
"github.com/waku-org/go-waku/waku/v2/utils"
|
||||
n "github.com/waku-org/noise"
|
||||
)
|
||||
|
||||
func createRelayNode(t *testing.T) (host.Host, *relay.WakuRelay) {
|
||||
@ -49,8 +49,8 @@ func TestPairingObj1Success(t *testing.T) {
|
||||
|
||||
time.Sleep(2 * time.Second) // Wait for relay to form mesh
|
||||
|
||||
bobStaticKey, _ := n.DH25519.GenerateKeypair(rand.Reader)
|
||||
bobEphemeralKey, _ := n.DH25519.GenerateKeypair(rand.Reader)
|
||||
bobStaticKey, _ := n.DH25519.GenerateKeypair()
|
||||
bobEphemeralKey, _ := n.DH25519.GenerateKeypair()
|
||||
|
||||
bobMessenger, err := NewWakuRelayMessenger(context.Background(), relay1, nil, timesource.NewDefaultClock())
|
||||
require.NoError(t, err)
|
||||
@ -91,8 +91,8 @@ func TestPairingObj1Success(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
}()
|
||||
|
||||
aliceStaticKey, _ := n.DH25519.GenerateKeypair(rand.Reader)
|
||||
aliceEphemeralKey, _ := n.DH25519.GenerateKeypair(rand.Reader)
|
||||
aliceStaticKey, _ := n.DH25519.GenerateKeypair()
|
||||
aliceEphemeralKey, _ := n.DH25519.GenerateKeypair()
|
||||
|
||||
aliceMessenger, err := NewWakuRelayMessenger(context.Background(), relay2, nil, timesource.NewDefaultClock())
|
||||
require.NoError(t, err)
|
||||
@ -126,7 +126,7 @@ func TestPairingObj1Success(t *testing.T) {
|
||||
// We test read/write of random messages exchanged between Alice and Bob
|
||||
// Note that we exchange more than the number of messages contained in the nametag buffer to test if they are filled correctly as the communication proceeds
|
||||
// We assume messages are sent via one of waku protocols
|
||||
for i := 0; i < 10*MessageNametagBufferSize; i++ {
|
||||
for i := 0; i < 10*n.MessageNametagBufferSize; i++ {
|
||||
// Alice writes to Bob
|
||||
message := generateRandomBytes(t, 32)
|
||||
msg, err := alicePairingObj.Encrypt(message)
|
||||
@ -165,8 +165,8 @@ func TestPairingObj1ShouldTimeout(t *testing.T) {
|
||||
|
||||
time.Sleep(2 * time.Second) // Wait for relay to form mesh
|
||||
|
||||
bobStaticKey, _ := n.DH25519.GenerateKeypair(rand.Reader)
|
||||
bobEphemeralKey, _ := n.DH25519.GenerateKeypair(rand.Reader)
|
||||
bobStaticKey, _ := n.DH25519.GenerateKeypair()
|
||||
bobEphemeralKey, _ := n.DH25519.GenerateKeypair()
|
||||
|
||||
bobMessenger, err := NewWakuRelayMessenger(context.Background(), relay1, nil, timesource.NewDefaultClock())
|
||||
require.NoError(t, err)
|
||||
@ -174,8 +174,8 @@ func TestPairingObj1ShouldTimeout(t *testing.T) {
|
||||
bobPairingObj, err := NewPairing(bobStaticKey, bobEphemeralKey, WithDefaultResponderParameters(), bobMessenger, utils.Logger())
|
||||
require.NoError(t, err)
|
||||
|
||||
aliceStaticKey, _ := n.DH25519.GenerateKeypair(rand.Reader)
|
||||
aliceEphemeralKey, _ := n.DH25519.GenerateKeypair(rand.Reader)
|
||||
aliceStaticKey, _ := n.DH25519.GenerateKeypair()
|
||||
aliceEphemeralKey, _ := n.DH25519.GenerateKeypair()
|
||||
|
||||
aliceMessenger, err := NewWakuRelayMessenger(context.Background(), relay2, nil, timesource.NewDefaultClock())
|
||||
require.NoError(t, err)
|
31
waku/v2/protocol/noise/payload.go
Normal file
31
waku/v2/protocol/noise/payload.go
Normal file
@ -0,0 +1,31 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
n "github.com/waku-org/go-noise"
|
||||
"github.com/waku-org/go-waku/waku/v2/protocol/pb"
|
||||
)
|
||||
|
||||
// Decodes a WakuMessage to a PayloadV2
|
||||
// Currently, this is just a wrapper over deserializePayloadV2 and encryption/decryption is done on top (no KeyInfo)
|
||||
func DecodePayloadV2(message *pb.WakuMessage) (*n.PayloadV2, error) {
|
||||
if message.Version != 2 {
|
||||
return nil, errors.New("wrong message version while decoding payload")
|
||||
}
|
||||
return n.DeserializePayloadV2(message.Payload)
|
||||
}
|
||||
|
||||
// Encodes a PayloadV2 to a WakuMessage
|
||||
// Currently, this is just a wrapper over serializePayloadV2 and encryption/decryption is done on top (no KeyInfo)
|
||||
func EncodePayloadV2(payload2 *n.PayloadV2) (*pb.WakuMessage, error) {
|
||||
serializedPayload2, err := payload2.Serialize()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pb.WakuMessage{
|
||||
Payload: serializedPayload2,
|
||||
Version: 2,
|
||||
}, nil
|
||||
}
|
41
waku/v2/protocol/noise/qr_test.go
Normal file
41
waku/v2/protocol/noise/qr_test.go
Normal file
@ -0,0 +1,41 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
n "github.com/waku-org/go-noise"
|
||||
)
|
||||
|
||||
func generateRandomBytes(t *testing.T, n int) []byte {
|
||||
b := make([]byte, n)
|
||||
_, err := rand.Read(b)
|
||||
require.NoError(t, err)
|
||||
return b
|
||||
}
|
||||
|
||||
func TestQR(t *testing.T) {
|
||||
staticKey, _ := n.DH25519.GenerateKeypair()
|
||||
ephemeralKey, _ := n.DH25519.GenerateKeypair()
|
||||
r := generateRandomBytes(t, 32)
|
||||
committedStaticKey := n.CommitPublicKey(sha256.New, staticKey.Public, r)
|
||||
|
||||
// Content topic information
|
||||
applicationName := "waku-noise-sessions"
|
||||
applicationVersion := "0.1"
|
||||
shardId := "10"
|
||||
|
||||
qr := NewQR(applicationName, applicationVersion, shardId, ephemeralKey.Public, committedStaticKey)
|
||||
readQR, err := StringToQR(qr.String())
|
||||
require.NoError(t, err)
|
||||
|
||||
// We check if QR serialization/deserialization works
|
||||
require.Equal(t, applicationName, readQR.applicationName)
|
||||
require.Equal(t, applicationVersion, readQR.applicationVersion)
|
||||
require.Equal(t, shardId, readQR.shardId)
|
||||
require.True(t, bytes.Equal(ephemeralKey.Public, readQR.ephemeralPublicKey))
|
||||
require.True(t, bytes.Equal(committedStaticKey[:], readQR.committedStaticKey[:]))
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user