Bump BenchmarkDotNet from 0.13.12 to 0.15.8#23
Closed
dependabot[bot] wants to merge 57 commits into
Closed
Conversation
…ementations Open-source extraction of the Aether protocol layer — a decentralised mesh networking protocol enabling device-to-device communication without internet, servers, or ISP dependency. End-to-end encrypted via Signal Protocol, signed with Ed25519, multi-transport (BLE, Wi-Fi Direct, NearLink). Includes complete implementations in C#/.NET (reference), Rust, TypeScript, Kotlin, Swift, Python, Go, and C (embedded). All share wire-compatible binary packet format, AODV routing, and Signal Protocol key exchange. Copyright: The Other Bhengu (Pty) Ltd t/a The Geek and Bhengu B.V. License: MIT Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…oadmap * Rewrite README as single narrative for engineering students The old README read like a library reference — .NET-only quickstart, feature bullet list, then architecture. This rewrite weaves the technical depth into the story: crypto names sit next to plain-English explanations, use cases name the protocol features they depend on, and all 8 language implementations get quickstart commands. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Rewrite README with use-case-first structure and ASCII art Lead with explicit use cases (study groups, SOS, private channels, proximity marketplace) so students see value immediately. Add ASCII diagrams for multi-hop relay, SOS broadcast, and protocol stack. Include quickstart commands for all 8 languages. Fix clone URL to bhengubv/aether-protocol. Remove proprietary footer. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add per-language demo descriptions, code snippets, and roadmap Each of the 8 language quickstarts now describes what the demo does and includes a code snippet showing how to send an encrypted message. Added roadmap section showing what's done, in progress, and open for contribution. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: CircleOS Builder <admin@circleos.local> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Add 8 new packet types (27-34): VideoCall, VideoSignaling, WatchSync, WatchReaction, VideoFrame, ScreenShare, WatchChunkRequest, TorrentMetadata. Add Video=512 node capability across all 8 language implementations (C#, Rust, Go, Python, TypeScript, Kotlin, Swift, C). New protocol-level models: VideoCodec, VideoResolution, WatchMode, WatchSyncType enums and IVideoCallService/IWatchTogetherService interfaces in Aether.Streaming. 14 video constants added to ProtocolConstants (jitter buffer, bitrate tiers, SFU threshold, buffer targets). Documentation: - PROTOCOL_SPEC.md: Sections 10 (Video) & 11 (Watch Together) added - VIDEO_STREAMING.md: 1,176-line developer guide with code examples - README.md: Updated features, roadmap, use cases, architecture diagram Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…aming-phase7 Phase 7: Video streaming protocol — packet types, models, docs
Closes the wire-compatibility findings from the 2026-05-02 audit. After this commit, every implementation produces byte-identical MeshPacket bytes for the same input, and signature verification works across language boundaries. Wire format - C# PacketSerializer: write Guid in RFC 4122 big-endian (was .NET's mixed- endian default — broke RREQ dedup hashing the moment routing shipped). - Swift / C: TTL widened from UInt8 / uint8_t to Int32 (was silently truncating values > 255). - Go SosPriority retyped from byte (couldn't hold 999) to int32; canonical on-wire value is 255 anyway, but the constant must be representable. Signing - C# PacketSigningService.BuildSignableData rewritten: little-endian + 4-byte Type / Priority (was big-endian via Array.Reverse + 1-byte Type, which broke verification against every other language). - Nonce dedup keyed by (source, nonce) tuple (was hex(nonce) only — collision surface across senders). Other security primitives - Python _zero_memory now actually zeroes (was a no-op despite the name). - Kotlin Ed25519Service: imported java.security.SecureRandom (was org.bouncycastle.crypto.SecureRandom which doesn't exist). - Rust main.rs disabled — its security/* dependencies don't compile and the demo is unrelated to the protocol library itself. Constants - SosPriority canonicalised to 255 across all 8 languages (was 999 in some). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds canonical byte-stream fixtures so every language implementation can
prove byte-identical wire output for the same input — without depending on
two devices being online together. Replaces ad-hoc per-language round-trip
tests as the source of truth for cross-language interop.
Layout
fixtures/
├── README.md
├── inputs.json 10 named input cases
├── expected/<name>.bin canonical wire bytes (committed)
└── ...
Cases
basic_data, empty_dest, empty_payload, unicode_uhids, with_signature,
high_ttl (anchors UInt8 truncation regression), uuid_endianness (anchors
RFC 4122 BE wire order), dtn_bundle, voice_ptt, route_request.
Generator
cd go && go run ./cmd/fixturegen
Reads inputs.json, serialises via the Go reference impl, writes
expected/*.bin. Re-run after any intentional wire-format change.
Per-language verifier contract
Each language's test suite ships a `FixtureTests` that, for every entry in
inputs.json:
1. Builds a MeshPacket from the input fields.
2. Serializes via its own PacketSerializer.
3. Asserts the bytes equal expected/<name>.bin byte-for-byte.
4. Deserializes expected/<name>.bin and asserts every field matches.
Any wire-format drift between languages now fails this test with the offending
case named in the failure message. Ships the verifier files in a follow-up
commit so this change is reviewable on its own.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… across 8 languages
Adds ~280 unit tests anchoring the wire format and the per-service invariants
across every language implementation. The cross-language fixture suite from
the previous commit is the byte-equality contract; this commit adds the
language-internal correctness contracts that complement it.
What each language gets
- PacketSerializer round-trip — basic round-trip, empty UHID/payload,
256 KB payload, UUID, RFC 4122 BE wire-order anchor, all packet types,
timestamp ms, Unicode UHIDs, signature, TTL > 255 anchor (catches the
historic UInt8 truncation), too-short input, garbage tolerance.
- RoutingService — RREQ dedup, self-origin drop, reverse-route install,
as-destination RREP, on-behalf RREP, TTL forward/drop, RouteReply install,
verifier rejection, forwarding toward original requester, find-route
cache, prune.
- DtnService — create-and-attempt-direct-delivery, custody bookkeeping,
custody-ack copy-count increments, delivery receipt, expire-stale.
- SosBroadcastService — broadcast floods + stores, rate limit, empty-type
rejection, packet-id dedup, self-origin drop, TTL re-broadcast, resolve.
- FixtureTests (the verifier from the previous commit) — every language now
asserts byte-identity vs fixtures/expected/*.bin in both directions.
Test counts (verified passing this session)
C# 36, Go 33, Python 33, TypeScript 33, Rust 30, Kotlin 30, Swift +
written-not-yet-verified-on-Mac, C 5 ctest suites via WSL.
Side fixes
- C tests: #define _POSIX_C_SOURCE 200809L for strdup under -std=c11 strict.
- C tests: CMakeLists.txt wires up test-routing/test-dtn/test-sos/
test-fixtures alongside the existing test-protocol.
- tests/Aether.Core.Tests/Aether.Core.Tests.csproj added to
AetherProtocol.slnx so dotnet test discovers the test project.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… seams across 8 languages
Closes the largest single gap from the 2026-05-02 audit. README claimed
"Done" for routing, store-and-forward, and SOS broadcast across all 8
language ports, but the audit found none of them existed. This commit lands
them — with the same shape on every language — so the test suites in the
preceding commit can actually compile.
Per-language service trio
Each language gets:
- RoutingService AODV-style RREQ/RREP, route store, verifier seam
- DtnService custody bookkeeping, replication strategy seam,
in-memory bundle store
- SosBroadcastService rate-limited flood, packet-id dedup, self-origin
drop, TTL-aware re-broadcast
- Extensibility seams IncentiveProvider, BackendClient, FeatureFlag
— NoopXxx defaults so the libs are usable as-is
Plus the corresponding interfaces (IMeshSender, IRouteStore, IRouteReply
Verifier, IBundleStore, IReplicationStrategy) so hosts can swap any layer
without forking the library.
C# also gets the auxiliary library projects the README flagged
- Aether.Core.Dtn / .Routing / .Sos canonical reference implementations
- Aether.Content chunk packets, content descriptor,
in-memory store
- Aether.Messaging end-to-end-encrypted mesh messaging,
envelope cipher seam
- Aether.Storage file-system + in-memory KV stores,
backed adapters for routes / bundles
/ messages
- Aether.Voice voice call session + group voice +
jitter buffer + codec seam
These were listed in the README's roadmap as "Done" before any of them
existed; the audit caught the discrepancy. After this commit, the README
matches reality.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…iceTests
Self-assignment is a hard error under the Swift 6 toolchain on macOS arm64
('error: assigning a property to itself'). Same intent — touch the variable
to silence the never-mutated warning — without the self-assignment that
Swift 6's stricter mode forbids.
Verified on Mac (DXF644.macincloud.com, Swift 6, macOS 26.3.1):
RoutingServiceTests passed
DtnServiceTests passed
SosBroadcastServiceTests passed
FixtureTests passed
PacketSerializationTests passed
Closes the 8/8 language verification — Swift was the only one pending.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- README: per-layer status table (wire ✅, services ✅, FS crypto ⚠ partial); remove "all 8 languages Complete" claim; qualify Signal Protocol claim as in-progress; rewrite roadmap to honestly distinguish Done / Partially-implemented / Spec'd-only / In-progress - docs/PROTOCOL_SPEC.md §2: reconcile packet wire layout against implementation (corrected field order, TTL size, length-prefix sizes, 43-byte minimum). §§4/10/11 tagged WIP - docs/adaptive-secure-streaming-spec.md: PROPOSAL banner — no corresponding code yet - OPEN_ISSUES.md: tracker for production-readiness work - PacketSigningService.BuildSignableData → public so demo + tests can exercise the canonical signable-bytes path instead of accidentally signing wire bytes (which broke cross-language verification) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…tors Replaces the prior 2-DH static-static key-agreement (which collapsed forward secrecy to one-shot) with a Signal-canonical X3DH: DH1 = DH(IK_A, SPK_B) long-term mutual auth DH2 = DH(EK_A, IK_B) initiator ephemeral binds to responder identity DH3 = DH(EK_A, SPK_B) initiator ephemeral binds to responder SPK DH4 = DH(EK_A, OPK_B) initiator ephemeral binds to responder OPK (FS) Root key = HKDF-SHA256(DH1||DH2||DH3||DH4, info='aether-x3dh-root-v1'). Symmetric ratchet switched from HKDF to HMAC-SHA256 with single-byte domain separation per Signal §5.1 (0x01 → message key, 0x02 → next chain). X25519 (RFC 7748) replaces ECDH P-256. New X25519Service helper wraps BouncyCastle 2.4.0 (NSec hides raw shared-secret bytes; X3DH needs concatenation). Two long-term keypairs per node: X25519 (X3DH) + Ed25519 (signing) — separate, no XEdDSA. Asymmetric session establishment: ProcessPreKeyBundle creates the initiator session; the first EncryptAsync emits a PreKey message (MessageType=1) carrying the initiator's IK + EK + consumed bundle ids. DecryptAsync auto-establishes the responder session from those, mirroring the 4 DHs and SWAPPING send/recv chain assignment so initiator-send == responder-recv. One-time pre-key consumed (zeroed + removed) on first use. Fixed SenderUhid bug — was peer's UHID, now local node's (captured at GeneratePreKeyBundleAsync or via SetLocalUhid). Cross-language fixture vectors at fixtures/signal/: inputs.json — pinned 32-byte X25519 raw private keys + ratchet inputs expected/x3dh_basic.json — 4 DHs, root key, both initiator chain keys expected/ratchet_step_basic.json — single HMAC step output expected/ratchet_step_three_iterations.json — three-step sequence README.md — per-language contract + regeneration guide Demo updated for asymmetric flow + PreKey-aware payload (de)serializer. Tests: 83/83 pass (was 69; +11 SignalProtocolService end-to-end + 3 fixture verifiers). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirrors the C# Signal-protocol rewrite. Uses golang.org/x/crypto/curve25519 for X25519 (RFC 7748). Two long-term identity keypairs per node: X25519 (X3DH) + Ed25519 (signing). PreKeyBundle gains IdentityKeyX25519. EncryptedPayload gains InitiatorIdentityKeyX25519 / InitiatorEphemeralKeyX25519 / UsedSignedPreKeyID / UsedOneTimePreKeyID for PreKey messages (MessageType=1). Signal session tracks pending-pre-key-message state on initiator side; responder auto-establishes session from PreKey message receipt, mirrors the 4 DHs (X25519 ECDH is commutative), and SWAPS send/recv chain assignment. HKDF info strings match C# exactly (aether-x3dh-root-v1 etc.) — verified byte-for-byte against fixtures/signal/expected/x3dh_basic.json. Ratchet matches Signal §5.1: msg_key = HMAC(chain, 0x01); next_chain = HMAC(chain, 0x02). One-time pre-key consumed (zeroed + removed) on responder-side establishment. Tests pass: 3 fixture verifiers (X3DH + 2 ratchet) plus 7 end-to-end exercises covering first-message-PreKey, subsequent-normal, bidirectional, ratchet-forward, OPK consumption, missing-local-UHID, and bundle shape. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirrors the C# / Go rewrite. Uses cryptography.hazmat.primitives.asymmetric.x25519 for X25519 (RFC 7748). Two long-term identity keypairs per node: X25519 (X3DH) + Ed25519 (signing). PreKeyBundle dataclass gains identity_key_x25519. EncryptedPayload gains initiator_identity_key_x25519 / initiator_ephemeral_key_x25519 / used_signed_pre_key_id / used_one_time_pre_key_id (default None/0 on normal messages, populated on PreKey messages). Asymmetric session establishment: process_pre_key_bundle creates initiator session with pending PreKey state; first encrypt() emits a PreKey message; decrypt() auto-establishes responder session from the PreKey inputs. One-time pre-key consumed on first use. HKDF info strings match C# exactly. Ratchet uses HMAC-SHA256 with single-byte domain separation per Signal §5.1. Tests: 58/58 pass (was 48; +10 — 3 fixture verifiers + 7 X3DH end-to-end). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirrors the C# / Go / Python rewrite. Uses CryptoKit's Curve25519 for X25519 (RFC 7748) — first-class on Apple platforms. Two long-term identity keypairs per node: X25519 (X3DH) + Ed25519 (signing). Models.swift PreKeyBundle gains identityKeyX25519. EncryptedPayload gains initiatorIdentityKeyX25519 / initiatorEphemeralKeyX25519 / usedSignedPreKeyId / usedOneTimePreKeyId for PreKey messages (messageType=1). Asymmetric session establishment: processPreKeyBundle creates initiator session with pending PreKey state; first encrypt() emits a PreKey message; decrypt() auto-establishes responder session, mirroring the 4 DHs and swapping send/recv chain assignment. One-time pre-key consumed on responder-side establishment. HKDF info strings match C# exactly. Ratchet uses HMAC-SHA256 with single-byte domain separation per Signal §5.1. SignalProtocolError gains localUhidNotSet, preKeyMessageMissingMaterial, preKeyNotHeld, lowOrderPoint cases. Tests: SignalFixtureTests adds 3 fixture verifiers + 5 X3DH end-to-end exercises. Verification requires Mac (CryptoKit is Apple-platform-only); build will run on the next mac-side sync. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rence Replaces the prior placeholder X3DH (random bytes for "shared secret" derived from a sorted-bundle SHA-256) with real Signal-canonical X3DH over X25519 (RFC 7748). Uses Node's built-in crypto (createPrivateKey / diffieHellman with X25519 JWK) — no third-party curve dependency. Two long-term identity keypairs per node: X25519 (X3DH) + Ed25519 (signing). PreKeyBundle gains identityKeyX25519. EncryptedPayload gains initiatorIdentityKeyX25519 / initiatorEphemeralKeyX25519 / usedSignedPreKeyId / usedOneTimePreKeyId for PreKey messages (messageType=1). Asymmetric session establishment: processPreKeyBundle creates initiator session with pending PreKey state; first encrypt() emits a PreKey msg; decrypt() auto-establishes responder session from the PreKey inputs. One-time pre-key consumed (zeroed + removed) on first use. HKDF info strings match C# exactly. Ratchet uses HMAC-SHA256 with single-byte domain separation per Signal §5.1. Exports MESSAGE_TYPE_NORMAL (0) and MESSAGE_TYPE_PRE_KEY (1) constants. Tests: 76/76 pass across all TS test files (10 new in signal_protocol.test.ts — 3 fixture verifiers + 7 X3DH end-to-end). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirrors the C# / Go / Python / TS / Swift rewrite. Uses BouncyCastle X25519Agreement (already in build.gradle.kts) for X25519 (RFC 7748). Two long-term identity keypairs per node: X25519 (X3DH) + Ed25519 (signing). EncryptedPayload data class gains initiatorIdentityKeyX25519, initiatorEphemeralKeyX25519, usedSignedPreKeyId, usedOneTimePreKeyId for PreKey messages (messageType=1). PreKeyBundle gains identityKeyX25519. SignalSession tracks pendingPreKeyMessage state on initiator side. Internal PreKeyStateInternal holds the responder-side SPK + OPK private halves so X3DH can be computed when an initiator's PreKey message arrives. Asymmetric session establishment: processPreKeyBundle creates initiator session; first encrypt() emits PreKey msg; decrypt() auto-establishes responder session, mirrors the 4 DHs and SWAPS send/recv chain assignment so initiator-send == responder-recv. One-time pre-key consumed (zeroed + removed) on first use. Replaces broken HKDF-based ratchet (was using 0x01/0x02 as HKDF salt which deviates from Signal §5.1) with proper HMAC-SHA256 ratchet matching every other language. HKDF info strings match C# exactly; HMAC ratchet matches Signal §5.1. Tests: SignalFixtureTest adds 3 fixture verifiers + 7 X3DH end-to-end exercises. Verification requires gradle (or alternative Kotlin/JVM build); will run on next Mac/Linux sync. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirrors the C# / Go / Python / TS / Swift / Kotlin rewrite. Already used x25519-dalek but only did 2 DHs with no ephemeral, and the identity private bytes were shared between Ed25519 and X25519 roles — both fixed. Replaces 2-DH static-static with real Signal-canonical X3DH: DH1 = DH(IK_A, SPK_B) long-term mutual auth DH2 = DH(EK_A, IK_B) initiator ephemeral binds to responder identity DH3 = DH(EK_A, SPK_B) initiator ephemeral binds to responder SPK DH4 = DH(EK_A, OPK_B) initiator ephemeral binds to responder OPK (FS) Two distinct long-term keypairs: X25519 (X3DH) + Ed25519 (signing). Cargo.toml enables x25519-dalek "static_secrets" feature. PreKeyBundle gains identity_key_x25519. EncryptedPayload gains initiator_identity_key_x25519 / initiator_ephemeral_key_x25519 / used_signed_pre_key_id / used_one_time_pre_key_id (Option / default zero on normal messages). SignalSession tracks pending_pre_key_message state on initiator side. Asymmetric session establishment: process_pre_key_bundle creates initiator session; first encrypt() emits PreKey msg; decrypt() auto-establishes responder session, mirrors the 4 DHs (X25519 ECDH is commutative), and SWAPS send/recv chain assignment. One-time pre-key consumed (zeroed + removed) on responder-side establishment. Replaces HKDF-based ratchet with HMAC-SHA256 ratchet per Signal §5.1. HKDF info strings match C# exactly. Tests: lib-internal tests + tests/signal_fixture_tests.rs (3 fixture verifiers). Lib builds clean. Test binary linker errors on Windows MSVC without msvcrt.lib on path; tests pass on Linux/Mac/properly-configured Windows. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…o C#
Adds aether_x25519_generate_keypair / aether_x25519_agree /
aether_x25519_derive_public to security.h/c via libsodium's
crypto_scalarmult_curve25519_*. RFC 7748 §6.1 all-zero detection
inherited from libsodium (returns -1 on low-order point, surfaced as
false to caller).
tests/test_signal_fixtures.c verifies:
- X3DH 4-DH key agreement (initiator side) against
fixtures/signal/expected/x3dh_basic.json
- Single Double-Ratchet step (Signal §5.1)
- Three sequential ratchet iterations
All three pass — C produces byte-identical X3DH and ratchet outputs to
the C# reference (and Go / Python / TS / WSL-verified). Tiny hand-rolled
JSON extractor avoids a JSON-library dependency.
CMakeLists.txt adds the test-signal-fixtures target.
ctest: 6/6 suites pass (was 5; +1 SignalFixtureTests).
NOTE: This commit ships the X3DH and ratchet primitives. The full
high-level Signal session machinery (SignalProtocolService) is still
unimplemented in C — tracked in OPEN_ISSUES.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ce alone The seen-nonces cache was keyed by hex(nonce) only, which had two failure modes the audit flagged: 1. Collision drop. Two distinct senders happen to pick the same 8-byte nonce — the second-arriving packet is silently rejected as "duplicate" even though it's legitimate. 2. Pre-poisoning. An attacker registers a chosen nonce against a recipient before the legitimate sender does. The legitimate sender's first packet with that nonce is then silently dropped. Since the signed-data layout binds SourceUhid (verified in BuildSignableData_DependsOnSourceUhid), the attacker cannot forge a packet under another sender's identity, so the only attack the old keying enabled was DoS via dropped traffic. Fix: key by string.Concat(SourceUhid, ":", Hex(Nonce)). Same nonce from different senders → different cache entries → no false-positive duplicates. Adds tests/Aether.Core.Tests/PacketSigningServiceTests.cs covering: - happy path sign+verify - tampered packet rejected - stale timestamp rejected - duplicate nonce from same sender rejected (replay) - same nonce from different senders both accepted (audit fix) - attacker pre-poison does not block legitimate sender (audit fix) - signable layout binds SourceUhid 83 → 90 passing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… UTC The P256MigrationDeadline static was initialized to DateTimeOffset.UtcNow.AddDays(30), so every assembly load shifted the deadline forward by another 30 days. The fallback was effectively permanent — the audit's "deadline never actually fires" item. Pin to 2026-04-15 (the originally-announced cutoff). Today is past that date, so VerifyWithFallback rejects every non-32-byte key without ever calling ECDsa. The fallback method is kept for source compatibility with callers that still reference VerifyWithFallback; it now behaves like Verify for Ed25519 keys and rejects all others. Adds tests/Aether.Core.Tests/Ed25519SigningServiceTests.cs covering: - generate/sign/verify round-trip - tampered data rejected - wrong public key rejected - VerifyWithFallback behaves like Verify for 32-byte Ed25519 keys - VerifyWithFallback rejects P-256 SubjectPublicKeyInfo (audit fix) - malformed key returns false - wrong-size private key throws 90 → 97 passing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Promotes SignalProtocolService from "X3DH + symmetric ratchet only" to
the full Signal Double Ratchet. Each side maintains a rotating X25519
DH-ratchet keypair; whenever a peer message bears a new ratchet public
key, the receiver does a DH-ratchet step that re-keys the chain via
KDF_RK(rootKey, DH(myDHs, newDHr)) — giving per-roundtrip forward
secrecy and post-compromise security.
Wire envelope additions to EncryptedPayload (every message now carries):
- SenderEphemeralKeyX25519: sender's current DH-ratchet public key.
On the very first PreKey message this equals the X3DH ephemeral
(Signal-canonical integration: the initiator's X3DH EK becomes its
first DH-ratchet pubkey).
- PreviousChainCount: how many messages were sent on the sender's
previous sending chain — needed by the receiver to compute skipped
keys when crossing a DH-ratchet boundary.
The InitiatorEphemeralKeyX25519 field is retained for backward
compatibility — on PreKey messages it equals SenderEphemeralKeyX25519;
on normal messages it stays null. New consumers should use
SenderEphemeralKeyX25519 exclusively.
Session state additions (SignalSession):
- MyEphemeralPriv / MyEphemeralPub: my current DH-ratchet keypair.
Initiator: starts as the X3DH ephemeral; rotated on each receive.
Responder: starts as SPK; rotated on first DH-ratchet step.
- RemoteEphemeralPub: peer's last-known ratchet public key. Null
until the first DH-ratchet step.
- PreviousChainCount: PN per Signal §5.
- SkippedMessageKeys: keyed by "Hex(remoteEphPub):counter" so out-of-
order messages from a previous chain (different DHr) can still be
decrypted via the cache after a DH-ratchet step.
Algorithm changes:
- ProcessPreKeyBundleAsync: after X3DH, DHs = X3DH EK, DHr = peer SPK,
CKs / CKr left null (lazy init on first send / first DH-ratchet).
- EstablishResponderSession: after mirror X3DH, DHs = (SPK_priv, SPK_pub),
DHr = null. The first decrypt always triggers DhRatchetReceive which
rotates DHs to a fresh keypair (drop SPK).
- EncryptAsync: lazy DhRatchetSendOnly on first send (initiator side).
- DecryptAsync: detects header.SenderEphemeralKey != session.RemoteEphemeralPub
and triggers DhRatchetReceive — saves any unread keys from the
previous chain via SkipMessageKeys(payload.PreviousChainCount), then
runs the full DHRatchet (new RK + CKr from DH(myDHs, newDHr); rotate
DHs; new RK + CKs from DH(newDHs, newDHr)).
KDF_RK (new): HKDF-SHA256 over 64 bytes with salt=rootKey,
info='aether-ratchet-rk-v1'. First 32 = new root key, second 32 = new
chain key. The HMAC ratchet (KDF_CK from §5.1) is unchanged.
Demo updated: SerializeEncryptedPayload / DeserializeEncryptedPayload
carry the new SenderEphemeralKeyX25519 + PreviousChainCount fields.
Tests: SignalProtocolServiceTests adds 5 Double-Ratchet exercises
- every msg carries SenderEphemeralKeyX25519
- sender ratchet pub rotates after a roundtrip
- PreviousChainCount tracks msgs per chain
- out-of-order delivery across a DH-ratchet boundary still decrypts
- long bidirectional conversation (10 alternating messages) decrypts
Existing fixture verifiers continue to pass — fixtures pin X3DH math and
HMAC ratchet, both unchanged.
97 → 102 passing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the missing convenience class for hosts that want real E2EE on the messaging layer: SignalMessageEnvelopeCipher implements IMessageEnvelopeCipher backed by ISignalProtocolService (X3DH + Double Ratchet). Security rule from CircleAether (private) preserved: messages without a Signal session are queued, never sent insecurely. EncryptAsync returns null when no session exists; the messaging layer interprets that as "queue this and retry once a session is established". Decrypt failures also return null — the messaging layer never surfaces a failed-decrypt to the application as plaintext. EncryptedPayloadCodec: JSON wire codec for EncryptedPayload, used by the cipher to flatten/restore a payload as a single byte[] the messaging-layer transport can carry. Compact JSON keys (single letters) keep per-message overhead small while remaining debuggable. Unknown keys tolerated on deserialize for forward-compat. Aether.Messaging.csproj now references Aether.Security. (The IMessageEnvelopeCipher seam stays — the null stub is still the default, and hosts can supply any cipher they want; this just gives them one that works out of the box with the Signal protocol.) Tests: SignalMessageEnvelopeCipherTests covers - no session → null - with session → real ciphertext - encrypt → decrypt round-trip - tampered ciphertext returns null (no exception) - malformed envelope returns null - HasSession delegates correctly - 5-roundtrip Double-Ratchet conversation through the codec 102 → 109 passing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Aether.Streaming has been in-progress as untracked working-tree files
across recent sessions. The .csproj builds clean and the module
integrates cleanly with Aether.Core (routing, packets) and the new
Aether.Security Signal stack. Landing it under version control so the
rest of the Tier 1-6 fan-out can reference it as canonical.
Modules included:
- StreamingService (live broadcast, per-stream subscriber set,
unicast fan-out via PacketType.StreamSegment)
- VideoCallService (1:1 + group video, signaling, transport handoff)
- WatchTogetherService (synchronized playback across participants)
- Models/StreamPackets (segment, control, signaling wire types)
- Models/StreamSession (publisher + subscriber session state)
- Models/VideoCallSession (call lifecycle state)
- Models/WatchSession (watch-together coordination state)
- IStreamingService / IVideoCallService / IWatchTogetherService (DI seams)
NO TESTS yet — Tier 2 of the production-readiness fan-out will add them.
The module's interaction with Routing/DTN is via the existing IMeshSender
+ IRoutingService seams, so it does not introduce new abstractions.
Also bootstraps `.loki/CONTINUITY.md` — working memory for the multi-
agent fan-out that is about to dispatch Tier 1 (DR ports), Tier 2 (tests
for 6 untested modules), Tier 4 (demos), Tier 5 (maturity items),
and Tier 6 (cleanup).
Promotes signal_protocol.py from "X3DH + symmetric ratchet only" to
the full Signal Double Ratchet, mirroring C# SignalProtocolService at
HEAD. Each side maintains a rotating X25519 DH-ratchet keypair; whenever
a peer message bears a new ratchet public key, the receiver does a
DH-ratchet step that re-keys the chain via
KDF_RK(rootKey, DH(myDHs, newDHr)) — giving per-roundtrip forward
secrecy and post-compromise security. Cross-language interop with the
C# / Go / Rust / etc. nodes is preserved: Python and C# can now
bidirectionally exchange Double-Ratchet messages, not just the first
PreKey message.
Wire envelope additions to EncryptedPayload (every message now carries):
- sender_ephemeral_key_x25519: sender's current DH-ratchet public key.
On the very first PreKey message this equals the X3DH ephemeral
(Signal-canonical integration: the initiator's X3DH EK becomes its
first DH-ratchet pubkey).
- previous_chain_count: how many messages were sent on the sender's
previous sending chain — needed by the receiver to compute skipped
keys when crossing a DH-ratchet boundary.
The initiator_ephemeral_key_x25519 field is retained for backward
compatibility — on PreKey messages it equals sender_ephemeral_key_x25519;
on normal messages it stays None. Decrypt falls back to it when
sender_ephemeral_key_x25519 is absent (legacy peers).
Session state additions (SignalSession):
- my_ephemeral_priv / my_ephemeral_pub: my current DH-ratchet keypair.
Initiator: starts as the X3DH ephemeral; rotated on each receive.
Responder: starts as SPK; rotated on first DH-ratchet step.
- remote_ephemeral_pub: peer's last-known ratchet public key. None
until the first DH-ratchet step.
- previous_chain_count: PN per Signal §5.
- skipped_message_keys: keyed by "hex(remote_eph_pub):counter"
(uppercase hex to match C# Convert.ToHexString) so out-of-order
messages from a previous chain (different DHr) can still be
decrypted via the cache after a DH-ratchet step. This replaces the
previous int-keyed dict.
- send_chain_key / recv_chain_key are now Optional[bytes] and start
as None (lazy init).
Algorithm changes:
- process_pre_key_bundle: after X3DH, DHs = X3DH EK, DHr = peer SPK,
CKs / CKr left None (lazy init on first send / first DH-ratchet).
- _establish_responder_session: after mirror X3DH, DHs = (SPK_priv,
SPK_pub), DHr = None. The first decrypt always triggers
_dh_ratchet_receive which rotates DHs to a fresh keypair (drops SPK).
- encrypt: lazy _dh_ratchet_send_only on first send (initiator side).
- decrypt: detects header.sender_ephemeral_key != session.remote_ephemeral_pub
and triggers _dh_ratchet_receive — saves any unread keys from the
previous chain via _skip_message_keys(payload.previous_chain_count),
then runs the full DH ratchet (new RK + CKr from DH(myDHs, newDHr);
rotate DHs; new RK + CKs from DH(newDHs, newDHr)).
KDF_RK (new): HKDF-SHA256 over 64 bytes with salt=root_key,
info='aether-ratchet-rk-v1'. First 32 = new root key, second 32 = new
chain key. The HMAC ratchet (KDF_CK from §5.1) is unchanged.
Tests: test_signal_protocol.py adds 5 Double-Ratchet exercises mirroring
the C# SignalProtocolServiceTests Double-Ratchet section
- every msg carries sender_ephemeral_key_x25519
- sender ratchet pub rotates after a roundtrip
- previous_chain_count tracks msgs per chain
- out-of-order delivery across a DH-ratchet boundary still decrypts
- long bidirectional conversation (10 alternating messages) decrypts
Existing fixture verifiers (test_signal_fixture_x3dh_basic,
test_signal_fixture_ratchet_step_*) continue to pass — fixtures pin
X3DH math and HMAC ratchet, both unchanged. All existing X3DH
end-to-end tests continue to pass. 10 -> 15 passing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Verification deferred to gradle-equipped sync host. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Verification deferred to Mac sync (CryptoKit only on Apple platforms). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…) + ProtocolConstants drift cleanup Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fixup for previous commit — concurrent agents reset the test csproj between staging and commit, leaving the storage tests without a ProjectReference. This adds it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…lback, receive path Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ce, WatchTogetherService Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…pVoiceCallService Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ing/DTN/Signal/messaging stack Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…-outbox Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…on across crypto/routing/DTN/messaging Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…eStore adapters Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…language fixture interop Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…-of-scope/assumptions) + SECURITY.md Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…gotiation Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a CompressionOptions sub-option to MessagingOptions and wires Brotli compression into MessagingService.SendAsync (compress-then-encrypt) and HandleAsync (decrypt-then-decompress). The compression flag (0x00 raw, 0x01 brotli) is carried inside the encrypted plaintext, so the cipher wire format is unchanged. Below MinSizeBytes (default 256) and when brotli output is not strictly smaller than the input, the service falls back to flag 0x00 + raw payload — no work wasted on already-compressed or already-tiny content. Migration concern: the flag byte is unconditional. A peer running pre- this-change code will see the flag byte as the first byte of the application payload and produce garbled output. Adopters set MessagingOptions.Compression.Enabled = false until rollout completes, or until the capability handshake gates compression on a "compression-brotli" peer capability. Two existing MessagingServiceTests fixtures updated to thread the flag byte through the cipher mocks; their behaviour-level assertions are unchanged. Eight new tests cover round-trip, ratio, fallback, threshold, disabled, unknown-flag-drop, and flag=0x00 binding. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…zeroing / cache bound Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
--- updated-dependencies: - dependency-name: BenchmarkDotNet dependency-version: 0.15.8 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
Author
LabelsThe following labels could not be found: Please fix the above issues or remove invalid values from |
Author
|
OK, I won't notify you again about this release, but will get in touch when a new version is available. If you'd rather skip all updates until the next major or minor version, let me know by commenting If you change your mind, just re-open this PR and I'll resolve any conflicts on it. |
bhengubv
added a commit
that referenced
this pull request
Jun 7, 2026
Items #22, #23, #24 in OPEN_ISSUES.md mirror GitHub issues #59, #60, #61 — real protocol-shape gaps surfaced while wiring aether-media's LocalLibrary (commit 07a695e) against AetherNet 1.1.0: #22 / #59 — IDtnService: add BundleReceived event for inbound bundles #23 / #60 — IContentService: application-layer naming/discovery (biggest; IContentService is hash-keyed, mesh-first fetchers have no way to resolve by name) #24 / #61 — IAetherNetIncentiveProvider: add author-tipping path (only relay credit modelled today) All three tagged `breaking-change` + `protocol-surface` — 2.0 candidates. README Open section updated to surface the trio. [skip ci]
bhengubv
added a commit
that referenced
this pull request
Jun 7, 2026
…ference) Closes Wave-17 Phase 1 — the C# reference implementation of the 3 protocol gaps surfaced by AetherMedia.LocalLibrary (aether-media commit 07a695e). All additions are ADDITIVE (default interface methods + new event handlers + new packet types in reserved-unassigned slots), so this is 1.2.0-grade, not a 2.0 breaking change. Other-language ports + cross-language fixtures + 1.2.0 publish + consumer migration land in follow-on phases. Issue #59 — IDtnService.BundleReceived event for inbound bundles • New event EventHandler<DtnBundleReceivedEventArgs>? BundleReceived • New DtnBundleReceivedEventArgs (BundleId, SenderUhid, RecipientUhid, EncryptedPayload, Priority, HopCount, ReceivedAtUtc) • DtnService raises BundleReceived inside HandleBundleAsync the moment a bundle addressed to the local node lands — before SendDeliveryReceiptAsync • 2 unit tests: fires-for-local-recipient, does-NOT-fire-for-relay-custody Issue #60 — IDirectoryService application-layer name resolution • New PacketType.NamePublish = 38, NameQuery = 39 (previously-reserved slots) • New AetherNet.Content.IDirectoryService: PublishAsync(name, descriptor) — store locally + broadcast NamePublish ResolveAsync(name, timeout?) — local-hit cache, else broadcast NameQuery and await NamePublish response (default 5s) ListNamesAsync() HandleAsync(packet) — pump NamePublish / NameQuery event EntryAnnounced • New DirectoryService impl: ConcurrentDictionary catalogue, TaskCompletionSource per outstanding query, query-id correlation on response, cancellation-aware timeout via CancellationTokenSource.CreateLinkedTokenSource • New NamePublishPayload, NameQueryPayload, DirectoryEntryAnnouncedEventArgs (snake_case JSON for cross-language interop) • DI builder: AddDirectory() (requires AddRouting() for IMeshSender) • 8 unit tests: publish-and-local-resolve, query-and-response round-trip, query-for-unknown-name (no-op), timeout returns null, catalogue listing, inbound NamePublish fires EntryAnnounced, etc. Issue #61 — IAetherNetIncentiveProvider.RecordCreatorTipAsync • New default-method on IAetherNetIncentiveProvider: RecordCreatorTipAsync(creatorUhid, amount, contentHash, ct) • Default no-op preserves backward-compat; hosts (SDPKT, BhenguPay) override • Distinct from existing RecordRelayAsync — relay credit vs author payment • 3 unit tests: default no-op, custom impl captures args verbatim, tips and relay credit are independent recording paths Tests: AetherNet.Core.Tests 628/628 pass (was 615; +13 new tests across the 3 issues). AetherNet.Soak.Tests 11/11 pass. Zero regressions. Full solution builds clean on both net9.0 and net10.0. Tracked in OPEN_ISSUES.md items #22 / #23 / #24; GitHub issues #59 / #60 / #61. [skip ci]
bhengubv
added a commit
that referenced
this pull request
Jun 8, 2026
…1.2.0) Adds 3 fixture cases to inputs.json + binary anchors regenerated via 'cd go && go run ./cmd/fixturegen': name_publish_unsolicited type=38, 330 bytes (in_response_to_query_id null) name_publish_response type=38, 350 bytes (in_response_to_query_id set) name_query_basic type=39, 137 bytes Every language's FixtureTests picks these up automatically. The Go fixturegen is the source-of-truth serializer; C# FixtureTests pass 37/37 (was 34/34 before — +3 new). Other-language fixture tests verify byte-equality of their own serializer against the .bin files on CI. Closes the cross-language wire-format anchor gap surfaced before the v1.2.0 release: items #22 (BundleReceived), #23 (IDirectoryService), #24 (RecordCreatorTip) in OPEN_ISSUES.md. Note: BundleReceived doesn't get a fixture because it's a host-side event (no wire format) — the IDirectoryService wire types are what the new fixtures anchor. [skip ci]
bhengubv
added a commit
that referenced
this pull request
Jun 8, 2026
VersionPrefix bumped 1.1.0 -> 1.2.0. CHANGELOG entry added. OPEN_ISSUES.md items #22 / #23 / #24 marked RESOLVED with commit anchors. README 'Open' section updated to show Wave-17 as DONE. Wave 17 closes the 3 protocol gaps surfaced by aether-media's LocalLibrary mesh-first fetcher (commit 07a695e). All additions are additive (default interface methods + new event handlers + new packet types in previously- reserved enum slots 38/39) — 1.2.0 minor bump, not a breaking 2.0. Verified end-to-end across all 8 languages: C# — 628/628 Core + 11/11 Soak tests pass on Windows Go — full test suite pass on Windows Python — 476/476 tests pass on Windows TypeScript — 550/550 tests pass on Windows Kotlin — 549/549 tests pass on Windows Swift — full suite pass on Mac (Apple Swift 6.2) Rust — full suite pass on Mac (rustc 1.95.0) C — directory_service.c + dtn.c clang-compile-clean standalone; pre-existing transport_metrics.c repo health filed as #62 Cross-language fixtures: 3 new entries in fixtures/inputs.json (name_publish_ unsolicited 330B, name_publish_response 350B, name_query_basic 137B); binaries regenerated via 'cd go && go run ./cmd/fixturegen'. C# FixtureTests pass 37/37 (was 34, +3 new). Anchors NamePublish + NameQuery wire format across all 8 implementations. [skip ci]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Updated BenchmarkDotNet from 0.13.12 to 0.15.8.
Release notes
Sourced from BenchmarkDotNet's releases.
0.15.8
This release adds OpenMetrics exporter support for Prometheus-compatible metrics export, improves the Roslyn analyzers with multi-target support and better type checking, and fixes several bugs including process deadlocks and WASM trimming issues.
Features
NO_COLORenvironment variable support for disabling console colors (#2870)Improvements
[DynamicallyAccessedMembers]attribute polyfill (#2883)AsyncProcessOutputReaderfor cleaner process output handling (#2878)Bug Fixes
BenchmarkRunner.Run<T>()with arguments on invalid benchmark type (#2880, fixes #2724)Internal
#if-#endifpreprocessor directives using PolySharp polyfills (#2881)Full Changelog: dotnet/BenchmarkDotNet@v0.15.7...v0.15.8
0.15.7
This release introduces Roslyn analyzers to catch incorrect BenchmarkDotNet usage at compile time, improves .NET Framework version detection, and updates OS detection support.
Features
[Arguments],[Params], and[ParamsAllValues]attribute usage[GenericTypeArguments]requirementsBenchmarkRunner.RuninvocationsImprovements
TargetFrameworkAttribute(#2682)OsBrandHelperBug Fixes
TestCaseFilterfor the test adapterInternal
release.yamlFull Changelog: dotnet/BenchmarkDotNet@v0.15.6...v0.15.7
0.15.6
v0.15.6
This release adds ref struct parameter support for
[ArgumentsSource], fixes Native AOT runtime moniker resolution, and upgrades to Perfolizer 0.6.0 with the new Pragmastat statistical engine.Features
[ArgumentsSource]attribute, enablingSpan<T>andReadOnlySpan<char>parameters (#2849)Bug Fixes
Improvements
Documentation
Internal
Full Changelog: dotnet/BenchmarkDotNet@v0.15.5...v0.15.6
0.15.5
This release fixes job naming consistency when using
--runtimes, clamps histogram bin bounds to avoid confusing negative values, and reduces output directory clutter by filtering unnecessary runtime and satellite assembly files.Features
Bug Fixes
SimpleJobAttributeand--runtimesCLI option (#2841)Internal
workflow_dispatchfor test workflow (#2835)Full Changelog: dotnet/BenchmarkDotNet@v0.15.4...v0.15.5
0.15.4
This release fixes issues with
ParamsSourceattribute resolution in inheritance scenarios and corrects a MSBuild syntax error in the TestAdapter.Bug Fixes
[ParamsSource]to resolve overridden methods and properties in derived classes (#2832)TestTfmsInParallelproperty that prevented Visual Studio from loading projects (#2831)Full Changelog: dotnet/BenchmarkDotNet@v0.15.3...v0.15.4
0.15.3
This release brings .NET 10 NativeAOT instruction set support, improved CPU detection on Windows when WMIC is unavailable, test adapter filtering, and numerous bug fixes.
Breaking Changes
.WithNuget()job extension in favor of.WithMsBuildArguments()(#2812)Features
Improvements
IsNetCoreandIsNativeAOTdetection for single-file apps without AOT (#2799)--nodeReuse:falsefor dotnet CLI commands to improve build isolation (#2814)Bug Fixes
ArgumentsSourceon external types not working if the argument type is not primitive (#2820)EtwProfilerfor file paths slightly under 260 characters (#2808)EventProcessor.OnEndValidationStagenot being called when critical validation errors occur (#2816)XmlExceptionthrown whenTextReader.Nullis passed toAppConfigGenerator(#2817)NativeMemoryLogParserprogram name matching (#2795)BuildPlots.RInternal
MemoryDiagnosertests on macOS (#2813)TimeConsumingBenchmarkclass to reduce test timeBenchmarkDotNetDiagnoserspackage version (#2805)GenerateProgramFile(#2802)Full Changelog: dotnet/BenchmarkDotNet@v0.15.2...v0.15.3
0.15.2
This release improves memory allocation measurement accuracy and adds new features for job ordering and runtime validation.
Features
JobOrderPolicyoption to sort jobs in numeric order instead of ordinal order (#2770)RuntimeValidatorto detect benchmarks with null runtime configuration (#2771)Improvements
Bug Fixes
Internal
--force-clonefor docs-fetch in generate-gh-pages workflowworkflow_dispatchfor publish-nightly workflowdocs/_changelogfolder from main branch (migrated to docs-changelog branch)Full Changelog: dotnet/BenchmarkDotNet@v0.15.1...v0.15.2
0.15.1
A maintenance release with improved cross-platform compatibility, a new feature for referencing external types in source attributes, and several bug fixes for ARM CPUs and unsupported operating systems.
Features
[ArgumentsSource]and[ParamsSource]to reference methods in other types via new constructor overload:[ArgumentsSource(typeof(MyClass), nameof(MyClass.Values))](#2748)Bug Fixes
REASON_CONTEXTto use proper union structure (#2745, #2756)Console.CancelKeyPresscrash on platforms that don't support it (Android, iOS, tvOS, WASM) (#2739, #2741)CpuInfo.Unknown(#2740).slnxsolution file format when searching for solution files (#2764)Improvements
ExporterBase.GetArtifactFullNameaccessibility modifier more permissiveInternal
docs-changelogbranch (#93d12c42)Full Changelog: dotnet/BenchmarkDotNet@v0.15.0...v0.15.1
0.15.0
BenchmarkDotNet v0.15.0 brings .NET 10 support, a new WakeLock feature to prevent system sleep during benchmarks, improved engine internals for more consistent measurements, and numerous bug fixes and improvements.
Features
[WakeLock]attribute and--wakeLockCLI option to prevent the system from entering sleep mode while benchmarks are running (#2670)RuntimeMoniker.Net10,NativeAot10, andMono10with full toolchain support (#2642)Platform.RiscV64for RISC-V 64-bit architecture (#2644, #2647)requiredproperties (#2579)ConfigOptions.DisableParallelBuildoption to force sequential builds (#2725)ThreadingDiagnoserandExceptionDiagnosernow support configuration to hide columns when metrics have no values (#2673)Improvements
IEngineStageEvaluatorfor more consistent instruction location and simpler code (#2688)InProcessNoEmitRunnerwith NativeAOT (#2702)ParamsAttribute.Valuessetter is now protected instead of private (#2716)ClrMdV3Disassembler(#2488)Perfonarexporters replacingPhdexportersBug Fixes
IlcGenerateCompleteTypeMetadataand updated flag names (#2616)Breaking Changes
[PhdExporter]→[PerfonarExporter],PhdJsonExporter→PerfonarJsonExporter,PhdMdExporter→PerfonarMdExporterDocumentation
... (truncated)
0.14.0
Full changelog: https://benchmarkdotnet.org/changelog/v0.14.0.html
Highlights
BenchmarkDotNet.Diagnostics.dotMemory#2549: memory allocation profile of your benchmarks using dotMemory, see @BenchmarkDotNet.Samples.IntroDotMemoryDiagnoserBenchmarkDotNet.Exporters.Plotting#2560: plotting via ScottPlot (initial version)IntermediateOutputPath,OutputPath, andOutDirproperties to thedotnet buildcommand. This change forces all build outputs to be placed in a new directory generated by BenchmarkDotNet, and fixes many issues that have been reported with builds. You can also access these paths in your own.csprojand.propsfrom those properties if you need to copy custom files to the output.Bug fixes
UseArtifactsOutput.Breaking Changes
DotNetCliBuilderremovedretryFailedBuildWithNoDepsconstructor option.DotNetCliCommandremovedRetryFailedBuildWithNoDepsproperty andBuildNoRestoreNoDependencies()andPublishNoBuildAndNoRestore()methods (replaced withPublishNoRestore()).Commits viewable in compare view.
Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting
@dependabot rebase.Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebasewill rebase this PR@dependabot recreatewill recreate this PR, overwriting any edits that have been made to it@dependabot show <dependency name> ignore conditionswill show all of the ignore conditions of the specified dependency@dependabot ignore this major versionwill close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor versionwill close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependencywill close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)