CS 395T: Systems Verification and Synthesis Spring 2023

Homework 4: Dafny

Due date: April 3, 10pm
Grading: 5% of your course grade: 1% for Problem 1, 2% each for Problems 2 and 3

Dafny is a verification-ready programming language. It's an imperative language, vaguely influenced by C#, but with built-in automatic verification to check the correctness of your code as you write it. Once your code is confirmed to be correct by the Dafny verifier, it can be automatically compiled to languages like C#, Go, or JavaScript.

In this homework we'll use Dafny to verify some CS 101 algorithms. You've certainly seen these algorithms before, and possibly even discussed informally why they're correct. But convincing Dafny of their correctness is another matter. We'll learn how to write pre- and post-conditions for these algorithms and how to use loop invariants.

Table of contents

Prerequisites

We'll be working with Dafny in this homework, so the first step is to it set up on your system.

I strongly suggest using Visual Studio Code to complete this homework, as it has a full-featured Dafny integration with many nice features. Regardless of operating system, install Visual Studio Code before going any further.

Now install the Dafny VSCode extension by clicking the Install button on its homepage or by searching for dafny-lang.ide-vscode in VSCode's extension pane. Make sure you get the right extension, as there are some deprecated ones still available—the one you're looking for is authored by "dafny-lang" rather than "Correctness Lab".

Next, follow the appropriate instructions below for your system to get the extension fully set up. If any of the instructions are unclear, see the official Dafny installation instructions for more detailed help. In every case, make sure you accept Dafny version 4.0.0 when the extension asks.

macOS

Install the .NET 6.0 SDK installer from the Microsoft website. Make sure you choose "SDK" rather than "ASP.NET". Don't try to install the SDK from Homebrew—you'll get a version that's too new to run Dafny.

That should be all you need to do. The first time you open a .dfy file in VSCode, the Dafny extension will automatically download and install the latest Dafny release.

Linux

Install the .NET 6.0 SDK by following the instructions for your distribution.

That should be all you need to do. The first time you open a .dfy file in VSCode, the Dafny extension will automatically download and install the latest Dafny release.

Windows

Nothing more to do! The first time you open a .dfy file in VSCode, the Dafny extension will automatically download and install the latest Dafny release.

Set up the code

We'll be using GitHub Classroom to check out and submit this homework. Follow the GitHub Classroom URL on Canvas to create your private copy of the homework repository, and then clone that repository to your machine. For example, the repository it created for me is called hw4-jamesbornholt, so I would do:

git clone git@github.com:cs395t-svs/hw4-jamesbornholt.git
cd hw4-jamesbornholt

To make sure everything's working, open the Homework.dfy file from this directory in VSCode. You should see "Could not prove" in the bottom left of the window (in the status bar), and some red squiggly underlines scattered around the file. You'll know you've finished the homework when you see "Verification Succeeded"!

Homework problems

A correct implementation of LinearSearch is already provided. Your job is to fill in the postconditions and loop invariants such that the LinearSearchTest method verifies successfully. Don't modify LinearSearchTest or any of the LinearSearch code—you should only add ensures and invariant clauses.

This time, you'll need to write your own correct implementation of binary search, and then add postconditions and loop invariants to make the BinarySearchTest method verify successfully. The precondition Sorted(s) is already provided, so don't modify that, or add any more preconditions.

One thing I found useful for writing specifications on this problem was the x in s[..] notation (and its !in counterpart) for stating that an element appears in a (sub)range of s. You can restrict the .. to a subrange like 4.. if you don't want to talk about the entire sequence.

Problem 3: Selection sort

For this problem you'll need to implement selection sort. However, unlike the textbook version of selection sort, you should build the sorted section of the array at the end of the array instead of the start. You should still sort in ascending order, though.

Note that this problem uses an array instead of a sequence. We want to sort the array in-place, so there's a modifies a clause to tell Dafny we're mutating a, and you'll need to swap elements between slots of the array. You can still write a[..] to convert the array into a sequence for use in invariants.

This time the pre- and post-conditions are already provided; don't add or change any requires or ensures clauses. You do, however, need to provide some loop invariants for the loops your implementation will need.

Resources for writing Dafny

Dafny is a "verification-ready" programming language. To a first approximation, it's like C# but with some weird syntactic differences, and then with pre/postconditions and assertions added to the language.

There's a good collection of Dafny resources on the Dafny website. In particular, the cheatsheet is good as a quick reference for syntax, and the Getting Started tutorial, while long, shows everything you'll need for this homework. The CS 345H lecture notes for Dafny and for Hoare logic also cover most of what you'll need for this homework.

Dafny can be frustrating at times. I have two suggestions of important tenets to keep in mind when writing Dafny:

  1. When Dafny says "Could not prove", it's choosing its words very carefully. It doesn't mean the assertion (or precondition, or postcondition, or invariant) is incorrect! It means Dafny wasn't able to prove the assertion was correct. That could mean the assertion is wrong, but often it just means Dafny doesn't "know enough" to prove what you're asking. This is especially true around loops, which "forget" most facts, and so force you to write loop invariants if there's a fact you want to use in an assertion after the invariant. To debug these issues, try just writing a list of asserts, starting from the simplest thing and increasingly adding back pieces until you get to the actual assertion you want. Somewhere along the way you'll find what fact Dafny isn't able to deduce on its own.
  2. It's very important to understand why something is true before you start trying to actually prove it. For these algorithms questions, first think informally about why the algorithms are correct. Since they involve loops, that usually means thinking about how the algorithm "makes progress" as the loop iterates more times. What new facts do you learn after each loop iteration? That's usually a good starting point to start thinking about what the invariants of the loop might be, and from there, what the postcondition of the entire method is.

What to submit

Submit your solutions by committing your changes in Git and pushing them to the private repository GitHub Classroom created for you in the Set up the code step. If you haven't used Git before, Chapters 1 and 2 of the Git book are a good tutorial.

The only file you should need to modify is Homework.dfy. GitHub will automatically select your most recent pushed commit before the deadline as your submission; there's no need to manually submit anything else via Canvas or GitHub.

GitHub Classroom will autograde your submission every time you push, by just running the Dafny verifier on Homework.dfy. If you can't complete the entire homework and so the autograder fails, don't worry—I will still be grading manually for partial credit. In particular, the autograder doesn't know about the points breakdown between problems.