<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Cleiton Augusto Correa Bezerra</title>
    <description>The latest articles on DEV Community by Cleiton Augusto Correa Bezerra (@cleiton_augusto_).</description>
    <link>https://dev.to/cleiton_augusto_</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3547488%2Ffea3af52-a724-429f-af20-3a2121bd4a27.jpg</url>
      <title>DEV Community: Cleiton Augusto Correa Bezerra</title>
      <link>https://dev.to/cleiton_augusto_</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cleiton_augusto_"/>
    <language>en</language>
    <item>
      <title>We Benchmarked 4 Rust Quantum Simulators. Three Agreed. One Didn't.</title>
      <dc:creator>Cleiton Augusto Correa Bezerra</dc:creator>
      <pubDate>Sun, 05 Jul 2026 11:42:18 +0000</pubDate>
      <link>https://dev.to/cleiton_augusto_/we-benchmarked-4-rust-quantum-simulators-three-agreed-one-didnt-4dd2</link>
      <guid>https://dev.to/cleiton_augusto_/we-benchmarked-4-rust-quantum-simulators-three-agreed-one-didnt-4dd2</guid>
      <description>&lt;p&gt;We built &lt;strong&gt;CleitonForge&lt;/strong&gt; — a neutral benchmarking layer for quantum simulation written in Rust. The idea is simple: take the same quantum circuit, run it through multiple simulators using an identical canonical IR, and compare. No favorites. No built-in assumptions about which framework is correct.&lt;/p&gt;

&lt;p&gt;We plugged in four backends: our own native statevector, &lt;strong&gt;quantrs2&lt;/strong&gt;, &lt;strong&gt;roqoqo&lt;/strong&gt;, and &lt;strong&gt;q1tsim&lt;/strong&gt;. On Bell states, Grover search, QFT, and Bernstein-Vazirani — all four agreed to machine precision. Then we ran QAOA.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Native vs quantrs2 fidelity: 0.00000000.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not a rounding error. Not a bug in our code. A fundamental sign disagreement in how one framework defines the Rz gate — invisible in standard benchmarks, catastrophic in parameterized quantum algorithms.&lt;/p&gt;




&lt;h2&gt;
  
  
  The finding: two definitions of the same gate
&lt;/h2&gt;

&lt;p&gt;The Rz(λ) gate is one of the most common in quantum computing. IBM, Qiskit, OpenQASM, and virtually every textbook define it as:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IBM / Qiskit convention — used by: native · roqoqo · q1tsim&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Rz(λ) = ⎡ e^{−iλ/2}    0        ⎤
         ⎣    0       e^{+iλ/2}  ⎦
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Opposite sign convention — used by: quantrs2-core&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Rz(λ) = ⎡ e^{+iλ/2}    0        ⎤
         ⎣    0       e^{−iλ/2}  ⎦
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference is a global sign flip in the exponent. For λ = 0, both give the identity — you can't tell them apart. For λ = π/4 (as in QAOA's cost layer), the two matrices produce orthogonal quantum states. Fidelity: exactly zero.&lt;/p&gt;




&lt;h2&gt;
  
  
  The evidence
&lt;/h2&gt;

&lt;p&gt;We ran every backend through the same QAOA MaxCut circuit (2 qubits, γ = −3π/4, β = −π/8) and measured cross-backend fidelity:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pair&lt;/th&gt;
&lt;th&gt;Fidelity&lt;/th&gt;
&lt;th&gt;Verdict&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;native ↔ roqoqo&lt;/td&gt;
&lt;td&gt;1.00000000&lt;/td&gt;
&lt;td&gt;✅ agree&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;native ↔ q1tsim&lt;/td&gt;
&lt;td&gt;1.00000000&lt;/td&gt;
&lt;td&gt;✅ agree&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;roqoqo ↔ q1tsim&lt;/td&gt;
&lt;td&gt;1.00000000&lt;/td&gt;
&lt;td&gt;✅ agree&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;native ↔ quantrs2&lt;/td&gt;
&lt;td&gt;0.00000000&lt;/td&gt;
&lt;td&gt;❌ differ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;roqoqo ↔ quantrs2&lt;/td&gt;
&lt;td&gt;0.00000000&lt;/td&gt;
&lt;td&gt;❌ differ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;q1tsim ↔ quantrs2&lt;/td&gt;
&lt;td&gt;0.00000000&lt;/td&gt;
&lt;td&gt;❌ differ&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Why Quantum Volume doesn't catch it
&lt;/h3&gt;

