silk/tls_record
Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc.
Bounded TLS 1.3 record protection and partial-byte transport driving.
When to use
Use TlsRecordSender and TlsRecordReceiver after a TLS handshake supplies a traffic
secret, or use their plaintext constructors for the initial handshake record framing.
Details
Each direction owns fixed-capacity storage allocated at construction. Later queue, input,
acknowledgment, and consumption operations allocate nothing and retain no caller buffer.
Protected epochs support the three TLS 1.3 cipher suites admitted by Silk and stop after
RECORDS_PER_EPOCH records. A record view borrows its receiver until it is consumed.
Gotchas
Possession of a traffic secret does not authenticate a server identity. This module does not perform a handshake, validate certificates, acquire trust, drive network resources, reserve a client KeyUpdate, or decide close-notify policy. Secret copies are not guaranteed to be erased.
Import as TlsRecordSender with import silk.tls_record { TlsRecordSender }.
Public declarations: 11.
RECORDS_PER_EPOCH
pub const RECORDS_PER_EPOCH: u64The conservative maximum number of records protected by one traffic epoch.
CipherSuite
pub enum CipherSuiteOne cipher suite in Silk's TLS 1.3 profile.
Aes128GcmSha256
Aes128GcmSha256 = 0TLS_AES_128_GCM_SHA256.
Aes256GcmSha384
Aes256GcmSha384 = 1TLS_AES_256_GCM_SHA384.
ChaCha20Poly1305Sha256
ChaCha20Poly1305Sha256 = 2TLS_CHACHA20_POLY1305_SHA256.
ContentType
pub enum ContentTypeA TLS record content type exposed after complete framing and authentication.
ChangeCipherSpec
ChangeCipherSpec = 0Compatibility change_cipher_spec content. It is admitted only by plaintext framing.
Alert
Alert = 1Exactly one complete two-byte alert.
Handshake
Handshake = 2A nonempty handshake fragment.
ApplicationData
ApplicationData = 3Application data, including an empty fragment.
InputDemand
pub enum InputDemandThe next receive-side action after a successful input call.
NeedInput
NeedInput = 0Supply more bytes for the current record.
RecordReady
RecordReady = 1Inspect and consume the completed record.
NeedRecordConsumption
NeedRecordConsumption = 2Consume the already-ready record before supplying more input.
InputProgress
pub struct InputProgressExact input progress and the next receive-side action.
Field consumed
pub consumed: usizeThe caller-input prefix copied during this call.
Field demand
pub demand: InputDemandThe resource or action needed next.
OutputDemand
pub enum OutputDemandThe next send-side action after a successful queue call.
RecordQueued
RecordQueued = 0One record was encoded and is ready for transport.
NeedOutput
NeedOutput = 1A prior record still has unacknowledged output.
OutputProgress
pub struct OutputProgressExact queue progress and the next send-side action.
Field accepted
pub accepted: usizeThe content prefix accepted into the queued record.
Field demand
pub demand: OutputDemandWhether output was queued or an existing record needs acknowledgment.
RecordError
pub union RecordErrorA semantic record-construction, caller-use, or peer-record failure.
InvalidSecretLength
RecordError.InvalidSecretLength { requested: usize, expected: usize }: RecordErrorA traffic secret did not have the suite hash's exact width.
Field requested
pub requested: usizeThe supplied byte length.
Field expected
pub expected: usizeThe required byte length.
InvalidState
RecordError.InvalidState: RecordErrorThe operation is not valid in the direction's current state.
RecordOverflow
RecordError.RecordOverflow { requested: usize, maximum: usize }: RecordErrorA declared or supplied record length exceeds the admitted bound.
Field requested
pub requested: usizeThe rejected length.
Field maximum
pub maximum: usizeThe largest admitted length.
InvalidContent
RecordError.InvalidContent: RecordErrorA content type, plaintext version, inner plaintext, or alert shape is invalid.
AuthenticationFailed
RecordError.AuthenticationFailed: RecordErrorA protected record's authenticated header, ciphertext, or tag did not verify.
InvalidAcknowledgment
RecordError.InvalidAcknowledgment { requested: usize, pending: usize }: RecordErrorAn output acknowledgment exceeds the currently pending suffix.
Field requested
pub requested: usizeThe requested acknowledgment count.
Field pending
pub pending: usizeThe number of bytes currently pending.
KeyUsageExhausted
RecordError.KeyUsageExhausted: RecordErrorThis traffic epoch has already protected its maximum record count.
RecordView
pub struct RecordView<'owner>A complete record borrowed from its receiver's verified storage.
Field contentType
pub contentType: ContentTypeThe authenticated or plaintext content type.
Field content
pub content: &'owner [u8]The complete content without header, tag, inner type, or padding.
TlsRecordSender
pub struct TlsRecordSenderAn affine owner of one TLS record send epoch and at most one pending record.
Details
Protected construction validates the traffic-secret width before allocation, derives the AEAD key and IV with TLS HKDF, and starts at sequence zero. Plaintext construction has no key epoch. Queueing accepts at most 16384 content bytes, adds no protected padding, and reserves one protected sequence only after complete encoding. Pending bytes remain stable until acknowledged.
Gotchas
The later authenticated client owns epoch installation and reserves its final send record for KeyUpdate. Standalone users must replace an exhausted sender; no sequence reset is exposed.
Associated function TlsRecordSender.make
pub effect<'life0> fn make<'life0>(suite: CipherSuite, trafficSecret: &'life0 [u8]) -> silk/result.Result<silk/tls_record.TlsRecordSender, silk/tls_record.RecordError> ! OutOfMemoryError ? &mut AllocatorCreates a protected send epoch from one exact-width traffic secret.
Details
SHA-256 suites require 32 secret bytes and the SHA-384 suite requires 48. A wrong width
returns InvalidSecretLength before allocation. Success acquires fixed pending and staging
storage once; later operations allocate nothing.
Gotchas
A traffic secret proves no peer identity. Install it only after authenticated key agreement.
Associated function TlsRecordSender.makePlaintext
pub effect<'static> fn makePlaintext() -> TlsRecordSender ! OutOfMemoryError ? &mut AllocatorCreates plaintext TLS record framing without a traffic secret or protected epoch.
Method TlsRecordSender.replaceEpoch
pub fn replaceEpoch<'life0, 'life1>(self: &'life0 mut TlsRecordSender, suite: CipherSuite, trafficSecret: &'life1 [u8]) -> silk/result.Result<(), silk/tls_record.RecordError>Installs a fresh protected traffic epoch on an idle sender without allocation.
Details
The replacement reuses the owned wire and staging storage and starts at sequence zero. The traffic secret must have the selected suite hash width.
Gotchas
Pending output makes the replacement invalid. Every failure leaves the complete old epoch unchanged. A successful replacement is allowed after the old epoch exhausts its record budget.
Method TlsRecordSender.queueRecord
pub fn queueRecord<'life0, 'life1>(self: &'life0 mut TlsRecordSender, contentType: ContentType, content: &'life1 [u8]) -> silk/result.Result<silk/tls_record.OutputProgress, silk/tls_record.RecordError>Queues at most one content fragment without retaining the caller input.
Details
An existing pending record returns zero accepted bytes with NeedOutput. Otherwise handshake
content must be nonempty, alerts exactly two bytes, and application content may be empty.
Inputs longer than 16384 bytes queue one exact prefix. A protected record adds its inner type,
no padding, an authenticated outer header, and one sequence reservation.
Method TlsRecordSender.pendingOutput
pub fn pendingOutput<'owner>(self: &'owner TlsRecordSender) -> &'owner [u8]Borrows the exact unacknowledged output suffix. Repeated inspection and inspection before any queued record are idempotent.
Method TlsRecordSender.cancelPending
pub fn cancelPending<'life0>(self: &'life0 mut TlsRecordSender) -> ()Cancels the complete pending suffix without changing the traffic-key epoch.
Gotchas
Callers must close a transport after canceling a partially written record; its already-written prefix cannot be completed or reused. Authenticated protocols use this only on terminal failure.
Method TlsRecordSender.recordsRemaining
pub fn recordsRemaining<'life0>(self: &'life0 TlsRecordSender) -> u64Returns the number of records that this protected epoch can still encode. Plaintext framing returns zero because it has no traffic-key epoch.
Method TlsRecordSender.ackWritten
pub fn ackWritten<'life0>(self: &'life0 mut TlsRecordSender, count: usize) -> silk/result.Result<(), silk/tls_record.RecordError>Acknowledges a written prefix, or leaves all state unchanged when the count is excessive.
TlsRecordReceiver
pub struct TlsRecordReceiverAn affine owner of one TLS record receive epoch and one verified record view.
Details
Input is copied only into fixed storage, headers are admitted before body bytes, and protected plaintext is published only after tag, type, padding, and content validation. A complete record remains ready until consumed, and its view structurally borrows this owner.
Gotchas
Every peer-record failure is terminal for this receiver. Construct a fresh epoch after a valid TLS key transition; never attempt to reuse a failed or exhausted receiver.
Associated function TlsRecordReceiver.make
pub effect<'life0> fn make<'life0>(suite: CipherSuite, trafficSecret: &'life0 [u8]) -> silk/result.Result<silk/tls_record.TlsRecordReceiver, silk/tls_record.RecordError> ! OutOfMemoryError ? &mut AllocatorCreates a protected receive epoch from one exact-width traffic secret.
Associated function TlsRecordReceiver.makePlaintext
pub effect<'static> fn makePlaintext() -> TlsRecordReceiver ! OutOfMemoryError ? &mut AllocatorCreates plaintext TLS record framing without a traffic secret or protected epoch.
Method TlsRecordReceiver.replaceEpoch
pub fn replaceEpoch<'life0, 'life1>(self: &'life0 mut TlsRecordReceiver, suite: CipherSuite, trafficSecret: &'life1 [u8]) -> silk/result.Result<(), silk/tls_record.RecordError>Installs a fresh protected traffic epoch on an idle receiver without allocation.
Details
The replacement reuses the owned wire and plaintext storage and starts at sequence zero. The traffic secret must have the selected suite hash width.
Gotchas
A partial, ready, or terminal receiver makes the replacement invalid. Every failure leaves the complete old epoch unchanged. A successful replacement is allowed after exhaustion.
Method TlsRecordReceiver.feedInput
pub fn feedInput<'life0, 'life1>(self: &'life0 mut TlsRecordReceiver, input: &'life1 [u8]) -> silk/result.Result<silk/tls_record.InputProgress, silk/tls_record.RecordError>Copies a prefix for the current record and reports the exact next receive action.
Details
Empty input reports zero-consumption NeedInput. Header admission occurs after exactly five
bytes and before any body byte is copied. Completion stops before a coalesced following record.
A ready record causes zero-consumption NeedRecordConsumption until consumeRecord or
consumeRecordInto succeeds. During a protected epoch, exact plaintext compatibility CCS
{1} is admitted without consuming a protected sequence; every other record remains protected.
Gotchas
Header, authentication, content, and key-use failures terminally invalidate this receiver.
Method TlsRecordReceiver.record
pub fn record<'owner>(self: &'owner TlsRecordReceiver) -> silk/option.Option<silk/tls_record.RecordView<'owner>>Borrows the complete current record, or returns None while more input is needed.
Method TlsRecordReceiver.readyContentType
pub fn readyContentType<'life0>(self: &'life0 TlsRecordReceiver) -> silk/option.Option<silk/tls_record.ContentType>Returns the ready record's authenticated content type without borrowing its content.
Method TlsRecordReceiver.readyLength
pub fn readyLength<'life0>(self: &'life0 TlsRecordReceiver) -> usizeReturns the ready record's authenticated content length, or zero when no record is ready.
Method TlsRecordReceiver.consumeRecordInto
pub fn consumeRecordInto<'life0, 'life1>(self: &'life0 mut TlsRecordReceiver, destination: &'life1 mut [u8]) -> silk/result.Result<usize, silk/tls_record.RecordError>Copies and consumes one complete authenticated record without retaining an owner-tied view.
Gotchas
A destination smaller than the ready content returns RecordOverflow and leaves the record
ready and unchanged. No ready record returns InvalidState.
Method TlsRecordReceiver.consumeRecord
pub fn consumeRecord<'life0>(self: &'life0 mut TlsRecordReceiver) -> silk/result.Result<(), silk/tls_record.RecordError>Releases the current record and permits input for the next record.