Viewing Results for "cryptol" (2 of 6 Pages)

Cryptol Course: High-assurance Cryptographic Development Using the Cryptol Workbench

Galois is offering a four‐day Cryptol course for those interested in exploring the capabilities of the Cryptol workbench.The course is highly participatory: we will work on a series of exercises for each new topic, using the Cryptol toolset interactively. Prospective participants should have experience writing programs and some knowledge of cryptography. Those who complete the course will have the skills necessary to develop high‐assurance, high‐performance cryptographic algorithms in Cryptol. A tentative outline and further information can be found in the course flyer. Interested parties should contact Dr. Sally Browning via e-mail at sally@galois.com, or call her at (503) 808 7151.

Read More

Solving n-Queens in Cryptol

The eight queens puzzle asks how to place eight queens on a chess board such that none of them attacks any other. The problem easily generalizes to n queens, using an nxn board. In this post, we’ll see how to solve the n-Queens puzzle in Cryptol, without lifting a finger!

Representing the board

It is easy to see that any solution to the n-Queens puzzle will have precisely one queen on each row and column of the board. Therefore, we can represent the solution as a sequence of n row numbers, corresponding to subsequent columns. For instance, the board pictured below (taken from the wikipedia page), can be represented by the sequence3  7  0  2  5  1  6  4
recording the row of the queen appearing in each consecutive column, starting from the top-left position. (And yes, we always count from 0!)

Read More

Shuffling a deck of cards, Cryptol style

I can never shuffle cards properly. They seem to go every which way when I try, and a perfect random shuffle seems nigh-impossible to achieve, even though the experts claim it takes a mere 7 moves. (The mathematical argument is surprisingly quite technical.) Luckily, we shall concern ourselves with a much simpler problem today: How many perfect out-shuffles does it take to restore a deck back to its original order? We’ll throw in a couple of variants of the problem for fun, but rest assured that we’ll let computers do the work. And, of course, we’ll use Cryptol to help us along the way.

What is a riffle shuffle?

According to wikipedia, a riffle (or dovetail) shuffle goes like this:

… half of the deck is held in each hand with the thumbs inward, then cards are released by the thumbs so that they fall to the table interleaved. Many also lift the cards up after a riffle, forming what is called a bridge which puts the cards back into place…

Well, I read that a couple times, and watched a couple of videos on the internet showing how to do it, but no luck so far. Luckily, this sort of shuffling is quite easy to express programmatically, and Cryptol has the right abstractions to code this in a couple of lines.

Bisecting the deck

The first step in the shuffle is bisecting the deck into two equal halves:

bisect : {a b} (fin a) => [2*a]b -> ([a]b, [a]b);bisect xs = (take (w, xs), drop (w, xs))where w = width xs / 2;

We simply compute the mid-point, and divide the given sequence xs into two, by take‘ing and drop‘ping the correct amounts from the input sequence. In fact, the type of bisect is more interesting than its definition: It succinctly captures the following four facts:

  1. The input has to be of even length (2*a),
  2. The input has to be finite (fin a),
  3. The output has two components, each of which has precisely a elements, that is, half the input,
  4. The actual contents of the sequence can be of any type (b), i.e., the function bisect is shape-polymorphic in the contents.

The ability to express precise size/shape-polymorphic properties using types is one of the strengths of Cryptol.

Out-shuffle vs in-shuffle

Once the deck is split into two, we proceed by picking the cards alternatingly from each half. We have two choices: We can either start with the first half, or the second. If you start with the first half, that’s called an out-shuffle. If you start with the second half, then it’s an in-shuffle. These two functions are actually quite easy to code in Cryptol:

 outShuffle : {a b} (fin a) => [2*a]b -> [2*a]b;outShuffle xs = join [| [x y] || x <- fh || y <- sh |]where (fh, sh) = bisect xs;inShuffle : {a b} (fin a) => [2*a]b -> [2*a]b;inShuffle xs = join [| [y x] || x <- fh || y <- sh |]where (fh, sh) = bisect xs;

