Num
class
Here is an example from the cryptographic library Raaz
. To prevent inadvertent use of the wrong offset measure, raaz uses what we call typesafe lengths. One such length is BYTES
but there are others. For example, the type BLOCKS c
measures length in multiples of the block length of the the cipher c
. The advantage of such a definition is that for low level functions like encryptBlocks
the length argument is in BLOCKS c
which ensures that one does not accidently supply length in bytes. The constructors of BLOCKS should not be directy availabe to the outside world to avoid users from circumventing such gurantees. Instead we define a class LengthUnit
which has a member function that converts instances to BYTES
. This instance function is what is use to perform the actual size calculation of pointer manipulation.
It is tempting to define the Num
instance for BLOCKS
as this is a great convenience for users. However, such an instance will effectively bypass all the type safety we so carefully built into the system. Consider for example, a code like encryptBlocks chacha20imp ptr 42
. Haskell is able to infer that the 42 is of type BLOCKS ChaCha20
because it knows the type of chacha20imp
. This will not raise any kind of type error and will result in encrypting 42 blocks (i.e. 2688 bytes) of data. This is a disaster if the user actually meant only 42
bytes. Haskell should not have the privilege of such bugs unlike others like Fortran (See Mariner 1).
A theoretical reason to see why the Num
instance is plain wrong for length units is the see that multiplication does not make sense here. In the language of physics, length offset is not a dimensionless scalar and hence the product of $6\mathrm{bytes} × 7 \mathrm{bytes}$ is $42 \mathrm{bytes}^2$ which is not a length unit at all. On the other hand, $10 * 4 \mathrm{ bytes}$ makes sense when calculating the size of say an array of Word32
of length 10. This is because the quantity 10 is a dimensionless and therefore the resulting product has the same dimension as bytes.
In the heat of the moment it is pretty easy to overlook these bugs. This is particularly tempting because of the “unnecessary” boilerplate that it gets rid of that to, at a very minimal cost; just a deriving
clause away. I would freely confess my stupidity in this aspect. At least we have repented and corrected this to avoid perdition.
TLDR: Do not waste time on hand optimising when there is GCC, the beast from the savanna.
We have a chacha state which is essentially a 4x4 matrix of 32bit unsigned word (Word32
in Haskell). The main body of the chacha transform consists of performing a quarter round, QROUND from now on, first on all the rows of the matrix and then on each of the diagonals of the matrix. For example, if the matrix is
x0 x4 x8 x12
x1 x5 x9 x13
x2 x6 x10 x14
x3 x7 x11 x15
Then a single round of ChaCha20 is the following operations.
QROUND(x0, x4, x8, x12); // QROUND(row0)
QROUND(x1, x5, x9, x13); // QROUND(row1)
QROUND(x2, x6, x10, x14); // QROUND(row2)
QROUND(x3, x7, x11, x15); // QROUND(row3)
QROUND(x0, x5, x10, x15); // QROUND(diag0)
QROUND(x1, x6, x11, x12); // QROUND(diag1)
QROUND(x2, x7, x8, x13); // QROUND(diag2)
QROUND(x3, x4, x9, x14); // QROUND(diag3)
The chacha20 stream is generated by performing this row and diagonal transformations 20 times followed by some adding up.
The first step was to get a portable version of ChaCha20 with the associated tests, which was done without much difficulty. You can have a look at it https://github.com/raazcrypto/raaz/blob/master/cbits/raaz/cipher/chacha20/cportable.c There was nothing clever here other than making sure that the variables xi’s are declared register.
The quarter round essentially consists of only addition and xor. It can easily be seen that the 4row operations are independent of each other. Similarly the four diagonal operations are independent of each other. If we store each of the rows in a 128bit vector consisting of 4 Word32
’s, then the 4row QROUND can be performed by a single vector version of QROUND. In other words, if we have the vectors
V0 = {x0, x1, x2, x3 };
V1 = {x4, x5, x6, x7 };
V2 = {x8, x9, x10, x11};
V3 = {x12, x13, x14, x15};
then the single QROUND(V0,V1,V2,V3)
performs the QROUND
for all the rows. For the diagonal ones we need to shift V1
,V2
, and V3
by 1, 2, and 3 positions to the left respectively and perform a single QROUND(V0,V1,V2,V3)
again.
The optimisation for 256bit vector instructions is similar, but we have to do 2chacha blocks at a time. This is possible because the two chacha20 blocks differ only by a counter and can be done in parallel.
With the above optimisations I wrote two versions, one using the 128bit vector the other using 256bit version using the support for vector types in GCC. Again the implementation was delightfully simple, in fact in many ways much simpler than the portable one because now we can use vector types. The result of these optimisations were not very impressive though.
The performance of 128bit vector version as compared to the portable version does not improve at all (actually it is slightly worse) instead of the expected 2x improvement.
The performance of 256bit version with avx2 is better than the portable one by roughly a factor of 2x where as the naive expectations are a 4x improvement^{1}.
I did look at the generate assembly and the code looked much like what was expected. The 128bit code was using %xmm
registers as expected and the 256bit version was using the %ymm
registers.
Cabal install and stack compiles C code with O2
. Just to see what has GCC got under its hood, I compiled stuff with the flags O3
and what a surprise/shock I had. The portable C started competing with the 256bit implementation. The generated assembly had the SIMD registers in it. Encouraged, I decided to throw in the march=native
and the figures blew me off. The portable C implementation was giving me an insane 14.4 Gbps where as the 256bit one was only giving me 9.55Gbps.
I can make two assumptions on the the message blocks because they are used only through FFI. Firstly, I can assume that the message block is 32byte (256bit) aligned by making sure that the Haskell stub function only passes 32byte aligned buffers to the portable C implementation. Implementations of primitives in Raaz are instances of the BlockAlgorithm
class. All I need to do is to ensure is that bufferStartAlignment
is 32 for portable C implementation as opposed to word alignment. I can also assume that the pointer is not aliased. This two tweaks gives only minor improvements and need not be included at all.
The final performance figures are available at:
https://gist.github.com/piyushkurur/93955e669ab72a51996590bfc106677d
The cabal package now has two flags optnative
and optvectorise
which results in adding the flags O2 ftreevectorize march=native
. These are not enabled by default but can be enabled if you are compiling for yourself. With these changes there is no more a need for the vector implementations. I am keeping it for historical records.
If you are cross compiling, for example, when you are compiling the code for packaging for a distro, it is not advisable to enable these flags. Note that the native in this case would mean the machine on which it is compiled and not on the one where it is run. There is not much of an advantage in the hand coded vector implementation either because one cannot make assumptions on the target.
If you know that your target machine supports vector instructions, you can vectorise with O2 ftreevectorize
. Throw in an mavx2
, if you are sure of its supported on the target, and get most of the performance described above. This would be the use case when you are compiling on your local machine but deploying on the cloud for example.
Update: I got rid of the restrict
key word in the portable c file because not all GCC versions seem to be familiar with it.
The naive expectation will not hold because of some vector overheads.↩
This release include the following primitives
Besides the portable C implementation, we have an implementation that uses 256bit vector instructions (using GCC/Clang intrinsics). The randomness source for this library uses the chachac20 cipher as a PRG. The stream cipher is really efficient with the following figures on my machine^{1}
Notice that the vector256+avx implementation can pretty much saturate a 10Gbps line. The PRG uses the most efficient chacha20 implementation available, which in this case is vector256+avx2. The reduction in performance for prg is due to some copying overhead that I have not bothered to optimise. For more details and comparisons with other primitives see the gist:
https://gist.github.com/piyushkurur/93955e669ab72a51996590bfc106677d
Intel i74770 CPU @ 3.40GHz x 8 cores.↩
The broad area of functional programming and type theory is seeing a revolution of some sort. For a functional programmer it seems nothing is “esoteric” as long as it helps in solving the nut and bolt problems encountered in designing reliable software. It would not surprise me if the next big idea after sliced bread and monads rise from the murky depths of hott and become suddenly mainstream. A large contingent of participants were from the Industry, not the usual suspects like Microsoft Research, but from startups, banks, trading companies (Wolves of wallstreet?). That is extremely satisfying to a researcher in this area.
For me, this conference is also special in the sense that for the first time, I collaborated with some one (Brent Yorgey) whom I have never met face to face before. I am amazed at the intensity with which we worked with git as the medium of communication. This was more like the collaboration in the free software world than the typical academics collaboration that I am more used to. I wish academics moves more to this kind of a model.
This is also my second visit to Japan and I should say I am just as impressed now as I was in 2003. For a fan of fast trains like me, Japan is the ultimate destination of course. But Japan is not just tech. Its culture, food and the subtle aesthetics are all impressive. No wonder this land produced geniuses like Akira Kurosawa or Hayao Miyazaki.
]]>Cryptographic software need to keep confidential data like private keys in its memory. Unless the machine is severly compromised, this is safe as no other process can access them and the data vaporises once the power is turned off. However, if the operating system swaps the data into external memory (hard disk) during the execution of the program, the secret data gets stored on permanent memory and can remain live for years to come. Therefore it is clear that one needs to prevent the OS from swapping out data that is sensitive and typical operating systems provide system calls mlock/munlock
which locks/unlocks memory from being swapped. The library should lock all the memory that contains sensitive data and after use should wipe the memory clean before unlocking and freeing.
ForeignPtr
.The ForeignPtr
type in Haskell is a pointer together with a finalisation routine. When the pointer goes out of scope, the finalisation routine is run before the memory is deallocated. A naive solution for storing sensitive data is to store it in a locked ForeignPtr
based buffer. The finalisation step of this foreign pointer should wipe the memory clean and unlock it. This seamingly easy solution has the following problem.
The system calls mlock
/munlock
works at the level of pages, i.e. it locks or unlocks multiple of pages. Now consider two locked buffers b₁
and b₂
where b₁
ends at the first byte of a page and b₂
is the rest of the page. Then unlocking b₁
will also unlock b₂
as munlock
unlocks all the pages that contains part of b₁
. If b₁
and b₂
are foriegn pointers, then when the gc notices that b₁
gets out of scope it will unlock b₁
as well as b₂
(because the entire page is unlocked). In other words nesting of mlock and munlock does not work. This clearly is not acceptable.
Of course this idea can be made to work by building a minigarbage collecter inside the cryptolibrary. We should maintain a pool of locked memory pages and ForeignPtr
’s meant to be used for sensitive data should be allocated from this pool. The finaliser of the these ForeignPtr
’s do not unlock immediately on going out of scope but merely mark that a given chunk of memory is unused. A particular page can be unlocked only when no portion of it is part of any live secure foreign pointers. With some bookkeeping such an allocator can be built but it is tricky. We need to take care of all the issues related to garbage collection like fragmentation besides knowing system level details like page sizes. An ancient version of raaz had such a memory allocator and it was not pretty.
The main idea behind the secure memory interface is that we allocate all the required secure memory in one go. This approach is faster and simpler. We describe this interface here.
In Raaz we have the notion of an abstract memory element which are buffers wrapped in an appropriate type. These are instances of the class Memory
.
>
> class Memory mem where
> memoryAlloc :: Alloc mem  allocation strategy
> underlyingPtr :: mem > Pointer  recover the pointer
The type Alloc mem
captures what we call an allocation strategy for the memory element mem
. This is essentially a pair (Pointer > mem, Int)
which encodes the following:
The Int
portion keeps track of the amount of memory that is required to create the memory element mem
.
The Pointer > mem
part gives the constructor for the memory element, i.e. it gives a function that takes a pointer which points to a block of memory, and create the memory element.
All actions that require secure memory should be of the type mem > IO a
for some memory element mem
. In the library, this is captured by the type MT mem a
. It is easy to see that one can easily define a higher order function securely :: MT mem a > IO a
that takes such a memory action and passes it a memory element by constructing it out of a locked memory of appropriate size. At the end of the action, this combinator also ensures that the memory is wiped clean before unlocking the memory. Such a use which involves a single mlock/munlock call is not problematice. Besides we do not need to know any system dependent parameters.
What about more complicated actions action that requires many such memory elements, say for example mem1
and mem2
? We think of it as an action that takes the pair (mem1, mem2)
. This requires us to define a memory instance for product types which becomes too tedious because of the pointer arithmetic and size calculation involved in defining its allocation strategy. Every such low level code has the word disaster written all around it.
It turns out that an Applicative
functor instance can be defined on the type Alloc
which does the right thing. The allocation strategy for the compound type (a product of simpler memory types) can be constructed out of the allocation strategy of its components using this applicative interface. The Memory
instance of a product type will then be something along this lines:
> instance (Memory mem1, Memory mem2) => Memory (mem1, mem2) where
> memoryAlloc = (,) <$> memoryAlloc <*> memoryAlloc
> underlyingPtr (m,_) = underlyingPtr m
Note that all the book keeping involved in the length calculations and pointer arithmetic is hidden in the applicative interface. All Implementations of primitives in Raaz always use a memory element to keep its internal state secure.
To bootstrap the process, the library provides some basic memory types like MemoryCell
. Compound memory types (which are essentially product of simpler memory types) can be built out of them using this Applicative
instance of Alloc
.
Unfortunately, there can still be instances where things can go outside secure memory. For example, if you reads the contents of a memory cell into a pure value of Haskell, the contents have leaked into the Haskell Heap which might be swapped. However, with care we can minimise such explicit reads. Copying from one memory cell to another can be done using a memcpy which does not involve such transfer to the heap.
For the actual implementation see the documentation of the module Raaz.Core.Memory. The theory behind the applicative structure of Alloc
is dealt with in our upcoming paper in Haskell 2016.
Firstly, I would like to dispose of the unnecessary fear of (re)implementing cryptography. This fear is unfounded and, I believe, is partly responsible for open source libraries like OpenSSL becoming the “enterprise” level cryptoimplementation that it is now. How else does one explain a successful open source project becoming such a nightmare of a code base? Cryptographic libraries are software libraries in the first place so all the best practices for building large scale software should be applicable to it as well. How can it be otherwise? I am not denying the fact that there are certain class of bugs unique to cryptographic implementations like timing based attacks. However, once these class of bugs are identified, it is just a question of suitably modifying the development process to account for such bugs as well. As a Haskell programmer, one should be wondering how to exploit the type system to avoid these kinds of bugs.
The second myth is that one needs to be a professional cryptographer to write a cryptographic library. Granted, it is difficult if one is Donald Trump but one does not need to be djb either to pull it off, although being the later does give some significant advantages. Building software in any field requires absorbing the nuances of the field and cryptography is no different. To drive home the point, it would be absurd to say that one should not work on an api to access databases just because one is not a database expert.
A professional cryptographer has an advantage but remember, she might not have experience building large software and might not be familiar with some of the cool tricks one can play with types. So if you think you are capable of developing complex software, with enough background reading and awareness of the literature, you should be able to contribute significantly in the development of a cryptolibrary.
I am not a professional cryptographer by any means. One of my current interest is to build reliable software by using formal methods whenever possible. With a strongly typed language like Haskell, I believe, one can go quite a bit in building a secure cryptographic library. This is my main motivation behind Raaz. The kind of bugs that we want to deal with are
Timing related bugs.
Bugs due to secret leaking out of unlocked memory.
Bugs arising due to low level buffer management.
Raaz addresses all these in its own unique ways.
While timing related bugs are hard in general, for example cachetiming attacks for AES SBOX (current version of raaz uses an sbox), some trivial kind of timing attacks like the ones due to naive string comparisons should be avoided whenever possible. In a language like C, one does not have much hope here. Even if the library writer is careful enough to provide a timing independent string comparison, the enforcement of this is left at the whims and fancies of the application developer.
Raaz provides the class Equality
, the timing independent cousin of the Eq
class. Instead of the the function (==) :: Eq a => a > a > Bool
what we have is the function eq : Equality a => a > a > Result
. Here the Result
type is an opaque type that captures the result of a comparison. Two such comparisons can be combined using the monoid instance of Result
which essentially takes the AND of the two results but does it in a timing safe way.
In raaz we insist that cryptographically sensitive types like hashes and MACs should have their Equality
instance declared first. Their Eq
instance is then declared using the combinator (===)
which makes use of eq
to do the timing safe comparison. Clearly, we cannot enforce this at compile time but we can look for this pattern while reviewing the code base. Anything other than this, like for example a deriving Eq
clause, should raise suspicion.
The library needs a lot of lowlevel pointer manipulation in serialisation/deserialisation and memory allocation. We have an abstraction for such pointer manipulation as a result of which, pointer arithmetic is done only once in the entire code base. The abstraction is based on a generalisation of semidirect product and is described in our upcoming Haskell symposium paper. In particular, our secure memory interface uses this abstraction.
My first aim is to get the API correct. We have place holder implementations of the SHA2 family of hashes and aescbc but we have not really tweaked these either for security or performance. The AES code for example uses sbox which is not really a great idea.
In no particular order these are the current goals (comments, criticism and most importantly pull requests are welcome).
High quality documentation (both haddock and internal source code level documentation).
Using types every where. The types should work for us even at the lowest of the levels at which we work.
Formalising a reviewer’s check list which contains things to actively look for while reviewing code. The example of the Equality
instance is one such.
Building against multiple architecture. This is to detect bugs due to alignment restrictions, endianness confusion etc. One easy way to get this working is to build on Ubuntu launch pad.
It does not mean I will be unhappy with merging a bitsliced implementation of AESCTR but the above ones are my priorities as of now.
]]>The current release is mostly a proof of concept release with very little primitives; we currently support sha1, sha2 hashes and their hmacs. We also have an implementation of aescbs but these are hard to use in an high level fashion.
We demonstrate the interface for computing message digests based of cryptographic hashes. Raaz uses distinct types for distinct hashes. These types are opaque in the sense that we do not expose its constructor. However, they are instances of the IsString
and Show
class which makes them conviently representable in code.
> {# LANGUAGE OverloadedStrings #}
> import Data.ByteString.Char8(ByteString)
We now demonstrate how the sha512 digest of a file can be computed. All cryptographic hashes are instance of the type class Hash
and the generic function hashFile :: Hash h => FilePath > h
can be used to compute the hash of a file. The top level signature is necessary in this case so that ghc can deduce which hash to compute.
> fileDst :: IO SHA512
> fileDst = hashFile "myphoto.jpg"
With the OverloadedStrings
extension, you can enter the hashes directly in the source code using the string notation. However, for objects that do not have 1:1 correspondence with byte strings, use of this extension often lead to runtime errors and its use is generally not recommended. There are some rarely cases when it is convenient to embedd hash values in source code like when writing unit tests.
> emptySHA256 :: SHA256
> emptySHA256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
Hashes can be compared for equality. What more, these comparison are constant time and hence timing safe.
> check :: Bool
> check = emptySHA256 == hash ("" :: ByteString)
Notice that for pure values like ByteString, we use function hash
to compute its digest. The result is also a pure value.
For more details, we refer the reader to the haddock documentation of Raaz.Hash
The raaz package will expose cryptographic primitives which will be used to implement specific cryptographic protocols (in separate packages). We would like to expose a highlevel view of cryptographic primitives and levarage the type safety of Haskell when ever possible. Here are some design principles that we have followed which we believe are important.
In cryptographic literature, data like hashes are often treated just as a sequece of bytes. For example, a string of 32 bytes, a sha256 hash or its hmac or for that matter any other hash like blake2s are all just 32byte strings. For a crypto library this is a bad design. This is confusing the semantics of the data type with is syntax (encoding)
Raaz makes these types distinct and, to prevent accidental usage in ways unindented, makes these types opaque.
Encodable
. Almost all cryptographic data that has some encodable presentation is an instance of this type. An instance of Encodable
can be converted to any of the supported binary formats. Currently only hexencoding is supported but the git repository has Base64 encoding. The design of the encoding interface is done and adding a new encoding should not be difficult.
Equality
which aids in constructing such timing safe equality.
Raaz.Core.Memory
in the library.
For more details visit
]]>For too long they have been pampered with
the unquestioned right to take offence and vandalise,
the unquestioned right to spread their superstitions, despite modern science poking holes into all their theories about the universe.
the unquestioned right to pretend that they are the sole authority when it comes to goodness and ethics,
the unquestioned right to tax breaks.
Not any more. Donc “Je suis Charlie”
]]>]]>Homotopy type theory is a homotopical interpretation of a system of constructive type theory. It provides a new framework for the foundations of mathematics with intrinsic geometric content and a computational implementation. It is currently under intense development by logicians, mathematicians and computer scientists as a potential tool for both the largescale formalization and verification of mathematical proofs and formal verification of software. In this survey talk, I will introduce this system and show how it can be used to give new logical proofs of some classical theorems from algebraic topology, making use of the new ideas of higher inductive types and the univalence axiom.
For information, see http://www.homotopytypetheory.org.
In the last post, we saw that the type inference rules of simply typed lambda calculus gave us the rules of natural deduction for (a fragment of) propositional logic via the CurryHoward isomorphism. To extend this to predicate logic, we would need a dependently typed lambda calculus as we explain now. Recall that we think of types as mathematical statements and elements of that type as proofs of the statements. Therefore, to capture predicates $P$ on a type $A$, we need a type $P(a)$ for every $a:A$, i.e. we need a type family on A. As before, to prove the statement $P(a)$ should mean constructing $y : P(a)$.
Given a set $A$ and a predicate $P$, which in the type theory world becomes a type $A$ and a type family $P$, we need types that capture the logical formulae $∃(x∈A) P(x)$ and $∀(x∈A) P(x)$. This is done through the dependent sum ($Σ$) and the dependent product ($Π$) types respectively.
For a type $A$ and a type family $P$, the dependent sum type (or $Σ$type) $Σ_{a:A} P(a)$ consists of all pairs $(a,x)$ where $a:A$ and $x : P(a)$. The motivation is that proving the statement $∃(x∈A) P(a)$ for the set $A$ and predicate $P$ on $A$ constructively involves constructing a witness element $a:A$ for which $P(a)$ is true. What more, in the constructive setting, $P(a)$ being true has to be demonstrated by a proof $x:P(a)$. Thus elements of $Σ_{a:A}P(a)$ can be thought of as proofs of $∃(x∈A) P(a)$. Clearly if $Σ_{a:A}P(a)$ is not inhabited, then $∃(x∈A) P(a)$ is not provable.
The ordinary product type $A × B$ (or $A ∧ B$ in the last post) can be seen as the $Σ$type $\Sigma_{a:A} P$ where $P$ is the type family that assigns $B$ to every $a$ in $A$. We can also define the ordinary sum type $A + B$ (or $A ∨ B$ in the last post) as the $Σ$type $Σ_{x:𝔹} P$, $𝔹$ is the boolean type containing two values $\mathrm{True}$ and $\mathrm{False}$ and $P$ is the type family $λ x . \mathbf{if}\; x\; \mathbf{then}\;A\;\mathbf{else}\;B$.
The first component of any element $z$ of $Σ_{a:A} P(a)$ gives an element of $A$. For types $A$ that do not have any inhabitants, it is impossible to construct element in $Σ_{a:A} P(a)$. This is in line with the idea that $∃(x∈∅) P(x)$ is false.
The dependenent product (or the $Π$type) $Π_{a : A} P(a)$ consists of functions $f$ whose value $f(a)$ is of type $P(a)$. The motivation from the logical side is that a proposition $∀(x∈A)P(x)$ can be proved by giving a function $f$ that takes every element $a:A$ to a proof $f(a) : P(a)$. In agda, the type $Π_{a : A} P(a)$ is denoted by $(a : A) → P(a)$.
Dependent type languages gives ways to construct functions in $Π_{a:A}P(a)$ for any empty type $A$. For example, if $P : ⊥ → \mathrm{Type}$ is a type family we can create the function f in agda by using what is known as the absurd pattern (see line 2 below).
1 2 

