3

I have been trying to rewrite a Rc4-algorithm from objective-c to swift, to test out apples(now old) claims, about it running a lot faster. However there must be somewhere that I am doing something horribly wrong with these times I am getting

This is the objective c code:

+(NSString*)Rc4:(NSString*)aInput key:(NSString *)aKey {
    NSMutableArray *iS = [[NSMutableArray alloc] initWithCapacity:256];
    NSMutableArray *iK = [[NSMutableArray alloc] initWithCapacity:256];

    for (int i = 0; i <256;i++){
        [iS addObject:[NSNumber numberWithInt:i]];
    }

    for(short i=0;i<256;i++){
        UniChar c = [aKey characterAtIndex:i%aKey.length];
        [iK addObject:[NSNumber numberWithChar:c]];
    }
    int j=2;
    for (int i=0; i<255;i++){
        int is = [[iS objectAtIndex:i]  intValue];
        UniChar ik = (UniChar)[[iK objectAtIndex:i]charValue];

        j= (j+is+ik)%256;
        NSNumber *temp = [iS objectAtIndex:i];
        [iS replaceObjectAtIndex:i withObject:[iS objectAtIndex:j]];
        [iS replaceObjectAtIndex:j withObject:temp];
    }

    int i =0;
    j=0;
    NSString *result = aInput;

    for (short x=0;x<[aInput length]; x++){
        i = (i+1)%256;

        int is = [[iS objectAtIndex:i]intValue];
        j=(j+is)%256;

        int is_i = [[iS objectAtIndex:i]intValue];
        int is_j = [[iS objectAtIndex:j]intValue];

        int t= (is_i+is_j)%256;
        int iY = [[iS objectAtIndex:t]intValue];

        UniChar ch = (UniChar)[aInput characterAtIndex:x];
        UniChar ch_y=ch^iY;
        //NSLog(ch);
        //NSLog(iY);

        result = [result stringByReplacingCharactersInRange:NSMakeRange(x,1) withString:
                  [NSString stringWithCharacters:&ch_y length:1] ];
    }
    [iS release];
    [iK release];
    return result;
}

This runs pretty fast compiling with -O3 I get times of:

100 runs:0.006 seconds

With key: 6f7e2a3d744a3b5859725f412f (128bit)

and input: "MySecretCodeToBeEncryptionSoNobodySeesIt"

This is my attempt to implement it in the same way using Swift:

extension String {
   subscript (i: Int) -> String {
      return String(Array(self)[i])
   }
}
extension Character {
  func unicodeValue() -> UInt32 {
    for s in String(self).unicodeScalars {
      return s.value
    }
    return 0

    }
  }
func Rc4(input:String, key:String)-> String{
  var iS = Array(count:256, repeatedValue: 0)
  var iK = Array(count:256, repeatedValue: "")
  var keyLength = countElements(key)

  for var i = 0; i < 256; i++ {
    iS[i] = i;
  }

  for var i = 0; i < 256 ; i++ {
    var c = key[i%keyLength]
    iK[i] = c;  
  }

  var j = 2

  for var i = 0; i < 255; i++ {
    var iss = iS[i]
    var ik = iK[i]
    // transform string to int
    var ik_x:Character = Character(ik)
    var ikk_xx = Int(ik_x.unicodeValue())

    j = (j+iss+ikk_xx)%256;
    var temp = iS[i]
    iS[i] = iS[j]
    iS[j] = temp
  }

  var i = 0
  j=0
  var result = input
  var eles = countElements(input)
  for var x = 0 ; x<eles ; x++ {
    i = (i+1)%256

    var iss = iS[i]
    j = (j+iss)%256

    var is_i = iS[i]
    var is_j = iS[j]
    var t = (is_i+is_j)%256
    var iY = iS[t]

    var ch = (input[x])
    var ch_x:Character = Character(ch)
    var ch_xx = Int(ch_x.unicodeValue())
    var ch_y = ch_xx^iY
    var start = advance(result.startIndex, x)
    var end = advance(start,1);
    let range = Range(start:start, end:end)
    var maybestring = String(UnicodeScalar(ch_y))
    result = result.stringByReplacingCharactersInRange(range, withString:maybestring)
  }
  return result;
}

