package pqkem import ( "testing" "time" "github.com/stretchr/testify/require" ) var ( wgA = []byte("peer-A-wireguard-pubkey-32bytes!") wgB = []byte("peer-B-wireguard-pubkey-32bytes!") ) func TestExchange_DerivesMatchingPSK(t *testing.T) { init, err := NewInitiator() require.NoError(t, err) require.Len(t, init.Offer(), OfferSize) answer, pskB, err := Respond(init.Offer(), Binding{LocalID: wgB, RemoteID: wgA}) require.NoError(t, err) require.Len(t, answer, AnswerSize) pskA, err := init.Finish(answer, Binding{LocalID: wgA, RemoteID: wgB}) require.NoError(t, err) require.Equal(t, pskB, pskA, "both sides must derive the same PSK") require.NotEqual(t, PSK{}, pskA, "PSK must not be zero") } func TestExchange_PSKBoundToPeerIdentities(t *testing.T) { init, err := NewInitiator() require.NoError(t, err) // responder computes with the honest pair... _, pskHonest, err := Respond(init.Offer(), Binding{LocalID: wgB, RemoteID: wgA}) require.NoError(t, err) // ...a second responder run with a different peer identity yields a different PSK, // even though the KEM material would otherwise combine identically. wgC := []byte("peer-C-wireguard-pubkey-32bytes!") _, pskWrong, err := Respond(init.Offer(), Binding{LocalID: wgC, RemoteID: wgA}) require.NoError(t, err) require.NotEqual(t, pskHonest, pskWrong, "PSK must be bound to the peer pair") } func TestExchange_RejectsMalformedMessages(t *testing.T) { init, err := NewInitiator() require.NoError(t, err) _, _, err = Respond(init.Offer()[:10], Binding{}) require.Error(t, err) _, err = init.Finish([]byte("too short"), Binding{}) require.Error(t, err) } // TestExchange_ReportSizesAndTiming is a spike measurement, not a pass/fail gate. // Run with: go test -run TestExchange_ReportSizesAndTiming -v ./client/internal/pqkem/ func TestExchange_ReportSizesAndTiming(t *testing.T) { const iters = 200 var tInit, tResp, tFinish time.Duration for i := 0; i < iters; i++ { s0 := time.Now() init, err := NewInitiator() require.NoError(t, err) tInit += time.Since(s0) s1 := time.Now() answer, _, err := Respond(init.Offer(), Binding{LocalID: wgB, RemoteID: wgA}) require.NoError(t, err) tResp += time.Since(s1) s2 := time.Now() _, err = init.Finish(answer, Binding{LocalID: wgA, RemoteID: wgB}) require.NoError(t, err) tFinish += time.Since(s2) } t.Logf("wire sizes: offer=%d B answer=%d B (Rosenpass static pubkey ~524160 B)", OfferSize, AnswerSize) t.Logf("total on-wire per handshake: %d B (~%.0fx smaller than RP static key)", OfferSize+AnswerSize, 524160.0/float64(OfferSize+AnswerSize)) t.Logf("avg NewInitiator (keygen): %s", tInit/iters) t.Logf("avg Respond (encaps+dh): %s", tResp/iters) t.Logf("avg Finish (decaps+dh): %s", tFinish/iters) t.Logf("avg full handshake CPU: %s", (tInit+tResp+tFinish)/iters) }