&lt;p&gt;We also ran the IBM Quantum Volume benchmark — Haar-random SU(4) circuits, 100 trials per width. All four backends returned &lt;strong&gt;identical HOG fractions to 4 decimal places&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Width n&lt;/th&gt;
&lt;th&gt;QV&lt;/th&gt;
&lt;th&gt;native&lt;/th&gt;
&lt;th&gt;quantrs2&lt;/th&gt;
&lt;th&gt;roqoqo&lt;/th&gt;
&lt;th&gt;q1tsim&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;n = 2&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;0.5355&lt;/td&gt;
&lt;td&gt;0.5355&lt;/td&gt;
&lt;td&gt;0.5355&lt;/td&gt;
&lt;td&gt;0.5355&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;n = 3&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;0.7340 ✅&lt;/td&gt;
&lt;td&gt;0.7340 ✅&lt;/td&gt;
&lt;td&gt;0.7340 ✅&lt;/td&gt;
&lt;td&gt;0.7340 ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;n = 4&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;0.7991 ✅&lt;/td&gt;
&lt;td&gt;0.7991 ✅&lt;/td&gt;
&lt;td&gt;0.7991 ✅&lt;/td&gt;
&lt;td&gt;0.7991 ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;n = 5&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;0.8459 ✅&lt;/td&gt;
&lt;td&gt;0.8459 ✅&lt;/td&gt;
&lt;td&gt;0.8459 ✅&lt;/td&gt;
&lt;td&gt;0.8459 ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is not a contradiction — it's the key insight. Quantum Volume uses &lt;em&gt;random&lt;/em&gt; angles. When λ is drawn from a uniform distribution over [0, 2π), the sign flip averages out across the ensemble. The divergence only surfaces with &lt;strong&gt;specific, purposeful angles&lt;/strong&gt; — exactly the kind used in QAOA, VQE, and other variational algorithms.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The implication:&lt;/strong&gt; Standard Clifford benchmarks and random circuit tests are blind to this class of convention disagreement. You need a benchmark that exercises parameterized gates at specific angles — which is exactly what QAOA does, and exactly what CleitonForge's benchmark suite runs automatically across all backends.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The architecture that found it
&lt;/h2&gt;

&lt;p&gt;CleitonForge is not a simulator. It's a &lt;strong&gt;neutral benchmarking layer&lt;/strong&gt; that sits between circuits and simulators. Every backend receives the same canonical intermediate representation — a flat list of typed operations with no framework-specific encoding — and returns a statevector.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Same circuit, four backends, zero code duplication&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;circuit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse_qasm2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qaoa_source&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;backends&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;SimulationBackend&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"native"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;NativeStateVectorBackend&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"quantrs2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;QuantRS2Backend&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"roqoqo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;RoqoqoBackend&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"q1tsim"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Q1tSimBackend&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;backend&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;backends&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;backend&lt;/span&gt;&lt;span class="nf"&gt;.run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;circuit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/*shots=*/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;measure_fidelity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;reference_sv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="py"&gt;.statevector&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The canonical IR means backends never see each other's types. roqoqo's gate structs, q1tsim's matrix API, and quantrs2's internal representation are all adapted at the backend boundary. This is also why the Rz divergence is detectable: the input angle λ is the same floating-point value for all backends. The difference is entirely in how each framework's gate definition applies it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Beyond the finding: what we built along the way
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Exact noisy simulation
&lt;/h3&gt;

&lt;p&gt;We implemented a &lt;strong&gt;density matrix backend&lt;/strong&gt; — exact noisy simulation via ρ ∈ ℂ^(4ⁿ), no Monte Carlo variance. Four Kraus noise channels (depolarizing, amplitude damping, bit-flip, phase-flip) applied after each gate. At 12 qubits you get the exact probability distribution from a single simulation run.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;cforge&lt;/span&gt;

&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cforge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Circuit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;h&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# IBM Nairobi calibration: avg SX err 0.03%, avg CX err 0.64%
&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cforge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;backend&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;density-matrix&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="n"&gt;depolarizing_1q&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.000315&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="n"&gt;depolarizing_2q&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.00638&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;top_states&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# [('00', 0.487), ('11', 0.487), ('01', 0.013), ('10', 0.013)]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real hardware calibration
&lt;/h3&gt;