I have tried to implement it so it looks as much as the objective-c version as possible. This however gives me these horrible times, using -O

100 runs: 0.5 seconds

EDIT Code should now run in xcode 6.1 using the extension methods I posted.

I run it from terminal like this:

xcrun swiftc -O Swift.swift -o swift

where Swift.swift is my file, and swift is my executable

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
  • Your Swift code doesn't build in Xcode 6.1. – MechEthan Dec 11 '14 at 02:23
  • Don't use strings in either case in the actual encryption portions. Encryption is a data operation. Compare your results to Common Crypto and you should see that neither implementation is even close. – zaph Dec 11 '14 at 11:19
  • The purpose here is to test very similar pieces of code in objective-c and swift, which i thought i was doing, but these weird runtimes are talking against it. It is not about optimizing safety in encryption or even doing it correct. Thanks for you input though, sorry if it seems weird. – Christian Martin Henriksen Dec 11 '14 at 12:06
  • Strings in Swift can be very slow as there is no direct indexing into them due to better unicode handling. The extensions added to String are not a good idea, they will not work with unicode characters that require multiple UTF-16 code units such as emoji, that is why they are not a part of Swift. Since the extensions don't work for all String characters just make the methods private. Also check the Swift compile optimization level. – zaph Dec 11 '14 at 12:20
  • I have actually been looking for documentation about compile optimization levels ( http://stackoverflow.com/questions/27233479/documentation-about-compiler-options-for-swift ) As far as i gathered -O (swift) is similar to -O3 (objective-c) But i haven't been able to find any strict documentation to support this. Thanks again! – Christian Martin Henriksen Dec 11 '14 at 12:28

2 Answers2

0

Usually claims of speed don't really apply to encryption algorithms, they are more for what I usually call "business logic". The functions on bits, bytes, 16/32/64 bit words etc. are usually difficult to optimize. Basically encryption algorithms are designed to be dense operations on these data structures with relatively few choices that can be optimized away.

Take for instance Java. Although infinitely faster than most interpreted languages it really doesn't compare well with C/C++, let alone with assembly optimized encryption algorithms. The same goes for most relatively small algebraic problems.

To make things faster you should at least use explicit numeric types for your numbers.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • Sure it is "business logic" indeed. I'm trying out some benchmarking because apple claimed a significant speed increase for Rc4 Encryption compared to objective-c (and less interesting for me, python). This article is mentioning the stuff that was said about the benchmark at the wwdc ( http://www.theregister.co.uk/2014/06/02/apple_aims_to_speed_up_secure_coding_with_swift_programming_language/ ) – Christian Martin Henriksen Dec 12 '14 at 18:58
0

After excessive testing of the code, i have narrowed it down to what is making my times ultra slow. If i comment out this code, so that the iK array just contains its initial value. i go from a runtime of 5 seconds to 1 second. Which is a significant increase.

for var i = 0; i < 256 ; i++ {
var c = key[i%keyLength]
iK[i] = c;  
}

The problem is with this part:

var c = key[i%keyLength]

There is no "characterAtIndex(int)" method in Swift, therefore i do this as a workaround to get the characterAtIndex. I do it using my extension:

extension String {
  subscript (i: Int) -> String {
    return String(Array(self)[i])
  }
}

But essentially it is the same as this:

var c = Array(key)[i%keyLength]

Instead of the O(1) - (constant time) of this operation in objective-c, we are getting a running time of O(n).

  • Keys shouldn't be strings at all. So I don't think Apple bothered about that. There is still a lot of optimization possible, I think, but as Apple again has created his own closed dev. environment, I cannot test. – Maarten Bodewes Dec 13 '14 at 10:23
  • @Christian In general unicode is not directly indexable because some characters can be composed of several code units whether UTF-8, UTF-16 or UTF-32 encoding. The US flag symbol is composed of four UTF-16 code units: 0xD83C 0xDDFA, 0xD83C 0xDDF8. Most emoji are two UTF-16 code units. UTF-16 is the underling encoding used by `String` and `NSString`. As owlstead and I have noted encryption is a data operation, not characters. – zaph Dec 13 '14 at 11:55