     }
 
     private func extractPayload(key: MaskingKey) throws -> [Byte] {
-        var bytes: [UInt8] = []
-
-        switch key {
+        let cyphered = key.cypher(iterator)
+        iterator = AnyIterator { return nil } // clear
+        return cyphered
+    }
+}
+
+extension MaskingKey {
+    /*
+     Octet i of the transformed data ("transformed-octet-i") is the XOR of
+     octet i of the original data ("original-octet-i") with octet at index
+     i modulo 4 of the masking key ("masking-key-octet-j"):
+
+     j                   = i MOD 4
+     transformed-octet-i = original-octet-i XOR masking-key-octet-j
+     
+     
+     Cypher is same for masking and unmasking
+     */
+    func cypher<S: Sequence where S.Iterator.Element == Byte>(_ input: S) -> [Byte] {
+        switch self {
         case .none:
-            while let next = iterator.next() {
-                bytes.append(next)
-            }
+            return Array(input)
         case let .key(zero: zero, one: one, two: two, three: three):
-            /*
-             Octet i of the transformed data ("transformed-octet-i") is the XOR of
-             octet i of the original data ("original-octet-i") with octet at index
-             i modulo 4 of the masking key ("masking-key-octet-j"):
-
-             j                   = i MOD 4
-             transformed-octet-i = original-octet-i XOR masking-key-octet-j
-             */
-
-            // needs to be UInt64 because that's max payload length and we need the space
             var count = UInt64(0)
             let keys = [zero, one, two, three]
-            while let original = iterator.next() {
+            // don't use enumerated(). it returns `Int` which may lose precision
+            return input.map { original in
                 let key = keys[Int(count % 4)]
-                let transformed = original ^ key
-                bytes.append(transformed)
                 count += 1
+                return original ^ key
             }
-
-        }
-
-        return bytes
+        }
     }
 }
 

     |K|             |
     +-+-------------+
     */
    func serializeMaskAndLength() -> [Byte] {
        var bytes: [Byte] = []

        var leadingByte: Byte = 0
        if isMasked {
            leadingByte |= Byte.maskKeyIncluded
        }

        // 126 / 127 (max, max-1) indicate 2 & 8 byte extensions respectively
        if payloadLength < 126 {
            leadingByte |= UInt8(payloadLength)
            return [leadingByte]
        } else if payloadLength < UInt16.max.toUIntMax() {
            leadingByte |= 126 // 126 flags that 2 bytes are required
        } else {
            leadingByte |= 127 // 127 flags that 8 bytes are requred
        }

        return bytes
    }
}



extension WebSocketHeader {
    func serialize() -> [Byte] {
        let zero = serializeByteZero()
        let one = serializeByteZero()
        return []
    }