The definitions are almost identical, except for the order in which we put the cards from the halves (fh and sh) together. In the outShuffle, the first card in each pair comes from the first-half. In the inShuffle, it comes from the second half. Easier done than said! Let’s make sure they behave as we expect:

 Cryptol> bisect [1..8]([1 2 3 4], [5 6 7 8])Cryptol> outShuffle [1..8][1 5 2 6 3 7 4 8]Cryptol> inShuffle [1..8][5 1 6 2 7 3 8 4]

Good! It’s interesting to see what happens when we apply bisect to an odd-length sequence:

 Crytpol> bisect [1..9]In a top-level expression: with inferred type:{a} ([a][4],[a][4])encountered the following unresolved constraints:fin a2*a == 9

Cryptol is basically telling us that there is no a such that 2*a is 9, resulting in a type-error. Note that this is a static-check before you run your program! In other words, if your program type-checks, then you can rest assured that whenever you call bisect, it is guaranteed to get an even-length sequence as its argument. Strong static typing and size-polymorphism of Cryptol really pays off in this case!

Sequences of shuffles

Before proceeding to the properties of shuffles, we need one last notion: The application of a shuffle repeatedly to a given input, yielding an infinite sequence of transformations:

 iterate : {a} (a -> a, a) -> [inf]a;iterate (f, x) = [x] # iterate (f, f x);outShuffles, inShuffles :{a b} (fin a) => [2*a]b -> [inf][2*a]b;outShuffles xs = iterate(outShuffle, xs);inShuffles xs = iterate(inShuffle, xs);

The high-order function iterate gives us the infinite sequence of results of applying a function to a value over and over. We simply use this helper to define outShuffles and inShuffles to apply the corresponding functions indefinitely to their input. Note that the resulting type shows that we get an infinite sequence as output, as indicated by the size inf.

Properties of shuffles

It turns out that if one applies 8 out-shuffles to a deck, a remarkable thing happens: Nothing! The deck goes back to its original order! This is a bit hard to believe, and harder to realize using a real deck of cards. (A friend of mine says he saw it done at college once by hand, but I’m yet to meet anyone who can do this successfully so far!)Well, the good thing about programming is that we can manipulate the sequences at will, without fear of messing up the cards. Even better, we can assert the above claim as a theorem in Cryptol:

 type Deck = [52][6];outShuffle8 : Deck -> Bit;theorem outShuffle8: {deck}.outShuffles(deck) @ 8 == deck;

We have defined a Deck to be a sequence of 52 things, each of which is 6-bits wide, which is more than enough to cover all the 52-unique elements that appear in an ordinary deck. (6-bits can encode 64 values, so we have 12 unused elements.) The theorem simply states that the 8’th element of the infinite sequence of outShuffle applied to an arbitrary deck gives us back the original deck.Let’s ask Cryptol to prove this theorem: (Cryptol’s symbolic and sbv backends can perform these proofs, so we first set our mode accordingly below.)

 Cryptol> :set sbvCryptol> :prove outShuffle8Q.E.D.

Voila! The proof completes instantaneously, with almost no time elapsed. (This might be surprising at first, since the input space to the theorem has 52*6 = 312 bits, which is quite large. However, we note that the theorem is actually fairly easy to prove since all shuffling does is a mere re-ordering of things with no specific computation; which is easy to manipulate symbolically for Cryptol’s proof engine.)

Reversing the deck

Can we reverse a deck of cards using outShuffle‘s? Turns out that this cannot be done. In particular, an outShuffle never moves the first element of the deck anywhere:

 outShuffleFirstCard : Deck -> Bit;theorem outShuffleFirstCard: {deck}.outShuffle deck @ 0 == deck @ 0;

We have:

 Cryptol> :prove outShuffleFirstCardQ.E.D.

Since the first card remains stationary, there is no way to reverse a deck of cards by just using outShuffles.How about with inShuffle? Turns out the magic number is 26 for reversing a deck of cards in this particular case:

inShuffle26Rev : Deck -> Bit;theorem inShuffle26Rev : {deck}.inShuffles(deck) @ 26 == reverse deck;

Again, the proof is immediate:

 Cryptol> :prove inShuffle26RevQ.E.D.

If 26 in-shuffle’s reverse the deck, then 52 of them will restore it back. Here’s the corresponding theorem:

inShuffle52 : Deck -> Bit;theorem inShuffle52: {deck}.inShuffles(deck) @ 52 == deck;

Again, the proof is immediate.

The Mongean Shuffle

There is one more variation on the shuffle that we w
ill consider. The mongean shuffle picks the even and odd numbered elements, reverses the odds and adds the evens at the back. For instance, given the sequence: 0 1 2 3 4 5 6 7 8 9, we first construct two sub-sequences: The even index elements: 0 2 4 6 8, and the odd ones 1 3 5 7 9. We then reverse the latter to get 9 7 5 3 1, and append the former, obtaining: 9 7 5 3 1 0 2 4 6 8. Luckily, the Cryptol definition is much easier to read:

monge xs = reverse odds # evenswhere { w = width xs;evens = xs @@ [0 2 .. (w-1)];odds = xs @@ [1 3 .. (w-1)]};monges xs = iterate(monge, xs);

With a monge shuffle, it takes 12 rounds to restore a deck:

monge12 : Deck -> Bit;theorem monge12: {deck}. monges(deck) @ 12 == deck;

We will leave it to the reader to construct the argument that no sequence of monge shuffles would reverse a deck. (In particular, one can prove that the 18th element from top will never move in a deck of 52. Proving this theorem in Cryptol is again quite trivial.)

A note on theorems

The attentive reader might worry that our Deck type does not quite correspond to a deck-of-cards. This is indeed the case. There are two discrepancies. First, as we mentioned before, our decks can represent 64 elements, while a deck of cards has only 52 distinct cards. On the plus side, this just makes our theorems “stronger,” since we allow for more cards then possible. More importantly, the properties are intended for decks that have no-repeating cards in them. (That is, every card occurs precisely once.) But our theorems apply to arbitrary deck‘s, even those that have repeating elements in them. Again, this just makes our theorems stronger, as the unique-sequence cases directly follow from them. We can rest assured that our proofs are conclusive, even though our model of playing-cards is not perfect.

Download

Free evaluation licenses of Cryptol are available at www.cryptol.net. The Cryptol source code for shuffling cards is also available as well.

Read More

Substitution ciphers in Cryptol

Substitution ciphers are one of the oldest encryption methods, dating back to at least the 15th century. In a substitution cipher, each character in the plain-text is simply “substituted” according to a predefined map. Decryption is simply the substitution in the reverse direction. Wikipedia has a nice description of these ciphers. Obviously, you wouldn’t want your bank to use such a cipher when executing your web-based transactions! But they are fun to play around, especially when entertaining kids in hot summer days. In this post, we’ll see how to code simple substitution ciphers in Cryptol, and go a step further and actually prove that our implementation is correct.

Preliminaries

The simplest form of substitution ciphers use a permutation of the input alphabet. That is, each letter in the input alphabet gets mapped to another in the same  alphabet. (Strictly speaking, input and output alphabets need not be the same, but nothing essential changes by making that assumption.) For instance, you might decide that your substitution will map ‘a’ to ‘q’, and ‘b’ to ‘d’, …, etc., making sure no two letters are mapped to the same target. Once this mapping is agreed on, all you have to do to encrypt a given message is to map each character to the corresponding element according to your predefined mapping rules.Here’s our Cryptol encoding of these ciphers. First, some preliminary declarations:

type Char = [8];type String(l) = [l]Char;type Table(n) = [n](Char, Char);

