mirror of
https://github.com/jmcorgan/fips.git
synced 2026-07-22 07:48:26 +00:00
proto: no_std hygiene for the fmt/alloc imports and the filter math
Bring the proto tree closer to a std+alloc-only posture, behavior unchanged on every decision path: - Sweep the remaining std::fmt and std::collections imports over to core::fmt and alloc::collections across the wire codecs and their tests. Subsystem files that shadow the core name with a child core module use the leading-colon ::core::fmt form. Imports only. - Replace the two f64::powi calls (bloom false-positive-rate, FMP backoff timer) with a shared core-only square-and-multiply helper in proto/math, bit-identical to std::powi (a guard test pins this against every exponent the codecs reach), and route the diagnostic estimated-count natural log through libm::log. The FPR reject decision and the backoff timer are bit-for-bit unchanged; only the debug-only count estimate may differ by at most one ULP.
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1087,6 +1087,7 @@ dependencies = [
|
||||
"hex",
|
||||
"hkdf",
|
||||
"libc",
|
||||
"libm",
|
||||
"mdns-sd",
|
||||
"nostr",
|
||||
"nostr-sdk",
|
||||
|
||||
@@ -17,6 +17,7 @@ secp256k1 = { version = "0.30", features = ["rand", "global-context"] }
|
||||
sha2 = "0.10"
|
||||
hkdf = "0.12"
|
||||
ring = "0.17"
|
||||
libm = "0.2"
|
||||
rand = "0.10.1"
|
||||
crossbeam-channel = "0.5"
|
||||
thiserror = "2.0"
|
||||
|
||||
@@ -141,7 +141,7 @@ impl BloomFilter {
|
||||
|
||||
/// Current false-positive rate: fill ratio raised to the hash count.
|
||||
pub fn fpr(&self) -> f64 {
|
||||
self.fill_ratio().powi(self.hash_count as i32)
|
||||
crate::proto::math::powi(self.fill_ratio(), self.hash_count as u32)
|
||||
}
|
||||
|
||||
/// Estimate the number of elements in the filter.
|
||||
@@ -170,7 +170,7 @@ impl BloomFilter {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(-(m / k) * (1.0 - fill).ln())
|
||||
Some(-(m / k) * libm::log(1.0 - fill))
|
||||
}
|
||||
|
||||
/// Check if the filter is empty.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Tests for `BloomState` (announcement state management).
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use alloc::collections::BTreeMap;
|
||||
|
||||
use crate::proto::bloom::{BloomFilter, BloomState};
|
||||
use crate::testutil::make_node_addr;
|
||||
|
||||
@@ -640,5 +640,5 @@ impl Fmp {
|
||||
/// arithmetic (the exponent is the resend count *after* this attempt).
|
||||
fn next_resend_at_ms(now_ms: u64, interval_ms: u64, backoff: f64, prior_count: u32) -> u64 {
|
||||
let count = prior_count + 1;
|
||||
now_ms + (interval_ms as f64 * backoff.powi(count as i32)) as u64
|
||||
now_ms + (interval_ms as f64 * crate::proto::math::powi(backoff, count)) as u64
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
use crate::proto::Error;
|
||||
use crate::proto::codec::Reader;
|
||||
use crate::proto::link::LinkMessageType;
|
||||
use std::fmt;
|
||||
use ::core::fmt;
|
||||
|
||||
/// Handshake message type identifiers.
|
||||
///
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::proto::fsp::core::{
|
||||
use crate::proto::fsp::limits::FSP_CUTOVER_DELAY_MS;
|
||||
use crate::proto::stp::TreeCoordinate;
|
||||
use crate::testutil::make_node_addr;
|
||||
use std::collections::VecDeque;
|
||||
use alloc::collections::VecDeque;
|
||||
|
||||
fn coords(byte: u8) -> TreeCoordinate {
|
||||
TreeCoordinate::from_addrs(vec![make_node_addr(byte)]).unwrap()
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
use crate::proto::Error;
|
||||
use crate::proto::codec::{Reader, Writer};
|
||||
use crate::proto::stp::{TreeCoordinate, decode_coords, decode_optional_coords, encode_coords};
|
||||
use std::fmt;
|
||||
use ::core::fmt;
|
||||
|
||||
// ============================================================================
|
||||
// Constants
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
use crate::NodeAddr;
|
||||
use crate::proto::Error;
|
||||
use std::fmt;
|
||||
use core::fmt;
|
||||
|
||||
// ============================================================================
|
||||
// Link-Layer Message Types
|
||||
|
||||
55
src/proto/math.rs
Normal file
55
src/proto/math.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
//! no_std-shaped numeric helpers for the protocol cores.
|
||||
//!
|
||||
//! `f64::powi` and the transcendental methods live in `std`, not `core`. The
|
||||
//! helpers here keep the small amount of protocol math the codecs need in a
|
||||
//! `core`-only shape so the cores stay portable, without changing any result.
|
||||
|
||||
/// Raise `base` to a non-negative integer power via square-and-multiply.
|
||||
///
|
||||
/// Bit-identical to `f64::powi` for the exponents the codecs use: it mirrors the
|
||||
/// compiler-rt `__powidf2` multiply order (multiply-then-square, skipping the
|
||||
/// final square), so — floating-point multiplication being non-associative — it
|
||||
/// reproduces `powi` exactly rather than a naive left-to-right product. The
|
||||
/// `powi_bit_identical_to_std` test pins this. Keeping it bit-identical matters:
|
||||
/// the bloom false-positive-rate feeds a reject comparison and the FMP backoff
|
||||
/// feeds a `u64` timer, so any drift could change a decision.
|
||||
pub(crate) fn powi(base: f64, exp: u32) -> f64 {
|
||||
let mut result = 1.0_f64;
|
||||
let mut b = base;
|
||||
let mut e = exp;
|
||||
loop {
|
||||
if e & 1 == 1 {
|
||||
result *= b;
|
||||
}
|
||||
e >>= 1;
|
||||
if e == 0 {
|
||||
break;
|
||||
}
|
||||
b *= b;
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::powi;
|
||||
|
||||
#[test]
|
||||
fn powi_bit_identical_to_std() {
|
||||
// The core square-and-multiply must match f64::powi bit-for-bit across
|
||||
// representative bases and every exponent the protocol math reaches, so
|
||||
// the FPR reject decision and the backoff timer are unchanged.
|
||||
let bases = [
|
||||
0.0, 1.0, 0.5, 0.5469, 0.5493, 0.5508, 0.9999, 1.5, 2.0, 3.7, 0.1, 1e-3,
|
||||
];
|
||||
for &base in &bases {
|
||||
for exp in 0u32..=64 {
|
||||
assert_eq!(
|
||||
powi(base, exp).to_bits(),
|
||||
base.powi(exp as i32).to_bits(),
|
||||
"powi mismatch at base={base}, exp={exp}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ pub(crate) mod discovery;
|
||||
pub(crate) mod fmp;
|
||||
pub(crate) mod fsp;
|
||||
pub(crate) mod link;
|
||||
pub(crate) mod math;
|
||||
pub(crate) mod mmp;
|
||||
pub(crate) mod rate_limit;
|
||||
pub(crate) mod routing;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Flap dampening / hold-down unit tests.
|
||||
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use alloc::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
use super::util::{make_coords, make_costs, make_node_addr};
|
||||
use crate::proto::stp::{ParentDeclaration, ParentEval, TreeState};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! ParentDeclaration, TreeState, parent-selection, and find_next_hop unit tests.
|
||||
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use alloc::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
use super::util::{add_peer, make_coords, make_costs, make_node_addr, make_tree_state};
|
||||
use crate::proto::stp::{ParentDeclaration, ParentEval, TreeCoordinate, TreeState};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Shared test helpers for the STP primitive unit tests.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use alloc::collections::BTreeMap;
|
||||
|
||||
use crate::NodeAddr;
|
||||
use crate::proto::stp::{ParentDeclaration, TreeCoordinate, TreeState};
|
||||
|
||||
Reference in New Issue
Block a user