diff --git a/UnitTest1/unittest1.cpp b/UnitTest1/unittest1.cpp
index 158a925aa85f5aec40ec99732d15b9182f90b4fa..2a8cec84c8ccf54b43e49a8c58085ecd8a9f972c 100644
--- a/UnitTest1/unittest1.cpp
+++ b/UnitTest1/unittest1.cpp
@@ -604,5 +604,12 @@ namespace UnitTest1
 
             Assert::AreEqual(ret, 0);
         }
+
+        TEST_METHOD(fuzz)
+        {
+            int ret = fuzz_test();
+
+            Assert::AreEqual(ret, 0);
+        }
     };
 }
diff --git a/picoquic/picoquic.h b/picoquic/picoquic.h
index 2e9aa4f26c18f9d87d39da0c5642c3fa135f16cd..49b5de2645339d37a5e5fd4844685f1e39c10908 100644
--- a/picoquic/picoquic.h
+++ b/picoquic/picoquic.h
@@ -272,6 +272,13 @@ typedef void (*picoquic_stream_data_cb_fn)(picoquic_cnx_t* cnx,
 typedef void (*cnx_id_cb_fn)(picoquic_connection_id_t cnx_id_local,
     picoquic_connection_id_t cnx_id_remote, void* cnx_id_cb_data, picoquic_connection_id_t * cnx_id_returned);
 
+/* The fuzzer function is used to inject error in packets randomly.
+ * It is called just prior to sending a packet, and can randomly
+ * change the content or length of the packet.
+ */
+typedef uint32_t(*picoquic_fuzz_fn)(void * fuzz_ctx, picoquic_cnx_t* cnx, uint8_t * bytes, size_t bytes_max, size_t length);
+void picoquic_set_fuzz(picoquic_quic_t* quic, picoquic_fuzz_fn fuzz_fn, void * fuzz_ctx);
+
 /* Will be called to verify that the given data corresponds to the given signature.
  * This callback and the `verify_ctx` will be set by the `verify_certificate_cb_fn`.
  * If `data` and `sign` are empty buffers, an error occurred and `verify_ctx` should be freed.
diff --git a/picoquic/picoquic_internal.h b/picoquic/picoquic_internal.h
index f5c586a3ad61ab91253cc02c29f06c33acb92684..c4b4c6221c012ffd1cc8fad109b359134c6f2f25 100644
--- a/picoquic/picoquic_internal.h
+++ b/picoquic/picoquic_internal.h
@@ -211,6 +211,9 @@ typedef struct st_picoquic_quic_t {
     picoquic_free_verify_certificate_ctx free_verify_certificate_callback_fn;
     void* verify_certificate_ctx;
     uint8_t local_ctx_length;
+
+    picoquic_fuzz_fn fuzz_fn;
+    void* fuzz_ctx;
 } picoquic_quic_t;
 
 picoquic_packet_context_enum picoquic_context_from_epoch(int epoch);
@@ -679,13 +682,13 @@ uint32_t picoquic_protect_packet(picoquic_cnx_t* cnx,
     picoquic_packet_type_enum ptype,
     uint8_t * bytes, uint64_t sequence_number,
     uint32_t length, uint32_t header_length,
-    uint8_t* send_buffer,
+    uint8_t* send_buffer, uint32_t send_buffer_max,
     void * aead_context, void* pn_enc);
 
 void picoquic_finalize_and_protect_packet(picoquic_cnx_t *cnx, picoquic_packet * packet, int ret,
     uint32_t length, uint32_t header_length, uint32_t checksum_overhead,
-    size_t * send_length, uint8_t * send_buffer, picoquic_path_t * path_x,
-    uint64_t current_time);
+    size_t * send_length, uint8_t * send_buffer, uint32_t send_buffer_max,
+    picoquic_path_t * path_x, uint64_t current_time);
 
 int picoquic_parse_header_and_decrypt(
     picoquic_quic_t* quic,
diff --git a/picoquic/quicctx.c b/picoquic/quicctx.c
index 325646885e8cf49318dddae61224eda1ffd151aa..9919a00cf2e2216fb306afa46deed12d5ad688cc 100644
--- a/picoquic/quicctx.c
+++ b/picoquic/quicctx.c
@@ -1057,6 +1057,12 @@ uint64_t picoquic_get_quic_time(picoquic_quic_t* quic)
     return now;
 }
 
+void picoquic_set_fuzz(picoquic_quic_t * quic, picoquic_fuzz_fn fuzz_fn, void * fuzz_ctx)
+{
+    quic->fuzz_fn = fuzz_fn;
+    quic->fuzz_ctx = fuzz_ctx;
+}
+
 
 
 void picoquic_set_callback(picoquic_cnx_t* cnx,
diff --git a/picoquic/sender.c b/picoquic/sender.c
index ea8cf658b7aaae749daa83f2e97773c2eceb899a..add1c0f840ebb553af5cc9ac2f09a2a10f1d2f67 100644
--- a/picoquic/sender.c
+++ b/picoquic/sender.c
@@ -385,7 +385,7 @@ uint32_t picoquic_protect_packet(picoquic_cnx_t* cnx,
     uint8_t * bytes, 
     uint64_t sequence_number,
     uint32_t length, uint32_t header_length,
-    uint8_t* send_buffer,
+    uint8_t* send_buffer, uint32_t send_buffer_max,
     void * aead_context, void* pn_enc)
 {
     uint32_t send_length;
@@ -394,7 +394,7 @@ uint32_t picoquic_protect_packet(picoquic_cnx_t* cnx,
     size_t sample_offset = 0;
     size_t sample_size = picoquic_pn_iv_size(pn_enc);
     uint32_t pn_length = 0;
-    size_t aead_checksum_length = picoquic_aead_get_checksum_length(aead_context);
+    uint32_t aead_checksum_length = (uint32_t)picoquic_aead_get_checksum_length(aead_context);
 
     /* Create the packet header just before encrypting the content */
     h_length = picoquic_create_packet_header(cnx, ptype,
@@ -403,6 +403,19 @@ uint32_t picoquic_protect_packet(picoquic_cnx_t* cnx,
     /* Using encryption, the "payload" length also includes the encrypted packet length */
     picoquic_update_payload_length(send_buffer, pn_offset, h_length - pn_length, length + aead_checksum_length);
 
+    /* If fuzzing is required, apply it*/
+    if (cnx->quic->fuzz_fn != NULL) {
+        if (h_length == header_length) {
+            memcpy(bytes, send_buffer, header_length);
+        }
+        length = cnx->quic->fuzz_fn(cnx->quic->fuzz_ctx, cnx, bytes,
+            send_buffer_max - aead_checksum_length, length);
+        if (h_length == header_length) {
+            memcpy(send_buffer, bytes, header_length);
+        }
+    }
+
+    /* Encrypt the packet */
     send_length = (uint32_t)picoquic_aead_encrypt_generic(send_buffer + /* header_length */ h_length,
         bytes + header_length, length - header_length,
         sequence_number, send_buffer, /* header_length */ h_length, aead_context);
@@ -500,8 +513,8 @@ void picoquic_queue_for_retransmit(picoquic_cnx_t* cnx, picoquic_path_t * path_x
 
 void picoquic_finalize_and_protect_packet(picoquic_cnx_t *cnx, picoquic_packet * packet, int ret, 
     uint32_t length, uint32_t header_length, uint32_t checksum_overhead,
-    size_t * send_length, uint8_t * send_buffer, picoquic_path_t * path_x,
-    uint64_t current_time)
+    size_t * send_length, uint8_t * send_buffer, uint32_t send_buffer_max, 
+    picoquic_path_t * path_x, uint64_t current_time)
 {
 
     if (ret == 0 && length > 0) {
@@ -515,28 +528,28 @@ void picoquic_finalize_and_protect_packet(picoquic_cnx_t *cnx, picoquic_packet *
         case picoquic_packet_initial:
             length = picoquic_protect_packet(cnx, packet->ptype, packet->bytes, packet->sequence_number,
                 length, header_length,
-                send_buffer, cnx->crypto_context[0].aead_encrypt, cnx->crypto_context[0].pn_enc);
+                send_buffer, send_buffer_max, cnx->crypto_context[0].aead_encrypt, cnx->crypto_context[0].pn_enc);
             break;
         case picoquic_packet_handshake:
             length = picoquic_protect_packet(cnx, packet->ptype, packet->bytes, packet->sequence_number,
                 length, header_length,
-                send_buffer, cnx->crypto_context[2].aead_encrypt, cnx->crypto_context[2].pn_enc);
+                send_buffer, send_buffer_max, cnx->crypto_context[2].aead_encrypt, cnx->crypto_context[2].pn_enc);
             break;
         case picoquic_packet_retry:
             length = picoquic_protect_packet(cnx, packet->ptype, packet->bytes, packet->sequence_number,
                 length, header_length,
-                send_buffer, cnx->crypto_context[0].aead_encrypt, cnx->crypto_context[0].pn_enc);
+                send_buffer, send_buffer_max, cnx->crypto_context[0].aead_encrypt, cnx->crypto_context[0].pn_enc);
             break;
         case picoquic_packet_0rtt_protected:
             length = picoquic_protect_packet(cnx, packet->ptype, packet->bytes, packet->sequence_number,
                 length, header_length,
-                send_buffer, cnx->crypto_context[1].aead_encrypt, cnx->crypto_context[1].pn_enc);
+                send_buffer, send_buffer_max, cnx->crypto_context[1].aead_encrypt, cnx->crypto_context[1].pn_enc);
             break;
         case picoquic_packet_1rtt_protected_phi0:
         case picoquic_packet_1rtt_protected_phi1:
             length = picoquic_protect_packet(cnx, packet->ptype, packet->bytes, packet->sequence_number,
                 length, header_length,
-                send_buffer, cnx->crypto_context[3].aead_encrypt, cnx->crypto_context[3].pn_enc);
+                send_buffer, send_buffer_max, cnx->crypto_context[3].aead_encrypt, cnx->crypto_context[3].pn_enc);
             break;
         default:
             /* Packet type error. Do nothing at all. */
@@ -1028,7 +1041,7 @@ static void picoquic_cnx_set_next_wake_time_init(picoquic_cnx_t* cnx, uint64_t c
 /* TODO: tie with per path scheduling */
 void picoquic_cnx_set_next_wake_time(picoquic_cnx_t* cnx, uint64_t current_time)
 {
-    uint64_t next_time = cnx->latest_progress_time + PICOQUIC_MICROSEC_SILENCE_MAX;
+    uint64_t next_time = cnx->latest_progress_time + PICOQUIC_MICROSEC_SILENCE_MAX * (2 - cnx->client_mode);
     picoquic_stream_head* stream = NULL;
     int timer_based = 0;
     int blocked = 1;
@@ -1202,7 +1215,7 @@ int picoquic_prepare_packet_0rtt(picoquic_cnx_t* cnx, picoquic_path_t * path_x,
 
     picoquic_finalize_and_protect_packet(cnx, packet,
         ret, length, header_length, checksum_overhead,
-        send_length, send_buffer, path_x, current_time);
+        send_length, send_buffer, send_buffer_max, path_x, current_time);
 
     if (length > 0) {
         /* Accounting of zero rtt packets sent */
@@ -1497,7 +1510,7 @@ int picoquic_prepare_packet_client_init(picoquic_cnx_t* cnx, picoquic_path_t * p
     } else {
         picoquic_finalize_and_protect_packet(cnx, packet,
             ret, length, header_length, checksum_overhead,
-            send_length, send_buffer, path_x, current_time);
+            send_length, send_buffer, send_buffer_max, path_x, current_time);
 
         if (cnx->cnx_state != picoquic_state_draining) {
             picoquic_cnx_set_next_wake_time(cnx, current_time);
@@ -1644,7 +1657,7 @@ int picoquic_prepare_packet_server_init(picoquic_cnx_t* cnx, picoquic_path_t * p
 
     picoquic_finalize_and_protect_packet(cnx, packet,
         ret, length, header_length, checksum_overhead,
-        send_length, send_buffer, path_x, current_time);
+        send_length, send_buffer, send_buffer_max, path_x, current_time);
 
     picoquic_cnx_set_next_wake_time(cnx, current_time);
 
@@ -1865,7 +1878,7 @@ int picoquic_prepare_packet_closing(picoquic_cnx_t* cnx, picoquic_path_t * path_
 
     picoquic_finalize_and_protect_packet(cnx, packet,
         ret, length, header_length, checksum_overhead,
-        send_length, send_buffer, path_x, current_time);
+        send_length, send_buffer, send_buffer_max, path_x, current_time);
 
     return ret;
 }
@@ -2099,7 +2112,7 @@ int picoquic_prepare_packet_ready(picoquic_cnx_t* cnx, picoquic_path_t * path_x,
 
     picoquic_finalize_and_protect_packet(cnx, packet,
         ret, length, header_length, checksum_overhead,
-        send_length, send_buffer, path_x, current_time);
+        send_length, send_buffer, send_buffer_min_max, path_x, current_time);
 
     picoquic_cnx_set_next_wake_time(cnx, current_time);
 
@@ -2114,7 +2127,7 @@ int picoquic_prepare_segment(picoquic_cnx_t* cnx, picoquic_path_t * path_x, pico
   
     /* Check that the connection is still alive -- the timer is asymmetric, so client will drop faster */
     if ((cnx->cnx_state < picoquic_state_disconnecting && 
-        (current_time - cnx->latest_progress_time) > (PICOQUIC_MICROSEC_SILENCE_MAX*(2 - cnx->client_mode))) ||
+        (current_time - cnx->latest_progress_time) >= (PICOQUIC_MICROSEC_SILENCE_MAX*(2 - cnx->client_mode))) ||
         (cnx->cnx_state < picoquic_state_client_ready &&
             current_time >= cnx->start_time + PICOQUIC_MICROSEC_HANDSHAKE_MAX))
     {
diff --git a/picoquic_t/picoquic_t.c b/picoquic_t/picoquic_t.c
index d0359cd44b024521b9936ecb2b2225712ca138a1..3e7499ed123e6c17d7ba04a46f9f4b218c4e82ea 100644
--- a/picoquic_t/picoquic_t.c
+++ b/picoquic_t/picoquic_t.c
@@ -126,7 +126,8 @@ static const picoquic_test_def_t test_table[] = {
     { "pn_vector", cleartext_pn_vector_test },
     { "zero_rtt_spurious", zero_rtt_spurious_test },
     { "zero_rtt_retry", zero_rtt_retry_test },
-    { "stress", stress_test }
+    { "stress", stress_test },
+    { "fuzz", fuzz_test }
 };
 
 static size_t const nb_tests = sizeof(test_table) / sizeof(picoquic_test_def_t);
@@ -174,6 +175,7 @@ int usage(char const * argv0)
     fprintf(stderr, "Options: \n");
     fprintf(stderr, "  -x test        Do not run the specified test.\n");
     fprintf(stderr, "  -s nnn         Run stress for nnn minutes.\n");
+    fprintf(stderr, "  -f nnn         Run fuzz for nnn minutes.\n");
     fprintf(stderr, "  -h             Print this help message\n");
 
     return -1;
@@ -201,6 +203,8 @@ int main(int argc, char** argv)
     int found_exclusion = 0;
     test_status_t * test_status = (test_status_t *) calloc(nb_tests, sizeof(test_status_t));
     int opt;
+    int do_fuzz = 0;
+    int do_stress = 0;
 
     if (test_status == NULL)
     {
@@ -209,7 +213,7 @@ int main(int argc, char** argv)
     }
     else
     {
-        while (ret == 0 && (opt = getopt(argc, argv, "s:x:h")) != -1) {
+        while (ret == 0 && (opt = getopt(argc, argv, "f:s:x:h")) != -1) {
             switch (opt) {
             case 'x': {
                 int test_number = get_test_number(optarg);
@@ -224,7 +228,16 @@ int main(int argc, char** argv)
                 }
                 break;
             }
+            case 'f':
+                do_fuzz = 1;
+                stress_minutes = atoi(optarg);
+                if (stress_minutes <= 0) {
+                    fprintf(stderr, "Incorrect stress minutes: %s\n", optarg);
+                    ret = usage(argv[0]);
+                }
+                break;
             case 's':
+                do_stress = 1;
                 stress_minutes = atoi(optarg);
                 if (stress_minutes <= 0) {
                     fprintf(stderr, "Incorrect stress minutes: %s\n", optarg);
@@ -244,7 +257,17 @@ int main(int argc, char** argv)
         if (ret == 0 && stress_minutes > 0) {
             if (optind >= argc && found_exclusion == 0) {
                 for (size_t i = 0; i < nb_tests; i++) {
-                    if (strcmp(test_table[i].test_name, "stress") != 0) {
+                    if (strcmp(test_table[i].test_name, "stress") == 0)
+                    {
+                        if (do_stress == 0){
+                            test_status[i] = test_excluded;
+                        }
+                    }
+                    else if (strcmp(test_table[i].test_name, "fuzz") == 0) {
+                        if (do_fuzz == 0) {
+                            test_status[i] = test_excluded;
+                        }
+                    } else {
                         test_status[i] = test_excluded;
                     }
                 }
diff --git a/picoquictest/parseheadertest.c b/picoquictest/parseheadertest.c
index 905397c79457b22be69333fc6a0ebd3d82039fc6..e8daa1a749a02d0e975726b8458271f7d0e05c03 100644
--- a/picoquictest/parseheadertest.c
+++ b/picoquictest/parseheadertest.c
@@ -503,7 +503,7 @@ int test_packet_encrypt_one(
         /* Create a packet with specified parameters */
         picoquic_finalize_and_protect_packet(cnx_client, packet,
             ret, length, header_length, checksum_overhead,
-            &send_length, send_buffer, path_x, current_time);
+            &send_length, send_buffer, PICOQUIC_MAX_PACKET_SIZE, path_x, current_time);
 
         expected_header.ptype = packet->ptype;
         expected_header.offset = packet->offset;
diff --git a/picoquictest/picoquictest.h b/picoquictest/picoquictest.h
index 33c22d0c4e93278f7bc63974f9a119876efe8e68..b2b6008fabf7ee434df6c1b2bdb2098bc206c560 100644
--- a/picoquictest/picoquictest.h
+++ b/picoquictest/picoquictest.h
@@ -119,6 +119,7 @@ int stress_test();
 int splay_test();
 int TlsStreamFrameTest();
 int draft13_vector_test();
+int fuzz_test();
 
 #ifdef __cplusplus
 }
diff --git a/picoquictest/stresstest.c b/picoquictest/stresstest.c
index 8953377e3da04022f727f74610ac71af7729b337..0ac81045f4281b3fa0abce7ef69e1cc71507e481 100644
--- a/picoquictest/stresstest.c
+++ b/picoquictest/stresstest.c
@@ -861,11 +861,12 @@ static void stress_delete_client_context(int client_index, picoquic_stress_ctx_t
     }
 }
 
-int stress_test()
+static int stress_or_fuzz_test(picoquic_fuzz_fn fuzz_fn, void * fuzz_ctx)
 {
     int ret = 0;
     picoquic_stress_ctx_t stress_ctx;
     double run_time_seconds = 0;
+    double target_seconds = 0;
     double wall_time_seconds = 0;
     uint64_t wall_time_start = picoquic_current_time();
     uint64_t wall_time_max = wall_time_start + picoquic_stress_test_duration;
@@ -895,6 +896,9 @@ int stress_test()
         else {
             for (int i = 0; ret == 0 && i < stress_ctx.nb_clients; i++) {
                 ret = stress_create_client_context(i, &stress_ctx);
+                if (ret == 0 && fuzz_fn != NULL) {
+                    picoquic_set_fuzz(stress_ctx.c_ctx[i]->qclient, fuzz_fn, fuzz_ctx);
+                }
             }
         }
     }
@@ -946,9 +950,81 @@ int stress_test()
 
     /* Report */
     run_time_seconds = ((double)stress_ctx.simulated_time) / 1000000.0;
+    target_seconds = ((double)picoquic_stress_test_duration) / 1000000.0;
     wall_time_seconds = ((double)(picoquic_current_time() - wall_time_start)) / 1000000.0;
-    DBG_PRINTF("Stress complete after simulating %3f s. in %3f s., returns %d\n",
-        run_time_seconds, wall_time_seconds, ret);
+
+    if (stress_ctx.simulated_time < picoquic_stress_test_duration) {
+        DBG_PRINTF("Stress incomplete after simulating %3fs instead of %3fs in %3f s., returns %d\n",
+            run_time_seconds, target_seconds, wall_time_seconds, ret);
+        ret = -1;
+    }
+    else {
+        DBG_PRINTF("Stress complete after simulating %3f s. in %3f s., returns %d\n",
+            run_time_seconds, wall_time_seconds, ret);
+    }
 
     return ret;
 }
+
+int stress_test()
+{
+    return stress_or_fuzz_test(NULL, NULL);
+}
+
+/*
+ * Basic fuzz test just tries to flip some bits in random packets
+ */
+
+typedef struct st_basic_fuzzer_ctx_t {
+    uint64_t random_context;
+    picoquic_state_enum highest_state_fuzzed;
+} basic_fuzzer_ctx_t;
+
+static uint32_t basic_fuzzer(void * fuzz_ctx, picoquic_cnx_t* cnx, uint8_t * bytes, size_t bytes_max, size_t length)
+{
+    basic_fuzzer_ctx_t * ctx = (basic_fuzzer_ctx_t *)fuzz_ctx;
+    uint64_t fuzz_pilot = picoquic_test_random(&ctx->random_context);
+    int should_fuzz = 0;
+    uint32_t fuzz_index = 0;
+
+    if (cnx->cnx_state > ctx->highest_state_fuzzed) {
+        should_fuzz = 1;
+        ctx->highest_state_fuzzed = cnx->cnx_state;
+    } else {
+        /* if already fuzzed this state, fuzz one packet in 16 */
+        should_fuzz = ((fuzz_pilot & 0xF) == 0xD);
+        fuzz_pilot >>= 4;
+    }
+
+    if (should_fuzz) {
+        /* Once in 64, fuzz by changing the length */
+        if (bytes_max > length + 16  && (fuzz_pilot & 0x3F) == 0x2B) {
+            fuzz_pilot >>= 6;
+            length = 16 + (uint32_t)((fuzz_pilot&0xFFFF) % length);
+            fuzz_pilot >>= 16;
+        }
+        /* Find the position that shall be fuzzed */
+        fuzz_index = (uint32_t)((fuzz_pilot & 0xFFFF) % length);
+        fuzz_pilot >>= 16;
+        while (fuzz_pilot != 0 && fuzz_index < length) {
+            /* flip one byte */
+            bytes[fuzz_index++] = (uint8_t)(fuzz_pilot & 0xFF);
+            fuzz_pilot >>= 8;
+        }
+    }
+
+    return length;
+}
+
+int fuzz_test()
+{
+    basic_fuzzer_ctx_t fuzz_ctx;
+    int ret = 0;
+
+    fuzz_ctx.highest_state_fuzzed = 0;
+    fuzz_ctx.random_context = 0xDEADBEEFBABACAFEull;
+
+    ret = stress_or_fuzz_test(basic_fuzzer, &fuzz_ctx);
+
+    return ret;
+}
\ No newline at end of file