diff --git a/auth/interop_test.go b/auth/interop_test.go new file mode 100644 index 0000000..c4a3a8e --- /dev/null +++ b/auth/interop_test.go @@ -0,0 +1,39 @@ +package auth + +// §13.5 interop capture (2026-09-01): three codes computed by an independent +// Python-stdlib TOTP implementation at recorded wall-clock Unix seconds, for +// the shared RFC secret. Cross-implementation agreement — the Python code +// also reproduced RFC 4226 App D counter 0 = 755224, anchoring it to the +// same algorithm. The Go implementation must produce identical codes at the +// same instants, and VerifyWindow(0) must accept each at its capture time. + +import ( + "testing" + "time" +) + +func TestInteropCapturePythonTOTP(t *testing.T) { + captures := []struct { + unix int64 + code string + }{ + {1788266430, "398267"}, + {1788266460, "060110"}, + {1788266490, "612712"}, + } + for _, c := range captures { + at := time.Unix(c.unix, 0) + step := Counter(at, 30*time.Second) + got, err := HOTP(totpSecret, step, 6) + if err != nil { + t.Fatalf("HOTP t=%d: %v", c.unix, err) + } + if got != c.code { + t.Errorf("t=%d: Go produced %s, independent impl produced %s", c.unix, got, c.code) + } + // window=0: the code must verify at exactly its capture instant. + if _, err := VerifyWindow(0, totpSecret, c.code, at); err != nil { + t.Errorf("t=%d: capture code %s failed window-0 verify: %v", c.unix, c.code, err) + } + } +}