This is in line with the idea that $∀(x:∅) P(x)$ is true.
Vector
type: An example from programming.We now give an example of the famous vector type in agda used to captures lists of a particular length.
1 2 3 

Having defined such a type we can define the function head
as follows
1 2 

One of the advantages of this definition of head
is that it can never be applied to an empty vector. This is because the input type Vector A (succ n)
of head
can never match with the type of the empty vector Vector A 0
and hence will lead to a compile time error.
We now give a sketch of the type inference rules for dependently typed lambda calculus. As before typing any term requires to “know” the type of all the free variables in it. We capture this by judgements of the kind $Γ ⊢ e:A$. However, unlike in the simply typed case, $A$ might itself have variables embedded in it. So not just the free variables in $e$ but all free variables that occur in $A$ should appear in the type assumption. Thus our strategy of defining types independent of terms like in the previous post will not work; we need to define them hand in hand.
The type assumptions themselves should now be an ordered sequence $Γ$ of assumptions of the form $x:A$ with the added restriction that for any assumption $x:A$ in the sequence $Γ$, all the variables that appear free in the type $A$ should themselves be defined in previous assumptions of $Γ$. Therefore the order of the assumptions in $Γ$ matters and they cannot be treated as mere sets. Such sequences will be called telescopes of type assumptions. Finally, we can form expressions like $λ x: A → e$ only if $A$ is known to be a valid type which in turn depends on the telescope that is effective at that context. The inference rules for dependently typed lambda calculus thus needs to define simultaneously what the valid types, terms, telescopes and type judgements are. This we capture via the following judgements.
$e\;\mathbf{term}$ which asserts that $e$ is a valid term,
$Γ\;\mathbf{telescope}$ which asserts that $\Gamma$ is a valid telescope,
$A\;\mathbf{type}$ which asserts that $A$ is a valid type and finally
$e:A$ which asserts that the term $e$ is of type $A$.
We use $ε$ to denote the empty telescope. Any judgement $Γ \vdash \mathbf{something}$ means that the judgement $\mathbf{something}$ is valid under the telescope $Γ$.
We write $ε \vdash \mathbf{something}$ as just $\vdash \mathbf{something}$ or even $\mathbf{something}$. To reduce a lot of boiler plate, we sometimes drop certain preconditions if it can be deduced from the other preconditions. For example, we drop the precondition $Γ\;\mathbf{telescope}$ if we also have a precondition $Γ ⊢ \mathbf{something}$ latter on.
$\frac{}{ε\;\mathbf{telescope}}$
The next inference rule says that we can add an assumption $x:A$ at the end of a valid telescope $Γ$ provided it is possible to infer that $A$ is a type from the telescope $Γ$.
$\frac{\Gamma\;\mathbf{telescope};\; \Gamma \vdash A\;\mathbf{type}}{\Gamma, x:A\;\mathbf{telescope}} x ∉ Γ$
We have slightly abused the notation in the expression of the side conditions $x ∉ Γ$ which essentially says that $x$ is fresh, i.e. does not occur in any assumptions of $Γ$.
$\frac{}{x\;\mathbf{term}},$
$\frac{e_1\;\mathbf{term};\;e_2\;\mathbf{term}} {e_1e_2\;\mathbf{term}},$
$\frac{Γ\;\mathbf{telescope};\; Γ ⊢ A\;\mathbf{type}}{Γ ⊢ λ x : A → e\;\mathbf{term}}$
The first two are essentially expressing the lambda calculus syntax for variables and application in the form of rules of inference. The last rule, however says that the expression $λ x : A → e$ is a valid term only if it is in the context of a telescope $Γ$ where $A$ is a type.
$\frac{Γ ⊢ A\;\mathbf{type};\;Γ, x:A \vdash B\;\mathbf{type}} {Γ ⊢ Π_{x:A} B\;\mathbf{type}}$
Notice that we omitted the precondition $Γ\;\mathbf{telescope}$ and $Γ,x : A \;\mathbf{telescope}$ as mentioned before.
$\frac{Γ, x : A\;\mathbf{telescope}}{Γ,x : A ⊢ x : A}$
$\frac{Γ ⊢ e_1 : Π_{x : A} B\; Γ ⊢ e_2 : A}{Γ ⊢ e_1 e_2 : B[x/e_2]}$
$\frac{Γ, x : A ⊢ e : B}{Γ ⊢ (λ x : A → e) \; : Π_{x : A} B}$
To incorporate the rules for $Σ$types, we need to introduce a dependent pairing primitive and the corresponding pairing operations. We leave this as an exercise.
The dependently typed language we introduced here is mostly useless in the absence of any interesting types and type families. One strategy would be to introduce each type and type family by hand giving its, formation, introduction and elimination rules. At the very least, we fix a base set of types $𝒯$ and add the formation rule $\frac{}{t\;\mathbf{type}} t ∈ 𝒯.$ This will give us all the types described in the previous post (once we identify $\Pi_{x:A}B$ with $A → B$ whenever $x$ is not free in $B$). To make dependently typed systems more useful actual systems supports construction of user defined types and type families. What these constructions are and what should be the restrictions on them has to be worked out. We defer this topic for the future.
]]>Update: An implementation of propositional logic in agada is available on my github repository samplecode/agda/Logic.agda
In this post, I briefly introduce typed lambda calculus in its simplest form and explain the type inference rules. The CurryHoward isomorphism appears for the first time here, although only for propositional logic.
We fix a set $𝒯$ of base types that can be thought of as the builtin types of the language. For this post, the set of types are all terms generated inductively as follows:
$τ ≔ t ∈ 𝒯  τ_1 → τ_2.$
The above inductive definition means that a type is either a basic type $t$, i.e. an element of the set $𝒯$, or it is the function type $τ_1 → τ_2$ where $τ_1$ and $τ_2$ are themselves types. The type $τ_1 → τ_2$ captures the type of functions whose domain is of type $τ_1$ and range is of type $τ_2$. There are few points that we want to clarify right away.
Consider the set of propositional logic formulas where the base set of propositions is $𝒯$ and the only logical connective is the logical implies $⇒$. There is a onetoone correspondence with types of our language: interpret the functional type symbol $→$ as the implication operator $⇒$. We will see in this post that this connection is not just skin deep.
The types in our language are defined independent of the terms in our lambda calculus. While this is possible for the version of typed $λ$calculus that we define here, when we want more powerful types this will no more be possible. We will have to define the values and types together.
Intuitively, a typed lambda calculus is a version of lambda calculus where each expression is assigned a type. This type is used to ensure that function application is of the correct type, i.e. whenever an expression $f$ of type $σ$ is applied on another expression $e$ of type $τ$, the type $σ$ should be a function type $τ → τ′$, for type $τ′$. This requires us to assign types to lambda calculus terms in a systematic way. We use the notation $e:τ$ to assert that the expression $e$ has type $τ$. Recall that a $λ$calculus term is a variable, or an application or a $λ$abstraction. Therefore, we need to give systematic rules for assigning types for these three cases.
The base case would be to assign types to variables in an expression. We ensure that the $λ$abstraction also have to assert the type of the variable it quantifies. Thus, any $λ$abstraction is of the form $λ x:τ. e$ and the bound variables $x$ gets its type from this abstractions, i.e. every free occurrence of $x$ in $e$ is assumed to be having the type $τ$. For the free variables, the only way we can have types is by type assumptions, a set of assertions of the kind $x : τ$. The type of an expression thus depends on the type of the free variables in it. Therefore, a well typed lambda calculus expression should be a combination of an expression and a set of type assumption for the free variables in it. Furthermore, they should satisfy some additional rules which we call the type inference rules.
A well typed $λ$calculus expression is an ordered pair of (1) a type assumption $Γ$ together with (2) a typed $λ$calculus term $e:τ$, written in the logical style $Γ ⊢ e:τ$, subject to the following inference rules:
Variable Rule (VAR) : $\frac{}{Γ \cup \{ x : τ\} ⊢ x : τ}.$
Rule for application (APP) : $\frac{Γ ⊢ f : τ_1 → τ_2;\;\; Γ ⊢ e : τ_1}{ Γ ⊢ f e : τ_2}.$
Rule for $λ$abstraction (ABS) : $\frac{Γ \cup \{x : τ_1\} ⊢ e : τ_2}{Γ ⊢ (λ x : τ_1 . e) : τ_1 → τ_2}.$
The notation that we used for defining well typed terms is like a set of logical deduction rules. The stuff on the top of the horizontal line are preconditions, i.e. stuff which we already have derived, and the stuff in the bottom are consequences. i.e. stuff that can be concluded given the preconditions on the top. Let us now interpret each of these rules informally:
VAR : This rule states that with no preconditions we can derive the type assertion $x: τ$ provided it is already an assumption. This rule takes care of the free variables in the expression.
APP : This is the rules that makes sure that the functions are applied to the right arguments. It makes sure of two things (1) We are allowed to form the expression $f e$ under the type assumption $Γ$ if and only if $f$ and $e$ have types $τ_1 → τ_2$ and $τ_1$ respectively under the assumption $Γ$ and (2) then the resulting expression $f e$ has type $τ_2$ under $Γ$.
ABS : This rules assign types to the bound variables. This rule needs a bit of getting used to as we normally think in the other direction, i.e. in the expression $λ x : τ_1 . e$, the occurrence of $x$ in $e$ has type $τ_1$.
In all the above rules, we assume that the type assumptions that arise on the left hand side of the $⊢$ symbol satisfies some obvious conditions like, no variables should have two distinct type assumptions etc.
Recall that any type $τ$ can be seen as a proposition over the set of basic proportion $𝒯$ by interpreting the function type operator $→$ as the Boolean implies operator $⇒$. Consider the three type inference rules that we discussed and replace any type assumption $x : σ$ or type assertion $e : τ$ in the rules above with just the associated proposition $σ$ and $τ$ respectively. This gives a set of inference rules for a restricted form of propositional logic that has implies operator $⇒$ as the only Boolean operator. This isomorphism between type inference and logical inference rules is often called the CurryHoward isomorphism and is one of the main ideas of type theory. The goal in the rest of the post is to give a different interpretation of typed lambda calculus so that some magic is removed out of this isomorphism.
Consider the type assertion $e:τ$. Normally, we think of types as a subset of allowed values and the assertion $e:τ$ as saying that $e$ is a value in the set associated with $τ$. There is an alternate interpretation which makes the logical connection easy to make. Think of $τ$ as a logical statement, proposition in this case. An assertion of the form $e: τ$ is thought of as $e$ being the proof of the statement $τ$. Alternatively, we think of the type $τ$ as the set of all proofs of the proposition associated with $τ$ in which case our usual interpretation means that $e:τ$ means that $e$ is a proof of the proposition $τ$. In this interpretation, a proof of the proposition $τ_1 → τ_2$ should be treated a method to convert proofs of $τ_1$ to proofs of $τ_2$. This then gives a valid interpretation of all the rules of type inference as rules of building proofs.
VAR : We can create a proof $x$ of $τ$ if we have such a proof by one of the assumption.
APP : If $f$ is a proof of $τ_1 → τ_2$ then it is a function that converts proofs of $τ_1$ to $τ_2$. If in addition, we have a proof $e$ of $τ_1$, we can apply $f$ to it and get the proof $f e$ of $τ_2$.
ABS : If assuming a proof $x$ of $τ_1$ we were able to get a proof $e$ (which can make use of $x$ as an axiom) of $τ_2$ then the function $λ x: τ_1 . e$ is a proof of $τ_1 → τ_2$ as it takes any input proof $p$ of $τ_1$ and produces as output the proof $e[x := p]$ of $τ_2$. Here $e[x := p]$ denotes replacing all free occurrence of $x$ by $p$.
This essentially is the crux of the “types as proofs” view point. If we want to effectively use this logical content of type theory, we need to look at richer and richer types and that is what we would be doing. We make some modest enriching in this post and leave the rest for future posts.
For the logical operator $→$, the ABS rule serves as the introduction rule as its postcondition is an implication. Any proof of a formula that is essentially an implication therefore would have ABS as its last step. On the other hand APP serves the dual purpose. It is the elimination rule for the operator $→$. You may think of VAR rules as both an introduction as well as an elimination rule (it introduces nothing and eliminates nothing). This style of presentation of logical rules is due to Gentzen and plays an important role in designing type theoretic systems. The introduction rules gives ways to “construct” objects of a given type and elimination rules gives ways to “use” the objects in expressions. All other operators that we introduce here will also have introduction and elimination rules.
We would like our logic to have the conjunctions and disjunctions. At the type level we just need to add two additional type formation operators $∧$ and $∨$. As a result our types are now inductively defined as:
$τ ≔ t ∈ 𝒯  τ_1 → τ_2  τ_1 ∧ τ_2  τ_1 ∨ τ_2.$
To prove conjunctions and disjunctions, we need ways to create values (remember they are our proofs) of type $τ_1 ∧ τ_2$ and $τ_1 ∨ τ_2$ respectively. For conjunctions, we introduce the primitive $(.,.)$ that pairs up two expressions to give a new expression. A value of type $τ_1 ∨ τ_2$ can be created in two ways: by applying the constructor $\mathbf{inl}$ on a value of type $τ_1$ or by applying the constructor $\mathbf{inr}$ on a value of type $τ_2$. These give the required introduction rules for the logical operators $∧$ and $∨$:
DISJ : $\frac{Γ ⊢ e : τ_1}{Γ ⊢ \mathbf{inl}\; e \;: τ_1 ∨ τ_2},$ $\frac{Γ ⊢ e : τ_2}{Γ ⊢ \mathbf{inr} \;e \;: τ_1 ∨ τ_2}.$
CONJ : $\frac{Γ ⊢ e_1 : τ_1;\; Γ ⊢ e_2 : τ_2} {Γ ⊢ (e_1,e_2) : τ_1 ∧ τ_2}.$
The justification of these rules from a proof theoretic point of view is that one can give a proof of $τ_1 ∧ τ_2$ by giving a pair of proofs where the first component is a proof of $τ_1$ and the second a proof of $τ_2$. Similarly, we give a proof of $τ_1 ∨ τ_2$ by giving either a proof of $τ_1$ or $τ_2$ except that we need to explicitly state which is the case by using the appropriate constructor $\mathbf{inl}$ or $\mathbf{inr}$.
Next we give the elimination rule for $∧$. The corresponding language primitive that we need is the projection operators which we add as built in functions in our calculus.
PROJ : $\frac{Γ ⊢ e : τ_1 ∧ τ_2}{Γ ⊢ \mathbf{fst}\; e \; :\; τ_1},$ $\frac{Γ ⊢ e : τ_1 ∧ τ_2}{Γ ⊢ \mathbf{snd}\;e \;:\; τ_2}.$
Similarly, to obtain the elimination rules for $∨$, we add the function $\mathbf{either}$ that does case by case analysis.
CASE : $\frac{Γ ⊢ e : τ_1 ∨ τ_2;\;Γ ⊢ l : τ_1 → τ;\; Γ ⊢ r : τ_2 → τ} {Γ ⊢ \mathbf{either}\;l\;r\;e\;:τ}.$
We define the the type $σ ↔ τ$ of logical equivalence of $τ$ and $σ$ as $(σ → τ) ∧ (τ → σ)$.
We have a proof theoretic view of truth and falsity in this setting. Propositions are “true” if they can be proved by giving a $λ$calculus expression of that type and not true otherwise. In that sense, we only have “truths” and “not truths” and every inhabited types, i.e. types for which we can construct an element with that type, is true. Explicit truth and falsity can be achieved by adding types $⊤$ and $⊥$ to the basic types $𝒯$ and to make $⊤$ provable, we enrich the $λ$calculus with a single constant $\mathbf{obvious}$ of type $⊤$. That there is no constants with type $⊥$ is deliberate design choice as we do not want to prove $⊥$ in our logic. Once we have the type $⊥$, we can define the negation $¬ τ$ of $τ$ to be the type $τ → ⊥$.
The law of excluded middle, LEM for short, is the statement $τ ↔ ¬ ¬ τ$ and is not a basic axiom of our logic. We can in fact prove one direction $τ → ¬ ¬ τ$: Consider the function $λ x f . f x$. It is easy to see that we can assign to it the type $τ → (τ → σ) → σ$ for any types $σ$ and $τ$. In particular, if $σ$ is the type $⊥$, we have $τ → ¬¬τ$. The converse however is not provable. This might be considered as a weakness of the logic because LEM is used through out mathematics. However, there is a distinct advantage here.
The proofs that we build are constructive and
If we are in dire need of the opium called LEM, we can recover it by adding a constant $\mathbf{lem}$ of type $τ ↔ ¬¬ τ$ the way we added the constant $\mathbf{obvious}$. However, this is never done in practice when using a proof assistant like coq
or agda
For any typed $λ$calculus term $Γ ⊢ e : τ$ we can get an untyped $λ$calculus term, denoted by $e$ itself, by ``erasing’’ out all types from abstractions. Is it possible to do the other way? Can we assign types to an untyped $λ$calculus expression in a way that is consistent to the rules defined above? Doing this algorithmically is the type inference problem. For example, consider the expression $λ x . x$. Intuition tells us that this can be assigned any type $τ → τ$ as it is the identity function. Indeed this is the case:
$\{x : τ\} ⊢ x : τ$ by VAR
$⊢ (λ x : τ . x) : τ → τ$ by ABS and (1).
It turns out that not all terms can be consistently typed, for example $λ x . xx$ cannot be assigned any type (why?).
Recall that the computational content of untyped $λ$calculus is captured in the notion of $β$reduction. To avoid variable collision we also need $α$conversions. It is easy to see that notion of $α$conversion and $β$reduction can be defined in a straight forward way for typed $λ$calculus. What then is the difference? The typed version of $β$reduction is strongly normalising. It turns out that term like $Ω= (λx . xx) (λx .xx)$ and fixed point combinators cannot be consistently typed. As a result general recursion, and hence infinite loops, are not possible in this calculus.
The CurryHoward isomorphism gives us a way to define logical system out of typed lambda calculus. Enriching the basic typed lambda calculus with constants like $\mathbf{obvious}$ or $\mathbf{lem}$ is like adding axioms to the logical system assoicated with the language. In any logical system, we need to worry about consistency. In classical logic, a set of axioms together with the inference rules form an inconsistent system if one can prove a statement $τ$ and its negation $¬τ$. This definition is not very useful in the type theoretic setting as it is crucially dependent on negation which we want to avoid as much as possible. An alternate way to define inconsistency is to define inconsistent system as those which proves all statements. It is this definition of inconsistency that is easier to work with in the type theoretic framework. We say that a type theoretic system, i.e. the under lying typed $λ$calculus and its type inference rules, is inconsistent if every type in inhabited. This makes sense because an inhabitant of a type $τ$ is the proof of the statement (associated) to $τ$. In this section, we want to connect consistency and the ability to do recursion. In fact, arbitrary recursion, or equivalently a uniform way to compute fixed points, is dangerous from a consistency perspective.
We saw that the typed $λ$calculus that we defined does not support fixed point combinators and therefore does not support recursion. This severely limits the kind of programs that one can write in such a language. However, we do know that fixed points can be implemented on a computer. Can we enrich the $λ$calculus to include a fixed point combinator by force? After all, we do know how to compile it into machine code. What would happen if we just enrich the calculus with a constant $\mathbf{fix}$, much like the way we included a constant $\mathbf{obvious}$ or $\mathbf{lem}$. For this to workout, we would need to augment our type inference rules with the following rule for $\mathbf{fix}$
FIX : $\frac{Γ ⊢ f : τ → τ} {Γ ⊢ \mathbf{fix}\;f\;:\; τ}.$
This would mean that, if we some how create a function of type $f:τ→τ$ then we can prove $τ$ using the proof $\mathbf{fix}\; f$. Recall that, for any type $τ$, the typed lambda calculus expression $I = λ x : τ . x$ has type $τ → τ$. Taking its fixed point $\mathbf{fix}\; I$ will give an inhabitant of $τ$. Therefore, adding arbitrary fixed points will make the logic inconsistent.
Real world programming languages like Haskell does not care about this issue as writing infinite loops are too important for a programmer. In fact, every type in Haskell has an inhabitant, namely undefined
. What this means is that the type system of Haskell is not directly suitable as a theorem prover although we can still use it to catch many bugs at compile time.
Languages like agda which has to double up as a proof assistant allow certain restricted kinds of recursion by making sure that the recursion is well formed. Other than the motivation to write real world programs, some restricted form of recursion is actually necessary to capture mathematical objects like natural numbers etc. We leave these issues for future posts.
]]>If you are not familiar with travis CI please check it out. The tight integration of travis with github means every push to the repository is built and checked. What more, the system also builds every pull requests, so before merging I can be sure that stuff works. Having said that there are certain limitation of travis builds particularly in the context of raaz which I list below.
The travis builds are done on an Ubuntu container. Therefore, the default builds are against whatever haskell platform comes with it. Thanks to Herbert Valerio Riedel for his write up and his Ubuntu ppa, we now build across multiple haskell platform. The instructions need to be tweaked though as they assume that repository is a single directory with the package in the root directory. I have described this in the next section. This therefore is mostly solved.
Since I myself use Debian stable and travis uses Ubuntu, there is not much cross OS builds. Ideally I would want it to be built on at least few of the BSD variants.
The builds happen only on one architecture, the architecture that the travis build runs on. While this is not a problem for most packages, raaz being a cryptographic library should be built across multiple architecture. Only then can we catch bugs due to endian mismatch, alignment problems (ARM in particular). This becomes all the more important when we start including architecture specific implementations of primitives.
I think (2) should be easy to solve. Someone with more BSD experience can help out on this. I think (3) is particularly difficult because we need actual hardware to test it out. One option would be to build it and run on an emulator like qemu. However, I do not know of any build system that makes this easy. On the other hand OS distributions like Debian should have solved this problem. I would like advice from some knowledgeable person here.
The raaz repository is a collection of haskell packages with dependencies between them. So Riedel’s instructions do not work directly. We need to make sure that
To build a package we need to be in its root directory. This involves cd’ing into the directory and essentially following Riedel’s instructions
Before installing a package like raazhashsha
, we need to install all its dependencies within the raaz collection as those packages are not on cabal. We use make
to ensure these.
I have documented most of this in the Makefile
which you might want to refer to. Let me know if the documentation needs improvements.
There is a subtle problem with dependencies that makes multiplatform builds more or less meaningless. The way we ensure that the packages are built against a platform is by setting up an appropriate cabal.config
file in the directory of the package. This config file puts constraints corresponding to the platform we want to test against. I noticed that the builds are actually not installing the platform packages because of the version dependency. For example, the dependency on Quickcheck that we had was Quickcheck==2.4.*
. This means that even for builds for platform 2013.2.0.0 the quick package used was Quickcheck2.4.something
. For this reason we had to go for a more liberal package version bounds (merge ac0ad7). As long as we are not using the packages like base
or Quickcheck
in a nonstandard way, I think we are fine.
The core idea of lambda calculus is an elegant notation invented by Alonzo Church to capture functions without naming them. Consider the function that increments its argument by 1. In notation of lambda calculus one can write such an increment function as $λ x . x + 1$ (assuming of course that $+$ has already been defined). This notation has now found its way to many programming languages like Haskell (\ x > x + 1
the backslash is an ASCII approximation of $λ$), python (lambda x: x + 1
) etc. The lambda calculus we deal with here does not have the builtin function like $+$. All it has is a (countably infinite) supply of variables, which we will denote by small case letters $x$, $y$, $z$ etc and two fundamental operation namely application and abstraction. The lambda calculus expressions can be inductively defined as follows:
$e = x  e_1 e_2  λ x . e$
In the above inductive definition $x$ is any one of the countably infinite variables and $e_1$ and $e_2$ are lambda calculus expressions defined recursively. We will follow that standard convention that all application associates to the left (i.e. $f g h$ means $((f g) h)$) and that application binds tighter than $λ$abstraction. Further, the the expression $λxy.xy$ means $λx . λy . xy$.
The lambda abstraction acts like any other mathematical quantifier when it comes to determining the free and bound variables. An occurrence of a variable in a expression is either free (i.e. is not in the scope of any $λ$abstraction) or is bound to a lambda abstraction. If an occurrence of a variable $x$ is in the scope of more than one $λ$abstraction then it is bound to the inner most one. For example in the expression $λx.xy$, $x$ is bound and $y$ is free. One can define the notion of free variables inductively as follows.
$FV(x) = \{ x\},$ $FV(e_1 e_2) = FV(e_1) ∪ FV(e_2),$ $FV(λx . e) = FV(e) ∖ \{x \}.$
As in other mathematical notations, the meaning of a lambda calculus expression depends only on the free variables, which means one can change the bound variables of an expression. For example the expression $λx . xy$ is the same as $λt. t y$. This change of bound variables is called $α$conversion. When doing an $α$conversion however, care must be taken to avoid variable bindings to be inadvertently changed. For example in the expression $λx.xy$, the variable x cannot be changed to $y$ as it is occurs free and changing $x$ to $y$ will make it bound. One can avoid such a situation if we always use fresh variables. We will assume from now on that all $α$conversion takes care of this problem.
The computational power of $λ$calculus comes from what is known as $β$reductions which formalises the notion of the $λ$abstraction. The essence of $β$reduction is that the expression $(λx. M)N$, under $β$reduction, reduces to $M'$ where $M'$ is the expression $M$ with all free occurrences of $x$ replaced by $N$. However, we have to be careful to take care that no free variable in $N$ gets inadvertently bound as a result. For example consider the expression $M = λy.xy$ and $N=y$. If we blindly reduce $(λx.M) N$ then the free variable $y$ of $N$ gets bound. This is because a free occurrence of $x$ in $M$ comes in the scope of a $λy$ and $y$ happens to be free in $N$. To avoid this problem one can $α$convert the $M$ to use a new bound variable instead of $y$. We assume from now on that each such $β$reduction carefully avoids the free variable capture.
A $β$normal form is an expression for which there are no more $β$reductions possible. For example a variable is a normal form so is expressions of the kind $λx.x$. One can think of this as a program that has terminated. We say that an expression $M$ has a normal form if there is normal form $N$ to which it can be reduced after a series of finitely many $β$reductions. Expressions might have a normal form or can diverge and it is undecidable to check which is the case. However, a consequence of the ChurchRosser theorem is that if an expression has a normal form then it should be unique.
A reduction strategy is an algorithm to choose which subterm of a lambda calculus expression should be $β$reduced next. Clearly there is no strategy that will terminate always as there are terms which do not have a normal form. Can we have a strategy which will guarantee termination if the expression has a normal form? Fortunately the normal order evaluation strategy is normalising, i.e. it finds a $β$normal form if it exists (See Lambda Calculus for more details). Therefore, the problem of finding the normal form is partially recursive in the sense that one can write a program to compute the normal form of an expression if it has one.
It might not appear so but hidden inside the simplicity of lambda calculus is a full fledged programming language. With appropriate encoding of natural numbers (see for example Church encoding) one can represent all computable functions. This is the ChurchTuring hypothesis. While we do not want to go into the details of this, we will show how to implement one important feature namely recursive definition of functions.
An important property of untyped lambda calculus is that every lambda calculus function $F$ has a fixed point: given $F$, consider the expression $X = λx. F(xx)$. One can easily show that the term $XX$ $β$reduces to $F(XX)$ and is therefore the fixed point of $F$. Furthermore, the computation of fixed point is effective as well, i.e. we have a lambda calculus combinator for computing it: Consider for example the combinator (i.e. lambda calculus term with no free variable) $Y$ defined as $Y = λf . (λx . f(xx))(λx. f(xx))$ It is easy to verify that $YF$ is the fixed point for $F$. Existence of fixed point combinator is important as that is what allows us to define functions recursively. A recursive definition $f = F(f)$ is nothing but the fixed point of the function $F$. The fact that it is effective make it possible for the compiler to support recursive functions. Fixed point theorem also allows mutual recursion. For this one has to have a way of pairing values into tuples which can be done in lambda calculus by suitable encoding (see the Lambda calculus#Pairs). The reset of the details I leave it as an exercise.
]]>This particular blog post also will serve as a “Table of Contents” for the series. While all the posts in this series will have the “Type theory” tag in it, the explicit listing of the contents serves as a suggested order in which to read the posts.
In a sufficiently rich functional programming language (like for example Haskell), we have expressions each of which are associated with a type. The types can be seen as invariants that the expressions satisfy through out the program. For example, when you assert that the variable x
has type Int
, you are implicitly asking the compiler to make sure that x
is used in ways that are consistent to the fact that it is an integer. Checking this invariant at compile time ensures that the programmer does not introduce silly bugs like trying to add 2
to "hello"
etc. Thus there is some amount of theorem proving, rather trivial in the above case, already built into any strongly typed language. This informal connection can be formalised via what is know as the CurryHoward Isomorphism which observes that the rules for assigning well defined types to expressions coincide remarkably with rules for proving statements in a suitable logic. For any type $τ$ one can associate a statement $A_τ$ such that if $e$ is a well typed expression of type $τ$, we can map $e$, rather the derivation of the type of $e$, to a proof of the statement $A_τ$. The precise statement of this connection is left for later posts but the core idea here is that type checking is essentially proof checking (and viceversa).
Why is this connection interesting? In order to fully see the type theory elephant, we often need to acquire the split personalities of a programmer (functional programmer) and a mathematician.
The programmer is actually interested in the expressions, as they are the programs. Types are a way of ensuring that the programs satisfy certain invariants. The stronger the type system, the larger is the class of invariants that can be expressed. Thus for her the types are a means to achieve correct programs. The holy grail in this line of thought is to have completely machine certified programs. A full fledged programming language which implements such types can thus be its own specification language.
The mathematician is more interested in the types as they correspond to mathematical truths. Expressions are just proofs of these statements. The functional programming language with sufficiently powerful types can thus be used as a proof assistant to achieve completely automated mathematical proof checking. However, proofs being values are now first class values. Much like in a functional programming language, where making functions first class values helped in a lot of simplification and abstraction, it is hoped that making proofs first class can give ways to manipulate and think about them which traditional mathematics could not.
The above two viewpoint have sometimes slightly conflicting goals. A programmer is concerned in the performance of these languages. There are certain technical issues like the fact that all function should terminate if one wants to avoid inconsistency that can be a show stopper in writing nonterminating programs like servers etc. The mathematician however is not much bothered about the actual efficiency of the running code. However, issues like consistency and termination is important. After all who wants a proof assistant that will accept all proofs.
A platform to experiment with various cryptographic primitives.
A library to write high performance servers and clients to some common cryptographic network protocols.
I believe that Haskell as a language has a lot of features that allow writing fast (as fast or better than any C library available) as well as secure cryptographic code. In this post, I attempt to explain some of the features of Haskell that we make use of.
Let me first dispose of the one myth that seems to persist in the mind of people who have never seen a modern functional language. No one wants their software to be slow. Cryptographic protocols should be especially well implemented otherwise folks would simply avoid using the secure options. Clearly when it comes to performance Haskell can beat any of the interpreted languages Python, Ruby or Java. But what about C?
The tight loops in the library which implements the primitives will anyway be written in C/Assembly. If one wants speed then one needs to do this whether one likes it or not. So for primitives it really does not matter which language one chooses. It then boils down to how easy it is to integrate C/Assembly code with Haskell. Having a low overhead foreign function Interface (FFI) is really critical here and Haskell fortunately has it.
Having fast primitives helps but a network library is not just a set of fast cryptographic primitives. Here are some of the features that one would.
High performance concurrency primitives for server applications. Haskell really has no competition in this department. Here are some of the features that GHC (and libraries) supports: Green threads STMs, MVars etc. Using these features, servers written in Haskell have been competitive (often outperforming) servers written is C. See for example mighttpd.
Efficient data serialisation and parsing libraries: Implementing the wire protocol efficiently is critical in improving the efficiency of the network application. Haskell is especially rich in this department as well: attoparsec, binary, blazebuilder etc. There are libraries that supports high performance (close to hand written C performance) at the same time achieving these feats at a much higher level of abstraction (which translates to less bugs and high maintainability).
While having fast libraries is great, languages like C achieve this at the cost of abstraction. It often appears to the programmer that one needs to sacrifice elegance for speed. Not so with Haskell. Many of the libraries I mentioned above achieve C speed with no compromise on the level of abstraction. This greatly enhances the maintainability and leads us to the next important feature that we want in our libraries, safety.
Cryptographic implementations are full of corner cases and the bugs in them can be particularly lethal. A cryptographic library is usually broken, not by a direct attack on the underlying algorithm, RSA although quite dated is still secure, but through other means like buffer overflows, cache timing attacks and other side channel attacks. How can one minimise this? Let me give an example of a code which, while correct in normal circumstances, is bad in a crypto setting. Suppose you grant privileged access to a user by comparing a secret that you posses with the user supplied password. A naive string comparison will be prone to timing attacks: The time taken to reject a password is proportional to length of the longest common prefix of the secret and the password. The attacker then can guess the password one character at a time by looking at the time it takes for you to reject the password. One would usually not compare the secrets directly but hash them together with a salt and compare the hashes. However, any comparisons that take time dependent on the user input is prone to lead to future attacks when deployed without much thought.
We could avoid this problem by asking users of our library to always use string comparisons that take constant time irrespective of the input. However, it is very likely that a user of our library, most of them will not be cryptographers, might miss this instruction. Won’t it be nice if such incidents are caught at compile time?
We avoid this problem in Haskell by leveraging its type safety. Instead of representing cryptographically significant data types like hashes, macs etc. as mere byte string, we define Haskell data types for them. For example sha1 hashes are represented (in a simplified form) as follows:
module Raaz.Hash.Sha1 ( Sha1 )
data Sha1 = Sha1 Word32 Word32 Word32 Word32 Word32
instance Eq Sha1 where
(==) (Sha1 h0 h1 h2 h3 h4) (Sha1 g0 g1 g2 g3 g4)
= xor h0 g0
.. xor h1 g1
.. xor h2 g2
.. xor h3 g3
.. xor h4 g4
== 0
The Eq
instance for Sha1 has comparison operator defined in such a way that it will take time independent on the number of positions they match. A user is then forced by the compiler to use this equality as we will not be exposing the constructor to her.
Currently we have just began. We have made no releases yet and we are still experimenting with the API. All code is available under BSD3 license from http://github.com/raazcrypto/raaz).
I look forward to your contributions. Even if you are not comfortable with haskell, you can contribute. For example, if computer architecture is your bread and butter and you are the Chuck Norris of assembly language programming, do join us for some fun coding: A lot of primitives require fast implementation often exploiting the platform specific features like SIMD instruction set.
]]>This is a static using no dynamic PHP or any such monstrosities. I could have something like Disqus.
I am already full with spams in my inbox and do not have the motivation like others to weed out the spam.
However if you are motivated, and feel that some one is wrong on the internet, then you can send your comments to me via email. I hope to make the source code of this site open to all. Once that happens you can also send patches to me which will be incorporated.
Update 28 May 2013: The entire hakyll source is available at _{http://hub.darcs.net/ppk/website} http://github.com/piyushkururpages/website
Update 03 Oct 2013: Now uses disqus for commenting.
]]>It was more or less clear to me from the start that I wanted a static site managed via darcs, written in markdown. Of course there is jekyll but I always thought pandoc was way more powerful than some of the other markdown processors that comes with jekyll. And then I heard of hakyll. It uses pandoc as its markdown processor which means that I get all the pandoc goodies: easy math integration, syntax highlighting, and possibility of using different input (say latex) and output (say pdf) formats. Besides, it is written in my favorite programming language. No more excuses for a bad homepage.
I never thought my page would ever be styled with css. As a language (if you can call it one) css is pretty lousy, maybe slightly better than html. Besides, no two browser seems to agree on the standard. Who, in their right senses would want to work with it ? Compass made me change my opinion. Firstly, you can use the sass now instead of css, an advantage comparable to using markdown instead of html. Secondly, it has mixins that take care of all (most) of those browser incompatibilities. It might not go well with IE users: I don’t know, neither do I care to know. But it should work mostly. The style for this page is entirely written in sass using the compass framework. I will publish the source code soon after some refactoring.
Thanks to the great softwares mentioned above, I now have a clean homepage complete with a blog and atom/rss feeds. Some lecture notes that I had are not yet hakyllised. It will soon be.
A big thank you to the folks behind hakyll, pandoc and compass.
Update 18 May 2013: I have added my old wrtings as blog post. So it might appear as if this not my first post.
]]>High cost of journal subscription. Journals of Elsevier are too costly. What is worse is that they have taken over other journals and currently have a huge monopoly.
Bundling journals. Libraries have to subscribe to a bundle to get a few journals of interest. Often bundles contain journals that are not of any interest to a particular institution. Worse, they include journals which themselves are questionable: e.g. journals like Chaos, Soliton and fractals.
Reviewing, which is important scientific responsibility of any journals, have been a sham in many cases. For example, Journals like Chaos, Soliton and fractals have published 302 papers from their Editorinchief El Naschie. (See http://rationalwiki.org/wiki/Mohamed_El_Naschie)
Setting up journals on pseudosciences like for e.g. The Homeopathy (No link given so that they don’t get the benefit of page ranking) which give them unnecessary scientific credibility. Astrologers, What are you waiting for? Call Elsevier right now.
There has been cases of Elsevier publishing many fake papers written by ghost writers in return to getting paid by drug companies. See for example
Reed Elsevier’s role in arms trade (See http://www.idiolect.org.uk/elsevier/) While an action that is difficult to justify, I would not consider this hurting the scientific publishing directly (other than the minor danger of completely wiping out humanity and thus the scientific establishment, at least on earth). With pressure mounting, apparently they have given up on this illustrious business.
Summarising, the business practice of Elsevier has hurt scientific foundation not only economically but also led to lose of scientific credibility due to the questionable publishing standards they have followed.
Boycott them. See http://thecostofknowledge.com.
If you are an editor of an Elsevier journal, resign now and encourage your fellow editors to resign en masse. See
If you happen to be in the library committee of your institute try to get Elsevier out of the subscription list.
Support and form journals like Theory of Computing
Make all your work available on the net.
Remember all of this is not without ``risks’’. So evaluate the best options for you and make up your mind.
]]>This is a tutorial on sshfs or ssh file system. The idea is to provide a nfs like mount which is secured by the very dependable ssh (the sftp subsystem of ssh).
1 2 

