Lamport Parachute implementation in Bourne Shell

I have implemented the Lamport Parachute utilities designed by Stasislav Datskovskiy in Bourne Shell. I did this because the article How to Make Your Own Lamport Parachute from Common Household Materials contains an implementation of the Lamport Parachute utilities in Bourne Again Shell, which I found useful, but convoluted and difficult to read.

lamport_mkpriv
generates a single-use private key
lamport_priv2pub
generates a public key from a private key
lamport_encode
generates a signature from a private key and a payload
lamport_decode
validates a signature against a public key and outputs a payload

A Lamport private key consists of two lists of random integers. A Lamport public key consists of two lists of hashes of the integers from the private key. The length of these lists must equal the payload size in bits. If a hash must be signed, this is the output size of the chosen hash function.

To create a Lamport signature, for each bit of the payload, include one corresponding integer from the private key – using one list if the bit is zero and the other if the bit is one. To check a Lamport signature, hash each value in the signature and look for the hashes in the public key; if each hash is found and the decoded payload matches, the signature is valid.

Cheat Sheet

Task Command
Create a private key lamport_mkpriv 256 512 >privkey
Create a public key lamport_priv2pub sha256sum <privkey >pubkey
Create a signature PAYLOAD=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
printf ${PAYLOAD} | lamport_encode privkey >signature
Validate a signature lamport_decode sha256sum pubkey <signature

Issues with Datskovskiy Implementation

  • Dependency on Bourne Again Shell (Bourne Shell is more portable)
  • Code contains both backticks and $() for subshell invocations
  • Code contains both (non-portable) echo and (portable) printf
  • Code contains subshells where variables could signal intent
  • Use of non-portable tr arguments [:lower:] and [:upper:]
  • Use of non-portable Bourne Again Shell arrays
  • Use of nested subshells inside strings
  • Needlessly short variable names
  • Inconsistent indentation
  • Useless use of cat