Index  Comments

As a form of practice, and as I'll be needing SHA1 for potential future work, I've decided to create my own implementations across my three main languages. This first implementation I'll be showcasing is written in APL, and sans function headers and footers, is eleven lines. This is that largest APL program I've written in a ways, certainly.

This program is licensed under the GNU Affero General Public License version three.

⍝ SHA1 - Provide a pleasant interface to the US Secure Hash Algorithm 1 function.
⍝ Copyright 2019 Prince Trippy programmer@verisimilitudes.net .

⍝ This program is free software: you can redistribute it and/or modify it under the terms of the
⍝ GNU Affero General Public License version 3 as published by the Free Software Foundation.

⍝ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
⍝ even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
⍝ See the GNU Affero General Public License for more details.

⍝ You should have received a copy of the GNU Affero General Public License along with this program.
⍝ If not, see <http://www.gnu.org/licenses/>.

Firstly, it's useful to have the initial values of the SHA1 algorithm available as a named variable; this is a five-by-thirty-two bit matrix corresponding conveniently to those five values:

⍝ This is that initial status, relating to the intermediate values.
status←⍉1732584193 4023233417 2562383102 271733878 3285377520⊤⍨32⍴2

The simple function k has been given a name purely due to its associated constants consuming so much horizontal space; obviously, floor twenty nicely splits the domain into the quadrants; it could be a character shorter by moving the bit vector transformation outside of the selection, but this is less likely to be optimized so well, considering the constants, and so that's not done:

∇ z←k y ⍝ This could be made to be one shorter but less optimized.
z←(⍉1518500249 1859775393 2400959708 3395469782⊤⍨32⍴2)[⎕IO+⌊y÷20;]
∇ ⍝ The domain of this function is zero to seventy-nine inclusive.

The more complex function f is also given a name; the first line sets the various variables for easy manipulation on the second, which functions much as the k function in selecting; alternative choices for all but the first quadrant are displayed in the second comment; unfortunately, I must use double decompression to get the result as the desired bit vector; an anonymous function is used much as the main function uses such:

∇ z←x f y;⎕IO;b;c;d ⍝ This could likely be simplified if only a tad.
⎕IO←0◊b←32↑y◊c←y[32+⍳32]◊d←y[64+⍳32] ⍝ (b=~c=~d) (∨/(b∧c)(b∧d)(c∧d))
z←⊃⊃(((b∧c)∨d∧~b)(≠/b c d)((b∧c)∨(b∧d)∨c∧d)(≠/b c d))[⌊x÷20]
∇ ⍝ That x is the domain of k and y is a ninety-six long bit vector.

The SHA1 function is dyadic, accepting state on the left, in the same form as status, and a block on the right; a block must be five hundred and twelve bits; the first line is entirely based around the initialization of every necessary variable, following the general trend of the SHA1 description; the second line is the first loop; it's easiest to shift the values if they're already assigned and thus those elements of w are collected and XORed into a thirty-two bit vector t, which is then circularly shifted and assigned to the relevant section of w; the final statement simply recurses on this line, until the value is eighty, at which point it will fall through to the next.

The third and fourth lines are that second loop, with the former performing the temporary assignment described and the latter performing the remainder of the assignments, with an exit condition just as the second line contained. The final line combines the intermediates into the same form expected by a following SHA1 invocation, with the only downside being the result should be raveled before usage:

∇ h←l SHA1 r;⎕IO;a;b;c;d;e;h0;h1;h2;h3;h4;t;u;v;w
⎕IO←v←0◊u←16◊h0←a←l[0;]◊h1←b←l[1;]◊h2←c←l[2;]◊h3←d←l[3;]◊h4←e←l[4;]◊w←r,2048⍴0
t←≠⌿w[(⍉32 4⍴32×u-3 8 14 16)+4 32⍴⍳32]◊w[(32×u)+⍳32]←(1↓t),↑t◊→2↓⍨80=u←u+1
t←(32⍴2)⊤(2*32)|+/2⊥⍉5 32⍴w[(32×v)+⍳32],e,((5↓a),5↑a),(k v),v f b,c,d
e←d◊d←c◊c←(30↓b),30↑b◊b←a◊a←t◊→3↓⍨80=v←v+1
h←⍉(32⍴2)⊤(2*32)|(2⊥⍉5 32⍴a,b,c,d,e)+2⊥⍉5 32⍴h0,h1,h2,h3,h4
∇ ⍝ The l is a five-by-thirty-two bit vector and r is five hundred and twelve.

This monadic SHA1 exists for convenience, yet my APL implementation refused to accept it:

∇ h←SHA1 r ⍝ I should be able to do this.
h←status SHA1 r ⍝ How odd, I seem unable.⍝ This is of course merely convenience.

I'd written a version of this program based around words, as this is most natural for the algorithm, and yet the required manipulations are only convenient and concise with bit vectors, leading to four quite superfluous function definitions in that version. Ultimately, I likely won't release that, as this bit-oriented implementation is fine and rather nice; follows is a generalized padding function:

∇ z←x pad y ⍝ The x is that bit-length and y that remaining.
z←((2↓⍨447≥⍴y),512)⍴y,1,(0⍴⍨(↑512 0↓⍨447≥⍴y)+447-⍴y),x⊤⍨64⍴2
∇ ⍝ The y must be a five hundred and twelve vector, or less.

This pad was written after the other two, but maintains a basic characteristic of their design since it returns a 512 vector or a 2 512 matrix as the result, making proper handling simple. Conditonals are isolated to the shaping of the result and the zeroes.

Follows is this function used on the empty message and then consisting solely of the ASCII A:

  '0123456789ABCDEF'[,⍉(8⍴16)⊤2⊥⍉status SHA1 0 pad 0⍴0] ⍝ ⎕IO is zero for all of these.
DA39A3EE5E6B4B0D3255BFEF95601890AFD80709
  '0123456789ABCDEF'[,⍉(8⍴16)⊤2⊥⍉status SHA1 8 pad (8⍴2)⊤⎕AV⍳'A'] ⍝ Sixty-five here's eight bits.
6DCD4CE23D88E2EE9568BA546C007C63D9131C1B
  k 19 39 59 79 ⍝ This shows all return values of k.
0 1 0 1 1 0 1 0 1 0 0 0 0 0 1 0 0 1 1 1 1 0 0 1 1 0 0 1 1 0 0 1
0 1 1 0 1 1 1 0 1 1 0 1 1 0 0 1 1 1 1 0 1 0 1 1 1 0 1 0 0 0 0 1
1 0 0 0 1 1 1 1 0 0 0 1 1 0 1 1 1 0 1 1 1 1 0 0 1 1 0 1 1 1 0 0
1 1 0 0 1 0 1 0 0 1 1 0 0 0 1 0 1 1 0 0 0 0 0 1 1 1 0 1 0 1 1 0
  19 f (32⍴0 1),(32⍴0 1 1),(32⍴1 1 1) ⍝ This is a basic f example.
1 1 1 0 1 1 1 1 1 0 1 1 1 1 1 0 1 1 1 1 1 0 1 1 1 1 1 0 1 1 1 1
  15 pad 448⍴2 ⍝ This exemplifies the larger case and uses two for clarity.
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
  2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
  2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
  2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
  2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
  2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
  2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
  2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
  2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
  2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
  2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
  2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
  2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
  2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
  1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1