package dnet_test import ( "bytes" "context" "crypto/ecdsa" "fmt" "net" "os" "sync" "testing" "koti.casa/numenor-labs/dsfx/shared/dcrypto" "koti.casa/numenor-labs/dsfx/shared/dnet" ) func TestHandshake(t *testing.T) { ctx := context.Background() // alice, represented by an ecdsa key pair. alice, _ := dcrypto.GenerateSigningKey() // bob, also represented by an ecdsa key pair. bob, _ := dcrypto.GenerateSigningKey() var ( // the secret that alice should arrive at on her own aliceSecret []byte // any errors produce by alice aliceErr error // alice's public key as discovered by bob discoveredAlicePublicKey *ecdsa.PublicKey // the secret that bob should arrive at on his own bobSecret []byte // any errors produce by bob bobErr error ) // Create a network pipe to simulate a network connection between alice and bob. client, server := net.Pipe() defer client.Close() defer server.Close() // Run the handshake in parallel so both sides can proceed concurrently. // Since they're talking through the network pipe, the entire process should // be simulated as if it were a real network connection. var wg sync.WaitGroup wg.Add(2) go func() { aliceSecret, aliceErr = dnet.Handshake(ctx, client, alice, &bob.PublicKey) wg.Done() }() go func() { discoveredAlicePublicKey, bobSecret, bobErr = dnet.AcceptHandshake(ctx, server, bob) wg.Done() }() wg.Wait() // Neither alice nor bob should have encountered any errors. if aliceErr != nil { t.Errorf("alice error: %v", aliceErr) return } if bobErr != nil { t.Errorf("bob error: %v", bobErr) return } // Both alice and bob should have arrived at a shared secret. if aliceSecret == nil || bobSecret == nil { t.Errorf("handshake failed: sessions are nil") return } // Alice and bob should have arrived at the SAME shared secret. if !bytes.Equal(aliceSecret, bobSecret) { t.Errorf("handshake failed: sessions are not equal") return } // Bob should have discovered alice's public key. if !alice.PublicKey.Equal(discoveredAlicePublicKey) { t.Errorf("handshake failed: discovered public key is not equal to alice's public key") return } } func BenchmarkHandshake(b *testing.B) { for b.Loop() { if err := runSimulation(); err != nil { fmt.Fprint(os.Stderr, err) } } } func runSimulation() error { ctx := context.Background() // alice, represented by an ecdsa key pair. alice, _ := dcrypto.GenerateSigningKey() // bob, also represented by an ecdsa key pair. bob, _ := dcrypto.GenerateSigningKey() var ( // the secret that alice should arrive at on her own // aliceSecret []byte // any errors produce by alice aliceErr error // alice's public key as discovered by bob // discoveredAlicePublicKey *ecdsa.PublicKey // the secret that bob should arrive at on his own // bobSecret []byte // any errors produce by bob bobErr error ) // Create a network pipe to simulate a network connection between alice and bob. client, server := net.Pipe() defer client.Close() defer server.Close() // Run the handshake in parallel so both sides can proceed concurrently. // Since they're talking through the network pipe, the entire process should // be simulated as if it were a real network connection. var wg sync.WaitGroup wg.Add(2) go func() { _, aliceErr = dnet.Handshake(ctx, client, alice, &bob.PublicKey) wg.Done() }() go func() { _, _, bobErr = dnet.AcceptHandshake(ctx, server, bob) wg.Done() }() wg.Wait() if aliceErr != nil { return aliceErr } if bobErr != nil { return bobErr } return nil }