where path/to/mount
is the point where you want the remote file system to be mounted.
path/to/mount
on your local machine is actually the home directory of the remote machine. So you can use it just like a local machine. Expect slow response if your network connection to remote machine is slow though.1 2 3 

1 2 

Sshfs is a userspace file system (fuse) that works over ssh, or rather sftp. Fuse is an implementation of filesystem primitives in userspace rather than in kernel space. This essentially means that users can mount and unmount file system without having to be root. Sshfs makes use of the sftp subsystem to do the remote file system operations. Thus all the great features of ssh holds true, i.e. key based authentication, use of sshagents. See my tutorial blog on ssh for more details on how to use ssh.
All linux distros have a prebuilt package for sshfs. On Debian/Ubuntu and Arch the relevant package is sshfs
. So all you need to do is to install it.
1 2 3 4 

On Fedora it looks like it is called fusesshfs
so something like this should work.
1 

A common error that people have reported is that ssh works but sshfs fails. If this happens, check whether your sftp subsystem is working. Most probably this too would fail or work incorrectly. One of the main reasons why sshfs/sftp does not work is because your startup scripts in the remote machine prints stuff on the screen. To check this out, try the following command.
1 

If this command produces any output then you are in trouble. You have to fix your startup script in your remote machine — .bash_profile
and .bashrc
, if you are using bash as your default shell. The startup script should check whether the standard output is a terminal before it outputs something. For this protect your output generating commands inside a test t 1
block as follows
1 2 3 4 5 6 

