package attesto import ( "encoding/hex" "encoding/json" "os" "path/filepath" "testing" ) func TestGoldenVectorCanonicalJSONAndHashes(t *testing.T) { vector := loadGoldenVector(t) events := vector["events"].([]any) first := events[0].(map[string]any) envelope := M(first["envelope"].(map[string]any)) gotCanonicalHex, err := CanonicalJSONHex(envelope) if err != nil { t.Fatalf("canonical json: %v", err) } if gotCanonicalHex != first["canonical_json_hex"].(string) { t.Fatalf("canonical json hex mismatch\ngot %s\nwant %s", gotCanonicalHex, first["canonical_json_hex"]) } domains := vector["domains"].(map[string]any) gotHash, err := DomainHashHex(domains["event"].(string), envelope) if err != nil { t.Fatalf("domain hash: %v", err) } if gotHash != first["event_hash"].(string) { t.Fatalf("event hash mismatch\ngot %s\nwant %s", gotHash, first["event_hash"]) } } func TestGoldenVectorReceiptOfflineVerification(t *testing.T) { vector := loadGoldenVector(t) rawReceipt, err := json.Marshal(vector["receipt"]) if err != nil { t.Fatal(err) } var receipt SignedReceipt if err := json.Unmarshal(rawReceipt, &receipt); err != nil { t.Fatalf("unmarshal receipt: %v", err) } signing := vector["signing"].(map[string]any) report := VerifyReceiptOffline(receipt, signing["public_key_hex"].(string)) if !report.OK { t.Fatalf("receipt should verify: %#v", report.Problems) } receipt.Payload["event_hash"] = "00" + receipt.Payload["event_hash"].(string)[2:] tampered := VerifyReceiptOffline(receipt, signing["public_key_hex"].(string)) if tampered.OK { t.Fatal("tampered receipt unexpectedly verified") } } func TestSignedConnectorWebhookHeaders(t *testing.T) { headers := SignedConnectorWebhookHeaders("secret", []byte(`{"eventType":"decision"}`), 1710000000) if headers["X-Attesto-Connector-Timestamp"] != "1710000000" { t.Fatalf("timestamp mismatch: %v", headers) } signature := headers["X-Attesto-Connector-Signature"] if _, err := hex.DecodeString(signature); err != nil { t.Fatalf("signature is not hex: %v", err) } if len(signature) != 64 { t.Fatalf("signature length mismatch: %d", len(signature)) } } func loadGoldenVector(t *testing.T) map[string]any { t.Helper() path := filepath.Join("..", "..", "golden-vectors", "proofstream-v0.1-alpha", "one-stream-two-events.json") raw, err := os.ReadFile(path) if err != nil { t.Fatalf("read golden vector: %v", err) } var data map[string]any if err := json.Unmarshal(raw, &data); err != nil { t.Fatalf("parse golden vector: %v", err) } return data }