|
@ -25,6 +25,10 @@ import ( |
|
|
tmrand "github.com/tendermint/tendermint/libs/rand" |
|
|
tmrand "github.com/tendermint/tendermint/libs/rand" |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
// Run go test -update from within this module
|
|
|
|
|
|
// to update the golden test vector file
|
|
|
|
|
|
var update = flag.Bool("update", false, "update .golden files") |
|
|
|
|
|
|
|
|
type kvstoreConn struct { |
|
|
type kvstoreConn struct { |
|
|
*io.PipeReader |
|
|
*io.PipeReader |
|
|
*io.PipeWriter |
|
|
*io.PipeWriter |
|
@ -39,60 +43,14 @@ func (drw kvstoreConn) Close() (err error) { |
|
|
return err1 |
|
|
return err1 |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Each returned ReadWriteCloser is akin to a net.Connection
|
|
|
|
|
|
func makeKVStoreConnPair() (fooConn, barConn kvstoreConn) { |
|
|
|
|
|
barReader, fooWriter := io.Pipe() |
|
|
|
|
|
fooReader, barWriter := io.Pipe() |
|
|
|
|
|
return kvstoreConn{fooReader, fooWriter}, kvstoreConn{barReader, barWriter} |
|
|
|
|
|
|
|
|
type privKeyWithNilPubKey struct { |
|
|
|
|
|
orig crypto.PrivKey |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func makeSecretConnPair(tb testing.TB) (fooSecConn, barSecConn *SecretConnection) { |
|
|
|
|
|
|
|
|
|
|
|
var fooConn, barConn = makeKVStoreConnPair() |
|
|
|
|
|
var fooPrvKey = ed25519.GenPrivKey() |
|
|
|
|
|
var fooPubKey = fooPrvKey.PubKey() |
|
|
|
|
|
var barPrvKey = ed25519.GenPrivKey() |
|
|
|
|
|
var barPubKey = barPrvKey.PubKey() |
|
|
|
|
|
|
|
|
|
|
|
// Make connections from both sides in parallel.
|
|
|
|
|
|
var trs, ok = async.Parallel( |
|
|
|
|
|
func(_ int) (val interface{}, abort bool, err error) { |
|
|
|
|
|
fooSecConn, err = MakeSecretConnection(fooConn, fooPrvKey) |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
tb.Errorf("failed to establish SecretConnection for foo: %v", err) |
|
|
|
|
|
return nil, true, err |
|
|
|
|
|
} |
|
|
|
|
|
remotePubBytes := fooSecConn.RemotePubKey() |
|
|
|
|
|
if !remotePubBytes.Equals(barPubKey) { |
|
|
|
|
|
err = fmt.Errorf("unexpected fooSecConn.RemotePubKey. Expected %v, got %v", |
|
|
|
|
|
barPubKey, fooSecConn.RemotePubKey()) |
|
|
|
|
|
tb.Error(err) |
|
|
|
|
|
return nil, false, err |
|
|
|
|
|
} |
|
|
|
|
|
return nil, false, nil |
|
|
|
|
|
}, |
|
|
|
|
|
func(_ int) (val interface{}, abort bool, err error) { |
|
|
|
|
|
barSecConn, err = MakeSecretConnection(barConn, barPrvKey) |
|
|
|
|
|
if barSecConn == nil { |
|
|
|
|
|
tb.Errorf("failed to establish SecretConnection for bar: %v", err) |
|
|
|
|
|
return nil, true, err |
|
|
|
|
|
} |
|
|
|
|
|
remotePubBytes := barSecConn.RemotePubKey() |
|
|
|
|
|
if !remotePubBytes.Equals(fooPubKey) { |
|
|
|
|
|
err = fmt.Errorf("unexpected barSecConn.RemotePubKey. Expected %v, got %v", |
|
|
|
|
|
fooPubKey, barSecConn.RemotePubKey()) |
|
|
|
|
|
tb.Error(err) |
|
|
|
|
|
return nil, false, nil |
|
|
|
|
|
} |
|
|
|
|
|
return nil, false, nil |
|
|
|
|
|
}, |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
require.Nil(tb, trs.FirstError()) |
|
|
|
|
|
require.True(tb, ok, "Unexpected task abortion") |
|
|
|
|
|
|
|
|
|
|
|
return fooSecConn, barSecConn |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
func (pk privKeyWithNilPubKey) Bytes() []byte { return pk.orig.Bytes() } |
|
|
|
|
|
func (pk privKeyWithNilPubKey) Sign(msg []byte) ([]byte, error) { return pk.orig.Sign(msg) } |
|
|
|
|
|
func (pk privKeyWithNilPubKey) PubKey() crypto.PubKey { return nil } |
|
|
|
|
|
func (pk privKeyWithNilPubKey) Equals(pk2 crypto.PrivKey) bool { return pk.orig.Equals(pk2) } |
|
|
|
|
|
|
|
|
func TestSecretConnectionHandshake(t *testing.T) { |
|
|
func TestSecretConnectionHandshake(t *testing.T) { |
|
|
fooSecConn, barSecConn := makeSecretConnPair(t) |
|
|
fooSecConn, barSecConn := makeSecretConnPair(t) |
|
@ -148,26 +106,6 @@ func TestConcurrentRead(t *testing.T) { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func writeLots(t *testing.T, wg *sync.WaitGroup, conn io.Writer, txt string, n int) { |
|
|
|
|
|
defer wg.Done() |
|
|
|
|
|
for i := 0; i < n; i++ { |
|
|
|
|
|
_, err := conn.Write([]byte(txt)) |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
t.Errorf("failed to write to fooSecConn: %v", err) |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func readLots(t *testing.T, wg *sync.WaitGroup, conn io.Reader, n int) { |
|
|
|
|
|
readBuffer := make([]byte, dataMaxSize) |
|
|
|
|
|
for i := 0; i < n; i++ { |
|
|
|
|
|
_, err := conn.Read(readBuffer) |
|
|
|
|
|
assert.NoError(t, err) |
|
|
|
|
|
} |
|
|
|
|
|
wg.Done() |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func TestSecretConnectionReadWrite(t *testing.T) { |
|
|
func TestSecretConnectionReadWrite(t *testing.T) { |
|
|
fooConn, barConn := makeKVStoreConnPair() |
|
|
fooConn, barConn := makeKVStoreConnPair() |
|
|
fooWrites, barWrites := []string{}, []string{} |
|
|
fooWrites, barWrites := []string{}, []string{} |
|
@ -282,13 +220,8 @@ func TestSecretConnectionReadWrite(t *testing.T) { |
|
|
|
|
|
|
|
|
compareWritesReads(fooWrites, barReads) |
|
|
compareWritesReads(fooWrites, barReads) |
|
|
compareWritesReads(barWrites, fooReads) |
|
|
compareWritesReads(barWrites, fooReads) |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Run go test -update from within this module
|
|
|
|
|
|
// to update the golden test vector file
|
|
|
|
|
|
var update = flag.Bool("update", false, "update .golden files") |
|
|
|
|
|
|
|
|
|
|
|
func TestDeriveSecretsAndChallengeGolden(t *testing.T) { |
|
|
func TestDeriveSecretsAndChallengeGolden(t *testing.T) { |
|
|
goldenFilepath := filepath.Join("testdata", t.Name()+".golden") |
|
|
goldenFilepath := filepath.Join("testdata", t.Name()+".golden") |
|
|
if *update { |
|
|
if *update { |
|
@ -322,15 +255,6 @@ func TestDeriveSecretsAndChallengeGolden(t *testing.T) { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
type privKeyWithNilPubKey struct { |
|
|
|
|
|
orig crypto.PrivKey |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (pk privKeyWithNilPubKey) Bytes() []byte { return pk.orig.Bytes() } |
|
|
|
|
|
func (pk privKeyWithNilPubKey) Sign(msg []byte) ([]byte, error) { return pk.orig.Sign(msg) } |
|
|
|
|
|
func (pk privKeyWithNilPubKey) PubKey() crypto.PubKey { return nil } |
|
|
|
|
|
func (pk privKeyWithNilPubKey) Equals(pk2 crypto.PrivKey) bool { return pk.orig.Equals(pk2) } |
|
|
|
|
|
|
|
|
|
|
|
func TestNilPubkey(t *testing.T) { |
|
|
func TestNilPubkey(t *testing.T) { |
|
|
var fooConn, barConn = makeKVStoreConnPair() |
|
|
var fooConn, barConn = makeKVStoreConnPair() |
|
|
var fooPrvKey = ed25519.GenPrivKey() |
|
|
var fooPrvKey = ed25519.GenPrivKey() |
|
@ -367,6 +291,26 @@ func TestNonEd25519Pubkey(t *testing.T) { |
|
|
}) |
|
|
}) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func writeLots(t *testing.T, wg *sync.WaitGroup, conn io.Writer, txt string, n int) { |
|
|
|
|
|
defer wg.Done() |
|
|
|
|
|
for i := 0; i < n; i++ { |
|
|
|
|
|
_, err := conn.Write([]byte(txt)) |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
t.Errorf("failed to write to fooSecConn: %v", err) |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func readLots(t *testing.T, wg *sync.WaitGroup, conn io.Reader, n int) { |
|
|
|
|
|
readBuffer := make([]byte, dataMaxSize) |
|
|
|
|
|
for i := 0; i < n; i++ { |
|
|
|
|
|
_, err := conn.Read(readBuffer) |
|
|
|
|
|
assert.NoError(t, err) |
|
|
|
|
|
} |
|
|
|
|
|
wg.Done() |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// Creates the data for a test vector file.
|
|
|
// Creates the data for a test vector file.
|
|
|
// The file format is:
|
|
|
// The file format is:
|
|
|
// Hex(diffie_hellman_secret), loc_is_least, Hex(recvSecret), Hex(sendSecret), Hex(challenge)
|
|
|
// Hex(diffie_hellman_secret), loc_is_least, Hex(recvSecret), Hex(sendSecret), Hex(challenge)
|
|
@ -386,6 +330,65 @@ func createGoldenTestVectors(t *testing.T) string { |
|
|
return data |
|
|
return data |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Each returned ReadWriteCloser is akin to a net.Connection
|
|
|
|
|
|
func makeKVStoreConnPair() (fooConn, barConn kvstoreConn) { |
|
|
|
|
|
barReader, fooWriter := io.Pipe() |
|
|
|
|
|
fooReader, barWriter := io.Pipe() |
|
|
|
|
|
return kvstoreConn{fooReader, fooWriter}, kvstoreConn{barReader, barWriter} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func makeSecretConnPair(tb testing.TB) (fooSecConn, barSecConn *SecretConnection) { |
|
|
|
|
|
var ( |
|
|
|
|
|
fooConn, barConn = makeKVStoreConnPair() |
|
|
|
|
|
fooPrvKey = ed25519.GenPrivKey() |
|
|
|
|
|
fooPubKey = fooPrvKey.PubKey() |
|
|
|
|
|
barPrvKey = ed25519.GenPrivKey() |
|
|
|
|
|
barPubKey = barPrvKey.PubKey() |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
// Make connections from both sides in parallel.
|
|
|
|
|
|
var trs, ok = async.Parallel( |
|
|
|
|
|
func(_ int) (val interface{}, abort bool, err error) { |
|
|
|
|
|
fooSecConn, err = MakeSecretConnection(fooConn, fooPrvKey) |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
tb.Errorf("failed to establish SecretConnection for foo: %v", err) |
|
|
|
|
|
return nil, true, err |
|
|
|
|
|
} |
|
|
|
|
|
remotePubBytes := fooSecConn.RemotePubKey() |
|
|
|
|
|
if !remotePubBytes.Equals(barPubKey) { |
|
|
|
|
|
err = fmt.Errorf("unexpected fooSecConn.RemotePubKey. Expected %v, got %v", |
|
|
|
|
|
barPubKey, fooSecConn.RemotePubKey()) |
|
|
|
|
|
tb.Error(err) |
|
|
|
|
|
return nil, true, err |
|
|
|
|
|
} |
|
|
|
|
|
return nil, false, nil |
|
|
|
|
|
}, |
|
|
|
|
|
func(_ int) (val interface{}, abort bool, err error) { |
|
|
|
|
|
barSecConn, err = MakeSecretConnection(barConn, barPrvKey) |
|
|
|
|
|
if barSecConn == nil { |
|
|
|
|
|
tb.Errorf("failed to establish SecretConnection for bar: %v", err) |
|
|
|
|
|
return nil, true, err |
|
|
|
|
|
} |
|
|
|
|
|
remotePubBytes := barSecConn.RemotePubKey() |
|
|
|
|
|
if !remotePubBytes.Equals(fooPubKey) { |
|
|
|
|
|
err = fmt.Errorf("unexpected barSecConn.RemotePubKey. Expected %v, got %v", |
|
|
|
|
|
fooPubKey, barSecConn.RemotePubKey()) |
|
|
|
|
|
tb.Error(err) |
|
|
|
|
|
return nil, true, err |
|
|
|
|
|
} |
|
|
|
|
|
return nil, false, nil |
|
|
|
|
|
}, |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
require.Nil(tb, trs.FirstError()) |
|
|
|
|
|
require.True(tb, ok, "Unexpected task abortion") |
|
|
|
|
|
|
|
|
|
|
|
return fooSecConn, barSecConn |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
// Benchmarks
|
|
|
|
|
|
|
|
|
func BenchmarkWriteSecretConnection(b *testing.B) { |
|
|
func BenchmarkWriteSecretConnection(b *testing.B) { |
|
|
b.StopTimer() |
|
|
b.StopTimer() |
|
|
b.ReportAllocs() |
|
|
b.ReportAllocs() |
|
|