Browse Source

Speed execution by 300% by replacing extension UInt32->Int conversion with the inline Int(value)

Marcin Krzyżanowski 10 years ago
parent
commit
b5f71dfb3d

+ 20 - 0
CryptoSwift.xcodeproj/xcshareddata/xcbaselines/754BE45F19693E190098E6F3.xcbaseline/85434D17-7706-4DE9-AFA7-B1DD0BD9FA39.plist

@@ -16,6 +16,26 @@
 					<string>Local Baseline</string>
 				</dict>
 			</dict>
+			<key>testAES_decrypt_performance()</key>
+			<dict>
+				<key>com.apple.XCTPerformanceMetric_WallClockTime</key>
+				<dict>
+					<key>baselineAverage</key>
+					<real>0.624</real>
+					<key>baselineIntegrationDisplayName</key>
+					<string>Local Baseline</string>
+				</dict>
+			</dict>
+			<key>testAES_encrypt_performance()</key>
+			<dict>
+				<key>com.apple.XCTPerformanceMetric_WallClockTime</key>
+				<dict>
+					<key>baselineAverage</key>
+					<real>0.5895</real>
+					<key>baselineIntegrationDisplayName</key>
+					<string>Local Baseline</string>
+				</dict>
+			</dict>
 		</dict>
 	</dict>
 </dict>

+ 40 - 52
CryptoSwift/AES.swift

@@ -46,6 +46,7 @@ final public class AES {
     private let key:[UInt8]
     private let iv:[UInt8]?
     public lazy var expandedKey:[[UInt32]] = { self.expandKey(self.key, variant: self.variant) }()
+    public lazy var expandedKeyInv:[[UInt32]] = { self.expandKeyInv(self.key, variant: self.variant) }()
     
 //    private lazy var sBoxes:(sBox:[UInt8], invSBox:[UInt8]) = self.calculateSBox()
 //    private lazy var sBox:[UInt8] = self.sBoxes.sBox
@@ -899,10 +900,10 @@ final public class AES {
     
     private func F1(x0: UInt32, _ x1: UInt32, _ x2: UInt32, _ x3: UInt32) -> UInt32 {
         var result:UInt32 = 0
-        result |= UInt32(B1(T0[x0 & 255]))
-        result |= UInt32(B1(T0[(x1 >> 8) & 255])) << 8
-        result |= UInt32(B1(T0[(x2 >> 16) & 255])) << 16
-        result |= UInt32(B1(T0[x3 >> 24])) << 24
+        result |= UInt32(B1(T0[Int(x0 & 255)]))
+        result |= UInt32(B1(T0[Int((x1 >> 8) & 255)])) << 8
+        result |= UInt32(B1(T0[Int((x2 >> 16) & 255)])) << 16
+        result |= UInt32(B1(T0[Int(x3 >> 24)])) << 24
         return result
     }
 
@@ -920,10 +921,10 @@ final public class AES {
             t[2] = b[2] ^ rk[r][2]
             t[3] = b[3] ^ rk[r][3]
             
-            b[0] = T0[t[0] & 0xFF] ^ T1[(t[1] >> 8) & 0xFF] ^ T2[(t[2] >> 16) & 0xFF] ^ T3[t[3] >> 24]
-            b[1] = T0[t[1] & 0xFF] ^ T1[(t[2] >> 8) & 0xFF] ^ T2[(t[3] >> 16) & 0xFF] ^ T3[t[0] >> 24]
-            b[2] = T0[t[2] & 0xFF] ^ T1[(t[3] >> 8) & 0xFF] ^ T2[(t[0] >> 16) & 0xFF] ^ T3[t[1] >> 24]
-            b[3] = T0[t[3] & 0xFF] ^ T1[(t[0] >> 8) & 0xFF] ^ T2[(t[1] >> 16) & 0xFF] ^ T3[t[2] >> 24]
+            b[0] = T0[Int(t[0] & 0xFF)] ^ T1[Int((t[1] >> 8) & 0xFF)] ^ T2[Int((t[2] >> 16) & 0xFF)] ^ T3[Int(t[3] >> 24)]
+            b[1] = T0[Int(t[1] & 0xFF)] ^ T1[Int((t[2] >> 8) & 0xFF)] ^ T2[Int((t[3] >> 16) & 0xFF)] ^ T3[Int(t[0] >> 24)]
+            b[2] = T0[Int(t[2] & 0xFF)] ^ T1[Int((t[3] >> 8) & 0xFF)] ^ T2[Int((t[0] >> 16) & 0xFF)] ^ T3[Int(t[1] >> 24)]
+            b[3] = T0[Int(t[3] & 0xFF)] ^ T1[Int((t[0] >> 8) & 0xFF)] ^ T2[Int((t[1] >> 16) & 0xFF)] ^ T3[Int(t[2] >> 24)]
         }
         
         // last round
@@ -976,44 +977,9 @@ final public class AES {
     }
     
     private func decryptBlock(block:[UInt8]) -> [UInt8]? {
-        
-        func prepareRK() -> [[UInt32]] {
-            let rounds = self.variant.Nr
-            let rk = self.expandedKey
-            var rk2 = rk
-            
-            //TODO: isn't it just COPY ?
-//            for(var r = 0; r < rk2.count; r++) {
-//                rk2[r] = [UInt32](count: 4, repeatedValue: 0)
-//                
-//                rk2[r][0] = rk[r][0];
-//                rk2[r][1] = rk[r][1];
-//                rk2[r][2] = rk[r][2];
-//                rk2[r][3] = rk[r][3];
-//            }
-            
-            for r in 1..<rounds {
-                var w:UInt32
-                
-                w = rk2[r][0];
-                rk2[r][0] = U1[B0(w)] ^ U2[B1(w)] ^ U3[B2(w)] ^ U4[B3(w)]
-                
-                w = rk2[r][1];
-                rk2[r][1] = U1[B0(w)] ^ U2[B1(w)] ^ U3[B2(w)] ^ U4[B3(w)]
-                
-                w = rk2[r][2];
-                rk2[r][2] = U1[B0(w)] ^ U2[B1(w)] ^ U3[B2(w)] ^ U4[B3(w)]
-                
-                w = rk2[r][3];
-                rk2[r][3] = U1[B0(w)] ^ U2[B1(w)] ^ U3[B2(w)] ^ U4[B3(w)]
-            }
-            
-            return rk2
-        }
-        
         let rounds = self.variant.Nr // TODO: remove later
         var b = block[block.startIndex..<block.endIndex].toUInt32Array()
-        let rk = prepareRK()
+        let rk = expandedKeyInv
 
         var t = [UInt32](count: 4, repeatedValue: 0) // UInt32 effectively
         
@@ -1023,10 +989,10 @@ final public class AES {
             t[2] = b[2] ^ rk[r][2]
             t[3] = b[3] ^ rk[r][3]
             
-            b[0] = T0_INV[t[0] & 0xFF] ^ T1_INV[(t[3] >> 8) & 0xFF] ^ T2_INV[(t[2] >> 16) & 0xFF] ^ T3_INV[t[1] >> 24]
-            b[1] = T0_INV[t[1] & 0xFF] ^ T1_INV[(t[0] >> 8) & 0xFF] ^ T2_INV[(t[3] >> 16) & 0xFF] ^ T3_INV[t[2] >> 24]
-            b[2] = T0_INV[t[2] & 0xFF] ^ T1_INV[(t[1] >> 8) & 0xFF] ^ T2_INV[(t[0] >> 16) & 0xFF] ^ T3_INV[t[3] >> 24]
-            b[3] = T0_INV[t[3] & 0xFF] ^ T1_INV[(t[2] >> 8) & 0xFF] ^ T2_INV[(t[1] >> 16) & 0xFF] ^ T3_INV[t[0] >> 24]
+            b[0] = T0_INV[Int(t[0] & 0xFF)] ^ T1_INV[Int((t[3] >> 8) & 0xFF)] ^ T2_INV[Int((t[2] >> 16) & 0xFF)] ^ T3_INV[Int(t[1] >> 24)]
+            b[1] = T0_INV[Int(t[1] & 0xFF)] ^ T1_INV[Int((t[0] >> 8) & 0xFF)] ^ T2_INV[Int((t[3] >> 16) & 0xFF)] ^ T3_INV[Int(t[2] >> 24)]
+            b[2] = T0_INV[Int(t[2] & 0xFF)] ^ T1_INV[Int((t[1] >> 8) & 0xFF)] ^ T2_INV[Int((t[0] >> 16) & 0xFF)] ^ T3_INV[Int(t[3] >> 24)]
+            b[3] = T0_INV[Int(t[3] & 0xFF)] ^ T1_INV[Int((t[2] >> 8) & 0xFF)] ^ T2_INV[Int((t[1] >> 16) & 0xFF)] ^ T3_INV[Int(t[0] >> 24)]
         }
         
         // last round
@@ -1036,10 +1002,10 @@ final public class AES {
         t[3] = b[3] ^ rk[1][3]
         
         // rounds
-        b[0] = sBoxInv[B0(t[0])] | (sBoxInv[B1(t[3])] << 8) | (sBoxInv[B2(t[2])] << 16) | (sBoxInv[B3(t[1])] << 24) ^ rk[0][0]
-        b[1] = sBoxInv[B0(t[1])] | (sBoxInv[B1(t[0])] << 8) | (sBoxInv[B2(t[3])] << 16) | (sBoxInv[B3(t[2])] << 24) ^ rk[0][1]
-        b[2] = sBoxInv[B0(t[2])] | (sBoxInv[B1(t[1])] << 8) | (sBoxInv[B2(t[0])] << 16) | (sBoxInv[B3(t[3])] << 24) ^ rk[0][2]
-        b[3] = sBoxInv[B0(t[3])] | (sBoxInv[B1(t[2])] << 8) | (sBoxInv[B2(t[1])] << 16) | (sBoxInv[B3(t[0])] << 24) ^ rk[0][3]
+        b[0] = sBoxInv[Int(B0(t[0]))] | (sBoxInv[Int(B1(t[3]))] << 8) | (sBoxInv[Int(B2(t[2]))] << 16) | (sBoxInv[Int(B3(t[1]))] << 24) ^ rk[0][0]
+        b[1] = sBoxInv[Int(B0(t[1]))] | (sBoxInv[Int(B1(t[0]))] << 8) | (sBoxInv[Int(B2(t[3]))] << 16) | (sBoxInv[Int(B3(t[2]))] << 24) ^ rk[0][1]
+        b[2] = sBoxInv[Int(B0(t[2]))] | (sBoxInv[Int(B1(t[1]))] << 8) | (sBoxInv[Int(B2(t[0]))] << 16) | (sBoxInv[Int(B3(t[3]))] << 24) ^ rk[0][2]
+        b[3] = sBoxInv[Int(B0(t[3]))] | (sBoxInv[Int(B1(t[2]))] << 8) | (sBoxInv[Int(B2(t[1]))] << 16) | (sBoxInv[Int(B3(t[0]))] << 24) ^ rk[0][3]
         
         var out = [UInt8]()
         out.reserveCapacity(b.count * 4)
@@ -1054,6 +1020,28 @@ final public class AES {
         return out
     }
     
+    private func expandKeyInv(key:[UInt8], variant:AESVariant) -> [[UInt32]] {
+        let rounds = variant.Nr
+        var rk2:[[UInt32]] = expandKey(key, variant: variant)
+        for r in 1..<rounds {
+            var w:UInt32
+            
+            w = rk2[r][0];
+            rk2[r][0] = U1[Int(B0(w))] ^ U2[Int(B1(w))] ^ U3[Int(B2(w))] ^ U4[Int(B3(w))]
+            
+            w = rk2[r][1];
+            rk2[r][1] = U1[Int(B0(w))] ^ U2[Int(B1(w))] ^ U3[Int(B2(w))] ^ U4[Int(B3(w))]
+            
+            w = rk2[r][2];
+            rk2[r][2] = U1[Int(B0(w))] ^ U2[Int(B1(w))] ^ U3[Int(B2(w))] ^ U4[Int(B3(w))]
+            
+            w = rk2[r][3];
+            rk2[r][3] = U1[Int(B0(w))] ^ U2[Int(B1(w))] ^ U3[Int(B2(w))] ^ U4[Int(B3(w))]
+        }
+        
+        return rk2
+    }
+    
     private func expandKey(key:[UInt8], variant:AESVariant) -> [[UInt32]] {
         
         func convertExpandedKey(expanded:[UInt8]) -> [[UInt32]] {

+ 4 - 0
CryptoSwift/Array+Extension.swift

@@ -23,6 +23,9 @@ extension Array {
         return words
     }
     
+    /*
+    This helper call is slow, therefore don't use it. It is due to extension, or due to optimization that can be done
+    
     subscript(index: UInt32) -> Element {
         get {
             return self[Int(index)]
@@ -31,5 +34,6 @@ extension Array {
             self[Int(index)] = newValue
         }
     }
+    */
 }