├── noheader.txt ├── dist ├── .gitignore ├── Makefile.include ├── LowStar.h ├── internal │ ├── LowStar.h │ ├── EverQuic_Krmllib.h │ └── LowParse.h ├── QUICTest.h ├── EverQuic_Krmllib.h ├── LowParse.c ├── libeverquic.def ├── QUIC.h ├── QUIC.c ├── Makefile.basic ├── EverQuic_EverCrypt.h └── EverQuic.h ├── .gitignore ├── src ├── EverCrypt.CTR.fsti ├── Makefile ├── Model.Flags.fst ├── Model.Helpers.fst ├── QUIC.Secret.Int.Base.fst ├── QUIC.UInt62.fst ├── QUIC.Impl.Base.fst ├── Model.Flags.fsti ├── experimental │ ├── QUIC.Cipher16.fst │ ├── PNEPRF.fsti │ ├── Model.PNEPRF.fsti │ ├── integers.fst │ ├── GCTR_s.fst │ └── DefineTable.fst ├── QUIC.Spec.VarInt.fsti ├── QUIC.TotSpec.fsti ├── QUIC.UInt.fst ├── QUIC.Spec.PacketNumber.Base.fst ├── QUIC.Impl.PacketNumber.fsti ├── QUIC.Spec.Base.fst ├── QUIC.Spec.PacketNumber.fsti ├── QUIC.Secret.Buffer.fst ├── QUIC.Impl.VarInt.fsti ├── Model.Indexing.fsti ├── QUIC.Spec.Crypto.fst ├── QUIC.Secret.Seq.fst ├── Model.Helpers.fsti ├── QUIC.Impl.Crypto.fsti ├── QUIC.Spec.Header.fsti ├── QUIC.Secret.Int.fst ├── QUIC.Spec.fsti ├── QUIC.Spec.Crypto.fsti ├── QUIC.Spec.PacketNumber.Lemmas.fst ├── QUIC.Impl.Header.Parse.fsti ├── Model.AEAD.fst ├── QUIC.Spec.fst ├── QUIC.Impl.Crypto.fst ├── Model.PNE.fst ├── QUIC.Secret.Seq.fsti ├── QUIC.Spec.Header.Base.fst ├── QUIC.Spec.Header.Parse.fsti ├── QUIC.Secret.Int.fsti ├── QUIC.Spec.Header.Public.fsti ├── QUIC.Impl.Header.fsti ├── Mem.fst └── QUIC.Impl.Lemmas.fsti ├── test ├── Makefile └── main.c ├── hints ├── Model.Flags.fsti.hints ├── EverCrypt.CTR.fsti.hints ├── QUIC.Impl.Base.fst.hints ├── QUIC.Secret.Int.Base.fst.hints ├── QUIC.UInt62.fst.hints ├── Model.Flags.fst.hints ├── QUIC.TotSpec.fsti.hints ├── Model.Indexing.fsti.hints ├── QUIC.Spec.Base.fst.hints ├── QUIC.Spec.PacketNumber.fsti.hints ├── QUIC.Spec.PacketNumber.Base.fst.hints ├── QUIC.Impl.PacketNumber.fsti.hints ├── NotEverCrypt.CTR.fsti.hints ├── QUIC.Impl.Crypto.fsti.hints ├── QUIC.Spec.VarInt.fsti.hints ├── QUIC.Spec.Header.fsti.hints ├── QUIC.Secret.Int.fsti.hints ├── QUIC.Impl.Header.Parse.fsti.hints └── QUIC.Spec.Crypto.fsti.hints ├── package ├── install-fstar-mode.el ├── fstar.sh ├── init.el └── package.sh ├── .gitattributes ├── Makefile.include ├── .docker └── build │ ├── config.json │ ├── build_helper.sh │ ├── linux │ └── Dockerfile │ ├── windows-nt │ └── Dockerfile │ └── build.sh ├── install-everest.sh ├── Dockerfile └── Makefile /noheader.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dist/.gitignore: -------------------------------------------------------------------------------- 1 | *.d 2 | *.o 3 | *.a 4 | test.exe 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | obj 2 | *~ 3 | .depend 4 | *.o 5 | *.orig 6 | .#* 7 | -------------------------------------------------------------------------------- /src/EverCrypt.CTR.fsti: -------------------------------------------------------------------------------- 1 | module EverCrypt.CTR 2 | 3 | include NotEverCrypt.CTR 4 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | EVERQUIC_HOME=$(realpath ..) 2 | 3 | include ../Makefile.include 4 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | EVERQUIC_HOME=$(realpath ..) 2 | 3 | include $(EVERQUIC_HOME)/Makefile.include 4 | -------------------------------------------------------------------------------- /hints/Model.Flags.fsti.hints: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/project-everest/everquic-crypto/HEAD/hints/Model.Flags.fsti.hints -------------------------------------------------------------------------------- /hints/EverCrypt.CTR.fsti.hints: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/project-everest/everquic-crypto/HEAD/hints/EverCrypt.CTR.fsti.hints -------------------------------------------------------------------------------- /hints/QUIC.Impl.Base.fst.hints: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/project-everest/everquic-crypto/HEAD/hints/QUIC.Impl.Base.fst.hints -------------------------------------------------------------------------------- /package/install-fstar-mode.el: -------------------------------------------------------------------------------- 1 | (load-file "~/.emacs.d/init.el") 2 | (package-refresh-contents) 3 | (package-install 'fstar-mode) 4 | -------------------------------------------------------------------------------- /hints/QUIC.Secret.Int.Base.fst.hints: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/project-everest/everquic-crypto/HEAD/hints/QUIC.Secret.Int.Base.fst.hints -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.fst eol=lf 2 | *.fsti eol=lf 3 | *.hints eol=lf -diff linguist-generated 4 | Makefile eol=lf 5 | Makefile.* eol=lf 6 | *.sh text eol=lf 7 | -------------------------------------------------------------------------------- /package/fstar.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if args=$(make -s --no-print-directory "$1-in") ; then 4 | echo Found arguments: $args 5 | exec "$FSTAR_EXE" $args "$@" 6 | fi 7 | 8 | "$FSTAR_EXE" "$@" 9 | -------------------------------------------------------------------------------- /src/Model.Flags.fst: -------------------------------------------------------------------------------- 1 | module Model.Flags 2 | 3 | inline_for_extraction let model = false 4 | inline_for_extraction let ideal_TS = false 5 | inline_for_extraction let ideal_AEAD = false 6 | inline_for_extraction let ideal_PNE = false 7 | -------------------------------------------------------------------------------- /hints/QUIC.UInt62.fst.hints: -------------------------------------------------------------------------------- 1 | [ 2 | "213e7d203bf40a2aedcc4fb3d3beb497", 3 | [ 4 | [ 5 | "QUIC.UInt62.bound", 6 | 1, 7 | 2, 8 | 1, 9 | [ "@query" ], 10 | 0, 11 | "46e7276c2d8c0be5ae35587ff63ec326" 12 | ] 13 | ] 14 | ] -------------------------------------------------------------------------------- /test/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "EverQuic.h" 5 | #include "QUICTest.h" 6 | 7 | bool QUICTest_is_equal (uint8_t * b1, uint8_t * b2, uint32_t len) { 8 | return (memcmp(b1, b2, len) == 0); 9 | } 10 | 11 | int main () { 12 | return QUICTest_test (); 13 | } 14 | -------------------------------------------------------------------------------- /dist/Makefile.include: -------------------------------------------------------------------------------- 1 | USER_TARGET=libeverquic.a 2 | USER_CFLAGS= 3 | USER_C_FILES= 4 | ALL_C_FILES=EverQuic.c EverQuic_EverCrypt.c LowParse.c QUIC.c QUICTest.c 5 | ALL_H_FILES=EverQuic.h EverQuic_EverCrypt.h QUIC.h QUICTest.h internal/EverQuic_EverCrypt.h internal/EverQuic_Krmllib.h internal/LowParse.h internal/LowStar.h 6 | -------------------------------------------------------------------------------- /src/Model.Helpers.fst: -------------------------------------------------------------------------------- 1 | module Model.Helpers 2 | 3 | friend Lib.RawIntTypes 4 | 5 | let correct #l (b:Seq.seq UInt8.t{Seq.length b = l}) 6 | : Lemma (reveal #l (hide b) == b) 7 | [SMTPat (reveal #l (hide b))] 8 | = 9 | assert (reveal #l (hide b) `Seq.equal` b) 10 | 11 | let correct2 #l b = 12 | assert (hide (reveal #l b) `Seq.equal` b) 13 | -------------------------------------------------------------------------------- /hints/Model.Flags.fst.hints: -------------------------------------------------------------------------------- 1 | [ 2 | "a782360fb568d33886f972380dfe42d3", 3 | [ 4 | [ 5 | "Model.Flags.ideal_PNE", 6 | 1, 7 | 2, 8 | 1, 9 | [ 10 | "@query", "equation_Model.Flags.ideal_AEAD", 11 | "projection_inverse_BoxBool_proj_0" 12 | ], 13 | 0, 14 | "16eaff9e2bc9af1dd3e31bc82a01f628" 15 | ] 16 | ] 17 | ] -------------------------------------------------------------------------------- /src/QUIC.Secret.Int.Base.fst: -------------------------------------------------------------------------------- 1 | module QUIC.Secret.Int.Base 2 | include Lib.IntTypes 3 | 4 | module U8 = FStar.UInt8 5 | module U16 = FStar.UInt16 6 | module U32 = FStar.UInt32 7 | module U64 = FStar.UInt64 8 | 9 | unfold 10 | let v #t #l (u: int_t t l) : GTot (range_t t) = 11 | v u 12 | 13 | noextract 14 | let supported_type = function 15 | | U8 | U16 | U32 | U64 -> true 16 | | _ -> false 17 | -------------------------------------------------------------------------------- /package/init.el: -------------------------------------------------------------------------------- 1 | (require 'package) 2 | (add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/") t) 3 | (package-initialize) 4 | (custom-set-variables 5 | ;; custom-set-variables was added by Custom. 6 | ;; If you edit it by hand, you could mess it up, so be careful. 7 | ;; Your init file should contain only one such instance. 8 | ;; If there is more than one, they won't work right. 9 | '(fstar-executable "~/bin/fstar.sh") 10 | ) 11 | -------------------------------------------------------------------------------- /dist/LowStar.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef __LowStar_H 4 | #define __LowStar_H 5 | 6 | 7 | 8 | 9 | #include "krml/internal/target.h" 10 | #include "krml/internal/types.h" 11 | #include "krml/lowstar_endianness.h" 12 | #include 13 | #include 14 | #include 15 | static inline void store128_le(uint8_t *x0, FStar_UInt128_uint128 x1); 16 | 17 | static inline FStar_UInt128_uint128 load128_be(uint8_t *x0); 18 | 19 | 20 | #define __LowStar_H_DEFINED 21 | #endif 22 | -------------------------------------------------------------------------------- /src/QUIC.UInt62.fst: -------------------------------------------------------------------------------- 1 | module QUIC.UInt62 2 | module U64 = FStar.UInt64 3 | include FStar.UInt64 4 | 5 | inline_for_extraction 6 | let bound : (bound: U64.t { U64.v bound == pow2 62 }) = 7 | [@inline_let] let v = 4611686018427387904uL in 8 | [@inline_let] let _ = assert_norm (U64.v v == pow2 62) in 9 | v 10 | 11 | inline_for_extraction 12 | let t = (x: U64.t { U64.v x < U64.v bound }) 13 | 14 | module Secret = QUIC.Secret.Int 15 | 16 | inline_for_extraction 17 | let secret = (x: Secret.uint64 { Secret.v x < U64.v bound }) 18 | -------------------------------------------------------------------------------- /src/QUIC.Impl.Base.fst: -------------------------------------------------------------------------------- 1 | module QUIC.Impl.Base 2 | 3 | module U32 = FStar.UInt32 4 | module U62 = QUIC.UInt62 5 | 6 | (* Length computations need to be transparent because the precondition 7 | to QUIC.Impl.encrypt requires the user to provide a destination buffer 8 | large enough to contain the byte representation of the header *) 9 | 10 | let varint_len 11 | (x: U62.t) 12 | : Tot (y: U32.t {U32.v y <= 8}) 13 | = if x `U62.lt` 64uL 14 | then 1ul 15 | else if x `U62.lt` 16384uL 16 | then 2ul 17 | else if x `U62.lt` 1073741824uL 18 | then 4ul 19 | else 8ul 20 | -------------------------------------------------------------------------------- /dist/internal/LowStar.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef __internal_LowStar_H 4 | #define __internal_LowStar_H 5 | 6 | #include "krml/internal/target.h" 7 | #include "krml/internal/types.h" 8 | #include "krml/lowstar_endianness.h" 9 | #include 10 | #include 11 | #include 12 | 13 | static inline void store128_le(uint8_t *x0, FStar_UInt128_uint128 x1); 14 | 15 | static inline FStar_UInt128_uint128 load128_be(uint8_t *x0); 16 | 17 | extern void LowStar_Printf_print_string(Prims_string uu___); 18 | 19 | 20 | #define __internal_LowStar_H_DEFINED 21 | #endif 22 | -------------------------------------------------------------------------------- /dist/QUICTest.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef __QUICTest_H 4 | #define __QUICTest_H 5 | 6 | #include "EverQuic_EverCrypt.h" 7 | #include "EverQuic.h" 8 | #include "krml/internal/target.h" 9 | #include "krml/internal/types.h" 10 | #include "krml/lowstar_endianness.h" 11 | #include 12 | #include 13 | #include 14 | 15 | extern EverQuic_index QUICTest_idx; 16 | 17 | bool QUICTest_is_success_body(EverCrypt_Error_error_code e); 18 | 19 | bool QUICTest_check_is_true_body(bool e); 20 | 21 | extern bool QUICTest_is_equal(uint8_t *b1, uint8_t *b2, uint32_t len); 22 | 23 | exit_code QUICTest_test(void); 24 | 25 | 26 | #define __QUICTest_H_DEFINED 27 | #endif 28 | -------------------------------------------------------------------------------- /hints/QUIC.TotSpec.fsti.hints: -------------------------------------------------------------------------------- 1 | [ 2 | "341037d04dc027fb5083324e811abe88", 3 | [ 4 | [ 5 | "QUIC.TotSpec.encrypt", 6 | 1, 7 | 2, 8 | 1, 9 | [ 10 | "@query", "equation_QUIC.Spec.Crypto.supported_aead", 11 | "equation_Spec.Agile.AEAD.is_supported_alg" 12 | ], 13 | 0, 14 | "c81b4f6e18747859ed3268068b689f9e" 15 | ], 16 | [ 17 | "QUIC.TotSpec.decrypt", 18 | 1, 19 | 2, 20 | 1, 21 | [ 22 | "@query", "equation_QUIC.Spec.Crypto.supported_aead", 23 | "equation_Spec.Agile.AEAD.is_supported_alg" 24 | ], 25 | 0, 26 | "bea78174073a587bdfd1fcd940431c0a" 27 | ] 28 | ] 29 | ] -------------------------------------------------------------------------------- /package/package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | NAME=quic-crypto 6 | ARCHIVE=$NAME.tar.bz2 7 | 8 | ln -s .. $NAME 9 | tar cjf $ARCHIVE \ 10 | $NAME/Dockerfile \ 11 | $NAME/install-everest.sh \ 12 | $NAME/src/*.fst \ 13 | $NAME/src/*.fsti \ 14 | $NAME/src/Makefile \ 15 | $NAME/test/* \ 16 | $NAME/Makefile* \ 17 | $NAME/README.md \ 18 | $NAME/package/package.sh \ 19 | $NAME/package/fstar.sh \ 20 | $NAME/package/*.el \ 21 | $NAME/noheader.txt \ 22 | $NAME/dist/EverQuic.c \ 23 | $NAME/dist/EverQuic.h \ 24 | $NAME/hints/* \ 25 | $(for f in $NAME/dist/*.c $NAME/dist/*.h $NAME/dist/*.def $NAME/dist/Makefile.* ; do if [[ -e $f ]] ; then echo $f ; fi ; done) 26 | rm $NAME 27 | -------------------------------------------------------------------------------- /src/Model.Flags.fsti: -------------------------------------------------------------------------------- 1 | module Model.Flags 2 | 3 | /// A generic flag that enables cryptographic modeling. Allows defining a switch 4 | /// between calling the specification / calling the implementation. 5 | inline_for_extraction 6 | val model : bool 7 | 8 | type ideal_flag = b:bool{b ==> model} 9 | 10 | /// Specific flags for each one of our cryptographic security assumptions. 11 | 12 | /// Ideal keying for transport secret (?) 13 | inline_for_extraction val ideal_TS: ideal_flag 14 | 15 | /// Ideal encrypted authenticated functionality 16 | inline_for_extraction val ideal_AEAD : f:ideal_flag{b2t f ==> b2t ideal_TS} 17 | 18 | /// Ideal PRF used with an auxiliary key. 19 | inline_for_extraction val ideal_PNE : f:ideal_flag{b2t f <==> b2t ideal_AEAD} 20 | -------------------------------------------------------------------------------- /hints/Model.Indexing.fsti.hints: -------------------------------------------------------------------------------- 1 | [ 2 | "82e40204790793e918819fa7e1caf2b3", 3 | [ 4 | [ 5 | "Model.Indexing.cipher_of_aead", 6 | 1, 7 | 2, 8 | 1, 9 | [ 10 | "@MaxIFuel_assumption", "@query", "bool_inversion", 11 | "disc_equation_Spec.Agile.AEAD.AES128_GCM", 12 | "disc_equation_Spec.Agile.AEAD.AES256_GCM", 13 | "disc_equation_Spec.Agile.AEAD.CHACHA20_POLY1305", 14 | "equation_Model.Indexing.ea", 15 | "equation_Model.Indexing.is_supported_aead", 16 | "refinement_interpretation_Tm_refine_b80938e075142236aafbfb01e60d70df", 17 | "typing_Model.Indexing.is_supported_aead" 18 | ], 19 | 0, 20 | "1e1e4a1d24210b89cbd5b2e4e7aeeb61" 21 | ] 22 | ] 23 | ] -------------------------------------------------------------------------------- /dist/EverQuic_Krmllib.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef __EverQuic_Krmllib_H 4 | #define __EverQuic_Krmllib_H 5 | 6 | 7 | 8 | 9 | #include "krml/internal/target.h" 10 | #include "krml/internal/types.h" 11 | #include "krml/lowstar_endianness.h" 12 | #include 13 | #include 14 | #include 15 | static inline uint32_t FStar_UInt32_eq_mask(uint32_t a, uint32_t b); 16 | 17 | static inline uint64_t FStar_UInt64_eq_mask(uint64_t a, uint64_t b); 18 | 19 | static inline uint64_t FStar_UInt64_gte_mask(uint64_t a, uint64_t b); 20 | 21 | static inline FStar_UInt128_uint128 22 | FStar_UInt128_add_mod(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); 23 | 24 | static inline FStar_UInt128_uint128 FStar_UInt128_uint64_to_uint128(uint64_t a); 25 | 26 | 27 | #define __EverQuic_Krmllib_H_DEFINED 28 | #endif 29 | -------------------------------------------------------------------------------- /dist/LowParse.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "internal/LowParse.h" 4 | 5 | uint8_t LowParse_BitFields_get_bitfield_gen8(uint8_t x, uint32_t lo, uint32_t hi) 6 | { 7 | uint8_t op1 = (uint32_t)x << (8U - hi); 8 | return (uint32_t)op1 >> (8U - hi + lo); 9 | } 10 | 11 | uint8_t LowParse_BitFields_set_bitfield_gen8(uint8_t x, uint32_t lo, uint32_t hi, uint8_t v) 12 | { 13 | uint8_t op0 = 255U; 14 | uint8_t op1 = (uint32_t)op0 >> (8U - (hi - lo)); 15 | uint8_t op2 = (uint32_t)op1 << lo; 16 | uint8_t op3 = ~op2; 17 | uint8_t op4 = (uint32_t)x & (uint32_t)op3; 18 | uint8_t op5 = (uint32_t)v << lo; 19 | return (uint32_t)op4 | (uint32_t)op5; 20 | } 21 | 22 | #define VALIDATOR_MAX_LENGTH (4294967295ULL) 23 | 24 | bool LowParse_Low_ErrorCode_is_error(uint64_t positionOrError) 25 | { 26 | return positionOrError > VALIDATOR_MAX_LENGTH; 27 | } 28 | 29 | -------------------------------------------------------------------------------- /dist/internal/EverQuic_Krmllib.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef __internal_EverQuic_Krmllib_H 4 | #define __internal_EverQuic_Krmllib_H 5 | 6 | #include "krml/internal/target.h" 7 | #include "krml/internal/types.h" 8 | #include "krml/lowstar_endianness.h" 9 | #include 10 | #include 11 | #include 12 | 13 | static KRML_NOINLINE uint32_t FStar_UInt32_eq_mask(uint32_t a, uint32_t b); 14 | 15 | static KRML_NOINLINE uint64_t FStar_UInt64_eq_mask(uint64_t a, uint64_t b); 16 | 17 | static KRML_NOINLINE uint64_t FStar_UInt64_gte_mask(uint64_t a, uint64_t b); 18 | 19 | static inline FStar_UInt128_uint128 20 | FStar_UInt128_add_mod(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); 21 | 22 | static inline FStar_UInt128_uint128 FStar_UInt128_uint64_to_uint128(uint64_t a); 23 | 24 | 25 | #define __internal_EverQuic_Krmllib_H_DEFINED 26 | #endif 27 | -------------------------------------------------------------------------------- /dist/internal/LowParse.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef __internal_LowParse_H 4 | #define __internal_LowParse_H 5 | 6 | #include "krml/internal/target.h" 7 | #include "krml/internal/types.h" 8 | #include "krml/lowstar_endianness.h" 9 | #include 10 | #include 11 | #include 12 | 13 | uint8_t LowParse_BitFields_get_bitfield_gen8(uint8_t x, uint32_t lo, uint32_t hi); 14 | 15 | uint8_t LowParse_BitFields_set_bitfield_gen8(uint8_t x, uint32_t lo, uint32_t hi, uint8_t v); 16 | 17 | bool LowParse_Low_ErrorCode_is_error(uint64_t positionOrError); 18 | 19 | #define LOWPARSE_LOW_ERRORCODE_VALIDATOR_ERROR_GENERIC (4294967296ULL) 20 | 21 | #define LOWPARSE_LOW_ERRORCODE_VALIDATOR_ERROR_NOT_ENOUGH_DATA (8589934592ULL) 22 | 23 | typedef struct LowParse_Slice_slice_s 24 | { 25 | uint8_t *base; 26 | uint32_t len; 27 | } 28 | LowParse_Slice_slice; 29 | 30 | 31 | #define __internal_LowParse_H_DEFINED 32 | #endif 33 | -------------------------------------------------------------------------------- /hints/QUIC.Spec.Base.fst.hints: -------------------------------------------------------------------------------- 1 | [ 2 | "ef34363b4849c2075fbce2248e6b4d55", 3 | [ 4 | [ 5 | "QUIC.Spec.Base.lbytes", 6 | 1, 7 | 2, 8 | 1, 9 | [ 10 | "@MaxIFuel_assumption", "@query", "equation_Prims.eqtype", 11 | "equation_Prims.nat", "function_token_typing_Prims.int", 12 | "haseqTm_refine_542f9d4f129664613f2483a6c88bc7c2", 13 | "refinement_interpretation_Tm_refine_414d0a9f578ab0048252f8c8f552b99f" 14 | ], 15 | 0, 16 | "c901d422dbb0deaf876a1af673c2a71b" 17 | ], 18 | [ 19 | "QUIC.Spec.Base.bitfield", 20 | 1, 21 | 2, 22 | 1, 23 | [ 24 | "@MaxIFuel_assumption", "@query", "equation_Prims.eqtype", 25 | "refinement_interpretation_Tm_refine_414d0a9f578ab0048252f8c8f552b99f", 26 | "typing_FStar.UInt8.t" 27 | ], 28 | 0, 29 | "3eb94c6c3fea094a3dd820871ad279a3" 30 | ] 31 | ] 32 | ] -------------------------------------------------------------------------------- /src/experimental/QUIC.Cipher16.fst: -------------------------------------------------------------------------------- 1 | module Cipher16 2 | 3 | module G = FStar.Ghost 4 | module B = LowStar.Buffer 5 | module U8 = FStar.UInt8 6 | module U32 = FStar.UInt32 7 | 8 | open FStar.HyperStack.ST 9 | open EverCrypt.Helpers 10 | open EverCrypt.Error 11 | 12 | module AC = EverCrypt.AutoConfig2 13 | module SC = EverCrypt.StaticConfig 14 | module SC16 = Spec.Cipher16 15 | 16 | // FIXME: integrate GCTR in Spec.Cipher16 and here 17 | #set-options "--admit_smt_queries true" 18 | 19 | 20 | 21 | val block: 22 | a:SC16.alg -> 23 | key: B.lbuffer U8.t (SC16.keylen a) -> 24 | input: B.lbuffer U8.t 16 -> 25 | output: B.lbuffer U8.t 16 -> 26 | Stack unit 27 | (requires fun h0 -> 28 | B.live h0 input /\ B.live h0 output /\ 29 | B.disjoint input output /\ 30 | B.disjoint key input /\ 31 | B.disjoint key output) 32 | (ensures fun h0 _ h1 -> 33 | B.modifies (B.loc_buffer output) h0 h1 /\ 34 | (let kb = B.as_seq h0 key in 35 | let inb = B.as_seq h0 input in 36 | let outb = B.as_seq h1 output in 37 | outb == SC16.block a kb inb)) 38 | 39 | -------------------------------------------------------------------------------- /Makefile.include: -------------------------------------------------------------------------------- 1 | EVERQUIC_HOME ?= $(realpath .) 2 | 3 | FSTAR_EXE ?= fstar.exe 4 | 5 | KRML_HOME ?= $(EVERQUIC_HOME)/../karamel 6 | HACL_HOME ?= $(EVERQUIC_HOME)/../hacl-star 7 | EVERPARSE_HOME ?= $(EVERQUIC_HOME)/../everparse 8 | 9 | include $(HACL_HOME)/Makefile.include 10 | 11 | FSTAR_INCLUDE_PATH= \ 12 | $(EVERQUIC_HOME)/src \ 13 | $(EVERQUIC_HOME)/test \ 14 | $(KRML_HOME)/krmllib \ 15 | $(KRML_HOME)/krmllib/obj \ 16 | $(EVERPARSE_HOME)/src/lowparse \ 17 | $(ALL_HACL_DIRS) 18 | 19 | # In interactive mode, chill out and don't roll over if something isn't cached 20 | # somewhere. 21 | FSTAR_CHILL_FLAGS= \ 22 | $(addprefix --include ,$(FSTAR_INCLUDE_PATH)) \ 23 | --cache_checked_modules \ 24 | --cache_dir $(EVERQUIC_HOME)/obj \ 25 | --odir $(EVERQUIC_HOME)/obj \ 26 | --cmi \ 27 | --use_hints \ 28 | --record_hints \ 29 | $(OTHERFLAGS) 30 | 31 | FSTAR_FLAGS=$(FSTAR_CHILL_FLAGS) \ 32 | --already_cached '*,-QUIC,-QUICTest,-Mem,-Model,-NotEverCrypt,-EverCrypt.CTR' \ 33 | --warn_error @241 \ 34 | 35 | FSTAR=$(FSTAR_EXE) $(FSTAR_FLAGS) 36 | 37 | %.fst-in %.fsti-in: 38 | @echo $(FSTAR_CHILL_FLAGS) 39 | -------------------------------------------------------------------------------- /.docker/build/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "ProjectName" : "everquic-crypto", 3 | 4 | "BaseContainerIsEverestImage" : true, 5 | "BaseContainerImageName" : "hacl-star", 6 | "BaseContainerImageTagOrCommitId": "latest", 7 | "BranchName" : "master", 8 | "GithubCommitUrl" : "https://github.com/project-everest/hacl-star/commit", 9 | "OnDemandBuildDefinition" : "Hacl\\Hacl-{agentOS}", 10 | 11 | "DockerFile": ".docker/build/{agentOS}/Dockerfile", 12 | "DependencyFiles" : [ 13 | ".docker/build/build_helper.sh", 14 | ".docker/build/build.sh" 15 | ], 16 | 17 | "DockerCacheEnabled" : true, 18 | "CIBuildTarget" : "everquic_crypto_test", 19 | "NightlyBuildTarget" : "everquic_crypto_nightly_test", 20 | "HasLogsToExtract" : true, 21 | 22 | "NotificationEnabled" : true, 23 | "NotificationChannel" : "#quic-build", 24 | "PublicBranches" : [ "master" ], 25 | 26 | "CompressBuildFolder": true, 27 | "FolderToCompress" : "everquic-crypto", 28 | "FoldersToExclude" : [ ], 29 | 30 | "RepoVersions" : { 31 | "everparse_version" : "origin/master" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /dist/libeverquic.def: -------------------------------------------------------------------------------- 1 | LIBRARY libeverquic 2 | 3 | EXPORTS 4 | LowParse_BitFields_get_bitfield_gen8 5 | LowParse_BitFields_set_bitfield_gen8 6 | LowParse_Low_ErrorCode_is_error 7 | Spec_Agile_Cipher_key_length 8 | Spec_Agile_AEAD_cipher_alg_of_supported_alg 9 | NotEverCrypt_CTR_create_in 10 | NotEverCrypt_CTR_init 11 | NotEverCrypt_CTR_update_block 12 | EverQuic_uu___is_State 13 | EverQuic_aead_alg_of_state 14 | EverQuic_hash_alg_of_state 15 | EverQuic_last_packet_number_of_state 16 | EverQuic_create_in 17 | EverQuic_encrypt 18 | EverQuic_initial_secrets 19 | EverQuic_decrypt 20 | EverQuic_uu___is_BInitial 21 | EverQuic_uu___is_BZeroRTT 22 | EverQuic_uu___is_BHandshake 23 | EverQuic_uu___is_BRetry 24 | EverQuic_uu___is_BLong 25 | EverQuic_uu___is_BShort 26 | EverQuic_dcid_len 27 | EverQuic_is_retry 28 | EverQuic_pn_length 29 | EverQuic_has_payload_length 30 | EverQuic_payload_and_pn_length 31 | EverQuic_payload_length 32 | EverQuic_public_header_len 33 | EverQuic_header_len 34 | QUICTest_is_success_body 35 | QUICTest_check_is_true_body 36 | QUICTest_test 37 | QUIC_cipher_keysize 38 | QUIC_encrypt 39 | QUIC_decrypt 40 | -------------------------------------------------------------------------------- /dist/QUIC.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef __QUIC_H 4 | #define __QUIC_H 5 | 6 | #include "EverQuic_EverCrypt.h" 7 | #include "EverQuic.h" 8 | #include "krml/internal/target.h" 9 | #include "krml/internal/types.h" 10 | #include "krml/lowstar_endianness.h" 11 | #include 12 | #include 13 | #include 14 | 15 | typedef krml_checked_int_t QUIC_nat62; 16 | 17 | krml_checked_int_t QUIC_cipher_keysize(Spec_Agile_AEAD_alg a); 18 | 19 | typedef uint8_t QUIC_u2; 20 | 21 | typedef uint8_t QUIC_u4; 22 | 23 | typedef uint64_t QUIC_u62; 24 | 25 | typedef EverQuic_index QUIC_index; 26 | 27 | typedef Prims_list__uint8_t *QUIC_traffic_secret; 28 | 29 | typedef EverQuic_state_s *QUIC_state; 30 | 31 | typedef void *QUIC_invariant; 32 | 33 | EverCrypt_Error_error_code 34 | QUIC_encrypt( 35 | EverQuic_index i, 36 | EverQuic_state_s *s, 37 | uint8_t *dst, 38 | uint64_t *dst_pn, 39 | EverQuic_header h, 40 | uint8_t *plain, 41 | uint32_t plain_len 42 | ); 43 | 44 | typedef void *QUIC_decrypt_post; 45 | 46 | EverCrypt_Error_error_code 47 | QUIC_decrypt( 48 | EverQuic_state_s *uu___1, 49 | EverQuic_result *uu___2, 50 | uint8_t *uu___3, 51 | uint32_t uu___4, 52 | uint8_t uu___5 53 | ); 54 | 55 | 56 | #define __QUIC_H_DEFINED 57 | #endif 58 | -------------------------------------------------------------------------------- /.docker/build/build_helper.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | target=$1 4 | out_file=$2 5 | threads=$3 6 | branchname=$4 7 | fstarVersion=$5 8 | 9 | export FSTAR_EXE=$(pwd)/FStar/bin/fstar.exe 10 | export HACL_HOME=$(pwd)/hacl-star 11 | # FIXME: The HACL* image should have been built on top of a KaRaMeL 12 | # image. But currently this is not the case, so we reuse the KaRaMeL 13 | # that was pulled within the HACL* image. 14 | export KRML_HOME=$HACL_HOME/karamel 15 | 16 | # Add ssh identity 17 | eval $(ssh-agent) 18 | ssh-add .ssh/id_rsa 19 | 20 | eval $(opam config env) 21 | 22 | echo $(date -u "+%Y-%m-%d %H:%M:%S") >> $out_file 23 | 24 | tail -f $out_file & 25 | tail_pd=$! 26 | { { { { { { stdbuf -e0 -o0 ./build.sh "$@" ; } 3>&1 1>&2 2>&3 ; } | sed -u 's!^![STDERR]!' ; } 3>&1 1>&2 2>&3 ; } | sed -u 's!^![STDOUT]!' ; } 2>&1 ; } >> $out_file 27 | kill $tail_pd 28 | 29 | echo $(date -u "+%Y-%m-%d %H:%M:%S") >> $out_file 30 | 31 | eval $(ssh-agent) 32 | ssh-add -D 33 | 34 | # Generate query-stats. 35 | # List the hints that fail to replay. 36 | FStar/.scripts/query-stats.py -f $out_file -F html -o log_no_replay.html -n all '--filter=fstar_usedhints=+' '--filter=fstar_tag=-' -g 37 | 38 | # Worst offenders (longest times) 39 | FStar/.scripts/query-stats.py -f $out_file -F html -o log_worst.html -c -g -n 10 40 | -------------------------------------------------------------------------------- /src/QUIC.Spec.VarInt.fsti: -------------------------------------------------------------------------------- 1 | module QUIC.Spec.VarInt 2 | 3 | module U62 = QUIC.UInt62 4 | module U64 = FStar.UInt64 5 | module LP = LowParse.Spec.BoundedInt // for bounded_int32 6 | module Cast = FStar.Int.Cast 7 | 8 | inline_for_extraction 9 | let parse_varint_kind = { 10 | LP.parser_kind_low = 1; 11 | LP.parser_kind_high = Some 8; 12 | LP.parser_kind_subkind = Some LP.ParserStrong; 13 | LP.parser_kind_metadata = None; 14 | } 15 | 16 | val parse_varint : LP.parser parse_varint_kind U62.t 17 | 18 | val serialize_varint : LP.serializer parse_varint 19 | 20 | val parse_bounded_varint 21 | (min: nat) 22 | (max: nat { min <= max /\ max < 4294967296 }) 23 | : Tot (LP.parser parse_varint_kind (LP.bounded_int32 min max)) 24 | 25 | val serialize_bounded_varint 26 | (min: nat) 27 | (max: nat { min <= max /\ max < 4294967296 }) 28 | : Tot (LP.serializer (parse_bounded_varint min max)) 29 | 30 | val varint_len_correct 31 | (x: U62.t) 32 | : Lemma 33 | (QUIC.Spec.Base.varint_len x == FStar.Seq.length (LP.serialize serialize_varint x)) 34 | 35 | val bounded_varint_len_correct 36 | (min: nat) 37 | (max: nat { min <= max /\ max < 4294967296 }) 38 | (x: LP.bounded_int32 min max) 39 | : Lemma 40 | (QUIC.Spec.Base.varint_len (Cast.uint32_to_uint64 x) == FStar.Seq.length (LP.serialize (serialize_bounded_varint min max) x)) 41 | -------------------------------------------------------------------------------- /src/QUIC.TotSpec.fsti: -------------------------------------------------------------------------------- 1 | module QUIC.TotSpec 2 | 3 | include QUIC.Spec.Header.Base 4 | include QUIC.Spec.Crypto 5 | 6 | module Seq = FStar.Seq 7 | module HD = Spec.Hash.Definitions 8 | module AEAD = Spec.Agile.AEAD 9 | module Cipher = Spec.Agile.Cipher 10 | module PN = QUIC.Spec.PacketNumber.Base 11 | module Secret = QUIC.Secret.Int 12 | module Spec = QUIC.Spec 13 | 14 | (* A total (non-ghost) specification of encryption and decryption, for idealization proof purposes, or for functional testing (extracting to OCaml) *) 15 | 16 | val block_of_sample 17 | (a: Cipher.cipher_alg) 18 | (k: Cipher.key a) 19 | (sample: Seq.lseq Secret.uint8 16) 20 | : Tot (y: Seq.lseq Secret.uint8 16 { y == QUIC.Spec.Header.block_of_sample a k sample }) 21 | 22 | val encrypt: 23 | a: ea -> 24 | k: AEAD.kv a -> 25 | static_iv: Spec.iv_t a -> 26 | hpk: Cipher.key (AEAD.cipher_alg_of_supported_alg a) -> 27 | h: header -> 28 | plain: pbytes' (is_retry h) -> 29 | Tot (p: packet { p == Spec.encrypt a k static_iv hpk h plain }) 30 | 31 | val decrypt: 32 | a: ea -> 33 | k: AEAD.kv a -> 34 | static_iv: Spec.iv_t a -> 35 | hpk: Cipher.key (AEAD.cipher_alg_of_supported_alg a) -> 36 | last: nat{last+1 < pow2 62} -> 37 | cid_len: nat { cid_len <= 20 } -> 38 | packet: packet -> 39 | Tot (r: Spec.result { 40 | r == Spec.decrypt a k static_iv hpk last cid_len packet 41 | }) 42 | -------------------------------------------------------------------------------- /dist/QUIC.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "QUIC.h" 4 | 5 | #include "internal/EverQuic_EverCrypt.h" 6 | 7 | krml_checked_int_t QUIC_cipher_keysize(Spec_Agile_AEAD_alg a) 8 | { 9 | return Spec_Agile_Cipher_key_length(Spec_Agile_AEAD_cipher_alg_of_supported_alg(a)); 10 | } 11 | 12 | static EverQuic_index iid(EverQuic_index i) 13 | { 14 | return i; 15 | } 16 | 17 | typedef EverQuic_state_s *raise; 18 | 19 | static EverQuic_state_s *istate(EverQuic_index i, EverQuic_state_s *s) 20 | { 21 | iid(i); 22 | return s; 23 | } 24 | 25 | EverCrypt_Error_error_code 26 | QUIC_encrypt( 27 | EverQuic_index i, 28 | EverQuic_state_s *s, 29 | uint8_t *dst, 30 | uint64_t *dst_pn, 31 | EverQuic_header h, 32 | uint8_t *plain, 33 | uint32_t plain_len 34 | ) 35 | { 36 | EverQuic_state_s *s1 = istate(i, s); 37 | return EverQuic_encrypt(s1, dst, dst_pn, h, plain, plain_len); 38 | } 39 | 40 | EverCrypt_Error_error_code 41 | QUIC_decrypt( 42 | EverQuic_state_s *uu___1, 43 | EverQuic_result *uu___2, 44 | uint8_t *uu___3, 45 | uint32_t uu___4, 46 | uint8_t uu___5 47 | ) 48 | { 49 | KRML_MAYBE_UNUSED_VAR(uu___1); 50 | KRML_MAYBE_UNUSED_VAR(uu___2); 51 | KRML_MAYBE_UNUSED_VAR(uu___3); 52 | KRML_MAYBE_UNUSED_VAR(uu___4); 53 | KRML_MAYBE_UNUSED_VAR(uu___5); 54 | KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, ""); 55 | KRML_HOST_EXIT(255U); 56 | } 57 | 58 | -------------------------------------------------------------------------------- /src/QUIC.UInt.fst: -------------------------------------------------------------------------------- 1 | module QUIC.UInt 2 | include FStar.UInt 3 | open FStar.Math.Lemmas 4 | 5 | #push-options "--z3rlimit 16" 6 | 7 | let rec to_vec_prefix 8 | (n: nat) 9 | (k: nat) 10 | (a: uint_t k) 11 | : Lemma 12 | (requires (k <= n)) 13 | (ensures ( 14 | pow2 k <= pow2 n /\ 15 | to_vec #k a `Seq.equal` Seq.slice (to_vec #n a) (n - k) n 16 | )) 17 | (decreases k) 18 | = if k = 0 19 | then () 20 | else to_vec_prefix (n - 1) (k - 1) (a / 2) 21 | 22 | let rec to_vec_inc 23 | (n: nat) 24 | (k: nat) 25 | (a: uint_t k) 26 | : Lemma 27 | (requires (k <= n)) 28 | (ensures ( 29 | pow2 k <= pow2 n /\ 30 | to_vec #n a `Seq.equal` (Seq.create (n - k) false `Seq.append` to_vec #k a) 31 | )) 32 | (decreases k) 33 | = if k = 0 34 | then () 35 | else to_vec_inc (n - 1) (k - 1) (a / 2) 36 | 37 | let lemma_logxor_lt (#n:pos) (a b:uint_t n) (k:nat{k <= n}) 38 | : Lemma (requires a < pow2 k /\ b < pow2 k) 39 | (ensures a `logxor` b < pow2 k) 40 | = if k = n 41 | then () 42 | else if k = 0 43 | then begin 44 | assert_norm (pow2 0 == 1); 45 | assert (a == 0); 46 | assert (b == 0); 47 | logxor_self #n 0 48 | end 49 | else begin 50 | pow2_lt_compat n k; 51 | to_vec_inc n k a; 52 | to_vec_inc n k b; 53 | to_vec_inc n k (logxor #k a b); 54 | nth_lemma #n (logxor #k a b) (logxor #n a b) 55 | end 56 | 57 | #pop-options 58 | -------------------------------------------------------------------------------- /install-everest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | set -x 4 | git clone https://github.com/project-everest/everest.git 5 | old_pwd="$PWD" 6 | everest_home="$old_pwd/everest" 7 | cd "$everest_home" 8 | git checkout b0d4d92bff399618e751881771f5b49f57069cbe 9 | ./everest --yes opam 10 | ./everest --yes reset 11 | ./everest --yes z3 12 | export PATH=$everest_home/z3/bin:$PATH 13 | export FSTAR_EXE=$everest_home/FStar/bin/fstar.exe 14 | export KRML_HOME=$everest_home/karamel 15 | export EVERPARSE_HOME=$everest_home/everparse 16 | export HACL_HOME=$everest_home/hacl-star 17 | export MLCRYPTO_HOME=$everest_home/MLCrypto 18 | export VALE_HOME=$everest_home/vale 19 | if [[ -z "$EVEREST_THREADS" ]] 20 | then 21 | EVEREST_THREADS=1 22 | fi 23 | OTHERFLAGS='--admit_smt_queries true' ./everest -j $EVEREST_THREADS FStar make karamel make everparse make 24 | OTHERFLAGS='--admit_smt_queries true' make -j $(($EVEREST_THREADS/2+1)) -C hacl-star vale-fst 25 | OTHERFLAGS='--admit_smt_queries true' make -j $(($EVEREST_THREADS/2+1)) -C hacl-star compile-gcc-compatible 26 | cd "$old_pwd" 27 | cat >everest-env.sh < 256 25 | | 1 -> 65536 26 | | 2 -> 16777216 27 | | 3 -> 4294967296 28 | 29 | let in_window (pn_len: nat { pn_len < 4 }) (last pn:nat) : Tot bool = 30 | let h = bound_npn' pn_len in 31 | (last+1 < h/2 && pn < h) || 32 | (last+1 >= U62.v U62.bound - h/2 && pn >= U62.v U62.bound - h) || 33 | (last+1 - h/2 < pn && pn <= last+1 + h/2) 34 | 35 | inline_for_extraction 36 | let packet_number_t = U62.secret 37 | 38 | inline_for_extraction 39 | let packet_number_t' 40 | (last: last_packet_number_t) 41 | (pn_len: packet_number_length_t) 42 | : Tot Type0 43 | = (pn: packet_number_t { in_window (Secret.v pn_len - 1) (Secret.v last) (Secret.v pn) }) 44 | -------------------------------------------------------------------------------- /src/QUIC.Impl.PacketNumber.fsti: -------------------------------------------------------------------------------- 1 | module QUIC.Impl.PacketNumber 2 | include QUIC.Spec.PacketNumber 3 | 4 | module U64 = FStar.UInt64 5 | module U32 = FStar.UInt32 6 | module HST = FStar.HyperStack.ST 7 | module B = LowStar.Buffer 8 | module HS = FStar.HyperStack 9 | module Secret = QUIC.Secret.Int 10 | module SecretBuffer = QUIC.Secret.Buffer 11 | module LP = LowParse.Spec.Base 12 | module Seq = QUIC.Secret.Seq 13 | 14 | val read_packet_number 15 | (last: last_packet_number_t) 16 | (pn_len: packet_number_length_t) 17 | (b: B.buffer Secret.uint8) 18 | : HST.Stack (packet_number_t' last pn_len) 19 | (requires (fun h -> 20 | B.live h b /\ 21 | 4 <= B.length b 22 | )) 23 | (ensures (fun h res h' -> 24 | B.modifies B.loc_none h h' /\ 25 | begin match LP.parse (parse_packet_number last pn_len) (Seq.seq_reveal (B.as_seq h b)) with 26 | | Some (v, _) -> res == v 27 | | None -> False 28 | end 29 | )) 30 | 31 | val write_packet_number 32 | (last: last_packet_number_t) 33 | (pn_len: packet_number_length_t) 34 | (pn: packet_number_t' last pn_len) 35 | (b: B.buffer Secret.uint8) 36 | : HST.Stack unit 37 | (requires (fun h -> 38 | B.live h b /\ 39 | 4 <= B.length b 40 | )) 41 | (ensures (fun h _ h' -> 42 | let b' = B.gsub b 0ul (U32.uint_to_t (Secret.v pn_len)) in 43 | B.modifies (B.loc_buffer b') h h' /\ 44 | Seq.seq_reveal (B.as_seq h' b') == LP.serialize (serialize_packet_number last pn_len) pn 45 | )) 46 | -------------------------------------------------------------------------------- /src/QUIC.Spec.Base.fst: -------------------------------------------------------------------------------- 1 | module QUIC.Spec.Base 2 | 3 | module FB = FStar.Bytes 4 | module U62 = QUIC.UInt62 5 | module U64 = FStar.UInt64 6 | module U32 = FStar.UInt32 7 | module U8 = FStar.UInt8 8 | module S = FStar.Seq 9 | module Secret = QUIC.Secret.Int 10 | 11 | type byte = FStar.UInt8.t 12 | type bytes = S.seq byte 13 | type lbytes (n:nat) = b:bytes{S.length b = n} 14 | 15 | inline_for_extraction 16 | noextract 17 | let bitfield 18 | (sz: nat { sz <= 8 }) 19 | : Tot eqtype 20 | = (x: U8.t { U8.v x < pow2 sz }) 21 | 22 | inline_for_extraction 23 | noextract 24 | let secret_bitfield 25 | (sz: nat { sz <= 8 }) 26 | : Tot Type0 27 | = (x: Secret.uint8 { Secret.v x < pow2 sz }) 28 | 29 | type payload_and_pn_length_t = (payload_and_pn_length: U62.t { U64.v payload_and_pn_length >= 20 }) 30 | 31 | let header_len_bound = 16500 // FIXME: this should be in line with the parser kind 32 | 33 | inline_for_extraction 34 | let short_dcid_len_t = (short_dcid_len: U32.t { U32.v short_dcid_len <= 20 }) 35 | 36 | inline_for_extraction 37 | noextract 38 | let token_max_len = 16383 // arbitrary bound 39 | 40 | inline_for_extraction 41 | let vlbytes (min: nat) (max: nat) = 42 | (x: FB.bytes { min <= FB.length x /\ FB.length x <= max }) 43 | 44 | (* Length computations need to be transparent because of the switch. *) 45 | 46 | let varint_len 47 | (x: U62.t) 48 | : GTot (y: nat {y <= 8}) 49 | = if x `U62.lt` 64uL 50 | then 1 51 | else if x `U62.lt` 16384uL 52 | then 2 53 | else if x `U62.lt` 1073741824uL 54 | then 4 55 | else 8 56 | -------------------------------------------------------------------------------- /dist/Makefile.basic: -------------------------------------------------------------------------------- 1 | # A basic Makefile that KaRaMeL copies in the output directory; this is not 2 | # guaranteed to work and will only work well for very simple projects. This 3 | # Makefile uses: 4 | # - the custom C files passed to your krml invocation 5 | # - the custom C flags passed to your krml invocation 6 | # - the -o option passed to your krml invocation 7 | 8 | include Makefile.include 9 | 10 | ifeq (,$(KRML_HOME)) 11 | $(error please define KRML_HOME to point to the root of your KaRaMeL git checkout) 12 | endif 13 | 14 | CFLAGS += -I. -I $(KRML_HOME)/include -I $(KRML_HOME)/krmllib/dist/minimal 15 | CFLAGS += -Wall -Wextra -Werror -std=c11 \ 16 | -Wno-unknown-warning-option \ 17 | -Wno-infinite-recursion \ 18 | -g -fwrapv -D_BSD_SOURCE -D_DEFAULT_SOURCE 19 | ifeq ($(OS),Windows_NT) 20 | CFLAGS += -D__USE_MINGW_ANSI_STDIO 21 | else 22 | CFLAGS += -fPIC 23 | endif 24 | CFLAGS += $(USER_CFLAGS) 25 | 26 | SOURCES += $(ALL_C_FILES) $(USER_C_FILES) 27 | ifneq (,$(BLACKLIST)) 28 | SOURCES := $(filter-out $(BLACKLIST),$(SOURCES)) 29 | endif 30 | OBJS += $(patsubst %.c,%.o,$(SOURCES)) 31 | 32 | all: $(USER_TARGET) 33 | 34 | $(USER_TARGET): $(OBJS) 35 | 36 | AR ?= ar 37 | 38 | %.a: 39 | $(AR) cr $@ $^ 40 | 41 | %.exe: 42 | $(CC) $(CFLAGS) -o $@ $^ $(KRML_HOME)/krmllib/dist/generic/libkrmllib.a 43 | 44 | %.so: 45 | $(CC) $(CFLAGS) -shared -o $@ $^ 46 | 47 | %.d: %.c 48 | @set -e; rm -f $@; \ 49 | $(CC) -MM -MG $(CFLAGS) $< > $@.$$$$; \ 50 | sed 's,\($(notdir $*)\)\.o[ :]*,$(dir $@)\1.o $@ : ,g' < $@.$$$$ > $@; \ 51 | rm -f $@.$$$$ 52 | 53 | include $(patsubst %.c,%.d,$(SOURCES)) 54 | 55 | clean: 56 | rm -rf *.o *.d $(USER_TARGET) 57 | -------------------------------------------------------------------------------- /.docker/build/linux/Dockerfile: -------------------------------------------------------------------------------- 1 | # EverQUIC-Crypto build container 2 | 3 | # Define on fstar-version.json what FStar base container image 4 | # mitls build should use. 5 | # By default it always look for the latest FStar container available 6 | # In case you would like to reference a specific commit, 7 | # replace latest with the commit id from github using 12 characters. 8 | ARG COMMITID 9 | FROM hacl-star-linux:${COMMITID} 10 | 11 | ARG BUILDLOGFILE 12 | ARG MAXTHREADS 13 | ARG BUILDTARGET 14 | ARG BRANCHNAME 15 | 16 | # ADD SSH KEY 17 | RUN mkdir -p ${MYHOME}/.ssh 18 | RUN chown everest ${MYHOME}/.ssh 19 | RUN chmod 700 ${MYHOME}/.ssh 20 | COPY --chown=everest id_rsa ${MYHOME}/.ssh/id_rsa 21 | RUN chmod 600 ${MYHOME}/.ssh/id_rsa 22 | 23 | # Copy source files 24 | RUN mkdir ${MYHOME}/everquic-crypto 25 | COPY --chown=everest / ${MYHOME}/everquic-crypto/ 26 | 27 | # Do some cleanup 28 | RUN rm -f build.sh 29 | RUN rm -f build_helper.sh 30 | RUN rm -f buildlogfile.txt 31 | RUN rm -f log_no_replay.html 32 | RUN rm -f log_worst.html 33 | RUN rm -f orange_status.txt 34 | RUN rm -f result.txt 35 | RUN rm -f status.txt 36 | RUN rm -f commitinfofilename.json 37 | 38 | RUN rm everquic-crypto/Dockerfile 39 | RUN rm everquic-crypto/build.sh 40 | RUN rm everquic-crypto/build_helper.sh 41 | RUN rm everquic-crypto/id_rsa 42 | RUN rm everquic-crypto/commitinfofilename.json 43 | 44 | COPY --chown=everest build.sh ${MYHOME}/build.sh 45 | RUN chmod +x build.sh 46 | COPY --chown=everest build_helper.sh ${MYHOME}/build_helper.sh 47 | RUN chmod +x build_helper.sh 48 | 49 | RUN ./build_helper.sh ${BUILDTARGET} ${BUILDLOGFILE} ${MAXTHREADS} ${BRANCHNAME} || true 50 | 51 | # Remove ssh identities. 52 | RUN rm ${MYHOME}/.ssh/id_rsa 53 | -------------------------------------------------------------------------------- /src/QUIC.Spec.PacketNumber.fsti: -------------------------------------------------------------------------------- 1 | module QUIC.Spec.PacketNumber 2 | include QUIC.Spec.PacketNumber.Base 3 | open LowParse.Spec.Base 4 | 5 | module U62 = QUIC.UInt62 6 | module U64 = FStar.UInt64 7 | module U32 = FStar.UInt32 8 | module Secret = QUIC.Secret.Int 9 | 10 | inline_for_extraction 11 | let parse_packet_number_kind = strong_parser_kind 1 4 None 12 | 13 | val parse_packet_number 14 | (last: last_packet_number_t) 15 | (pn_len: packet_number_length_t) 16 | : Tot (parser parse_packet_number_kind (packet_number_t' last pn_len)) 17 | 18 | inline_for_extraction 19 | let parse_packet_number_kind' 20 | (sz: packet_number_length_t) 21 | : GTot parser_kind 22 | = total_constant_size_parser_kind (Secret.v sz) 23 | 24 | (* we cannot use this as the actual parser kind, because it is ghost, 25 | relying on the actual value of pn_len. So we work around: *) 26 | 27 | val parse_packet_number_kind'_correct 28 | (last: last_packet_number_t) 29 | (pn_len: packet_number_length_t) 30 | : Lemma 31 | (parser_kind_prop (parse_packet_number_kind' pn_len) (parse_packet_number last pn_len)) 32 | 33 | val serialize_packet_number 34 | (last: last_packet_number_t) 35 | (pn_len: packet_number_length_t) 36 | : Tot (serializer (parse_packet_number last pn_len)) 37 | 38 | val serialize_packet_number_ext 39 | (last1 last2: last_packet_number_t) 40 | (pn_len: packet_number_length_t) 41 | (pn: packet_number_t) 42 | : Lemma 43 | (requires ( 44 | in_window (Secret.v pn_len - 1) (Secret.v last1) (Secret.v pn) /\ 45 | in_window (Secret.v pn_len - 1) (Secret.v last2) (Secret.v pn) 46 | )) 47 | (ensures ( 48 | serialize (serialize_packet_number last1 pn_len) pn == serialize (serialize_packet_number last2 pn_len) pn 49 | )) 50 | -------------------------------------------------------------------------------- /src/QUIC.Secret.Buffer.fst: -------------------------------------------------------------------------------- 1 | module QUIC.Secret.Buffer 2 | 3 | friend Lib.IntTypes 4 | 5 | module Secret = QUIC.Secret.Int 6 | module B = LowStar.Buffer 7 | module U8 = FStar.UInt8 8 | module HS = FStar.HyperStack 9 | module HST = FStar.HyperStack.ST 10 | module Seq = QUIC.Secret.Seq 11 | module Ghost = FStar.Ghost 12 | 13 | #set-options "--z3rlimit 64" // --query_stats" 14 | 15 | #restart-solver 16 | 17 | let seq_hide_eq 18 | (#t: Secret.inttype { Secret.unsigned t }) 19 | (x: Seq.seq (Secret.uint_t t Secret.PUB)) 20 | : Lemma 21 | (Seq.seq_hide x `Seq.equal` x) 22 | [SMTPat (Seq.seq_hide x)] 23 | = () 24 | 25 | let seq_reveal_eq 26 | (#t: Secret.inttype { Secret.unsigned t }) 27 | (#sec: Secret.secrecy_level) 28 | (x: Seq.seq (Secret.uint_t t sec)) 29 | : Lemma 30 | (Seq.seq_reveal x `Seq.equal` x) 31 | [SMTPat (Seq.seq_reveal x)] 32 | = () 33 | 34 | let with_buffer_hide #t b from to h0 lin lout x1 x2 x3 x4 x5 x6 post f = 35 | let bl = B.sub b 0ul from in 36 | let bs = B.sub b from (to `U32.sub` from) in 37 | let br = B.offset b to in 38 | f (Ghost.hide (B.loc_buffer b)) bl bs br 39 | 40 | let with_buffer_hide_from #t b from h0 lin lout x1 x2 x3 x4 post f = 41 | let bl = B.sub b 0ul from in 42 | let bs = B.offset b from in 43 | f (Ghost.hide (B.loc_buffer b)) bl bs 44 | 45 | let load64_be 46 | b 47 | = 48 | LowStar.Endianness.load64_be b 49 | 50 | let load32_be 51 | b 52 | = 53 | LowStar.Endianness.load32_be b 54 | 55 | let load32_le 56 | b 57 | = 58 | LowStar.Endianness.load32_le b 59 | 60 | let store64_be 61 | b z 62 | = LowStar.Endianness.store64_be b z 63 | 64 | let store32_be 65 | b z 66 | = LowStar.Endianness.store32_be b z 67 | 68 | let store32_le 69 | b z 70 | = LowStar.Endianness.store32_le b z 71 | -------------------------------------------------------------------------------- /src/QUIC.Impl.VarInt.fsti: -------------------------------------------------------------------------------- 1 | module QUIC.Impl.VarInt 2 | include QUIC.Spec.VarInt 3 | include QUIC.Impl.Base 4 | 5 | module Cast = FStar.Int.Cast 6 | module U64 = FStar.UInt64 7 | module LP = LowParse.Spec.BoundedInt // for bounded_int32 8 | module LL = LowParse.Low.Base 9 | module U62 = QUIC.UInt62 10 | 11 | val validate_varint: LL.validator parse_varint 12 | 13 | val read_varint: LL.leaf_reader parse_varint 14 | 15 | val jump_varint: LL.jumper parse_varint 16 | 17 | val write_varint: LL.serializer32 serialize_varint 18 | 19 | module U32 = FStar.UInt32 20 | 21 | val validate_bounded_varint 22 | (min: U32.t) 23 | (max: U32.t { U32.v min <= U32.v max }) 24 | : Tot (LL.validator (parse_bounded_varint (U32.v min) (U32.v max))) 25 | 26 | inline_for_extraction 27 | noextract 28 | val read_bounded_varint 29 | (min: nat) 30 | (max: nat { min <= max /\ max < 4294967296 }) 31 | : Tot (LL.leaf_reader (parse_bounded_varint min max)) 32 | 33 | inline_for_extraction 34 | noextract 35 | val jump_bounded_varint 36 | (min: nat) 37 | (max: nat { min <= max /\ max < 4294967296 }) 38 | : Tot (LL.jumper (parse_bounded_varint min max)) 39 | 40 | inline_for_extraction 41 | noextract 42 | val write_bounded_varint 43 | (min: nat) 44 | (max: nat { min <= max /\ max < 4294967296 }) 45 | : Tot (LL.serializer32 (serialize_bounded_varint min max)) 46 | 47 | val varint_len_correct 48 | (x: U62.t) 49 | : Lemma 50 | (U32.v (varint_len x) == FStar.Seq.length (LP.serialize QUIC.Spec.VarInt.serialize_varint x)) 51 | 52 | val bounded_varint_len_correct 53 | (min: nat) 54 | (max: nat { min <= max /\ max < 4294967296 }) 55 | (x: LP.bounded_int32 min max) 56 | : Lemma 57 | (U32.v (varint_len (Cast.uint32_to_uint64 x)) == FStar.Seq.length (LP.serialize (QUIC.Spec.VarInt.serialize_bounded_varint min max) x)) 58 | -------------------------------------------------------------------------------- /.docker/build/windows-nt/Dockerfile: -------------------------------------------------------------------------------- 1 | # EverQUIC-Crypto build container 2 | 3 | # Define on fstar-version.json what FStar base container image 4 | # mitls build should use. 5 | # By default it always look for the latest FStar container available 6 | # In case you would like to reference a specific commit, 7 | # replace latest with the commit id from github using 12 characters. 8 | ARG COMMITID 9 | FROM hacl-star-windows-nt:${COMMITID} 10 | 11 | ARG BUILDLOGFILE 12 | ARG MAXTHREADS 13 | ARG BUILDTARGET 14 | ARG BRANCHNAME 15 | 16 | # Add ssh key 17 | # We cannot copy directly to the .ssh folder, instead we copy to a temp folder 18 | WORKDIR "everestsshkey" 19 | COPY id_rsa . 20 | WORKDIR ".." 21 | 22 | # Now, using bash we copy the file, set the correct security and remove the previous folder 23 | RUN Invoke-BashCmd '"cd .ssh && cp ../everestsshkey/id_rsa . && chmod 600 id_rsa && rm -rf ../everestsshkey"' 24 | 25 | # Copy source files 26 | WORKDIR "everquic-crypto" 27 | COPY / . 28 | WORKDIR ".." 29 | 30 | # Do some cleanup 31 | RUN Invoke-BashCmd rm -f build.sh 32 | RUN Invoke-BashCmd rm -f build_helper.sh 33 | RUN Invoke-BashCmd rm -f buildlogfile.txt 34 | RUN Invoke-BashCmd rm -f log_no_replay.html 35 | RUN Invoke-BashCmd rm -f log_worst.html 36 | RUN Invoke-BashCmd rm -f orange_status.txt 37 | RUN Invoke-BashCmd rm -f result.txt 38 | RUN Invoke-BashCmd rm -f status.txt 39 | RUN Invoke-BashCmd rm -f commitinfofilename.json 40 | 41 | RUN Invoke-BashCmd rm everquic-crypto/Dockerfile 42 | RUN Invoke-BashCmd rm everquic-crypto/build.sh 43 | RUN Invoke-BashCmd rm everquic-crypto/build_helper.sh 44 | RUN Invoke-BashCmd rm everquic-crypto/id_rsa 45 | RUN Invoke-BashCmd rm everquic-crypto/commitinfofilename.json 46 | 47 | COPY build.sh build.sh 48 | COPY build_helper.sh build_helper.sh 49 | 50 | RUN Invoke-BashCmd ./build_helper.sh $Env:BUILDTARGET $Env:BUILDLOGFILE $Env:MAXTHREADS $Env:BRANCHNAME '||' true 51 | 52 | # Remove ssh key. 53 | RUN Invoke-BashCmd rm .ssh/id_rsa 54 | -------------------------------------------------------------------------------- /hints/QUIC.Spec.PacketNumber.fsti.hints: -------------------------------------------------------------------------------- 1 | [ 2 | "5e58f9e52aedd3d7ef884fcd214cb610", 3 | [ 4 | [ 5 | "QUIC.Spec.PacketNumber.parse_packet_number_kind'", 6 | 1, 7 | 2, 8 | 1, 9 | [ 10 | "@MaxIFuel_assumption", "@query", 11 | "equation_QUIC.Spec.PacketNumber.Base.packet_number_length_t", 12 | "projection_inverse_BoxInt_proj_0", 13 | "refinement_interpretation_Tm_refine_1622082edcbeee4d7aa5d33c2647f14f" 14 | ], 15 | 0, 16 | "aff42e3e42b95cd569819f6fbc7e63aa" 17 | ], 18 | [ 19 | "QUIC.Spec.PacketNumber.serialize_packet_number_ext", 20 | 1, 21 | 2, 22 | 1, 23 | [ 24 | "@MaxIFuel_assumption", "@query", 25 | "constructor_distinct_Lib.IntTypes.U64", 26 | "equality_tok_Lib.IntTypes.SEC@tok", 27 | "equality_tok_Lib.IntTypes.U32@tok", 28 | "equality_tok_Lib.IntTypes.U64@tok", "equation_Lib.IntTypes.minint", 29 | "equation_Lib.IntTypes.range", "equation_Lib.IntTypes.unsigned", 30 | "equation_Lib.IntTypes.v", 31 | "equation_QUIC.Spec.PacketNumber.Base.last_packet_number_t", 32 | "equation_QUIC.Spec.PacketNumber.Base.packet_number_length_t", 33 | "equation_QUIC.Spec.PacketNumber.Base.packet_number_t", 34 | "equation_QUIC.UInt62.secret", "primitive_Prims.op_Subtraction", 35 | "projection_inverse_BoxInt_proj_0", 36 | "refinement_interpretation_Tm_refine_1622082edcbeee4d7aa5d33c2647f14f", 37 | "refinement_interpretation_Tm_refine_83845a86f2550cdf941eeb1d9b59602b", 38 | "refinement_interpretation_Tm_refine_9c5111a8a1b8b4814eee52e4b652d66d", 39 | "refinement_interpretation_Tm_refine_bc091439e537dad49a811907a6d15e1b", 40 | "refinement_interpretation_Tm_refine_cfb1e053a2878b8fbd187297e44bc30d", 41 | "typing_Lib.IntTypes.v", "typing_tok_Lib.IntTypes.SEC@tok", 42 | "typing_tok_Lib.IntTypes.U64@tok" 43 | ], 44 | 0, 45 | "2f5b4b81022cb66635080350fa530f1a" 46 | ] 47 | ] 48 | ] -------------------------------------------------------------------------------- /src/Model.Indexing.fsti: -------------------------------------------------------------------------------- 1 | module Model.Indexing 2 | 3 | (* 4 | This module provides the functions that the QUIC 5 | record layer security model expect to be provided 6 | by the TLS handshake security model. In particular, 7 | it assumes that the indexes contain the history of 8 | the derivation of each key, including the implicit 9 | authentication of algorithms to use. 10 | *) 11 | 12 | open Mem 13 | include Model.Flags 14 | 15 | module C = Spec.Agile.Cipher 16 | module AE = Spec.Agile.AEAD 17 | module HD = Spec.Hash.Definitions 18 | module G = FStar.Ghost 19 | 20 | let is_supported_hash = function 21 | | HD.SHA1 | HD.SHA2_256 | HD.SHA2_384 | HD.SHA2_512 -> true 22 | | _ -> false 23 | 24 | let is_supported_aead = function 25 | | AE.AES128_GCM | AE.AES256_GCM | AE.CHACHA20_POLY1305 -> true 26 | | _ -> false 27 | 28 | let is_supported_cipher = function 29 | | C.AES128 | C.AES256 | C.CHACHA20 -> true 30 | | _ -> false 31 | 32 | type ha = a:HD.hash_alg{is_supported_hash a} 33 | type ea = a:AE.alg{is_supported_aead a} 34 | type ca = a:C.cipher_alg{is_supported_cipher a} 35 | 36 | let cipher_of_aead (a:ea) = 37 | match a with 38 | | AE.AES128_GCM -> C.AES128 39 | | AE.AES256_GCM -> C.AES256 40 | | AE.CHACHA20_POLY1305 -> C.CHACHA20 41 | 42 | val id: eqtype 43 | inline_for_extraction 44 | val is_honest: id -> bool 45 | 46 | val id_ginfo: i:id -> GTot (ha * ea * ca) 47 | val id_info: i:id{model} -> a:(ha * ea * ca){a == id_ginfo i} 48 | 49 | val ae_id: eqtype 50 | inline_for_extraction 51 | val is_ae_honest: ae_id -> bool 52 | 53 | val ae_id_ginfo: i:ae_id -> GTot ea 54 | val ae_id_info: i:ae_id{model} -> a:ea{a == ae_id_ginfo i} 55 | val ae_id_ghash: i:ae_id -> GTot ha 56 | val ae_id_hash: i:ae_id{model} -> a:ha{a == ae_id_ghash i} 57 | 58 | val pne_id: eqtype 59 | inline_for_extraction 60 | val is_pne_honest: pne_id -> bool 61 | 62 | val pne_id_ginfo: i:pne_id -> GTot ca 63 | val pne_id_info: i:pne_id{model} -> a:ca{a == pne_id_ginfo i} 64 | val pne_id_ghash: i:pne_id -> GTot ha 65 | val pne_id_hash: i:pne_id{model} -> a:ha{a == pne_id_ghash i} 66 | 67 | -------------------------------------------------------------------------------- /src/QUIC.Spec.Crypto.fst: -------------------------------------------------------------------------------- 1 | module QUIC.Spec.Crypto 2 | 3 | module U8 = FStar.UInt8 4 | module Seq = QUIC.Secret.Seq 5 | module HKDF = Spec.Agile.HKDF 6 | 7 | inline_for_extraction 8 | noextract 9 | let prefix_l: List.Tot.llist U8.t 11 = 10 | // : "tls13 quic " 11 | [@inline_let] 12 | let l = [0x74uy; 0x6cuy; 0x73uy; 0x31uy; 0x33uy; 13 | 0x20uy; 0x71uy; 0x75uy; 0x69uy; 0x63uy; 0x20uy] in 14 | assert_norm (List.Tot.length l == 11); 15 | l 16 | 17 | noextract 18 | let prefix: lbytes 11 = 19 | Seq.seq_of_list prefix_l 20 | 21 | #push-options "--z3rlimit 10" 22 | let lemma_hash_lengths (a:ha) 23 | : Lemma (HD.hash_length a <= 64 /\ HD.word_length a <= 8 /\ 24 | HD.block_length a <= 128 /\ 25 | (if Some? (HD.max_input_length a) then Some?.v (HD.max_input_length a) >= pow2 61 - 1 else True)) 26 | = 27 | assert_norm(pow2 61 < pow2 125) 28 | #pop-options 29 | 30 | inline_for_extraction 31 | noextract 32 | let label_key_l: List.Tot.llist U8.t 3 = 33 | [@inline_let] 34 | let l = [ 0x6buy; 0x65uy; 0x79uy ] in 35 | assert_norm (List.Tot.length l = 3); 36 | l 37 | 38 | let label_key = 39 | Seq.seq_of_list label_key_l 40 | 41 | inline_for_extraction 42 | noextract 43 | let label_iv_l: List.Tot.llist U8.t 2 = 44 | [@inline_let] 45 | let l = [ 0x69uy; 0x76uy ] in 46 | assert_norm (List.Tot.length l = 2); 47 | l 48 | 49 | let label_iv = 50 | Seq.seq_of_list label_iv_l 51 | 52 | inline_for_extraction 53 | noextract 54 | let label_hp_l: List.Tot.llist U8.t 2 = 55 | [@inline_let] 56 | let l = [ 0x68uy; 0x70uy ] in 57 | assert_norm (List.Tot.length l = 2); 58 | l 59 | 60 | let label_hp = 61 | Seq.seq_of_list label_hp_l 62 | 63 | let derive_secret a prk label len = 64 | let open Seq in 65 | let z = Seq.create 1 0uy in 66 | let lb = Seq.create 1 (U8.uint_to_t len) in // len <= 255 67 | let llen = Seq.create 1 (U8.uint_to_t (11 + Seq.length label)) in 68 | let info = z @| lb @| llen @| prefix @| label @| z in 69 | lemma_hash_lengths a; 70 | assert_norm(452 < pow2 61); 71 | HKDF.expand a prk (Seq.seq_hide info) len 72 | -------------------------------------------------------------------------------- /src/QUIC.Secret.Seq.fst: -------------------------------------------------------------------------------- 1 | module QUIC.Secret.Seq 2 | open FStar.Seq 3 | 4 | module Secret = QUIC.Secret.Int 5 | module U8 = FStar.UInt8 6 | module Ghost = FStar.Ghost 7 | 8 | (* NOTE: abstraction is NOT broken here *) 9 | 10 | noextract 11 | let rec seq_map 12 | (#t1 #t2: Type) 13 | (f: (t1 -> Tot t2)) 14 | (x: seq t1) 15 | : Tot (lseq t2 (length x)) 16 | (decreases (length x)) 17 | = if length x = 0 18 | then empty 19 | else cons (f (head x)) (seq_map f (tail x)) 20 | 21 | let rec seq_map_index 22 | (#t1 #t2: Type) 23 | (f: (t1 -> Tot t2)) 24 | (x: seq t1) 25 | (i: nat { i < length x }) 26 | : Lemma 27 | (ensures (index (seq_map f x) i == f (index x i))) 28 | (decreases (length x)) 29 | [SMTPat (index (seq_map f x) i)] 30 | = if i = 0 31 | then () 32 | else seq_map_index f (tail x) (i - 1) 33 | 34 | let seq_hide 35 | #t x 36 | = seq_map (Secret.cast t Secret.SEC) x 37 | 38 | let seq_hide_length 39 | #t x 40 | = () 41 | 42 | #push-options "--z3rlimit 32" 43 | 44 | let seq_hide_index 45 | #t x i 46 | = () 47 | 48 | #pop-options 49 | 50 | noextract 51 | let rec seq_gmap 52 | (#t1 #t2: Type) 53 | (f: (t1 -> GTot t2)) 54 | (x: seq t1) 55 | : GTot (lseq t2 (length x)) 56 | (decreases (length x)) 57 | = if length x = 0 58 | then empty 59 | else cons (f (head x)) (seq_gmap f (tail x)) 60 | 61 | let rec seq_gmap_index 62 | (#t1 #t2: Type) 63 | (f: (t1 -> GTot t2)) 64 | (x: seq t1) 65 | (i: nat { i < length x }) 66 | : Lemma 67 | (ensures (index (seq_gmap f x) i == f (index x i))) 68 | (decreases (length x)) 69 | [SMTPat (index (seq_gmap f x) i)] 70 | = if i = 0 71 | then () 72 | else seq_gmap_index f (tail x) (i - 1) 73 | 74 | let uint_reveal 75 | (t: Secret.inttype { Secret.unsigned t }) 76 | (sec_from sec_to: Secret.secrecy_level) 77 | (x: Secret.uint_t t sec_from) 78 | : GTot (Secret.uint_t t sec_to) 79 | = Secret.mk_int #t (Secret.v x) 80 | 81 | let seq_reveal 82 | #t #sec x 83 | = seq_gmap (uint_reveal t sec Secret.PUB) x 84 | 85 | let seq_reveal_length 86 | #t #sec x 87 | = () 88 | 89 | let seq_reveal_index 90 | #t #sec x i 91 | = () 92 | -------------------------------------------------------------------------------- /dist/EverQuic_EverCrypt.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef __EverQuic_EverCrypt_H 4 | #define __EverQuic_EverCrypt_H 5 | 6 | #include "krml/internal/target.h" 7 | #include "krml/internal/types.h" 8 | #include "krml/lowstar_endianness.h" 9 | #include 10 | #include 11 | #include 12 | 13 | #define Spec_Hash_Definitions_SHA2_224 0 14 | #define Spec_Hash_Definitions_SHA2_256 1 15 | #define Spec_Hash_Definitions_SHA2_384 2 16 | #define Spec_Hash_Definitions_SHA2_512 3 17 | #define Spec_Hash_Definitions_SHA1 4 18 | #define Spec_Hash_Definitions_MD5 5 19 | #define Spec_Hash_Definitions_Blake2S 6 20 | #define Spec_Hash_Definitions_Blake2B 7 21 | #define Spec_Hash_Definitions_SHA3_256 8 22 | #define Spec_Hash_Definitions_SHA3_224 9 23 | #define Spec_Hash_Definitions_SHA3_384 10 24 | #define Spec_Hash_Definitions_SHA3_512 11 25 | #define Spec_Hash_Definitions_Shake128 12 26 | #define Spec_Hash_Definitions_Shake256 13 27 | 28 | typedef uint8_t Spec_Hash_Definitions_hash_alg; 29 | 30 | typedef struct Prims_list__uint8_t_s Prims_list__uint8_t; 31 | 32 | #define Prims_Nil 0 33 | #define Prims_Cons 1 34 | 35 | typedef uint8_t Prims_list__uint8_t_tags; 36 | 37 | typedef struct Prims_list__uint8_t_s 38 | { 39 | Prims_list__uint8_t_tags tag; 40 | uint8_t hd; 41 | Prims_list__uint8_t *tl; 42 | } 43 | Prims_list__uint8_t; 44 | 45 | #define Spec_Agile_AEAD_AES128_GCM 0 46 | #define Spec_Agile_AEAD_AES256_GCM 1 47 | #define Spec_Agile_AEAD_CHACHA20_POLY1305 2 48 | #define Spec_Agile_AEAD_AES128_CCM 3 49 | #define Spec_Agile_AEAD_AES256_CCM 4 50 | #define Spec_Agile_AEAD_AES128_CCM8 5 51 | #define Spec_Agile_AEAD_AES256_CCM8 6 52 | 53 | typedef uint8_t Spec_Agile_AEAD_alg; 54 | 55 | #define EverCrypt_Error_Success 0 56 | #define EverCrypt_Error_UnsupportedAlgorithm 1 57 | #define EverCrypt_Error_InvalidKey 2 58 | #define EverCrypt_Error_AuthenticationFailure 3 59 | #define EverCrypt_Error_InvalidIVLength 4 60 | #define EverCrypt_Error_DecodeError 5 61 | #define EverCrypt_Error_MaximumLengthExceeded 6 62 | 63 | typedef uint8_t EverCrypt_Error_error_code; 64 | 65 | 66 | #define __EverQuic_EverCrypt_H_DEFINED 67 | #endif 68 | -------------------------------------------------------------------------------- /.docker/build/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #set -x 4 | 5 | target=$1 6 | out_file=$2 7 | threads=$3 8 | branchname=$4 9 | 10 | function export_home() { 11 | if command -v cygpath >/dev/null 2>&1; then 12 | export $1_HOME=$(cygpath -m "$2") 13 | else 14 | export $1_HOME="$2" 15 | fi 16 | } 17 | 18 | function raise () { 19 | return $1 20 | } 21 | 22 | function fetch_everparse() { 23 | if [ ! -d everparse ]; then 24 | git clone https://github.com/project-everest/everparse everparse 25 | fi 26 | 27 | cd everparse 28 | git fetch origin 29 | local ref=$(jq -c -r '.RepoVersions["everparse_version"]' "$rootPath/.docker/build/config.json" ) 30 | if [[ $ref == "" || $ref == "null" ]]; then 31 | echo "Unable to find RepoVersions.everparse_version on $rootPath/.docker/build/config.json" 32 | return -1 33 | fi 34 | 35 | echo Switching to EverParse $ref 36 | git reset --hard $ref 37 | cd .. 38 | export_home EVERPARSE "$(pwd)/everparse" 39 | } 40 | 41 | function fetch_and_make_everparse() { 42 | fetch_everparse 43 | 44 | # Default build target is quackyducky lowparse, unless specified otherwise 45 | local target 46 | if [[ $1 == "" ]]; then 47 | target="quackyducky lowparse" 48 | else 49 | target="$1" 50 | fi 51 | 52 | OTHERFLAGS='--admit_smt_queries true' make -C everparse -j $threads $target 53 | } 54 | 55 | function exec_build() { 56 | 57 | result_file="../result.txt" 58 | local status_file="../status.txt" 59 | echo -n false >$status_file 60 | 61 | fetch_and_make_everparse && 62 | make -j $threads -k && 63 | { echo -n true >$status_file ; } 64 | 65 | if [[ $(cat $status_file) != "true" ]]; then 66 | echo "Build failed" 67 | echo Failure >$result_file 68 | else 69 | echo "Build succeeded" 70 | echo Success >$result_file 71 | fi 72 | } 73 | 74 | # Some environment variables we want 75 | export OCAMLRUNPARAM=b 76 | export OTHERFLAGS="--print_z3_statistics --query_stats" 77 | export MAKEFLAGS="$MAKEFLAGS -Otarget" 78 | 79 | cd everquic-crypto 80 | rootPath=$(pwd) 81 | exec_build 82 | cd .. 83 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # This Dockerfile is intended for the end user. 2 | # Our CI system is using another one in .docker/build 3 | 4 | FROM ubuntu:focal 5 | 6 | # Install the dependencies of Project Everest 7 | RUN apt-get update 8 | RUN apt-get --yes --no-install-recommends install software-properties-common dirmngr gpg-agent 9 | RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF 10 | RUN echo "deb https://download.mono-project.com/repo/ubuntu stable-focal main" | tee /etc/apt/sources.list.d/mono-official-stable.list 11 | RUN apt-get update 12 | RUN apt-get --yes install --no-install-recommends opam emacs gcc binutils make m4 git time gnupg ca-certificates mono-devel sudo 13 | 14 | # Create a new user and give them sudo rights 15 | RUN useradd -d /home/test test 16 | RUN echo 'test ALL=NOPASSWD: ALL' >> /etc/sudoers 17 | RUN mkdir /home/test 18 | RUN chown test:test /home/test 19 | USER test 20 | ENV HOME /home/test 21 | WORKDIR $HOME 22 | 23 | SHELL ["/bin/bash", "--login", "-c"] 24 | 25 | # Install OCaml 26 | ENV OPAMYES 1 27 | RUN opam init --disable-sandboxing --compiler=4.09.1 28 | RUN opam env --set-switch | tee --append .profile .bashrc .bash_profile 29 | 30 | # Install emacs F* mode 31 | ADD --chown=test package/fstar.sh bin/fstar.sh 32 | ADD --chown=test package/init.el .emacs.d/init.el 33 | ADD --chown=test package/install-fstar-mode.el .emacs.d/install-fstar-mode.el 34 | RUN emacs --script .emacs.d/install-fstar-mode.el 35 | 36 | # Add the project files proper 37 | RUN mkdir quic-crypto 38 | WORKDIR quic-crypto 39 | ADD --chown=test src/*.fst src/*.fsti src/Makefile src/ 40 | ADD --chown=test hints/*.hints hints/ 41 | ADD --chown=test Makefile Makefile 42 | ADD --chown=test Makefile.include Makefile.include 43 | ADD --chown=test README.md README.md 44 | ADD --chown=test test/main.c test/QUICTest.fst test/Makefile test/ 45 | ADD --chown=test noheader.txt noheader.txt 46 | ADD --chown=test install-everest.sh install-everest.sh 47 | 48 | # Clone and build Project Everest 49 | ARG EVEREST_THREADS=1 50 | RUN ./install-everest.sh 51 | RUN cat everest-env.sh | tee --append $HOME/.profile $HOME/.bashrc $HOME/.bash_profile 52 | 53 | ENTRYPOINT ["/bin/bash", "--login"] 54 | -------------------------------------------------------------------------------- /src/Model.Helpers.fsti: -------------------------------------------------------------------------------- 1 | module Model.Helpers 2 | 3 | let lbytes (l:nat) = b:Seq.seq Lib.IntTypes.uint8 { Seq.length b = l } 4 | 5 | let hide (b:Seq.seq UInt8.t) : lbytes (Seq.length b) = 6 | Seq.init (Seq.length b) (fun i -> Lib.RawIntTypes.u8_from_UInt8 (Seq.index b i)) 7 | 8 | let hide_eq (b:Seq.seq UInt8.t) : Lemma 9 | (ensures hide b == QUIC.Secret.Seq.seq_hide #Lib.IntTypes.U8 b) 10 | [ SMTPat (QUIC.Secret.Seq.seq_hide #Lib.IntTypes.U8 b) ] 11 | = 12 | assert (hide b `Seq.equal` QUIC.Secret.Seq.seq_hide b) 13 | 14 | let reveal #l (b:lbytes l) : (QUIC.Spec.lbytes l) = 15 | Seq.init l (fun i -> Lib.RawIntTypes.u8_to_UInt8 (Seq.index b i)) 16 | 17 | let reveal_eq (b:Seq.seq Lib.IntTypes.uint8): Lemma 18 | (ensures reveal #(Seq.length b) b == QUIC.Secret.Seq.seq_reveal b) 19 | [ SMTPat (QUIC.Secret.Seq.seq_reveal b) ] 20 | = 21 | assert (reveal #(Seq.length b) b `Seq.equal` QUIC.Secret.Seq.seq_reveal b) 22 | 23 | 24 | val correct (#l: nat) (b:Seq.seq UInt8.t{Seq.length b = l}) 25 | : Lemma (reveal #l (hide b) == b) 26 | [SMTPat (reveal #l (hide b))] 27 | 28 | val correct2 (#l: nat) (b:lbytes l) 29 | : Lemma (hide (reveal #l b) == b) 30 | [SMTPat (hide (reveal #l b))] 31 | 32 | let random (l: nat { l < pow2 32 }) 33 | : HyperStack.ST.ST (lbytes l) 34 | (requires fun h0 -> True) 35 | (ensures fun h0 _ h1 -> h0 == h1) 36 | = 37 | let open Lib.RandomSequence in 38 | snd (crypto_random entropy0 l) 39 | 40 | let rec lbytes_eq (x y: Seq.seq Lib.IntTypes.uint8): Tot (b:bool { b <==> x `Seq.equal` y }) (decreases (Seq.length x)) = 41 | if Seq.length x = 0 && Seq.length y = 0 then 42 | true 43 | else if Seq.length x = 0 && Seq.length y <> 0 then 44 | false 45 | else if Seq.length x <> 0 && Seq.length y = 0 then 46 | false 47 | else 48 | let hx = Seq.head x in 49 | let hy = Seq.head y in 50 | let tx = Seq.tail x in 51 | let ty = Seq.tail y in 52 | if Lib.RawIntTypes.u8_to_UInt8 hx = Lib.RawIntTypes.u8_to_UInt8 hy && lbytes_eq tx ty then begin 53 | assert (x `Seq.equal` Seq.append (Seq.create 1 hx) tx); 54 | assert (y `Seq.equal` Seq.append (Seq.create 1 hy) ty); 55 | assert (Seq.index (Seq.create 1 hx) 0 == Seq.index (Seq.create 1 hy) 0); 56 | assert (Seq.create 1 hx `Seq.equal` Seq.create 1 hy); 57 | true 58 | end else 59 | false 60 | -------------------------------------------------------------------------------- /src/QUIC.Impl.Crypto.fsti: -------------------------------------------------------------------------------- 1 | module QUIC.Impl.Crypto 2 | include QUIC.Spec.Crypto 3 | 4 | open EverCrypt.Error 5 | 6 | module B = LowStar.Buffer 7 | module HS = FStar.HyperStack 8 | module S = FStar.Seq 9 | module PN = QUIC.Spec.PacketNumber.Base 10 | module HST = FStar.HyperStack.ST 11 | module Secret = QUIC.Secret.Int 12 | module G = FStar.Ghost 13 | module U8 = FStar.UInt8 14 | module IB = LowStar.ImmutableBuffer 15 | module Spec = QUIC.Spec.Crypto 16 | 17 | 18 | 19 | /// Globals 20 | /// ------- 21 | 22 | val label_key : (label_key: IB.ibuffer U8.t { 23 | IB.frameOf label_key == HS.root /\ 24 | IB.length label_key == Seq.length Spec.label_key /\ 25 | IB.recallable label_key /\ 26 | IB.witnessed label_key (IB.cpred Spec.label_key) 27 | }) 28 | 29 | val label_iv : (label_iv : IB.ibuffer U8.t { 30 | IB.frameOf label_key == HS.root /\ 31 | IB.length label_iv == Seq.length Spec.label_iv /\ 32 | IB.recallable label_iv /\ 33 | IB.witnessed label_iv (IB.cpred Spec.label_iv) 34 | }) 35 | 36 | val label_hp : (label_hp : IB.ibuffer U8.t { 37 | IB.frameOf label_hp == HS.root /\ 38 | IB.length label_hp == Seq.length Spec.label_hp /\ 39 | IB.recallable label_hp /\ 40 | IB.witnessed label_hp (IB.cpred Spec.label_hp) 41 | }) 42 | 43 | /// Actual code 44 | /// ----------- 45 | 46 | #push-options "--max_ifuel 1 --initial_ifuel 1 --z3rlimit 10" 47 | /// One ifuel for inverting on the hash algorithm for computing bounds (the 48 | /// various calls to assert_norm should help ensure this proof goes through 49 | /// reliably). Note that I'm breaking from the usual convention where lengths 50 | /// are UInt32's, mostly to avoid trouble reasoning with modulo when casting 51 | /// from UInt32 to UInt8 to write the label for the key derivation. This could 52 | /// be fixed later. 53 | val derive_secret: a: ha -> 54 | dst:B.buffer Secret.uint8 -> 55 | dst_len: U8.t { B.length dst = U8.v dst_len /\ U8.v dst_len <= 255 } -> 56 | secret:B.buffer Secret.uint8 { B.length secret = Spec.Hash.Definitions.hash_length a } -> 57 | label:IB.ibuffer U8.t -> 58 | label_len:U8.t { IB.length label = U8.v label_len /\ U8.v label_len <= 244 } -> 59 | HST.Stack unit 60 | (requires fun h0 -> 61 | B.(all_live h0 [ buf secret; buf label; buf dst ]) /\ 62 | B.disjoint dst secret) 63 | (ensures fun h0 _ h1 -> 64 | assert_norm (255 < pow2 61); 65 | assert_norm (pow2 61 < pow2 125); 66 | B.(modifies (loc_buffer dst) h0 h1) /\ 67 | B.as_seq h1 dst == derive_secret a (B.as_seq h0 secret) 68 | (IB.as_seq h0 label) (U8.v dst_len)) 69 | #pop-options 70 | -------------------------------------------------------------------------------- /hints/QUIC.Spec.PacketNumber.Base.fst.hints: -------------------------------------------------------------------------------- 1 | [ 2 | "f72943b503531231acb09de391e530d8", 3 | [ 4 | [ 5 | "QUIC.Spec.PacketNumber.Base.bound_npn'", 6 | 1, 7 | 2, 8 | 1, 9 | [ 10 | "@MaxIFuel_assumption", "@query", "equation_Prims.nat", 11 | "int_inversion", "primitive_Prims.op_Addition", 12 | "primitive_Prims.op_Multiply", "projection_inverse_BoxInt_proj_0", 13 | "refinement_interpretation_Tm_refine_542f9d4f129664613f2483a6c88bc7c2", 14 | "refinement_interpretation_Tm_refine_7acf795d50ec256996534a97e12bfa61" 15 | ], 16 | 0, 17 | "6c2406e181292b016f109b21a99cd5bc" 18 | ], 19 | [ 20 | "QUIC.Spec.PacketNumber.Base.in_window", 21 | 1, 22 | 2, 23 | 1, 24 | [ 25 | "@MaxIFuel_assumption", "@query", "equation_Prims.nat", 26 | "primitive_Prims.op_Addition", "primitive_Prims.op_Multiply", 27 | "projection_inverse_BoxInt_proj_0", 28 | "refinement_interpretation_Tm_refine_542f9d4f129664613f2483a6c88bc7c2", 29 | "refinement_interpretation_Tm_refine_7acf795d50ec256996534a97e12bfa61" 30 | ], 31 | 0, 32 | "28058934897598ec4c7747134b5016c7" 33 | ], 34 | [ 35 | "QUIC.Spec.PacketNumber.Base.packet_number_t'", 36 | 1, 37 | 2, 38 | 1, 39 | [ 40 | "@MaxIFuel_assumption", "@query", 41 | "constructor_distinct_Lib.IntTypes.U32", 42 | "constructor_distinct_Lib.IntTypes.U64", 43 | "equality_tok_Lib.IntTypes.SEC@tok", 44 | "equality_tok_Lib.IntTypes.U64@tok", "equation_Lib.IntTypes.minint", 45 | "equation_Lib.IntTypes.range", "equation_Lib.IntTypes.unsigned", 46 | "equation_Lib.IntTypes.v", 47 | "equation_QUIC.Spec.PacketNumber.Base.last_packet_number_t", 48 | "equation_QUIC.Spec.PacketNumber.Base.packet_number_length_t", 49 | "equation_QUIC.Spec.PacketNumber.Base.packet_number_t", 50 | "equation_QUIC.UInt62.secret", "primitive_Prims.op_Subtraction", 51 | "projection_inverse_BoxInt_proj_0", 52 | "refinement_interpretation_Tm_refine_1622082edcbeee4d7aa5d33c2647f14f", 53 | "refinement_interpretation_Tm_refine_83845a86f2550cdf941eeb1d9b59602b", 54 | "refinement_interpretation_Tm_refine_bc091439e537dad49a811907a6d15e1b", 55 | "refinement_interpretation_Tm_refine_cfb1e053a2878b8fbd187297e44bc30d", 56 | "typing_Lib.IntTypes.v", "typing_tok_Lib.IntTypes.SEC@tok", 57 | "typing_tok_Lib.IntTypes.U64@tok" 58 | ], 59 | 0, 60 | "55a46723399d6d9d0b6aa04717ac666d" 61 | ] 62 | ] 63 | ] -------------------------------------------------------------------------------- /hints/QUIC.Impl.PacketNumber.fsti.hints: -------------------------------------------------------------------------------- 1 | [ 2 | "df4a6cdc13b6bf6741d6a35918dcc6ae", 3 | [ 4 | [ 5 | "QUIC.Impl.PacketNumber.read_packet_number", 6 | 1, 7 | 2, 8 | 1, 9 | [ 10 | "@MaxIFuel_assumption", "@query", 11 | "disc_equation_FStar.Pervasives.Native.None", 12 | "disc_equation_FStar.Pervasives.Native.Some", 13 | "fuel_guarded_inversion_FStar.Pervasives.Native.option", 14 | "projection_inverse_BoxBool_proj_0" 15 | ], 16 | 0, 17 | "d1edee93dd950381b51a75d253a91f80" 18 | ], 19 | [ 20 | "QUIC.Impl.PacketNumber.write_packet_number", 21 | 1, 22 | 2, 23 | 1, 24 | [ 25 | "@MaxIFuel_assumption", "@query", "b2t_def", "bool_inversion", 26 | "constructor_distinct_Lib.IntTypes.U8", 27 | "equality_tok_Lib.IntTypes.U8@tok", 28 | "equation_FStar.Monotonic.HyperHeap.hmap", 29 | "equation_FStar.Monotonic.HyperStack.is_tip", 30 | "equation_FStar.Monotonic.HyperStack.is_wf_with_ctr_and_tip", 31 | "equation_FStar.Monotonic.HyperStack.mem", 32 | "equation_FStar.UInt.fits", "equation_FStar.UInt.max_int", 33 | "equation_FStar.UInt.min_int", "equation_FStar.UInt.size", 34 | "equation_FStar.UInt.uint_t", "equation_Lib.IntTypes.uint8", 35 | "equation_Lib.IntTypes.unsigned", "equation_LowStar.Buffer.buffer", 36 | "equation_LowStar.Buffer.trivial_preorder", 37 | "equation_LowStar.Monotonic.Buffer.length", 38 | "equation_QUIC.Spec.PacketNumber.Base.packet_number_length_t", 39 | "function_token_typing_FStar.Monotonic.Heap.heap", 40 | "function_token_typing_Lib.IntTypes.uint8", 41 | "lemma_FStar.Map.lemma_ContainsDom", "primitive_Prims.op_Addition", 42 | "primitive_Prims.op_AmpAmp", "primitive_Prims.op_LessThanOrEqual", 43 | "projection_inverse_BoxBool_proj_0", 44 | "projection_inverse_BoxInt_proj_0", 45 | "refinement_interpretation_Tm_refine_05e15190c946858f68c69156f585f95a", 46 | "refinement_interpretation_Tm_refine_1622082edcbeee4d7aa5d33c2647f14f", 47 | "refinement_interpretation_Tm_refine_34dcdc053118776a0155a1902c276821", 48 | "refinement_interpretation_Tm_refine_f13070840248fced9d9d60d77bdae3ec", 49 | "typing_FStar.Map.contains", "typing_FStar.Monotonic.HyperHeap.rid", 50 | "typing_FStar.Monotonic.HyperStack.get_hmap", 51 | "typing_FStar.Monotonic.HyperStack.get_tip", "typing_FStar.UInt32.v", 52 | "typing_LowStar.Buffer.trivial_preorder", 53 | "typing_LowStar.Monotonic.Buffer.len" 54 | ], 55 | 0, 56 | "7b8429840d976606b400c180d9a1be0b" 57 | ] 58 | ] 59 | ] -------------------------------------------------------------------------------- /src/QUIC.Spec.Header.fsti: -------------------------------------------------------------------------------- 1 | module QUIC.Spec.Header 2 | include QUIC.Spec.Crypto 3 | include QUIC.Spec.Header.Base 4 | 5 | module Seq = FStar.Seq 6 | module HD = Spec.Hash.Definitions 7 | module AEAD = Spec.Agile.AEAD 8 | module U32 = FStar.UInt32 9 | module U64 = FStar.UInt64 10 | module PN = QUIC.Spec.PacketNumber.Base 11 | module Secret = QUIC.Secret.Int 12 | module AEAD = Spec.Agile.AEAD 13 | module Cipher = Spec.Agile.Cipher 14 | 15 | // Header serialization and protection 16 | 17 | val block_of_sample 18 | (a: Cipher.cipher_alg) 19 | (k: Cipher.key a) 20 | (sample: Seq.lseq Secret.uint8 16) 21 | : GTot (Seq.lseq Secret.uint8 16) 22 | 23 | val pn_sizemask (pn_len: nat { pn_len < 4 }) : Tot (lbytes (pn_len + 1)) 24 | 25 | val header_encrypt: 26 | a:ea -> 27 | hpk: Cipher.key (AEAD.cipher_alg_of_supported_alg a) -> 28 | h: header -> 29 | c: cbytes' (is_retry h) -> 30 | GTot packet 31 | 32 | val header_encrypt_length: 33 | a: ea -> 34 | hpk: Cipher.key (AEAD.cipher_alg_of_supported_alg a) -> 35 | h: header -> 36 | c: cbytes' (is_retry h) -> 37 | Lemma 38 | ( 39 | Seq.length (header_encrypt a hpk h c) == 40 | header_len h + Seq.length c 41 | ) 42 | 43 | noeq 44 | type h_result = 45 | | H_Success: 46 | h: header -> 47 | cipher: bytes { 48 | let len = Seq.length cipher in 49 | if is_retry h 50 | then len == 0 51 | else 16 <= len (* the true bound is 20-pn_len h *) /\ len < max_cipher_length 52 | } -> 53 | rem: bytes -> 54 | h_result 55 | | H_Failure 56 | 57 | // Header protection removal and parsing 58 | 59 | val header_decrypt: 60 | a:ea -> 61 | hpk: Cipher.key (AEAD.cipher_alg_of_supported_alg a) -> 62 | cid_len: nat { cid_len <= 20 } -> 63 | last: nat { last + 1 < pow2 62 } -> 64 | p: packet -> 65 | GTot (r: h_result { match r with 66 | | H_Failure -> True 67 | | H_Success h c rem -> 68 | is_valid_header h cid_len last /\ 69 | Seq.length rem <= Seq.length p /\ 70 | rem `Seq.equal` Seq.slice p (Seq.length p - Seq.length rem) (Seq.length p) 71 | }) 72 | 73 | // This is just functional correctness, but does not guarantee security: 74 | // decryption can succeed on an input that is not the encryption 75 | // of the same arguments (see QUIC.Spec.Old.*_malleable) 76 | val lemma_header_encryption_correct: 77 | a:ea -> 78 | k: Cipher.key (AEAD.cipher_alg_of_supported_alg a) -> 79 | h:header -> 80 | cid_len: nat { cid_len <= 20 /\ (MShort? h ==> cid_len == dcid_len h) } -> 81 | last: nat { last + 1 < pow2 62 /\ ((~ (is_retry h)) ==> PN.in_window (Secret.v (pn_length h) - 1) last (Secret.v (packet_number h))) } -> 82 | c: cbytes' (is_retry h) { has_payload_length h ==> Secret.v (payload_length h) == Seq.length c } -> 83 | Lemma ( 84 | header_decrypt a k cid_len last (header_encrypt a k h c) 85 | == H_Success h c Seq.empty) 86 | -------------------------------------------------------------------------------- /src/QUIC.Secret.Int.fst: -------------------------------------------------------------------------------- 1 | module QUIC.Secret.Int 2 | module Aux = QUIC.Secret.Int.Aux 3 | 4 | let usub 5 | #t #sec x y 6 | = x `sub` y 7 | 8 | let cast_up 9 | #t1 t2 #sec x 10 | = cast t2 SEC x 11 | 12 | let cast_down 13 | #t1 t2 #sec x 14 | = cast t2 SEC x 15 | 16 | let hide 17 | #t #sec x 18 | = cast t SEC x 19 | 20 | let reveal 21 | #t #sec x 22 | = mk_int #t (v x) 23 | 24 | 25 | let lognot' 26 | #t #l x 27 | = U.nth_lemma #(bits t) (U.lognot (v x)) (v x `U.logxor` v (ones t l)); 28 | x `logxor` ones t l 29 | 30 | let logand_one_bit = Aux.logand_one_bit 31 | 32 | let logor_one_bit = Aux.logor_one_bit 33 | 34 | let logxor_one_bit = Aux.logxor_one_bit 35 | 36 | let secret_bool = Aux.secret_bool 37 | 38 | let lognot_one_bit = Aux.lognot_one_bit 39 | 40 | #push-options "--z3rlimit 64" 41 | 42 | #restart-solver 43 | 44 | let get_bitfield 45 | #t #l x lo hi 46 | = BF.get_bitfield_eq_2 #(bits t) (v x) (U32.v lo) (U32.v hi); 47 | // due to https://github.com/FStarLang/karamel/issues/102 we need explicit intermediate operations here 48 | let op1 = x `shift_left` (U32.uint_to_t (bits t) `U32.sub` hi) in 49 | let op2 = op1 `shift_right` (U32.uint_to_t (bits t) `U32.sub` hi `U32.add` lo) in 50 | op2 51 | 52 | #restart-solver 53 | 54 | let set_bitfield 55 | #t #l x lo hi w 56 | = BF.set_bitfield_eq #(bits t) (v x) (U32.v lo) (U32.v hi) (v w); 57 | U.lognot_lemma_1 #(bits t); 58 | // same as before 59 | let op0 = ones t l in 60 | let op1 = op0 `shift_right` (U32.uint_to_t (bits t) `U32.sub` (hi `U32.sub` lo)) in 61 | let op2 = op1 `shift_left` lo in 62 | let op3 = lognot' op2 in 63 | let op4 = x `logand` op3 in 64 | let op5 = w `shift_left` lo in 65 | let op6 = op4 `logor` op5 in 66 | op6 67 | #pop-options 68 | 69 | (* Instances *) 70 | 71 | let secrets_are_equal_32_2 72 | (x: uint32 { v x < pow2 2 }) 73 | (y: uint32 { v y < pow2 2 }) 74 | : Tot (z: uint32 { 75 | v z == (if v x = v y then 1 else 0) 76 | }) 77 | = Aux.secrets_are_equal x y 78 | 79 | let secret_is_le_64 80 | (x: uint64) 81 | (y: uint64) 82 | : Tot (z: uint64 { v z == (if v x <= v y then 1 else 0) }) 83 | = lognot_one_bit (Aux.secret_is_lt y x) 84 | 85 | let secret_is_lt_64 86 | (x: uint64) 87 | (y: uint64) 88 | : Tot (z: uint64 { v z == (if v x < v y then 1 else 0) }) 89 | = Aux.secret_is_lt x y 90 | 91 | let secrets_are_equal_64_2 92 | (x: uint64 { v x < pow2 2 }) 93 | (y: uint64 { v y < pow2 2 }) 94 | : Tot (z: uint64 { 95 | v z == (if v x = v y then 1 else 0) 96 | }) 97 | = Aux.secrets_are_equal x y 98 | 99 | let secrets_are_equal_62 100 | (x: uint64 { v x < pow2 62 }) 101 | (y: uint64 { v y < pow2 62 }) 102 | : Tot (z: uint64 { 103 | v z == (if v x = v y then 1 else 0) 104 | }) 105 | = Aux.secrets_are_equal x y 106 | 107 | let min64 x y = Aux.min64 x y 108 | 109 | let max64 x y = Aux.max64 x y 110 | -------------------------------------------------------------------------------- /src/QUIC.Spec.fsti: -------------------------------------------------------------------------------- 1 | module QUIC.Spec 2 | 3 | include QUIC.Spec.Header.Base 4 | include QUIC.Spec.Crypto 5 | 6 | module Seq = FStar.Seq 7 | module HD = Spec.Hash.Definitions 8 | module AEAD = Spec.Agile.AEAD 9 | module Cipher = Spec.Agile.Cipher 10 | module PN = QUIC.Spec.PacketNumber.Base 11 | module Secret = QUIC.Secret.Int 12 | 13 | noeq 14 | type h_result = 15 | | H_Success: 16 | h: header -> 17 | cipher: cbytes' (is_retry h) -> 18 | rem: bytes -> 19 | h_result 20 | | H_Failure 21 | 22 | // TODO: add a prefix lemma on header_decrypt, if ever useful 23 | 24 | module U32 = FStar.UInt32 25 | module U64 = FStar.UInt64 26 | 27 | 28 | noeq 29 | type result = 30 | | Success: 31 | h: header -> 32 | plain: bytes -> 33 | remainder: bytes -> 34 | result 35 | | Failure 36 | 37 | let iv_t (a: ea) = (x: AEAD.iv a { Seq.length x == 12 }) 38 | 39 | val encrypt: 40 | a: ea -> 41 | k: AEAD.kv a -> 42 | static_iv: iv_t a -> 43 | hpk: Cipher.key (AEAD.cipher_alg_of_supported_alg a) -> 44 | h: header -> 45 | plain: pbytes' (is_retry h) -> 46 | GTot packet 47 | 48 | val encrypt_length: 49 | a: ea -> 50 | k: AEAD.kv a -> 51 | static_iv: iv_t a -> 52 | hpk: Cipher.key (AEAD.cipher_alg_of_supported_alg a) -> 53 | h: header -> 54 | plain: pbytes' (is_retry h) -> 55 | Lemma 56 | (ensures ( 57 | Seq.length (encrypt a k static_iv hpk h plain) == 58 | header_len h + 59 | begin if is_retry h 60 | then Seq.length plain 61 | else AEAD.tag_length a + Seq.length plain 62 | end 63 | )) 64 | 65 | /// decryption and correctness 66 | 67 | val decrypt: 68 | a: ea -> 69 | k: AEAD.kv a -> 70 | static_iv: iv_t a -> 71 | hpk: Cipher.key (AEAD.cipher_alg_of_supported_alg a) -> 72 | last: nat{last+1 < pow2 62} -> 73 | cid_len: nat { cid_len <= 20 } -> 74 | packet: packet -> 75 | GTot (r: result { 76 | match r with 77 | | Failure -> True 78 | | Success h _ rem -> 79 | is_valid_header h cid_len last /\ 80 | Seq.length rem <= Seq.length packet /\ 81 | rem `Seq.equal` Seq.slice packet (Seq.length packet - Seq.length rem) (Seq.length packet) 82 | }) 83 | 84 | val lemma_encrypt_correct: 85 | a: ea -> 86 | k: AEAD.kv a -> 87 | siv: iv_t a -> 88 | hpk: Cipher.key (AEAD.cipher_alg_of_supported_alg a) -> 89 | h: header -> 90 | cid_len: nat { cid_len <= 20 /\ (MShort? h ==> cid_len == dcid_len h) } -> 91 | last: nat{last+1 < pow2 62 } -> 92 | p: pbytes' (is_retry h) { has_payload_length h ==> Secret.v (payload_length h) == Seq.length p + AEAD.tag_length a } -> Lemma 93 | (requires ( 94 | (~ (is_retry h)) ==> ( 95 | PN.in_window (Secret.v (pn_length h) - 1) last (Secret.v (packet_number h)) 96 | ))) 97 | (ensures ( 98 | decrypt a k siv hpk last cid_len 99 | (encrypt a k siv hpk h p) 100 | == Success h p Seq.empty 101 | )) 102 | -------------------------------------------------------------------------------- /src/QUIC.Spec.Crypto.fsti: -------------------------------------------------------------------------------- 1 | module QUIC.Spec.Crypto 2 | include QUIC.Spec.Base 3 | 4 | module Seq = FStar.Seq 5 | module HD = Spec.Hash.Definitions 6 | module AEAD = Spec.Agile.AEAD 7 | module Secret = QUIC.Secret.Int 8 | module Cipher = Spec.Agile.Cipher 9 | 10 | let supported_hash = function 11 | | HD.SHA1 | HD.SHA2_256 | HD.SHA2_384 | HD.SHA2_512 -> true 12 | | _ -> false 13 | 14 | let supported_aead = function 15 | | AEAD.AES128_GCM | AEAD.AES256_GCM | AEAD.CHACHA20_POLY1305 -> true 16 | | _ -> false 17 | 18 | type ha = a:HD.hash_alg{supported_hash a} 19 | type ea = a:AEAD.alg{supported_aead a} 20 | 21 | 22 | inline_for_extraction noextract 23 | let as_cipher_alg (a: ea): a:Cipher.cipher_alg { 24 | Cipher.(a == AES128 \/ a == AES256 \/ a == CHACHA20) 25 | } = 26 | AEAD.cipher_alg_of_supported_alg a 27 | 28 | let cipher_keysize (a:ea) = 29 | Spec.Agile.Cipher.key_length (Spec.Agile.AEAD.cipher_alg_of_supported_alg a) 30 | 31 | // Move from Hashing.Spec to Spec.Hash? 32 | let keysized (a:ha) (l:nat) = 33 | l `HD.less_than_max_input_length` a /\ l + HD.block_length a < pow2 32 34 | let hashable (a:ha) (l:nat) = l `HD.less_than_max_input_length` a 35 | 36 | // AEAD plain and ciphertext. We want to guarantee that regardless 37 | // of the header size (max is 54), the neader + ciphertext + tag fits in a buffer 38 | // : perhaps cleaner with a separate lemma; any reason for putting this in a refinement? 39 | let max_plain_length: n:nat { 40 | forall a. {:pattern AEAD.max_length a} n <= AEAD.max_length a 41 | } = 42 | pow2 32 - header_len_bound - 16 43 | 44 | let max_cipher_length : n:nat { 45 | forall a. {:pattern AEAD.max_length a \/ AEAD.tag_length a } 46 | n <= AEAD.max_length a + AEAD.tag_length a 47 | } = 48 | pow2 32 - header_len_bound 49 | 50 | type packet = b:bytes{let l = Seq.length b in (* 21 <= l /\ *) l < pow2 32} 51 | type pbytes = b:bytes{let l = Seq.length b in 3 <= l /\ l < max_plain_length} 52 | type pbytes' (is_retry: bool) = b:bytes{let l = Seq.length b in if is_retry then l == 0 else (3 <= l /\ l < max_plain_length)} 53 | type cbytes = b:bytes{let l = Seq.length b in 19 <= l /\ l < max_cipher_length} 54 | type cbytes' (is_retry: bool) = b: bytes { let l = Seq.length b in if is_retry then l == 0 else (19 <= l /\ l < max_cipher_length) } 55 | 56 | // Static byte sequences to be fed into secret derivation. Marked as inline, so 57 | // that they can be used as arguments to gcmalloc_of_list for top-level arrays. 58 | inline_for_extraction 59 | noextract 60 | val label_key: lbytes 3 61 | inline_for_extraction 62 | noextract 63 | val label_iv: lbytes 2 64 | inline_for_extraction 65 | noextract 66 | val label_hp: lbytes 2 67 | 68 | val derive_secret: 69 | a: ha -> 70 | prk:HD.bytes_hash a -> 71 | label: bytes -> 72 | len: nat -> 73 | Pure (Seq.seq Secret.uint8) 74 | (requires len <= 255 /\ 75 | Seq.length label <= 244 /\ 76 | keysized a (Seq.length prk) 77 | ) 78 | (ensures fun out -> 79 | Seq.length out == len 80 | ) 81 | -------------------------------------------------------------------------------- /src/experimental/PNEPRF.fsti: -------------------------------------------------------------------------------- 1 | module PNEPRF 2 | module HS = FStar.HyperStack 3 | 4 | module I = Crypto.Indexing 5 | module U32 = FStar.UInt32 6 | module U128 = FStar.UInt128 7 | 8 | open FStar.HyperStack 9 | open FStar.Seq 10 | open FStar.Monotonic.Seq 11 | open FStar.Error 12 | open FStar.Bytes 13 | 14 | open FStar.Bytes 15 | open FStar.UInt32 16 | open Mem 17 | open Pkg 18 | 19 | 20 | //let pnlen = 4 21 | 22 | type prfid = Flag.prfid 23 | 24 | type sample = lbytes 16 25 | 26 | type mask = lbytes 5 27 | 28 | let safePNE (j:prfid) = Flag.safePNE j 29 | 30 | val table_region : rgn 31 | 32 | 33 | type entry (j:prfid) = 34 | | Entry : 35 | s:sample -> 36 | m:mask -> 37 | entry j 38 | 39 | val pne_state : (j:prfid) -> Type0 40 | 41 | val table : (#j:prfid) -> (st:pne_state j) -> (h:mem) -> GTot (Seq.seq (entry j)) 42 | 43 | val footprint : #j:prfid -> st:pne_state j -> GTot (subrgn table_region) 44 | 45 | val frame_table: #j:prfid -> st:pne_state j -> l:Seq.seq (entry j) -> 46 | h0:mem -> s:Set.set rid -> h1:mem -> 47 | Lemma 48 | (requires 49 | safePNE j /\ 50 | table st h0 == l /\ 51 | modifies s h0 h1 /\ 52 | Set.disjoint s (Set.singleton (footprint st))) 53 | (ensures table st h1 == l) 54 | 55 | let sample_filter (j:prfid) (s:sample) (e:entry j) : bool = 56 | Entry?.s e = s 57 | 58 | let entry_for_sample (#j:prfid) (s:sample) (st:pne_state j) (h:mem) : 59 | GTot (option (entry j)) = 60 | Seq.find_l (sample_filter j s) (table st h) 61 | 62 | let fresh_sample (#j:prfid) (s:sample) (st:pne_state j) (h:mem) : 63 | GTot bool = 64 | None? (entry_for_sample s st h) 65 | 66 | let find_sample (#j:prfid) (s:sample) (st:pne_state j) (h:mem) : 67 | GTot bool = 68 | Some? (entry_for_sample s st h) 69 | 70 | 71 | let sample_mask_filter (j:prfid) (s:sample) (m:mask) (e:entry j) : bool = 72 | Entry?.s e = s && Entry?.m e = m 73 | 74 | let entry_for_sample_mask (#j:prfid) (s:sample) (m:mask) (st:pne_state j) (h:mem) : 75 | GTot (option (entry j)) = 76 | Seq.find_l (sample_mask_filter j s m) (table st h) 77 | 78 | let find_sample_mask (#j:prfid) (s:sample) (m:mask) (st:pne_state j) (h:mem) : 79 | GTot bool = 80 | Some? (entry_for_sample_mask s m st h) 81 | 82 | 83 | val create (j:prfid) : ST (pne_state j) 84 | (requires fun _ -> True) 85 | (ensures fun h0 st h1 -> 86 | modifies_none h0 h1 /\ 87 | table st h1 == Seq.empty) 88 | 89 | val compute : 90 | (#j:prfid) -> 91 | (st:pne_state j) -> 92 | (s:sample) -> 93 | ST (mask) 94 | (requires fun h0 -> True) 95 | (ensures fun h0 m h1 -> 96 | modifies_one (footprint st) h0 h1 /\ 97 | (safePNE j ==> 98 | (match (entry_for_sample s st h0) with 99 | | None -> table st h1 == Seq.snoc (table st h0) (Entry s m) 100 | | Some (Entry _ m') -> m = m'))) 101 | 102 | 103 | 104 | //let sample_cipher (c:cipher) : s:sample = 105 | // Bytes.slice c 0ul 16ul 106 | -------------------------------------------------------------------------------- /src/experimental/Model.PNEPRF.fsti: -------------------------------------------------------------------------------- 1 | module PNEPRF 2 | module HS = FStar.HyperStack 3 | 4 | module I = Crypto.Indexing 5 | module U32 = FStar.UInt32 6 | module U128 = FStar.UInt128 7 | 8 | open FStar.HyperStack 9 | open FStar.Seq 10 | open FStar.Monotonic.Seq 11 | open FStar.Error 12 | open FStar.Bytes 13 | 14 | open FStar.Bytes 15 | open FStar.UInt32 16 | open Mem 17 | open Pkg 18 | 19 | 20 | //let pnlen = 4 21 | 22 | type prfid = Flag.prfid 23 | 24 | type sample = lbytes 16 25 | 26 | type mask = lbytes 5 27 | 28 | let safePNE (j:prfid) = Flag.safePNE j 29 | 30 | val table_region : rgn 31 | 32 | 33 | type entry (j:prfid) = 34 | | Entry : 35 | s:sample -> 36 | m:mask -> 37 | entry j 38 | 39 | val pne_state : (j:prfid) -> Type0 40 | 41 | val table : (#j:prfid) -> (st:pne_state j) -> (h:mem) -> GTot (Seq.seq (entry j)) 42 | 43 | val footprint : #j:prfid -> st:pne_state j -> GTot (subrgn table_region) 44 | 45 | val frame_table: #j:prfid -> st:pne_state j -> l:Seq.seq (entry j) -> 46 | h0:mem -> s:Set.set rid -> h1:mem -> 47 | Lemma 48 | (requires 49 | safePNE j /\ 50 | table st h0 == l /\ 51 | modifies s h0 h1 /\ 52 | Set.disjoint s (Set.singleton (footprint st))) 53 | (ensures table st h1 == l) 54 | 55 | let sample_filter (j:prfid) (s:sample) (e:entry j) : bool = 56 | Entry?.s e = s 57 | 58 | let entry_for_sample (#j:prfid) (s:sample) (st:pne_state j) (h:mem) : 59 | GTot (option (entry j)) = 60 | Seq.find_l (sample_filter j s) (table st h) 61 | 62 | let fresh_sample (#j:prfid) (s:sample) (st:pne_state j) (h:mem) : 63 | GTot bool = 64 | None? (entry_for_sample s st h) 65 | 66 | let find_sample (#j:prfid) (s:sample) (st:pne_state j) (h:mem) : 67 | GTot bool = 68 | Some? (entry_for_sample s st h) 69 | 70 | 71 | let sample_mask_filter (j:prfid) (s:sample) (m:mask) (e:entry j) : bool = 72 | Entry?.s e = s && Entry?.m e = m 73 | 74 | let entry_for_sample_mask (#j:prfid) (s:sample) (m:mask) (st:pne_state j) (h:mem) : 75 | GTot (option (entry j)) = 76 | Seq.find_l (sample_mask_filter j s m) (table st h) 77 | 78 | let find_sample_mask (#j:prfid) (s:sample) (m:mask) (st:pne_state j) (h:mem) : 79 | GTot bool = 80 | Some? (entry_for_sample_mask s m st h) 81 | 82 | 83 | val create (j:prfid) : ST (pne_state j) 84 | (requires fun _ -> True) 85 | (ensures fun h0 st h1 -> 86 | modifies_none h0 h1 /\ 87 | table st h1 == Seq.empty) 88 | 89 | val compute : 90 | (#j:prfid) -> 91 | (st:pne_state j) -> 92 | (s:sample) -> 93 | ST (mask) 94 | (requires fun h0 -> True) 95 | (ensures fun h0 m h1 -> 96 | modifies_one (footprint st) h0 h1 /\ 97 | (safePNE j ==> 98 | (match (entry_for_sample s st h0) with 99 | | None -> table st h1 == Seq.snoc (table st h0) (Entry s m) 100 | | Some (Entry _ m') -> m = m'))) 101 | 102 | 103 | 104 | //let sample_cipher (c:cipher) : s:sample = 105 | // Bytes.slice c 0ul 16ul 106 | -------------------------------------------------------------------------------- /src/experimental/integers.fst: -------------------------------------------------------------------------------- 1 | (* demo at https://www.fstar-lang.org/tutorial/ *) 2 | 3 | module Integers 4 | 5 | 6 | (** Several definitions of the factorial function **) 7 | 8 | (* factorial function (non-tail version) *) 9 | let rec factorial (n:nat) : Tot nat = 10 | if n = 0 then 1 else op_Multiply (factorial (n-1)) n 11 | 12 | (* tail-rec factorial with accumulator *) 13 | let rec factorial_tail_aux (n:nat) (accu:nat) : Tot nat = 14 | if n = 0 then accu 15 | else factorial_tail_aux (n-1) (op_Multiply n accu) 16 | let factorial_tail (n:nat) : Tot nat = 17 | factorial_tail_aux n 1 18 | 19 | (*tail-rec factorial with cps *) 20 | let rec factorial_cps_aux (n:nat) (f:nat->Tot nat) : Tot nat = 21 | if n = 0 then f 1 22 | else factorial_cps_aux (n-1) (fun res -> f (op_Multiply res n)) 23 | let factorial_cps (n:nat) : Tot nat = 24 | factorial_cps_aux n (fun res -> res) 25 | 26 | 27 | 28 | (** Equivalence of the several definitions **) 29 | 30 | (* correctness of the accumulator version, formalised with a local auxiliary lemma *) 31 | let correctness_factorial_tail_raw (n:nat) : Lemma 32 | (requires True) 33 | (ensures factorial_tail n = factorial n) = 34 | 35 | let rec induction_lemma (n:nat) (accu:nat) : Lemma 36 | (requires True) 37 | (ensures op_Multiply (factorial n) accu = factorial_tail_aux n accu) = 38 | if n = 0 then () 39 | else induction_lemma (n-1) (op_Multiply n accu) in 40 | 41 | induction_lemma n 1 42 | 43 | 44 | (* correctness of the accumulator version, formalised with a separated auxiliary lemma *) 45 | let rec correctness_factorial_tail_aux (n:nat) (accu:nat) : Lemma 46 | (requires True) 47 | (ensures factorial_tail_aux n accu = (op_Multiply (factorial n) accu)) = 48 | if n = 0 then () 49 | else correctness_factorial_tail_aux (n-1) (op_Multiply n accu) 50 | let correctness_factorial_tail (n:nat) : Lemma 51 | (requires True) 52 | (ensures factorial_tail n = factorial n) = 53 | correctness_factorial_tail_aux n 1 54 | 55 | 56 | (* correctness of the cps version, formalised with a local auxiliary lemma *) 57 | let correctness_factorial_cps_raw (n:nat) : Lemma 58 | (requires True) 59 | (ensures factorial_cps n = factorial n) = 60 | 61 | let rec induction_lemma (n:nat) (f:nat->nat) : Lemma 62 | (requires True) 63 | (ensures factorial_cps_aux n f = f (factorial n)) = 64 | if n = 0 then () 65 | else induction_lemma (n-1) (fun res -> f (op_Multiply res n)) in 66 | 67 | induction_lemma n (fun res -> res) 68 | 69 | 70 | (* correctness of the cps version, formalised with a separated auxiliary lemma 71 | /!\ FStar does not manage to prove the auxiliary lemma *) 72 | let rec correctness_factorial_cps_aux (n:nat) (f:nat->nat) : Lemma 73 | (requires True) 74 | (ensures factorial_cps_aux n f = f (factorial n)) = 75 | if n = 0 then () 76 | else correctness_factorial_cps_aux (n-1) (fun res -> f (op_Multiply res n)) 77 | let correctness_factorial_cps (n:nat) : Lemma 78 | (requires True) 79 | (ensures factorial_cps n = factorial n) = 80 | correctness_factorial_cps_aux n (fun res -> res) 81 | -------------------------------------------------------------------------------- /src/experimental/GCTR_s.fst: -------------------------------------------------------------------------------- 1 | module GCTR_s 2 | 3 | // IMPORTANT: Following NIST's specification, this spec is written assuming a big-endian mapping from bytes to quad32s 4 | // Since the AES spec (AES_s) is in little-endian, we need to byteswap each time we call AES 5 | 6 | open Prop_s 7 | open Opaque_s 8 | open Words_s 9 | open Types_s 10 | open FStar.Mul 11 | open AES_s 12 | open FStar.Seq 13 | 14 | // length plain < pow2_32 / 4096 <= spec max of 2**39 - 256; 15 | let is_gctr_plain_LE (p:seq nat8) : prop0 = 4096 * length p < pow2_32 16 | type gctr_plain_LE:eqtype = p:seq nat8 { is_gctr_plain_LE p } 17 | type gctr_plain_internal_LE:eqtype = p:seq quad32 18 | 19 | let inc32 (cb:quad32) (i:int) : quad32 = 20 | Mkfour ((cb.lo0 + i) % pow2_32) cb.lo1 cb.hi2 cb.hi3 21 | 22 | let gctr_encrypt_block (icb_BE:quad32) (plain_LE:quad32) (alg:algorithm) (key:seq nat32) (i:int) : Pure quad32 23 | (requires is_aes_key_LE alg key) 24 | (ensures fun _ -> True) 25 | = 26 | let icb_LE = reverse_bytes_quad32 (inc32 icb_BE i) in 27 | quad32_xor plain_LE (aes_encrypt_LE alg key icb_LE) 28 | 29 | 30 | let rec gctr_encrypt_recursive (icb_BE:quad32) (plain:gctr_plain_internal_LE) 31 | (alg:algorithm) (key:aes_key_LE alg) (i:int) : Tot (seq quad32) (decreases %[length plain]) = 32 | if length plain = 0 then empty 33 | else 34 | cons (gctr_encrypt_block icb_BE (head plain) alg key i) (gctr_encrypt_recursive icb_BE (tail plain) alg key (i + 1)) 35 | 36 | let pad_to_128_bits (p:seq nat8) : Pure (seq nat8) 37 | (requires True) 38 | (ensures fun q -> length q % 16 == 0 /\ length q <= length p + 15) 39 | = 40 | let num_extra_bytes = length p % 16 in 41 | if num_extra_bytes = 0 then p 42 | else p @| (create (16 - num_extra_bytes) 0) 43 | 44 | // little-endian, except for icb_BE 45 | let gctr_encrypt_LE_def (icb_BE:quad32) (plain:seq nat8) (alg:algorithm) (key:seq nat32) : Pure (seq nat8) 46 | (requires is_gctr_plain_LE plain /\ is_aes_key_LE alg key) 47 | (ensures fun _ -> True) 48 | = 49 | let num_extra = (length plain) % 16 in 50 | 51 | if num_extra = 0 then 52 | let plain_quads_LE = le_bytes_to_seq_quad32 plain in 53 | let cipher_quads_LE = gctr_encrypt_recursive icb_BE plain_quads_LE alg key 0 in 54 | le_seq_quad32_to_bytes cipher_quads_LE 55 | else 56 | let full_bytes_len = (length plain) - num_extra in 57 | let full_blocks, final_block = split plain full_bytes_len in 58 | 59 | let full_quads_LE = le_bytes_to_seq_quad32 full_blocks in 60 | let final_quad_LE = le_bytes_to_quad32 (pad_to_128_bits final_block) in 61 | 62 | let cipher_quads_LE = gctr_encrypt_recursive icb_BE full_quads_LE alg key 0 in 63 | let final_cipher_quad_LE = gctr_encrypt_block icb_BE final_quad_LE alg key (full_bytes_len / 16) in 64 | 65 | let cipher_bytes_full_LE = le_seq_quad32_to_bytes cipher_quads_LE in 66 | let final_cipher_bytes_LE = slice (le_quad32_to_bytes final_cipher_quad_LE) 0 num_extra in 67 | 68 | cipher_bytes_full_LE @| final_cipher_bytes_LE 69 | 70 | let gctr_encrypt_LE = make_opaque gctr_encrypt_LE_def 71 | -------------------------------------------------------------------------------- /src/QUIC.Spec.PacketNumber.Lemmas.fst: -------------------------------------------------------------------------------- 1 | module QUIC.Spec.PacketNumber.Lemmas 2 | 3 | let replace_modulo' (a b new_mod:nat) : Pure nat 4 | (requires b > 0 /\ new_mod < b) 5 | (ensures fun res -> res % b = new_mod /\ res / b = a / b) = 6 | let open FStar.Math.Lemmas in 7 | let res = a - a%b + new_mod in 8 | lemma_mod_plus new_mod (a/b) b; 9 | small_mod new_mod b; 10 | res 11 | 12 | #push-options "--z3rlimit 256" 13 | let lemma_replace_modulo_bound_aux (k:nat) (a:nat) (b:nat) (u:nat) 14 | : Lemma (requires a < pow2 k /\ a % pow2 u == 0 /\ b < pow2 u /\ u < k) 15 | (ensures a + b < pow2 k) = 16 | let open FStar.Math.Lemmas in 17 | let open FStar.Mul in 18 | lemma_div_mod a (pow2 u); 19 | assert(a + b == pow2 u * (a / pow2 u) + b); 20 | lemma_div_plus b (a / pow2 u) (pow2 u); 21 | small_div b (pow2 u); 22 | lemma_div_lt_nat a k u; 23 | assert((a / pow2 u) < pow2 (k-u)); 24 | assert(((a + b) / pow2 u) / pow2 (k-u) < 1); 25 | division_multiplication_lemma (a+b) (pow2 u) (pow2 (k-u)); 26 | pow2_plus u (k-u) 27 | #pop-options 28 | 29 | #push-options "--z3rlimit 1024" 30 | 31 | #restart-solver 32 | let lemma_replace_modulo_bound (a mod_pow new_mod up_pow:nat) : Lemma 33 | (requires 34 | mod_pow < up_pow /\ 35 | new_mod < pow2 mod_pow /\ 36 | a < pow2 up_pow) 37 | (ensures replace_modulo' a (pow2 mod_pow) new_mod < pow2 up_pow) = 38 | let open FStar.Math.Lemmas in 39 | let open FStar.Mul in 40 | let (pmod,umod) = (pow2 mod_pow, pow2 up_pow) in 41 | lemma_div_mod a pmod; 42 | multiple_modulo_lemma (a / pmod) pmod; 43 | assert_spinoff (a-a%pow2 mod_pow >= 0); 44 | lemma_replace_modulo_bound_aux up_pow (a-a%pow2 mod_pow) new_mod mod_pow 45 | 46 | module U64 = FStar.UInt64 47 | 48 | #restart-solver 49 | 50 | module Secret = QUIC.Secret.Int 51 | module U = FStar.UInt 52 | 53 | let logand_mask (#n:pos) (a:U.uint_t n) (m:nat{m <= n}) 54 | : Lemma (pow2 m <= pow2 n /\ U.logand #n a (pow2 m - 1) == a % pow2 m) 55 | = if m = 0 56 | then U.logand_lemma_1 a 57 | else if m = n 58 | then begin 59 | FStar.Math.Lemmas.small_mod a (pow2 n); 60 | U.logand_lemma_2 a 61 | end 62 | else U.logand_mask a m 63 | 64 | #pop-options 65 | 66 | #push-options "--z3rlimit 2048" 67 | 68 | #restart-solver 69 | 70 | inline_for_extraction 71 | let replace_modulo 72 | (a: Secret.uint64 { Secret.v a < pow2 62 }) 73 | (b_size: FStar.Ghost.erased nat { b_size <= 64 }) 74 | (b_mask: Secret.uint64 { Secret.v b_mask == pow2 b_size - 1 }) 75 | (new_mod: Secret.uint64) 76 | : Pure Secret.uint64 77 | (requires Secret.v new_mod < pow2 (b_size)) 78 | (ensures fun res -> Secret.v res == replace_modulo' (Secret.v a) (pow2 (b_size)) (Secret.v new_mod)) 79 | = 80 | let open FStar.Math.Lemmas in 81 | [@inline_let] let _ = 82 | lemma_mod_plus (Secret.v new_mod) (Secret.v a / pow2 b_size) (pow2 b_size); 83 | Secret.logand_spec a b_mask; 84 | logand_mask #64 (Secret.v a) b_size; 85 | small_mod (Secret.v new_mod) (pow2 b_size); 86 | lemma_mod_lt (Secret.v a) (pow2 b_size) 87 | in 88 | (a `Secret.sub` (a `Secret.logand` b_mask)) `Secret.add` new_mod 89 | 90 | #pop-options 91 | -------------------------------------------------------------------------------- /src/QUIC.Impl.Header.Parse.fsti: -------------------------------------------------------------------------------- 1 | module QUIC.Impl.Header.Parse 2 | open QUIC.Spec.Header.Parse 3 | include QUIC.Impl.Header.Base 4 | 5 | module HS = FStar.HyperStack 6 | module U32 = FStar.UInt32 7 | module Seq = FStar.Seq 8 | module PN = QUIC.Spec.PacketNumber.Base 9 | module Secret = QUIC.Secret.Int 10 | module Spec = QUIC.Spec.Header.Parse 11 | module U8 = FStar.UInt8 12 | module B = LowStar.Buffer 13 | module HST = FStar.HyperStack.ST 14 | 15 | val public_header_len_is_pn_offset 16 | (h: header { ~ (is_retry h) }) 17 | (m: HS.mem) 18 | (pn: PN.packet_number_t) 19 | : Lemma 20 | (U32.v (public_header_len h) == pn_offset (g_header h m pn)) 21 | 22 | val header_len_correct 23 | (h: header) 24 | (m: HS.mem) 25 | (pn: PN.packet_number_t) 26 | : Lemma 27 | (Secret.v (header_len h) == Spec.header_len (g_header h m pn)) 28 | 29 | val write_header 30 | (h: header) 31 | (pn: PN.packet_number_t) 32 | (out: B.buffer U8.t) 33 | (out_len: U32.t { U32.v out_len <= B.length out }) 34 | : HST.Stack unit 35 | (requires (fun h0 -> 36 | header_live h h0 /\ 37 | B.live h0 out /\ 38 | B.loc_disjoint (header_footprint h) (B.loc_buffer out) /\ 39 | U32.v (public_header_len h) + (if is_retry h then 0 else 4) <= U32.v out_len // needs more space than just pn_length to write pn in constant time 40 | )) 41 | (ensures (fun h0 _ h1 -> 42 | let gh = g_header h h0 pn in 43 | let s = format_header gh in 44 | let len = header_len h in 45 | B.modifies (B.loc_buffer out) h0 h1 /\ 46 | Secret.v len <= U32.v out_len /\ 47 | Seq.slice (B.as_seq h1 out) 0 (Secret.v len) `Seq.equal` s 48 | )) 49 | 50 | val putative_pn_offset 51 | (cid_len: short_dcid_len_t) 52 | (b: B.buffer U8.t) 53 | (b_len: U32.t { U32.v b_len == B.length b }) 54 | : HST.Stack (option U32.t) 55 | (requires (fun h -> 56 | B.live h b 57 | )) 58 | (ensures (fun h res h' -> 59 | B.modifies B.loc_none h h' /\ 60 | begin match Spec.putative_pn_offset (U32.v cid_len) (B.as_seq h b), res with 61 | | None, None -> True 62 | | Some off, Some off' -> U32.v off' == off 63 | | _ -> False 64 | end 65 | )) 66 | 67 | val read_header 68 | (packet: B.buffer U8.t) 69 | (packet_len: U32.t { let v = U32.v packet_len in v == B.length packet }) 70 | (cid_len: U32.t { U32.v cid_len <= 20 } ) 71 | (last: PN.last_packet_number_t) 72 | : HST.Stack (header & PN.packet_number_t) 73 | (requires (fun h -> 74 | B.live h packet /\ 75 | begin match Spec.putative_pn_offset (U32.v cid_len) (B.as_seq h packet) with 76 | | None -> False 77 | | Some off -> (~ (packet_is_retry (B.as_seq h packet))) ==> off + 4 <= B.length packet 78 | end 79 | )) 80 | (ensures (fun h (x, pn) h' -> 81 | B.modifies B.loc_none h h' /\ 82 | begin match parse_header (U32.v cid_len) (Secret.v last) (B.as_seq h packet) with 83 | | H_Success hd _ -> 84 | let len = public_header_len x in 85 | U32.v len <= B.length packet /\ 86 | header_live x h' /\ 87 | B.loc_buffer (B.gsub packet 0ul len) `B.loc_includes` header_footprint x /\ 88 | g_header x h' pn == hd 89 | | _ -> False 90 | end 91 | )) 92 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: test 2 | 3 | test: dist/test.exe 4 | $< 5 | 6 | # Boilerplate 7 | # ----------- 8 | 9 | include Makefile.include 10 | 11 | EXCLUDE_MODULES=Spec.Old Impl.Old 12 | 13 | FST_FILES=$(filter-out $(addprefix src/QUIC.,$(addsuffix .fst,$(EXCLUDE_MODULES)) $(addsuffix .fsti,$(EXCLUDE_MODULES))),$(wildcard src/*.fst) $(wildcard src/*.fsti)) test/QUICTest.fst 14 | 15 | ifndef NODEPEND 16 | ifndef MAKE_RESTARTS 17 | .depend: .FORCE 18 | @mkdir -p obj 19 | @$(FSTAR) --dep full $(FST_FILES) > $@ 20 | 21 | .PHONY: .FORCE 22 | .FORCE: 23 | endif 24 | endif 25 | 26 | include .depend 27 | 28 | clean-dist: 29 | rm -rf dist 30 | 31 | clean: clean-dist 32 | rm -rf obj .depend 33 | 34 | # Verification 35 | # ------------ 36 | 37 | %.checked: 38 | $(FSTAR) --hint_file hints/$(notdir $*).hints $(notdir $*) && touch -c $@ 39 | 40 | %.krml: 41 | $(FSTAR) --codegen krml \ 42 | --extract_module $(basename $(notdir $(subst .checked,,$<))) \ 43 | $(notdir $(subst .checked,,$<)) 44 | 45 | verify: $(ALL_CHECKED_FILES) 46 | 47 | # Karamel 48 | # ------- 49 | 50 | KRML=$(KRML_HOME)/krml 51 | 52 | obj/krml.rsp: $(filter-out %/prims.krml,$(ALL_KRML_FILES)) 53 | for f in $^ ; do echo $$f ; done > $@ 54 | 55 | dist/Makefile.basic: obj/krml.rsp 56 | $(KRML) $(KOPTS) -library EverCrypt,EverCrypt.* @$^ -tmpdir dist -skip-compilation \ 57 | -minimal \ 58 | -header noheader.txt \ 59 | -add-include '"krml/internal/target.h"' \ 60 | -add-include '"krml/internal/types.h"' \ 61 | -add-include '"krml/lowstar_endianness.h"' \ 62 | -add-include '' \ 63 | -add-include '' \ 64 | -add-include '' \ 65 | -library 'Vale.Stdcalls.*' \ 66 | -no-prefix 'Vale.Stdcalls.*' \ 67 | -static-header 'Vale.Inline.*' \ 68 | -library 'Vale.Inline.X64.Fadd_inline' \ 69 | -library 'Vale.Inline.X64.Fmul_inline' \ 70 | -library 'Vale.Inline.X64.Fswap_inline' \ 71 | -library 'Vale.Inline.X64.Fsqr_inline' \ 72 | -no-prefix 'Vale.Inline.X64.Fadd_inline' \ 73 | -no-prefix 'Vale.Inline.X64.Fmul_inline' \ 74 | -no-prefix 'Vale.Inline.X64.Fswap_inline' \ 75 | -no-prefix 'Vale.Inline.X64.Fsqr_inline' \ 76 | -fparentheses \ 77 | -o libeverquic.a \ 78 | -bundle LowParse.* \ 79 | -bundle LowStar.* \ 80 | -bundle Prims,C.Failure,C,C.String,C.Loops,Spec.Loops,C.Endianness,FStar.*[rename=EverQuic_Krmllib] \ 81 | -bundle 'Meta.*,Hacl.*,Vale.*,Spec.*,Lib.*,EverCrypt,EverCrypt.*,NotEverCrypt.*[rename=EverQuic_EverCrypt]' \ 82 | -bundle Model.* \ 83 | -bundle Mem \ 84 | -bundle 'QUIC.State+QUIC.Impl.Header.Base=QUIC.\*[rename=EverQuic,rename-prefix]' 85 | 86 | dist/libeverquic.a: dist/Makefile.basic 87 | $(MAKE) -C dist -f Makefile.basic 88 | 89 | .PHONY: clean clean-dist verify 90 | 91 | # Tests 92 | # ----- 93 | 94 | CFLAGS+=-I$(realpath .)/dist -I$(realpath $(KRML_HOME))/include -I$(realpath $(KRML_HOME))/krmllib/dist/minimal 95 | export CFLAGS 96 | 97 | test/main.o: dist/Makefile.basic 98 | 99 | dist/test.exe: test/main.o dist/libeverquic.a $(HACL_HOME)/dist/gcc-compatible/libevercrypt.a $(KRML_HOME)/krmllib/dist/generic/libkrmllib.a 100 | $(CC) $^ -o $@ 101 | -------------------------------------------------------------------------------- /src/Model.AEAD.fst: -------------------------------------------------------------------------------- 1 | module Model.AEAD 2 | 3 | module HS = FStar.HyperStack 4 | module I = Model.Indexing 5 | module U32 = FStar.UInt32 6 | module U128 = FStar.UInt128 7 | module B = LowStar.Buffer 8 | module Spec = Spec.Agile.AEAD 9 | 10 | #set-options "--fuel 0 --ifuel 0" 11 | 12 | open Mem 13 | open LowStar.BufferOps 14 | open Model.Helpers 15 | 16 | let log #i (u: info i): Type0 = 17 | Seq.seq (entry i u) 18 | 19 | let model_writer i: Type u#1 = 20 | u:info i & B.pointer (log #i u) 21 | 22 | let unsafe_writer i = 23 | info i & Spec.kv (I.ae_id_ginfo i) 24 | 25 | let aead_writer (i: id): Type u#1 = 26 | if is_safe i then 27 | model_writer i 28 | else 29 | unsafe_writer i 30 | 31 | let aead_reader #i (w: aead_writer i) = 32 | w':aead_writer i { w' == w } 33 | 34 | let wgetinfo #i (u: aead_writer i) = 35 | if is_safe i then 36 | dfst (u <: model_writer i) 37 | else 38 | fst (u <: unsafe_writer i) 39 | 40 | let rgetinfo #_ #w _ = 41 | wgetinfo w 42 | 43 | let wlog #i w h = 44 | B.deref h (dsnd (w <: model_writer i)) 45 | 46 | let wkey #i w = 47 | snd (w <: unsafe_writer i) 48 | 49 | let wfootprint #i w = 50 | if is_safe i then 51 | B.loc_addr_of_buffer (dsnd (w <: model_writer i)) 52 | else 53 | B.loc_none 54 | 55 | let winvariant #i w h = 56 | if is_safe i then 57 | B.live h (dsnd (w <: model_writer i)) 58 | else 59 | True 60 | 61 | let wframe_invariant #_ w h0 l h1 = 62 | () 63 | 64 | let frame_log #_ w h0 l h1 = 65 | () 66 | 67 | let gen i u = 68 | if is_safe i then 69 | let l: log #i u = Seq.empty #(entry i u) in 70 | ((| u, B.malloc q_ae_region l 1ul |) <: model_writer i) 71 | else 72 | let key_l = Spec.key_length u.alg in 73 | (u, random key_l) <: unsafe_writer i 74 | 75 | let gen_reader #i w = 76 | w 77 | 78 | let coerce #i u kv = 79 | (u, kv) <: unsafe_writer i 80 | 81 | // With QUIC-specific derivation of key from transport secret 82 | let quic_coerce #i u ts = 83 | coerce u 84 | (QUIC.Spec.derive_secret u.halg ts 85 | QUIC.Spec.label_key (Spec.key_length u.alg)) 86 | 87 | let encrypt i w nonce aad plain_length plain = 88 | if is_safe i then 89 | let a = (wgetinfo w).alg in 90 | let w: model_writer i = w in 91 | let p = dsnd w in 92 | let log = !*p in 93 | let cipher_length = (plain_length <: nat) + Spec.tag_length a in 94 | let cipher = random cipher_length in 95 | p *= Seq.snoc log (Entry #i #(wgetinfo w) nonce aad #plain_length plain cipher); 96 | cipher 97 | else 98 | let a = (wgetinfo w).alg in 99 | let k: Spec.kv a = wkey w in 100 | let iv = Helpers.hide nonce in 101 | let p = (wgetinfo w).plain_pkg.repr i plain_length plain in 102 | Spec.encrypt #a k iv aad p 103 | 104 | let decrypt i #w r aad n l c = 105 | if is_safe i then 106 | let w: model_writer i = w in 107 | let log = !*(dsnd w) in 108 | match Seq.find_l (nonce_filter w n) log with 109 | | None -> None 110 | | Some (Entry n' aad' #l' p' c') -> 111 | assert (n == n'); 112 | if lbytes_eq aad aad' && lbytes_eq c c' && l = l' then 113 | Some p' 114 | else 115 | None 116 | else 117 | let a = (wgetinfo w).alg in 118 | let k: Spec.kv a = wkey w in 119 | match Spec.decrypt k (Helpers.hide n) aad c with 120 | | None -> None 121 | | Some p -> 122 | Some ((wgetinfo w).plain_pkg.mk i (Seq.length p) p) 123 | -------------------------------------------------------------------------------- /src/QUIC.Spec.fst: -------------------------------------------------------------------------------- 1 | module QUIC.Spec 2 | 3 | open QUIC.Spec.Lemmas 4 | open QUIC.Spec.Header.Base 5 | 6 | module Seq = QUIC.Secret.Seq 7 | module U32 = FStar.UInt32 8 | module U8 = FStar.UInt8 9 | module H = Spec.Agile.Hash 10 | module HD = Spec.Hash.Definitions 11 | module Cipher = Spec.Agile.Cipher 12 | module AEAD = Spec.Agile.AEAD 13 | module HKDF = Spec.Agile.HKDF 14 | module Parse = QUIC.Spec.Header.Parse 15 | module H = QUIC.Spec.Header 16 | module Secret = QUIC.Secret.Int 17 | 18 | /// encryption of a packet 19 | 20 | let iv_for_encrypt_decrypt 21 | (a: ea) 22 | (siv: iv_t a) 23 | (h: header { ~ (is_retry h) }) 24 | : GTot (iv_t a) 25 | = 26 | let pn_len = Secret.v (pn_length h) - 1 in 27 | let seqn = packet_number h in 28 | let _ = assert_norm(pow2 62 < pow2 (8 `op_Multiply` 12)) in 29 | let pnb = FStar.Endianness.n_to_be 12 (Secret.v seqn) in 30 | Seq.seq_hide #Secret.U8 (xor_inplace pnb (Seq.seq_reveal siv) 0) 31 | 32 | let payload_encrypt 33 | (a: ea) 34 | (k: AEAD.kv a) 35 | (siv: iv_t a) 36 | (h: header { ~ (is_retry h) }) 37 | (plain: pbytes) 38 | : GTot (cbytes) 39 | = 40 | let aad = Parse.format_header h in 41 | let iv = iv_for_encrypt_decrypt a siv h in 42 | Seq.seq_reveal (AEAD.encrypt #a k iv (Seq.seq_hide aad) (Seq.seq_hide plain)) 43 | 44 | let encrypt 45 | a k siv hpk h plain 46 | = 47 | let cipher = 48 | if is_retry h 49 | then plain 50 | else payload_encrypt a k siv h plain 51 | in 52 | H.header_encrypt a hpk h cipher 53 | 54 | let encrypt_length 55 | a k siv hpk h plain 56 | = 57 | let c = 58 | if is_retry h 59 | then plain 60 | else payload_encrypt a k siv h plain 61 | in 62 | H.header_encrypt_length a hpk h c 63 | 64 | #restart-solver 65 | 66 | let payload_decrypt 67 | (a: ea) 68 | (k: AEAD.kv a) 69 | (siv: iv_t a) 70 | (h: header { ~ (is_retry h) }) 71 | (c: Seq.seq Secret.uint8 { 16 <= Seq.length c /\ Seq.length c < max_cipher_length }) 72 | : GTot (option (AEAD.decrypted c)) 73 | = 74 | let iv = iv_for_encrypt_decrypt a siv h in 75 | let aad = Parse.format_header h in 76 | AEAD.decrypt #a k iv (Seq.seq_hide aad) c 77 | 78 | let decrypt 79 | a k siv hpk last cid_len packet 80 | = 81 | let open FStar.Math.Lemmas in 82 | let open FStar.Endianness in 83 | match H.header_decrypt a hpk cid_len last packet with 84 | | H.H_Failure -> Failure 85 | | H.H_Success h c rem -> 86 | if is_retry h 87 | then Success h c rem 88 | else 89 | match payload_decrypt a k siv h (Seq.seq_hide c) with 90 | | None -> Failure 91 | | Some plain -> Success h (Seq.seq_reveal plain) rem 92 | 93 | #push-options "--z3rlimit 20" 94 | 95 | let lemma_encrypt_correct 96 | a k siv hpk h cid_len last plain 97 | = 98 | let packet = encrypt a k siv hpk h plain in 99 | let aad = Seq.seq_hide (Parse.format_header h) in 100 | let cipher = if is_retry h then plain else 101 | let iv = iv_for_encrypt_decrypt a siv h in 102 | Seq.seq_reveal (AEAD.encrypt #a k iv aad (Seq.seq_hide plain)) 103 | in 104 | assert (packet == H.header_encrypt a hpk h cipher); 105 | H.lemma_header_encryption_correct a hpk h cid_len last cipher; 106 | if is_retry h 107 | then () 108 | else begin 109 | let iv = iv_for_encrypt_decrypt a siv h in 110 | let dc = H.header_decrypt a hpk cid_len last packet in 111 | assert (H.H_Success? dc); 112 | let H.H_Success h' c' rem' = dc in 113 | assert (h == h' /\ cipher == c'); 114 | let clen = Seq.length cipher in 115 | assert (19 <= clen && clen < max_cipher_length); 116 | AEAD.correctness #a k iv aad (Seq.seq_hide plain) 117 | end 118 | 119 | #pop-options 120 | -------------------------------------------------------------------------------- /src/experimental/DefineTable.fst: -------------------------------------------------------------------------------- 1 | module DefineTable 2 | 3 | open Mem 4 | 5 | module M = LowStar.Modifies 6 | module DM = FStar.DependentMap 7 | module MH = FStar.Monotonic.Heap 8 | module HS = FStar.HyperStack 9 | 10 | open FStar.HyperStack.ST 11 | 12 | friend FStar.Monotonic.DependentMap 13 | 14 | let alloc #it vt = 15 | if model then 16 | MDM.alloc #it #vt #(fun _ -> True) #q_ae_region () 17 | else () 18 | 19 | let lookup #it #vt t i = 20 | if model then 21 | begin 22 | let t0 = ideal t in 23 | recall t0; 24 | match MDM.sel !t0 i with 25 | | None -> None 26 | | Some v -> mr_witness t0 (MDM.defined t0 i); Some v 27 | end 28 | else None 29 | 30 | let extend #it #vt t #i k = 31 | if model then 32 | begin 33 | let t0 = ideal t in 34 | recall t0; 35 | t0 := MDM.upd !t0 i k; 36 | mr_witness t0 (MDM.contains t0 i k); 37 | mr_witness t0 (MDM.defined t0 i) 38 | end 39 | else () 40 | 41 | let dt_forall #it #vt t pred h = 42 | model ==> (forall (i:it) (k:vt i{defined_as t k h}). 43 | {:pattern (defined_as t k h)} pred k h) 44 | 45 | val fold_gtot: ('a -> 'b -> GTot 'a) -> 'a -> l:list 'b -> GTot 'a (decreases l) 46 | let rec fold_gtot f x l = match l with 47 | | [] -> x 48 | | hd::tl -> f (fold_gtot f x tl) hd 49 | 50 | let fp_add (#it:eqtype) (#vt:it->Type) 51 | (fp:local_fp vt) (l:M.loc) (cur:(i:it & vt i)) = 52 | let (| i, k |) = cur in 53 | M.loc_union l (fp k) 54 | 55 | let empty_fp #it vt = 56 | fun (#i:it) (k:vt i) -> M.loc_none 57 | 58 | let lemma_empty_fp_none #it #vt #i k = () 59 | 60 | let rec lemma_fold_constant (#it:eqtype) (#vt:it->Type) 61 | (f: M.loc -> (i:it & vt i) -> GTot M.loc) 62 | (x0:M.loc) (l: list (i:it & vt i)) 63 | : Lemma 64 | (requires (forall (x:M.loc) (y:(i:it & vt i)). f x y == x)) 65 | (ensures fold_gtot f x0 l == x0) 66 | = 67 | match l with 68 | | [] -> () 69 | | h :: t -> lemma_fold_constant f x0 t 70 | 71 | let footprint #it #vt t fp h = 72 | if model then 73 | let l = HS.sel h (ideal t) in 74 | fold_gtot (fp_add fp) M.loc_none l 75 | else M.loc_none 76 | 77 | let lemma_footprint_empty_fp #it #vt t h = 78 | if model then 79 | let l = HS.sel h (ideal t) in 80 | lemma_fold_constant (fp_add (empty_fp vt)) M.loc_none l 81 | else () 82 | 83 | let lemma_footprint_empty #it #vt t fp h0 = () 84 | 85 | let lemma_footprint_frame #it #vt t fp h0 h1 = () 86 | 87 | let lemma_footprint_extend #it #vt t fp #i k h0 h1 = () 88 | 89 | let rec lemma_fp_includes (#it:eqtype) (vt:it->Type) (t:MDM.map it vt) 90 | (fp:local_fp vt) (#i:it) (k:vt i) 91 | : Lemma (requires (MDM.sel t i == Some k)) 92 | (ensures fold_gtot (fp_add fp) M.loc_none t `M.loc_includes` (fp k)) 93 | (decreases %[t]) 94 | = 95 | match t with 96 | | [] -> () 97 | | (| x, y |) :: tl -> 98 | if x = i then () 99 | else lemma_fp_includes vt tl fp k 100 | 101 | let lemma_footprint_includes #it #vt t fp #i k h = 102 | if model then 103 | let t0 = HS.sel h (ideal t) in 104 | lemma_fp_includes vt t0 fp k 105 | else () 106 | 107 | let lemma_forall_empty #it #vt t pred h = () 108 | 109 | let lemma_forall_elim #it #vt t pred h #i k = () 110 | 111 | let lemma_forall_extend #it #vt t pred fp pred_frame #i k h0 h1 = 112 | if model then 113 | let prove_on_witness (x:it) (y:vt x{defined_as t y h1}) 114 | : Lemma (pred y h1) = 115 | if x = i then () 116 | else ( 117 | lemma_forall_elim t pred h0 y; 118 | lemma_footprint_includes t fp y h0; 119 | pred_frame y h0 (loc t) h1 120 | ) in 121 | FStar.Classical.forall_intro_2 prove_on_witness 122 | else () 123 | 124 | let lemma_forall_restore #it #vt t pred fp pred_frame #i k h0 h1 = admit () 125 | 126 | let lemma_forall_frame #it #vt t pred fp pred_frame h0 l h1 = 127 | if model then 128 | let prove_on_witness (x:it) (y:vt x{defined_as t y h1}) 129 | : Lemma (ensures pred y h1) 130 | = 131 | lemma_forall_elim t pred h0 y; 132 | lemma_footprint_includes t fp y h0; 133 | pred_frame y h0 l h1 134 | in 135 | FStar.Classical.forall_intro_2 prove_on_witness 136 | else () 137 | -------------------------------------------------------------------------------- /src/QUIC.Impl.Crypto.fst: -------------------------------------------------------------------------------- 1 | module QUIC.Impl.Crypto 2 | 3 | module Cipher = EverCrypt.Cipher 4 | module AEAD = EverCrypt.AEAD 5 | module HKDF = EverCrypt.HKDF 6 | module CTR = EverCrypt.CTR 7 | module IB = LowStar.ImmutableBuffer 8 | module U32 = FStar.UInt32 9 | 10 | module Seq = QUIC.Secret.Seq 11 | module SecretBuffer = QUIC.Secret.Buffer 12 | 13 | module SHKDF = Spec.Agile.HKDF 14 | module SHD = Spec.Hash.Definitions 15 | 16 | friend QUIC.Spec.Crypto (* for the _l list constants *) 17 | module Spec = QUIC.Spec.Crypto 18 | 19 | open LowStar.BufferOps (* for the !* notation *) 20 | 21 | 22 | /// Helpers & globals 23 | /// ----------------- 24 | 25 | open QUIC.Impl.Lemmas 26 | 27 | inline_for_extraction noextract 28 | let u32_of_u8 = FStar.Int.Cast.uint8_to_uint32 29 | inline_for_extraction noextract 30 | let u64_of_u8 = FStar.Int.Cast.uint8_to_uint64 31 | inline_for_extraction noextract 32 | let u64_of_u32 = FStar.Int.Cast.uint32_to_uint64 33 | 34 | #push-options "--warn_error -272" 35 | let label_key = LowStar.ImmutableBuffer.igcmalloc_of_list HS.root label_key_l 36 | let label_iv = LowStar.ImmutableBuffer.igcmalloc_of_list HS.root label_iv_l 37 | let label_hp = LowStar.ImmutableBuffer.igcmalloc_of_list HS.root label_hp_l 38 | let prefix = LowStar.ImmutableBuffer.igcmalloc_of_list HS.root prefix_l 39 | #pop-options 40 | 41 | /// Actual code 42 | /// ----------- 43 | 44 | #push-options "--z3rlimit 100" 45 | let derive_secret a dst dst_len secret label label_len = 46 | LowStar.ImmutableBuffer.recall prefix; 47 | LowStar.ImmutableBuffer.recall_contents prefix Spec.prefix; 48 | (**) let h0 = HST.get () in 49 | 50 | HST.push_frame (); 51 | (**) let h1 = HST.get () in 52 | 53 | let label_len32 = FStar.Int.Cast.uint8_to_uint32 label_len in 54 | let dst_len32 = FStar.Int.Cast.uint8_to_uint32 dst_len in 55 | let info_len = U32.(1ul +^ 1ul +^ 1ul +^ 11ul +^ label_len32 +^ 1ul) in 56 | let info = B.alloca 0uy info_len in 57 | 58 | // : best way to reason about this sort of code is to slice the buffer very thinly 59 | let info_z = B.sub info 0ul 1ul in 60 | let info_lb = B.sub info 1ul 1ul in 61 | let info_llen = B.sub info 2ul 1ul in 62 | let info_prefix = B.sub info 3ul 11ul in 63 | let info_label = B.sub info 14ul label_len32 in 64 | let info_z' = B.sub info (14ul `U32.add` label_len32) 1ul in 65 | (**) assert (14ul `U32.add` label_len32 `U32.add` 1ul = B.len info); 66 | (**) assert B.(all_disjoint [ loc_buffer info_z; loc_buffer info_lb; loc_buffer info_llen; 67 | (**) loc_buffer info_prefix; loc_buffer info_label; loc_buffer info_z' ]); 68 | 69 | info_lb.(0ul) <- dst_len; 70 | info_llen.(0ul) <- U8.(label_len +^ 11uy); 71 | B.blit prefix 0ul info_prefix 0ul 11ul; 72 | B.blit label 0ul info_label 0ul label_len32; 73 | 74 | (**) let h2 = HST.get () in 75 | (**) assert ( 76 | (**) let z = Seq.create 1 0uy in 77 | (**) let lb = Seq.create 1 dst_len in // len <= 255 78 | (**) let llen = Seq.create 1 (U8.uint_to_t (11 + Seq.length (B.as_seq h0 label))) in 79 | (**) let info = B.as_seq h2 info in 80 | (**) B.as_seq h2 info_z `Seq.equal` z /\ 81 | (**) B.as_seq h2 info_lb `Seq.equal` lb /\ 82 | (**) B.as_seq h2 info_llen `Seq.equal` llen /\ 83 | (**) B.as_seq h2 info_prefix `Seq.equal` Spec.prefix /\ 84 | (**) B.as_seq h2 info_label `Seq.equal` (B.as_seq h0 label) /\ 85 | (**) B.as_seq h2 info_z' `Seq.equal` z 86 | (**) ); 87 | (**) ( 88 | (**) let z = Seq.create 1 0uy in 89 | (**) let lb = Seq.create 1 dst_len in // len <= 255 90 | (**) let llen = Seq.create 1 (U8.uint_to_t (11 + Seq.length (B.as_seq h0 label))) in 91 | (**) let info = B.as_seq h2 info in 92 | (**) lemma_five_cuts info 1 2 3 14 (14 + U8.v label_len) 93 | (**) z lb llen Spec.prefix (B.as_seq h0 label) z 94 | (**) ); 95 | (**) hash_is_keysized_ a; 96 | let h25 = HST.get () in 97 | SecretBuffer.with_whole_buffer_hide_weak_modifies 98 | #unit 99 | info 100 | h25 101 | (B.loc_buffer secret `B.loc_union` B.loc_buffer dst) 102 | (B.loc_buffer dst) 103 | false 104 | (fun _ cont m -> 105 | (SHD.hash_length a + B.length info + 1 + SHD.block_length a) `SHD.less_than_max_input_length` a /\ 106 | B.as_seq m dst == SHKDF.expand a (B.as_seq h25 secret) (Seq.seq_hide #Secret.U8 (B.as_seq h25 info)) (U32.v dst_len32) 107 | ) 108 | (fun _ bs -> 109 | HKDF.hash_block_length_fits a; 110 | HKDF.expand a dst secret (Hacl.Hash.Definitions.hash_len a) bs info_len dst_len32 111 | ); 112 | (**) let h3 = HST.get () in 113 | HST.pop_frame (); 114 | (**) let h4 = HST.get () in 115 | (**) B.modifies_fresh_frame_popped h0 h1 (B.loc_buffer dst) h3 h4; 116 | (**) assert (HST.equal_domains h0 h4) 117 | #pop-options 118 | -------------------------------------------------------------------------------- /src/Model.PNE.fst: -------------------------------------------------------------------------------- 1 | module Model.PNE 2 | 3 | module B = LowStar.Buffer 4 | module HS = FStar.HyperStack 5 | module I = Model.Indexing 6 | module U32 = FStar.UInt32 7 | module U128 = FStar.UInt128 8 | module Spec = Spec.Agile.Cipher 9 | 10 | module ST = FStar.HyperStack.ST 11 | 12 | #set-options "--fuel 0 --ifuel 0" 13 | 14 | open FStar.HyperStack 15 | open Mem 16 | open Model.Helpers 17 | open LowStar.BufferOps 18 | 19 | let clip_cipherpad cp l = 20 | let cipher, bits = cp in 21 | Seq.slice cipher 0 l, bits 22 | 23 | let log (#i: id) (u: info i): Type0 = 24 | Seq.seq (entry #i u) 25 | 26 | let model_state j = 27 | u:info j & B.pointer (log #j u) 28 | 29 | let unsafe_state j = 30 | // I don't understand why we have to go through model.indexing here when 31 | // the algorithm is readily available in the info 32 | info j & Spec.key (I.pne_id_ginfo j) 33 | 34 | // why is this type parameterized over the info? 35 | let pne_state #j u = 36 | if is_safe j then 37 | s:model_state j { dfst s == u } 38 | else 39 | s:unsafe_state j { fst s == u } 40 | 41 | let table #j #u st h = 42 | let (| u, p |) = st <: model_state j in 43 | B.deref h p 44 | 45 | let key #j #u st = 46 | snd (st <: unsafe_state j) 47 | 48 | let footprint #i #u w = 49 | if is_safe i then 50 | B.loc_addr_of_buffer (dsnd (w <: model_state i)) 51 | else 52 | B.loc_none 53 | 54 | let invariant #i #u st h = 55 | if is_safe i then 56 | B.live h (dsnd (st <: model_state i)) 57 | else 58 | True 59 | 60 | let frame_invariant #_ #_ _ _ _ _ = 61 | () 62 | 63 | let frame_table #_ #_ _ _ _ _ = 64 | () 65 | 66 | let create j u = 67 | if is_safe j then 68 | let l: log #j u = Seq.empty #(entry #j u) in 69 | ((| u, B.malloc q_pne_region l 1ul |) <: model_state j) 70 | else 71 | (u, random (Spec.key_length u.calg)) <: unsafe_state j 72 | 73 | let coerce j u k = 74 | (u, k) <: unsafe_state j 75 | 76 | let quic_coerce j u ts = 77 | let k = 78 | (QUIC.Spec.derive_secret u.halg ts 79 | QUIC.Spec.label_hp (key_len u)) in 80 | coerce j u k 81 | 82 | let random_bits (): 83 | HyperStack.ST.ST bits 84 | (requires fun h0 -> True) 85 | (ensures fun h0 _ h1 -> h0 == h1) 86 | = 87 | let r = random 1 in 88 | LowParse.BitFields.get_bitfield #8 (UInt8.v (Lib.RawIntTypes.u8_to_UInt8 (Seq.index r 0))) 0 5 89 | 90 | let encrypt #j #u st #l n s = 91 | let h0 = ST.get () in 92 | if is_safe j then 93 | let (| u, p |) = st <: model_state j in 94 | let log = !*p in 95 | assert (log == table st h0); 96 | let cipher: pne_cipherpad = random 4, random_bits () in 97 | p *= Seq.snoc log (Entry s #l n cipher); 98 | clip_cipherpad cipher l 99 | else 100 | let open QUIC.Spec.Lemmas in 101 | let pn, bits = PNEPlainPkg?.repr u.plain j l n in 102 | let k = snd (st <: unsafe_state j) in 103 | let alg = (fst (st <: unsafe_state j)).calg in 104 | encrypt_spec alg l pn bits s k 105 | 106 | #push-options "--fuel 1" 107 | let snoc_find #a (s: Seq.seq a) (f: a -> bool) (x: a): Lemma 108 | (requires f x /\ None? FStar.Seq.(find_l f s)) 109 | (ensures FStar.Seq.(find_l f (snoc s x)) == Some x) 110 | = 111 | assert (Seq.snoc s x `Seq.equal` Seq.append s (Seq.create 1 x)); 112 | Seq.find_append_none s (Seq.create 1 x) f; 113 | () 114 | #pop-options 115 | 116 | let decrypt #j #u st cp s = 117 | if is_safe j then 118 | let (| info, p |) = st <: model_state j in 119 | let log = !*p in 120 | match Seq.find_l (sample_filter u s) log with 121 | | Some (Entry _ #l' n' c') -> 122 | // The sample is present in the table, cipher may or may not match, it's 123 | // up to the caller to prove that when there's a match (i.e. c' == cp) 124 | // then c'' == zeroes which then entails that the returns value is the 125 | // plaintext that was in the table 126 | let c'' = c' `xor_cipherpad` cp in 127 | PNEPlainPkg?.xor u.plain j l' n' c'' 128 | | None -> 129 | // Need to add into the table: 130 | let bits = random_bits () in 131 | let l = LowParse.BitFields.get_bitfield bits 0 2 + 1 in 132 | let c' = random 4, bits in 133 | // let n' = clip_cipherpad (c' `xor_cipherpad` cp) l in 134 | let r = random l in 135 | let n = PNEPlainPkg?.mk u.plain j l r bits in 136 | let new_log = Seq.snoc log (Entry s #l n c') in 137 | p *= new_log; 138 | snoc_find log (sample_filter u s) (Entry s #l n c'); 139 | let h1 = ST.get () in 140 | let r = PNEPlainPkg?.xor u.plain j l n (c' `xor_cipherpad` cp) in 141 | assert ( 142 | let entry = entry_for_sample s st h1 in 143 | Some? entry /\ ( 144 | let Some (Entry _ #l' n' c') = entry in 145 | r == PNEPlainPkg?.xor u.plain j l' n' (c' `xor_cipherpad` cp))); 146 | r 147 | else 148 | let info, k = st <: unsafe_state j in 149 | decrypt_spec info.calg (fst cp) (snd cp) k s 150 | 151 | -------------------------------------------------------------------------------- /dist/EverQuic.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef __EverQuic_H 4 | #define __EverQuic_H 5 | 6 | #include "EverQuic_EverCrypt.h" 7 | #include "krml/internal/target.h" 8 | #include "krml/internal/types.h" 9 | #include "krml/lowstar_endianness.h" 10 | #include 11 | #include 12 | #include 13 | 14 | #define EverQuic_BInitial 0 15 | #define EverQuic_BZeroRTT 1 16 | #define EverQuic_BHandshake 2 17 | #define EverQuic_BRetry 3 18 | 19 | typedef uint8_t EverQuic_long_header_specifics_tags; 20 | 21 | typedef struct EverQuic_long_header_specifics_s 22 | { 23 | EverQuic_long_header_specifics_tags tag; 24 | union { 25 | struct 26 | { 27 | uint8_t reserved_bits; 28 | uint64_t payload_and_pn_length; 29 | uint32_t packet_number_length; 30 | uint8_t *token; 31 | uint32_t token_length; 32 | } 33 | case_BInitial; 34 | struct 35 | { 36 | uint8_t reserved_bits; 37 | uint64_t payload_and_pn_length; 38 | uint32_t packet_number_length; 39 | } 40 | case_BZeroRTT; 41 | struct 42 | { 43 | uint8_t reserved_bits; 44 | uint64_t payload_and_pn_length; 45 | uint32_t packet_number_length; 46 | } 47 | case_BHandshake; 48 | struct 49 | { 50 | uint8_t unused; 51 | uint8_t *odcid; 52 | uint32_t odcil; 53 | } 54 | case_BRetry; 55 | } 56 | ; 57 | } 58 | EverQuic_long_header_specifics; 59 | 60 | #define EverQuic_BLong 0 61 | #define EverQuic_BShort 1 62 | 63 | typedef uint8_t EverQuic_header_tags; 64 | 65 | typedef struct EverQuic_header_s 66 | { 67 | EverQuic_header_tags tag; 68 | union { 69 | struct 70 | { 71 | uint32_t version; 72 | uint8_t *dcid; 73 | uint32_t dcil; 74 | uint8_t *scid; 75 | uint32_t scil; 76 | EverQuic_long_header_specifics spec; 77 | } 78 | case_BLong; 79 | struct 80 | { 81 | uint8_t reserved_bits; 82 | bool spin; 83 | uint8_t phase; 84 | uint8_t *cid; 85 | uint32_t cid_len; 86 | uint32_t packet_number_length; 87 | } 88 | case_BShort; 89 | } 90 | ; 91 | } 92 | EverQuic_header; 93 | 94 | typedef struct EverQuic_result_s EverQuic_result; 95 | 96 | typedef struct EverQuic_result_s 97 | { 98 | uint64_t pn; 99 | EverQuic_header header; 100 | uint32_t header_len; 101 | uint32_t plain_len; 102 | uint32_t total_len; 103 | } 104 | EverQuic_result; 105 | 106 | typedef struct EverQuic_index_s 107 | { 108 | Spec_Hash_Definitions_hash_alg hash_alg; 109 | Spec_Agile_AEAD_alg aead_alg; 110 | } 111 | EverQuic_index; 112 | 113 | typedef struct EverQuic_state_s_s EverQuic_state_s; 114 | 115 | bool EverQuic_uu___is_State(EverQuic_index i, EverQuic_state_s projectee); 116 | 117 | typedef EverQuic_state_s *EverQuic_state; 118 | 119 | typedef void *EverQuic_invariant_s; 120 | 121 | typedef void *EverQuic_invariant; 122 | 123 | Spec_Agile_AEAD_alg EverQuic_aead_alg_of_state(EverQuic_state_s *s); 124 | 125 | Spec_Hash_Definitions_hash_alg EverQuic_hash_alg_of_state(EverQuic_state_s *s); 126 | 127 | uint64_t EverQuic_last_packet_number_of_state(EverQuic_state_s *s); 128 | 129 | EverCrypt_Error_error_code 130 | EverQuic_create_in( 131 | EverQuic_index i, 132 | EverQuic_state_s **dst, 133 | uint64_t initial_pn, 134 | uint8_t *traffic_secret 135 | ); 136 | 137 | EverCrypt_Error_error_code 138 | EverQuic_encrypt( 139 | EverQuic_state_s *s, 140 | uint8_t *dst, 141 | uint64_t *dst_pn, 142 | EverQuic_header h, 143 | uint8_t *plain, 144 | uint32_t plain_len 145 | ); 146 | 147 | void 148 | EverQuic_initial_secrets( 149 | uint8_t *dst_client, 150 | uint8_t *dst_server, 151 | uint8_t *cid, 152 | uint32_t cid_len 153 | ); 154 | 155 | typedef void *EverQuic_decrypt_post; 156 | 157 | EverCrypt_Error_error_code 158 | EverQuic_decrypt( 159 | EverQuic_state_s *s, 160 | EverQuic_result *dst, 161 | uint8_t *packet, 162 | uint32_t len, 163 | uint8_t cid_len 164 | ); 165 | 166 | bool EverQuic_uu___is_BInitial(EverQuic_long_header_specifics projectee); 167 | 168 | bool EverQuic_uu___is_BZeroRTT(EverQuic_long_header_specifics projectee); 169 | 170 | bool EverQuic_uu___is_BHandshake(EverQuic_long_header_specifics projectee); 171 | 172 | bool EverQuic_uu___is_BRetry(EverQuic_long_header_specifics projectee); 173 | 174 | bool EverQuic_uu___is_BLong(EverQuic_header projectee); 175 | 176 | bool EverQuic_uu___is_BShort(EverQuic_header projectee); 177 | 178 | uint32_t EverQuic_dcid_len(EverQuic_header h); 179 | 180 | bool EverQuic_is_retry(EverQuic_header h); 181 | 182 | uint32_t EverQuic_pn_length(EverQuic_header h); 183 | 184 | bool EverQuic_has_payload_length(EverQuic_header h); 185 | 186 | uint64_t EverQuic_payload_and_pn_length(EverQuic_header h); 187 | 188 | uint64_t EverQuic_payload_length(EverQuic_header h); 189 | 190 | typedef void *EverQuic_header_live; 191 | 192 | uint32_t EverQuic_public_header_len(EverQuic_header h); 193 | 194 | uint32_t EverQuic_header_len(EverQuic_header h); 195 | 196 | 197 | #define __EverQuic_H_DEFINED 198 | #endif 199 | -------------------------------------------------------------------------------- /src/QUIC.Secret.Seq.fsti: -------------------------------------------------------------------------------- 1 | module QUIC.Secret.Seq 2 | include FStar.Seq 3 | 4 | module Secret = QUIC.Secret.Int 5 | module U8 = FStar.UInt8 6 | module Ghost = FStar.Ghost 7 | 8 | noextract 9 | val seq_hide 10 | (#t: Secret.inttype { Secret.unsigned t }) 11 | (x: seq (Secret.uint_t t Secret.PUB)) 12 | : Tot (seq (Secret.uint_t t Secret.SEC)) 13 | 14 | val seq_hide_length 15 | (#t: Secret.inttype { Secret.unsigned t }) 16 | (x: seq (Secret.uint_t t Secret.PUB)) 17 | : Lemma 18 | (length (seq_hide x) == length x) 19 | [SMTPat (length (seq_hide x))] 20 | 21 | val seq_hide_index 22 | (#t: Secret.inttype { Secret.unsigned t }) 23 | (x: seq (Secret.uint_t t Secret.PUB)) 24 | (i: nat) 25 | : Lemma 26 | (requires (i < length x)) 27 | (ensures ( 28 | Secret.v (index (seq_hide x) i) == Secret.v (index x i) 29 | )) 30 | 31 | let seq_hide_index' 32 | (#t: Secret.inttype { Secret.unsigned t }) 33 | (x: seq (Secret.uint_t t Secret.PUB)) 34 | (i: nat) 35 | : Lemma 36 | (requires (i < length x)) 37 | (ensures ( 38 | index (seq_hide x) i == Secret.hide #t (index x i) 39 | )) 40 | [SMTPat (index (seq_hide x) i)] 41 | = seq_hide_index x i 42 | 43 | val seq_reveal 44 | (#t: Secret.inttype { Secret.unsigned t }) 45 | (#sec: Secret.secrecy_level) 46 | (x: seq (Secret.uint_t t sec)) 47 | : GTot (seq (Secret.uint_t t Secret.PUB)) 48 | 49 | val seq_reveal_length 50 | (#t: Secret.inttype { Secret.unsigned t }) 51 | (#sec: Secret.secrecy_level) 52 | (x: seq (Secret.uint_t t sec)) 53 | : Lemma 54 | (length (seq_reveal x) == length x) 55 | [SMTPat (length (seq_reveal x))] 56 | 57 | val seq_reveal_index 58 | (#t: Secret.inttype { Secret.unsigned t }) 59 | (#sec: Secret.secrecy_level) 60 | (x: seq (Secret.uint_t t sec)) 61 | (i: nat) 62 | : Lemma 63 | (requires (i < length x)) 64 | (ensures ( 65 | Secret.v (index (seq_reveal x) i) == Secret.v (index x i) 66 | )) 67 | 68 | let seq_reveal_index' 69 | (#t: Secret.inttype { Secret.unsigned t }) 70 | (#sec: Secret.secrecy_level) 71 | (x: seq (Secret.uint_t t sec)) 72 | (i: nat) 73 | : Lemma 74 | (requires (i < length x)) 75 | (ensures ( 76 | index (seq_reveal x) i == Secret.reveal (index x i) 77 | )) 78 | [SMTPat (index (seq_reveal x) i)] 79 | = seq_reveal_index x i 80 | 81 | let seq_reveal_pub 82 | (#t: Secret.inttype { Secret.unsigned t }) 83 | (x: seq (Secret.uint_t t Secret.PUB)) 84 | : Lemma 85 | (seq_reveal x `equal` x) 86 | = () 87 | 88 | let seq_reveal_hide 89 | (#t: Secret.inttype { Secret.unsigned t }) 90 | (x: seq (Secret.uint_t t Secret.PUB)) 91 | : Lemma 92 | (seq_reveal (seq_hide x) `equal` x) 93 | [SMTPat (seq_reveal (seq_hide x))] 94 | = () 95 | 96 | let seq_hide_reveal 97 | (#t: Secret.inttype { Secret.unsigned t }) 98 | (x: seq (Secret.uint_t t Secret.SEC)) 99 | : Lemma 100 | (seq_hide (seq_reveal x) `equal` x) 101 | [SMTPat (seq_hide (seq_reveal x))] 102 | = () 103 | 104 | let seq_reveal_inj 105 | (#t: Secret.inttype { Secret.unsigned t }) 106 | (#sec: Secret.secrecy_level) 107 | (x1 x2: seq (Secret.uint_t t sec)) 108 | : Lemma 109 | (requires (seq_reveal x1 `equal` seq_reveal x2)) 110 | (ensures (x1 `equal` x2)) 111 | = match sec with 112 | | Secret.PUB -> seq_reveal_pub #t x1; seq_reveal_pub #t x2 113 | | Secret.SEC -> seq_hide_reveal #t x1; seq_hide_reveal #t x2 114 | 115 | let seq_hide_inj 116 | (#t: Secret.inttype { Secret.unsigned t }) 117 | (x1 x2: seq (Secret.uint_t t Secret.PUB)) 118 | : Lemma 119 | (requires (seq_hide x1 `equal` seq_hide x2)) 120 | (ensures (x1 `equal` x2)) 121 | = seq_reveal_hide #t x1; seq_reveal_hide #t x2 122 | 123 | (* Properties *) 124 | 125 | let slice_seq_hide 126 | (#t: Secret.inttype { Secret.unsigned t }) 127 | (x: seq (Secret.uint_t t Secret.PUB)) 128 | (from: nat) 129 | (to: nat { from <= to /\ to <= length x }) 130 | : Lemma 131 | (slice (seq_hide x) from to == seq_hide (slice x from to)) 132 | [SMTPat (slice (seq_hide x) from to)] 133 | = assert (slice (seq_hide x) from to `equal` seq_hide (slice x from to)) 134 | 135 | let reveal_seq_slice 136 | (#t: Secret.inttype { Secret.unsigned t }) 137 | (#sec: Secret.secrecy_level) 138 | (x: seq (Secret.uint_t t sec)) 139 | (from: nat) 140 | (to: nat { from <= to /\ to <= length x }) 141 | : Lemma 142 | (slice (seq_reveal x) from to == seq_reveal (slice x from to)) 143 | [SMTPat (slice (seq_reveal x) from to)] 144 | = assert (slice (seq_reveal x) from to `equal` seq_reveal (slice x from to)) 145 | 146 | let cons_seq_hide 147 | (#t: Secret.inttype { Secret.unsigned t }) 148 | (a: Secret.uint_t t Secret.PUB) 149 | (x: seq (Secret.uint_t t Secret.PUB)) 150 | : Lemma 151 | (cons (Secret.hide a) (seq_hide x) == seq_hide (cons a x)) 152 | = assert (cons (Secret.hide a) (seq_hide x) `equal` seq_hide (cons a x)) 153 | 154 | let cons_seq_reveal 155 | (#t: Secret.inttype { Secret.unsigned t }) 156 | (#sec: Secret.secrecy_level) 157 | (a: Secret.uint_t t sec) 158 | (x: seq (Secret.uint_t t sec)) 159 | : Lemma 160 | (cons (Secret.reveal a) (seq_reveal x) == seq_reveal (cons a x)) 161 | = assert (cons (Secret.reveal a) (seq_reveal x) `equal` seq_reveal (cons a x)) 162 | -------------------------------------------------------------------------------- /src/QUIC.Spec.Header.Base.fst: -------------------------------------------------------------------------------- 1 | module QUIC.Spec.Header.Base 2 | include QUIC.Spec.Base 3 | 4 | module FB = FStar.Bytes 5 | module U62 = QUIC.UInt62 6 | module U64 = FStar.UInt64 7 | module U32 = FStar.UInt32 8 | module U8 = FStar.UInt8 9 | module S = FStar.Seq 10 | module PN = QUIC.Spec.PacketNumber.Base 11 | module Cast = FStar.Int.Cast 12 | 13 | noeq 14 | type long_header_specifics = 15 | | MInitial: 16 | (reserved_bits: bitfield 2) -> 17 | (token: vlbytes 0 token_max_len) -> // arbitrary bound 18 | (payload_and_pn_length: payload_and_pn_length_t) -> 19 | (packet_number_length: PN.packet_number_length_t) -> 20 | (packet_number: PN.packet_number_t) -> 21 | long_header_specifics 22 | | MZeroRTT: 23 | (reserved_bits: bitfield 2) -> 24 | (payload_and_pn_length: payload_and_pn_length_t) -> 25 | (packet_number_length: PN.packet_number_length_t) -> 26 | (packet_number: PN.packet_number_t) -> 27 | long_header_specifics 28 | | MHandshake: 29 | (reserved_bits: bitfield 2) -> 30 | (payload_and_pn_length: payload_and_pn_length_t) -> 31 | (packet_number_length: PN.packet_number_length_t) -> 32 | (packet_number: PN.packet_number_t) -> 33 | long_header_specifics 34 | | MRetry: 35 | (unused: bitfield 4) -> 36 | (odcid: vlbytes 0 20) -> // TODO: change bounds to drop instead of rejecting as invalid 37 | long_header_specifics 38 | 39 | noeq 40 | type header = 41 | | MLong: 42 | (version: U32.t) -> 43 | (dcid: vlbytes 0 20) -> 44 | (scid: vlbytes 0 20) -> 45 | (spec: long_header_specifics) -> 46 | header 47 | | MShort: 48 | (reserved_bits: bitfield 2) -> 49 | (spin: bool) -> 50 | (key_phase: bool) -> 51 | (dcid: vlbytes 0 20) -> 52 | (packet_number_length: PN.packet_number_length_t) -> 53 | (packet_number: PN.packet_number_t) -> 54 | header 55 | 56 | let is_initial (h: header) : Tot bool = 57 | if MLong? h then MInitial? (MLong?.spec h) else false 58 | 59 | let is_zero_rtt (h: header) : Tot bool = 60 | if MLong? h then MZeroRTT? (MLong?.spec h) else false 61 | 62 | let is_handshake (h: header) : Tot bool = 63 | if MLong? h then MHandshake? (MLong?.spec h) else false 64 | 65 | let is_retry (h: header) : Tot bool = 66 | if MLong? h then MRetry? (MLong?.spec h) else false 67 | 68 | let reserved_bits (h: header { ~ (is_retry h) }) : Tot (bitfield 2) = 69 | match h with 70 | | MLong _ _ _ spec -> 71 | begin match spec with 72 | | MInitial pb _ _ _ _ -> pb 73 | | MZeroRTT pb _ _ _ -> pb 74 | | MHandshake pb _ _ _ -> pb 75 | end 76 | | MShort pb _ _ _ _ _ -> pb 77 | 78 | let pn_length (h: header { ~ (is_retry h) }) : Tot PN.packet_number_length_t = 79 | match h with 80 | | MLong _ _ _ spec -> 81 | begin match spec with 82 | | MInitial _ _ _ pnl _ -> pnl 83 | | MZeroRTT _ _ pnl _ -> pnl 84 | | MHandshake _ _ pnl _ -> pnl 85 | end 86 | | MShort _ _ _ _ pnl _ -> pnl 87 | 88 | let packet_number (h: header {~ (is_retry h)}) : Tot PN.packet_number_t = 89 | match h with 90 | | MLong _ _ _ spec -> 91 | begin match spec with 92 | | MInitial _ _ _ _ pn -> pn 93 | | MZeroRTT _ _ _ pn -> pn 94 | | MHandshake _ _ _ pn -> pn 95 | end 96 | | MShort _ _ _ _ _ pn -> pn 97 | 98 | let dcid_len (h: header) : Tot nat = 99 | match h with 100 | | MLong _ dcid _ _ -> FB.length dcid 101 | | MShort _ _ _ dcid _ _ -> FB.length dcid 102 | 103 | (* Payload length *) 104 | 105 | let has_payload_length 106 | (h: header) 107 | : Tot bool 108 | = MLong? h && (not (MRetry? (MLong?.spec h))) 109 | 110 | let payload_and_pn_length 111 | (h: header { has_payload_length h }) 112 | : Tot U62.t 113 | = match MLong?.spec h with 114 | | MInitial _ _ pl _ _ -> pl 115 | | MZeroRTT _ pl _ _ -> pl 116 | | MHandshake _ pl _ _ -> pl 117 | 118 | module Secret = QUIC.Secret.Int 119 | 120 | let payload_length 121 | (h: header { has_payload_length h }) 122 | : Tot U62.secret 123 | = match MLong?.spec h with 124 | | MInitial _ _ pl pnl _ -> Secret.to_u64 pl `Secret.sub` Secret.to_u64 pnl 125 | | MZeroRTT _ pl pnl _ -> Secret.to_u64 pl `Secret.sub` Secret.to_u64 pnl 126 | | MHandshake _ pl pnl _ -> Secret.to_u64 pl `Secret.sub` Secret.to_u64 pnl 127 | 128 | 129 | (* Correctness of a packet wrt. parsing parameters (cid_len, window) *) 130 | 131 | let is_valid_header (h: header) (cid_len: nat) (last: nat) : Tot Type0 = 132 | (MShort? h ==> dcid_len h == cid_len) /\ 133 | ((~ (is_retry h)) ==> PN.in_window (Secret.v (pn_length h) - 1) last (Secret.v (packet_number h))) 134 | 135 | (* Explicit length computation is needed for the switch. *) 136 | 137 | let header_len 138 | (h: header) 139 | : GTot (n: pos { n <= header_len_bound }) 140 | = match h with 141 | | MShort _ _ _ dcid packet_number_length _ -> 142 | 1 + FB.length dcid + Secret.v packet_number_length 143 | | MLong version dcid scid spec -> 144 | 7 + FB.length dcid + FB.length scid + 145 | begin match spec with 146 | | MInitial _ token payload_and_pn_length packet_number_length _ -> 147 | varint_len (Cast.uint32_to_uint64 (FB.len token)) + FB.length token + varint_len payload_and_pn_length + Secret.v packet_number_length 148 | | MZeroRTT _ payload_and_pn_length packet_number_length _ -> 149 | varint_len payload_and_pn_length + Secret.v packet_number_length 150 | | MHandshake _ payload_and_pn_length packet_number_length _ -> 151 | varint_len payload_and_pn_length + Secret.v packet_number_length 152 | | MRetry _ odcid -> 153 | 1 + FB.length odcid 154 | end 155 | 156 | -------------------------------------------------------------------------------- /src/QUIC.Spec.Header.Parse.fsti: -------------------------------------------------------------------------------- 1 | module QUIC.Spec.Header.Parse 2 | include QUIC.Spec.Header.Base 3 | 4 | module U8 = FStar.UInt8 5 | module U32 = FStar.UInt32 6 | module S = FStar.Seq 7 | module U64 = FStar.UInt64 8 | module Secret = QUIC.Secret.Int 9 | 10 | val format_header: h:header -> GTot (lbytes (header_len h)) 11 | 12 | module BF = LowParse.BitFields 13 | 14 | val format_header_is_short: h: header -> Lemma 15 | (MShort? h <==> BF.get_bitfield (U8.v (S.index (format_header h) 0)) 7 8 == 0) 16 | 17 | val format_header_is_retry: h: header -> Lemma 18 | (is_retry h <==> ( 19 | BF.get_bitfield (U8.v (S.index (format_header h) 0)) 7 8 == 1 /\ 20 | BF.get_bitfield (U8.v (S.index (format_header h) 0)) 4 6 == 3 21 | )) 22 | 23 | val format_header_pn_length: h: header -> Lemma 24 | (requires (~ (is_retry h))) 25 | (ensures (BF.get_bitfield (U8.v (S.index (format_header h) 0)) 0 2 == Secret.v (pn_length h) - 1)) 26 | 27 | val pn_offset: (h: header { ~ (is_retry h) }) -> GTot (n: nat { 0 < n /\ n + Secret.v (pn_length h) == header_len h }) // need to know that packet number is the last field of the format 28 | 29 | val putative_pn_offset: (cid_len: nat) -> (x: bytes) -> GTot (y: option nat { 30 | match y with 31 | | None -> True 32 | | Some y -> 0 < y /\ y <= Seq.length x /\ y <= header_len_bound 33 | }) 34 | 35 | val putative_pn_offset_frame 36 | (cid_len: nat) 37 | (x1 x2: bytes) 38 | : Lemma 39 | (requires (match putative_pn_offset cid_len x1 with 40 | | None -> False 41 | | Some off -> 42 | off <= Seq.length x2 /\ 43 | Seq.slice x1 1 off `Seq.equal` Seq.slice x2 1 off /\ ( 44 | let f1 = Seq.index x1 0 in 45 | let f2 = Seq.index x2 0 in 46 | let is_short = BF.get_bitfield (U8.v f1) 7 8 = 0 in 47 | let number_of_protected_bits = if is_short then 5 else 4 in 48 | BF.get_bitfield (U8.v f1) number_of_protected_bits 8 == BF.get_bitfield (U8.v f2) number_of_protected_bits 8 49 | ))) 50 | (ensures (match putative_pn_offset cid_len x1 with 51 | | None -> False 52 | | Some off -> putative_pn_offset cid_len x2 == Some (off <: nat) 53 | )) 54 | 55 | val putative_pn_offset_correct 56 | (h: header {~ (is_retry h)}) 57 | (cid_len: nat { cid_len <= 20 }) 58 | : Lemma 59 | (requires (MShort? h ==> cid_len == dcid_len h)) 60 | (ensures (putative_pn_offset cid_len (format_header h) == Some (pn_offset h <: nat))) 61 | 62 | noeq 63 | type h_result = 64 | | H_Success: 65 | h: header -> 66 | c: bytes -> 67 | h_result 68 | | H_Failure 69 | 70 | val parse_header: cid_len: nat { cid_len <= 20 } -> last: nat { last + 1 < pow2 62 } -> b:bytes -> GTot (r: h_result { 71 | match r with 72 | | H_Failure -> True 73 | | H_Success h c -> 74 | is_valid_header h cid_len last /\ 75 | Seq.length c <= Seq.length b /\ 76 | c `Seq.equal` Seq.slice b (Seq.length b - Seq.length c) (Seq.length b) 77 | }) 78 | 79 | val lemma_header_parsing_correct: 80 | h: header -> 81 | c: bytes -> 82 | cid_len: nat { cid_len <= 20 } -> 83 | last: nat { last + 1 < pow2 62 } -> 84 | Lemma 85 | (requires ( 86 | is_valid_header h cid_len last 87 | )) 88 | (ensures ( 89 | parse_header cid_len last S.(format_header h @| c) 90 | == H_Success h c)) 91 | 92 | // N.B. this is only true for a given DCID len 93 | val lemma_header_parsing_safe: cid_len: nat -> last: nat -> b1:bytes -> b2:bytes -> Lemma 94 | (requires ( 95 | cid_len <= 20 /\ 96 | last + 1 < pow2 62 /\ 97 | parse_header cid_len last b1 == parse_header cid_len last b2 98 | )) 99 | (ensures parse_header cid_len last b1 == H_Failure \/ b1 = b2) 100 | 101 | let lemma_header_parsing_post 102 | (cid_len: nat { cid_len <= 20 }) 103 | (last: nat { last + 1 < pow2 62 }) 104 | (b: bytes) 105 | : Lemma 106 | (match parse_header cid_len last b with 107 | | H_Failure -> True 108 | | H_Success h c -> 109 | is_valid_header h cid_len last /\ 110 | header_len h + Seq.length c == Seq.length b /\ 111 | b == format_header h `Seq.append` c /\ 112 | Seq.slice b 0 (header_len h) == format_header h /\ 113 | c == Seq.slice b (header_len h) (Seq.length b) 114 | ) 115 | = match parse_header cid_len last b with 116 | | H_Failure -> () 117 | | H_Success h c -> 118 | lemma_header_parsing_correct h c cid_len last ; 119 | lemma_header_parsing_safe cid_len last b (format_header h `S.append` c); 120 | assert (b `Seq.equal` (format_header h `Seq.append` c)); 121 | assert (Seq.slice b 0 (header_len h) `Seq.equal` format_header h); 122 | assert (c `Seq.equal` Seq.slice b (header_len h) (Seq.length b)) 123 | 124 | let packet_is_retry 125 | (x: bytes) 126 | : GTot bool 127 | = if Seq.length x > 0 128 | then 129 | let f = S.index x 0 in 130 | BF.get_bitfield (U8.v f) 7 8 = 1 && 131 | BF.get_bitfield (U8.v f) 4 6 = 3 132 | else false 133 | 134 | val parse_header_exists 135 | (cid_len: nat { cid_len <= 20 }) 136 | (last: nat { last + 1 < pow2 62 }) 137 | (x:bytes) 138 | : Lemma 139 | (requires ( 140 | match putative_pn_offset cid_len x with 141 | | None -> False 142 | | Some off -> (~ (packet_is_retry x)) ==> off + 4 <= Seq.length x 143 | )) 144 | (ensures ( 145 | H_Success? (parse_header cid_len last x) 146 | )) 147 | 148 | val parse_header_exists_recip 149 | (cid_len: nat { cid_len <= 20 }) 150 | (last: nat { last + 1 < pow2 62 }) 151 | (x:bytes) 152 | : Lemma 153 | (requires ( 154 | H_Success? (parse_header cid_len last x) 155 | )) 156 | (ensures ( 157 | Some? (putative_pn_offset cid_len x) 158 | )) 159 | -------------------------------------------------------------------------------- /hints/NotEverCrypt.CTR.fsti.hints: -------------------------------------------------------------------------------- 1 | [ 2 | "30b9af3f40399ed42618a048d0eecd28", 3 | [ 4 | [ 5 | "NotEverCrypt.CTR.invariant", 6 | 1, 7 | 2, 8 | 1, 9 | [ 10 | "@MaxIFuel_assumption", "@query", "equation_LowStar.Buffer.pointer", 11 | "equation_NotEverCrypt.CTR.state", 12 | "projection_inverse_BoxInt_proj_0", 13 | "refinement_interpretation_Tm_refine_573cfed777dae20cc82e8fef9622857e" 14 | ], 15 | 0, 16 | "e63513708b82b5088397a95b23ece298" 17 | ], 18 | [ 19 | "NotEverCrypt.CTR.create_in_st", 20 | 1, 21 | 2, 22 | 1, 23 | [ 24 | "@MaxIFuel_assumption", "@query", "b2t_def", 25 | "constructor_distinct_Lib.IntTypes.U8", 26 | "equality_tok_Lib.IntTypes.U1@tok", 27 | "equality_tok_Lib.IntTypes.U8@tok", "equation_FStar.UInt.fits", 28 | "equation_FStar.UInt.min_int", "equation_FStar.UInt.size", 29 | "equation_Lib.IntTypes.minint", "equation_Lib.IntTypes.uint8", 30 | "equation_Lib.IntTypes.unsigned", "equation_Lib.Sequence.lseq", 31 | "equation_Lib.Sequence.seq", "equation_LowStar.Buffer.buffer", 32 | "equation_LowStar.Buffer.pointer_or_null", 33 | "equation_NotEverCrypt.CTR.uint8", "equation_Prims.eqtype", 34 | "equation_Prims.nat", "equation_Spec.AES.aes_key", 35 | "equation_Spec.AES.gf8", "equation_Spec.AES.irred", 36 | "equation_Spec.Agile.Cipher.key", 37 | "equation_Spec.Agile.Cipher.key_length", 38 | "equation_Spec.Chacha20.key", "equation_Spec.GaloisField.gf", 39 | "fuel_guarded_inversion_Spec.Agile.Cipher.cipher_alg", 40 | "function_token_typing_Lib.IntTypes.uint8", 41 | "function_token_typing_Prims.int", 42 | "haseqTm_refine_542f9d4f129664613f2483a6c88bc7c2", 43 | "lemma_LowStar.Monotonic.Buffer.length_as_seq", 44 | "primitive_Prims.op_AmpAmp", "primitive_Prims.op_LessThanOrEqual", 45 | "proj_equation_Spec.GaloisField.GF_t", 46 | "projection_inverse_BoxBool_proj_0", 47 | "projection_inverse_Spec.GaloisField.GF_t", 48 | "refinement_interpretation_Tm_refine_19d8d2f9c96051f779b12cd94ceba71d", 49 | "refinement_interpretation_Tm_refine_414d0a9f578ab0048252f8c8f552b99f", 50 | "refinement_interpretation_Tm_refine_cd18e9962a0d204005dcfcda04529ffc", 51 | "refinement_interpretation_Tm_refine_d8d83307254a8900dd20598654272e42", 52 | "refinement_interpretation_Tm_refine_de8080fdc4bd6678af723874a7d70466", 53 | "typing_LowStar.Buffer.trivial_preorder", "typing_Spec.AES.gf8", 54 | "typing_Spec.GaloisField.__proj__GF__item__t" 55 | ], 56 | 0, 57 | "eb8d6a6e549895886e2485988275a825" 58 | ], 59 | [ 60 | "NotEverCrypt.CTR.init", 61 | 1, 62 | 2, 63 | 1, 64 | [ 65 | "@MaxIFuel_assumption", "@query", "b2t_def", 66 | "constructor_distinct_Lib.IntTypes.U8", 67 | "equality_tok_Lib.IntTypes.U1@tok", 68 | "equality_tok_Lib.IntTypes.U8@tok", "equation_FStar.UInt.fits", 69 | "equation_FStar.UInt.min_int", "equation_FStar.UInt.size", 70 | "equation_Lib.IntTypes.minint", "equation_Lib.IntTypes.uint8", 71 | "equation_Lib.IntTypes.unsigned", "equation_Lib.Sequence.lseq", 72 | "equation_Lib.Sequence.seq", "equation_LowStar.Buffer.buffer", 73 | "equation_LowStar.Buffer.trivial_preorder", 74 | "equation_NotEverCrypt.CTR.uint8", "equation_Prims.eqtype", 75 | "equation_Prims.nat", "equation_Spec.AES.aes_key", 76 | "equation_Spec.AES.gf8", "equation_Spec.AES.irred", 77 | "equation_Spec.Agile.Cipher.key", 78 | "equation_Spec.Agile.Cipher.key_length", 79 | "equation_Spec.Chacha20.key", "equation_Spec.GaloisField.gf", 80 | "fuel_guarded_inversion_Spec.Agile.Cipher.cipher_alg", 81 | "function_token_typing_Lib.IntTypes.uint8", 82 | "function_token_typing_Prims.int", 83 | "haseqTm_refine_542f9d4f129664613f2483a6c88bc7c2", 84 | "lemma_LowStar.Monotonic.Buffer.length_as_seq", 85 | "lemma_LowStar.Monotonic.Buffer.modifies_buffer_elim", 86 | "primitive_Prims.op_AmpAmp", "primitive_Prims.op_LessThanOrEqual", 87 | "proj_equation_Spec.GaloisField.GF_t", 88 | "projection_inverse_BoxBool_proj_0", 89 | "projection_inverse_Spec.GaloisField.GF_t", 90 | "refinement_interpretation_Tm_refine_414d0a9f578ab0048252f8c8f552b99f", 91 | "refinement_interpretation_Tm_refine_ac3ceafd33cb9109a2f7b09243802765", 92 | "refinement_interpretation_Tm_refine_d8d83307254a8900dd20598654272e42", 93 | "refinement_interpretation_Tm_refine_de8080fdc4bd6678af723874a7d70466", 94 | "refinement_interpretation_Tm_refine_f2987b92671c38423f3d7c8601248229", 95 | "typing_LowStar.Buffer.trivial_preorder", 96 | "typing_NotEverCrypt.CTR.footprint", "typing_Spec.AES.gf8", 97 | "typing_Spec.GaloisField.__proj__GF__item__t" 98 | ], 99 | 0, 100 | "e5ce9a194ac11ee0ac27e173a975c8dd" 101 | ], 102 | [ 103 | "NotEverCrypt.CTR.update_block_st", 104 | 1, 105 | 2, 106 | 1, 107 | [ 108 | "@MaxIFuel_assumption", "@query", "equation_Lib.IntTypes.uint8", 109 | "equation_LowStar.Buffer.buffer", "equation_NotEverCrypt.CTR.uint8", 110 | "function_token_typing_Lib.IntTypes.uint8", 111 | "lemma_LowStar.Monotonic.Buffer.length_as_seq", 112 | "refinement_interpretation_Tm_refine_5ee71fe5c7930e31074d92947f42fe4b", 113 | "typing_LowStar.Buffer.trivial_preorder" 114 | ], 115 | 0, 116 | "c62af10f1bf63aa480adbf93b598eae6" 117 | ] 118 | ] 119 | ] -------------------------------------------------------------------------------- /src/QUIC.Secret.Int.fsti: -------------------------------------------------------------------------------- 1 | module QUIC.Secret.Int 2 | include QUIC.Secret.Int.Base 3 | 4 | module U8 = FStar.UInt8 5 | module U16 = FStar.UInt16 6 | module U32 = FStar.UInt32 7 | module U64 = FStar.UInt64 8 | module U = FStar.UInt 9 | module BF = LowParse.BitFields 10 | 11 | inline_for_extraction 12 | noextract 13 | val usub 14 | (#t: inttype { unsigned t }) 15 | (#sec: secrecy_level) 16 | (x: uint_t t sec) 17 | (y: uint_t t sec { v y <= v x }) 18 | : Tot (z: uint_t t sec { v z == v x - v y }) 19 | 20 | inline_for_extraction 21 | noextract 22 | val cast_up 23 | (#t1: inttype { unsigned t1 }) 24 | (t2: inttype { unsigned t2 /\ bits t1 <= bits t2 }) 25 | (#sec: secrecy_level) 26 | (x: uint_t t1 sec) 27 | : Tot (y: uint_t t2 SEC { v y == v x }) 28 | 29 | inline_for_extraction 30 | noextract 31 | val cast_down 32 | (#t1: inttype { unsigned t1 }) 33 | (t2: inttype { unsigned t2 }) 34 | (#sec: secrecy_level) 35 | (x: uint_t t1 sec { v x < pow2 (bits t2) } ) 36 | : Tot (y: uint_t t2 SEC { v y == v x }) 37 | 38 | inline_for_extraction 39 | noextract 40 | val hide 41 | (#t: inttype { unsigned t }) 42 | (#sec: secrecy_level) 43 | (x: uint_t t sec) 44 | : Tot (y: uint_t t SEC { v y == v x }) 45 | 46 | inline_for_extraction 47 | noextract 48 | val reveal 49 | (#t: inttype { unsigned t }) 50 | (#sec: secrecy_level) 51 | (x: uint_t t sec) 52 | : GTot (y: uint_t t PUB { v y == v x }) 53 | 54 | let hide_reveal 55 | (#t: inttype { unsigned t }) 56 | (x: uint_t t SEC) 57 | : Lemma 58 | (hide (reveal x) == x) 59 | [SMTPat (hide (reveal x))] 60 | = () 61 | 62 | let reveal_hide 63 | (#t: inttype { unsigned t }) 64 | (x: uint_t t PUB) 65 | : Lemma 66 | (reveal (hide x) == x) 67 | [SMTPat (reveal (hide x))] 68 | = () 69 | 70 | (* Patterns *) 71 | 72 | let logand_spec' 73 | (#t:inttype) 74 | (#l:secrecy_level) 75 | (a:int_t t l) 76 | (b:int_t t l) 77 | : Lemma (v (a `logand` b) == v a `logand_v` v b) 78 | [SMTPat (v (a `logand` b))] 79 | = logand_spec a b 80 | 81 | let logor_spec' 82 | (#t:inttype) 83 | (#l:secrecy_level) 84 | (a:int_t t l) 85 | (b:int_t t l) 86 | : Lemma (v (a `logor` b) == v a `logor_v` v b) 87 | [SMTPat (v (a `logor` b))] 88 | = logor_spec a b 89 | 90 | let logxor_spec' 91 | (#t:inttype) 92 | (#l:secrecy_level) 93 | (a:int_t t l) 94 | (b:int_t t l) 95 | : Lemma (v (a `logxor` b) == v a `logxor_v` v b) 96 | [SMTPat (v (a `logxor` b))] 97 | = logxor_spec a b 98 | 99 | inline_for_extraction 100 | noextract 101 | val lognot' 102 | (#t:inttype { supported_type t }) 103 | (#l:secrecy_level) 104 | (x: uint_t t l) 105 | : Tot (y: uint_t t l { v y == U.lognot #(bits t) (v x) }) 106 | 107 | (* Logic *) 108 | 109 | inline_for_extraction 110 | noextract 111 | val logand_one_bit 112 | (#t: inttype { supported_type t }) 113 | (#sec: secrecy_level) 114 | (x: int_t t sec { v x == 0 \/ v x == 1 }) 115 | (y: int_t t sec { v y == 0 \/ v y == 1 }) 116 | : Tot (z: int_t t sec { v z == (if v x = 1 && v y = 1 then 1 else 0) }) 117 | 118 | inline_for_extraction 119 | noextract 120 | val logor_one_bit 121 | (#t: inttype { supported_type t }) 122 | (#sec: secrecy_level) 123 | (x: int_t t sec { v x == 0 \/ v x == 1 }) 124 | (y: int_t t sec { v y == 0 \/ v y == 1 }) 125 | : Tot (z: int_t t sec { v z == (if v x = 1 || v y = 1 then 1 else 0) }) 126 | 127 | inline_for_extraction 128 | noextract 129 | val logxor_one_bit 130 | (#t: inttype { supported_type t }) 131 | (#sec: secrecy_level) 132 | (x: int_t t sec { v x == 0 \/ v x == 1 }) 133 | (y: int_t t sec { v y == 0 \/ v y == 1 }) 134 | : Tot (z: int_t t sec { v z == (if v x = v y then 0 else 1) }) 135 | 136 | inline_for_extraction 137 | noextract 138 | val secret_bool 139 | (#t: inttype { supported_type t }) 140 | (#sec: secrecy_level) 141 | (x: bool) 142 | : Tot (z: int_t t sec { v z == (if x then 1 else 0) }) 143 | 144 | inline_for_extraction 145 | noextract 146 | val lognot_one_bit 147 | (#t: inttype { supported_type t }) 148 | (#sec: secrecy_level) 149 | (x: int_t t sec { v x == 0 \/ v x == 1 }) 150 | : Tot (z: int_t t sec { v z == (if v x = 1 then 0 else 1) }) 151 | 152 | 153 | (* Bitfields of secret integers but public bit positions *) 154 | 155 | inline_for_extraction 156 | noextract 157 | val get_bitfield 158 | (#t: inttype { supported_type t }) 159 | (#l: secrecy_level) 160 | (x: uint_t t l) 161 | (lo: U32.t) 162 | (hi: U32.t { U32.v lo < U32.v hi /\ U32.v hi <= bits t }) 163 | : Tot (y: uint_t t l { v y == BF.get_bitfield #(bits t) (v x) (U32.v lo) (U32.v hi) }) 164 | 165 | inline_for_extraction 166 | noextract 167 | [@"opaque_to_smt"] 168 | val set_bitfield 169 | (#t: inttype { supported_type t }) 170 | (#l: secrecy_level) 171 | (x: uint_t t l) 172 | (lo: U32.t) 173 | (hi: U32.t { U32.v lo < U32.v hi /\ U32.v hi <= bits t }) 174 | (w: uint_t t l { v w < pow2 (U32.v hi - U32.v lo) }) 175 | : Tot (y: uint_t t l { v y == BF.set_bitfield #(bits t) (v x) (U32.v lo) (U32.v hi) (v w) }) 176 | 177 | (* Comparisons *) 178 | 179 | val secrets_are_equal_32_2 180 | (x: uint32 { v x < pow2 2 }) 181 | (y: uint32 { v y < pow2 2 }) 182 | : Tot (z: uint32 { 183 | v z == (if v x = v y then 1 else 0) 184 | }) 185 | 186 | val secret_is_le_64 187 | (x: uint64) 188 | (y: uint64) 189 | : Tot (z: uint64 { v z == (if v x <= v y then 1 else 0) }) 190 | 191 | val secret_is_lt_64 192 | (x: uint64) 193 | (y: uint64) 194 | : Tot (z: uint64 { v z == (if v x < v y then 1 else 0) }) 195 | 196 | val secrets_are_equal_64_2 197 | (x: uint64 { v x < pow2 2 }) 198 | (y: uint64 { v y < pow2 2 }) 199 | : Tot (z: uint64 { 200 | v z == (if v x = v y then 1 else 0) 201 | }) 202 | 203 | val secrets_are_equal_62 204 | (x: uint64 { v x < pow2 62 }) 205 | (y: uint64 { v y < pow2 62 }) 206 | : Tot (z: uint64 { 207 | v z == (if v x = v y then 1 else 0) 208 | }) 209 | 210 | val min64 211 | (x y: uint64) 212 | : Tot (z: uint64 { v z == (if v x <= v y then v x else v y) }) 213 | 214 | val max64 215 | (x y: uint64) 216 | : Tot (z: uint64 { v z == (if v y <= v x then v x else v y) }) 217 | -------------------------------------------------------------------------------- /hints/QUIC.Impl.Crypto.fsti.hints: -------------------------------------------------------------------------------- 1 | [ 2 | "998955813b65a6dd595a08ec1e7024b1", 3 | [ 4 | [ 5 | "QUIC.Impl.Crypto.derive_secret", 6 | 1, 7 | 2, 8 | 1, 9 | [ 10 | "@MaxFuel_assumption", "@MaxIFuel_assumption", 11 | "@fuel_correspondence_Prims.pow2.fuel_instrumented", 12 | "@fuel_irrelevance_Prims.pow2.fuel_instrumented", "@query", 13 | "bool_inversion", "constructor_distinct_FStar.Integers.Unsigned", 14 | "constructor_distinct_FStar.Integers.W16", 15 | "constructor_distinct_FStar.Integers.W32", 16 | "constructor_distinct_FStar.Integers.W64", 17 | "constructor_distinct_FStar.Integers.W8", 18 | "constructor_distinct_FStar.Pervasives.Native.Some", 19 | "constructor_distinct_Lib.IntTypes.PUB", 20 | "constructor_distinct_Lib.IntTypes.S128", 21 | "constructor_distinct_Lib.IntTypes.S32", 22 | "constructor_distinct_Lib.IntTypes.S64", 23 | "constructor_distinct_Lib.IntTypes.U1", 24 | "constructor_distinct_Lib.IntTypes.U128", 25 | "constructor_distinct_Lib.IntTypes.U16", 26 | "constructor_distinct_Lib.IntTypes.U32", 27 | "constructor_distinct_Lib.IntTypes.U64", 28 | "constructor_distinct_Lib.IntTypes.U8", 29 | "constructor_distinct_Spec.Hash.Definitions.SHA1", 30 | "constructor_distinct_Spec.Hash.Definitions.SHA2_256", 31 | "constructor_distinct_Spec.Hash.Definitions.SHA2_384", 32 | "constructor_distinct_Spec.Hash.Definitions.SHA2_512", 33 | "disc_equation_FStar.Pervasives.Native.Some", 34 | "equality_tok_FStar.Integers.W16@tok", 35 | "equality_tok_FStar.Integers.W32@tok", 36 | "equality_tok_FStar.Integers.W64@tok", 37 | "equality_tok_FStar.Integers.W8@tok", 38 | "equality_tok_Lib.IntTypes.PUB@tok", 39 | "equality_tok_Lib.IntTypes.U1@tok", 40 | "equality_tok_Lib.IntTypes.U8@tok", 41 | "equality_tok_Spec.Hash.Definitions.SHA2_384@tok", 42 | "equality_tok_Spec.Hash.Definitions.SHA2_512@tok", 43 | "equation_FStar.Integers.int_t", "equation_FStar.Integers.uint_8", 44 | "equation_Lib.IntTypes.byte_t", "equation_Lib.IntTypes.int_t", 45 | "equation_Lib.IntTypes.minint", "equation_Lib.IntTypes.pub_int_t", 46 | "equation_Lib.IntTypes.uint8", "equation_Lib.IntTypes.unsigned", 47 | "equation_LowStar.Buffer.buffer", 48 | "equation_LowStar.Buffer.trivial_preorder", 49 | "equation_LowStar.ImmutableBuffer.ibuffer", 50 | "equation_LowStar.ImmutableBuffer.immutable_preorder", 51 | "equation_Prims.eqtype", "equation_Prims.nat", "equation_Prims.pos", 52 | "equation_QUIC.Spec.Base.byte", "equation_QUIC.Spec.Crypto.ha", 53 | "equation_QUIC.Spec.Crypto.keysized", 54 | "equation_QUIC.Spec.Crypto.supported_hash", "equation_Spec.AES.gf8", 55 | "equation_Spec.AES.irred", "equation_Spec.Chacha20.size_key", 56 | "equation_Spec.GaloisField.gf", 57 | "equation_Spec.Hash.Definitions.block_length", 58 | "equation_Spec.Hash.Definitions.block_word_length", 59 | "equation_Spec.Hash.Definitions.hash_length", 60 | "equation_Spec.Hash.Definitions.hash_word_length", 61 | "equation_Spec.Hash.Definitions.is_md", 62 | "equation_Spec.Hash.Definitions.is_shake", 63 | "equation_Spec.Hash.Definitions.less_than_max_input_length", 64 | "equation_Spec.Hash.Definitions.max_input_length", 65 | "equation_Spec.Hash.Definitions.word_length", 66 | "equation_with_fuel_Prims.pow2.fuel_instrumented", 67 | "function_token_typing_FStar.Integers.uint_8", 68 | "function_token_typing_Lib.IntTypes.byte_t", 69 | "function_token_typing_Lib.IntTypes.uint8", 70 | "function_token_typing_Prims.int", 71 | "haseqTm_refine_542f9d4f129664613f2483a6c88bc7c2", "int_inversion", 72 | "int_typing", "lemma_FStar.UInt.pow2_values", 73 | "lemma_LowStar.Monotonic.Buffer.length_as_seq", 74 | "lemma_LowStar.Monotonic.Buffer.length_null_1", 75 | "lemma_LowStar.Monotonic.Buffer.length_null_2", 76 | "lemma_Spec.Hash.Definitions.md_alg_is_maxed", 77 | "primitive_Prims.op_Addition", "primitive_Prims.op_LessThanOrEqual", 78 | "primitive_Prims.op_Multiply", "primitive_Prims.op_Subtraction", 79 | "proj_equation_Spec.GaloisField.GF_t", 80 | "projection_inverse_BoxBool_proj_0", 81 | "projection_inverse_BoxInt_proj_0", 82 | "projection_inverse_FStar.Integers.Signed__0", 83 | "projection_inverse_FStar.Integers.Unsigned__0", 84 | "projection_inverse_FStar.Pervasives.Native.Some_a", 85 | "projection_inverse_FStar.Pervasives.Native.Some_v", 86 | "projection_inverse_Spec.GaloisField.GF_t", 87 | "refinement_interpretation_Tm_refine_11f5c63c78caccafb41a6490396f36ec", 88 | "refinement_interpretation_Tm_refine_414d0a9f578ab0048252f8c8f552b99f", 89 | "refinement_interpretation_Tm_refine_542f9d4f129664613f2483a6c88bc7c2", 90 | "refinement_interpretation_Tm_refine_837aaa25c6967f53b930fd73a3026b51", 91 | "refinement_interpretation_Tm_refine_9b6c425a4cbc030b259d3962549fd246", 92 | "refinement_interpretation_Tm_refine_de8080fdc4bd6678af723874a7d70466", 93 | "refinement_interpretation_Tm_refine_f9aae508184255bcb409c67f176bc4df", 94 | "typing_LowStar.Buffer.trivial_preorder", 95 | "typing_LowStar.ImmutableBuffer.immutable_preorder", 96 | "typing_LowStar.Monotonic.Buffer.length", 97 | "typing_QUIC.Spec.Crypto.supported_hash", "typing_Spec.AES.gf8", 98 | "typing_Spec.Chacha20.size_key", 99 | "typing_Spec.GaloisField.__proj__GF__item__t", 100 | "typing_Spec.Hash.Definitions.is_shake", 101 | "typing_Spec.Hash.Definitions.less_than_max_input_length", 102 | "typing_tok_Spec.Hash.Definitions.SHA2_384@tok", 103 | "typing_tok_Spec.Hash.Definitions.SHA2_512@tok" 104 | ], 105 | 0, 106 | "db7e851403d37b47436961116a7de9d2" 107 | ] 108 | ] 109 | ] -------------------------------------------------------------------------------- /src/QUIC.Spec.Header.Public.fsti: -------------------------------------------------------------------------------- 1 | module QUIC.Spec.Header.Public 2 | include QUIC.Spec.Base 3 | 4 | module LP = LowParse.Spec.Base 5 | module U32 = FStar.UInt32 6 | module U62 = QUIC.UInt62 7 | module U64 = FStar.UInt64 8 | module U8 = FStar.UInt8 9 | module LPB = LowParse.BitFields 10 | module FB = FStar.Bytes 11 | module Cast = FStar.Int.Cast 12 | 13 | noeq 14 | type long_header_specifics = 15 | | PInitial: 16 | (token: vlbytes 0 token_max_len) -> // arbitrary bound 17 | (payload_and_pn_length: payload_and_pn_length_t) -> 18 | long_header_specifics 19 | | PZeroRTT: 20 | (payload_and_pn_length: payload_and_pn_length_t) -> 21 | long_header_specifics 22 | | PHandshake: 23 | (payload_and_pn_length: payload_and_pn_length_t) -> 24 | long_header_specifics 25 | | PRetry: 26 | (odcid: vlbytes 0 20) -> // TODO: change bounds to drop instead of rejecting as invalid 27 | long_header_specifics 28 | 29 | noeq 30 | type header = 31 | | PLong: 32 | (protected_bits: bitfield 4) -> 33 | (version: U32.t) -> 34 | (dcid: vlbytes 0 20) -> 35 | (scid: vlbytes 0 20) -> 36 | (spec: long_header_specifics) -> 37 | header 38 | | PShort: 39 | (protected_bits: bitfield 5) -> 40 | (spin: bool) -> 41 | (dcid: vlbytes 0 20) -> 42 | header 43 | 44 | let is_retry 45 | (h: header) 46 | : Tot bool 47 | = if PShort? h 48 | then false 49 | else 50 | let spec = PLong?.spec h in 51 | PRetry? spec 52 | 53 | let dcid_len (h: header) : Tot nat = 54 | match h with 55 | | PLong _ _ dcid _ _ -> FB.length dcid 56 | | PShort _ _ dcid -> FB.length dcid 57 | 58 | let short_dcid_len_prop 59 | (short_dcid_len: short_dcid_len_t) 60 | (h: header) 61 | : GTot Type0 62 | = (PShort? h ==> dcid_len h == U32.v short_dcid_len) 63 | 64 | unfold 65 | let parse_header_prop 66 | (short_dcid_len: short_dcid_len_t) 67 | (m: header) 68 | : GTot Type0 69 | = short_dcid_len_prop short_dcid_len m 70 | 71 | inline_for_extraction 72 | type header' 73 | (short_dcid_len: short_dcid_len_t) 74 | = (m: header { parse_header_prop short_dcid_len m }) 75 | 76 | inline_for_extraction 77 | noextract 78 | val parse_header_kind 79 | (short_dcid_len: short_dcid_len_t) 80 | : Tot (k: LP.parser_kind { 81 | k.LP.parser_kind_subkind == Some LP.ParserStrong /\ 82 | k.LP.parser_kind_low > 0 /\ 83 | begin match k.LP.parser_kind_high with 84 | | None -> False 85 | | Some max -> max + 4 < header_len_bound 86 | end 87 | }) 88 | 89 | val parse_header 90 | (short_dcid_len: short_dcid_len_t) 91 | : Tot (LP.parser (parse_header_kind short_dcid_len) (header' short_dcid_len)) 92 | 93 | val serialize_header 94 | (short_dcid_len: short_dcid_len_t) 95 | : Tot (LP.serializer (parse_header short_dcid_len)) 96 | 97 | val serialize_header_ext 98 | (short_dcid_len1 short_dcid_len2: short_dcid_len_t) 99 | (h: header) 100 | : Lemma 101 | (requires (short_dcid_len_prop short_dcid_len1 h /\ short_dcid_len_prop short_dcid_len2 h)) 102 | (ensures ( 103 | short_dcid_len_prop short_dcid_len1 h /\ short_dcid_len_prop short_dcid_len2 h /\ 104 | LP.serialize (serialize_header short_dcid_len1) h == LP.serialize (serialize_header short_dcid_len2) h 105 | )) 106 | 107 | val serialize_header_is_short 108 | (short_dcid_len: short_dcid_len_t) 109 | (h: header' short_dcid_len) 110 | : Lemma ( 111 | let s = LP.serialize (serialize_header short_dcid_len) h in 112 | Seq.length s > 0 /\ 113 | (PShort? h <==> LPB.get_bitfield (U8.v (Seq.index s 0)) 7 8 == 0) 114 | ) 115 | 116 | val serialize_header_is_retry 117 | (short_dcid_len: short_dcid_len_t) 118 | (h: header' short_dcid_len) 119 | : Lemma ( 120 | let s = LP.serialize (serialize_header short_dcid_len) h in 121 | Seq.length s > 0 /\ ( 122 | is_retry h <==> ( 123 | LPB.get_bitfield (U8.v (Seq.index s 0)) 7 8 == 1 /\ 124 | LPB.get_bitfield (U8.v (Seq.index s 0)) 4 6 == 3 125 | ))) 126 | 127 | 128 | (* Mutating the protected bits *) 129 | 130 | let get_protected_bits 131 | (h: header) 132 | : Tot (bitfield (if PShort? h then 5 else 4)) 133 | = match h with 134 | | PShort pb spin dcid -> pb 135 | | PLong pb version dcid scid spec -> pb 136 | 137 | let set_protected_bits 138 | (h: header) 139 | (new_pb: bitfield (if PShort? h then 5 else 4)) 140 | : Tot header 141 | = match h with 142 | | PShort _ spin dcid -> PShort new_pb spin dcid 143 | | PLong _ version dcid scid spec -> PLong new_pb version dcid scid spec 144 | 145 | val serialize_get_protected_bits 146 | (short_dcid_len: short_dcid_len_t) 147 | (h: header' short_dcid_len) 148 | : Lemma 149 | (let sq = LP.serialize (serialize_header short_dcid_len) h in 150 | Seq.length sq > 0 /\ 151 | get_protected_bits h == LPB.uint8.LPB.get_bitfield (Seq.head sq) 0 (if PShort? h then 5 else 4)) 152 | 153 | val serialize_set_protected_bits 154 | (short_dcid_len: short_dcid_len_t) 155 | (h: header' short_dcid_len) 156 | (new_pb: bitfield (if PShort? h then 5 else 4)) 157 | : Lemma 158 | (let sq = LP.serialize (serialize_header short_dcid_len) h in 159 | Seq.length sq > 0 /\ 160 | LP.serialize (serialize_header short_dcid_len) (set_protected_bits h new_pb) `Seq.equal` 161 | (LPB.uint8.LPB.set_bitfield (Seq.head sq) 0 (if PShort? h then 5 else 4) new_pb `Seq.cons` Seq.tail sq)) 162 | 163 | (* Explicit length computation is needed for the switch. *) 164 | 165 | let header_len' 166 | (h: header) 167 | : GTot (n: pos { n <= header_len_bound }) 168 | = match h with 169 | | PShort _ _ dcid -> 170 | 1 + FB.length dcid 171 | | PLong pb version dcid scid spec -> 172 | 7 + FB.length dcid + FB.length scid + 173 | begin match spec with 174 | | PInitial token payload_and_pn_length -> 175 | varint_len (Cast.uint32_to_uint64 (FB.len token)) + FB.length token + varint_len payload_and_pn_length 176 | | PZeroRTT payload_and_pn_length -> 177 | varint_len payload_and_pn_length 178 | | PHandshake payload_and_pn_length -> 179 | varint_len payload_and_pn_length 180 | | PRetry odcid -> 181 | 1 + FB.length odcid 182 | end 183 | 184 | val header_len'_correct 185 | (short_dcid_len: short_dcid_len_t) 186 | (h: header' short_dcid_len) 187 | : Lemma 188 | (header_len' h == Seq.length (LP.serialize (serialize_header short_dcid_len) h)) 189 | -------------------------------------------------------------------------------- /hints/QUIC.Spec.VarInt.fsti.hints: -------------------------------------------------------------------------------- 1 | [ 2 | "448e9604a3a810cab3e1136e5b7d5e8b", 3 | [ 4 | [ 5 | "QUIC.Spec.VarInt.parse_varint", 6 | 1, 7 | 2, 8 | 1, 9 | [ 10 | "@query", "equation_Prims.nat", 11 | "equation_QUIC.Spec.VarInt.parse_varint_kind", 12 | "proj_equation_FStar.Pervasives.Native.Some_v", 13 | "proj_equation_LowParse.Spec.Base.Mkparser_kind__parser_kind_high", 14 | "proj_equation_LowParse.Spec.Base.Mkparser_kind__parser_kind_low", 15 | "projection_inverse_BoxInt_proj_0", 16 | "projection_inverse_FStar.Pervasives.Native.Some_v", 17 | "projection_inverse_LowParse.Spec.Base.Mkparser_kind__parser_kind_high", 18 | "projection_inverse_LowParse.Spec.Base.Mkparser_kind__parser_kind_low" 19 | ], 20 | 0, 21 | "3cc9c2c7ce79bafb72df4b5740ec4d03" 22 | ], 23 | [ 24 | "QUIC.Spec.VarInt.serialize_varint", 25 | 1, 26 | 2, 27 | 1, 28 | [ 29 | "@query", "equation_Prims.nat", 30 | "equation_QUIC.Spec.VarInt.parse_varint_kind", 31 | "proj_equation_FStar.Pervasives.Native.Some_v", 32 | "proj_equation_LowParse.Spec.Base.Mkparser_kind__parser_kind_high", 33 | "proj_equation_LowParse.Spec.Base.Mkparser_kind__parser_kind_low", 34 | "projection_inverse_BoxInt_proj_0", 35 | "projection_inverse_FStar.Pervasives.Native.Some_v", 36 | "projection_inverse_LowParse.Spec.Base.Mkparser_kind__parser_kind_high", 37 | "projection_inverse_LowParse.Spec.Base.Mkparser_kind__parser_kind_low" 38 | ], 39 | 0, 40 | "e5be240a193c0831e5ea472ec12d0feb" 41 | ], 42 | [ 43 | "QUIC.Spec.VarInt.parse_bounded_varint", 44 | 1, 45 | 2, 46 | 1, 47 | [ 48 | "@query", "equation_Prims.nat", 49 | "equation_QUIC.Spec.VarInt.parse_varint_kind", 50 | "proj_equation_FStar.Pervasives.Native.Some_v", 51 | "proj_equation_LowParse.Spec.Base.Mkparser_kind__parser_kind_high", 52 | "proj_equation_LowParse.Spec.Base.Mkparser_kind__parser_kind_low", 53 | "projection_inverse_BoxInt_proj_0", 54 | "projection_inverse_FStar.Pervasives.Native.Some_v", 55 | "projection_inverse_LowParse.Spec.Base.Mkparser_kind__parser_kind_high", 56 | "projection_inverse_LowParse.Spec.Base.Mkparser_kind__parser_kind_low" 57 | ], 58 | 0, 59 | "1727ed2de79a1e691e9597ba20d627c5" 60 | ], 61 | [ 62 | "QUIC.Spec.VarInt.serialize_bounded_varint", 63 | 1, 64 | 2, 65 | 1, 66 | [ 67 | "@query", "equation_Prims.nat", 68 | "equation_QUIC.Spec.VarInt.parse_varint_kind", 69 | "proj_equation_FStar.Pervasives.Native.Some_v", 70 | "proj_equation_LowParse.Spec.Base.Mkparser_kind__parser_kind_high", 71 | "proj_equation_LowParse.Spec.Base.Mkparser_kind__parser_kind_low", 72 | "projection_inverse_BoxInt_proj_0", 73 | "projection_inverse_FStar.Pervasives.Native.Some_v", 74 | "projection_inverse_LowParse.Spec.Base.Mkparser_kind__parser_kind_high", 75 | "projection_inverse_LowParse.Spec.Base.Mkparser_kind__parser_kind_low" 76 | ], 77 | 0, 78 | "87aa49017e7a402d1abd28780f1f04cf" 79 | ], 80 | [ 81 | "QUIC.Spec.VarInt.varint_len_correct", 82 | 1, 83 | 2, 84 | 1, 85 | [ 86 | "@query", "equation_Prims.nat", 87 | "equation_QUIC.Spec.VarInt.parse_varint_kind", 88 | "proj_equation_FStar.Pervasives.Native.Some_v", 89 | "proj_equation_LowParse.Spec.Base.Mkparser_kind__parser_kind_high", 90 | "proj_equation_LowParse.Spec.Base.Mkparser_kind__parser_kind_low", 91 | "projection_inverse_BoxInt_proj_0", 92 | "projection_inverse_FStar.Pervasives.Native.Some_v", 93 | "projection_inverse_LowParse.Spec.Base.Mkparser_kind__parser_kind_high", 94 | "projection_inverse_LowParse.Spec.Base.Mkparser_kind__parser_kind_low" 95 | ], 96 | 0, 97 | "df3807da03dd32424fdbaf33cee0cde8" 98 | ], 99 | [ 100 | "QUIC.Spec.VarInt.bounded_varint_len_correct", 101 | 1, 102 | 2, 103 | 1, 104 | [ 105 | "@MaxFuel_assumption", "@MaxIFuel_assumption", 106 | "@fuel_correspondence_Prims.pow2.fuel_instrumented", 107 | "@fuel_irrelevance_Prims.pow2.fuel_instrumented", "@query", 108 | "b2t_def", "bool_inversion", "bool_typing", 109 | "equation_FStar.UInt.fits", "equation_FStar.UInt.max_int", 110 | "equation_FStar.UInt.min_int", "equation_FStar.UInt.size", 111 | "equation_FStar.UInt.uint_t", 112 | "equation_LowParse.Spec.BoundedInt.bounded_int32", 113 | "equation_LowParse.Spec.BoundedInt.in_bounds", "equation_Prims.nat", 114 | "equation_QUIC.Spec.VarInt.parse_varint_kind", 115 | "equation_QUIC.UInt62.bound", "int_inversion", "int_typing", 116 | "lemma_FStar.UInt.pow2_values", "lemma_FStar.UInt64.vu_inv", 117 | "primitive_Prims.op_AmpAmp", "primitive_Prims.op_BarBar", 118 | "primitive_Prims.op_LessThan", "primitive_Prims.op_LessThanOrEqual", 119 | "primitive_Prims.op_Negation", "primitive_Prims.op_Subtraction", 120 | "proj_equation_FStar.Pervasives.Native.Some_v", 121 | "proj_equation_LowParse.Spec.Base.Mkparser_kind__parser_kind_high", 122 | "proj_equation_LowParse.Spec.Base.Mkparser_kind__parser_kind_low", 123 | "projection_inverse_BoxBool_proj_0", 124 | "projection_inverse_BoxInt_proj_0", 125 | "projection_inverse_FStar.Pervasives.Native.Some_v", 126 | "projection_inverse_LowParse.Spec.Base.Mkparser_kind__parser_kind_high", 127 | "projection_inverse_LowParse.Spec.Base.Mkparser_kind__parser_kind_low", 128 | "refinement_interpretation_Tm_refine_4689762d8936cd661071819a684ec9b0", 129 | "refinement_interpretation_Tm_refine_542f9d4f129664613f2483a6c88bc7c2", 130 | "refinement_interpretation_Tm_refine_a87dbe8fa6c2ba694a031fa266bf0206", 131 | "refinement_interpretation_Tm_refine_f13070840248fced9d9d60d77bdae3ec", 132 | "typing_FStar.UInt32.v", "typing_LowParse.Spec.BoundedInt.in_bounds" 133 | ], 134 | 0, 135 | "c235b6a1e44f0e269db19c4b6762d03f" 136 | ] 137 | ] 138 | ] -------------------------------------------------------------------------------- /hints/QUIC.Spec.Header.fsti.hints: -------------------------------------------------------------------------------- 1 | [ 2 | "b6573cf14e907167a5d37edd49e4bfa1", 3 | [ 4 | [ 5 | "QUIC.Spec.Header.pn_sizemask", 6 | 1, 7 | 2, 8 | 1, 9 | [ 10 | "@MaxIFuel_assumption", "@query", "equation_Prims.nat", 11 | "primitive_Prims.op_Addition", "projection_inverse_BoxInt_proj_0", 12 | "refinement_interpretation_Tm_refine_542f9d4f129664613f2483a6c88bc7c2", 13 | "refinement_interpretation_Tm_refine_7acf795d50ec256996534a97e12bfa61" 14 | ], 15 | 0, 16 | "6958743e17522283a7ae92270e64db4f" 17 | ], 18 | [ 19 | "QUIC.Spec.Header.header_encrypt", 20 | 1, 21 | 2, 22 | 1, 23 | [ 24 | "@query", "equation_QUIC.Spec.Crypto.supported_aead", 25 | "equation_Spec.Agile.AEAD.is_supported_alg" 26 | ], 27 | 0, 28 | "ef74b8bfe6ecbaa71644de0bde45fb1b" 29 | ], 30 | [ 31 | "QUIC.Spec.Header.header_encrypt_length", 32 | 1, 33 | 2, 34 | 1, 35 | [ 36 | "@query", "equation_QUIC.Spec.Crypto.supported_aead", 37 | "equation_Spec.Agile.AEAD.is_supported_alg" 38 | ], 39 | 0, 40 | "bec8471d1c2e7fbf26e8fd53d66a46d7" 41 | ], 42 | [ 43 | "QUIC.Spec.Header.__proj__H_Success__item__h", 44 | 1, 45 | 2, 46 | 1, 47 | [ 48 | "@MaxIFuel_assumption", "@query", 49 | "disc_equation_QUIC.Spec.Header.H_Success", 50 | "projection_inverse_BoxBool_proj_0", 51 | "refinement_interpretation_Tm_refine_72ac4fe9fdddef08064367bbd1d11dde" 52 | ], 53 | 0, 54 | "4170b39a6367bd5c484db0029566966a" 55 | ], 56 | [ 57 | "QUIC.Spec.Header.__proj__H_Success__item__cipher", 58 | 1, 59 | 2, 60 | 1, 61 | [ 62 | "@MaxIFuel_assumption", "@query", 63 | "disc_equation_QUIC.Spec.Header.H_Success", 64 | "proj_equation_QUIC.Spec.Header.H_Success_h", 65 | "projection_inverse_BoxBool_proj_0", 66 | "projection_inverse_QUIC.Spec.Header.H_Success_h", 67 | "refinement_interpretation_Tm_refine_72ac4fe9fdddef08064367bbd1d11dde" 68 | ], 69 | 0, 70 | "ff774a1844085967ac1cd38d43e4fba5" 71 | ], 72 | [ 73 | "QUIC.Spec.Header.__proj__H_Success__item__rem", 74 | 1, 75 | 2, 76 | 1, 77 | [ 78 | "@MaxIFuel_assumption", "@query", 79 | "disc_equation_QUIC.Spec.Header.H_Success", 80 | "projection_inverse_BoxBool_proj_0", 81 | "refinement_interpretation_Tm_refine_72ac4fe9fdddef08064367bbd1d11dde" 82 | ], 83 | 0, 84 | "3b051b13b53e61ab3d1ed3f5e9efe38d" 85 | ], 86 | [ 87 | "QUIC.Spec.Header.header_decrypt", 88 | 1, 89 | 2, 90 | 1, 91 | [ 92 | "@MaxIFuel_assumption", "@query", 93 | "constructor_distinct_Lib.IntTypes.PUB", 94 | "constructor_distinct_Lib.IntTypes.U8", 95 | "disc_equation_QUIC.Spec.Header.H_Failure", 96 | "disc_equation_QUIC.Spec.Header.H_Success", 97 | "equality_tok_Lib.IntTypes.PUB@tok", 98 | "equality_tok_Lib.IntTypes.U1@tok", 99 | "equality_tok_Lib.IntTypes.U8@tok", "equation_Lib.IntTypes.byte_t", 100 | "equation_Lib.IntTypes.int_t", "equation_Lib.IntTypes.pub_int_t", 101 | "equation_Lib.IntTypes.unsigned", "equation_Prims.nat", 102 | "equation_QUIC.Spec.Base.byte", "equation_QUIC.Spec.Base.bytes", 103 | "equation_QUIC.Spec.Crypto.supported_aead", "equation_Spec.AES.gf8", 104 | "equation_Spec.AES.irred", 105 | "equation_Spec.Agile.AEAD.is_supported_alg", 106 | "equation_Spec.GaloisField.gf", 107 | "fuel_guarded_inversion_QUIC.Spec.Header.h_result", 108 | "function_token_typing_Lib.IntTypes.byte_t", 109 | "primitive_Prims.op_LessThanOrEqual", 110 | "primitive_Prims.op_Subtraction", 111 | "proj_equation_Spec.GaloisField.GF_t", 112 | "projection_inverse_BoxInt_proj_0", 113 | "projection_inverse_Spec.GaloisField.GF_t", 114 | "refinement_interpretation_Tm_refine_542f9d4f129664613f2483a6c88bc7c2", 115 | "refinement_interpretation_Tm_refine_de8080fdc4bd6678af723874a7d70466", 116 | "typing_FStar.Seq.Base.length", "typing_Spec.AES.gf8", 117 | "typing_Spec.GaloisField.__proj__GF__item__t" 118 | ], 119 | 0, 120 | "bacafcd1f6a154ea90ceed5027768829" 121 | ], 122 | [ 123 | "QUIC.Spec.Header.lemma_header_encryption_correct", 124 | 1, 125 | 2, 126 | 1, 127 | [ 128 | "@MaxIFuel_assumption", "@query", 129 | "constructor_distinct_FStar.Integers.W16", 130 | "constructor_distinct_FStar.Integers.W32", 131 | "constructor_distinct_FStar.Integers.W64", 132 | "constructor_distinct_FStar.Integers.W8", 133 | "constructor_distinct_Lib.IntTypes.U64", 134 | "constructor_distinct_Lib.IntTypes.U8", 135 | "equality_tok_FStar.Integers.W16@tok", 136 | "equality_tok_FStar.Integers.W32@tok", 137 | "equality_tok_FStar.Integers.W64@tok", 138 | "equality_tok_FStar.Integers.W8@tok", 139 | "equality_tok_Lib.IntTypes.U1@tok", 140 | "equality_tok_Lib.IntTypes.U64@tok", 141 | "equality_tok_Lib.IntTypes.U8@tok", "equation_Lib.IntTypes.minint", 142 | "equation_Lib.IntTypes.range", "equation_Lib.IntTypes.unsigned", 143 | "equation_QUIC.Spec.Crypto.supported_aead", 144 | "equation_QUIC.Spec.PacketNumber.Base.packet_number_length_t", 145 | "equation_Spec.AES.gf8", "equation_Spec.AES.irred", 146 | "equation_Spec.Agile.AEAD.is_supported_alg", 147 | "equation_Spec.GaloisField.gf", "primitive_Prims.op_Subtraction", 148 | "proj_equation_Spec.GaloisField.GF_t", 149 | "projection_inverse_BoxInt_proj_0", 150 | "projection_inverse_FStar.Integers.Signed__0", 151 | "projection_inverse_FStar.Integers.Unsigned__0", 152 | "projection_inverse_Spec.GaloisField.GF_t", 153 | "refinement_interpretation_Tm_refine_1622082edcbeee4d7aa5d33c2647f14f", 154 | "refinement_interpretation_Tm_refine_de8080fdc4bd6678af723874a7d70466", 155 | "typing_Spec.AES.gf8", "typing_Spec.GaloisField.__proj__GF__item__t" 156 | ], 157 | 0, 158 | "be62f20e0cf4ff6324abb92c2c3e4cf6" 159 | ] 160 | ] 161 | ] -------------------------------------------------------------------------------- /src/QUIC.Impl.Header.fsti: -------------------------------------------------------------------------------- 1 | module QUIC.Impl.Header 2 | include QUIC.Impl.Header.Base 3 | 4 | open QUIC.Spec.Crypto 5 | 6 | module G = FStar.Ghost 7 | module U8 = FStar.UInt8 8 | module B = LowStar.Buffer 9 | module U32 = FStar.UInt32 10 | module Secret = QUIC.Secret.Int 11 | module PN = QUIC.Spec.PacketNumber.Base 12 | module HST = FStar.HyperStack.ST 13 | module Seq = FStar.Seq 14 | module HS = FStar.HyperStack 15 | 16 | module Spec = QUIC.Spec.Header 17 | module Parse = QUIC.Spec.Header.Parse 18 | module SAEAD = Spec.Agile.AEAD 19 | module SCipher = Spec.Agile.Cipher 20 | 21 | module CTR = EverCrypt.CTR 22 | 23 | unfold 24 | let header_encrypt_pre 25 | (a: ea) 26 | (s: CTR.state (SAEAD.cipher_alg_of_supported_alg a)) 27 | (k: B.buffer Secret.uint8) 28 | (dst:B.buffer U8.t) 29 | (h: G.erased Spec.header) 30 | (is_short: bool) 31 | (is_retry: bool) 32 | (public_len: U32.t) 33 | (pn_len: PN.packet_number_length_t) 34 | (m: HS.mem) 35 | : GTot Type0 36 | = 37 | let a' = SAEAD.cipher_alg_of_supported_alg a in 38 | let fmt = Parse.format_header h in 39 | let header_len = Seq.length fmt in 40 | 41 | B.all_disjoint [ 42 | CTR.footprint m s; 43 | B.loc_buffer k; 44 | B.loc_buffer dst; 45 | ] /\ 46 | 47 | CTR.invariant m s /\ 48 | B.live m k /\ B.length k == SCipher.key_length a' /\ 49 | B.live m dst /\ 50 | 51 | is_short == Spec.MShort? h /\ 52 | is_retry == Spec.is_retry h /\ 53 | begin if is_retry 54 | then 55 | U32.v public_len == header_len /\ 56 | B.length dst == header_len 57 | else 58 | let cipher_len = B.length dst - header_len in 59 | U32.v public_len == Parse.pn_offset h /\ 60 | pn_len == Spec.pn_length h /\ 61 | 19 <= cipher_len /\ cipher_len < max_cipher_length 62 | end /\ 63 | Seq.slice (B.as_seq m dst) 0 header_len `Seq.equal` fmt 64 | 65 | unfold 66 | let header_encrypt_post 67 | (a: ea) 68 | (s: CTR.state (SAEAD.cipher_alg_of_supported_alg a)) 69 | (k: B.buffer Secret.uint8) 70 | (dst:B.buffer U8.t) 71 | (h: G.erased Spec.header) 72 | (is_short: bool) 73 | (is_retry: bool) 74 | (public_len: U32.t) 75 | (pn_len: PN.packet_number_length_t) 76 | (m: HS.mem) 77 | (m' : HS.mem) 78 | : GTot Type0 79 | = 80 | header_encrypt_pre a s k dst h is_short is_retry public_len pn_len m /\ 81 | begin 82 | let a' = SAEAD.cipher_alg_of_supported_alg a in 83 | let fmt = Parse.format_header h in 84 | let header_len = Seq.length fmt in 85 | let cipher = Seq.slice (B.as_seq m dst) header_len (B.length dst) in 86 | B.modifies (B.loc_buffer dst `B.loc_union` CTR.footprint m s) m m' /\ 87 | B.as_seq m' dst `Seq.equal` 88 | Spec.header_encrypt a (B.as_seq m k) h cipher /\ 89 | CTR.invariant m' s /\ 90 | CTR.footprint m s == CTR.footprint m' s 91 | end 92 | 93 | val header_encrypt: a: ea -> 94 | (s: CTR.state (SAEAD.cipher_alg_of_supported_alg a)) -> 95 | (k: B.buffer Secret.uint8) -> 96 | dst:B.buffer U8.t -> 97 | h: G.erased Spec.header -> 98 | is_short: bool -> 99 | is_retry: bool -> 100 | public_len: U32.t -> 101 | pn_len: PN.packet_number_length_t -> 102 | HST.Stack unit 103 | (requires (fun h0 -> 104 | header_encrypt_pre a s k dst h is_short is_retry public_len pn_len h0 105 | )) 106 | (ensures fun h0 _ h1 -> 107 | header_encrypt_post a s k dst h is_short is_retry public_len pn_len h0 h1 108 | ) 109 | 110 | noeq 111 | type h_result = 112 | | H_Failure 113 | | H_Success: 114 | (h: header) -> 115 | (pn: PN.packet_number_t) -> 116 | (cipher_length: Secret.uint32) -> 117 | h_result 118 | 119 | unfold 120 | let header_decrypt_pre 121 | (a: ea) 122 | (s: CTR.state (SAEAD.cipher_alg_of_supported_alg a)) 123 | (k: B.buffer Secret.uint8) 124 | (cid_len: short_dcid_len_t) 125 | (last: PN.last_packet_number_t) 126 | (dst:B.buffer U8.t) 127 | (dst_len: U32.t) 128 | (m: HS.mem) 129 | : GTot Type0 130 | = 131 | let a' = SAEAD.cipher_alg_of_supported_alg a in 132 | B.all_disjoint [ 133 | CTR.footprint m s; 134 | B.loc_buffer k; 135 | B.loc_buffer dst; 136 | ] /\ 137 | CTR.invariant m s /\ 138 | B.live m k /\ B.length k == SCipher.key_length a' /\ 139 | B.live m dst /\ B.length dst == U32.v dst_len 140 | 141 | unfold 142 | let header_decrypt_post 143 | (a: ea) 144 | (s: CTR.state (SAEAD.cipher_alg_of_supported_alg a)) 145 | (k: B.buffer Secret.uint8) 146 | (cid_len: short_dcid_len_t) 147 | (last: PN.last_packet_number_t) 148 | (dst:B.buffer U8.t) 149 | (dst_len: U32.t) 150 | (m: HS.mem) 151 | (res: h_result) 152 | (m' : HS.mem) 153 | : GTot Type0 154 | = 155 | header_decrypt_pre a s k cid_len last dst dst_len m /\ 156 | CTR.footprint m' s == CTR.footprint m s /\ 157 | CTR.invariant m' s /\ 158 | begin match res, Spec.header_decrypt a (B.as_seq m k) (U32.v cid_len) (Secret.v last) (B.as_seq m dst) with 159 | | H_Failure, Spec.H_Failure -> 160 | B.modifies B.loc_none m m' 161 | | H_Success h pn cipher_len, Spec.H_Success gh gcipher grem -> 162 | header_live h m' /\ 163 | gh == g_header h m' pn /\ 164 | Secret.v (header_len h) + Secret.v cipher_len <= B.length dst /\ 165 | B.loc_buffer (B.gsub dst 0ul (public_header_len h)) `B.loc_includes` header_footprint h /\ 166 | B.modifies (B.loc_buffer (B.gsub dst 0ul (Secret.reveal (header_len h))) `B.loc_union` CTR.footprint m s) m m' /\ 167 | Seq.length gcipher == Secret.v cipher_len /\ 168 | B.as_seq m' dst `Seq.equal` (Parse.format_header gh `Seq.append` gcipher `Seq.append` grem) /\ 169 | B.as_seq m' (B.gsub dst 0ul (Secret.reveal (header_len h))) == Parse.format_header gh /\ 170 | B.as_seq m' (B.gsub dst (Secret.reveal (header_len h)) (Secret.reveal cipher_len)) == gcipher /\ 171 | B.as_seq m' (B.gsub dst (Secret.reveal (header_len h) `U32.add` Secret.reveal cipher_len) (B.len dst `U32.sub` (Secret.reveal (header_len h) `U32.add` Secret.reveal cipher_len))) == grem 172 | | _ -> False 173 | end 174 | 175 | val header_decrypt 176 | (a: ea) 177 | (s: CTR.state (SAEAD.cipher_alg_of_supported_alg a)) 178 | (k: B.buffer Secret.uint8) 179 | (cid_len: short_dcid_len_t) 180 | (last: PN.last_packet_number_t) 181 | (dst:B.buffer U8.t) 182 | (dst_len: U32.t) 183 | : HST.Stack h_result 184 | (requires (fun m -> 185 | header_decrypt_pre a s k cid_len last dst dst_len m 186 | )) 187 | (ensures (fun m res m' -> 188 | header_decrypt_post a s k cid_len last dst dst_len m res m' 189 | )) 190 | -------------------------------------------------------------------------------- /hints/QUIC.Secret.Int.fsti.hints: -------------------------------------------------------------------------------- 1 | [ 2 | "5057c3a5e4d3ed1eba2fbf7122eb3728", 3 | [ 4 | [ 5 | "QUIC.Secret.Int.cast_up", 6 | 1, 7 | 2, 8 | 1, 9 | [ "@query" ], 10 | 0, 11 | "1dc0fc1409f32febfc1342a6080bb473" 12 | ], 13 | [ 14 | "QUIC.Secret.Int.cast_down", 15 | 1, 16 | 2, 17 | 1, 18 | [ 19 | "@MaxIFuel_assumption", "@query", "equation_Lib.IntTypes.bits", 20 | "fuel_guarded_inversion_Lib.IntTypes.inttype", 21 | "projection_inverse_BoxInt_proj_0", 22 | "refinement_interpretation_Tm_refine_387e6d282145573240ab7b8a4b94cce5" 23 | ], 24 | 0, 25 | "e1ed4e58e307982af4e31adca3ba9a0f" 26 | ], 27 | [ 28 | "QUIC.Secret.Int.hide_reveal", 29 | 1, 30 | 2, 31 | 1, 32 | [ 33 | "@MaxIFuel_assumption", "@query", 34 | "equality_tok_Lib.IntTypes.PUB@tok", 35 | "equality_tok_Lib.IntTypes.SEC@tok", 36 | "lemma_Lib.IntTypes.v_injective", 37 | "refinement_interpretation_Tm_refine_1c83e43dc119f3b9f843ce1b4fcf61f0", 38 | "refinement_interpretation_Tm_refine_387e6d282145573240ab7b8a4b94cce5", 39 | "refinement_interpretation_Tm_refine_cdb20ea2e877751488e618552edde090", 40 | "typing_QUIC.Secret.Int.hide", "typing_QUIC.Secret.Int.reveal", 41 | "typing_tok_Lib.IntTypes.PUB@tok", "typing_tok_Lib.IntTypes.SEC@tok" 42 | ], 43 | 0, 44 | "2b268ae28ce99e2a9d98f20abeeb0bb5" 45 | ], 46 | [ 47 | "QUIC.Secret.Int.reveal_hide", 48 | 1, 49 | 2, 50 | 1, 51 | [ 52 | "@MaxIFuel_assumption", "@query", 53 | "equality_tok_Lib.IntTypes.PUB@tok", 54 | "equality_tok_Lib.IntTypes.SEC@tok", 55 | "lemma_Lib.IntTypes.v_injective", 56 | "refinement_interpretation_Tm_refine_1c83e43dc119f3b9f843ce1b4fcf61f0", 57 | "refinement_interpretation_Tm_refine_387e6d282145573240ab7b8a4b94cce5", 58 | "refinement_interpretation_Tm_refine_cdb20ea2e877751488e618552edde090", 59 | "typing_QUIC.Secret.Int.hide", "typing_QUIC.Secret.Int.reveal", 60 | "typing_tok_Lib.IntTypes.PUB@tok", "typing_tok_Lib.IntTypes.SEC@tok" 61 | ], 62 | 0, 63 | "e84610889c65208556e6b9f2346418ad" 64 | ], 65 | [ 66 | "QUIC.Secret.Int.lognot'", 67 | 1, 68 | 2, 69 | 1, 70 | [ 71 | "@MaxIFuel_assumption", "@query", "b2t_def", "bool_inversion", 72 | "constructor_distinct_Lib.IntTypes.U1", 73 | "constructor_distinct_Lib.IntTypes.U16", 74 | "constructor_distinct_Lib.IntTypes.U32", 75 | "constructor_distinct_Lib.IntTypes.U64", 76 | "constructor_distinct_Lib.IntTypes.U8", "equation_FStar.UInt.fits", 77 | "equation_FStar.UInt.max_int", "equation_FStar.UInt.min_int", 78 | "equation_FStar.UInt.size", "equation_Lib.IntTypes.bits", 79 | "equation_Lib.IntTypes.maxint", "equation_Lib.IntTypes.minint", 80 | "equation_Lib.IntTypes.range", "equation_Lib.IntTypes.unsigned", 81 | "equation_QUIC.Secret.Int.Base.supported_type", 82 | "primitive_Prims.op_AmpAmp", "primitive_Prims.op_LessThanOrEqual", 83 | "projection_inverse_BoxBool_proj_0", 84 | "projection_inverse_BoxInt_proj_0", 85 | "refinement_interpretation_Tm_refine_403dcd338975ef02e47311f00ebef66c", 86 | "typing_Lib.IntTypes.unsigned", 87 | "typing_QUIC.Secret.Int.Base.supported_type" 88 | ], 89 | 0, 90 | "0925b323480031ebc3b42323ff568f2b" 91 | ], 92 | [ 93 | "QUIC.Secret.Int.get_bitfield", 94 | 1, 95 | 2, 96 | 1, 97 | [ 98 | "@MaxIFuel_assumption", "@query", "b2t_def", "bool_inversion", 99 | "equation_FStar.UInt.fits", "equation_FStar.UInt.max_int", 100 | "equation_FStar.UInt.min_int", "equation_FStar.UInt.size", 101 | "equation_FStar.UInt.uint_t", "equation_Lib.IntTypes.bits", 102 | "equation_Lib.IntTypes.maxint", "equation_Lib.IntTypes.minint", 103 | "equation_Lib.IntTypes.range", "equation_Lib.IntTypes.unsigned", 104 | "equation_QUIC.Secret.Int.Base.supported_type", "int_inversion", 105 | "primitive_Prims.op_AmpAmp", "primitive_Prims.op_LessThanOrEqual", 106 | "primitive_Prims.op_Subtraction", 107 | "projection_inverse_BoxBool_proj_0", 108 | "projection_inverse_BoxInt_proj_0", 109 | "refinement_interpretation_Tm_refine_403dcd338975ef02e47311f00ebef66c", 110 | "refinement_interpretation_Tm_refine_4ed2966bc981558086015a6cee33e20f", 111 | "refinement_interpretation_Tm_refine_83845a86f2550cdf941eeb1d9b59602b", 112 | "refinement_interpretation_Tm_refine_f13070840248fced9d9d60d77bdae3ec", 113 | "typing_FStar.UInt32.v", "typing_Lib.IntTypes.unsigned", 114 | "typing_QUIC.Secret.Int.Base.supported_type" 115 | ], 116 | 0, 117 | "030f59cee6bb5579a192cd1370bad2e7" 118 | ], 119 | [ 120 | "QUIC.Secret.Int.set_bitfield", 121 | 1, 122 | 2, 123 | 1, 124 | [ 125 | "@MaxIFuel_assumption", "@query", "b2t_def", "bool_inversion", 126 | "equation_FStar.UInt.fits", "equation_FStar.UInt.max_int", 127 | "equation_FStar.UInt.min_int", "equation_FStar.UInt.size", 128 | "equation_FStar.UInt.uint_t", "equation_Lib.IntTypes.bits", 129 | "equation_Lib.IntTypes.maxint", "equation_Lib.IntTypes.minint", 130 | "equation_Lib.IntTypes.range", "equation_Lib.IntTypes.unsigned", 131 | "equation_Lib.IntTypes.v", 132 | "equation_QUIC.Secret.Int.Base.supported_type", "int_inversion", 133 | "primitive_Prims.op_AmpAmp", "primitive_Prims.op_LessThanOrEqual", 134 | "primitive_Prims.op_Subtraction", 135 | "projection_inverse_BoxBool_proj_0", 136 | "projection_inverse_BoxInt_proj_0", 137 | "refinement_interpretation_Tm_refine_0e3216350b91def83640e631132372d7", 138 | "refinement_interpretation_Tm_refine_403dcd338975ef02e47311f00ebef66c", 139 | "refinement_interpretation_Tm_refine_4ed2966bc981558086015a6cee33e20f", 140 | "refinement_interpretation_Tm_refine_83845a86f2550cdf941eeb1d9b59602b", 141 | "refinement_interpretation_Tm_refine_f13070840248fced9d9d60d77bdae3ec", 142 | "typing_FStar.UInt32.v", "typing_Lib.IntTypes.unsigned", 143 | "typing_Lib.IntTypes.v", "typing_QUIC.Secret.Int.Base.supported_type" 144 | ], 145 | 0, 146 | "b2528c265f4384084d80cb950c59a2a8" 147 | ] 148 | ] 149 | ] -------------------------------------------------------------------------------- /src/Mem.fst: -------------------------------------------------------------------------------- 1 | module Mem 2 | 3 | /// * Sets a uniform Low* HyperStack-based memory model, gathering 4 | /// abbreviations and top-level regions. 5 | /// 6 | /// * Depends on Flags, as we do not to extract the global TLS region 7 | /// and its contents (only ideal stuff). 8 | /// 9 | /// Coding guidelines (aligned to EverCrypt) 10 | /// - avoid eternal refs and buffers (fstar may deprecate them in lowstar) 11 | /// - use LowStar.Buffer 12 | /// - use monotonic buffers 13 | /// 14 | /// - migrate from Bytes --> Spec-level sequences or Buffer [will take a while] 15 | /// - enable divergence checking (try it out on a Everest feature branch?) 16 | /// - use abbreviations wisely, e.g. only those to be defined in this file 17 | /// (no clear consensus yet) 18 | /// - use FStar.Integers (but avoid opening it because of v n etc... IntegersOps?) 19 | /// 20 | /// - [create parent_region ...] may allocate a private sub-region, 21 | /// unless its state is e.g. just a single transparent reference; 22 | /// the caller usually tracks it using locations rather than regions. 23 | 24 | open FStar.Error 25 | 26 | include FStar.HyperStack 27 | include FStar.HyperStack.ST 28 | 29 | open LowStar.Buffer 30 | open LowStar.BufferOps 31 | 32 | module HS = FStar.HyperStack 33 | module ST = FStar.HyperStack.ST 34 | 35 | #set-options "--z3rlimit 40 --max_fuel 0 --max_ifuel 0" 36 | 37 | inline_for_extraction noextract 38 | let model = Model.Flags.model 39 | 40 | // START quic-specific version of what was originally found in miTLS Mem.fst 41 | let rgn = r:erid{r =!= root} 42 | 43 | type fresh_subregion child parent h0 h1 = 44 | fresh_region child h0 h1 /\ extends child parent 45 | 46 | type subrgn p = r:rgn{parent r == p} 47 | 48 | let quic_region: rgn = new_region root 49 | type subq = subrgn quic_region 50 | // END quic-specific stuff 51 | 52 | /// Top-level disjointness 53 | /// ---------------------- 54 | /// 55 | /// We define an infrastructure for allocating a set of regions that are know 56 | /// automatically to be disjoint from each other. 57 | 58 | #push-options "--max_ifuel 1" 59 | 60 | (** r `rlist_disjoint` l holds if r is disjoint from all regions in l *) 61 | val rlist_disjoint: subq -> list subq -> Type0 62 | let rec rlist_disjoint r = function 63 | | [] -> True 64 | | r' :: l -> r `HS.disjoint` r' /\ rlist_disjoint r l 65 | 66 | (** r_pairwise_disjoint l holds if all regions in l are pairwise disjoint *) 67 | val r_pairwise_disjoint: list subq -> Type0 68 | let rec r_pairwise_disjoint = function 69 | | [] -> True 70 | | r :: l -> rlist_disjoint r l /\ r_pairwise_disjoint l 71 | 72 | (** r_fresh l h0 h1 holds when all regions in l are fresh between h0 and h1 *) 73 | val r_fresh: list subq -> mem -> mem -> Type0 74 | let rec r_fresh l h0 h1 = 75 | match l with 76 | | [] -> True 77 | | r :: l -> fresh_region r h0 h1 /\ r_fresh l h0 h1 78 | 79 | val fresh_back (r:rgn) (h0 h1 h2:mem) : Lemma 80 | (requires fresh_region r h1 h2 /\ modifies_none h0 h1) 81 | (ensures fresh_region r h0 h2) 82 | // [SMTPat (fresh_region r h1 h2); SMTPat (modifies_none h0 h1)] 83 | let fresh_back r h0 h1 h2 = () 84 | 85 | #pop-options 86 | 87 | #push-options "--max_fuel 1 --max_ifuel 1" 88 | 89 | val r_fresh_back (l:list subq) (h0 h1 h2:mem) : Lemma 90 | (requires r_fresh l h1 h2 /\ modifies_none h0 h1) 91 | (ensures r_fresh l h0 h2) 92 | let rec r_fresh_back l h0 h1 h2 = 93 | match l with 94 | | [] -> () 95 | | r :: l' -> r_fresh_back l' h0 h1 h2 96 | 97 | val r_fresh_fwd (l:list subq) (h0 h1 h2:mem) : Lemma 98 | (requires r_fresh l h0 h1 /\ modifies_none h1 h2) 99 | (ensures r_fresh l h0 h2) 100 | let rec r_fresh_fwd l h0 h1 h2 = 101 | match l with 102 | | [] -> () 103 | | r :: l' -> r_fresh_fwd l' h0 h1 h2 104 | 105 | val r_fresh_disjoint (r:subq) (l:list subq) (h0 h1 h2:mem) : Lemma 106 | (requires r_fresh l h0 h1 /\ fresh_region r h1 h2) 107 | (ensures rlist_disjoint r l) 108 | let rec r_fresh_disjoint r l h0 h1 h2 = 109 | match l with 110 | | [] -> () 111 | | r' :: l' -> 112 | lemma_extends_disjoint quic_region r r'; 113 | r_fresh_disjoint r l' h0 h1 h2 114 | 115 | val r_fresh_forall: l:list subq -> h0:mem -> h1:mem -> Lemma 116 | ((forall r.{:pattern fresh_region r h0 h1} List.Tot.mem r l ==> fresh_region r h0 h1) <==> 117 | r_fresh l h0 h1) 118 | let rec r_fresh_forall l h0 h1 = 119 | match l with 120 | | [] -> () 121 | | r :: l' -> r_fresh_forall l' h0 h1 122 | 123 | (** Allocates n pairwise disjoint subregions of tls_region *) 124 | val r_disjoint_alloc: n:nat -> ST (l:list subq) 125 | (requires fun h0 -> True) 126 | (ensures fun h0 l h1 -> 127 | modifies_none h0 h1 /\ 128 | r_fresh l h0 h1 /\ 129 | List.Tot.length l == n /\ 130 | r_pairwise_disjoint l) 131 | 132 | let rec r_disjoint_alloc n = 133 | if n = 0 then [] 134 | else 135 | begin 136 | let h0 = ST.get () in 137 | let l = r_disjoint_alloc (n-1) in 138 | let h1 = ST.get () in 139 | let r = new_region quic_region in 140 | let h2 = ST.get () in 141 | r_fresh_disjoint r l h0 h1 h2; 142 | r_fresh_fwd l h0 h1 h2; 143 | r :: l 144 | end 145 | 146 | #pop-options 147 | 148 | // We use region disjointness as a coarse grained way of framing invariants. 149 | let top_regions: (l:list subq{List.Tot.length l == 5 /\ r_pairwise_disjoint l}) 150 | = r_disjoint_alloc 5 151 | 152 | let q_ae_region = List.Tot.index top_regions 0 153 | let q_pne_region = List.Tot.index top_regions 1 154 | let q_idx_region = List.Tot.index top_regions 2 155 | 156 | #push-options "--z3rlimit 40 --max_fuel 5 --max_ifuel 0" 157 | 158 | val top_regions_disjoint: i:nat{i < 5} -> j:nat{j < 5} -> Lemma 159 | (requires i <> j) 160 | (ensures (List.Tot.index top_regions i) `HS.disjoint` (List.Tot.index top_regions j)) 161 | [SMTPat (List.Tot.index top_regions i); SMTPat (List.Tot.index top_regions j)] 162 | let top_regions_disjoint i j = () 163 | 164 | #pop-options 165 | 166 | /// Loc-based disjointness 167 | /// 168 | /// `loc_region_only` has GTot effect so we need to thunk these to avoid 169 | /// problems with top-level masked effects 170 | 171 | val loc_ae_region: unit -> GTot loc 172 | let loc_ae_region _ = loc_region_only true q_ae_region 173 | 174 | val loc_pne_region: unit -> GTot loc 175 | let loc_pne_region _ = loc_region_only true q_pne_region 176 | 177 | val loc_idx_region: unit -> GTot loc 178 | let loc_idx_region _ = loc_region_only true q_idx_region 179 | 180 | (** Sanity check: this works with fuel=0, ifuel=0 because of the lemma above *) 181 | let _ = assert (all_disjoint 182 | [loc_ae_region (); 183 | loc_pne_region (); 184 | loc_idx_region (); 185 | // loc_psk_region (); 186 | // loc_crf_region () 187 | ]) 188 | -------------------------------------------------------------------------------- /src/QUIC.Impl.Lemmas.fsti: -------------------------------------------------------------------------------- 1 | module QUIC.Impl.Lemmas 2 | include QUIC.Spec.Lemmas 3 | 4 | module G = FStar.Ghost 5 | module S = QUIC.Secret.Seq 6 | 7 | module U64 = FStar.UInt64 8 | module U32 = FStar.UInt32 9 | module U8 = FStar.UInt8 10 | 11 | module QS = QUIC.Spec.Crypto 12 | module QSL = QUIC.Spec.Lemmas 13 | 14 | module Secret = QUIC.Secret.Int 15 | module B = LowStar.Buffer 16 | module HST = FStar.HyperStack.ST 17 | 18 | val lemma_five_cuts (#t: Type) (s: S.seq t) (i1 i2 i3 i4 i5: nat) (s0 s1 s2 s3 s4 s5: S.seq t): Lemma 19 | (requires ( 20 | i1 <= S.length s /\ 21 | i2 <= S.length s /\ 22 | i3 <= S.length s /\ 23 | i4 <= S.length s /\ 24 | i5 <= S.length s /\ 25 | i1 <= i2 /\ 26 | i2 <= i3 /\ 27 | i3 <= i4 /\ 28 | i4 <= i5 /\ 29 | s0 `S.equal` S.slice s 0 i1 /\ 30 | s1 `S.equal` S.slice s i1 i2 /\ 31 | s2 `S.equal` S.slice s i2 i3 /\ 32 | s3 `S.equal` S.slice s i3 i4 /\ 33 | s4 `S.equal` S.slice s i4 i5 /\ 34 | s5 `S.equal` S.slice s i5 (S.length s))) 35 | (ensures ( 36 | let open S in 37 | s `equal` (s0 @| s1 @| s2 @| s3 @| s4 @| s5))) 38 | 39 | val hash_is_keysized_ (a: QS.ha): Lemma 40 | (ensures (QS.keysized a (Spec.Hash.Definitions.hash_length a))) 41 | 42 | val lemma_slice (#t: Type) (s: S.seq t) (i: nat { i <= S.length s }): Lemma 43 | (ensures (s `S.equal` S.append (S.slice s 0 i) (S.slice s i (S.length s)))) 44 | 45 | val lemma_slice3 (#a: Type) (s: S.seq a) (i j: nat): Lemma 46 | (requires (i <= j /\ j <= S.length s)) 47 | (ensures (s `S.equal` 48 | (S.slice s 0 i `S.append` S.slice s i j `S.append` S.slice s j (S.length s)))) 49 | 50 | val lemma_slice0 (#a: Type) (s: S.seq a): Lemma (S.slice s 0 (S.length s) `S.equal` s) 51 | 52 | val lemma_slice1 (#a: Type) (s: S.seq a) (i j: nat): Lemma 53 | (requires (i <= j /\ j <= S.length s)) 54 | (ensures (S.slice s 0 j `S.equal` 55 | (S.slice s 0 i `S.append` S.slice s i j))) 56 | 57 | open FStar.Mul 58 | 59 | /// Lemmas about pointwise_op 60 | /// ------------------------------------------- 61 | 62 | val pointwise_upd (#a: Type) (f: a -> a -> Tot a) (b1 b2: S.seq a) (i: nat) (pos: nat) (x: a): Lemma 63 | (requires (S.length b2 + pos <= S.length b1 /\ i < pos)) 64 | (ensures (S.upd (QSL.pointwise_op f b1 b2 pos) i x `S.equal` 65 | QSL.pointwise_op f (S.upd b1 i x) b2 pos)) 66 | 67 | val pointwise_seq_map2 (#a: Type) (f: a -> a -> a) (s1 s2: S.seq a) (i: nat): Lemma 68 | (requires ( 69 | let l = S.length s1 in 70 | S.length s2 = l - i /\ i <= S.length s1)) 71 | (ensures ( 72 | let l = S.length s1 in 73 | Spec.Loops.seq_map2 f (S.slice s1 i l) s2 `S.equal` 74 | S.slice (QSL.pointwise_op f s1 s2 i) i l)) 75 | (decreases (S.length s2)) 76 | 77 | val and_inplace_commutative (s1 s2: S.seq U8.t): Lemma 78 | (requires S.length s1 = S.length s2) 79 | (ensures Spec.Loops.seq_map2 U8.logand s1 s2 `S.equal` 80 | Spec.Loops.seq_map2 U8.logand s2 s1) 81 | (decreases (S.length s1)) 82 | 83 | val seq_map2_xor0 (s1 s2: S.seq Secret.uint8): Lemma 84 | (requires 85 | S.length s1 = S.length s2 /\ 86 | s1 `S.equal` S.create (S.length s2) (Secret.to_u8 0uy)) 87 | (ensures 88 | Spec.Loops.seq_map2 EverCrypt.CTR.xor8 s1 s2 `S.equal` s2) 89 | (decreases (S.length s1)) 90 | 91 | val upd_op_inplace (#a:Type) (op: a -> a -> Tot a) (s: S.seq a) (x: a): Lemma 92 | (requires S.length s > 0) 93 | (ensures (S.upd s 0 (S.index s 0 `op` x) `S.equal` 94 | QSL.pointwise_op op s (S.create 1 x) 0)) 95 | 96 | val be_to_n_slice (s: S.seq U8.t) (i: nat): Lemma 97 | (requires i <= S.length s) 98 | (ensures FStar.Endianness.be_to_n (S.slice s i (S.length s)) = 99 | FStar.Endianness.be_to_n s % pow2 (8 `op_Multiply` (S.length s - i))) 100 | (decreases (S.length s)) 101 | 102 | val n_to_be_lower 103 | (len: nat) 104 | (len' : nat) 105 | (n: nat) 106 | : Lemma 107 | (requires ( 108 | len <= len' /\ 109 | n < pow2 (8 * len) 110 | )) 111 | (ensures ( 112 | let open FStar.Endianness in 113 | n < pow2 (8 * len') /\ 114 | n_to_be len n `S.equal` S.slice (n_to_be len' n) (len' - len) len' 115 | )) 116 | 117 | val n_to_be_lower' 118 | (len: nat) 119 | (len' : nat) 120 | (n: nat) 121 | : Lemma 122 | (requires ( 123 | len <= len' /\ 124 | n < pow2 (8 * len) 125 | )) 126 | (ensures ( 127 | let open FStar.Endianness in 128 | n < pow2 (8 * len') /\ 129 | n_to_be len' n `S.equal` (S.create (len' - len) 0uy `S.append` n_to_be len n) 130 | )) 131 | 132 | (* Inplace implementation of pointwise_op *) 133 | 134 | inline_for_extraction noextract 135 | val op_inplace 136 | (#t: Type) 137 | (dst: B.buffer t) 138 | (src: B.buffer t) 139 | (src_len: U32.t) 140 | (ofs: U32.t) 141 | (op: t -> t -> t) 142 | : 143 | HST.Stack unit 144 | (requires fun h0 -> 145 | B.(all_live h0 [ buf dst; buf src ]) /\ 146 | B.disjoint dst src /\ 147 | B.length src == U32.v src_len /\ 148 | B.length dst >= U32.v ofs + B.length src) 149 | (ensures fun h0 _ h1 -> 150 | B.(modifies (loc_buffer dst) h0 h1) /\ 151 | B.as_seq h1 dst `S.equal` 152 | pointwise_op op (B.as_seq h0 dst) (B.as_seq h0 src) (U32.v ofs) /\ 153 | S.slice (B.as_seq h0 dst) 0 (U32.v ofs) `S.equal` 154 | S.slice (B.as_seq h1 dst) 0 (U32.v ofs) /\ 155 | S.slice (B.as_seq h0 dst) (U32.v (ofs `U32.add` src_len)) (B.length dst) `S.equal` 156 | S.slice (B.as_seq h1 dst) (U32.v (ofs `U32.add` src_len)) (B.length dst)) 157 | 158 | (* Secret operation specs *) 159 | 160 | let secret_and_inplace (b1 b2:S.seq Secret.uint8) (pos:nat) 161 | : Pure (S.seq Secret.uint8) 162 | (requires S.length b2 + pos <= S.length b1) 163 | (ensures fun b -> S.length b == S.length b1) 164 | = 165 | pointwise_op (Secret.logand #Secret.U8 #Secret.SEC) b1 b2 pos 166 | 167 | val secret_and_inplace_eq 168 | (b1 b2: S.seq Secret.uint8) 169 | (pos: nat) 170 | : Lemma 171 | (requires (S.length b2 + pos <= S.length b1)) 172 | (ensures ( 173 | S.length b2 + pos <= S.length b1/\ 174 | S.seq_reveal (secret_and_inplace b1 b2 pos) `S.equal` and_inplace (S.seq_reveal b1) (S.seq_reveal b2) pos 175 | )) 176 | [SMTPat (secret_and_inplace b1 b2 pos)] 177 | 178 | let secret_xor_inplace (b1 b2:Seq.seq Secret.uint8) (pos:nat) 179 | : Pure (Seq.seq Secret.uint8) 180 | (requires Seq.length b2 + pos <= Seq.length b1) 181 | (ensures fun b -> Seq.length b == Seq.length b1) 182 | = 183 | pointwise_op (Secret.logxor #Secret.U8 #Secret.SEC) b1 b2 pos 184 | 185 | val secret_xor_inplace_eq 186 | (b1 b2: S.seq Secret.uint8) 187 | (pos: nat) 188 | : Lemma 189 | (requires (S.length b2 + pos <= S.length b1)) 190 | (ensures ( 191 | S.length b2 + pos <= S.length b1/\ 192 | S.seq_reveal (secret_xor_inplace b1 b2 pos) `S.equal` xor_inplace (S.seq_reveal b1) (S.seq_reveal b2) pos 193 | )) 194 | [SMTPat (secret_xor_inplace b1 b2 pos)] 195 | -------------------------------------------------------------------------------- /hints/QUIC.Impl.Header.Parse.fsti.hints: -------------------------------------------------------------------------------- 1 | [ 2 | "7d683b88123fb925ba5fd98931743766", 3 | [ 4 | [ 5 | "QUIC.Impl.Header.Parse.public_header_len_is_pn_offset", 6 | 1, 7 | 2, 8 | 1, 9 | [ 10 | "@MaxIFuel_assumption", "@query", "bool_inversion", 11 | "constructor_distinct_QUIC.Spec.Header.Base.MHandshake", 12 | "constructor_distinct_QUIC.Spec.Header.Base.MInitial", 13 | "constructor_distinct_QUIC.Spec.Header.Base.MLong", 14 | "constructor_distinct_QUIC.Spec.Header.Base.MShort", 15 | "constructor_distinct_QUIC.Spec.Header.Base.MZeroRTT", 16 | "disc_equation_QUIC.Impl.Header.Base.BLong", 17 | "disc_equation_QUIC.Impl.Header.Base.BRetry", 18 | "disc_equation_QUIC.Spec.Header.Base.MLong", 19 | "disc_equation_QUIC.Spec.Header.Base.MRetry", 20 | "equation_FStar.Monotonic.HyperHeap.hmap", 21 | "equation_FStar.Monotonic.HyperStack.is_tip", 22 | "equation_FStar.Monotonic.HyperStack.is_wf_with_ctr_and_tip", 23 | "equation_FStar.Monotonic.HyperStack.mem", 24 | "equation_QUIC.Impl.Header.Base.g_header", 25 | "equation_QUIC.Impl.Header.Base.is_retry", 26 | "equation_QUIC.Spec.Header.Base.is_retry", 27 | "fuel_guarded_inversion_QUIC.Impl.Header.Base.header", 28 | "fuel_guarded_inversion_QUIC.Impl.Header.Base.long_header_specifics", 29 | "function_token_typing_FStar.Monotonic.Heap.heap", 30 | "lemma_FStar.Map.lemma_ContainsDom", "primitive_Prims.op_AmpAmp", 31 | "proj_equation_QUIC.Impl.Header.Base.BLong_spec", 32 | "proj_equation_QUIC.Spec.Header.Base.MLong_spec", 33 | "projection_inverse_BoxBool_proj_0", 34 | "projection_inverse_QUIC.Spec.Header.Base.MLong_dcid", 35 | "projection_inverse_QUIC.Spec.Header.Base.MLong_scid", 36 | "projection_inverse_QUIC.Spec.Header.Base.MLong_spec", 37 | "projection_inverse_QUIC.Spec.Header.Base.MLong_version", 38 | "refinement_interpretation_Tm_refine_05e15190c946858f68c69156f585f95a", 39 | "refinement_interpretation_Tm_refine_1492f4895393222aa77bbbc6dc655326", 40 | "refinement_interpretation_Tm_refine_df7141b051e9600374b6a7fbebd3eca8", 41 | "typing_FStar.Map.contains", "typing_FStar.Monotonic.HyperHeap.rid", 42 | "typing_FStar.Monotonic.HyperStack.get_hmap", 43 | "typing_FStar.Monotonic.HyperStack.get_tip", 44 | "typing_QUIC.Impl.Header.Base.__proj__BLong__item__spec", 45 | "typing_QUIC.Impl.Header.Base.is_retry", 46 | "typing_QUIC.Spec.Header.Base.is_retry" 47 | ], 48 | 0, 49 | "5ea906888e4dd2cfc68de6c12b33b929" 50 | ], 51 | [ 52 | "QUIC.Impl.Header.Parse.header_len_correct", 53 | 1, 54 | 2, 55 | 1, 56 | [ "@query" ], 57 | 0, 58 | "edc7546efc76a689ac1dc631c2f23d35" 59 | ], 60 | [ 61 | "QUIC.Impl.Header.Parse.write_header", 62 | 1, 63 | 2, 64 | 1, 65 | [ 66 | "@MaxIFuel_assumption", "@query", "bool_inversion", 67 | "constructor_distinct_Lib.IntTypes.PUB", 68 | "constructor_distinct_Lib.IntTypes.U32", 69 | "constructor_distinct_Lib.IntTypes.U8", 70 | "equality_tok_Lib.IntTypes.PUB@tok", 71 | "equality_tok_Lib.IntTypes.SEC@tok", 72 | "equality_tok_Lib.IntTypes.U32@tok", 73 | "equality_tok_Lib.IntTypes.U8@tok", "equation_Lib.IntTypes.byte_t", 74 | "equation_Lib.IntTypes.int_t", "equation_Lib.IntTypes.minint", 75 | "equation_Lib.IntTypes.pub_int_t", "equation_Lib.IntTypes.range", 76 | "equation_Lib.IntTypes.unsigned", "equation_Lib.IntTypes.v", 77 | "equation_LowStar.Buffer.buffer", 78 | "equation_LowStar.Buffer.trivial_preorder", "equation_Prims.eqtype", 79 | "equation_QUIC.Impl.Header.Base.is_retry", 80 | "function_token_typing_Lib.IntTypes.byte_t", 81 | "lemma_LowStar.Monotonic.Buffer.length_as_seq", 82 | "primitive_Prims.op_LessThanOrEqual", 83 | "projection_inverse_BoxBool_proj_0", 84 | "refinement_interpretation_Tm_refine_3a7ee7b4fcebce48cea41cb8a1be947d", 85 | "refinement_interpretation_Tm_refine_414d0a9f578ab0048252f8c8f552b99f", 86 | "refinement_interpretation_Tm_refine_4b278dbc0dccd817818cfad7ade30d15", 87 | "typing_FStar.UInt8.t", "typing_LowStar.Buffer.trivial_preorder", 88 | "typing_QUIC.Impl.Header.Base.is_retry" 89 | ], 90 | 0, 91 | "0844c0bd3007784ee7b99db7db39cb9e" 92 | ], 93 | [ 94 | "QUIC.Impl.Header.Parse.putative_pn_offset", 95 | 1, 96 | 2, 97 | 1, 98 | [ 99 | "@query", "b2t_def", "equation_FStar.UInt.fits", 100 | "equation_FStar.UInt.min_int", "equation_FStar.UInt.size", 101 | "primitive_Prims.op_AmpAmp", "primitive_Prims.op_LessThanOrEqual", 102 | "projection_inverse_BoxBool_proj_0" 103 | ], 104 | 0, 105 | "9f01202c65c7984b615f1b2e3dc3fe2e" 106 | ], 107 | [ 108 | "QUIC.Impl.Header.Parse.read_header", 109 | 1, 110 | 2, 111 | 1, 112 | [ 113 | "@MaxIFuel_assumption", "@query", "b2t_def", 114 | "constructor_distinct_Lib.IntTypes.U64", 115 | "disc_equation_FStar.Pervasives.Native.None", 116 | "disc_equation_FStar.Pervasives.Native.Some", 117 | "equality_tok_Lib.IntTypes.SEC@tok", 118 | "equality_tok_Lib.IntTypes.U64@tok", "equation_FStar.UInt.fits", 119 | "equation_FStar.UInt.min_int", "equation_FStar.UInt.size", 120 | "equation_FStar.UInt.uint_t", "equation_Lib.IntTypes.minint", 121 | "equation_Lib.IntTypes.range", "equation_Lib.IntTypes.unsigned", 122 | "equation_Lib.IntTypes.v", "equation_Prims.nat", 123 | "equation_QUIC.Spec.PacketNumber.Base.last_packet_number_t", 124 | "equation_QUIC.UInt62.bound", "equation_QUIC.UInt62.secret", 125 | "int_inversion", "primitive_Prims.op_Addition", 126 | "primitive_Prims.op_AmpAmp", "primitive_Prims.op_LessThanOrEqual", 127 | "projection_inverse_BoxBool_proj_0", 128 | "projection_inverse_BoxInt_proj_0", 129 | "refinement_interpretation_Tm_refine_527d85e49cee936bcf8c285d50eeaa76", 130 | "refinement_interpretation_Tm_refine_78f5e8a506254fe27e2444ae9b7bd7fb", 131 | "refinement_interpretation_Tm_refine_83845a86f2550cdf941eeb1d9b59602b", 132 | "refinement_interpretation_Tm_refine_bc091439e537dad49a811907a6d15e1b", 133 | "refinement_interpretation_Tm_refine_cac8aa68b54068bf033c8d3d335357f8", 134 | "refinement_interpretation_Tm_refine_cfb1e053a2878b8fbd187297e44bc30d", 135 | "refinement_interpretation_Tm_refine_f13070840248fced9d9d60d77bdae3ec", 136 | "typing_FStar.UInt32.v", "typing_Lib.IntTypes.v", 137 | "typing_QUIC.UInt62.bound", "typing_tok_Lib.IntTypes.SEC@tok", 138 | "typing_tok_Lib.IntTypes.U64@tok" 139 | ], 140 | 0, 141 | "2f9507f545a39c01bc99da06c64c5bbd" 142 | ] 143 | ] 144 | ] -------------------------------------------------------------------------------- /hints/QUIC.Spec.Crypto.fsti.hints: -------------------------------------------------------------------------------- 1 | [ 2 | "f4638d94317dcb26b474404ccdab9646", 3 | [ 4 | [ 5 | "QUIC.Spec.Crypto.as_cipher_alg", 6 | 1, 7 | 2, 8 | 1, 9 | [ 10 | "@MaxIFuel_assumption", "@query", "bool_inversion", 11 | "constructor_distinct_Lib.IntTypes.U8", 12 | "equality_tok_Lib.IntTypes.U1@tok", 13 | "equality_tok_Lib.IntTypes.U8@tok", 14 | "equality_tok_Spec.Agile.Cipher.AES128@tok", 15 | "equality_tok_Spec.Agile.Cipher.AES256@tok", 16 | "equality_tok_Spec.Agile.Cipher.CHACHA20@tok", 17 | "equation_Lib.IntTypes.unsigned", "equation_QUIC.Spec.Crypto.ea", 18 | "equation_QUIC.Spec.Crypto.supported_aead", "equation_Spec.AES.gf8", 19 | "equation_Spec.AES.irred", 20 | "equation_Spec.Agile.AEAD.is_supported_alg", 21 | "equation_Spec.GaloisField.gf", 22 | "fuel_guarded_inversion_Spec.Agile.Cipher.cipher_alg", 23 | "proj_equation_Spec.GaloisField.GF_t", 24 | "projection_inverse_Spec.GaloisField.GF_t", 25 | "refinement_interpretation_Tm_refine_69c8dece313a8e5d48c4e41a27b5d1ae", 26 | "refinement_interpretation_Tm_refine_de8080fdc4bd6678af723874a7d70466", 27 | "typing_QUIC.Spec.Crypto.supported_aead", "typing_Spec.AES.gf8", 28 | "typing_Spec.GaloisField.__proj__GF__item__t" 29 | ], 30 | 0, 31 | "6f435d819f5fb3c67c0fd861f2a461e9" 32 | ], 33 | [ 34 | "QUIC.Spec.Crypto.cipher_keysize", 35 | 1, 36 | 2, 37 | 1, 38 | [ 39 | "@query", "equation_QUIC.Spec.Crypto.supported_aead", 40 | "equation_Spec.Agile.AEAD.is_supported_alg" 41 | ], 42 | 0, 43 | "87132c091cb48d146dd03a2e8578b01c" 44 | ], 45 | [ 46 | "QUIC.Spec.Crypto.max_plain_length", 47 | 1, 48 | 2, 49 | 1, 50 | [ 51 | "@MaxFuel_assumption", "@MaxIFuel_assumption", 52 | "@fuel_correspondence_Prims.pow2.fuel_instrumented", 53 | "@fuel_irrelevance_Prims.pow2.fuel_instrumented", "@query", 54 | "constructor_distinct_FStar.Integers.Signed", 55 | "constructor_distinct_FStar.Integers.Winfinite", 56 | "constructor_distinct_Lib.IntTypes.U8", 57 | "constructor_distinct_Tm_unit", 58 | "equality_tok_FStar.Integers.Winfinite@tok", 59 | "equality_tok_Lib.IntTypes.U1@tok", 60 | "equality_tok_Lib.IntTypes.U8@tok", "equation_FStar.Integers.int_t", 61 | "equation_Lib.IntTypes.minint", "equation_Lib.IntTypes.unsigned", 62 | "equation_Prims.nat", "equation_QUIC.Spec.Base.header_len_bound", 63 | "equation_Spec.AES.gf8", "equation_Spec.AES.irred", 64 | "equation_Spec.Agile.AEAD.max_length", 65 | "equation_Spec.Chacha20.size_key", "equation_Spec.GaloisField.gf", 66 | "equation_with_fuel_Prims.pow2.fuel_instrumented", "int_inversion", 67 | "int_typing", "lemma_FStar.UInt.pow2_values", 68 | "primitive_Prims.op_Multiply", "primitive_Prims.op_Subtraction", 69 | "proj_equation_Spec.GaloisField.GF_t", 70 | "projection_inverse_BoxInt_proj_0", 71 | "projection_inverse_FStar.Integers.Signed__0", 72 | "projection_inverse_Spec.GaloisField.GF_t", 73 | "refinement_interpretation_Tm_refine_542f9d4f129664613f2483a6c88bc7c2", 74 | "refinement_interpretation_Tm_refine_90a1661541e4f009452ab107b47b5955", 75 | "refinement_interpretation_Tm_refine_de8080fdc4bd6678af723874a7d70466", 76 | "typing_Spec.AES.gf8", "typing_Spec.Agile.AEAD.max_length", 77 | "typing_Spec.Chacha20.size_key", 78 | "typing_Spec.GaloisField.__proj__GF__item__t" 79 | ], 80 | 0, 81 | "20c9fc1719a4b27cb2f5105a6ccfff41" 82 | ], 83 | [ 84 | "QUIC.Spec.Crypto.max_cipher_length", 85 | 1, 86 | 2, 87 | 1, 88 | [ 89 | "@MaxFuel_assumption", "@MaxIFuel_assumption", 90 | "@fuel_correspondence_Prims.pow2.fuel_instrumented", 91 | "@fuel_irrelevance_Prims.pow2.fuel_instrumented", "@query", 92 | "constructor_distinct_FStar.Integers.Signed", 93 | "constructor_distinct_FStar.Integers.W16", 94 | "constructor_distinct_FStar.Integers.W8", 95 | "constructor_distinct_FStar.Integers.Winfinite", 96 | "constructor_distinct_Lib.IntTypes.U1", 97 | "constructor_distinct_Lib.IntTypes.U128", 98 | "constructor_distinct_Lib.IntTypes.U16", 99 | "constructor_distinct_Lib.IntTypes.U8", 100 | "constructor_distinct_Tm_unit", 101 | "equality_tok_FStar.Integers.W16@tok", 102 | "equality_tok_FStar.Integers.W8@tok", 103 | "equality_tok_FStar.Integers.Winfinite@tok", 104 | "equality_tok_Lib.IntTypes.U1@tok", 105 | "equality_tok_Lib.IntTypes.U8@tok", "equation_FStar.Integers.int_t", 106 | "equation_Lib.IntTypes.minint", "equation_Lib.IntTypes.unsigned", 107 | "equation_Prims.nat", "equation_QUIC.Spec.Base.header_len_bound", 108 | "equation_Spec.AES.gf8", "equation_Spec.AES.irred", 109 | "equation_Spec.Agile.AEAD.max_length", 110 | "equation_Spec.Agile.AEAD.supported_alg", 111 | "equation_Spec.Agile.AEAD.tag_length", 112 | "equation_Spec.Chacha20.size_key", "equation_Spec.GaloisField.gf", 113 | "equation_with_fuel_Prims.pow2.fuel_instrumented", "int_inversion", 114 | "int_typing", "lemma_FStar.UInt.pow2_values", 115 | "primitive_Prims.op_Addition", "primitive_Prims.op_Multiply", 116 | "primitive_Prims.op_Subtraction", 117 | "proj_equation_Spec.GaloisField.GF_t", 118 | "projection_inverse_BoxInt_proj_0", 119 | "projection_inverse_FStar.Integers.Signed__0", 120 | "projection_inverse_FStar.Integers.Unsigned__0", 121 | "projection_inverse_Spec.GaloisField.GF_t", 122 | "refinement_interpretation_Tm_refine_542f9d4f129664613f2483a6c88bc7c2", 123 | "refinement_interpretation_Tm_refine_90a1661541e4f009452ab107b47b5955", 124 | "refinement_interpretation_Tm_refine_ce5a1bd8437baa640019cd70bf466fc0", 125 | "refinement_interpretation_Tm_refine_de8080fdc4bd6678af723874a7d70466", 126 | "typing_Spec.AES.gf8", "typing_Spec.Agile.AEAD.max_length", 127 | "typing_Spec.Agile.AEAD.tag_length", "typing_Spec.Chacha20.size_key", 128 | "typing_Spec.GaloisField.__proj__GF__item__t" 129 | ], 130 | 0, 131 | "2e25535b7be7346289d14d86a99b3893" 132 | ], 133 | [ 134 | "QUIC.Spec.Crypto.derive_secret", 135 | 1, 136 | 2, 137 | 1, 138 | [ 139 | "@MaxIFuel_assumption", "@query", "bool_inversion", 140 | "equation_QUIC.Spec.Crypto.ha", 141 | "equation_QUIC.Spec.Crypto.supported_hash", 142 | "equation_Spec.Hash.Definitions.is_shake", 143 | "projection_inverse_BoxBool_proj_0", 144 | "refinement_interpretation_Tm_refine_837aaa25c6967f53b930fd73a3026b51", 145 | "typing_QUIC.Spec.Crypto.supported_hash", 146 | "typing_Spec.Hash.Definitions.is_shake" 147 | ], 148 | 0, 149 | "8a40ea59fe4ba4d0f95211a9ffc29656" 150 | ] 151 | ] 152 | ] --------------------------------------------------------------------------------