Skip to content

feat(native): signing, validation & DID layer with zero-copy architecture#186

Merged
JeromySt merged 12 commits intousers/jstatia/native_ports_finalfrom
native_signing_validation
Apr 2, 2026
Merged

feat(native): signing, validation & DID layer with zero-copy architecture#186
JeromySt merged 12 commits intousers/jstatia/native_ports_finalfrom
native_signing_validation

Conversation

@JeromySt
Copy link
Copy Markdown
Member

Layer 3 staged merge from native_ports onto native_ports_final.

Zero-Copy Architecture

Single-allocation parsing: CoseSign1Message wraps one Arc<[u8]> and all fields (headers, payload, signature) are Range into that buffer.

  • CoseData::from_arc_range() — sub-view into parent buffer (0 alloc)
  • parse_from_shared() / parse_from_arc_slice() — parse nested messages (e.g. receipts) sharing the parent's Arc with zero allocation
  • ArcSlice::arc() / range() — expose backing buffer for downstream sharing
  • LazyHeaderMap — deferred parsing via OnceLock, zero-copy ArcSlice/ArcStr values reference the parent buffer
  • extract_receipts() returns Vec (no data copy)
  • merge_receipts() deduplicates via HashSet (no byte copying)

Message Lifecycle (Composing → Signed)

  • MessageState enum tracks mutability: Signed messages lock protected headers, payload, and signature
  • set_unprotected_header() / remove_unprotected_header() — only mutation allowed post-signing, sets dirty flag
  • encode() fast-path: clean signed messages return backing bytes directly
  • encode_and_persist() — re-serializes and updates backing buffer
  • CoseSign1Builder::sign_to_message() — produces Signed message directly

New Crates

Signing: cose_sign1_signing, cose_sign1_factories, cose_sign1_headers Validation: cose_sign1_validation, cose_sign1_validation_primitives,
cose_sign1_validation_test_utils
DID: did_x509
FFI: 7 C-ABI projection crates for all above

Handle-Based FFI (zero-copy across boundary)

15 new _to_message FFI functions return CoseSign1MessageHandle instead of copied byte buffers. C/C++ callers borrow data via accessor functions:

  • cose_sign1_message_as_bytes() → *const u8 into Rust Arc
  • cose_sign1_message_payload/signature/protected_bytes() → borrowed

C++ Projections (thin RAII, no allocations)

  • ByteView struct replaces std::vector<uint8_t> for all byte accessors
  • CoseSign1Builder::Sign() returns CoseSign1Message (RAII handle)
  • Validator::Validate(const CoseSign1Message&) borrows message bytes
  • CryptoProvider::SignerFromPem() / VerifierFromPem() — PEM key support

PEM Key Support

Added across Rust → FFI → C++ layers:

  • EvpSigner::from_pem() / EvpVerifier::from_pem()
  • cose_crypto_openssl_signer_from_pem() / verifier_from_pem()
  • CryptoProvider::SignerFromPem(string/vector overloads)

Coverage

5,681 tests, 0 failures. Line coverage: 90.34% (gate: 90%).

…ture

Layer 3 staged merge from native_ports onto native_ports_final.

## Zero-Copy Architecture

Single-allocation parsing: CoseSign1Message wraps one Arc<[u8]> and all
fields (headers, payload, signature) are Range<usize> into that buffer.

- CoseData::from_arc_range() — sub-view into parent buffer (0 alloc)
- parse_from_shared() / parse_from_arc_slice() — parse nested messages
  (e.g. receipts) sharing the parent's Arc with zero allocation
- ArcSlice::arc() / range() — expose backing buffer for downstream sharing
- LazyHeaderMap — deferred parsing via OnceLock, zero-copy ArcSlice/ArcStr
  values reference the parent buffer
- extract_receipts() returns Vec<ArcSlice> (no data copy)
- merge_receipts() deduplicates via HashSet<ArcSlice> (no byte copying)

## Message Lifecycle (Composing → Signed)

- MessageState enum tracks mutability: Signed messages lock protected
  headers, payload, and signature
- set_unprotected_header() / remove_unprotected_header() — only mutation
  allowed post-signing, sets dirty flag
- encode() fast-path: clean signed messages return backing bytes directly
- encode_and_persist() — re-serializes and updates backing buffer
- CoseSign1Builder::sign_to_message() — produces Signed message directly

## New Crates

Signing: cose_sign1_signing, cose_sign1_factories, cose_sign1_headers
Validation: cose_sign1_validation, cose_sign1_validation_primitives,
  cose_sign1_validation_test_utils
DID: did_x509
FFI: 7 C-ABI projection crates for all above

## Handle-Based FFI (zero-copy across boundary)

15 new _to_message FFI functions return CoseSign1MessageHandle instead of
copied byte buffers. C/C++ callers borrow data via accessor functions:
- cose_sign1_message_as_bytes() → *const u8 into Rust Arc
- cose_sign1_message_payload/signature/protected_bytes() → borrowed

