-- Copyright (C) 1983  by Xerox Corporation. All rights reserved. 
-- DESTesterOthello.mesa, HGM, 22-Dec-83  0:39:00

DIRECTORY
  Format USING [],
  Process USING [Detach, GetPriority, Priority, SetPriority, Yield],
  ProcessPriorities USING [priorityClientLow],
  Put USING [Char, CR, Line, Text],
  String USING [AppendLongDecimal, AppendNumber],
  System USING [GetClockPulses, Pulses, PulsesToMicroseconds],
  Window USING [Handle],
  
  OthelloDefs USING [
    CommandProcessor, IndexTooLarge, MyNameIs, ReadChar, RegisterCommandProc],
  
  DESFace USING [
    Block, Blocks, CBCDecrypt, CBCEncrypt, DecryptBlock,
    ECBDecrypt, ECBEncrypt, EncryptBlock, GetRandomIV, GetRandomKey, IV, Key];

DESTesterOthello: PROGRAM
  IMPORTS
    Process, Put, String, System,
    OthelloDefs, DESFace =
  BEGIN
  
  log: Window.Handle ← NIL;
  
  password: LONG STRING ← NIL;
  key: DESFace.Key ← DESFace.GetRandomKey[];
  seed: DESFace.IV ← [123, 456, 789, 43321];
  

  -- Test data that exercises every S-Box Entry
  -- Source: Federal Register, XXX
  -- Values in Hex
  -- (Key)                (Data)                (Cipher)
  -- 7CA110454A1A6E57   01A1D6D039776742   690F5B0D9A26939B
  -- 0131D9619DC1376E   5CD54CA83DEF57DA   7A389D10354BD271
  -- 07A1133E4A0B2686   0248D43806F67172   868EBB51CAB4599A
  -- 3849674C2602319E   51454B582DDF440A   7178876E01F19B2A
  -- 04B915BA43FEB5B6   42FD443059577FA2   AF37FB421F8C4095
  -- 0113B970FD34F2CE   059B5E0851CF143A   86A560F10EC6D85B
  -- 0170F175468FB5E6   0756D8E0774761D2   0CD3DA020021DC09
  -- 43297FAD38E373FE   762514B829BF486A   EA676B2CB7DB2B7A
  -- 07A7137045DA2A16   3BDD119049372802   DFD64A815CAF1A0F
  -- 04689104C2FD3B2F   26955F6835AF609A   5C513C9C4886C088
  -- 37D06BB516CB7546   164D5E404F275232   0A2AEEAE3FF4AB77
  -- 1F08260D1AC2465E   6B056E18759F5CCA   EF1BF03E5DFA575A
  -- 584023641ABA6176   004BD6EF09176062   88BF0DB6D70DEE56
  -- 025816164629B007   480D39006EE762F2   A1F9915541020B56
  -- 49793EBC79B3258F   437540C8698F3CFA   6FBF1CAFCFFD0556
  -- 4FB05E1515AB73A7   072D43A077075292   2F22E49BAB7CA1AC
  -- 49E95D6D4CA229BF   02FE55778117F12A   5A6B612CC26CCE4A
  -- 018310DC409B26D6   1D9D5C5018F728C2   5F4C038ED12B2E41
  -- 1C587F1C13924FEF   305532286D6F295A   63FAC0D034D9F793
  -- 0101010101010101   AAAAAAAAAAAAAAAA   3AE716954DC04E25
  -- 0101010101010101   0000000000000000   8CA64DE9C1B123A7

  keySequence: ARRAY [0..21) OF DESFace.Block ← [
    DESFace.Block[76241B, 10105B, 45032B, 67127B],
    DESFace.Block[461B, 154541B, 116701B, 33556B],
    DESFace.Block[3641B, 11476B, 45013B, 23206B],
    DESFace.Block[34111B, 63514B, 23002B, 30636B],
    DESFace.Block[2271B, 12672B, 41776B, 132666B],
    DESFace.Block[423B, 134560B, 176464B, 171316B],
    DESFace.Block[560B, 170565B, 43217B, 132746B],
    DESFace.Block[41451B, 77655B, 34343B, 71776B],
    DESFace.Block[3647B, 11560B, 42732B, 25026B],
    DESFace.Block[2150B, 110404B, 141375B, 35457B],
    DESFace.Block[33720B, 65665B, 13313B, 72506B],
    DESFace.Block[17410B, 23015B, 15302B, 43136B],
    DESFace.Block[54100B, 21544B, 15272B, 60566B],
    DESFace.Block[1130B, 13026B, 43051B, 130007B],
    DESFace.Block[44571B, 37274B, 74663B, 22617B],
    DESFace.Block[47660B, 57025B, 12653B, 71647B],
    DESFace.Block[44751B, 56555B, 46242B, 24677B],
    DESFace.Block[603B, 10334B, 40233B, 23326B],
    DESFace.Block[16130B, 77434B, 11622B, 47757B],
    DESFace.Block[401B, 401B, 401B, 401B],
    DESFace.Block[401B, 401B, 401B, 401B] ];

  dataSequence: ARRAY [0..21) OF DESFace.Block ← [
    DESFace.Block[641B, 153320B, 34567B, 63502B],
    DESFace.Block[56325B, 46250B, 36757B, 53732B],
    DESFace.Block[1110B, 152070B, 3366B, 70562B],
    DESFace.Block[50505B, 45530B, 26737B, 42012B],
    DESFace.Block[41375B, 42060B, 54527B, 77642B],
    DESFace.Block[2633B, 57010B, 50717B, 12072B],
    DESFace.Block[3526B, 154340B, 73507B, 60722B],
    DESFace.Block[73045B, 12270B, 24677B, 44152B],
    DESFace.Block[35735B, 10620B, 44467B, 24002B],
    DESFace.Block[23225B, 57550B, 32657B, 60232B],
    DESFace.Block[13115B, 57100B, 47447B, 51062B],
    DESFace.Block[65405B, 67030B, 72637B, 56312B],
    DESFace.Block[113B, 153357B, 4427B, 60142B],
    DESFace.Block[44015B, 34400B, 67347B, 61362B],
    DESFace.Block[41565B, 40310B, 64617B, 36372B],
    DESFace.Block[3455B, 41640B, 73407B, 51222B],
    DESFace.Block[1376B, 52567B, 100427B, 170452B],
    DESFace.Block[16635B, 56120B, 14367B, 24302B],
    DESFace.Block[30125B, 31050B, 66557B, 24532B],
    DESFace.Block[125252B, 125252B, 125252B, 125252B],
    DESFace.Block[0B, 0B, 0B, 0B] ];

  cipherSequence: ARRAY [0..21) OF DESFace.Block ← [
    DESFace.Block[64417B, 55415B, 115046B, 111633B],
    DESFace.Block[75070B, 116420B, 32513B, 151161B],
    DESFace.Block[103216B, 135521B, 145264B, 54632B],
    DESFace.Block[70570B, 103556B, 761B, 115452B],
    DESFace.Block[127467B, 175502B, 17614B, 40225B],
    DESFace.Block[103245B, 60361B, 7306B, 154133B],
    DESFace.Block[6323B, 155002B, 41B, 156011B],
    DESFace.Block[165147B, 65454B, 133733B, 25572B],
    DESFace.Block[157726B, 45201B, 56257B, 15017B],
    DESFace.Block[56121B, 36234B, 44206B, 140210B],
    DESFace.Block[5052B, 167256B, 37764B, 125567B],
    DESFace.Block[167433B, 170076B, 56772B, 53532B],
    DESFace.Block[104277B, 6666B, 153415B, 167126B],
    DESFace.Block[120771B, 110525B, 40402B, 5526B],
    DESFace.Block[67677B, 16257B, 147775B, 2526B],
    DESFace.Block[27442B, 162233B, 125574B, 120654B],
    DESFace.Block[55153B, 60454B, 141154B, 147112B],
    DESFace.Block[57514B, 1616B, 150453B, 27101B],
    DESFace.Block[61772B, 140320B, 32331B, 173623B],
    DESFace.Block[35347B, 13225B, 46700B, 47045B],
    DESFace.Block[106246B, 46751B, 140661B, 21647B] ];

  RandomKey: PROCEDURE =
    BEGIN 
    Put.Line[log, "Making Random key..."L];
    key ← DESFace.GetRandomKey[];
    PutKey[@key];
    Put.CR[log];
    END;

  RandomSeed: PROCEDURE =
    BEGIN 
    Put.Line[log, "Making Random seed..."L];
    seed ← DESFace.GetRandomIV[];
    PutIV[@seed];
    Put.CR[log];
    END;

  FixedPatternTests: PROCEDURE =
    BEGIN
    error: BOOLEAN ← FALSE;
    block: DESFace.Block;
    Put.Line[log, "Fixed pattern tests..."L];
    FOR i: CARDINAL IN [0..21) DO
      DESFace.EncryptBlock[LOOPHOLE[keySequence[i], DESFace.Key], @dataSequence[i], @block];
      IF block # cipherSequence[i] THEN
        BEGIN
        Put.Text[log, "Encryption # "L];
        PutDecimal[i];
        Put.Line[log, " wrong."L];
        error ← TRUE
        END;
      DESFace.DecryptBlock[LOOPHOLE[keySequence[i], DESFace.Key], @cipherSequence[i], @block];
      IF block # dataSequence[i] THEN
        BEGIN
        Put.Text[log, "Decryption # "L];
        PutDecimal[i];
        Put.Line[log, " wrong."L];
        error ← TRUE
        END;
      ENDLOOP;
    IF NOT error THEN Put.Line[log, "No errors."L];
    Put.CR[log];
    END;

  ECB1: PROCEDURE =
    BEGIN
    a, b, c: ARRAY [0..1) OF DESFace.Block ← [dataSequence[0]];
    aa: DESFace.Blocks = @a;
    bb: DESFace.Blocks = @b;
    cc: DESFace.Blocks = @c;
    Put.Line[log, "Electronic Code Book, 1 block..."L];
    PutKey[@key];
    PutBlocks["in:  "L, aa, 1];
    DESFace.ECBEncrypt[key, 1, aa, bb];
    PutBlocks["en:  "L, bb, 1];
    DESFace.ECBDecrypt[key, 1, bb, cc];
    PutBlocks["de:  "L, cc, 1];
    IF a # c THEN Put.Line[log, "Didn't get the right answer.  ←←←←←←←←"L];
    Put.CR[log];
    END;

  ECB4: PROCEDURE =
    BEGIN
    a, b, c: ARRAY [0..4) OF DESFace.Block ←
      [dataSequence[0], dataSequence[1], dataSequence[2], dataSequence[3]];
    aa: DESFace.Blocks = @a;
    bb: DESFace.Blocks = @b;
    cc: DESFace.Blocks = @c;
    Put.Line[log, "Electronic Code Book, 4 blocks..."L];
    PutKey[@key];
    PutBlocks["in:  "L, aa, 4];
    DESFace.ECBEncrypt[key, 4, aa, bb];
    PutBlocks["en:  "L, bb, 4];
    DESFace.ECBDecrypt[key, 4, bb, cc];
    PutBlocks["de:  "L, cc, 4];
    IF a # c THEN Put.Line[log, "Didn't get the right answer.  ←←←←←←←←"L];
    Put.CR[log];
    END;

  CBC1: PROCEDURE =
    BEGIN
    a, b, c: ARRAY [0..1) OF DESFace.Block ← [dataSequence[0]];
    aa: DESFace.Blocks = @a;
    bb: DESFace.Blocks = @b;
    cc: DESFace.Blocks = @c;
    Put.Line[log, "Cipher Block Chaining, 1 block..."L];
    PutKey[@key];
    PutIV[@seed];
    PutBlocks["in:  "L, aa, 1];
    DESFace.CBCEncrypt[key, 1, aa, bb, seed];
    PutBlocks["en:  "L, bb, 1];
    DESFace.CBCDecrypt[key, 1, bb, cc, seed];
    PutBlocks["de:  "L, cc, 1];
    IF a # c THEN Put.Line[log, "Didn't get the right answer.  ←←←←←←←←"L];
    Put.CR[log];
    END;
  
  CBC4: PROCEDURE =
    BEGIN
    a, b, c: ARRAY [0..4) OF DESFace.Block ←
      [dataSequence[0], dataSequence[1], dataSequence[2], dataSequence[3]];
    aa: DESFace.Blocks = @a;
    bb: DESFace.Blocks = @b;
    cc: DESFace.Blocks = @c;
    Put.Line[log, "Cipher Block Chaining, 4 blocks..."L];
    PutKey[@key];
    PutIV[@seed];
    PutBlocks["in:  "L, aa, 4];
    DESFace.CBCEncrypt[key, 4, aa, bb, seed];
    PutBlocks["en:  "L, bb, 4];
    DESFace.CBCDecrypt[key, 4, bb, cc, seed];
    PutBlocks["de:  "L, cc, 4];
    IF a # c THEN Put.Line[log, "Didn't get the right answer.  ←←←←←←←←"L];
    Put.CR[log];
    END;
  
  Loop: PROCEDURE [mode: {ecb, cbc}] =
    BEGIN
    old: Process.Priority ← Process.GetPriority[];
    start, stop, p1, p65: System.Pulses ← [0];
    good, bad, since: CARDINAL ← 0;
    t1, t65: LONG CARDINAL ← 0;
    setupTime, blockTime: LONG CARDINAL;
    clumps: LONG CARDINAL ← 0;
    error: BOOLEAN ← FALSE;
    input: ARRAY [0..65) OF DESFace.Block;
    encrypted: ARRAY [0..65) OF DESFace.Block;
    decrypted: ARRAY [0..65) OF DESFace.Block;
    in: DESFace.Blocks = LOOPHOLE[LONG[@input]];
    en: DESFace.Blocks = LOOPHOLE[LONG[@encrypted]];
    de: DESFace.Blocks = LOOPHOLE[LONG[@decrypted]];
    pleaseStop: BOOLEAN ← FALSE;
    Watch: PROCEDURE =
      BEGIN
      [] ← OthelloDefs.ReadChar[ ! ABORTED => CONTINUE];
      pleaseStop ← TRUE;
      END;
    FOR i: CARDINAL IN [0..65) DO
      input[i] ← dataSequence[i MOD 21];
      ENDLOOP;
    SELECT mode FROM
      ecb => Put.Line[log, "Looping (ECB mode) ..."L];
      cbc => Put.Line[log, "Looping (CBC mode) ..."L];
      ENDCASE => ERROR;
    Process.Detach[FORK Watch[]];
    UNTIL pleaseStop DO
      ok: BOOLEAN ← TRUE;
      Process.SetPriority[7];
      start ← System.GetClockPulses[];
      SELECT mode FROM
        ecb =>
	  BEGIN
          DESFace.ECBEncrypt[key, 1, in, en];
          DESFace.ECBDecrypt[key, 1, en, de];
	  END;
        cbc =>
	  BEGIN
          DESFace.CBCEncrypt[key, 1, in, en, seed];
          DESFace.CBCDecrypt[key, 1, en, de, seed];
	  END;
        ENDCASE => ERROR;
      stop ← System.GetClockPulses[];
      Process.SetPriority[ProcessPriorities.priorityClientLow];
      p1 ← [p1 + stop - start];
      IF input[0] # decrypted[0] THEN
        BEGIN
	ok ← FALSE;
	Put.Char[log, '~];
	END;
      Process.SetPriority[7];
      start ← System.GetClockPulses[];
      SELECT mode FROM
        ecb =>
	  BEGIN
          DESFace.ECBEncrypt[key, 65, in, en];
          DESFace.ECBDecrypt[key, 65, en, de];
	  END;
        cbc =>
	  BEGIN
          DESFace.CBCEncrypt[key, 65, in, en, seed];
          DESFace.CBCDecrypt[key, 65, en, de, seed];
	  END;
        ENDCASE => ERROR;
      stop ← System.GetClockPulses[];
      Process.SetPriority[ProcessPriorities.priorityClientLow];
      p65 ← [p65 + stop - start];
      IF input # decrypted THEN
        BEGIN
	ok ← FALSE;
	Put.Char[log, '#];
	END;
      clumps ← clumps + 1;
      IF ok THEN
        BEGIN
	good ← good + 1;
	since ← since + 1;
	IF since = 100 THEN
	  BEGIN
	  Put.Char[log, '!];
	  since ← 0;
	  END;
	END
      ELSE bad ← bad + 1;
      ENDLOOP;
    t1 ← System.PulsesToMicroseconds[[p1]];
    t65 ← System.PulsesToMicroseconds[[p65]];
    Put.CR[log];
    Process.SetPriority[old];
    IF bad # 0 THEN
      BEGIN
      PutLongDecimal[bad];
      Put.Text[log, " bad clumps.  "L];
      END;
    PutLongDecimal[good];
    Put.Line[log, " good clumps."L];
    Put.Text[log, "It took "L];
    PutLongDecimal[t1/clumps];
    Put.Line[log, " microseconds to encrypt and decrypt a 1 block clump."L];
    Put.Text[log, "It took "L];
    PutLongDecimal[t65/clumps];
    Put.Line[log, " microseconds to encrypt and decrypt a 65 block clump."L];
    blockTime ← (t65-t1)/(65-1)/clumps/2;
    setupTime ← (t1 - 1*blockTime)/clumps/2;
    Put.Text[log, "That's "L];
    PutLongDecimal[setupTime];
    Put.Text[log, " microseconds of setup and "L];
    PutLongDecimal[blockTime];
    Put.Text[log, " microseconds/block, or "L];
    PutLongDecimal[64000000/blockTime];
    Put.Line[log, " bits/second."L];
    Put.CR[log];
    END;

  Flap: PROCEDURE =
    BEGIN
    good, bad: LONG CARDINAL ← 0;
    data: ARRAY [0..21) OF DESFace.Block ← dataSequence;
    encrypted: ARRAY [0..21) OF DESFace.Block;
    decrypted: ARRAY [0..21) OF DESFace.Block;
    in: DESFace.Blocks = LOOPHOLE[LONG[@data]];
    en: DESFace.Blocks = LOOPHOLE[LONG[@encrypted]];
    de: DESFace.Blocks = LOOPHOLE[LONG[@decrypted]];
    pleaseStop: BOOLEAN ← FALSE;
    Watch: PROCEDURE =
      BEGIN
      [] ← OthelloDefs.ReadChar[ ! ABORTED => CONTINUE];
      pleaseStop ← TRUE;
      END;
    Put.Line[log, "Flapping DES signals (21 blocks of CBC)..."L];
    Process.Detach[FORK Watch[]];
    UNTIL pleaseStop DO
      DESFace.CBCEncrypt[key, 21, in, en, seed];
      DESFace.CBCDecrypt[key, 21, en, de, seed];
      IF data = decrypted THEN good ← good + 1
      ELSE bad ← bad + 1;
      Process.Yield[];
      ENDLOOP;
    Put.Text[log, "There were "L];
    PutLongDecimal[good];
    Put.Text[log, " good and "L];
    PutLongDecimal[bad];
    Put.Line[log, " bad clumps."L];
    Put.CR[log];
    END;

  PutIV: PROCEDURE [p: LONG POINTER TO DESFace.IV] =
    BEGIN
    PutClump["iv:  "L, p, SIZE[DESFace.IV]];
    END;

  PutKey: PROCEDURE [p: LONG POINTER TO DESFace.Key] =
    BEGIN
    PutClump["key: "L, p, SIZE[DESFace.Key]];
    END;

  PutBlocks: PROCEDURE [id: LONG STRING, p: DESFace.Blocks, n: CARDINAL] =
    BEGIN
    PutClump[id, p, n*SIZE[DESFace.Block]];
    END;

  PutClump: PROCEDURE [id: LONG STRING, p: LONG POINTER, n: CARDINAL] =
    BEGIN
    Put.Text[log, id];
    FOR i: CARDINAL IN [0..n) DO
      temp: STRING = [20];
      IF i # 0 AND (i MOD 8) = 0 THEN
        BEGIN
        Put.CR[log];
        Put.Text[log, "     "L];
	END;
      String.AppendNumber[temp, (p+i)↑, 16];
      THROUGH [temp.length..5) DO Put.Char[log, ' ]; ENDLOOP;
      Put.Text[log, temp];
      ENDLOOP;
    Put.CR[log];
    END;

  PutDecimal: PROCEDURE [n: CARDINAL] = INLINE BEGIN PutLongDecimal[n]; END;

  PutLongDecimal: PROCEDURE [n: LONG CARDINAL] =
    BEGIN
    temp: STRING = [20];
    String.AppendLongDecimal[temp, n];
    Put.Text[log, temp];
    END;

  commandProcessor: OthelloDefs.CommandProcessor ← [Commands];
  Commands: PROCEDURE [index: CARDINAL] =
    BEGIN
    SELECT index FROM
      0 =>
        BEGIN
        OthelloDefs.MyNameIs[
	  myNameIs: "DES RandomKey"L,
	  myHelpIs: "Make Random Key for DES Testing"L];
	RandomKey[];
	END;
      1 =>
        BEGIN
        OthelloDefs.MyNameIs[
	  myNameIs: "DES RandomSeed"L,
	  myHelpIs: "Make Random Seed for DES Testing in CBC mode"L];
	RandomSeed[];
	END;
      2 =>
        BEGIN
        OthelloDefs.MyNameIs[
	  myNameIs: "DES Fixed Pattern Tests"L,
	  myHelpIs: "Run magic patterns to test all bits in DES chip"L];
	FixedPatternTests[];
	END;
      3 =>
        BEGIN
        OthelloDefs.MyNameIs[
	  myNameIs: "DES ECB1"L,
	  myHelpIs: "Feed 1 block to DES in ECB mode"L];
	ECB1[];
	END;
      4 =>
        BEGIN
        OthelloDefs.MyNameIs[
	  myNameIs: "DES ECB4"L,
	  myHelpIs: "Feed 4 blocks to DES in ECB mode"L];
	ECB4[];
	END;
      5 =>
        BEGIN
        OthelloDefs.MyNameIs[
	  myNameIs: "DES CBC1"L,
	  myHelpIs: "Feed 1 block to DES in CBC mode"L];
	CBC1[];
	END;
      6 =>
        BEGIN
        OthelloDefs.MyNameIs[
	  myNameIs: "DES CBC4"L,
	  myHelpIs: "Feed 4 blocks to DES in CBC mode"L];
	CBC4[];
	END;
      7 =>
        BEGIN
        OthelloDefs.MyNameIs[
	  myNameIs: "DES Loop ECB"L,
	  myHelpIs: "Loop running DES chip in ECB mode"L];
        Loop[ecb];
	END;
      8 =>
        BEGIN
        OthelloDefs.MyNameIs[
	  myNameIs: "DES Loop CBC"L,
	  myHelpIs: "Loop running DES chip in CBC mode"L];
        Loop[cbc];
	END;
      9 =>
        BEGIN
        OthelloDefs.MyNameIs[
	  myNameIs: "DES Flap"L,
	  myHelpIs: "Loop flapping DES signals (no printout)"L];
        Flap[];
	END;
      ENDCASE => OthelloDefs.IndexTooLarge;
    END;
   
  
  -- Main Body
  OthelloDefs.RegisterCommandProc[@commandProcessor];
  END.