2025-03-08 15:07:27 -05:00
|
|
|
package dnet_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"context"
|
|
|
|
"crypto/ecdsa"
|
2025-03-09 10:21:48 -04:00
|
|
|
"fmt"
|
2025-03-08 15:07:27 -05:00
|
|
|
"net"
|
2025-03-09 10:21:48 -04:00
|
|
|
"os"
|
2025-03-08 15:07:27 -05:00
|
|
|
"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
|
|
|
|
}
|
|
|
|
}
|
2025-03-09 10:21:48 -04:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|