Skip to content

Support QUIC v1 alongside v2 for cross-language interop (Rust/quinn) #288

@espeed

Description

@espeed

Problem

The Go bifrost QUIC configuration hardcodes Versions: []quic.Version{quic.Version2} in transport/common/quic/config.go:47. This means Go bifrost peers only accept QUIC v2 (RFC 9369) connections.

No pure Rust QUIC library implements QUIC v2:

  • quinn (0.11.9) — no v2 support, open issue since 2023, not on roadmap
  • s2n-quic (1.76.0) — no v2 support
  • quiche (0.26.1) — no v2 support

This makes it impossible for a Rust bifrost peer to connect to a Go bifrost peer, even though every other protocol layer (protobuf wire formats, TLS certificate extensions, signaling, floodsub, SRPC) is wire-compatible.

What happens

A Rust peer (quinn) sends a QUIC v1 Initial packet. The Go peer (quic-go) rejects it because it only accepts v2. After adding v2 to quinn's supported_versions list, version negotiation passes but quinn can't parse v2 Initial packets (the long header packet types are permuted in v2).

Go error: timeout: no recent network activity
Quinn log: ignoring non-initial packet for unknown connection

Proposed fix

In transport/common/quic/config.go, change line 47 from:

Versions: []quic.Version{quic.Version2},

to:

Versions: []quic.Version{quic.Version2, quic.Version1},

This accepts both v1 and v2 connections. Go peers connecting to Go peers will still negotiate v2 (preferred). Rust peers will negotiate v1. The QUIC transport is otherwise identical — same TLS 1.3, same bifrost certificate extension (OID 1.3.6.1.4.1.53594.1.1), same ALPN ("bifrost"), same stream multiplexing.

Context

This comes from a Rust port of bifrost with 27 conformance tests proving byte-identical wire compatibility with Go for: peer IDs, SignedMsg, floodsub Packet, signaling SessionRequest/Response, WebRTC Signal, SRPC Packet, peer encryption, envelope, and KeyPEM format. The QUIC version is the only remaining interop barrier.

RFC 9369 (QUIC v2) is primarily an anti-ossification measure — the protocol behavior is identical to v1, only the packet header encoding and crypto salt differ. Accepting v1 alongside v2 has no security or functionality impact.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions