// Copyright (c) 2011-2016 Galois, Inc. // An implementation of ZUC, Version 1.5 // Version info: If the following variable is set to True, then we implement // Version 1.5 of ZUC. Otherwise, version 1.4 is implemented. There are // precisely two points in the implementation where the difference matters, // search for occurrences of version1_5 to spot them. // Note that the ZUC test vectors below will not work for version 1.4, as the // old test vectors are no longer published. version1_5 : Bit version1_5 = True // addition in GF(2^31-1) over a list of terms add : {a} (fin a) => [a][31] -> [31] add xs = sums ! 0 where sums = [0] # [plus (s, x) | s <- sums | x <- xs] // the binary addition specified in the note at the end of section 3.2 plus : ([31], [31]) -> [31] plus (a, b) = if sab @ 0 then sab' + 1 else sab' where sab : [32] sab = ((zero : [1]) # a) + ((zero : [1]) # b) sab' : [31] sab' = drop sab // The ZUC LFSR is 16 31-bit words type LFSR = [16][31] // Section 3.2 LFSRWithInitializationMode : ([31], LFSR) -> LFSR LFSRWithInitializationMode (u, ss) = ss @@ [1 .. 15] # [s16] where v = add [s <<< c | s <- ss @@ [15, 13, 10, 4, 0, 0] | c <- [15, 17, 21, 20, 8, 0]] vu = if version1_5 then add [v, u] else v ^ u s16 = if vu == 0 then `0x7FFFFFFF else vu // Section 3.2 LFSRWithWorkMode : LFSR -> LFSR LFSRWithWorkMode ss = ss @@ [1 .. 15] # [s16] where v = add [s <<< c | s <- ss @@ [15, 13, 10, 4, 0, 0] | c <- [15, 17, 21, 20, 8, 0]] s16 = if v == 0 then `0x7FFFFFFF else v // Section 3.3 BitReorganization : LFSR -> [4][32] BitReorganization ss = [ hi s15 # lo s14 , lo s11 # hi s9 , lo s7 # hi s5 , lo s2 # hi s0] where lo : [31] -> [16] hi : [31] -> [16] lo x = x @@ [15 .. 30] hi x = x @@ [0 .. 15] [s0, s2, s5, s7, s9, s11, s14, s15] = ss @@ [0, 2, 5, 7, 9, 11, 14, 15] // Section 3.4 F : ([3][32], [2][32]) -> ([32], [2][32]) F ([X0, X1, X2], [R1, R2]) = (W, [R1', R2']) where W = (X0 ^ R1) + R2 W1 = R1 + X1 W2 = R2 ^ X2 [W1H, W1L] = split W1 [W2H, W2L] = split W2 R1' = S (L1 (W1L # W2H)) R2' = S (L2 (W2L # W1H)) // Section 3.4.1 S : [32] -> [32] S X = Y0 # Y1 # Y2 # Y3 where [X0, X1, X2, X3] = split X [Y0, Y1, Y2, Y3] = [S0 X0, S1 X1, S2 X2, S3 X3] // Example 8 property example8 = S(0x12345678) == 0xF9C05A4E S0 : [8] -> [8] S1 : [8] -> [8] S2 : [8] -> [8] S3 : [8] -> [8] S0 x = S0Table @ x S1 x = S1Table @ x S2 = S0 S3 = S1 // Table 3.1 S0Table : [256][8] S0Table = [0x3E, 0x72, 0x5B, 0x47, 0xCA, 0xE0, 0x00, 0x33, 0x04, 0xD1, 0x54, 0x98, 0x09, 0xB9, 0x6D, 0xCB, 0x7B, 0x1B, 0xF9, 0x32, 0xAF, 0x9D, 0x6A, 0xA5, 0xB8, 0x2D, 0xFC, 0x1D, 0x08, 0x53, 0x03, 0x90, 0x4D, 0x4E, 0x84, 0x99, 0xE4, 0xCE, 0xD9, 0x91, 0xDD, 0xB6, 0x85, 0x48, 0x8B, 0x29, 0x6E, 0xAC, 0xCD, 0xC1, 0xF8, 0x1E, 0x73, 0x43, 0x69, 0xC6, 0xB5, 0xBD, 0xFD, 0x39, 0x63, 0x20, 0xD4, 0x38, 0x76, 0x7D, 0xB2, 0xA7, 0xCF, 0xED, 0x57, 0xC5, 0xF3, 0x2C, 0xBB, 0x14, 0x21, 0x06, 0x55, 0x9B, 0xE3, 0xEF, 0x5E, 0x31, 0x4F, 0x7F, 0x5A, 0xA4, 0x0D, 0x82, 0x51, 0x49, 0x5F, 0xBA, 0x58, 0x1C, 0x4A, 0x16, 0xD5, 0x17, 0xA8, 0x92, 0x24, 0x1F, 0x8C, 0xFF, 0xD8, 0xAE, 0x2E, 0x01, 0xD3, 0xAD, 0x3B, 0x4B, 0xDA, 0x46, 0xEB, 0xC9, 0xDE, 0x9A, 0x8F, 0x87, 0xD7, 0x3A, 0x80, 0x6F, 0x2F, 0xC8, 0xB1, 0xB4, 0x37, 0xF7, 0x0A, 0x22, 0x13, 0x28, 0x7C, 0xCC, 0x3C, 0x89, 0xC7, 0xC3, 0x96, 0x56, 0x07, 0xBF, 0x7E, 0xF0, 0x0B, 0x2B, 0x97, 0x52, 0x35, 0x41, 0x79, 0x61, 0xA6, 0x4C, 0x10, 0xFE, 0xBC, 0x26, 0x95, 0x88, 0x8A, 0xB0, 0xA3, 0xFB, 0xC0, 0x18, 0x94, 0xF2, 0xE1, 0xE5, 0xE9, 0x5D, 0xD0, 0xDC, 0x11, 0x66, 0x64, 0x5C, 0xEC, 0x59, 0x42, 0x75, 0x12, 0xF5, 0x74, 0x9C, 0xAA, 0x23, 0x0E, 0x86, 0xAB, 0xBE, 0x2A, 0x02, 0xE7, 0x67, 0xE6, 0x44, 0xA2, 0x6C, 0xC2, 0x93, 0x9F, 0xF1, 0xF6, 0xFA, 0x36, 0xD2, 0x50, 0x68, 0x9E, 0x62, 0x71, 0x15, 0x3D, 0xD6, 0x40, 0xC4, 0xE2, 0x0F, 0x8E, 0x83, 0x77, 0x6B, 0x25, 0x05, 0x3F, 0x0C, 0x30, 0xEA, 0x70, 0xB7, 0xA1, 0xE8, 0xA9, 0x65, 0x8D, 0x27, 0x1A, 0xDB, 0x81, 0xB3, 0xA0, 0xF4, 0x45, 0x7A, 0x19, 0xDF, 0xEE, 0x78, 0x34, 0x60] // Table 3.2 S1Table : [256][8] S1Table = [0x55, 0xC2, 0x63, 0x71, 0x3B, 0xC8, 0x47, 0x86, 0x9F, 0x3C, 0xDA, 0x5B, 0x29, 0xAA, 0xFD, 0x77, 0x8C, 0xC5, 0x94, 0x0C, 0xA6, 0x1A, 0x13, 0x00, 0xE3, 0xA8, 0x16, 0x72, 0x40, 0xF9, 0xF8, 0x42, 0x44, 0x26, 0x68, 0x96, 0x81, 0xD9, 0x45, 0x3E, 0x10, 0x76, 0xC6, 0xA7, 0x8B, 0x39, 0x43, 0xE1, 0x3A, 0xB5, 0x56, 0x2A, 0xC0, 0x6D, 0xB3, 0x05, 0x22, 0x66, 0xBF, 0xDC, 0x0B, 0xFA, 0x62, 0x48, 0xDD, 0x20, 0x11, 0x06, 0x36, 0xC9, 0xC1, 0xCF, 0xF6, 0x27, 0x52, 0xBB, 0x69, 0xF5, 0xD4, 0x87, 0x7F, 0x84, 0x4C, 0xD2, 0x9C, 0x57, 0xA4, 0xBC, 0x4F, 0x9A, 0xDF, 0xFE, 0xD6, 0x8D, 0x7A, 0xEB, 0x2B, 0x53, 0xD8, 0x5C, 0xA1, 0x14, 0x17, 0xFB, 0x23, 0xD5, 0x7D, 0x30, 0x67, 0x73, 0x08, 0x09, 0xEE, 0xB7, 0x70, 0x3F, 0x61, 0xB2, 0x19, 0x8E, 0x4E, 0xE5, 0x4B, 0x93, 0x8F, 0x5D, 0xDB, 0xA9, 0xAD, 0xF1, 0xAE, 0x2E, 0xCB, 0x0D, 0xFC, 0xF4, 0x2D, 0x46, 0x6E, 0x1D, 0x97, 0xE8, 0xD1, 0xE9, 0x4D, 0x37, 0xA5, 0x75, 0x5E, 0x83, 0x9E, 0xAB, 0x82, 0x9D, 0xB9, 0x1C, 0xE0, 0xCD, 0x49, 0x89, 0x01, 0xB6, 0xBD, 0x58, 0x24, 0xA2, 0x5F, 0x38, 0x78, 0x99, 0x15, 0x90, 0x50, 0xB8, 0x95, 0xE4, 0xD0, 0x91, 0xC7, 0xCE, 0xED, 0x0F, 0xB4, 0x6F, 0xA0, 0xCC, 0xF0, 0x02, 0x4A, 0x79, 0xC3, 0xDE, 0xA3, 0xEF, 0xEA, 0x51, 0xE6, 0x6B, 0x18, 0xEC, 0x1B, 0x2C, 0x80, 0xF7, 0x74, 0xE7, 0xFF, 0x21, 0x5A, 0x6A, 0x54, 0x1E, 0x41, 0x31, 0x92, 0x35, 0xC4, 0x33, 0x07, 0x0A, 0xBA, 0x7E, 0x0E, 0x34, 0x88, 0xB1, 0x98, 0x7C, 0xF3, 0x3D, 0x60, 0x6C, 0x7B, 0xCA, 0xD3, 0x1F, 0x32, 0x65, 0x04, 0x28, 0x64, 0xBE, 0x85, 0x9B, 0x2F, 0x59, 0x8A, 0xD7, 0xB0, 0x25, 0xAC, 0xAF, 0x12, 0x03, 0xE2, 0xF2] // Section 3.4.2 L1 : [32] -> [32] L1 X = X ^ X <<< 2 ^ X <<< 10 ^ X <<< 18 ^ X <<< 24 // Section 3.4.2 L2 : [32] -> [32] L2 X = X ^ X <<< 8 ^ X <<< 14 ^ X <<< 22 ^ X <<< 30 // Section 3.5 LoadKey : ([128], [128]) -> LFSR LoadKey (key, iv) = [k # d # i | k <- ks | i <- is | d <- ds] where ks : [16][8] ks = split key is : [16][8] is = split iv ds : [16][15] ds = [ 0b100010011010111, 0b010011010111100 , 0b110001001101011, 0b001001101011110 , 0b101011110001001, 0b011010111100010 , 0b111000100110101, 0b000100110101111 , 0b100110101111000, 0b010111100010011 , 0b110101111000100, 0b001101011110001 , 0b101111000100110, 0b011110001001101 , 0b111100010011010, 0b100011110101100 ] type ZUC = (LFSR, [32], [32]) // Return an infinite sequence of ZUC states by applying the initialization step // repeatedly. This is a generalization of section 3.6.1 InitializeZUC : ([128], [128]) -> [inf]ZUC InitializeZUC (key, iv) = outs where initLFSR = LoadKey (key, iv) outs = [(initLFSR, 0, 0)] # [step out | out <- outs] step (lfsr, R1, R2) = (LFSRWithInitializationMode (drop (w >> 1), lfsr), R1', R2') where [X0, X1, X2, X3] = BitReorganization lfsr (w', [R1', R2']) = F ([X0, X1, X2], [R1, R2]) w = if version1_5 then w' else w' ^ X3 // Section 3.6.2 WorkingStage : ZUC -> ZUC WorkingStage (lfsr, R1, R2) = (lfsr', R1', R2') where [X0, X1, X2, _] = BitReorganization lfsr (_, [R1', R2']) = F ([X0, X1, X2], [R1, R2]) lfsr' = LFSRWithWorkMode lfsr // Section 3.6.2 ProductionStage : ZUC -> ([32], ZUC) ProductionStage (lfsr, R1, R2) = (w ^ X3, (lfsr', R1', R2')) where [X0, X1, X2, X3] = BitReorganization lfsr (w, [R1', R2']) = F ([X0, X1, X2], [R1, R2]) lfsr' = LFSRWithWorkMode lfsr // ZUC API ZUC : [128] -> [128] -> [inf][32] ZUC key iv = tail [w | (w, _) <- zucs] where initZuc = WorkingStage (InitializeZUC (key, iv) @ 32) zucs = [(zero, initZuc)] # [ProductionStage zuc | (_, zuc) <- zucs] // Test vectors property ZUC_TestVectors = t1 /\ t2 /\ t3 /\ t4 where t1 = take (ZUC zero zero ) == [0x27BEDE74, 0x018082DA] t2 = take (ZUC (~zero) (~zero)) == [0x0657CFA0, 0x7096398B] t3 = take (ZUC (join [ 0x3D, 0x4C, 0x4B, 0xE9, 0x6A, 0x82, 0xFD, 0xAE , 0xB5, 0x8F, 0x64, 0x1D, 0xB1, 0x7B, 0x45, 0x5B ]) (join [ 0x84, 0x31, 0x9A, 0xA8, 0xDE, 0x69, 0x15, 0xCA , 0x1F, 0x6B, 0xDA, 0x6B, 0xFB, 0xD8, 0xC7, 0x66 ])) == [0x14F1C272, 0x3279C419] t4 = take ks # [ks @ 1999] == [0xED4400E7, 0x0633E5C5, 0x7A574CDB] where ks = ZUC (join [ 0x4D, 0x32, 0x0B, 0xFA, 0xD4, 0xC2, 0x85, 0xBF , 0xD6, 0xB8, 0xBD, 0x00, 0xF3, 0x9D, 0x8B, 0x41 ]) (join [ 0x52, 0x95, 0x9D, 0xAB, 0xA0, 0xBF, 0x17, 0x6E , 0xCE, 0x2D, 0xC3, 0x15, 0x04, 0x9E, 0xB5, 0x74 ]) // 3.3-3.6 of the implementor's test data document lists "LFSR-state at the // beginning", which is immediately after running LoadKey. property LoadKey_TestVectors = [ LoadKey(k, iv) == lfsr0 | k <- ks | iv <- ivs | lfsr0 <- lfsr0s ] == ~0 where ks = [ 0 , ~0 , 0x3d4c4be96a82fdaeb58f641db17b455b , 0x4d320bfad4c285bfd6b8bd00f39d8b41 ] ivs = [ 0 , ~0 , 0x84319aa8de6915ca1f6bda6bfbd8c766 , 0x52959daba0bf176ece2dc315049eb574 ] lfsr0s = [ [ `0x0044d700, `0x0026bc00, `0x00626b00, `0x00135e00 , `0x00578900, `0x0035e200, `0x00713500, `0x0009af00 , `0x004d7800, `0x002f1300, `0x006bc400, `0x001af100 , `0x005e2600, `0x003c4d00, `0x00789a00, `0x0047ac00 ] , [ `0x7fc4d7ff, `0x7fa6bcff, `0x7fe26bff, `0x7f935eff , `0x7fd789ff, `0x7fb5e2ff, `0x7ff135ff, `0x7f89afff , `0x7fcd78ff, `0x7faf13ff, `0x7febc4ff, `0x7f9af1ff , `0x7fde26ff, `0x7fbc4dff, `0x7ff89aff, `0x7fc7acff ] , [ `0x1ec4d784, `0x2626bc31, `0x25e26b9a, `0x74935ea8 , `0x355789de, `0x4135e269, `0x7ef13515, `0x5709afca , `0x5acd781f, `0x47af136b, `0x326bc4da, `0x0e9af16b , `0x58de26fb, `0x3dbc4dd8, `0x22f89ac7, `0x2dc7ac66 ] , [ `0x26c4d752, `0x1926bc95, `0x05e26b9d, `0x7d135eab , `0x6a5789a0, `0x6135e2bf, `0x42f13517, `0x5f89af6e , `0x6b4d78ce, `0x5c2f132d, `0x5eebc4c3, `0x001af115 , `0x79de2604, `0x4ebc4d9e, `0x45f89ab5, `0x20c7ac74 ] ] // Collision attack on ZUC. Only version1.5 is resistant to it. Thus, the // following theorem holds only when version1_5 is set to True. // // NB. We only compare the first output of the InitializeZUC sequence, as it // cuts down on the problem size and is sufficient to ensure the iv's will be // the same. That is, if this theorem fails, then so would the final iv's used // by ZUC. // // Use a solver other than CVC4; Z3 and Boolector do it quickly. property ZUC_isResistantToCollisionAttack k iv1 iv2 = if iv1 != iv2 then InitializeZUC (k, iv1) @ 1 != InitializeZUC (k, iv2) @ 1 else True