&lt;p&gt;We ship a parser for IBM's public calibration JSON format — T1/T2 times, per-qubit SX error rates, per-pair CX error rates — and convert it directly to a &lt;code&gt;NoisyConfig&lt;/code&gt;. IBM Nairobi numbers are included as a reference snapshot.&lt;/p&gt;

&lt;h3&gt;
  
  
  Python bindings
&lt;/h3&gt;

&lt;p&gt;Everything above is available from Python via &lt;code&gt;pip install cleitonforge&lt;/code&gt;. The bindings expose all backends, noise channels, and the QASM parser. Built with PyO3 and maturin; Linux/macOS/Windows wheels on PyPI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Performance (release build)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Benchmark&lt;/th&gt;
&lt;th&gt;Qubits&lt;/th&gt;
&lt;th&gt;Gates&lt;/th&gt;
&lt;th&gt;Time (ms)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Bell state&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;0.6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GHZ state&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;0.4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;QFT&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;0.4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bernstein-Vazirani&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;0.3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Grover search&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;43&lt;/td&gt;
&lt;td&gt;0.3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  What we are — and what we're not
&lt;/h2&gt;

&lt;p&gt;The temptation when you find a convention divergence is to build your own simulator and do it "right." We're not doing that.&lt;/p&gt;

&lt;p&gt;Our moat is &lt;strong&gt;neutrality&lt;/strong&gt;. The moment CleitonForge ships its own simulator, it becomes a competitor to the projects it benchmarks — and loses the only thing that makes its findings credible: no skin in the game. roqoqo cannot tell you "our Rz convention matches IBM and quantrs2's doesn't," because they're a party to the comparison. We can.&lt;/p&gt;

&lt;p&gt;What &lt;em&gt;does&lt;/em&gt; make sense: a &lt;strong&gt;convention normalization transpiler&lt;/strong&gt; — a layer that detects which Rz convention a circuit assumes and corrects it for the target backend. That's an extension of the benchmarking mission, not a departure from it.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Open source:&lt;/strong&gt; Convention normalization transpiler — detect and correct Rz sign on any circuit. Planned as part of &lt;code&gt;cforge-parser&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;arXiv:&lt;/strong&gt; Preprint: &lt;em&gt;"Neutral cross-framework benchmarking reveals Rz sign convention divergence in quantum simulation backends."&lt;/em&gt; Formally citable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enterprise SaaS:&lt;/strong&gt; &lt;code&gt;cforge-enterprise&lt;/code&gt;: per-device calibration tables, Zero-Noise Extrapolation, convention-aware circuit routing. API for teams running multi-backend quantum workloads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tooling:&lt;/strong&gt; Jupyter notebook companion, QASM linter that flags convention-sensitive gates, dashboard for multi-hardware fidelity tracking.&lt;/p&gt;

&lt;p&gt;The SaaS angle is straightforward: quantum teams running the same algorithm on different hardware providers need consistency guarantees that no single provider can offer. CleitonForge is the neutral layer that can.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try it yourself
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;cleitonforge

&lt;span class="c"&gt;# or from source — reproduce the exact findings:&lt;/span&gt;
cargo run &lt;span class="nt"&gt;--release&lt;/span&gt; &lt;span class="nt"&gt;--example&lt;/span&gt; benchmark_suite &lt;span class="nt"&gt;-p&lt;/span&gt; cforge-cli
cargo run &lt;span class="nt"&gt;--release&lt;/span&gt; &lt;span class="nt"&gt;--example&lt;/span&gt; quantum_volume &lt;span class="nt"&gt;-p&lt;/span&gt; cforge-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHub: &lt;a href="https://github.com/cleitonaugusto/cleitonforge" rel="noopener noreferrer"&gt;github.com/cleitonaugusto/cleitonforge&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>quantumcomputing</category>
      <category>opensource</category>
      <category>programming</category>
    </item>
    <item>
      <title>I built a neutral benchmarking layer for quantum simulators in Rust — and it revealed a silent disagreement between two backends</title>
      <dc:creator>Cleiton Augusto Correa Bezerra</dc:creator>
      <pubDate>Sat, 04 Jul 2026 18:26:18 +0000</pubDate>
      <link>https://dev.to/cleiton_augusto_/i-built-a-neutral-benchmarking-layer-for-quantum-simulators-in-rust-and-it-revealed-a-silent-2i59</link>
      <guid>https://dev.to/cleiton_augusto_/i-built-a-neutral-benchmarking-layer-for-quantum-simulators-in-rust-and-it-revealed-a-silent-2i59</guid>
      <description>&lt;p&gt;placeholder&lt;/p&gt;

