moonbitstack/moontls/record does not have a README file

    Auth

    pub(all) enum Auth {
    Rsa
    Ecdsa
    } derive(Eq,
    Debug
    )

    The kind of certificate a suite is for. EdDSA certificates go with Ecdsa, as RFC 8422 §5.1 has.

    Auth::equal

    fn Auth::equal(Auth, Auth) -> Bool

    Auth::not_equal

    fn Auth::not_equal(x : Auth, y : Auth) -> Bool

    Auth::to_repr

    Bulk

    pub(all) enum Bulk {
    Aead(Suite)
    Ccm(key~ : Int, tag~ : Int)
    Cbc(key~ : Int, mac~ : Mac)
    } derive(Eq,
    Debug
    )

    How a suite protects its records.

    Bulk::equal

    fn Bulk::equal(Bulk, Bulk) -> Bool

    Bulk::not_equal

    fn Bulk::not_equal(x : Bulk, y : Bulk) -> Bool

    Bulk::to_repr

    Cipher

    pub struct Cipher {
    suite : Suite
    traffic : Traffic
    seq : UInt64
    // private fields
    }

    One direction's record protection: its suite, traffic keys, and the sequence number that keeps their nonces apart. RFC 8446 §5.3 restarts the sequence at zero on every key change.

    Cipher::is_tls12

    fn Cipher::is_tls12(self : Cipher) -> Bool

    Whether this cipher frames records the TLS 1.2 way.

    Cipher::new

    fn Cipher::new(secret : BytesView, suite? : Suite) -> Cipher

    Record protection under the traffic secret, starting at sequence zero.

    Cipher::nonce

    fn Cipher::nonce(self : Cipher) -> Bytes

    The nonce the next record will be sealed or opened under (RFC 8446 §5.3).

    Cipher::of12

    fn Cipher::of12(suite : Suite12, key : BytesView, iv : BytesView, mac_key? : BytesView, etm? : Bool, rand~ : (Int) -> Bytes) -> Cipher

    Record protection for TLS 1.2 under keys from the key block. etm is whether RFC 7366 was agreed, and rand is where CBC's per-record IVs come from.

    Cipher::open

    fn Cipher::open(self : Cipher, record : BytesView) -> (Kind, Bytes) raise
    Alert

    Open one whole TLSCiphertext record — header included, since RFC 8446 §5.2 makes that header the AEAD's additional data — into the content type and content sealed inside, advancing the sequence number.

    A tag that does not verify is a BadRecordMac and the sequence does not move, because §5.2 ends the connection there.

    Cipher::rekey

    fn Cipher::rekey(self : Cipher, secret : BytesView) -> Unit

    Install a new traffic secret and restart the sequence number at zero (RFC 8446 §5.3).

    Cipher::seal

    fn Cipher::seal(self : Cipher, kind : Kind, content : BytesView, padding? : Int) -> Bytes raise
    Alert

    Seal content as a TLSCiphertext record (RFC 8446 §5.2) with padding zero octets after the inner content type, and advance the sequence number.

    Cipher::seq

    fn Cipher::seq(self : Cipher) -> UInt64

    The sequence number the next record will use.

    Cipher::traffic

    fn Cipher::traffic(self : Cipher) -> Traffic

    The traffic keys in force.

    Exchange

    pub(all) enum Exchange {
    Ecdhe
    Dhe
    Rsa
    } derive(Eq,
    Debug
    )

    How the two ends agree on a premaster secret.

    Exchange::equal

    fn Exchange::equal(Exchange, Exchange) -> Bool

    Exchange::not_equal

    fn Exchange::not_equal(x : Exchange, y : Exchange) -> Bool

    Exchange::to_repr

    Kind

    pub(all) enum Kind {
    ChangeCipherSpec
    Alert
    Handshake
    ApplicationData
    Ack
    Other(Int)
    } derive(Eq,
    Debug
    )

    What a record carries (RFC 8446 §5).

    Other keeps a content type the RFC does not define rather than losing it, but the parser refuses one: an unknown type is an UnexpectedMessage, not something to skip past.

    Kind::code

    fn Kind::code(self : Kind) -> Int

    The octet this content type goes on the wire as.

    Kind::equal

    fn Kind::equal(Kind, Kind) -> Bool

    Kind::not_equal

    fn Kind::not_equal(x : Kind, y : Kind) -> Bool

    Kind::of

    fn Kind::of(code : Int) -> Kind?

    The content type an octet names, or None for one RFC 8446 §5 does not define — which the record parser turns into an alert rather than tolerating.

    Kind::to_repr

    Mac

    pub(all) enum Mac {
    Sha1
    Sha256
    Sha384
    } derive(Eq,
    Debug
    )

    The MAC of a CBC suite.

    Mac::equal

    fn Mac::equal(Mac, Mac) -> Bool

    Mac::hasher

    fn Mac::hasher(self : Mac) -> (() -> &
    Hash
    )

    The hash a MAC is keyed over.

    Mac::not_equal

    fn Mac::not_equal(x : Mac, y : Mac) -> Bool

    Mac::size

    fn Mac::size(self : Mac) -> Int

    The MAC's length, which is also its key's.

    Mac::to_repr

    Record

    pub(all) struct Record {
    kind : Kind
    fragment : Bytes
    } derive(Eq,
    Debug
    )

    One record's content type and fragment (RFC 8446 §5.1).

    For a TLSCiphertext the kind is the outer ApplicationData and the fragment is still sealed.

    Record::equal

    fn Record::equal(Record, Record) -> Bool

    Record::not_equal

    fn Record::not_equal(x : Record, y : Record) -> Bool

    Record::to_repr

    Suite

    pub(all) enum Suite {
    Aes128Gcm
    Aes256Gcm
    ChaCha20Poly1305
    } derive(Eq,
    Debug
    )

    A TLS 1.3 cipher suite (RFC 8446 §B.4): the AEAD and the hash, which fix the key length.

    Suite::aead

    fn Suite::aead(self : Suite, key : Bytes) -> &
    Aead

    The suite's AEAD over key. Aborts on a key of the wrong length: every key reaching it came from [traffic] at the suite's length.

    Suite::code

    fn Suite::code(self : Suite) -> Int

    The suite's code on the wire.

    Suite::digest

    The hash the suite's key schedule runs.

    Suite::equal

    fn Suite::equal(Suite, Suite) -> Bool

    Suite::key_size

    fn Suite::key_size(self : Suite) -> Int

    The AEAD key length.

    Suite::not_equal

    fn Suite::not_equal(x : Suite, y : Suite) -> Bool

    Suite::of

    fn Suite::of(code : Int) -> Suite?

    The suite a code names, None for one this library does not implement.

    Suite::to_repr

    Suite12

    pub(all) struct Suite12 {
    code : Int
    exchange : Exchange
    auth : Auth
    bulk : Bulk
    digest :
    Digest

    } derive(Eq,
    Debug
    )

    A row of the table.

    Suite12::equal

    fn Suite12::equal(Suite12, Suite12) -> Bool

    Suite12::is_cbc

    fn Suite12::is_cbc(self : Suite12) -> Bool

    Whether records under this suite are CBC, which is what encrypt-then-MAC applies to.

    Suite12::iv_size

    fn Suite12::iv_size(self : Suite12) -> Int

    The fixed part of the nonce the key block gives each direction: GCM's and CCM's four-octet salt, ChaCha20-Poly1305's twelve, and nothing for CBC, whose IV goes out with each record.

    Suite12::key_size

    fn Suite12::key_size(self : Suite12) -> Int

    The key length.

    Suite12::mac_size

    fn Suite12::mac_size(self : Suite12) -> Int

    The MAC key length: nothing for an AEAD.

    Suite12::name

    fn Suite12::name(self : Suite12) -> String

    The suite's name in the IANA registry, which is what openssl ciphers -stdname prints.

    Suite12::not_equal

    fn Suite12::not_equal(x : Suite12, y : Suite12) -> Bool

    Suite12::of

    fn Suite12::of(code : Int) -> Suite12?

    The suite a code names, None for one this library does not speak.

    Suite12::to_repr

    Traffic

    pub(all) struct Traffic {
    key : Bytes
    iv : Bytes
    } derive(Eq,
    Debug
    )

    The AEAD key and IV one direction protects its records with (RFC 8446 §7.3), at TLS_AES_128_GCM_SHA256's lengths.

    Traffic::equal

    fn Traffic::equal(Traffic, Traffic) -> Bool

    Traffic::not_equal

    fn Traffic::not_equal(x : Traffic, y : Traffic) -> Bool

    Traffic::to_repr

    all12

    let all12 : Array[Suite12]

    Every suite this library speaks, strongest first. Asking for these is asking to talk to whatever is out there; suites12 is the default for good reason.

    decode

    fn decode(view : BytesView) -> (Record, Int)? raise
    Alert

    Read one TLSPlaintext record (RFC 8446 §5.1) and how many octets it consumed, or None while the view is short of a whole record.

    decode12

    fn decode12(view : BytesView) -> (Record, Int)? raise
    Alert

    Read a TLS 1.2 record, whose ciphertext may run past what 1.3 allows.

    decode_encrypted

    fn decode_encrypted(view : BytesView) -> (Record, Int)? raise
    Alert

    Read one TLSCiphertext record (RFC 8446 §5.2) and how many octets it consumed.

    The fragment is the still-sealed encrypted_record, so the ceiling is the larger §5.2 one.

    encode

    fn encode(kind : Kind, fragment : BytesView) -> Bytes raise
    Alert

    Frame fragment as a TLSPlaintext record (RFC 8446 §5.1).

    legacy_record_version is 0x0303 whatever the negotiated version is; a receiver ignores it.
    let header : Int

    The record header: content type, legacy_record_version, and a 16-bit length.

    inner

    fn inner(kind : Kind, content : BytesView, padding? : Int) -> Bytes

    A TLSInnerPlaintext (RFC 8446 §5.2): the content, then the content type the outer header is hiding, then padding zero octets.

    The padding is §5.4's length-hiding knob — a record's length leaks how much was said, and zero octets after the type cost only bandwidth.

    iv_size

    let iv_size : Int

    The IV length AEAD_AES_128_GCM fixes (RFC 5116 §5.1).

    key_size

    let key_size : Int

    The key length TLS_AES_128_GCM_SHA256 fixes: AES-128.

    max_encrypted

    let max_encrypted : Int

    The largest TLSCiphertext encrypted_record (RFC 8446 §5.2): 2^14 + 256 — the fragment limit plus the room the inner content type, the padding and the AEAD tag need.

    max_fragment

    let max_fragment : Int

    The largest TLSPlaintext fragment (RFC 8446 §5.1): 2^14 octets.

    The RFC fixes it, so it is a constant and not a parameter: a record past it is not a record.

    max_fragment12

    let max_fragment12 : Int

    The longest TLSCiphertext fragment TLS 1.2 allows (RFC 5246 §6.2.3).

    nonce

    fn nonce(iv : BytesView, seq : UInt64) -> Bytes

    The per-record AEAD nonce (RFC 8446 §5.3): the 64-bit sequence number, big- endian and left-padded with zeros to the IV's length, XORed with the static write IV.

    The IV never changes, so the sequence number alone is what keeps two records under one key from ever sharing a nonce.

    suites12

    let suites12 : Array[Suite12]

    The ECDHE suites with an AEAD, which is what is on by default: forward secrecy, and no MAC to time.

    tag_size

    let tag_size : Int

    The AEAD tag length AEAD_AES_128_GCM fixes.

    traffic

    fn traffic(secret : BytesView, digest? :
    Digest
    , prefix? : BytesView, len? : Int) -> Traffic

    Derive a direction's record-protection key and IV from its traffic secret (RFC 8446 §7.3).

    QUIC expands the same secret under "quic key"/"quic iv" and adds a header-protection key (RFC 9001 §5.1); over TCP the labels are bare and there is no header to protect.

    unpad

    fn unpad(plaintext : BytesView) -> (Kind, Bytes) raise
    Alert

    Split a TLSInnerPlaintext back into its content type and content (RFC 8446 §5.2).

    Scan back over the zero padding to the last non-zero octet, which is the type. An inner plaintext of nothing but zeros names no type at all, which §5.2 makes an UnexpectedMessage rather than an empty record.

    Powered by MoonBit

    Site sourceReport issueModulesSkillsBuild queueStatistics

    © 2026 mooncakes.io