![]() |
VOOZH | about |
dotnet add package ECP.Core --version 2.0.6
NuGet\Install-Package ECP.Core -Version 2.0.6
<PackageReference Include="ECP.Core" Version="2.0.6" />
<PackageVersion Include="ECP.Core" Version="2.0.6" />Directory.Packages.props
<PackageReference Include="ECP.Core" />Project file
paket add ECP.Core --version 2.0.6
#r "nuget: ECP.Core, 2.0.6"
#:package ECP.Core@2.0.6
#addin nuget:?package=ECP.Core&version=2.0.6Install as a Cake Addin
#tool nuget:?package=ECP.Core&version=2.0.6Install as a Cake Tool
A binary protocol for emergency communications.
👁 CI
👁 .NET 8
👁 License
👁 Patent
👁 Security: Snyk monitored
dotnet add package ECP.CoreECP is provided under Apache-2.0 on an "AS IS" basis and is not warranted to be error-free. ECP is not developed, tested, or certified as a standalone safety mechanism for life-safety systems. Users and integrators are solely responsible for system-level hazard analysis, validation, certification, and compliance with applicable laws and standards before operational deployment. See also NOTICE for additional legal and safety notices.
ECP encodes emergency alerts into compact binary messages — from 8 to 100 bytes — with built-in cryptographic integrity. It was designed for scenarios where bandwidth is limited, latency matters, and message authenticity cannot be optional.
| Format | Alert size | Notes |
|---|---|---|
| CAP XML (OASIS) | 669 bytes | Industry standard for alerting |
| JSON over HTTP | 270 bytes | Common in web applications |
| ECP Envelope | 45–100 bytes | Binary, signed, with metadata |
| ECP Token (UET) | 8 bytes | Minimal alert, no payload |
These numbers are reproducible. Public benchmarks are available in benchmarks/ so you can measure them yourself.
ECP achieves an average 96% data reduction across supported emergency types. This number is derived from protocol format comparison (CAP XML 669B, JSON 270B, ECP 8B) and is independently reproducible using the benchmarks and test vectors in this repository.
dotnet add package ECP.Core
using ECP.Core;
using ECP.Core.Models;
byte[] alert = Ecp.Alert(EmergencyType.Fire, zoneHash: 1, priority: EcpPriority.Critical);
That's it. alert contains the emergency type, priority, zone, timestamp, and action flags in 8 bytes.
Want to see the size difference? Run dotnet run in samples/ProofCard for a visual comparison.
Ecp.Alert(...) uses the current timestamp when timestampMinutes is omitted, so the resulting hex changes over time.
For deterministic hex (for example, to match test vectors), pass fixed values for timestampMinutes and confirmHash, or call UniversalEmergencyToken.Create(...) with fixed fields.
byte[] deterministic = Ecp.Alert(
EmergencyType.Fire,
zoneHash: 1,
priority: EcpPriority.Critical,
actionFlags: ActionFlags.None,
timestampMinutes: 12345,
confirmHash: 0);
ECP has a progressive API. Start simple, add control when you need it.
using ECP.Core;
using ECP.Core.Models;
byte[] alert = Ecp.Alert(EmergencyType.Earthquake, zoneHash: 42, priority: EcpPriority.Critical);
// 8 bytes, done.
using ECP.Core;
using ECP.Core.Models;
var token = Ecp.Token(
EmergencyType.Fire,
EcpPriority.Critical,
ActionFlags.SoundAlarm | ActionFlags.FlashLights);
byte[] bytes = token.ToBytes(); // 8 bytes
string base64 = token.ToBase64(); // 12 chars — fits in an SMS
using ECP.Core;
using ECP.Core.Models;
byte[] hmacKey = new byte[32]; // your HMAC-SHA256 key (32 bytes recommended)
var envelope = Ecp.Envelope()
.WithType(EmergencyType.Earthquake)
.WithPriority(EcpPriority.Critical)
.WithTtl(120)
.WithPayload("Evacuate Building A via Stairway B")
.WithHmacKey(hmacKey)
.Build();
byte[] wire = envelope.ToBytes(); // 45–100 bytes, signed, verified
using ECP.Core;
using ECP.Core.Models;
using ECP.Core.Token;
var token = Ecp.Token(EmergencyType.Fire, EcpPriority.Critical);
Span<byte> buffer = stackalloc byte[UniversalEmergencyToken.Size]; // 8 bytes
token.WriteTo(buffer);
// 0.28 ns, zero heap allocation
using ECP.Core;
using ECP.Core.Models;
byte[] incomingBytes = GetIncomingBytes();
if (Ecp.TryDecode(incomingBytes, out var message))
{
if (message.IsUet)
{
System.Console.WriteLine($"Type: {message.Token.EmergencyType}, Priority: {message.Token.Priority}");
}
else if (message.IsEnvelope)
{
System.Console.WriteLine($"Envelope payload type: {message.Envelope.PayloadType}");
}
}
static byte[] GetIncomingBytes() => System.Array.Empty<byte>();
| Package | Tier | What it does | When to use it |
|---|---|---|---|
ECP.Core |
Free (Apache-2.0) | Protocol encoder/decoder, UET, Envelope, security | Start here. Zero dependencies. |
ECP.Standard |
Free (Apache-2.0) | Core + Registry + Cascade + DI helpers | Full-featured applications |
ECP.Registry |
Free (Apache-2.0) | Semantic compression, multilingual templates | When you need smaller payloads |
ECP.Cascade |
Free (Apache-2.0) | P2P broadcast, adaptive fan-out, confirmations | Multi-node delivery |
ECP.DependencyInjection |
Free (Apache-2.0) | AddEcpCore() for .NET DI |
ASP.NET Core / hosted services |
ECP.Transport.Abstractions |
Free (Apache-2.0) | Transport layer interfaces | Building custom transports |
ECP.Transport.WebSocket |
Free (Apache-2.0) | WebSocket transport | Real-time web delivery |
ECP.Transport.SignalR |
Free (Apache-2.0) | SignalR transport | ASP.NET Core SignalR |
ECP.Compatibility |
Free (Apache-2.0) | JSON-to-ECP bridge | Migrating from JSON APIs |
ECP.Offline |
Premium (commercial) | Offline activation, deterministic authorization, forensic chain integration | Enterprise offline and compliance scenarios |
ECP.Diagnostics.Enterprise (planned) |
Premium (commercial) | Advanced diagnostics and governance/compliance tooling | Large-scale operations and audit programs |
Naming note: Cascade is a public package name for multi-node propagation and confirmation behavior.
Which package do I need?
ECP.Core (zero dependencies)ECP.Standard + ECP.DependencyInjectionECP.CompatibilityECP.Offline (commercial license)ECP.Core and ECP.Standard already have examples above. This section covers the other free packages with copy/paste snippets.
using System.Text;
using ECP.Registry.Dictionary;
var dictionary = EmergencyDictionary.CreateDefault(dictionaryId: 1, dictionaryVersion: 1);
byte[] input = Encoding.UTF8.GetBytes("immediate evacuation at Gate B2");
Span<byte> compressed = stackalloc byte[128];
dictionary.TryCompress(input, compressed, out int compressedLength);
Span<byte> restored = stackalloc byte[128];
dictionary.TryDecompress(compressed[..compressedLength], restored, out int restoredLength);
string text = Encoding.UTF8.GetString(restored[..restoredLength]);
using ECP.Cascade;
var trust = new TrustScoreService();
int defaultScore = trust.GetScore("node-alpha"); // 55 by default
trust.SetScore("node-alpha", 82);
int score = trust.GetScore("node-alpha");
int fanOut = trust.GetFanOutLimit("node-alpha"); // high tier => wider propagation
using ECP.Compatibility;
using ECP.Core.Models;
byte[] hmacKey = new byte[32];
string legacyJson = """{"payloadText":"Evacuate terminal 3 via stairway B","ttl":90}""";
byte[] ecpBytes = JsonBridge.ToEcp(
legacyJson,
hmacKey.AsSpan(),
hmacLength: 16, // valid range: 8-16 (or 0 to disable HMAC)
keyVersion: 1,
priority: EcpPriority.Critical,
ttlSeconds: 120,
flags: EcpFlags.None,
payloadType: EcpPayloadType.Alert);
using System.Linq;
using ECP.Core.Security;
using ECP.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
byte[] hmacKey = new byte[32];
var services = new ServiceCollection();
var keyRing = new KeyRing();
keyRing.AddKey(1, hmacKey);
services.AddEcpCore(o => { o.HmacLength = 16; o.KeyVersion = 1; o.KeyProvider = keyRing; });
string[] registered = services.Select(d => d.ServiceType.FullName!).OrderBy(n => n).ToArray();
Console.WriteLine($"AddEcpCore registered {registered.Length} services.");
With a KeyRing provider, AddEcpCore() registers these 7 services:
ECP.Core.EcpOptionsECP.Core.Security.IKeyProviderECP.Core.Security.ITenantKeyProviderECP.Core.Tenancy.ITenantContextECP.Core.Privacy.ITenantPrivacyOptionsProviderECP.Core.Privacy.ZoneHashProviderECP.Core.Strategy.IStrategySelectorusing ECP.Transport.Abstractions;
static async Task SendAlertAsync(IEcpTransport transport, byte[] packet, CancellationToken ct)
{
if (!transport.IsConnected)
{
await transport.ConnectAsync("wss://alerts.example/ws", ct);
}
await transport.SendAsync(packet, ct);
}
using System.Threading;
using ECP.Core.Security;
using ECP.Core;
using ECP.Transport.WebSocket;
byte[] hmacKey = new byte[32];
var keyRing = new KeyRing();
keyRing.AddKey(1, hmacKey);
await using var transport = new EcpWebSocketTransport(
new EcpWebSocketOptions(),
new EcpOptions { HmacLength = 16, KeyVersion = 1, KeyProvider = keyRing },
keyRing);
string endpoint = "wss://alerts.example/ws";
var connect = (CancellationToken ct) => transport.ConnectAsync(endpoint, ct); // endpoint belongs here
using System.Threading;
using ECP.Core.Security;
using ECP.Core;
using ECP.Transport.SignalR;
byte[] hmacKey = new byte[32];
var keyRing = new KeyRing();
keyRing.AddKey(1, hmacKey);
await using var transport = new EcpSignalRTransport(
new EcpSignalROptions(),
new EcpOptions { HmacLength = 16, KeyVersion = 1, KeyProvider = keyRing },
keyRing);
string endpoint = "https://alerts.example/hubs/ecp";
var connect = (CancellationToken ct) => transport.ConnectAsync(endpoint, ct); // endpoint belongs here
using ECP.Core;
using ECP.Core.Security;
using ECP.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
byte[] hmacKey = new byte[32]; // load your key from secure storage
var keyRing = new KeyRing();
keyRing.AddKey(keyVersion: 1, key: hmacKey);
builder.Services.AddEcpCore(options =>
{
options.HmacLength = 16;
options.KeyVersion = 1;
options.KeyProvider = keyRing;
});
using ECP.Core;
using ECP.Core.Security;
using ECP.Standard;
var builder = WebApplication.CreateBuilder(args);
byte[] hmacKey = new byte[32]; // load your key from secure storage
var keyRing = new KeyRing();
keyRing.AddKey(keyVersion: 1, key: hmacKey);
builder.Services.AddEcpStandard(options =>
{
options.HmacLength = 16;
options.KeyVersion = 1;
options.KeyProvider = keyRing;
});
using ECP.Core.Profiles;
using ECP.Standard;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEcpProfile(EcpProfile.Minimal); // Core only
builder.Services.AddEcpProfile(EcpProfile.Enterprise); // Core + Registry + Cascade
Run with BenchmarkDotNet on .NET 8.0.
Environment: 13th Gen Intel(R) Core(TM) i9-13900KF, .NET SDK 8.0.418 (Microsoft.NETCore.App 8.0.24), Release configuration, RyuJIT x64. Full details and runnable code are in benchmarks/.
| Operation | Time | Allocation |
|---|---|---|
| UET Encode | 3.3 ns | 32 B |
| UET Encode (zero-alloc) | 0.28 ns | 0 B |
| UET Decode | 1.2 ns | 0 B |
| Envelope Build + Encode | 334 ns | 416 B |
| Envelope Encode (zero-alloc) | 6.5 ns | 0 B |
| Envelope Decode + HMAC verify | 262 ns | 0 B |
At 262 ns per decode, a single core can process roughly 3.8 million messages per second. Most of that time (~250 ns) is spent on HMAC-SHA256 verification — a deliberate choice to keep integrity verification on by default.
Runnable benchmark code is available in benchmarks/ so you can reproduce these numbers on your own hardware. If your measurements differ significantly, please open an issue with your environment details.
These numbers come from protocol comparisons and public repository artifacts.
Test vectors and source tests are available in test-vectors/ and tests/ so you can verify protocol behavior independently.
| Metric | Value |
|---|---|
| Average data reduction | 96% |
| Automated tests (public repo) | 235 |
| Public test projects | 10 |
We're a small team and this is a young protocol. If you find issues, inconsistencies, or have questions about these numbers, we genuinely want to hear from you.
WriteTo(Span<byte>) for constrained environmentsECP-SDK does not collect, transmit, or store any data. No telemetry, no analytics, no network calls. The SDK runs entirely inside your application.
This design helps support compliance with regulations such as GDPR, HIPAA, and similar frameworks, depending on your system integration.
ECP follows Semantic Versioning:
Public APIs marked [Obsolete] are maintained for at least one minor version before removal.
ECP uses an Open Core model.
Free packages (Apache-2.0): The packages listed as "Free" in this README are licensed under Apache 2.0 and can be used in development and production, including commercial use.
Premium packages (commercial license): Premium modules (such as ECP.Offline and ECP.Diagnostics.Enterprise) require a separate commercial agreement. Contact .
ECP technology includes patent-pending elements filed with UIBM. For Apache-licensed packages, patent rights (if any) are granted only as stated in Section 3 of Apache License 2.0.
See LICENSE.txt and NOTICE for legal terms and attribution notices.
Found a vulnerability? Do not open a public issue. See SECURITY.md for our responsible disclosure policy.
This software uses standard cryptographic algorithms (AES-GCM, HMAC-SHA256) provided by the .NET runtime. It does not implement custom cryptographic primitives. Distribution of this software may be subject to export control regulations in certain jurisdictions.
In this repository:
External:
Made in Italy by Egonex S.R.L. — built for emergencies, open source for builders.
Copyright © 2026 Egonex S.R.L.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 net8.0 is compatible. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 was computed. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 was computed. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
Showing the top 5 NuGet packages that depend on ECP.Core:
| Package | Downloads |
|---|---|
|
ECP.Transport.Abstractions
Transport interfaces for sending and receiving raw protocol bytes. Build custom adapters for WebSocket, BLE, LoRa, satellite, or any proprietary channel. |
|
|
ECP.DependencyInjection
Dependency injection extensions for Microsoft.Extensions.DependencyInjection. Registers protocol, key management, tenant, privacy, and strategy services via AddEcpCore(). |
|
|
ECP.Registry
Dictionary-based semantic compression with multilingual templates for alert payloads. Reduces message size by an additional 30-50% on top of binary encoding. |
|
|
ECP.Cascade
Adaptive multi-node broadcast with trust-based fan-out, O(log N) propagation, confirmation aggregation, and geo-quorum primitives for resilient delivery. |
|
|
ECP.Standard
Full-stack distribution that bundles Core, Registry, Cascade, and DI setup. Use one reference to enable encoding, compression, adaptive broadcast, and service registration. |
This package is not used by any popular GitHub repositories.