## C++ Projections (thin RAII, no allocations)

- ByteView struct replaces std::vector<uint8_t> for all byte accessors
- CoseSign1Builder::Sign() returns CoseSign1Message (RAII handle)
- Validator::Validate(const CoseSign1Message&) borrows message bytes
- CryptoProvider::SignerFromPem() / VerifierFromPem() — PEM key support

## PEM Key Support

Added across Rust → FFI → C++ layers:
- EvpSigner::from_pem() / EvpVerifier::from_pem()
- cose_crypto_openssl_signer_from_pem() / verifier_from_pem()
- CryptoProvider::SignerFromPem(string/vector overloads)

## Coverage

5,681 tests, 0 failures. Line coverage: 90.34% (gate: 90%).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@JeromySt JeromySt force-pushed the native_signing_validation branch 5 times, most recently from 2f71aee to bbded5b Compare March 31, 2026 17:19
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@JeromySt JeromySt force-pushed the native_signing_validation branch from bbded5b to 96be233 Compare April 1, 2026 20:42
Jstatia and others added 10 commits April 1, 2026 14:26
… tests

- Add nightly Rust toolchain step to native-c-cpp CI job so coverage(off)
  attributes are properly activated during ASAN coverage collection
- Remove redundant RUSTFLAGS --cfg coverage_nightly (cargo-llvm-cov sets
  it automatically on nightly)
- Add 45 tests for _to_message FFI functions in signing core FFI
- Add 33 tests for _to_message FFI functions in factories FFI
- Total: 78 new tests covering previously untested _to_message variants

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Create minimal placeholder headers for certificates.h, mst.h, and
azure_key_vault.h so the C smoke test can compile. The actual
extension pack functions are gated behind #ifdef macros and are not
yet implemented in this layer.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix rustfmt import ordering in factories_to_message_tests.rs
- Guard trust plan compilation in C smoke test on having at least one
  extension pack (certificates, MST, or AKV) since compile_or fails
  with zero plans

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ility

The BundledTrustPlan tests call compile_or() which fails when zero
extension packs contribute default plans. Gate these tests on having
at least one pack (certificates, MST, or AKV) available. Fixes
C and C++ smoke test failures when extension packs are not built.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix unsound 'static lifetimes in FFI handle casts — use bounded <'a>
  lifetime parameters matching the primitives FFI pattern. Affects
  signing, factories, DID, and headers FFI crates (12 functions).
- Add missing cose_sign1_message_as_bytes() declaration to C header.
- Add validate_arc() / validate_arc_async() zero-copy overloads that
  accept Arc<CoseSign1Message> to avoid cloning in the validation path.
- Eliminate header double-clone in FFI sign path — move fields out of
  the consumed BuilderInner instead of cloning.
- Move options.additional_data instead of cloning in factory sign path.
- Fix DID x509 FFI string ownership: change out params from *const to
  *mut c_char to correctly express ownership transfer, removing
  const_cast from C++ wrapper.
- Document vector-returning factory methods noting zero-copy ToMessage
  alternatives.

5806 tests pass, 0 failures.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add cose_sign1_builder_consume_protected/unprotected FFI functions
  that move (not clone) header maps into the builder
- Add C header declarations and C++ ConsumeProtected/ConsumeUnprotected
  RAII wrappers with HeaderMap::release() ownership transfer
- Remove unnecessary .to_string()/.clone() allocations in DID x509 parser
  error paths (8 sites) and percent_encoding (use std::mem::take)
- Add PartialEq derive to CwtClaims for whole-struct roundtrip assertions
- Add round_trip_full_claims_struct_equality test covering all fields
- Add module-level doc comments with architecture diagrams to signing
  and validation core lib.rs
- Add @see cross-references from vector-returning factory methods to
  their zero-copy ToMessage alternatives in C++ headers
- Add 7 new tests for consume FFI functions (success + null safety)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
New instruction files codifying the design principles, review criteria,
migration patterns, and testing standards established during the signing
and validation layer port:

- zero-copy-design.instructions.md: No-allocation architecture patterns,
  Arc-based sharing, consume-vs-set FFI, known trade-offs checklist
- code-review-standards.instructions.md: 5-dimension review grading (A-F),
  anti-patterns catalog, coverage exclusion policy
- migration-playbook.instructions.md: V2 C# to Rust porting guide, phase
  tracker, trait mapping, async/config/DI translation patterns
- testing-standards.instructions.md: FFI lifecycle tests, null safety,
  roundtrip tests, parallel safety, coverage targets and exclusions

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@JeromySt JeromySt marked this pull request as ready for review April 2, 2026 20:54
@JeromySt JeromySt merged commit 2c5149b into users/jstatia/native_ports_final Apr 2, 2026
14 checks passed
@JeromySt JeromySt deleted the native_signing_validation branch April 2, 2026 20:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants