Files
zeekay 9ba50e4128 pqsafe: decomplect — consume luxfi/zwing for X-Wing + hybrid identity
One and only one X-Wing implementation in the Lux stack: zwing.
Removed pqsafe/pkg/xwing and pqsafe/pkg/identity; replaced their
call sites in capsule + envelope with direct zwing imports
(zwing.XWingPublicKey / XWingPrivateKey / XWingEncapsulate /
XWingDecapsulate, zwing.Identity / IdentityPublic / Sign / Verify).

Same bytes that protect a Z-Wing session now protect a PQSAFE file:
one X-Wing, one hybrid-sig surface, vetted once.

All E2E tests still pass against the zwing-backed Seal/Open path:
  TestSealOpenRoundTrip          full round-trip
  TestWrongRecipientCannotOpen   wrong key fails closed
  TestCorruptChunkFails          chunk SHA mismatch detected
  TestTamperedManifestFails      zwing hybrid sig refuses
  TestSwapCapsulesFails          zwing X-Wing decap fails for wrong key
  TestExpiredEnvelopeRefused     TTL gate at Open time

Example program now uses zwing.GenerateIdentity() and the
PQSAFE-IL5-HYBRID-v1 envelope rides on top.
2026-05-12 20:34:23 -07:00

108 lines
2.9 KiB
Go

// Copyright (C) 2025-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
// Example program: end-to-end PQSAFE-IL5-HYBRID-v1 round-trip using
// luxfi/zwing for the canonical X-Wing + hybrid identity primitives.
//
// go run ./_examples/basic
//
// Generates a sender + two recipients via zwing.GenerateIdentity(),
// seals a payload to both, has each recipient open the envelope and
// verify byte-identical recovery of the plaintext, then proves a
// tampered chunk fails closed.
package main
import (
"bytes"
"crypto/rand"
"fmt"
"log"
"time"
"github.com/luxfi/zwing"
"github.com/luxfi/pqsafe/pkg/envelope"
)
func main() {
sender, err := zwing.GenerateIdentity()
must(err)
alice, err := zwing.GenerateIdentity()
must(err)
bob, err := zwing.GenerateIdentity()
must(err)
plaintext := make([]byte, 200_000)
if _, err := rand.Read(plaintext); err != nil {
log.Fatal(err)
}
fmt.Printf("Sealing %d bytes for 2 recipients (zwing identities)...\n", len(plaintext))
sealed, err := envelope.Seal(envelope.SealInput{
Plaintext: plaintext,
Sender: sender,
Recipients: []envelope.Recipient{
{ID: "alice@mil", Public: alice.Public()},
{ID: "bob@gov", Public: bob.Public()},
},
PolicyLabel: "CUI",
PolicyURI: "policy://safe.apps.mil/policies/CUI-IL5-HYBRID-PQ-v1",
TTL: 24 * time.Hour,
})
must(err)
fmt.Printf(" manifest: %d bytes\n", len(sealed.ManifestBytes))
fmt.Printf(" manifest sig: %d bytes (zwing hybrid Ed25519+ML-DSA-65)\n", len(sealed.ManifestSig))
fmt.Printf(" chunks: %d\n", len(sealed.Chunks))
fmt.Printf(" capsules: %d\n", len(sealed.Capsules))
fmt.Printf(" envelope_id: %x...\n", sealed.EnvelopeID[:12])
for _, r := range []struct {
name string
id string
sk *zwing.Identity
}{
{"Alice", "alice@mil", alice},
{"Bob", "bob@gov", bob},
} {
fmt.Printf("\nOpening as %s...\n", r.name)
got, err := envelope.Open(envelope.OpenInput{
ManifestBytes: sealed.ManifestBytes,
ManifestSig: sealed.ManifestSig,
Chunks: sealed.Chunks,
Capsules: sealed.Capsules,
Recipient: r.sk,
RecipientID: r.id,
Now: time.Now(),
})
must(err)
if !bytes.Equal(got, plaintext) {
log.Fatalf("%s: plaintext mismatch", r.name)
}
fmt.Printf(" ✓ recovered %d bytes byte-identical\n", len(got))
}
fmt.Println("\nTampering with chunk 0...")
sealed.Chunks[0][0] ^= 0xFF
_, err = envelope.Open(envelope.OpenInput{
ManifestBytes: sealed.ManifestBytes,
ManifestSig: sealed.ManifestSig,
Chunks: sealed.Chunks,
Capsules: sealed.Capsules,
Recipient: alice,
RecipientID: "alice@mil",
})
if err == nil {
log.Fatal("expected Open to fail on tampered chunk")
}
fmt.Printf(" ✓ Open refused: %v\n", err)
fmt.Println("\nE2E PQSAFE-IL5-HYBRID-v1 (via luxfi/zwing) round-trip OK.")
}
func must(err error) {
if err != nil {
log.Fatal(err)
}
}