We’ll simply assume that the input consist of “characters,” each of which will be 8-bit quantities (i.e., numbers from 0 to 255). We will simply use ASCII encoding for normal English characters. This is captured by the Char type declaration above, which simply gives a convenient name for 8-bit wide words. The second type declaration captures sized-strings: For any given size l, the type String(l) represents a sequence of length l, containing 8-bit words. For instance, String(16) is the type of all sequences of length 16, containing numbers from 0 to 255 as elements. Finally a Table of size n is simply n-pairings of characters that form a substitution. Here’s the example table we will use:

cipherTable : Table(28);cipherTable = [| (x, y) || x <- plain || y <- cipher |]where { plain = "abcdefghijklmnopqrstuvwxyz .";cipher = "oebxa.cdf hijklmnzpqtuvwrygs"};

Note that our table has 28 entries (the lower-case English alphabet, plus space and the dot). A simple Cryptol sequence-comprehension succinctly zips the sequences up, forming our example table.

Read More

Verifying Legato’s multiplier in Cryptol

Consider the following multiplication algorithm, coded in Mostek 6502 Assembler:

 LDX #8 ; 1; load X immediate with the 8LDA #0 ; 2; load A immediate with the 0CLC ; 3; set C to 0LOOP ROR F1 ; 4; rotate F1 right circular through CBCC ZCOEF ; 5; branch to ZCOEF if C = 0CLC ; 6; set C to 0ADC F2 ; 7; set A to A+F2+C and C to the carryZCOEF ROR A ; 8; rotate A right circular through CROR LOW ; 9; rotate LOW right circular through CDEX ;10; set X to X-1BNE LOOP ;11; branch to LOOP if Z = 0

This program comes from Wilfred Legato’s paper “A Weakest Precondition Model for Assembly Language Programs.” It multiplies the contents of the memory locations F1 and F2; each of which is 8-bits wide. The result is stored in the accumulator register A and the memory location LOW, each of which is, again, 8-bits. It holds that:

 F1 * F2 = 256 * A + LOW

when the algorithm terminates, correctly handling the overflow. It is worth spending a moment or two pondering how this algorithm works; it is not at all obvious how the multiplication is done!Legato’s challenge  (as  referred to in ACL2 circles) is to prove a deep-embedding of Legato’s algorithm correct with respect to a Mostek simulator coded in ACL2. We do not attempt to solve  Legato’s challenge in Cryptol. We are merely interested in coding and proving that Legato’s multiplier is correct in Cryptol. Our interest stems from the fact that Legato’s algorithm is a truly interesting multiplier on its own right, and we would like to make sure that a straightforward encoding of it in Cryptol can be proven correct automatically by Cryptol’s verification tools. And of course, it’s just too hard to pass up on the opportunity to  pay respect to the Mostek chip that powered the Commodore 64‘s and Atari 800XL‘s of our childhood.

A shallow embedding