See the openssh FAQ for more details.
]]>$
prompt of course) it on to the terminal. Also by ssh I mean openssh throughout.
All the files used by ssh are inside the .ssh directory in your home area. Here is a list of them and their use.
The known_hosts file contains the public keys of all the hosts that you have logged in to. It is a good idea to get these known hosts from a trusted source. When your ssh client contacts a server, it receives public key of the server. If there is a mismatch, ssh warns you that the key has changed. This could be due to a maninthemiddle attack or due to a system reinstallation. When you get such a message it is better to be sure that there is no tampering. Be especially careful if you in an unknown LAN or WiFi network like that of an airport or a hotel. Having a trusted known_hosts file is a very good security measure.
Usually one uses ssh with passwords to login. Although this is secure in the sense that the passwords sent are encrypted, it has all the problems of password based authentication. An alternative is to use public key/private key based authentication. The public key access is more secure and in fact more convenient than the password based access. Here is the step by step procedure.
1 2 

You will find the generated keys inside the .ssh directory. The files with extension .pub are the public keys. Copy them into the .ssh/authorized_keys file of the remote machine.
1 2 3 4 5 6 7 

The last step is particularly important. Ssh will refuse to login if it finds that the .ssh/authorized_keys is writeable to someone other than the user. Otherwise an intruder could leave his public key and will have unrestricted access. So do not forget to change permissions. Many have been stumped by this and ssh does not give any indication on where the problem is.
In case you connect to many hosts it is a good idea to install the same public key in all the different hosts you log into. Thus you need to remember only one passphrase for all these hosts.
Of course the best option is to install yourself an operating system, one of the BSD’s or GNU/Linuxes for example. However if you don’t have that option, you will also be forced to use other ssh clients like putty. My experience with these clients are limited and that prevents me from giving a detailed procedure. Usually they have a clickclick interface to generate keys. The keys generated are however not in the format expected by by openssh. Don’t you worry. The correct format is only a command line away.
As before you have to copy the public key to the remote machine. The command
1 2 

