aboutsummaryrefslogtreecommitdiffstats
path: root/whisper
diff options
context:
space:
mode:
authorgluk256 <gluk256@users.noreply.github.com>2017-04-27 03:05:48 +0800
committerFelix Lange <fjl@users.noreply.github.com>2017-04-27 03:05:48 +0800
commit95f0bd0acf301bf8415747c4ff050e8a4dfdc864 (patch)
tree13edad970fb30a8e12151b2ec1a443b0ad970d2b /whisper
parent8dce4c283dda3a8e10aa30dadab05a8c0dd9e19d (diff)
downloaddexon-95f0bd0acf301bf8415747c4ff050e8a4dfdc864.tar.gz
dexon-95f0bd0acf301bf8415747c4ff050e8a4dfdc864.tar.zst
dexon-95f0bd0acf301bf8415747c4ff050e8a4dfdc864.zip
whisper: message format refactoring (#14335)
* whisper: salt removed from AES encryption * whisper: padding format updated * whisper: padding test added * whisper: padding refactored, tests fixed * whisper: padding test updated * whisper: wnode bugfix * whisper: send/receive protocol updated * whisper: minor update * whisper: bugfix in test * whisper: updated parameter names and comments * whisper: functions renamed * whisper: minor refactoring
Diffstat (limited to 'whisper')
-rw-r--r--whisper/mailserver/server_test.go13
-rw-r--r--whisper/whisperv5/api.go47
-rw-r--r--whisper/whisperv5/api_test.go8
-rw-r--r--whisper/whisperv5/benchmarks_test.go20
-rw-r--r--whisper/whisperv5/doc.go16
-rw-r--r--whisper/whisperv5/envelope.go27
-rw-r--r--whisper/whisperv5/filter_test.go39
-rw-r--r--whisper/whisperv5/message.go133
-rw-r--r--whisper/whisperv5/message_test.go140
-rw-r--r--whisper/whisperv5/peer.go21
-rw-r--r--whisper/whisperv5/peer_test.go10
-rw-r--r--whisper/whisperv5/whisper.go55
-rw-r--r--whisper/whisperv5/whisper_test.go15
13 files changed, 326 insertions, 218 deletions
diff --git a/whisper/mailserver/server_test.go b/whisper/mailserver/server_test.go
index 15652ea4a..64dbcd783 100644
--- a/whisper/mailserver/server_test.go
+++ b/whisper/mailserver/server_test.go
@@ -58,15 +58,19 @@ func TestDBKey(t *testing.T) {
}
func generateEnvelope(t *testing.T) *whisper.Envelope {
+ h := crypto.Keccak256Hash([]byte("test sample data"))
params := &whisper.MessageParams{
- KeySym: []byte("test key"),
+ KeySym: h[:],
Topic: whisper.TopicType{},
Payload: []byte("test payload"),
PoW: powRequirement,
WorkTime: 2,
}
- msg := whisper.NewSentMessage(params)
+ msg, err := whisper.NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err := msg.Wrap(params)
if err != nil {
t.Fatalf("failed to wrap with seed %d: %s.", seed, err)
@@ -188,7 +192,10 @@ func createRequest(t *testing.T, p *ServerTestParams) *whisper.Envelope {
Src: p.key,
}
- msg := whisper.NewSentMessage(params)
+ msg, err := whisper.NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err := msg.Wrap(params)
if err != nil {
t.Fatalf("failed to wrap with seed %d: %s.", seed, err)
diff --git a/whisper/whisperv5/api.go b/whisper/whisperv5/api.go
index 579efba9e..841bbc2ba 100644
--- a/whisper/whisperv5/api.go
+++ b/whisper/whisperv5/api.go
@@ -214,7 +214,6 @@ func (api *PublicWhisperAPI) Subscribe(args WhisperFilterArgs) (string, error) {
}
filter := Filter{
- Src: crypto.ToECDSAPub(common.FromHex(args.SignedWith)),
PoW: args.MinPoW,
Messages: make(map[common.Hash]*ReceivedMessage),
AllowP2P: args.AllowP2P,
@@ -233,6 +232,11 @@ func (api *PublicWhisperAPI) Subscribe(args WhisperFilterArgs) (string, error) {
}
if len(args.SignedWith) > 0 {
+ sb := common.FromHex(args.SignedWith)
+ if sb == nil {
+ return "", errors.New("subscribe: SignedWith parameter is invalid")
+ }
+ filter.Src = crypto.ToECDSAPub(sb)
if !ValidatePublicKey(filter.Src) {
return "", errors.New("subscribe: invalid 'SignedWith' field")
}
@@ -269,9 +273,10 @@ func (api *PublicWhisperAPI) Unsubscribe(id string) {
api.whisper.Unsubscribe(id)
}
-// GetSubscriptionMessages retrieves all the new messages matched by a filter since the last retrieval.
-func (api *PublicWhisperAPI) GetSubscriptionMessages(filterId string) []*WhisperMessage {
- f := api.whisper.GetFilter(filterId)
+// GetSubscriptionMessages retrieves all the new messages matched by the corresponding
+// subscription filter since the last retrieval.
+func (api *PublicWhisperAPI) GetNewSubscriptionMessages(id string) []*WhisperMessage {
+ f := api.whisper.GetFilter(id)
if f != nil {
newMail := f.Retrieve()
return toWhisperMessages(newMail)
@@ -279,10 +284,10 @@ func (api *PublicWhisperAPI) GetSubscriptionMessages(filterId string) []*Whisper
return toWhisperMessages(nil)
}
-// GetMessages retrieves all the floating messages that match a specific filter.
+// GetMessages retrieves all the floating messages that match a specific subscription filter.
// It is likely to be called once per session, right after Subscribe call.
-func (api *PublicWhisperAPI) GetMessages(filterId string) []*WhisperMessage {
- all := api.whisper.Messages(filterId)
+func (api *PublicWhisperAPI) GetFloatingMessages(id string) []*WhisperMessage {
+ all := api.whisper.Messages(id)
return toWhisperMessages(all)
}
@@ -345,7 +350,11 @@ func (api *PublicWhisperAPI) Post(args PostArgs) error {
return errors.New("post: topic is missing for symmetric encryption")
}
} else if args.Type == "asym" {
- params.Dst = crypto.ToECDSAPub(common.FromHex(args.Key))
+ kb := common.FromHex(args.Key)
+ if kb == nil {
+ return errors.New("post: public key for asymmetric encryption is invalid")
+ }
+ params.Dst = crypto.ToECDSAPub(kb)
if !ValidatePublicKey(params.Dst) {
return errors.New("post: public key for asymmetric encryption is invalid")
}
@@ -354,9 +363,9 @@ func (api *PublicWhisperAPI) Post(args PostArgs) error {
}
// encrypt and send
- message := NewSentMessage(&params)
- if message == nil {
- return errors.New("post: failed create new message, probably due to failed rand function (OS level)")
+ message, err := NewSentMessage(&params)
+ if err != nil {
+ return err
}
envelope, err := message.Wrap(&params)
if err != nil {
@@ -383,7 +392,7 @@ type PostArgs struct {
Type string `json:"type"` // "sym"/"asym" (symmetric or asymmetric)
TTL uint32 `json:"ttl"` // time-to-live in seconds
SignWith string `json:"signWith"` // id of the signing key
- Key string `json:"key"` // id of encryption key
+ Key string `json:"key"` // key id (in case of sym) or public key (in case of asym)
Topic hexutil.Bytes `json:"topic"` // topic (4 bytes)
Padding hexutil.Bytes `json:"padding"` // optional padding bytes
Payload hexutil.Bytes `json:"payload"` // payload to be encrypted
@@ -474,7 +483,6 @@ type WhisperMessage struct {
// NewWhisperMessage converts an internal message into an API version.
func NewWhisperMessage(message *ReceivedMessage) *WhisperMessage {
msg := WhisperMessage{
- Topic: common.ToHex(message.Topic[:]),
Payload: common.ToHex(message.Payload),
Padding: common.ToHex(message.Padding),
Timestamp: message.Sent,
@@ -483,11 +491,20 @@ func NewWhisperMessage(message *ReceivedMessage) *WhisperMessage {
Hash: common.ToHex(message.EnvelopeHash.Bytes()),
}
+ if len(message.Topic) == TopicLength {
+ msg.Topic = common.ToHex(message.Topic[:])
+ }
if message.Dst != nil {
- msg.Dst = common.ToHex(crypto.FromECDSAPub(message.Dst))
+ b := crypto.FromECDSAPub(message.Dst)
+ if b != nil {
+ msg.Dst = common.ToHex(b)
+ }
}
if isMessageSigned(message.Raw[0]) {
- msg.Src = common.ToHex(crypto.FromECDSAPub(message.SigToPubKey()))
+ b := crypto.FromECDSAPub(message.SigToPubKey())
+ if b != nil {
+ msg.Src = common.ToHex(b)
+ }
}
return &msg
}
diff --git a/whisper/whisperv5/api_test.go b/whisper/whisperv5/api_test.go
index 9207c6f10..c837b0a14 100644
--- a/whisper/whisperv5/api_test.go
+++ b/whisper/whisperv5/api_test.go
@@ -43,7 +43,7 @@ func TestBasic(t *testing.T) {
t.Fatalf("wrong version: %d.", ver)
}
- mail := api.GetSubscriptionMessages("non-existent-id")
+ mail := api.GetNewSubscriptionMessages("non-existent-id")
if len(mail) != 0 {
t.Fatalf("failed GetFilterChanges: premature result")
}
@@ -282,7 +282,7 @@ func waitForMessages(api *PublicWhisperAPI, id string, target int) []*WhisperMes
// timeout: 2 seconds
result := make([]*WhisperMessage, 0, target)
for i := 0; i < 100; i++ {
- mail := api.GetSubscriptionMessages(id)
+ mail := api.GetNewSubscriptionMessages(id)
if len(mail) > 0 {
for _, m := range mail {
result = append(result, m)
@@ -448,7 +448,7 @@ func TestIntegrationSym(t *testing.T) {
f.Topics = make([][]byte, 2)
f.Topics[0] = topics[0][:]
f.Topics[1] = topics[1][:]
- f.MinPoW = 0.324
+ f.MinPoW = DefaultMinimumPoW / 2
f.SignedWith = sigPubKey.String()
f.AllowP2P = false
@@ -546,7 +546,7 @@ func TestIntegrationSymWithFilter(t *testing.T) {
f.Topics = make([][]byte, 2)
f.Topics[0] = topics[0][:]
f.Topics[1] = topics[1][:]
- f.MinPoW = 0.324
+ f.MinPoW = DefaultMinimumPoW / 2
f.SignedWith = sigPubKey.String()
f.AllowP2P = false
diff --git a/whisper/whisperv5/benchmarks_test.go b/whisper/whisperv5/benchmarks_test.go
index 417b2881b..dcfbcb56d 100644
--- a/whisper/whisperv5/benchmarks_test.go
+++ b/whisper/whisperv5/benchmarks_test.go
@@ -28,12 +28,6 @@ func BenchmarkDeriveKeyMaterial(b *testing.B) {
}
}
-func BenchmarkDeriveOneTimeKey(b *testing.B) {
- for i := 0; i < b.N; i++ {
- DeriveOneTimeKey([]byte("test value 1"), []byte("test value 2"), 0)
- }
-}
-
func BenchmarkEncryptionSym(b *testing.B) {
InitSingleTest()
@@ -43,7 +37,7 @@ func BenchmarkEncryptionSym(b *testing.B) {
}
for i := 0; i < b.N; i++ {
- msg := NewSentMessage(params)
+ msg, _ := NewSentMessage(params)
_, err := msg.Wrap(params)
if err != nil {
b.Errorf("failed Wrap with seed %d: %s.", seed, err)
@@ -68,7 +62,7 @@ func BenchmarkEncryptionAsym(b *testing.B) {
params.Dst = &key.PublicKey
for i := 0; i < b.N; i++ {
- msg := NewSentMessage(params)
+ msg, _ := NewSentMessage(params)
_, err := msg.Wrap(params)
if err != nil {
b.Fatalf("failed Wrap with seed %d: %s.", seed, err)
@@ -83,7 +77,7 @@ func BenchmarkDecryptionSymValid(b *testing.B) {
if err != nil {
b.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
}
- msg := NewSentMessage(params)
+ msg, _ := NewSentMessage(params)
env, err := msg.Wrap(params)
if err != nil {
b.Fatalf("failed Wrap with seed %d: %s.", seed, err)
@@ -105,7 +99,7 @@ func BenchmarkDecryptionSymInvalid(b *testing.B) {
if err != nil {
b.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
}
- msg := NewSentMessage(params)
+ msg, _ := NewSentMessage(params)
env, err := msg.Wrap(params)
if err != nil {
b.Fatalf("failed Wrap with seed %d: %s.", seed, err)
@@ -134,7 +128,7 @@ func BenchmarkDecryptionAsymValid(b *testing.B) {
f := Filter{KeyAsym: key}
params.KeySym = nil
params.Dst = &key.PublicKey
- msg := NewSentMessage(params)
+ msg, _ := NewSentMessage(params)
env, err := msg.Wrap(params)
if err != nil {
b.Fatalf("failed Wrap with seed %d: %s.", seed, err)
@@ -161,7 +155,7 @@ func BenchmarkDecryptionAsymInvalid(b *testing.B) {
}
params.KeySym = nil
params.Dst = &key.PublicKey
- msg := NewSentMessage(params)
+ msg, _ := NewSentMessage(params)
env, err := msg.Wrap(params)
if err != nil {
b.Fatalf("failed Wrap with seed %d: %s.", seed, err)
@@ -203,7 +197,7 @@ func BenchmarkPoW(b *testing.B) {
for i := 0; i < b.N; i++ {
increment(params.Payload)
- msg := NewSentMessage(params)
+ msg, _ := NewSentMessage(params)
_, err := msg.Wrap(params)
if err != nil {
b.Fatalf("failed Wrap with seed %d: %s.", seed, err)
diff --git a/whisper/whisperv5/doc.go b/whisper/whisperv5/doc.go
index d60868f67..768291a16 100644
--- a/whisper/whisperv5/doc.go
+++ b/whisper/whisperv5/doc.go
@@ -49,18 +49,16 @@ const (
paddingMask = byte(3)
signatureFlag = byte(4)
- TopicLength = 4
- signatureLength = 65
- aesKeyLength = 32
- saltLength = 12
- AESNonceMaxLength = 12
- keyIdSize = 32
+ TopicLength = 4
+ signatureLength = 65
+ aesKeyLength = 32
+ AESNonceLength = 12
+ keyIdSize = 32
DefaultMaxMessageLength = 1024 * 1024
- DefaultMinimumPoW = 1.0 // todo: review after testing.
+ DefaultMinimumPoW = 0.2
- padSizeLimitLower = 128 // it can not be less - we don't want to reveal the absence of signature
- padSizeLimitUpper = 256 // just an arbitrary number, could be changed without losing compatibility
+ padSizeLimit = 256 // just an arbitrary number, could be changed without breaking the protocol (must not exceed 2^24)
messageQueueLimit = 1024
expirationCycle = time.Second
diff --git a/whisper/whisperv5/envelope.go b/whisper/whisperv5/envelope.go
index dffa7b286..d95fcab75 100644
--- a/whisper/whisperv5/envelope.go
+++ b/whisper/whisperv5/envelope.go
@@ -40,7 +40,6 @@ type Envelope struct {
Expiry uint32
TTL uint32
Topic TopicType
- Salt []byte
AESNonce []byte
Data []byte
EnvNonce uint64
@@ -50,15 +49,25 @@ type Envelope struct {
// Don't access hash directly, use Hash() function instead.
}
+// size returns the size of envelope as it is sent (i.e. public fields only)
+func (e *Envelope) size() int {
+ return 20 + len(e.Version) + len(e.AESNonce) + len(e.Data)
+}
+
+// rlpWithoutNonce returns the RLP encoded envelope contents, except the nonce.
+func (e *Envelope) rlpWithoutNonce() []byte {
+ res, _ := rlp.EncodeToBytes([]interface{}{e.Version, e.Expiry, e.TTL, e.Topic, e.AESNonce, e.Data})
+ return res
+}
+
// NewEnvelope wraps a Whisper message with expiration and destination data
// included into an envelope for network forwarding.
-func NewEnvelope(ttl uint32, topic TopicType, salt []byte, aesNonce []byte, msg *SentMessage) *Envelope {
+func NewEnvelope(ttl uint32, topic TopicType, aesNonce []byte, msg *SentMessage) *Envelope {
env := Envelope{
Version: make([]byte, 1),
Expiry: uint32(time.Now().Add(time.Second * time.Duration(ttl)).Unix()),
TTL: ttl,
Topic: topic,
- Salt: salt,
AESNonce: aesNonce,
Data: msg.Raw,
EnvNonce: 0,
@@ -126,10 +135,6 @@ func (e *Envelope) Seal(options *MessageParams) error {
return nil
}
-func (e *Envelope) size() int {
- return len(e.Data) + len(e.Version) + len(e.AESNonce) + len(e.Salt) + 20
-}
-
func (e *Envelope) PoW() float64 {
if e.pow == 0 {
e.calculatePoW(0)
@@ -159,12 +164,6 @@ func (e *Envelope) powToFirstBit(pow float64) int {
return int(bits)
}
-// rlpWithoutNonce returns the RLP encoded envelope contents, except the nonce.
-func (e *Envelope) rlpWithoutNonce() []byte {
- res, _ := rlp.EncodeToBytes([]interface{}{e.Expiry, e.TTL, e.Topic, e.Salt, e.AESNonce, e.Data})
- return res
-}
-
// Hash returns the SHA3 hash of the envelope, calculating it if not yet done.
func (e *Envelope) Hash() common.Hash {
if (e.hash == common.Hash{}) {
@@ -210,7 +209,7 @@ func (e *Envelope) OpenAsymmetric(key *ecdsa.PrivateKey) (*ReceivedMessage, erro
// OpenSymmetric tries to decrypt an envelope, potentially encrypted with a particular key.
func (e *Envelope) OpenSymmetric(key []byte) (msg *ReceivedMessage, err error) {
msg = &ReceivedMessage{Raw: e.Data}
- err = msg.decryptSymmetric(key, e.Salt, e.AESNonce)
+ err = msg.decryptSymmetric(key, e.AESNonce)
if err != nil {
msg = nil
}
diff --git a/whisper/whisperv5/filter_test.go b/whisper/whisperv5/filter_test.go
index ae21d1739..dd4ab9e8d 100644
--- a/whisper/whisperv5/filter_test.go
+++ b/whisper/whisperv5/filter_test.go
@@ -68,7 +68,7 @@ func generateFilter(t *testing.T, symmetric bool) (*Filter, error) {
f.Src = &key.PublicKey
if symmetric {
- f.KeySym = make([]byte, 12)
+ f.KeySym = make([]byte, aesKeyLength)
mrand.Read(f.KeySym)
f.SymKeyHash = crypto.Keccak256Hash(f.KeySym)
} else {
@@ -179,7 +179,10 @@ func TestMatchEnvelope(t *testing.T) {
params.Topic[0] = 0xFF // ensure mismatch
// mismatch with pseudo-random data
- msg := NewSentMessage(params)
+ msg, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err := msg.Wrap(params)
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
@@ -197,7 +200,10 @@ func TestMatchEnvelope(t *testing.T) {
i := mrand.Int() % 4
fsym.Topics[i] = params.Topic[:]
fasym.Topics[i] = params.Topic[:]
- msg = NewSentMessage(params)
+ msg, err = NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err = msg.Wrap(params)
if err != nil {
t.Fatalf("failed Wrap() with seed %d: %s.", seed, err)
@@ -245,7 +251,10 @@ func TestMatchEnvelope(t *testing.T) {
}
params.KeySym = nil
params.Dst = &key.PublicKey
- msg = NewSentMessage(params)
+ msg, err = NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err = msg.Wrap(params)
if err != nil {
t.Fatalf("failed Wrap() with seed %d: %s.", seed, err)
@@ -323,12 +332,14 @@ func TestMatchMessageSym(t *testing.T) {
params.KeySym = f.KeySym
params.Topic = BytesToTopic(f.Topics[index])
- sentMessage := NewSentMessage(params)
+ sentMessage, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err := sentMessage.Wrap(params)
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
}
-
msg := env.Open(f)
if msg == nil {
t.Fatalf("failed Open with seed %d.", seed)
@@ -419,12 +430,14 @@ func TestMatchMessageAsym(t *testing.T) {
keySymOrig := params.KeySym
params.KeySym = nil
- sentMessage := NewSentMessage(params)
+ sentMessage, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err := sentMessage.Wrap(params)
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
}
-
msg := env.Open(f)
if msg == nil {
t.Fatalf("failed to open with seed %d.", seed)
@@ -506,7 +519,10 @@ func generateCompatibeEnvelope(t *testing.T, f *Filter) *Envelope {
params.KeySym = f.KeySym
params.Topic = BytesToTopic(f.Topics[2])
- sentMessage := NewSentMessage(params)
+ sentMessage, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err := sentMessage.Wrap(params)
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
@@ -678,7 +694,10 @@ func TestVariableTopics(t *testing.T) {
if err != nil {
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
}
- msg := NewSentMessage(params)
+ msg, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err := msg.Wrap(params)
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
diff --git a/whisper/whisperv5/message.go b/whisper/whisperv5/message.go
index 9b9c389a6..4ef469b51 100644
--- a/whisper/whisperv5/message.go
+++ b/whisper/whisperv5/message.go
@@ -23,14 +23,14 @@ import (
"crypto/cipher"
"crypto/ecdsa"
crand "crypto/rand"
- "crypto/sha256"
+ "encoding/binary"
"errors"
+ "strconv"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/ecies"
"github.com/ethereum/go-ethereum/log"
- "golang.org/x/crypto/pbkdf2"
)
// Options specifies the exact way a message should be wrapped into an Envelope.
@@ -86,58 +86,76 @@ func (msg *ReceivedMessage) isAsymmetricEncryption() bool {
return msg.Dst != nil
}
-func DeriveOneTimeKey(key []byte, salt []byte, version uint64) ([]byte, error) {
- if version == 0 {
- derivedKey := pbkdf2.Key(key, salt, 8, aesKeyLength, sha256.New)
- return derivedKey, nil
- } else {
- return nil, unknownVersionError(version)
- }
-}
-
// NewMessage creates and initializes a non-signed, non-encrypted Whisper message.
-func NewSentMessage(params *MessageParams) *SentMessage {
+func NewSentMessage(params *MessageParams) (*SentMessage, error) {
msg := SentMessage{}
- msg.Raw = make([]byte, 1, len(params.Payload)+len(params.Payload)+signatureLength+padSizeLimitUpper)
+ msg.Raw = make([]byte, 1, len(params.Payload)+len(params.Padding)+signatureLength+padSizeLimit)
msg.Raw[0] = 0 // set all the flags to zero
err := msg.appendPadding(params)
if err != nil {
- log.Error("failed to create NewSentMessage", "err", err)
- return nil
+ return nil, err
}
msg.Raw = append(msg.Raw, params.Payload...)
- return &msg
+ return &msg, nil
+}
+
+// getSizeOfLength returns the number of bytes necessary to encode the entire size padding (including these bytes)
+func getSizeOfLength(b []byte) (sz int, err error) {
+ sz = intSize(len(b)) // first iteration
+ sz = intSize(len(b) + sz) // second iteration
+ if sz > 3 {
+ err = errors.New("oversized padding parameter")
+ }
+ return sz, err
+}
+
+// sizeOfIntSize returns minimal number of bytes necessary to encode an integer value
+func intSize(i int) (s int) {
+ for s = 1; i >= 256; s++ {
+ i /= 256
+ }
+ return s
}
// appendPadding appends the pseudorandom padding bytes and sets the padding flag.
// The last byte contains the size of padding (thus, its size must not exceed 256).
func (msg *SentMessage) appendPadding(params *MessageParams) error {
- total := len(params.Payload) + 1
+ rawSize := len(params.Payload) + 1
if params.Src != nil {
- total += signatureLength
+ rawSize += signatureLength
}
- padChunk := padSizeLimitUpper
- if total <= padSizeLimitLower {
- padChunk = padSizeLimitLower
- }
- odd := total % padChunk
- if odd > 0 {
- padSize := padChunk - odd
- if padSize > 255 {
- // this algorithm is only valid if padSizeLimitUpper <= 256.
- // if padSizeLimitUpper will ever change, please fix the algorithm
- // (for more information see ReceivedMessage.extractPadding() function).
+ odd := rawSize % padSizeLimit
+
+ if len(params.Padding) != 0 {
+ padSize := len(params.Padding)
+ padLengthSize, err := getSizeOfLength(params.Padding)
+ if err != nil {
+ return err
+ }
+ totalPadSize := padSize + padLengthSize
+ buf := make([]byte, 8)
+ binary.LittleEndian.PutUint32(buf, uint32(totalPadSize))
+ buf = buf[:padLengthSize]
+ msg.Raw = append(msg.Raw, buf...)
+ msg.Raw = append(msg.Raw, params.Padding...)
+ msg.Raw[0] |= byte(padLengthSize) // number of bytes indicating the padding size
+ } else if odd != 0 {
+ totalPadSize := padSizeLimit - odd
+ if totalPadSize > 255 {
+ // this algorithm is only valid if padSizeLimit < 256.
+ // if padSizeLimit will ever change, please fix the algorithm
+ // (please see also ReceivedMessage.extractPadding() function).
panic("please fix the padding algorithm before releasing new version")
}
- buf := make([]byte, padSize)
+ buf := make([]byte, totalPadSize)
_, err := crand.Read(buf[1:])
if err != nil {
return err
}
- buf[0] = byte(padSize)
- if params.Padding != nil {
- copy(buf[1:], params.Padding)
+ if totalPadSize > 6 && !validateSymmetricKey(buf) {
+ return errors.New("failed to generate random padding of size " + strconv.Itoa(totalPadSize))
}
+ buf[0] = byte(totalPadSize)
msg.Raw = append(msg.Raw, buf...)
msg.Raw[0] |= byte(0x1) // number of bytes indicating the padding size
}
@@ -178,46 +196,31 @@ func (msg *SentMessage) encryptAsymmetric(key *ecdsa.PublicKey) error {
// encryptSymmetric encrypts a message with a topic key, using AES-GCM-256.
// nonce size should be 12 bytes (see cipher.gcmStandardNonceSize).
-func (msg *SentMessage) encryptSymmetric(key []byte) (salt []byte, nonce []byte, err error) {
+func (msg *SentMessage) encryptSymmetric(key []byte) (nonce []byte, err error) {
if !validateSymmetricKey(key) {
- return nil, nil, errors.New("invalid key provided for symmetric encryption")
- }
-
- salt = make([]byte, saltLength)
- _, err = crand.Read(salt)
- if err != nil {
- return nil, nil, err
- } else if !validateSymmetricKey(salt) {
- return nil, nil, errors.New("crypto/rand failed to generate salt")
+ return nil, errors.New("invalid key provided for symmetric encryption")
}
- derivedKey, err := DeriveOneTimeKey(key, salt, EnvelopeVersion)
- if err != nil {
- return nil, nil, err
- }
- if !validateSymmetricKey(derivedKey) {
- return nil, nil, errors.New("failed to derive one-time key")
- }
- block, err := aes.NewCipher(derivedKey)
+ block, err := aes.NewCipher(key)
if err != nil {
- return nil, nil, err
+ return nil, err
}
aesgcm, err := cipher.NewGCM(block)
if err != nil {
- return nil, nil, err
+ return nil, err
}
// never use more than 2^32 random nonces with a given key
nonce = make([]byte, aesgcm.NonceSize())
_, err = crand.Read(nonce)
if err != nil {
- return nil, nil, err
+ return nil, err
} else if !validateSymmetricKey(nonce) {
- return nil, nil, errors.New("crypto/rand failed to generate nonce")
+ return nil, errors.New("crypto/rand failed to generate nonce")
}
msg.Raw = aesgcm.Seal(nil, nonce, msg.Raw, nil)
- return salt, nonce, nil
+ return nonce, nil
}
// Wrap bundles the message into an Envelope to transmit over the network.
@@ -231,11 +234,11 @@ func (msg *SentMessage) Wrap(options *MessageParams) (envelope *Envelope, err er
return nil, err
}
}
- var salt, nonce []byte
+ var nonce []byte
if options.Dst != nil {
err = msg.encryptAsymmetric(options.Dst)
} else if options.KeySym != nil {
- salt, nonce, err = msg.encryptSymmetric(options.KeySym)
+ nonce, err = msg.encryptSymmetric(options.KeySym)
} else {
err = errors.New("unable to encrypt the message: neither symmetric nor assymmetric key provided")
}
@@ -244,7 +247,7 @@ func (msg *SentMessage) Wrap(options *MessageParams) (envelope *Envelope, err er
return nil, err
}
- envelope = NewEnvelope(options.TTL, options.Topic, salt, nonce, msg)
+ envelope = NewEnvelope(options.TTL, options.Topic, nonce, msg)
err = envelope.Seal(options)
if err != nil {
return nil, err
@@ -254,13 +257,8 @@ func (msg *SentMessage) Wrap(options *MessageParams) (envelope *Envelope, err er
// decryptSymmetric decrypts a message with a topic key, using AES-GCM-256.
// nonce size should be 12 bytes (see cipher.gcmStandardNonceSize).
-func (msg *ReceivedMessage) decryptSymmetric(key []byte, salt []byte, nonce []byte) error {
- derivedKey, err := DeriveOneTimeKey(key, salt, msg.EnvelopeVersion)
- if err != nil {
- return err
- }
-
- block, err := aes.NewCipher(derivedKey)
+func (msg *ReceivedMessage) decryptSymmetric(key []byte, nonce []byte) error {
+ block, err := aes.NewCipher(key)
if err != nil {
return err
}
@@ -323,7 +321,8 @@ func (msg *ReceivedMessage) Validate() bool {
// can be successfully decrypted.
func (msg *ReceivedMessage) extractPadding(end int) (int, bool) {
paddingSize := 0
- sz := int(msg.Raw[0] & paddingMask) // number of bytes containing the entire size of padding, could be zero
+ sz := int(msg.Raw[0] & paddingMask) // number of bytes indicating the entire size of padding (including these bytes)
+ // could be zero -- it means no padding
if sz != 0 {
paddingSize = int(bytesToUintLittleEndian(msg.Raw[1 : 1+sz]))
if paddingSize < sz || paddingSize+1 > end {
diff --git a/whisper/whisperv5/message_test.go b/whisper/whisperv5/message_test.go
index 1ed7250d3..aa82a02f3 100644
--- a/whisper/whisperv5/message_test.go
+++ b/whisper/whisperv5/message_test.go
@@ -31,9 +31,9 @@ func copyFromBuf(dst []byte, src []byte, beg int) int {
}
func generateMessageParams() (*MessageParams, error) {
- // set all the parameters except p.Dst
+ // set all the parameters except p.Dst and p.Padding
- buf := make([]byte, 1024)
+ buf := make([]byte, 4)
mrand.Read(buf)
sz := mrand.Intn(400)
@@ -42,14 +42,10 @@ func generateMessageParams() (*MessageParams, error) {
p.WorkTime = 1
p.TTL = uint32(mrand.Intn(1024))
p.Payload = make([]byte, sz)
- p.Padding = make([]byte, padSizeLimitUpper)
p.KeySym = make([]byte, aesKeyLength)
-
- var b int
- b = copyFromBuf(p.Payload, buf, b)
- b = copyFromBuf(p.Padding, buf, b)
- b = copyFromBuf(p.KeySym, buf, b)
- p.Topic = BytesToTopic(buf[b:])
+ mrand.Read(p.Payload)
+ mrand.Read(p.KeySym)
+ p.Topic = BytesToTopic(buf)
var err error
p.Src, err = crypto.GenerateKey()
@@ -77,11 +73,12 @@ func singleMessageTest(t *testing.T, symmetric bool) {
}
text := make([]byte, 0, 512)
- steg := make([]byte, 0, 512)
text = append(text, params.Payload...)
- steg = append(steg, params.Padding...)
- msg := NewSentMessage(params)
+ msg, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err := msg.Wrap(params)
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
@@ -102,10 +99,6 @@ func singleMessageTest(t *testing.T, symmetric bool) {
t.Fatalf("failed to validate with seed %d.", seed)
}
- padsz := len(decrypted.Padding)
- if !bytes.Equal(steg[:padsz], decrypted.Padding) {
- t.Fatalf("failed with seed %d: compare padding.", seed)
- }
if !bytes.Equal(text, decrypted.Payload) {
t.Fatalf("failed with seed %d: compare payload.", seed)
}
@@ -140,7 +133,10 @@ func TestMessageWrap(t *testing.T) {
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
}
- msg := NewSentMessage(params)
+ msg, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
params.TTL = 1
params.WorkTime = 12
params.PoW = target
@@ -155,7 +151,10 @@ func TestMessageWrap(t *testing.T) {
}
// set PoW target too high, expect error
- msg2 := NewSentMessage(params)
+ msg2, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
params.TTL = 1000000
params.WorkTime = 1
params.PoW = 10000000.0
@@ -175,14 +174,15 @@ func TestMessageSeal(t *testing.T) {
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
}
- msg := NewSentMessage(params)
+ msg, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
params.TTL = 1
aesnonce := make([]byte, 12)
- salt := make([]byte, 12)
mrand.Read(aesnonce)
- mrand.Read(salt)
- env := NewEnvelope(params.TTL, params.Topic, salt, aesnonce, msg)
+ env := NewEnvelope(params.TTL, params.Topic, aesnonce, msg)
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
}
@@ -236,11 +236,12 @@ func singleEnvelopeOpenTest(t *testing.T, symmetric bool) {
}
text := make([]byte, 0, 512)
- steg := make([]byte, 0, 512)
text = append(text, params.Payload...)
- steg = append(steg, params.Padding...)
- msg := NewSentMessage(params)
+ msg, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err := msg.Wrap(params)
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
@@ -252,10 +253,6 @@ func singleEnvelopeOpenTest(t *testing.T, symmetric bool) {
t.Fatalf("failed to open with seed %d.", seed)
}
- padsz := len(decrypted.Padding)
- if !bytes.Equal(steg[:padsz], decrypted.Padding) {
- t.Fatalf("failed with seed %d: compare padding.", seed)
- }
if !bytes.Equal(text, decrypted.Payload) {
t.Fatalf("failed with seed %d: compare payload.", seed)
}
@@ -291,21 +288,38 @@ func TestEncryptWithZeroKey(t *testing.T) {
if err != nil {
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
}
-
- msg := NewSentMessage(params)
-
+ msg, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
params.KeySym = make([]byte, aesKeyLength)
_, err = msg.Wrap(params)
if err == nil {
t.Fatalf("wrapped with zero key, seed: %d.", seed)
}
+ params, err = generateMessageParams()
+ if err != nil {
+ t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
+ }
+ msg, err = NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
params.KeySym = make([]byte, 0)
_, err = msg.Wrap(params)
if err == nil {
t.Fatalf("wrapped with empty key, seed: %d.", seed)
}
+ params, err = generateMessageParams()
+ if err != nil {
+ t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
+ }
+ msg, err = NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
params.KeySym = nil
_, err = msg.Wrap(params)
if err == nil {
@@ -320,7 +334,10 @@ func TestRlpEncode(t *testing.T) {
if err != nil {
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
}
- msg := NewSentMessage(params)
+ msg, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err := msg.Wrap(params)
if err != nil {
t.Fatalf("wrapped with zero key, seed: %d.", seed)
@@ -344,3 +361,60 @@ func TestRlpEncode(t *testing.T) {
t.Fatalf("Hashes are not equal: %x vs. %x", he, hd)
}
}
+
+func singlePaddingTest(t *testing.T, padSize int) {
+ params, err := generateMessageParams()
+ if err != nil {
+ t.Fatalf("failed generateMessageParams with seed %d and sz=%d: %s.", seed, padSize, err)
+ }
+ params.Padding = make([]byte, padSize)
+ params.PoW = 0.0000000001
+ pad := make([]byte, padSize)
+ _, err = mrand.Read(pad)
+ if err != nil {
+ t.Fatalf("padding is not generated (seed %d): %s", seed, err)
+ }
+ n := copy(params.Padding, pad)
+ if n != padSize {
+ t.Fatalf("padding is not copied (seed %d): %s", seed, err)
+ }
+ msg, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
+ env, err := msg.Wrap(params)
+ if err != nil {
+ t.Fatalf("failed to wrap, seed: %d and sz=%d.", seed, padSize)
+ }
+ f := Filter{KeySym: params.KeySym}
+ decrypted := env.Open(&f)
+ if decrypted == nil {
+ t.Fatalf("failed to open, seed and sz=%d: %d.", seed, padSize)
+ }
+ if !bytes.Equal(pad, decrypted.Padding) {
+ t.Fatalf("padding is not retireved as expected with seed %d and sz=%d:\n[%x]\n[%x].", seed, padSize, pad, decrypted.Padding)
+ }
+}
+
+func TestPadding(t *testing.T) {
+ InitSingleTest()
+
+ for i := 1; i < 260; i++ {
+ singlePaddingTest(t, i)
+ }
+
+ lim := 256 * 256
+ for i := lim - 5; i < lim+2; i++ {
+ singlePaddingTest(t, i)
+ }
+
+ for i := 0; i < 256; i++ {
+ n := mrand.Intn(256*254) + 256
+ singlePaddingTest(t, n)
+ }
+
+ for i := 0; i < 256; i++ {
+ n := mrand.Intn(256*1024) + 256*256
+ singlePaddingTest(t, n)
+ }
+}
diff --git a/whisper/whisperv5/peer.go b/whisper/whisperv5/peer.go
index 184c4ebf8..179c93179 100644
--- a/whisper/whisperv5/peer.go
+++ b/whisper/whisperv5/peer.go
@@ -149,23 +149,22 @@ func (peer *Peer) expire() {
// broadcast iterates over the collection of envelopes and transmits yet unknown
// ones over the network.
func (p *Peer) broadcast() error {
- // Fetch the envelopes and collect the unknown ones
+ var cnt int
envelopes := p.host.Envelopes()
- transmit := make([]*Envelope, 0, len(envelopes))
for _, envelope := range envelopes {
if !p.marked(envelope) {
- transmit = append(transmit, envelope)
- p.mark(envelope)
+ err := p2p.Send(p.ws, messagesCode, envelope)
+ if err != nil {
+ return err
+ } else {
+ p.mark(envelope)
+ cnt++
+ }
}
}
- if len(transmit) == 0 {
- return nil
- }
- // Transmit the unknown batch (potentially empty)
- if err := p2p.Send(p.ws, messagesCode, transmit); err != nil {
- return err
+ if cnt > 0 {
+ log.Trace("broadcast", "num. messages", cnt)
}
- log.Trace("broadcast", "num. messages", len(transmit))
return nil
}
diff --git a/whisper/whisperv5/peer_test.go b/whisper/whisperv5/peer_test.go
index a79b6ad14..d3cd63b0b 100644
--- a/whisper/whisperv5/peer_test.go
+++ b/whisper/whisperv5/peer_test.go
@@ -265,7 +265,10 @@ func sendMsg(t *testing.T, expected bool, id int) {
opt.Payload = opt.Payload[1:]
}
- msg := NewSentMessage(&opt)
+ msg, err := NewSentMessage(&opt)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
envelope, err := msg.Wrap(&opt)
if err != nil {
t.Fatalf("failed to seal message: %s", err)
@@ -286,7 +289,10 @@ func TestPeerBasic(t *testing.T) {
}
params.PoW = 0.001
- msg := NewSentMessage(params)
+ msg, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err := msg.Wrap(params)
if err != nil {
t.Fatalf("failed Wrap with seed %d.", seed)
diff --git a/whisper/whisperv5/whisper.go b/whisper/whisperv5/whisper.go
index c4d5d04a7..f2aad08ef 100644
--- a/whisper/whisperv5/whisper.go
+++ b/whisper/whisperv5/whisper.go
@@ -262,24 +262,14 @@ func (w *Whisper) GetPrivateKey(id string) (*ecdsa.PrivateKey, error) {
// GenerateSymKey generates a random symmetric key and stores it under id,
// which is then returned. Will be used in the future for session key exchange.
func (w *Whisper) GenerateSymKey() (string, error) {
- const size = aesKeyLength * 2
- buf := make([]byte, size)
- _, err := crand.Read(buf)
+ key := make([]byte, aesKeyLength)
+ _, err := crand.Read(key)
if err != nil {
return "", err
- } else if !validateSymmetricKey(buf) {
+ } else if !validateSymmetricKey(key) {
return "", fmt.Errorf("error in GenerateSymKey: crypto/rand failed to generate random data")
}
- key := buf[:aesKeyLength]
- salt := buf[aesKeyLength:]
- derived, err := DeriveOneTimeKey(key, salt, EnvelopeVersion)
- if err != nil {
- return "", err
- } else if !validateSymmetricKey(derived) {
- return "", fmt.Errorf("failed to derive valid key")
- }
-
id, err := GenerateRandomID()
if err != nil {
return "", fmt.Errorf("failed to generate ID: %s", err)
@@ -291,7 +281,7 @@ func (w *Whisper) GenerateSymKey() (string, error) {
if w.symKeys[id] != nil {
return "", fmt.Errorf("failed to generate unique ID")
}
- w.symKeys[id] = derived
+ w.symKeys[id] = key
return id, nil
}
@@ -395,6 +385,9 @@ func (w *Whisper) Unsubscribe(id string) error {
// network in the coming cycles.
func (w *Whisper) Send(envelope *Envelope) error {
ok, err := w.add(envelope)
+ if err != nil {
+ return err
+ }
if !ok {
return fmt.Errorf("failed to add envelope")
}
@@ -469,21 +462,18 @@ func (wh *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error {
log.Warn("unxepected status message received", "peer", p.peer.ID())
case messagesCode:
// decode the contained envelopes
- var envelopes []*Envelope
- if err := packet.Decode(&envelopes); err != nil {
+ var envelope Envelope
+ if err := packet.Decode(&envelope); err != nil {
log.Warn("failed to decode envelope, peer will be disconnected", "peer", p.peer.ID(), "err", err)
return errors.New("invalid envelope")
}
- // inject all envelopes into the internal pool
- for _, envelope := range envelopes {
- cached, err := wh.add(envelope)
- if err != nil {
- log.Warn("bad envelope received, peer will be disconnected", "peer", p.peer.ID(), "err", err)
- return errors.New("invalid envelope")
- }
- if cached {
- p.mark(envelope)
- }
+ cached, err := wh.add(&envelope)
+ if err != nil {
+ log.Warn("bad envelope received, peer will be disconnected", "peer", p.peer.ID(), "err", err)
+ return errors.New("invalid envelope")
+ }
+ if cached {
+ p.mark(&envelope)
}
case p2pCode:
// peer-to-peer message, sent directly to peer bypassing PoW checks, etc.
@@ -550,14 +540,11 @@ func (wh *Whisper) add(envelope *Envelope) (bool, error) {
return false, fmt.Errorf("oversized version [%x]", envelope.Hash())
}
- if len(envelope.AESNonce) > AESNonceMaxLength {
- // the standard AES GSM nonce size is 12,
- // but const gcmStandardNonceSize cannot be accessed directly
- return false, fmt.Errorf("oversized AESNonce [%x]", envelope.Hash())
- }
-
- if len(envelope.Salt) > saltLength {
- return false, fmt.Errorf("oversized salt [%x]", envelope.Hash())
+ aesNonceSize := len(envelope.AESNonce)
+ if aesNonceSize != 0 && aesNonceSize != AESNonceLength {
+ // the standard AES GCM nonce size is 12 bytes,
+ // but constant gcmStandardNonceSize cannot be accessed (not exported)
+ return false, fmt.Errorf("wrong size of AESNonce: %d bytes [env: %x]", aesNonceSize, envelope.Hash())
}
if envelope.PoW() < wh.minPoW {
diff --git a/whisper/whisperv5/whisper_test.go b/whisper/whisperv5/whisper_test.go
index d5668259e..225728c42 100644
--- a/whisper/whisperv5/whisper_test.go
+++ b/whisper/whisperv5/whisper_test.go
@@ -455,7 +455,10 @@ func TestExpiry(t *testing.T) {
}
params.TTL = 1
- msg := NewSentMessage(params)
+ msg, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err := msg.Wrap(params)
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
@@ -515,7 +518,10 @@ func TestCustomization(t *testing.T) {
params.Topic = BytesToTopic(f.Topics[2])
params.PoW = smallPoW
params.TTL = 3600 * 24 // one day
- msg := NewSentMessage(params)
+ msg, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err := msg.Wrap(params)
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
@@ -533,7 +539,10 @@ func TestCustomization(t *testing.T) {
}
params.TTL++
- msg = NewSentMessage(params)
+ msg, err = NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err = msg.Wrap(params)
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)