The Cryptol solution to Legato’s problem will be a fairly shallow encoding of the multiplier, together with an automated proof of correctness. We choose to do a shallow encoding here since it allows us to focus on the multiplication algorithm itself, as opposed to the particulars of the underlying Mostek chip. Theorem proving based solutions (such as those given by ACL2 folks) will rightly pursue a deeper embedding of the algorithm and the Mostek architecture in general. Cryptol is not particularly suitable for deep embeddings. Representing Mostek assembly instructions directly as Cryptol functions is a much simpler and straightforward choice.Looking at Legato’s multiplier above, we will represent each instruction (from 1 to 11) as a simple state transformer, taking a simplified representation of the Mostek machine state as input and delivering a new one. We will only represent parts of the state that matter for our problem. The following Cryptol type declaration succinctly captures what we need:

 type Mostek = ( [8] // F1, [8] // F2, [8] // A, [8] // X, [8] // LOW, Bit // C (Carry), Bit // Z (Zero));

Using this state representation, each instruction in the program can be modeled as a  state transformer:

 type Instruction = Mostek -> Mostek;

This takes care of the data-flow aspect of the embedding; but the question of how to model control-flow remains. We will simply use the host-language’s control-flow features, using the quintessential functional idiom: by calling functions! This is actually easier done than said, and here’s our embedding of the first instruction of the program:

 // step1: LDX #8; load X immediate with the integer 8.step1 : Instruction;step1 (f1, f2, a, _, l, c, z) =step2 (f1, f2, a, 8, l, c, z);

Let’s spend a minute explaining this in detail. The first step in the program loads the register X with the immediate value 8. Using our state-transformer model, our step1 function will receive a Mostek state (consisting of the “current” values of F1, F2, A, X, LOW, CARRY, and ZERO). The “effect” of this instruction is to put the value 8 into the register X, leaving everything else the same. Once this is done, the control goes to the next instruction, which we model by calling the function step2 (which is yet to be defined).In this fashion, we can shallowly embed all the instructions in Legato’s multiplier, using Cryptol’s native functions and control-flow features. Of course, this is hardly a new idea, being the essence of the whole domain-specific embedded language saga: Using a rich host-language to “fake” other languages.Following the recipe set by step1, it is easy to model the next two instructions:

 // step2: LDA #0; load A immediate with the integer 0.step2 : Instruction;step2 (f1, f2, _, x, l, c, z) =step3 (f1, f2, 0, x, l, c, z);// step3: CLC; set C to 0 (Note the use of Bit False here)step3 : Instruction;step3 (f1, f2, a, x, l, _, z) =step4 (f1, f2, a, x, l, False, z);

Step 4 is equally easy in terms of control flow, but is tricky in terms of operation. After some head-scratching, one figures out that the term “rotate F1 right circular through C” means put the right-most bit of F1 in C, and put C in the first position of F1. A bizarre thing to do indeed, but that’s the beauty of Legato’s multiplier. The Cryptol translation is almost literal:

// step4: LOOP ROR F1; rotate F1 right circular through C.step4 : Instruction;step4 (f1, f2, a, x, l, c, z) =step5 (f1', f2, a, x, l, b0, z)where {[b0 b1 b2 b3 b4 b5 b6 b7] = f1;f1' = [b1 b2 b3 b4 b5 b6 b7 c];};

The use of pattern matching in getting the bits out of f1, and the construction of the new value of f1 is idiomatic Cryptol. There’s one little catch though: Apparently Mostek was a big-endian machine, having a most-significant-bit-first representation. Cryptol is little-endian. So, instead of rotating the bits to right, we  rotate them left.The fifth instruction is the first time where we use Cryptol’s control-flow to model the Mostek jump instruction:

 // step5 : BCC ZCOEF; branch to ZCOEF if C = 0.// ZCOEF is step8 in our encodingstep5 (f1, f2, a, x, l, c, z)= if c then step6 (f1, f2, a, x, l, c, z)else step8 (f1, f2, a, x, l, c, z);

In this case, we simply receive a state, and depending on the value of the carry bit (C), we either go to the next step (i.e., no jump); or go to the ZCOEF instruction, which is going to be step-8 in our model. Easy as pie!Step-6 is a replica of Step-3, clearing the carry bit:

 // step6: CLC; set C to 0step6 (f1, f2, a, x, l, _, z) =step7 (f1, f2, a, x, l, False, z);

Step-7 is the most compute intensive part of the algorithm. The Cryptol encoding is a bit complicated due to the need to determine if there was a carry in the addition. Since all Cryptol arithmetic is modular, we are forced to do the computation at an extended bit-size. Otherwise, the modeling of the ADC instruction is quite straightforward:

 // step7: ADC F2; set A to A+F2+C and C to the carry.step7 (f1, f2, a, x, l, c, z) =step8 (f1, f2, a', x, l, c', z')where {// 8-bit "modular" resulta' = a + f2 + (if c then (1:[8]) else (0:[8]));// Was there a carry? Check that "real"// result is larger than 255a'Large : [9];a'Large =(a # zero) // extend a by adding zero bits+ (f2 # zero) // same for f2+ (if c then (1:[9]) else (0:[9]));c' = a'Large > (255:[9]);// set the zero flagz' = a' == 0;};

The Cryptol idiom x # zero simply represents the value x extended on the right with 0 bits. (Remember that Cryptol is little-endian, hence the addition of zero bits on the right does not change the value.) Due to the polymorphic type of the value zero, the result has any number of bits larger than equal to the original bit-size of x. (Since we only need 9-bits i
n this case, we could have coded the same via the expression x # [False], but the former expression is more idiomatic Cryptol.)Steps 8 and 9 are similar to Step-4, using A and LOW instead of F1, respectively:

 // step8 : ZCOEF ROR A; rotate A right circular through C.step8 : Instruction;step8 (f1, f2, a, x, l, c, z) =step9 (f1, f2, a', x, l, a0, z)where {[a0 a1 a2 a3 a4 a5 a6 a7] = a;a' = [a1 a2 a3 a4 a5 a6 a7 c];};// step9 : ROR LOW; rotate LOW right circular through C.step9 : Instruction;step9 (f1, f2, a, x, l, c, z) =step10 (f1, f2, a, x, l', l0, z)where {[l0 l1 l2 l3 l4 l5 l6 l7] = l;l' = [l1 l2 l3 l4 l5 l6 l7 c];};

Step-10 simply decrements X, setting the ZERO flag appropriately:

 // step10: DEX; set X to X-1step10 : Instruction;step10 (f1, f2, a, x, l, c, z) =step11 (f1, f2, a, x', l, c, x'==0)where x' = x-1;

Finally, step-11 either jumps back to the top of the loop (step-4), or finishes the algorithm:

 // step11: BNE LOOP; branch to LOOP if Z = 0.// LOOP is step4 in our encodingstep11 : Instruction;step11 (f1, f2, a, x, l, c, z)= if zthen (f1, f2, a, x, l, c, z) // done!else step4 (f1, f2, a, x, l, c, z);

From a control-flow perspective, we indicate the end of the algorithm by simply returning the final Mostek state. It is worthwile at this point to go through the Cryptol embeddings of the instructions to see how they match-up to the Mostek assembly given by Legato.

Extracting the multiplier

Having coded Legato’s multiplier as a sequence of state transformers, we can simply call the function step1 to use it with an appropriate state. The following helper function simplifies this task for us, by loading the registers F1 and F2, and extracting the high and low bits at the end:

legato : ([8], [8], Mostek) -> ([8], [8]);legato (f1, f2, st) = (hi, lo)where {// get the relevant parts// to construct the starting state(_, _, A, X, LOW, C, Z) = st;// Run legato multiplier;// final A is hi; and final LOW is low(_, _, hi, _, lo, _, _) =step1 (f1, f2, A, X, LOW, C, Z);};

Note that legato still takes the starting machine state st as an argument. Legato’s claim (which we will shortly prove) is that the algorithm works correctly no matter what the initial state is, hence it is important to be explicit about the starting state.To see legato in action, let’s just run it on a simple input:

 legato> legato (12, 93, (9, 42, 3, 8, 1, False, True))(4, 92)

where I just made up the initial state by plugging in some random values. If Legato is right, then it must be the case that

 12 * 93 = 256 * 4 + 92

correctly computing the high and low bytes. And voila! Both sides equal 1116. Magic!

Correctness

If you do believe in magic,  you can stop reading now. But I suspect most readers of the Galois blog will be looking for something more concrete. Surely, we must be able to give a better argument than claiming witchcraft for the correctness of our implementation.Let us first formally capture what we mean by “correct,” by writing a Cryptol theorem that expresses our intuitive expectation:

theoremlegatoIsCorrect: {x y st}. x' * y' == 256 * hi' + lo'where { (hi, lo) = legato (x, y, st);hi', lo', x', y' : [16];hi' = hi # zero;lo' = lo # zero;x' = x # zero;y' = y # zero};

Here’s the English reading of this theorem: “For all values of x, y, and st, if we run legato on these values and get the results hi and lo, then, it’ll be the case that x * y = 256 * hi + lo.” The only caveat is that we have to do arithmetic operations over 16 bit values (instead of 8), to make sure the theorem statement correctly captures the intended mathematical meaning. (Recall that all Cryptol arithmetic is modular with respect to the bit-size involved.) Hence, we simply add extra zero‘s at the end to enlarge the arguments to 16 bits. Note that, we do not have to assert that the value of lo is at most 255; this is automatically guaranteed by the fact that it is an 8-bit value. Cryptol’s bit-precise type system saves the day!

Verification

Here’s what happens when I run cryptol on the file containing the above theorem:

$ cryptol legato.cryCryptol version 1.8.5, Copyright (C) 2004-2009 Galois, Inc.www.cryptol.netType :? for helpLoading "legato.cry".. Checking types.. Processing.. Done!*** Auto quickchecking 1 theorem.*** Checking "legatoIsCorrect" ["legato.cry", line 147, col 1]Checking case 100 of 100 (100.00%)100 tests passed OK[Coverage: 3.47e-14%. (100/288230376151711744)]

When Cryptol sees a theorem declaration in a loaded file, it automatically performs a quick-check run to provide feedback on its validity. In this case, Cryptol automatically created 100 random test values for the theorem and checked that each one of them satisfied the statement. This is a quick way of getting feedback on the correctness of theorems, courtesy of Cryptol at no additonal cost to the user!While the quick-check run is promising, the coverage info indicates that we’ve barely scratched the surface. The entire state space in this case has 58 bits (8 each for x and y, plus the starting arbitrary state of the Mostek machine costing us an extra 42 bits; for a total of 58). The total number of possible inputs is, therefore, 258 or 288230376151711744. This is a huge number: If you had a computer that run 1-billion (109) test cases every second, it’d still take you over 9 years to go through all possible inputs!Of course, we can do better. Cryptol’s theorem proving environment uses modern equivalence-checkers to prove such theorems automatically, at the push of a (virtual) button:

 legato> :prove legatoIsCorrectQ.E.D.

And there, we’ve proved that our implementation of Legato’s multiplier is indeed correct for all possible inputs! (The above proof takes about 2.5 minutes to complete on my 3-year old MacBook Pro, using abc as the underlying equivalence checker in Cryptol’s symbolic mode. I should also note that the symbolic mode is only available in the full Cryptol release, for which free licenses are available.)

Closing thoughts

I must emphasize that we are not advocating Cryptol as a platform for doing proofs of algorithm correctness. Modern theorem provers such as ACL2, Coq, or Isabelle are the leading tools in this regard. (In particular, the logic behind Cryptol’s automated theorem prover is much less expressive, for starters.) Where Cryptol shines is in its restricted attention to bit-vectors and data-flow algorithms (cryptography being a prime application area), and it turns out that automated equivalence-checking based techniques do perform rather well for such problems. Our shallow embedding of Legato’s multiplier and the automated proof-of-correctness is a case in point.There is one more important point to make. While push-button provers are indispensable in industrial practice, the final Q.E.D. you get from an interactive theorem prover such as ACL2 or Isabelle is much more satisfactory. For instance, we can hardly claim that the above proof increased our understanding of Legato’s algorithm in any sense, it just made us really believe it. I’m willing to bet that anyone who goes through a similar proof in ACL2 or Isabelle would have a much higher chance of having their “aha!” moment, where everything just sinks in…On the practical side, however, nothing beats the fully-automated Q.E.D., especially when your boss is breathing down your neck!

Download

The Cryptol file containing Legato’s multiplier and the correctness theorem is here. The Cryptol toolset licenses are freely available at www.cryptol.net.

Read More

Solving Sudoku Using Cryptol

Cryptol is a language tailored for cryptographic algorithms. Sudoku is a popular puzzle the reader  is no-doubt already familiar with. We will offer no deep reason why anyone should try to solve Sudoku in Cryptol; other than the very fact that it’d be a shame if we couldn’t!Needless to say, Cryptol has not been designed for encoding search algorithms. Nonetheless, some of the features of Cryptol and its associated toolset make it extremely suitable for expressing certain constraint satisfaction problems very concisely; and Sudoku very nicely falls into this category.

Representing the board

A Sudoku board can be represented in a variety of ways. We will pick the simplest: A sequence of 9 rows, each of which has 9 elements storing the digits. Each digit will require 4 bits; since they range from 1 to 9. So, a good Cryptol type for a board is:

  [9][9][4]

In Cryptol-speak, this type simply represents a sequence of precisely 9 elements, each of which is a sequence of 9 elements themselves, each of which are 4-bit words. (Technically, the type [4] also represents a sequence of precisely 4 elements, each of which are bits. But it’s easier to read that as 4-bit words. The type [4] and [4]Bit are synonymous in Cryptol, and can be used interchangeably in all contexts.)

Read More

Equivalence and Safety Checking in Cryptol

The Cryptol language comes with an integrated verification tool-set that can automatically perform equivalence and safety checking on Cryptol programs. Recently, we have presented a paper on this topic at PLPV’09: “Programming Languages Meets Program Verification” workshop. (Slides are also available.)

Briefly, equivalence checking refers to the problem of proving that two functions have the exact same input/output behavior. Typically, these functions are versions of the same algorithm; one being a reference implementation and the other being an optimized version. Cryptol automatically establishes that the optimized version is precisely equivalent to the original. If the functions are not equivalent, Cryptol provides a counter-example where they disagree; aiding greatly in development/debugging.

Safety checking refers to the problem of proving that the execution of a function cannot raise any exceptions; such as division by zero; index out-of-bounds, etc. When the safety checker says that a function is safe, you will know for sure that such conditions will never arise at run-time. (Similarly, you will get a concrete counter-example from Cryptol if this is not the case.)

Cryptol uses symbolic simulation to translate equivalence and safety checking problems to equivalent problems using the bit-vector logic of SMT-Lib. Furthermore, Cryptol has built-in connections to several SAT/SMT solvers. It automatically calls these provers and presents the results to the user in original Cryptol terms; providing a seamless verification environment for the end-user.

The full paper and slides on equivalence checking in Cryptol are available for download.

Read More

A Cryptol Implementation of Skein

Following on from the MD6-in-Cryptol posting, let’s consider another very interesting candidate from the (deep) pool of SHA-3 submissions; Skein 

 http://www.skein-hash.info/ http://www.schneier.com/skein.html

by the merry band of Ferguson, Lucks, Schneier, et al.The expression of their reference implementation comes out, we think, fairly cleanly in Cryptol. The digest output size is a variable parameter to the algorithm, but we’ll focus on the 512-bit version here — the submission’s primary candidate for SHA-3.In order to avoid duplicating the introductory material on Cryptol, we suggest the reader go through the MD6 writeup to get a grounding in Cryptol, its idioms, and syntax.

Read More

MD6 in Cryptol

NIST is currently running a competition to come up with the next generation message hashing function that it intends to standardize and FIPS recommend upon completion (assuming one good candidate is left standing and well at the conclusion of the evaluation process):

 http://csrc.nist.gov/groups/ST/hash/sha-3/index.html

Apart from the need to come up with better alternatives to its current recommendation, the SHA-2 family of hashing functions, this competition draws inspiration from the success that the AES competition had a couple of years ago in engaging the community in coming up with a replacement for the DES block cipher. As then, a lot of new innovation has resulted.As with block ciphers, many common types of hashing functions lend themselves well to expression in Cryptol. To demonstrate some of the features of Cryptol and how it could be used to express SHA-3 candidates, here’s one of the submissions, MD6 from the CSAIL group at MIT, headed by Ronald L. Rivest:

 http://groups.csail.mit.edu/cis/md6/

The goal of this writeup is twofold:

  • Introduce you to the MD6 hashing algorithm and its construction.
  • Expose you to the Cryptol language, and how it lends itself to expressing MD6.

Ideally, you’ll come away with enthusiasm on both accounts!

Read More