</description>
      <category>rust</category>
      <category>quantumcomputing</category>
      <category>opensource</category>
      <category>benchmark</category>
    </item>
    <item>
      <title>Nonce Design for Safety-Critical Systems: Lessons from a Post-Quantum MAVLink Protocol</title>
      <dc:creator>Cleiton Augusto Correa Bezerra</dc:creator>
      <pubDate>Tue, 23 Jun 2026 02:39:57 +0000</pubDate>
      <link>https://dev.to/cleiton_augusto_/nonce-design-for-safety-critical-systems-lessons-from-a-post-quantum-mavlink-protocol-2kmc</link>
      <guid>https://dev.to/cleiton_augusto_/nonce-design-for-safety-critical-systems-lessons-from-a-post-quantum-mavlink-protocol-2kmc</guid>
      <description>&lt;p&gt;Replay attacks on drone command links are not theoretical. A ground station sends &lt;code&gt;ARM&lt;/code&gt; at timestamp T. An adversary records the packet. Thirty seconds later they retransmit it verbatim. If the drone accepts it, you have a serious problem — and in a jammed or contested environment, the attacker can do this silently.&lt;/p&gt;

&lt;p&gt;The standard defense is a monotonically increasing nonce: every packet carries a counter, and the receiver only accepts packets with counters strictly greater than the last accepted value. Simple in concept. The implementation details are where things get interesting.&lt;/p&gt;

&lt;p&gt;This post walks through the nonce design in &lt;a href="https://github.com/cleitonaugusto/CleitonQ" rel="noopener noreferrer"&gt;CleitonQ&lt;/a&gt;, a post-quantum authentication layer for MAVLink v2, and the three decisions that are non-obvious but matter for security.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem: Concurrent Control Loops
&lt;/h2&gt;

&lt;p&gt;A drone's onboard software runs several concurrent threads: a 100 Hz telemetry loop, a command processor, and potentially a mesh relay. All of them sign outbound packets. All of them need nonces.&lt;/p&gt;

&lt;p&gt;The naive implementation is a shared &lt;code&gt;u64&lt;/code&gt; behind a &lt;code&gt;Mutex&lt;/code&gt;. It works. It's also a footgun: if two threads call &lt;code&gt;next_nonce()&lt;/code&gt; simultaneously without proper synchronization, they can read the same value, both increment to the same next value, and emit duplicate nonces. The receiver sees the duplicate and treats it as a replay — silently dropping a legitimate command.&lt;/p&gt;

&lt;p&gt;In a flight-critical system, a dropped command is not an acceptable error mode.&lt;/p&gt;

&lt;p&gt;The second naive implementation is &lt;code&gt;fetch_add&lt;/code&gt; on an &lt;code&gt;AtomicU64&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Tempting, but has a subtle problem&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;u64&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="na"&gt;.0&lt;/span&gt;&lt;span class="nf"&gt;.fetch_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;Ordering&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Relaxed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This fixes the race. But it wraps silently at &lt;code&gt;u64::MAX&lt;/code&gt;. After 18.4 quintillion packets — unlikely in practice, but not impossible over the lifetime of a long-running system — nonce 0 becomes valid again. An adversary who stored a packet from the beginning of time can now replay it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Decision 1: Saturate, Don't Wrap
&lt;/h2&gt;

&lt;p&gt;CleitonQ's &lt;code&gt;AtomicNonce::next()&lt;/code&gt; uses a compare-and-exchange loop that saturates at &lt;code&gt;u64::MAX&lt;/code&gt; instead of wrapping:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;u64&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="na"&gt;.0&lt;/span&gt;&lt;span class="nf"&gt;.load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Ordering&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Relaxed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;loop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nn"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;MAX&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nn"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// channel is exhausted, not rolled over&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="na"&gt;.0&lt;/span&gt;&lt;span class="nf"&gt;.compare_exchange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nn"&gt;Ordering&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Relaxed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;Ordering&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Relaxed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;observed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;observed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the counter saturates, the receiver rejects &lt;code&gt;u64::MAX&lt;/code&gt; as a replay (it was already accepted). The channel stops working. That is the correct behavior: a locked channel surfaces as an observable failure — an operator sees it, investigates, and re-establishes the session. A silently rolled-over channel surfaces as an intermittent security hole that nobody notices until it's too late.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fail loudly rather than fail silently.&lt;/strong&gt; In safety-critical systems, this principle is not optional.&lt;/p&gt;