will convert an SSH2 compatible key format, which is what many of the commercial sshclient uses, to openssh compatible key format and print it on the standard output. So after copying the public key to the remote machine, you can type
1 2 

on the remote machine.
While generating a public key/private key pair one is asked for a passphrase. The passphrase is used to keep you private key encrypted on the disk. It is never sent across the network or used in the protocol. Thus one can use an empty passphrase in which case the private key is kept unencrypted on the disk. In case your machine is a private laptop this is not such a bad idea. The advantage of an empty passphrase is that you will never have to type any passwords while sshing or scping. However there is always a risk of your private key getting compromised if the local machine from which you log on to the remote machine is a shared machine. You could, for example, forget to logout from the common terminal. So it is a good idea to have a passphrase.
A better alternative to an empty passphrase is to use an sshagent. The sshagent keeps you private key with it and does all authentication on your behalf. Here is a quick example.
1 2 3 4 5 6 

I like to use sshagent in conjunction with screen (another cute program). This is what I do.
1 2 3 

Now no passwords are asked in any of the windows of the screen session. Usually I leave my screen session running in the office machine (which is physically secure as only I have the key to my office) and when I connect from home, I attach my self to the already running screen in my office machine.
1 2 3 

When I am done I detach the screen. Thus one can go on for months without typing any passphrase for any of the ssh/scp/sftp sessions.
One of the most powerful uses of ssh is its ability to port forward. You can build an ssh tunnel and connect a local port to a remote port. For all purpose this local port is the remote port. For example suppose there is an smtp server (mail server) running on remote which relays mails only from remote. You can set up a tunnel that connects your local port with that of the remote smtp port provided you have shell access to the remote host. Here is how you do it.
1 2 