&lt;p&gt;The CAS loop also handles the race correctly: if two threads read the same &lt;code&gt;current&lt;/code&gt;, one wins the exchange and the other retries with the updated value. No duplicates, no locks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Decision 2: Memory Ordering Is Not Symmetric
&lt;/h2&gt;

&lt;p&gt;The sender (&lt;code&gt;AtomicNonce&lt;/code&gt;) and the receiver (&lt;code&gt;NonceTracker&lt;/code&gt;) have different memory ordering requirements, and they are not interchangeable.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;AtomicNonce::next()&lt;/code&gt; uses &lt;code&gt;Relaxed&lt;/code&gt; for both the load and the CAS. This is intentional. The only property needed is that each call returns a unique, strictly increasing value. There is no requirement that the nonce emission &lt;em&gt;happens-before&lt;/em&gt; anything else in the caller's memory. The packet containing the nonce will be serialized and sent over the network — the network ordering establishes the happens-before relationship with the receiver. Using &lt;code&gt;SeqCst&lt;/code&gt; here would be correct but unnecessary, adding synchronization overhead on every outbound packet in a 100 Hz loop.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;NonceTracker::accept()&lt;/code&gt; is different:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="na"&gt;.0&lt;/span&gt;&lt;span class="nf"&gt;.load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Ordering&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Acquire&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;loop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;nonce&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="na"&gt;.0&lt;/span&gt;&lt;span class="nf"&gt;.compare_exchange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nn"&gt;Ordering&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;AcqRel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;Ordering&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Acquire&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;observed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;observed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The receiver uses &lt;code&gt;Acquire&lt;/code&gt; on the load and &lt;code&gt;AcqRel&lt;/code&gt; on the successful exchange. This establishes a happens-before edge: any thread that subsequently reads the tracker's value with &lt;code&gt;Acquire&lt;/code&gt; sees all writes that preceded the accepted nonce. In practice this means: the authentication check that accepted a packet happens-before any processing of that packet's payload. If two threads race to accept the same nonce, exactly one wins the CAS — the other sees &lt;code&gt;nonce &amp;lt;= current&lt;/code&gt; on retry and returns &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;Relaxed&lt;/code&gt; on the receiver would be wrong. It would allow a theoretical reordering where a thread begins processing a payload before the nonce check completes — which, in a language with a memory model that permits this, is a real vulnerability class.&lt;/p&gt;




&lt;h2&gt;
  
  
  Decision 3: Process Restarts Without Persistent State
&lt;/h2&gt;

&lt;p&gt;What happens when the companion computer reboots mid-flight? The &lt;code&gt;AtomicU64&lt;/code&gt; in RAM is gone. If the new process starts from 0, every nonce it emits is below the receiver's &lt;code&gt;last_accepted&lt;/code&gt; — the channel is dead until a new session is established.&lt;/p&gt;

&lt;p&gt;One answer is NVRAM persistence: write the nonce to flash periodically, read it on boot. This works but adds I/O latency on the critical path and creates a new failure mode: flash write corruption during power loss.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;AtomicNonce::from_time()&lt;/code&gt; takes a different approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;from_time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;nanos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;time&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;SystemTime&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.duration_since&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;time&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;UNIX_EPOCH&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.unwrap_or_default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.as_nanos&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;try_from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nanos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap_or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seeding from nanoseconds since the Unix epoch means a restarted process almost certainly starts with nonces higher than anything emitted before the restart. A 10-second reboot adds 10 billion nonces of headroom. A 1-millisecond glitch adds 1 million. The wall clock is the implicit persistent store.&lt;/p&gt;

&lt;p&gt;This relies on the system clock being monotonic across reboots — which is true on any platform with a battery-backed RTC and NTP. On systems without one (some deeply embedded targets), &lt;code&gt;from_time()&lt;/code&gt; is unavailable and the application must manage initial nonce values explicitly.&lt;/p&gt;

&lt;p&gt;The deeper architectural answer is that CleitonQ's session boundary makes this largely moot: a reboot forces a new ML-KEM session, which establishes a new session key. Since nonces are checked within a session (HMAC tags include the session key), cross-session replay is impossible regardless of nonce values.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Embedded Target
&lt;/h2&gt;

&lt;p&gt;Not all targets have 64-bit atomics. Cortex-M4 (the processor in most Pixhawk flight controllers) does not. For these, CleitonQ provides &lt;code&gt;SimpleNonce&lt;/code&gt; and &lt;code&gt;SimpleNonceTracker&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nf"&gt;SimpleNonce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;SimpleNonce&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;next_nonce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;u64&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="na"&gt;.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="na"&gt;.0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="na"&gt;.0&lt;/span&gt;&lt;span class="nf"&gt;.wrapping_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;v&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are not thread-safe — the &lt;code&gt;&amp;amp;mut self&lt;/code&gt; receiver makes that explicit at the type level. On a single-threaded embedded executor, this is correct and zero-overhead. On a multi-threaded target with 64-bit atomics, the compiler will refuse to compile the single-threaded variant in a shared context.&lt;/p&gt;

&lt;p&gt;The platform split is expressed via &lt;code&gt;#[cfg(target_has_atomic = "64")]&lt;/code&gt;, not runtime checks — it's a compile-time guarantee, not a runtime assertion.&lt;/p&gt;




&lt;h2&gt;
  
  
  Testing the Properties
&lt;/h2&gt;

&lt;p&gt;Three properties need tests, not documentation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Uniqueness under concurrency&lt;/strong&gt; — 8 threads each calling &lt;code&gt;next()&lt;/code&gt; 1000 times should produce 8000 distinct nonces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Arc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;AtomicNonce&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Arc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="nf"&gt;.next&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="py"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="nf"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;HashSet&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;threads&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;nonce&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="nf"&gt;.join&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;assert!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="nf"&gt;.insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"duplicate nonce — race in AtomicNonce::next"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Replay rejection&lt;/strong&gt; — the tracker must reject exact replays and regressions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;NonceTracker&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nd"&gt;assert!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="nf"&gt;.accept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nd"&gt;assert!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="nf"&gt;.accept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;   &lt;span class="c1"&gt;// exact replay&lt;/span&gt;
&lt;span class="nd"&gt;assert!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="nf"&gt;.accept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;   &lt;span class="c1"&gt;// regression&lt;/span&gt;
&lt;span class="nd"&gt;assert!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="nf"&gt;.accept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;    &lt;span class="c1"&gt;// forward progress&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;No double-accept under concurrency&lt;/strong&gt; — 4 threads racing to accept nonces 1..=500 should produce exactly 500 total acceptances:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;tracker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Arc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;NonceTracker&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="c1"&gt;// 4 threads, each tries to accept all 500 nonces&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;total_accepted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;usize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="nf"&gt;.into_iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="nf"&gt;.join&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="nf"&gt;.sum&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total_accepted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tracker&lt;/span&gt;&lt;span class="nf"&gt;.last_accepted&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These tests run on every CI push, including on a Neoverse-N2 ARM64 runner that mirrors the hardware profile of production companion computers.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Broader Point
&lt;/h2&gt;

&lt;p&gt;Nonce design looks simple until you consider the combination of concurrent writers, concurrent readers, process restarts, and an adversary who stores packets indefinitely. Each of those constraints pushes the design in a different direction. Getting all four right simultaneously requires explicit reasoning about each decision — not just picking the first implementation that passes the unit tests.&lt;/p&gt;

&lt;p&gt;The three decisions above — saturating arithmetic, asymmetric memory ordering, and clock-seeded initialization — are each defensible in isolation. Together they form a design that fails loudly, maintains happens-before guarantees where they matter, and survives the most common production failure mode (process restart) without persistent state.&lt;/p&gt;

&lt;p&gt;CleitonQ is open source under MIT OR Apache-2.0. The full nonce implementation, with all tests, is in &lt;a href="https://github.com/cleitonaugusto/CleitonQ/blob/main/src/nonce.rs" rel="noopener noreferrer"&gt;&lt;code&gt;src/nonce.rs&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;CleitonQ is a post-quantum authentication layer for MAVLink v2, combining ML-KEM-1024 (FIPS 203) for session establishment and ML-DSA-87 (FIPS 204) for command signing. A formal security model in ProVerif 2.05 verifies session key secrecy (Q1) and command authenticity (Q2) against a Dolev-Yao attacker. &lt;a href="https://doi.org/10.5281/zenodo.20776349" rel="noopener noreferrer"&gt;Paper on Zenodo&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>security</category>
      <category>embedded</category>
      <category>drone</category>
    </item>
    <item>
      <title>Implementing Adaptive Backpressure in Rust with FlowGuard</title>
      <dc:creator>Cleiton Augusto Correa Bezerra</dc:creator>
      <pubDate>Sat, 27 Dec 2025 15:43:34 +0000</pubDate>
      <link>https://dev.to/cleiton_augusto_/implementing-adaptive-backpressure-in-rust-with-flowguard-1iof</link>
      <guid>https://dev.to/cleiton_augusto_/implementing-adaptive-backpressure-in-rust-with-flowguard-1iof</guid>
      <description>&lt;p&gt;Implementing Adaptive Backpressure in Rust with FlowGuard&lt;br&gt;