Now you have a smtp server “running” at port 2500 of your machine. All the traffic to port 2500 is redirected via the ssh tunnel to the port 25 of the remote machine. If you want to actually forward the port 25 of you local machine, you need to be root on your local machine as this is a privileged port. However you don’t need root access on remote.
Using tunnel devices and ssh port forwarding one can also setup vpn like network. We wont go into the details in this article.
]]>The popularity of html is baffling. It is not the most efficient of the formats from the rendering point of view and definitely not a format for mere mortals. The kludge called html also brought about an industry of WYSIWYG html editors which really spits venom when asked to render a Hello world page. This has lead to many “Best view by …. under 1024 x 798 resolution” pages; so much for the “portability” of html. Despite all these shortcomings html became popular. What more its “success” as a text format lead people to the creation of even uglier cousins like XML.
In this difficult world I had to make my homepage. Having a homepage is important in today’s world, they say. It is important to have your papers online, for example, in the unlikely event that some one is interested in your work. But the ugliness of html was unbearable. I searched far and low for other ways to create html including LaTeX2HTML. All had their drawbacks.
Enter Markdown. This really changed my life as far as webpage creation is concerned. Here is a format that one can easily convert to html and is as pleasing to write as an anonymous hate mail to your boss (markdown’s format is based on email conventions). To convert markdown to html one just uses the markdown.pl script. However my favourite converter is the swiss army knife for format conversion pandoc. Pandoc is a program that can inter convert between various text formats much like the convert for image formats. This means that if you already have an existing homepage you can use pandoc to first convert it into markdown, edit it and then reconvert to html. Pandoc also supports much needed extensions like the inline math a la LaTeX, a horror if one has to do it using MathML.
Pandoc is not just a text format converter. It comes with a supporting Haskell library which can be used to program specialised converters if needed.
]]>