Hey fellow Rustaceans! 👋&lt;/p&gt;

&lt;p&gt;I recently open-sourced FlowGuard, a library for adaptive concurrency control and backpressure in Rust services. In this post, I'll share why static rate limiting fails and how FlowGuard solves it with TCP Vegas congestion control.&lt;/p&gt;

&lt;p&gt;🤔 The Problem with Static Limits&lt;br&gt;
We've all done this:&lt;/p&gt;

&lt;p&gt;rust&lt;br&gt;
// "Maximum 100 concurrent connections"&lt;br&gt;
let max_connections = 100;&lt;br&gt;
But static limits are a trap:&lt;/p&gt;

&lt;p&gt;Set too high? Your system crashes before reaching the limit&lt;/p&gt;

&lt;p&gt;Set too low? You waste resources and refuse legitimate traffic&lt;/p&gt;

&lt;p&gt;Guessing game? You're always tuning based on hunches&lt;/p&gt;

&lt;p&gt;🚀 The Solution: Dynamic Backpressure&lt;br&gt;
Instead of guessing, what if your system could self-adjust based on real-time performance? That's where FlowGuard comes in.&lt;/p&gt;

&lt;p&gt;Introducing FlowGuard&lt;br&gt;
FlowGuard implements the TCP Vegas congestion control algorithm to dynamically adjust concurrency limits based on actual system latency.&lt;/p&gt;

&lt;p&gt;🎯 How It Works&lt;br&gt;
rust&lt;br&gt;
use flow_guard::{FlowGuard, VegasStrategy};&lt;br&gt;
use std::sync::Arc;&lt;/p&gt;

&lt;h1&gt;
  
  
  [tokio::main]
&lt;/h1&gt;

&lt;p&gt;async fn main() {&lt;br&gt;
    // Start with 10 concurrent operations&lt;br&gt;
    let strategy = Arc::new(VegasStrategy::new(10));&lt;br&gt;
    let guard = FlowGuard::new(Arc::clone(&amp;amp;strategy));&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;println!("Initial limit: {}", guard.current_limit());

// Execute tasks with adaptive backpressure
let result = guard.run(async {
    // Your database query, API call, etc.
    tokio::time::sleep(std::time::Duration::from_millis(100)).await;
    Ok::&amp;lt;_, &amp;amp;str&amp;gt;("Success!")
}).await;

println!("Final limit: {}", guard.current_limit()); // Adjusted!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;br&gt;
✨ Key Features&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Real-time Adjustment
rust
// Watch limits adjust dynamically
println!("Current limit: {}", guard.current_limit());
println!("Available permits: {}", guard.available_permits());&lt;/li&gt;
&lt;li&gt;Vegas Algorithm
Based on the difference between expected and actual throughput:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;✅ Increases limit when system has spare capacity&lt;/p&gt;

&lt;p&gt;✅ Decreases limit when latency indicates congestion&lt;/p&gt;

&lt;p&gt;✅ Self-tuning - no manual configuration needed&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Web Framework Integration
rust
// Axum 0.8 middleware
let strategy = VegasStrategy::new(50);
let flow_layer = FlowGuardLayer::new(strategy);&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;let app = Router::new()&lt;br&gt;
    .route("/api/data", get(handler))&lt;br&gt;
    .layer(flow_layer);&lt;br&gt;
📦 Getting Started&lt;br&gt;
Add to your Cargo.toml:&lt;/p&gt;

&lt;p&gt;toml&lt;br&gt;
[dependencies]&lt;br&gt;
flow-guard = "0.2.1"&lt;/p&gt;

&lt;h1&gt;
  
  
  With Axum/Tower support
&lt;/h1&gt;

&lt;p&gt;flow-guard = { version = "0.2.1", features = ["axum", "tower"] }&lt;br&gt;
🔧 Under the Hood&lt;br&gt;
FlowGuard replaces tokio::sync::Semaphore with a custom DynamicSemaphore that can adjust its limit up and down in real-time:&lt;/p&gt;

&lt;p&gt;rust&lt;br&gt;
pub struct DynamicSemaphore {&lt;br&gt;
    max_permits: AtomicUsize,&lt;br&gt;
    available_permits: AtomicUsize,&lt;br&gt;
    notify: Notify,&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;impl DynamicSemaphore {&lt;br&gt;
    pub fn set_limit(&amp;amp;self, new_limit: usize) {&lt;br&gt;
        // Adjusts permits dynamically based on Vegas calculations&lt;br&gt;
    }&lt;br&gt;
}&lt;br&gt;
🎯 Use Cases&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Database Protection
rust
// Prevent database overload
let db_guard = FlowGuard::new(VegasStrategy::new(20));&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;async fn query_database() -&amp;gt; Result {&lt;br&gt;
    db_guard.run(|| async {&lt;br&gt;
        // Your database query here&lt;br&gt;
        database.query("SELECT * FROM users").await&lt;br&gt;
    }).await``&lt;br&gt;
}&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;API Rate Limiting
rust
// Adaptive rate limiting for external APIs
let api_guard = FlowGuard::new(VegasStrategy::new(5));&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;async fn call_external_api() -&amp;gt; Result {&lt;br&gt;
    api_guard.run(|| async {&lt;br&gt;
        client.get("&lt;a href="https://api.example.com/data%22).await" rel="noopener noreferrer"&gt;https://api.example.com/data").await&lt;/a&gt;&lt;br&gt;
    }).await&lt;br&gt;
}&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Microservices
rust
// Protect services from cascading failures
let service_guard = FlowGuard::new(VegasStrategy::new(100));
📊 Benchmarks
In testing, FlowGuard showed:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;5 → 12 limit adjustment under optimal conditions&lt;/p&gt;

&lt;p&gt;Sub-millisecond overhead per request&lt;/p&gt;

&lt;p&gt;Zero allocation in hot path&lt;/p&gt;

&lt;p&gt;Thread-safe with atomic operations&lt;/p&gt;

&lt;p&gt;🚀 Try It Yourself&lt;br&gt;
bash&lt;/p&gt;

&lt;h1&gt;
  
  
  Clone and run examples
&lt;/h1&gt;

&lt;p&gt;git clone &lt;a href="https://github.com/cleitonaugusto/flow-guard" rel="noopener noreferrer"&gt;https://github.com/cleitonaugusto/flow-guard&lt;/a&gt;&lt;br&gt;
cd flow-guard&lt;br&gt;
cargo run --example basic_usage&lt;br&gt;
🔗 Resources&lt;br&gt;
GitHub: &lt;a href="https://github.com/cleitonaugusto/flow-guard" rel="noopener noreferrer"&gt;https://github.com/cleitonaugusto/flow-guard&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Crates.io: &lt;a href="https://crates.io/crates/flow-guard" rel="noopener noreferrer"&gt;https://crates.io/crates/flow-guard&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Documentation: &lt;a href="https://docs.rs/flow-guard/0.2.1/" rel="noopener noreferrer"&gt;https://docs.rs/flow-guard/0.2.1/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Examples: basic_usage.rs, server_demo.rs&lt;/p&gt;

&lt;p&gt;💭 Why I Built This&lt;br&gt;
After seeing too many services crash from static limits or waste resources with conservative settings, I wanted a solution that adapts to actual system performance. The TCP Vegas algorithm has been battle-tested for decades in networking - why not apply it to service concurrency?&lt;/p&gt;

&lt;p&gt;🤝 Contributing &amp;amp; Feedback&lt;br&gt;
FlowGuard is open source under MIT license. I'd love your:&lt;/p&gt;

&lt;p&gt;Feedback on the API design&lt;/p&gt;

&lt;p&gt;Use cases from your projects&lt;/p&gt;

&lt;p&gt;Contributions to the codebase&lt;/p&gt;

&lt;p&gt;Ideas for improvements&lt;/p&gt;

&lt;p&gt;What adaptive concurrency patterns have you used in your Rust projects? Share in the comments!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>webdev</category>
      <category>rust</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
