Merge pull request #104 from zeriontech/chores

chores
This commit is contained in:
ivan grachev 2023-10-27 20:56:35 +03:00 committed by GitHub
commit 08a12f6f3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
475 changed files with 2955 additions and 49227 deletions

View File

@ -2,10 +2,10 @@ inhibit_all_warnings!
use_frameworks!
def shared_pods
pod 'Web3Swift.io', :git => 'https://github.com/grachyov/Web3Swift.git', :branch => 'develop'
pod 'BlockiesSwift'
pod 'Kingfisher'
pod 'TrustWalletCore'
pod 'BigInt'
end
target 'Tokenary' do

View File

@ -1,61 +1,36 @@
PODS:
- BigInt (5.2.0)
- BlockiesSwift (0.1.2)
- CryptoSwift (1.8.0)
- Kingfisher (7.9.1)
- secp256k1.swift (0.1.4)
- SwiftProtobuf (1.24.0)
- SwiftyJSON (4.3.0)
- TrustWalletCore (4.0.0):
- TrustWalletCore/Core (= 4.0.0)
- TrustWalletCore/Core (4.0.0):
- TrustWalletCore (4.0.1):
- TrustWalletCore/Core (= 4.0.1)
- TrustWalletCore/Core (4.0.1):
- TrustWalletCore/Types
- TrustWalletCore/Types (4.0.0):
- TrustWalletCore/Types (4.0.1):
- SwiftProtobuf
- Web3Swift.io (0.0.4):
- BigInt (~> 5.0)
- CryptoSwift (~> 1.0)
- secp256k1.swift (~> 0.1)
- SwiftyJSON (~> 4.3)
DEPENDENCIES:
- BigInt
- BlockiesSwift
- Kingfisher
- TrustWalletCore
- Web3Swift.io (from `https://github.com/grachyov/Web3Swift.git`, branch `develop`)
SPEC REPOS:
trunk:
- BigInt
- BlockiesSwift
- CryptoSwift
- Kingfisher
- secp256k1.swift
- SwiftProtobuf
- SwiftyJSON
- TrustWalletCore
EXTERNAL SOURCES:
Web3Swift.io:
:branch: develop
:git: https://github.com/grachyov/Web3Swift.git
CHECKOUT OPTIONS:
Web3Swift.io:
:commit: 951e6217f7899b5614b1530c3fbd2a46ee315b3c
:git: https://github.com/grachyov/Web3Swift.git
SPEC CHECKSUMS:
BigInt: f668a80089607f521586bbe29513d708491ef2f7
BlockiesSwift: 22d8d56dd187e6bfd16cb8c8fbd4fd4896c3e65d
CryptoSwift: 52aaf3fce7337552863b1d952e408085f0e65030
Kingfisher: 1d14e9f59cbe19389f591c929000332bf70efd32
secp256k1.swift: a7e7a214f6db6ce5db32cc6b2b45e5c4dd633634
SwiftProtobuf: bcfd2bc231cf9ae552cdc7c4e877bd3b41fe57b1
SwiftyJSON: 6faa0040f8b59dead0ee07436cbf76b73c08fd08
TrustWalletCore: b9b385357a858510454254d8d503f9fd4a7dc334
Web3Swift.io: 18fd06aed9d56df9c704f9c6f87b06675bb05b53
TrustWalletCore: 77c78bda1d1a411390321b7d9f7b81bd1d547b71
PODFILE CHECKSUM: 8e21bf453906c437bcd2b86369d4e0a459130c78
PODFILE CHECKSUM: 80600e3a469003bb39f77a8b610658742fa669da
COCOAPODS: 1.13.0

View File

@ -1,11 +0,0 @@
Copyright (C) 2014-3099 Marcin Krzyżanowski <marcin.krzyzanowski@gmail.com>
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
- The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
- Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
- This notice may not be removed or altered from any source or binary distribution.
- Redistributions of any form whatsoever must retain the following acknowledgment: 'This product includes software developed by the "Marcin Krzyzanowski" (http://krzyzanowskim.com/).'

View File

@ -1,681 +0,0 @@
[![Platform](https://img.shields.io/badge/Platforms-iOS%20%7C%20Android%20%7CmacOS%20%7C%20watchOS%20%7C%20tvOS%20%7C%20Linux-4E4E4E.svg?colorA=28a745)](#installation)
[![Swift support](https://img.shields.io/badge/Swift-3.1%20%7C%203.2%20%7C%204.0%20%7C%204.1%20%7C%204.2%20%7C%205.0-lightgrey.svg?colorA=28a745&colorB=4E4E4E)](#swift-versions-support)
[![Swift Package Manager compatible](https://img.shields.io/badge/SPM-compatible-brightgreen.svg?style=flat&colorA=28a745&&colorB=4E4E4E)](https://github.com/apple/swift-package-manager)
[![CocoaPods Compatible](https://img.shields.io/cocoapods/v/CryptoSwift.svg?style=flat&label=CocoaPods&colorA=28a745&&colorB=4E4E4E)](https://cocoapods.org/pods/CryptoSwift)
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-brightgreen.svg?style=flat&colorA=28a745&&colorB=4E4E4E)](https://github.com/Carthage/Carthage)
# CryptoSwift
Crypto related functions and helpers for [Swift](https://swift.org) implemented in Swift. ([#PureSwift](https://twitter.com/hashtag/pureswift))
**Note**: The `main` branch follows the latest currently released **version of Swift**. If you need an earlier version for an older version of Swift, specify its version in your `Podfile` or use the code on the branch for that version. Older branches are unsupported. Check [versions](#swift-versions-support) for details.
---
[Requirements](#requirements) | [Features](#features) | [Contribution](#contribution) | [Installation](#installation) | [Swift versions](#swift-versions-support) | [How-to](#how-to) | [Author](#author) | [License](#license) | [Changelog](#changelog)
### Support & Sponsors
The financial sustainability of the project is possible thanks to the ongoing contributions from our [GitHub Sponsors](https://github.com/sponsors/krzyzanowskim)
### Premium Sponsors
[Emerge Tools](https://www.emergetools.com/) is a suite of revolutionary products designed to supercharge mobile apps and the teams that build them.
[<img alt="www.emergetools.com/" width="200" src="https://github-production-user-asset-6210df.s3.amazonaws.com/758033/256565082-a21f5ac1-ef39-4b56-a8d2-575adeb7fe55.png" />](https://www.emergetools.com)
## Requirements
Good mood
## Features
- Easy to use
- Convenient extensions for String and Data
- Support for incremental updates (stream, ...)
- iOS, Android, macOS, AppleTV, watchOS, Linux support
#### Hash (Digest)
[MD5](https://tools.ietf.org/html/rfc1321)
| [SHA1](https://tools.ietf.org/html/rfc3174)
| [SHA2-224](https://tools.ietf.org/html/rfc6234)
| [SHA2-256](https://tools.ietf.org/html/rfc6234)
| [SHA2-384](https://tools.ietf.org/html/rfc6234)
| [SHA2-512](https://tools.ietf.org/html/rfc6234)
| [SHA3](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf)
#### Cyclic Redundancy Check (CRC)
[CRC32](https://en.wikipedia.org/wiki/Cyclic_redundancy_check)
| [CRC32C](https://en.wikipedia.org/wiki/Cyclic_redundancy_check)
| [CRC16](https://en.wikipedia.org/wiki/Cyclic_redundancy_check)
#### Cipher
[AES-128, AES-192, AES-256](http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf)
| [ChaCha20](http://cr.yp.to/chacha/chacha-20080128.pdf)
| [XChaCha20](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha)
| [Rabbit](https://tools.ietf.org/html/rfc4503)
| [Blowfish](https://www.schneier.com/academic/blowfish/)
#### RSA (public-key encryption algorithm)
[Encryption, Signature](https://github.com/krzyzanowskim/CryptoSwift#rsa)
#### Message authenticators
[Poly1305](https://cr.yp.to/mac/poly1305-20050329.pdf)
| [HMAC (MD5, SHA1, SHA256)](https://www.ietf.org/rfc/rfc2104.txt)
| [CMAC](https://tools.ietf.org/html/rfc4493)
| [CBC-MAC](https://en.wikipedia.org/wiki/CBC-MAC)
#### Cipher mode of operation
- Electronic codebook ([ECB](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_.28ECB.29))
- Cipher-block chaining ([CBC](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29))
- Propagating Cipher Block Chaining ([PCBC](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Propagating_Cipher_Block_Chaining_.28PCBC.29))
- Cipher feedback ([CFB](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_feedback_.28CFB.29))
- Output Feedback ([OFB](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Output_Feedback_.28OFB.29))
- Counter Mode ([CTR](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29))
- Galois/Counter Mode ([GCM](https://csrc.nist.gov/publications/detail/sp/800-38d/final))
- Counter with Cipher Block Chaining-Message Authentication Code ([CCM](https://csrc.nist.gov/publications/detail/sp/800-38c/final))
- OCB Authenticated-Encryption Algorithm ([OCB](https://tools.ietf.org/html/rfc7253))
#### Password-Based Key Derivation Function
- [PBKDF1](https://tools.ietf.org/html/rfc2898#section-5.1) (Password-Based Key Derivation Function 1)
- [PBKDF2](https://tools.ietf.org/html/rfc2898#section-5.2) (Password-Based Key Derivation Function 2)
- [HKDF](https://tools.ietf.org/html/rfc5869) (HMAC-based Extract-and-Expand Key Derivation Function)
- [Scrypt](https://tools.ietf.org/html/rfc7914) (The scrypt Password-Based Key Derivation Function)
#### Data padding
- [PKCS#5](https://www.rfc-editor.org/rfc/rfc2898.html)
- [EMSA-PKCS1-v1_5 (Encoding Method for Signature)](https://www.rfc-editor.org/rfc/rfc3447#section-9.2)
- [EME-PCKS1-v1_5 (Encoding Method for Encryption)](https://www.rfc-editor.org/rfc/rfc3447)
- [PKCS#7](https://tools.ietf.org/html/rfc5652#section-6.3)
- [Zero padding](https://en.wikipedia.org/wiki/Padding_(cryptography)#Zero_padding)
- [ISO78164](https://www.embedx.com/pdfs/ISO_STD_7816/info_isoiec7816-4%7Bed21.0%7Den.pdf)
- [ISO10126](https://en.wikipedia.org/wiki/Padding_(cryptography)#ISO_10126)
- No padding
#### Authenticated Encryption with Associated Data (AEAD)
- [AEAD\_CHACHA20\_POLY1305](https://tools.ietf.org/html/rfc7539#section-2.8)
- [AEAD\_XCHACHA20\_POLY1305](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha#section-2)
## Why
[Why?](https://github.com/krzyzanowskim/CryptoSwift/discussions/982) [Because I can](https://github.com/krzyzanowskim/CryptoSwift/discussions/982#discussioncomment-3669415).
## How do I get involved?
You want to help, great! Go ahead and fork our repo, make your changes and send us a pull request.
## Contribution
Check out [CONTRIBUTING.md](CONTRIBUTING.md) for more information on how to help with CryptoSwift.
- If you found a bug, [open a discussion](https://github.com/krzyzanowskim/CryptoSwift/discussions).
- If you have a feature request, [open a discussion](https://github.com/krzyzanowskim/CryptoSwift/discussions).
## Installation
### Hardened Runtime (macOS) and Xcode
Binary CryptoSwift.xcframework (Used by Swift Package Manager package integration) won't load properly in your app if the app uses **Sign to Run Locally** Signing Certificate with Hardened Runtime enabled. It is possible to setup Xcode like this. To solve the problem you have two options:
- Use proper Signing Certificate, eg. *Development* <- this is the proper action
- Use `Disable Library Validation` aka `com.apple.security.cs.disable-library-validation` entitlement
#### Xcode Project
To install CryptoSwift, add it as a submodule to your project (on the top level project directory):
git submodule add https://github.com/krzyzanowskim/CryptoSwift.git
It is recommended to enable [Whole-Module Optimization](https://swift.org/blog/whole-module-optimizations/) to gain better performance. Non-optimized build results in significantly worse performance.
#### Swift Package Manager
You can use [Swift Package Manager](https://swift.org/package-manager/) and specify dependency in `Package.swift` by adding this:
```swift
.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMajor(from: "1.8.0"))
```
See: [Package.swift - manual](https://blog.krzyzanowskim.com/2016/08/09/package-swift-manual/)
Notice: Swift Package Manager uses debug configuration for debug Xcode build, that may result in significant (up to x10000) worse performance. Performance characteristic is different in Release build. To overcome this problem, consider embed `CryptoSwift.xcframework` described below.
#### CocoaPods
You can use [CocoaPods](https://cocoapods.org/pods/CryptoSwift).
```ruby
pod 'CryptoSwift', '~> 1.8.0'
```
Bear in mind that CocoaPods will build CryptoSwift without [Whole-Module Optimization](https://swift.org/blog/whole-module-optimizations/) that may impact performance. You can change it manually after installation, or use [cocoapods-wholemodule](https://github.com/jedlewison/cocoapods-wholemodule) plugin.
#### Carthage
You can use [Carthage](https://github.com/Carthage/Carthage).
Specify in Cartfile:
```ruby
github "krzyzanowskim/CryptoSwift"
```
Run `carthage` to build the framework and drag the built CryptoSwift.framework into your Xcode project. Follow [build instructions](https://github.com/Carthage/Carthage#getting-started). [Common issues](https://github.com/krzyzanowskim/CryptoSwift/discussions/983#discussioncomment-3669433).
#### XCFramework
XCFrameworks require Xcode 11 or later and they can be integrated similarly to how were used to integrating the `.framework` format.
Please use script [scripts/build-framework.sh](scripts/build-framework.sh) to generate binary `CryptoSwift.xcframework` archive that you can use as a dependency in Xcode.
CryptoSwift.xcframework is a Release (Optimized) binary that offer best available Swift code performance.
<img width="320" alt="Screen Shot 2020-10-27 at 00 06 32" src="https://user-images.githubusercontent.com/758033/97240586-f0878280-17ee-11eb-9119-e5a960417d04.png">
#### Embedded Framework
Embedded frameworks require a minimum deployment target of iOS 11.0 or macOS Sierra (10.13). Drag the `CryptoSwift.xcodeproj` file into your Xcode project, and add appropriate framework as a dependency to your target. Now select your App and choose the General tab for the app target. Find *Embedded Binaries* and press "+", then select `CryptoSwift.framework` (iOS, macOS, watchOS or tvOS)
![](https://cloud.githubusercontent.com/assets/758033/10834511/25a26852-7e9a-11e5-8c01-6cc8f1838459.png)
Sometimes "embedded framework" option is not available. In that case, you have to add new build phase for the target.
![](https://cloud.githubusercontent.com/assets/758033/18415615/d5edabb0-77f8-11e6-8c94-f41d9fc2b8cb.png)
##### iOS, macOS, watchOS, tvOS
In the project, you'll find [single scheme](https://mxcl.dev/PromiseKit/news/2016/08/Multiplatform-Single-Scheme-Xcode-Projects/) for all platforms:
- CryptoSwift
#### Swift versions support
- Swift 1.2: branch [swift12](https://github.com/krzyzanowskim/CryptoSwift/tree/swift12) version <= 0.0.13
- Swift 2.1: branch [swift21](https://github.com/krzyzanowskim/CryptoSwift/tree/swift21) version <= 0.2.3
- Swift 2.2, 2.3: branch [swift2](https://github.com/krzyzanowskim/CryptoSwift/tree/swift2) version <= 0.5.2
- Swift 3.1, branch [swift3](https://github.com/krzyzanowskim/CryptoSwift/tree/swift3) version <= 0.6.9
- Swift 3.2, branch [swift32](https://github.com/krzyzanowskim/CryptoSwift/tree/swift32) version = 0.7.0
- Swift 4.0, branch [swift4](https://github.com/krzyzanowskim/CryptoSwift/tree/swift4) version <= 0.12.0
- Swift 4.2, branch [swift42](https://github.com/krzyzanowskim/CryptoSwift/tree/swift42) version <= 0.15.0
- Swift 5.0, branch [swift5](https://github.com/krzyzanowskim/CryptoSwift/tree/swift5) version <= 1.2.0
- Swift 5.1, branch [swift5](https://github.com/krzyzanowskim/CryptoSwift/tree/swift51) version <= 1.3.3
- Swift 5.3 and newer, branch [main](https://github.com/krzyzanowskim/CryptoSwift/tree/main)
## How-to
* [Basics (data types, conversion, ...)](#basics)
* [Digest (MD5, SHA...)](#calculate-digest)
* [Message authenticators (HMAC, CMAC...)](#message-authenticators-1)
* [Password-Based Key Derivation Function (PBKDF2, ...)](#password-based-key-derivation-functions)
* [HMAC-based Key Derivation Function (HKDF)](#hmac-based-key-derivation-function)
* [Data Padding](#data-padding)
* [ChaCha20](#chacha20)
* [Rabbit](#rabbit)
* [Blowfish](#blowfish)
* [AES - Advanced Encryption Standard](#aes)
* [AES-GCM](#aes-gcm)
* [Authenticated Encryption with Associated Data (AEAD)](#aead)
##### Basics
```swift
import CryptoSwift
```
CryptoSwift uses array of bytes aka `Array<UInt8>` as a base type for all operations. Every data may be converted to a stream of bytes. You will find convenience functions that accept `String` or `Data`, and it will be internally converted to the array of bytes.
##### Data types conversion
For your convenience, **CryptoSwift** provides two functions to easily convert an array of bytes to `Data` or `Data` to an array of bytes:
Data from bytes:
```swift
let data = Data([0x01, 0x02, 0x03])
```
`Data` to `Array<UInt8>`
```swift
let bytes = data.bytes // [1,2,3]
```
[Hexadecimal](https://en.wikipedia.org/wiki/Hexadecimal) encoding:
```swift
let bytes = Array<UInt8>(hex: "0x010203") // [1,2,3]
let hex = bytes.toHexString() // "010203"
```
Build bytes out of `String`
```swift
let bytes: Array<UInt8> = "cipherkey".bytes // Array("cipherkey".utf8)
```
Also... check out helpers that work with **Base64** encoded data:
```swift
"aPf/i9th9iX+vf49eR7PYk2q7S5xmm3jkRLejgzHNJs=".decryptBase64ToString(cipher)
"aPf/i9th9iX+vf49eR7PYk2q7S5xmm3jkRLejgzHNJs=".decryptBase64(cipher)
bytes.toBase64()
```
##### Calculate Digest
Hashing a data or array of bytes (aka `Array<UInt8>`)
```swift
/* Hash struct usage */
let bytes: Array<UInt8> = [0x01, 0x02, 0x03]
let digest = input.md5()
let digest = Digest.md5(bytes)
```
```swift
let data = Data([0x01, 0x02, 0x03])
let hash = data.md5()
let hash = data.sha1()
let hash = data.sha224()
let hash = data.sha256()
let hash = data.sha384()
let hash = data.sha512()
```
```swift
do {
var digest = MD5()
let partial1 = try digest.update(withBytes: [0x31, 0x32])
let partial2 = try digest.update(withBytes: [0x33])
let result = try digest.finish()
} catch { }
```
Hashing a String and printing result
```swift
let hash = "123".md5() // "123".bytes.md5()
```
##### Calculate CRC
```swift
bytes.crc16()
data.crc16()
bytes.crc32()
data.crc32()
```
##### Message authenticators
```swift
// Calculate Message Authentication Code (MAC) for message
let key: Array<UInt8> = [1,2,3,4,5,6,7,8,9,10,...]
try Poly1305(key: key).authenticate(bytes)
try HMAC(key: key, variant: .sha256).authenticate(bytes)
try CMAC(key: key).authenticate(bytes)
```
##### Password-Based Key Derivation Functions
```swift
let password: Array<UInt8> = Array("s33krit".utf8)
let salt: Array<UInt8> = Array("nacllcan".utf8)
let key = try PKCS5.PBKDF2(password: password, salt: salt, iterations: 4096, keyLength: 32, variant: .sha256).calculate()
```
```swift
let password: Array<UInt8> = Array("s33krit".utf8)
let salt: Array<UInt8> = Array("nacllcan".utf8)
// Scrypt implementation does not implement work parallelization, so `p` parameter will
// increase the work time even in multicore systems
let key = try Scrypt(password: password, salt: salt, dkLen: 64, N: 16384, r: 8, p: 1).calculate()
```
##### HMAC-based Key Derivation Function
```swift
let password: Array<UInt8> = Array("s33krit".utf8)
let salt: Array<UInt8> = Array("nacllcan".utf8)
let key = try HKDF(password: password, salt: salt, variant: .sha256).calculate()
```
##### Data Padding
Some content-encryption algorithms assume the input length is a multiple of `k` octets, where `k` is greater than one. For such algorithms, the input shall be padded.
```swift
Padding.pkcs7.add(to: bytes, blockSize: AES.blockSize)
```
#### Working with Ciphers
##### ChaCha20
```swift
let encrypted = try ChaCha20(key: key, iv: iv).encrypt(message)
let decrypted = try ChaCha20(key: key, iv: iv).decrypt(encrypted)
```
##### Rabbit
```swift
let encrypted = try Rabbit(key: key, iv: iv).encrypt(message)
let decrypted = try Rabbit(key: key, iv: iv).decrypt(encrypted)
```
##### Blowfish
```swift
let encrypted = try Blowfish(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).encrypt(message)
let decrypted = try Blowfish(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).decrypt(encrypted)
```
##### AES
Notice regarding padding: *Manual padding of data is optional, and CryptoSwift is using PKCS7 padding by default. If you need to manually disable/enable padding, you can do this by setting parameter for __AES__ class*
Variant of AES encryption (AES-128, AES-192, AES-256) depends on given key length:
- AES-128 = 16 bytes
- AES-192 = 24 bytes
- AES-256 = 32 bytes
AES-256 example
```swift
let encryptedBytes = try AES(key: [1,2,3,...,32], blockMode: CBC(iv: [1,2,3,...,16]), padding: .pkcs7)
```
Full example:
```swift
let password: [UInt8] = Array("s33krit".utf8)
let salt: [UInt8] = Array("nacllcan".utf8)
/* Generate a key from a `password`. Optional if you already have a key */
let key = try PKCS5.PBKDF2(
password: password,
salt: salt,
iterations: 4096,
keyLength: 32, /* AES-256 */
variant: .sha256
).calculate()
/* Generate random IV value. IV is public value. Either need to generate, or get it from elsewhere */
let iv = AES.randomIV(AES.blockSize)
/* AES cryptor instance */
let aes = try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7)
/* Encrypt Data */
let inputData = Data()
let encryptedBytes = try aes.encrypt(inputData.bytes)
let encryptedData = Data(encryptedBytes)
/* Decrypt Data */
let decryptedBytes = try aes.decrypt(encryptedData.bytes)
let decryptedData = Data(decryptedBytes)
```
###### All at once
```swift
do {
let aes = try AES(key: "keykeykeykeykeyk", iv: "drowssapdrowssap") // aes128
let ciphertext = try aes.encrypt(Array("Nullam quis risus eget urna mollis ornare vel eu leo.".utf8))
} catch { }
```
###### Incremental updates
Incremental operations use instance of Cryptor and encrypt/decrypt one part at a time, this way you can save on memory for large files.
```swift
do {
var encryptor = try AES(key: "keykeykeykeykeyk", iv: "drowssapdrowssap").makeEncryptor()
var ciphertext = Array<UInt8>()
// aggregate partial results
ciphertext += try encryptor.update(withBytes: Array("Nullam quis risus ".utf8))
ciphertext += try encryptor.update(withBytes: Array("eget urna mollis ".utf8))
ciphertext += try encryptor.update(withBytes: Array("ornare vel eu leo.".utf8))
// finish at the end
ciphertext += try encryptor.finish()
print(ciphertext.toHexString())
} catch {
print(error)
}
```
###### AES Advanced usage
```swift
let input: Array<UInt8> = [0,1,2,3,4,5,6,7,8,9]
let key: Array<UInt8> = [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
let iv: Array<UInt8> = // Random bytes of `AES.blockSize` length
do {
let encrypted = try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).encrypt(input)
let decrypted = try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).decrypt(encrypted)
} catch {
print(error)
}
```
AES without data padding
```swift
let input: Array<UInt8> = [0,1,2,3,4,5,6,7,8,9]
let encrypted: Array<UInt8> = try! AES(key: Array("secret0key000000".utf8), blockMode: CBC(iv: Array("0123456789012345".utf8)), padding: .noPadding).encrypt(input)
```
Using convenience extensions
```swift
let plain = Data([0x01, 0x02, 0x03])
let encrypted = try! plain.encrypt(ChaCha20(key: key, iv: iv))
let decrypted = try! encrypted.decrypt(ChaCha20(key: key, iv: iv))
```
##### AES-GCM
The result of Galois/Counter Mode (GCM) encryption is ciphertext and **authentication tag**, that is later used to decryption.
encryption
```swift
do {
// In combined mode, the authentication tag is directly appended to the encrypted message. This is usually what you want.
let gcm = GCM(iv: iv, mode: .combined)
let aes = try AES(key: key, blockMode: gcm, padding: .noPadding)
let encrypted = try aes.encrypt(plaintext)
let tag = gcm.authenticationTag
} catch {
// failed
}
```
decryption
```swift
do {
// In combined mode, the authentication tag is appended to the encrypted message. This is usually what you want.
let gcm = GCM(iv: iv, mode: .combined)
let aes = try AES(key: key, blockMode: gcm, padding: .noPadding)
return try aes.decrypt(encrypted)
} catch {
// failed
}
```
**Note**: GCM instance is not intended to be reused. So you can't use the same `GCM` instance from encoding to also perform decoding.
##### AES-CCM
The result of Counter with Cipher Block Chaining-Message Authentication Code encryption is ciphertext and **authentication tag**, that is later used to decryption.
```swift
do {
// The authentication tag is appended to the encrypted message.
let tagLength = 8
let ccm = CCM(iv: iv, tagLength: tagLength, messageLength: ciphertext.count - tagLength, additionalAuthenticatedData: data)
let aes = try AES(key: key, blockMode: ccm, padding: .noPadding)
return try aes.decrypt(encrypted)
} catch {
// failed
}
```
Check documentation or CCM specification for valid parameters for CCM.
##### AEAD
```swift
let encrypt = try AEADChaCha20Poly1305.encrypt(plaintext, key: key, iv: nonce, authenticationHeader: header)
let decrypt = try AEADChaCha20Poly1305.decrypt(ciphertext, key: key, iv: nonce, authenticationHeader: header, authenticationTag: tagArr: tag)
```
##### RSA
RSA initialization from parameters
```swift
let input: Array<UInt8> = [0,1,2,3,4,5,6,7,8,9]
let n: Array<UInt8> = // RSA modulus
let e: Array<UInt8> = // RSA public exponent
let d: Array<UInt8> = // RSA private exponent
let rsa = RSA(n: n, e: e, d: d)
do {
let encrypted = try rsa.encrypt(input)
let decrypted = try rsa.decrypt(encrypted)
} catch {
print(error)
}
```
RSA key generation
```swift
let rsa = try RSA(keySize: 2048) // This generates a modulus, public exponent and private exponent with the given size
```
RSA Encryption & Decryption Example
``` swift
// Alice Generates a Private Key
let alicesPrivateKey = try RSA(keySize: 1024)
// Alice shares her **public** key with Bob
let alicesPublicKeyData = try alicesPrivateKey.publicKeyExternalRepresentation()
// Bob receives the raw external representation of Alices public key and imports it
let bobsImportOfAlicesPublicKey = try RSA(rawRepresentation: alicesPublicKeyData)
// Bob can now encrypt a message for Alice using her public key
let message = "Hi Alice! This is Bob!"
let privateMessage = try bobsImportOfAlicesPublicKey.encrypt(message.bytes)
// This results in some encrypted output like this
// URcRwG6LfH63zOQf2w+HIllPri9Rb6hFlXbi/bh03zPl2MIIiSTjbAPqbVFmoF3RmDzFjIarIS7ZpT57a1F+OFOJjx50WYlng7dioKFS/rsuGHYnMn4csjCRF6TAqvRQcRnBueeINRRA8SLaLHX6sZuQkjIE5AoHJwgavmiv8PY=
// Bob can now send this encrypted message to Alice without worrying about people being able to read the original contents
// Alice receives the encrypted message and uses her private key to decrypt the data and recover the original message
let originalDecryptedMessage = try alicesPrivateKey.decrypt(privateMessage)
print(String(data: Data(originalDecryptedMessage), encoding: .utf8))
// "Hi Alice! This is Bob!"
```
RSA Signature & Verification Example
``` swift
// Alice Generates a Private Key
let alicesPrivateKey = try RSA(keySize: 1024)
// Alice wants to sign a message that she agrees with
let messageAliceSupports = "Hi my name is Alice!"
let alicesSignature = try alicesPrivateKey.sign(messageAliceSupports.bytes)
// Alice shares her Public key and the signature with Bob
let alicesPublicKeyData = try alicesPrivateKey.publicKeyExternalRepresentation()
// Bob receives the raw external representation of Alices Public key and imports it!
let bobsImportOfAlicesPublicKey = try RSA(rawRepresentation: alicesPublicKeyData)
// Bob can now verify that Alice signed the message using the Private key associated with her shared Public key.
let verifiedSignature = try bobsImportOfAlicesPublicKey.verify(signature: alicesSignature, for: "Hi my name is Alice!".bytes)
if verifiedSignature == true {
// Bob knows that the signature Alice provided is valid for the message and was signed using the Private key associated with Alices shared Public key.
} else {
// The signature was invalid, so either
// - the message Alice signed was different then what we expected.
// - or Alice used a Private key that isn't associated with the shared Public key that Bob has.
}
```
CryptoSwift RSA Key -> Apple's Security Framework SecKey Example
``` swift
/// Starting with a CryptoSwift RSA Key
let rsaKey = try RSA(keySize: 1024)
/// Define your Keys attributes
let attributes: [String:Any] = [
kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
kSecAttrKeyClass as String: kSecAttrKeyClassPrivate, // or kSecAttrKeyClassPublic
kSecAttrKeySizeInBits as String: 1024, // The appropriate bits
kSecAttrIsPermanent as String: false
]
var error:Unmanaged<CFError>? = nil
guard let rsaSecKey = try SecKeyCreateWithData(rsaKey.externalRepresentation() as CFData, attributes as CFDictionary, &error) else {
/// Error constructing SecKey from raw key data
return
}
/// You now have an RSA SecKey for use with Apple's Security framework
```
Apple's Security Framework SecKey -> CryptoSwift RSA Key Example
``` swift
/// Starting with a SecKey RSA Key
let rsaSecKey:SecKey
/// Copy External Representation
var externalRepError:Unmanaged<CFError>?
guard let cfdata = SecKeyCopyExternalRepresentation(rsaSecKey, &externalRepError) else {
/// Failed to copy external representation for RSA SecKey
return
}
/// Instantiate the RSA Key from the raw external representation
let rsaKey = try RSA(rawRepresentation: cfdata as Data)
/// You now have a CryptoSwift RSA Key
```
## Author
CryptoSwift is owned and maintained by [Marcin Krzyżanowski](https://www.krzyzanowskim.com)
You can follow me on Twitter at [@krzyzanowskim](https://twitter.com/krzyzanowskim) for project updates and releases.
# Cryptography Notice
This distribution includes cryptographic software. The country in which you currently reside may have restrictions on the import, possession, use, and/or re-export to another country, of encryption software. BEFORE using any encryption software, please check your country's laws, regulations and policies concerning the import, possession, or use, and re-export of encryption software, to see if this is permitted. See https://www.wassenaar.org/ for more information.
## License
Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
- The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, **an acknowledgment in the product documentation is required**.
- Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
- This notice may not be removed or altered from any source or binary distribution.
- Redistributions of any form whatsoever must retain the following acknowledgment: 'This product includes software developed by the "Marcin Krzyzanowski" (https://krzyzanowskim.com/).'
## Changelog
See [CHANGELOG](./CHANGELOG) file.

View File

@ -1,40 +0,0 @@
//
// AEAD.swift
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
//
// https://www.iana.org/assignments/aead-parameters/aead-parameters.xhtml
/// Authenticated Encryption with Associated Data (AEAD)
public protocol AEAD {
static var kLen: Int { get } // key length
static var ivRange: Range<Int> { get } // nonce length
}
extension AEAD {
static func calculateAuthenticationTag(authenticator: Authenticator, cipherText: Array<UInt8>, authenticationHeader: Array<UInt8>) throws -> Array<UInt8> {
let headerPadding = ((16 - (authenticationHeader.count & 0xf)) & 0xf)
let cipherPadding = ((16 - (cipherText.count & 0xf)) & 0xf)
var mac = authenticationHeader
mac += Array<UInt8>(repeating: 0, count: headerPadding)
mac += cipherText
mac += Array<UInt8>(repeating: 0, count: cipherPadding)
mac += UInt64(bigEndian: UInt64(authenticationHeader.count)).bytes()
mac += UInt64(bigEndian: UInt64(cipherText.count)).bytes()
return try authenticator.authenticate(mac)
}
}

View File

@ -1,66 +0,0 @@
//
// AEADChaCha20Poly1305.swift
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
//
// https://tools.ietf.org/html/rfc7539#section-2.8.1
/// AEAD_CHACHA20_POLY1305
public final class AEADChaCha20Poly1305: AEAD {
public static let kLen = 32 // key length
public static var ivRange = Range<Int>(12...12)
/// Authenticated encryption
public static func encrypt(_ plainText: Array<UInt8>, key: Array<UInt8>, iv: Array<UInt8>, authenticationHeader: Array<UInt8>) throws -> (cipherText: Array<UInt8>, authenticationTag: Array<UInt8>) {
let cipher = try ChaCha20(key: key, iv: iv)
return try self.encrypt(cipher: cipher, plainText, key: key, iv: iv, authenticationHeader: authenticationHeader)
}
public static func encrypt(cipher: Cipher, _ plainText: Array<UInt8>, key: Array<UInt8>, iv: Array<UInt8>, authenticationHeader: Array<UInt8>) throws -> (cipherText: Array<UInt8>, authenticationTag: Array<UInt8>) {
var polykey = Array<UInt8>(repeating: 0, count: kLen)
var toEncrypt = polykey
polykey = try cipher.encrypt(polykey)
toEncrypt += polykey
toEncrypt += plainText
let fullCipherText = try cipher.encrypt(toEncrypt)
let cipherText = Array(fullCipherText.dropFirst(64))
let tag = try calculateAuthenticationTag(authenticator: Poly1305(key: polykey), cipherText: cipherText, authenticationHeader: authenticationHeader)
return (cipherText, tag)
}
/// Authenticated decryption
public static func decrypt(_ cipherText: Array<UInt8>, key: Array<UInt8>, iv: Array<UInt8>, authenticationHeader: Array<UInt8>, authenticationTag: Array<UInt8>) throws -> (plainText: Array<UInt8>, success: Bool) {
let cipher = try ChaCha20(key: key, iv: iv)
return try self.decrypt(cipher: cipher, cipherText: cipherText, key: key, iv: iv, authenticationHeader: authenticationHeader, authenticationTag: authenticationTag)
}
static func decrypt(cipher: Cipher, cipherText: Array<UInt8>, key: Array<UInt8>, iv: Array<UInt8>, authenticationHeader: Array<UInt8>, authenticationTag: Array<UInt8>) throws -> (plainText: Array<UInt8>, success: Bool) {
let polykey = try cipher.encrypt(Array<UInt8>(repeating: 0, count: self.kLen))
let mac = try calculateAuthenticationTag(authenticator: Poly1305(key: polykey), cipherText: cipherText, authenticationHeader: authenticationHeader)
guard mac == authenticationTag else {
return (cipherText, false)
}
var toDecrypt = Array<UInt8>(reserveCapacity: cipherText.count + 64)
toDecrypt += polykey
toDecrypt += polykey
toDecrypt += cipherText
let fullPlainText = try cipher.decrypt(toDecrypt)
let plainText = Array(fullPlainText.dropFirst(64))
return (plainText, true)
}
}

View File

@ -1,83 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
import Foundation
/// This class implements the XChaCha20-Poly1305 Authenticated Encryption with
/// Associated Data (AEAD_XCHACHA20_POLY1305) construction, providing both encryption and authentication.
///
/// For more information about the XChaCha20-Poly1305 algorithm, refer to the IETF draft: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha
public final class AEADXChaCha20Poly1305: AEAD {
/// The key length (in bytes) required for the XChaCha20 cipher (32 bytes).
public static let kLen = 32 // key length
/// The valid range of initialization vector lengths for the XChaCha20 cipher (12 bytes).
public static var ivRange = Range<Int>(12...12)
/// Encrypts the given plaintext using the XChaCha20 cipher and generates an authentication
/// tag using the Poly1305 MAC.
///
/// - Parameters:
/// - plainText: The plaintext to be encrypted.
/// - key: The encryption key.
/// - iv: The initialization vector.
/// - authenticationHeader: The authentication header.
/// - Returns: A tuple containing the ciphertext and authentication tag.
/// - Throws: An error if encryption fails.
public static func encrypt(
_ plainText: Array<UInt8>,
key: Array<UInt8>,
iv: Array<UInt8>,
authenticationHeader: Array<UInt8>
) throws -> (cipherText: Array<UInt8>, authenticationTag: Array<UInt8>) {
try AEADChaCha20Poly1305.encrypt(
cipher: XChaCha20(key: key, iv: iv),
plainText,
key: key,
iv: iv,
authenticationHeader: authenticationHeader
)
}
/// Decrypts the given ciphertext using the XChaCha20 cipher and verifies the authentication
/// tag using the Poly1305 MAC.
///
/// - Parameters:
/// - cipherText: The ciphertext to be decrypted.
/// - key: The decryption key.
/// - iv: The initialization vector.
/// - authenticationHeader: The authentication header.
/// - authenticationTag: The authentication tag.
/// - Returns: A tuple containing the decrypted plaintext and a boolean value indicating
/// the success of the decryption and authentication process.
/// - Throws: An error if decryption fails.
public static func decrypt(
_ cipherText: Array<UInt8>,
key: Array<UInt8>,
iv: Array<UInt8>,
authenticationHeader: Array<UInt8>,
authenticationTag: Array<UInt8>
) throws -> (plainText: Array<UInt8>, success: Bool) {
try AEADChaCha20Poly1305.decrypt(
cipher: XChaCha20(key: key, iv: iv),
cipherText: cipherText,
key: key,
iv: iv,
authenticationHeader: authenticationHeader,
authenticationTag: authenticationTag
)
}
}

View File

@ -1,39 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
// MARK: Cryptors
extension AES: Cryptors {
@inlinable
public func makeEncryptor() throws -> Cryptor & Updatable {
let blockSize = blockMode.customBlockSize ?? AES.blockSize
let worker = try blockMode.worker(blockSize: blockSize, cipherOperation: encrypt, encryptionOperation: encrypt)
if worker is StreamModeWorker {
return try StreamEncryptor(blockSize: blockSize, padding: padding, worker)
}
return try BlockEncryptor(blockSize: blockSize, padding: padding, worker)
}
@inlinable
public func makeDecryptor() throws -> Cryptor & Updatable {
let blockSize = blockMode.customBlockSize ?? AES.blockSize
let cipherOperation: CipherOperationOnBlock = blockMode.options.contains(.useEncryptToDecrypt) == true ? encrypt : decrypt
let worker = try blockMode.worker(blockSize: blockSize, cipherOperation: cipherOperation, encryptionOperation: encrypt)
if worker is StreamModeWorker {
return try StreamDecryptor(blockSize: blockSize, padding: padding, worker)
}
return try BlockDecryptor(blockSize: blockSize, padding: padding, worker)
}
}

View File

@ -1,556 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
// Implementation of Gladman algorithm http://www.gladman.me.uk/AES
//
/// The Advanced Encryption Standard (AES)
public final class AES: BlockCipher {
public enum Error: Swift.Error {
/// Invalid key
case invalidKeySize
/// Data padding is required
case dataPaddingRequired
/// Invalid Data
case invalidData
}
public enum Variant: Int {
case aes128 = 1, aes192, aes256
var Nk: Int { // Nk words
[4, 6, 8][self.rawValue - 1]
}
var Nb: Int { // Nb words
4
}
var Nr: Int { // Nr
self.Nk + 6
}
}
@usableFromInline
internal let variantNr: Int
@usableFromInline
internal let variantNb: Int
@usableFromInline
internal let variantNk: Int
public static let blockSize: Int = 16 // 128 /8
public let keySize: Int
/// AES Variant
public let variant: Variant
// Parameters
let key: Key
@usableFromInline
let blockMode: BlockMode
@usableFromInline
let padding: Padding
//
@usableFromInline
internal lazy var expandedKey: Array<Array<UInt32>> = self.expandKey(self.key, variant: self.variant)
@usableFromInline
internal lazy var expandedKeyInv: Array<Array<UInt32>> = self.expandKeyInv(self.key, variant: self.variant)
private lazy var sBoxes: (sBox: Array<UInt32>, invSBox: Array<UInt32>) = self.calculateSBox()
private lazy var sBox: Array<UInt32> = self.sBoxes.sBox
private lazy var sBoxInv: Array<UInt32> = self.sBoxes.invSBox
// Parameters for Linear Congruence Generators
private static let Rcon: Array<UInt8> = [
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39,
0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef,
0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b,
0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,
0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,
0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,
0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63,
0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d
]
@usableFromInline static let T0: Array<UInt32> = [0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0xdf2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x3010102, 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, 0x15fafaef, 0xeb5959b2, 0xc947478e, 0xbf0f0fb, 0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x2f7f7f5, 0x4fcccc83, 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x8f1f1f9, 0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a, 0xc040408, 0x52c7c795, 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0xf05050a, 0xb59a9a2f, 0x907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, 0xf55353a6, 0x68d1d1b9, 0x0, 0x2cededc1, 0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85, 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a, 0x10f9f9e9, 0x6020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x4f5f5f1, 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020, 0x1affffe5, 0xef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992, 0xa06060c, 0x6c242448, 0xe45c5cb8, 0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8, 0xfa5656ac, 0x7f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x5030306, 0x1f6f6f7, 0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c]
@usableFromInline static let T0_INV: Array<UInt32> = [0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b, 0xf1459d1f, 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad, 0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 0x8fa362b5, 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d, 0x2752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, 0xe75f8f03, 0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458, 0x2969e049, 0x44c8c98e, 0x6a89c275, 0x78798ef4, 0x6b3e5899, 0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d, 0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 0xe07764b1, 0x84ae6bbb, 0x1ca081fe, 0x942b08f9, 0x58684870, 0x19fd458f, 0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3, 0x2aab5566, 0x728ebb2, 0x3c2b52f, 0x9a7bc586, 0xa50837d3, 0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a, 0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506, 0x1f6234d1, 0x8afea6c4, 0x9d532e34, 0xa055f3a2, 0x32e18a05, 0x75ebf6a4, 0x39ec830b, 0xaaef6040, 0x69f715e, 0x51106ebd, 0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491, 0x55dc471, 0x6fd40604, 0xff155060, 0x24fb9819, 0x97e9bdd6, 0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7, 0xdbeec879, 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x0, 0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, 0xfbff0efd, 0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68, 0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0xfe75793, 0xd296eeb4, 0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c, 0xaba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0xb0d090e, 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af, 0xbbdd99ee, 0xfd607fa3, 0x9f2601f7, 0xbcf5725c, 0xc53b6644, 0x347efb5b, 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8, 0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, 0x7d244a85, 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc, 0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411, 0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322, 0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6, 0x28de7aa5, 0x268eb7da, 0xa4bfad3f, 0xe49d3a2c, 0xd927850, 0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e, 0xf5afc382, 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf, 0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x97826cd, 0xf418596e, 0x1b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa, 0x8cfbc21, 0xe6e815ef, 0xd99be7ba, 0xce366f4a, 0xd4099fea, 0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235, 0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 0x4a9804f1, 0xf7daec41, 0xe50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43, 0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 0x7f516546, 0x4ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb, 0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, 0x8c61d79a, 0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7, 0xede51ce1, 0x3cb1477a, 0x59dfd29c, 0x3f73f255, 0x79ce1418, 0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478, 0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16, 0xc25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08, 0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48, 0x4257b8d0]
@usableFromInline static let T1: Array<UInt32> = [0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, 0xf2f2ff0d, 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, 0x30306050, 0x1010203, 0x6767cea9, 0x2b2b567d, 0xfefee719, 0xd7d7b562, 0xabab4de6, 0x7676ec9a, 0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87, 0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b, 0xadad41ec, 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, 0x9c9c23bf, 0xa4a453f7, 0x7272e496, 0xc0c09b5b, 0xb7b775c2, 0xfdfde11c, 0x93933dae, 0x26264c6a, 0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f, 0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908, 0x7171e293, 0xd8d8ab73, 0x31316253, 0x15152a3f, 0x404080c, 0xc7c79552, 0x23234665, 0xc3c39d5e, 0x18183028, 0x969637a1, 0x5050a0f, 0x9a9a2fb5, 0x7070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d, 0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, 0x909121b, 0x83831d9e, 0x2c2c5874, 0x1a1a342e, 0x1b1b362d, 0x6e6edcb2, 0x5a5ab4ee, 0xa0a05bfb, 0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 0xb3b37dce, 0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397, 0x5353a6f5, 0xd1d1b968, 0x0, 0xededc12c, 0x20204060, 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed, 0x6a6ad4be, 0xcbcb8d46, 0xbebe67d9, 0x3939724b, 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 0xcfcf854a, 0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16, 0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, 0x45458acf, 0xf9f9e910, 0x2020406, 0x7f7ffe81, 0x5050a0f0, 0x3c3c7844, 0x9f9f25ba, 0xa8a84be3, 0x5151a2f3, 0xa3a35dfe, 0x404080c0, 0x8f8f058a, 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104, 0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, 0x10102030, 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, 0xcdcd814c, 0xc0c1814, 0x13132635, 0xececc32f, 0x5f5fbee1, 0x979735a2, 0x444488cc, 0x17172e39, 0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47, 0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695, 0x6060c0a0, 0x81811998, 0x4f4f9ed1, 0xdcdca37f, 0x22224466, 0x2a2a547e, 0x90903bab, 0x88880b83, 0x46468cca, 0xeeeec729, 0xb8b86bd3, 0x1414283c, 0xdedea779, 0x5e5ebce2, 0xb0b161d, 0xdbdbad76, 0xe0e0db3b, 0x32326456, 0x3a3a744e, 0xa0a141e, 0x494992db, 0x6060c0a, 0x2424486c, 0x5c5cb8e4, 0xc2c29f5d, 0xd3d3bd6e, 0xacac43ef, 0x6262c4a6, 0x919139a8, 0x959531a4, 0xe4e4d337, 0x7979f28b, 0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7, 0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, 0x6c6cd8b4, 0x5656acfa, 0xf4f4f307, 0xeaeacf25, 0x6565caaf, 0x7a7af48e, 0xaeae47e9, 0x8081018, 0xbaba6fd5, 0x7878f088, 0x25254a6f, 0x2e2e5c72, 0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751, 0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, 0x4b4b96dd, 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, 0x7070e090, 0x3e3e7c42, 0xb5b571c4, 0x6666ccaa, 0x484890d8, 0x3030605, 0xf6f6f701, 0xe0e1c12, 0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0, 0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9, 0xe1e1d938, 0xf8f8eb13, 0x98982bb3, 0x11112233, 0x6969d2bb, 0xd9d9a970, 0x8e8e0789, 0x949433a7, 0x9b9b2db6, 0x1e1e3c22, 0x87871592, 0xe9e9c920, 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a, 0x8c8c038f, 0xa1a159f8, 0x89890980, 0xd0d1a17, 0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8, 0x414182c3, 0x999929b0, 0x2d2d5a77, 0xf0f1e11, 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a]
@usableFromInline static let T1_INV: Array<UInt32> = [0xa7f45150, 0x65417e53, 0xa4171ac3, 0x5e273a96, 0x6bab3bcb, 0x459d1ff1, 0x58faacab, 0x3e34b93, 0xfa302055, 0x6d76adf6, 0x76cc8891, 0x4c02f525, 0xd7e54ffc, 0xcb2ac5d7, 0x44352680, 0xa362b58f, 0x5ab1de49, 0x1bba2567, 0xeea4598, 0xc0fe5de1, 0x752fc302, 0xf04c8112, 0x97468da3, 0xf9d36bc6, 0x5f8f03e7, 0x9c921595, 0x7a6dbfeb, 0x595295da, 0x83bed42d, 0x217458d3, 0x69e04929, 0xc8c98e44, 0x89c2756a, 0x798ef478, 0x3e58996b, 0x71b927dd, 0x4fe1beb6, 0xad88f017, 0xac20c966, 0x3ace7db4, 0x4adf6318, 0x311ae582, 0x33519760, 0x7f536245, 0x7764b1e0, 0xae6bbb84, 0xa081fe1c, 0x2b08f994, 0x68487058, 0xfd458f19, 0x6cde9487, 0xf87b52b7, 0xd373ab23, 0x24b72e2, 0x8f1fe357, 0xab55662a, 0x28ebb207, 0xc2b52f03, 0x7bc5869a, 0x837d3a5, 0x872830f2, 0xa5bf23b2, 0x6a0302ba, 0x8216ed5c, 0x1ccf8a2b, 0xb479a792, 0xf207f3f0, 0xe2694ea1, 0xf4da65cd, 0xbe0506d5, 0x6234d11f, 0xfea6c48a, 0x532e349d, 0x55f3a2a0, 0xe18a0532, 0xebf6a475, 0xec830b39, 0xef6040aa, 0x9f715e06, 0x106ebd51, 0x8a213ef9, 0x6dd963d, 0x53eddae, 0xbde64d46, 0x8d5491b5, 0x5dc47105, 0xd406046f, 0x155060ff, 0xfb981924, 0xe9bdd697, 0x434089cc, 0x9ed96777, 0x42e8b0bd, 0x8b890788, 0x5b19e738, 0xeec879db, 0xa7ca147, 0xf427ce9, 0x1e84f8c9, 0x0, 0x86800983, 0xed2b3248, 0x70111eac, 0x725a6c4e, 0xff0efdfb, 0x38850f56, 0xd5ae3d1e, 0x392d3627, 0xd90f0a64, 0xa65c6821, 0x545b9bd1, 0x2e36243a, 0x670a0cb1, 0xe757930f, 0x96eeb4d2, 0x919b1b9e, 0xc5c0804f, 0x20dc61a2, 0x4b775a69, 0x1a121c16, 0xba93e20a, 0x2aa0c0e5, 0xe0223c43, 0x171b121d, 0xd090e0b, 0xc78bf2ad, 0xa8b62db9, 0xa91e14c8, 0x19f15785, 0x775af4c, 0xdd99eebb, 0x607fa3fd, 0x2601f79f, 0xf5725cbc, 0x3b6644c5, 0x7efb5b34, 0x29438b76, 0xc623cbdc, 0xfcedb668, 0xf1e4b863, 0xdc31d7ca, 0x85634210, 0x22971340, 0x11c68420, 0x244a857d, 0x3dbbd2f8, 0x32f9ae11, 0xa129c76d, 0x2f9e1d4b, 0x30b2dcf3, 0x52860dec, 0xe3c177d0, 0x16b32b6c, 0xb970a999, 0x489411fa, 0x64e94722, 0x8cfca8c4, 0x3ff0a01a, 0x2c7d56d8, 0x903322ef, 0x4e4987c7, 0xd138d9c1, 0xa2ca8cfe, 0xbd49836, 0x81f5a6cf, 0xde7aa528, 0x8eb7da26, 0xbfad3fa4, 0x9d3a2ce4, 0x9278500d, 0xcc5f6a9b, 0x467e5462, 0x138df6c2, 0xb8d890e8, 0xf7392e5e, 0xafc382f5, 0x805d9fbe, 0x93d0697c, 0x2dd56fa9, 0x1225cfb3, 0x99acc83b, 0x7d1810a7, 0x639ce86e, 0xbb3bdb7b, 0x7826cd09, 0x18596ef4, 0xb79aec01, 0x9a4f83a8, 0x6e95e665, 0xe6ffaa7e, 0xcfbc2108, 0xe815efe6, 0x9be7bad9, 0x366f4ace, 0x99fead4, 0x7cb029d6, 0xb2a431af, 0x233f2a31, 0x94a5c630, 0x66a235c0, 0xbc4e7437, 0xca82fca6, 0xd090e0b0, 0xd8a73315, 0x9804f14a, 0xdaec41f7, 0x50cd7f0e, 0xf691172f, 0xd64d768d, 0xb0ef434d, 0x4daacc54, 0x496e4df, 0xb5d19ee3, 0x886a4c1b, 0x1f2cc1b8, 0x5165467f, 0xea5e9d04, 0x358c015d, 0x7487fa73, 0x410bfb2e, 0x1d67b35a, 0xd2db9252, 0x5610e933, 0x47d66d13, 0x61d79a8c, 0xca1377a, 0x14f8598e, 0x3c13eb89, 0x27a9ceee, 0xc961b735, 0xe51ce1ed, 0xb1477a3c, 0xdfd29c59, 0x73f2553f, 0xce141879, 0x37c773bf, 0xcdf753ea, 0xaafd5f5b, 0x6f3ddf14, 0xdb447886, 0xf3afca81, 0xc468b93e, 0x3424382c, 0x40a3c25f, 0xc31d1672, 0x25e2bc0c, 0x493c288b, 0x950dff41, 0x1a83971, 0xb30c08de, 0xe4b4d89c, 0xc1566490, 0x84cb7b61, 0xb632d570, 0x5c6c4874, 0x57b8d042]
@usableFromInline static let T2: Array<UInt32> = [0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, 0xf2ff0df2, 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, 0x30605030, 0x1020301, 0x67cea967, 0x2b567d2b, 0xfee719fe, 0xd7b562d7, 0xab4de6ab, 0x76ec9a76, 0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d, 0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0, 0xad41ecad, 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, 0x9c23bf9c, 0xa453f7a4, 0x72e49672, 0xc09b5bc0, 0xb775c2b7, 0xfde11cfd, 0x933dae93, 0x264c6a26, 0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc, 0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1, 0x71e29371, 0xd8ab73d8, 0x31625331, 0x152a3f15, 0x4080c04, 0xc79552c7, 0x23466523, 0xc39d5ec3, 0x18302818, 0x9637a196, 0x50a0f05, 0x9a2fb59a, 0x70e0907, 0x12243612, 0x801b9b80, 0xe2df3de2, 0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, 0x9121b09, 0x831d9e83, 0x2c58742c, 0x1a342e1a, 0x1b362d1b, 0x6edcb26e, 0x5ab4ee5a, 0xa05bfba0, 0x52a4f652, 0x3b764d3b, 0xd6b761d6, 0xb37dceb3, 0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784, 0x53a6f553, 0xd1b968d1, 0x0, 0xedc12ced, 0x20406020, 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b, 0x6ad4be6a, 0xcb8d46cb, 0xbe67d9be, 0x39724b39, 0x4a94de4a, 0x4c98d44c, 0x58b0e858, 0xcf854acf, 0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb, 0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, 0x458acf45, 0xf9e910f9, 0x2040602, 0x7ffe817f, 0x50a0f050, 0x3c78443c, 0x9f25ba9f, 0xa84be3a8, 0x51a2f351, 0xa35dfea3, 0x4080c040, 0x8f058a8f, 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5, 0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, 0x10203010, 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, 0xcd814ccd, 0xc18140c, 0x13263513, 0xecc32fec, 0x5fbee15f, 0x9735a297, 0x4488cc44, 0x172e3917, 0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d, 0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573, 0x60c0a060, 0x81199881, 0x4f9ed14f, 0xdca37fdc, 0x22446622, 0x2a547e2a, 0x903bab90, 0x880b8388, 0x468cca46, 0xeec729ee, 0xb86bd3b8, 0x14283c14, 0xdea779de, 0x5ebce25e, 0xb161d0b, 0xdbad76db, 0xe0db3be0, 0x32645632, 0x3a744e3a, 0xa141e0a, 0x4992db49, 0x60c0a06, 0x24486c24, 0x5cb8e45c, 0xc29f5dc2, 0xd3bd6ed3, 0xac43efac, 0x62c4a662, 0x9139a891, 0x9531a495, 0xe4d337e4, 0x79f28b79, 0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d, 0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, 0x6cd8b46c, 0x56acfa56, 0xf4f307f4, 0xeacf25ea, 0x65caaf65, 0x7af48e7a, 0xae47e9ae, 0x8101808, 0xba6fd5ba, 0x78f08878, 0x254a6f25, 0x2e5c722e, 0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6, 0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, 0x4b96dd4b, 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, 0x70e09070, 0x3e7c423e, 0xb571c4b5, 0x66ccaa66, 0x4890d848, 0x3060503, 0xf6f701f6, 0xe1c120e, 0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9, 0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e, 0xe1d938e1, 0xf8eb13f8, 0x982bb398, 0x11223311, 0x69d2bb69, 0xd9a970d9, 0x8e07898e, 0x9433a794, 0x9b2db69b, 0x1e3c221e, 0x87159287, 0xe9c920e9, 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf, 0x8c038f8c, 0xa159f8a1, 0x89098089, 0xd1a170d, 0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868, 0x4182c341, 0x9929b099, 0x2d5a772d, 0xf1e110f, 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16]
@usableFromInline static let T2_INV: Array<UInt32> = [0xf45150a7, 0x417e5365, 0x171ac3a4, 0x273a965e, 0xab3bcb6b, 0x9d1ff145, 0xfaacab58, 0xe34b9303, 0x302055fa, 0x76adf66d, 0xcc889176, 0x2f5254c, 0xe54ffcd7, 0x2ac5d7cb, 0x35268044, 0x62b58fa3, 0xb1de495a, 0xba25671b, 0xea45980e, 0xfe5de1c0, 0x2fc30275, 0x4c8112f0, 0x468da397, 0xd36bc6f9, 0x8f03e75f, 0x9215959c, 0x6dbfeb7a, 0x5295da59, 0xbed42d83, 0x7458d321, 0xe0492969, 0xc98e44c8, 0xc2756a89, 0x8ef47879, 0x58996b3e, 0xb927dd71, 0xe1beb64f, 0x88f017ad, 0x20c966ac, 0xce7db43a, 0xdf63184a, 0x1ae58231, 0x51976033, 0x5362457f, 0x64b1e077, 0x6bbb84ae, 0x81fe1ca0, 0x8f9942b, 0x48705868, 0x458f19fd, 0xde94876c, 0x7b52b7f8, 0x73ab23d3, 0x4b72e202, 0x1fe3578f, 0x55662aab, 0xebb20728, 0xb52f03c2, 0xc5869a7b, 0x37d3a508, 0x2830f287, 0xbf23b2a5, 0x302ba6a, 0x16ed5c82, 0xcf8a2b1c, 0x79a792b4, 0x7f3f0f2, 0x694ea1e2, 0xda65cdf4, 0x506d5be, 0x34d11f62, 0xa6c48afe, 0x2e349d53, 0xf3a2a055, 0x8a0532e1, 0xf6a475eb, 0x830b39ec, 0x6040aaef, 0x715e069f, 0x6ebd5110, 0x213ef98a, 0xdd963d06, 0x3eddae05, 0xe64d46bd, 0x5491b58d, 0xc471055d, 0x6046fd4, 0x5060ff15, 0x981924fb, 0xbdd697e9, 0x4089cc43, 0xd967779e, 0xe8b0bd42, 0x8907888b, 0x19e7385b, 0xc879dbee, 0x7ca1470a, 0x427ce90f, 0x84f8c91e, 0x0, 0x80098386, 0x2b3248ed, 0x111eac70, 0x5a6c4e72, 0xefdfbff, 0x850f5638, 0xae3d1ed5, 0x2d362739, 0xf0a64d9, 0x5c6821a6, 0x5b9bd154, 0x36243a2e, 0xa0cb167, 0x57930fe7, 0xeeb4d296, 0x9b1b9e91, 0xc0804fc5, 0xdc61a220, 0x775a694b, 0x121c161a, 0x93e20aba, 0xa0c0e52a, 0x223c43e0, 0x1b121d17, 0x90e0b0d, 0x8bf2adc7, 0xb62db9a8, 0x1e14c8a9, 0xf1578519, 0x75af4c07, 0x99eebbdd, 0x7fa3fd60, 0x1f79f26, 0x725cbcf5, 0x6644c53b, 0xfb5b347e, 0x438b7629, 0x23cbdcc6, 0xedb668fc, 0xe4b863f1, 0x31d7cadc, 0x63421085, 0x97134022, 0xc6842011, 0x4a857d24, 0xbbd2f83d, 0xf9ae1132, 0x29c76da1, 0x9e1d4b2f, 0xb2dcf330, 0x860dec52, 0xc177d0e3, 0xb32b6c16, 0x70a999b9, 0x9411fa48, 0xe9472264, 0xfca8c48c, 0xf0a01a3f, 0x7d56d82c, 0x3322ef90, 0x4987c74e, 0x38d9c1d1, 0xca8cfea2, 0xd498360b, 0xf5a6cf81, 0x7aa528de, 0xb7da268e, 0xad3fa4bf, 0x3a2ce49d, 0x78500d92, 0x5f6a9bcc, 0x7e546246, 0x8df6c213, 0xd890e8b8, 0x392e5ef7, 0xc382f5af, 0x5d9fbe80, 0xd0697c93, 0xd56fa92d, 0x25cfb312, 0xacc83b99, 0x1810a77d, 0x9ce86e63, 0x3bdb7bbb, 0x26cd0978, 0x596ef418, 0x9aec01b7, 0x4f83a89a, 0x95e6656e, 0xffaa7ee6, 0xbc2108cf, 0x15efe6e8, 0xe7bad99b, 0x6f4ace36, 0x9fead409, 0xb029d67c, 0xa431afb2, 0x3f2a3123, 0xa5c63094, 0xa235c066, 0x4e7437bc, 0x82fca6ca, 0x90e0b0d0, 0xa73315d8, 0x4f14a98, 0xec41f7da, 0xcd7f0e50, 0x91172ff6, 0x4d768dd6, 0xef434db0, 0xaacc544d, 0x96e4df04, 0xd19ee3b5, 0x6a4c1b88, 0x2cc1b81f, 0x65467f51, 0x5e9d04ea, 0x8c015d35, 0x87fa7374, 0xbfb2e41, 0x67b35a1d, 0xdb9252d2, 0x10e93356, 0xd66d1347, 0xd79a8c61, 0xa1377a0c, 0xf8598e14, 0x13eb893c, 0xa9ceee27, 0x61b735c9, 0x1ce1ede5, 0x477a3cb1, 0xd29c59df, 0xf2553f73, 0x141879ce, 0xc773bf37, 0xf753eacd, 0xfd5f5baa, 0x3ddf146f, 0x447886db, 0xafca81f3, 0x68b93ec4, 0x24382c34, 0xa3c25f40, 0x1d1672c3, 0xe2bc0c25, 0x3c288b49, 0xdff4195, 0xa8397101, 0xc08deb3, 0xb4d89ce4, 0x566490c1, 0xcb7b6184, 0x32d570b6, 0x6c48745c, 0xb8d04257]
@usableFromInline static let T3: Array<UInt32> = [0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, 0xff0df2f2, 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, 0x60503030, 0x2030101, 0xcea96767, 0x567d2b2b, 0xe719fefe, 0xb562d7d7, 0x4de6abab, 0xec9a7676, 0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d, 0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0, 0x41ecadad, 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, 0x23bf9c9c, 0x53f7a4a4, 0xe4967272, 0x9b5bc0c0, 0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, 0x4c6a2626, 0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc, 0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1, 0xe2937171, 0xab73d8d8, 0x62533131, 0x2a3f1515, 0x80c0404, 0x9552c7c7, 0x46652323, 0x9d5ec3c3, 0x30281818, 0x37a19696, 0xa0f0505, 0x2fb59a9a, 0xe090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2, 0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, 0x121b0909, 0x1d9e8383, 0x58742c2c, 0x342e1a1a, 0x362d1b1b, 0xdcb26e6e, 0xb4ee5a5a, 0x5bfba0a0, 0xa4f65252, 0x764d3b3b, 0xb761d6d6, 0x7dceb3b3, 0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484, 0xa6f55353, 0xb968d1d1, 0x0, 0xc12ceded, 0x40602020, 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b, 0xd4be6a6a, 0x8d46cbcb, 0x67d9bebe, 0x724b3939, 0x94de4a4a, 0x98d44c4c, 0xb0e85858, 0x854acfcf, 0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb, 0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, 0x8acf4545, 0xe910f9f9, 0x4060202, 0xfe817f7f, 0xa0f05050, 0x78443c3c, 0x25ba9f9f, 0x4be3a8a8, 0xa2f35151, 0x5dfea3a3, 0x80c04040, 0x58a8f8f, 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5, 0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, 0x20301010, 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, 0x814ccdcd, 0x18140c0c, 0x26351313, 0xc32fecec, 0xbee15f5f, 0x35a29797, 0x88cc4444, 0x2e391717, 0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d, 0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373, 0xc0a06060, 0x19988181, 0x9ed14f4f, 0xa37fdcdc, 0x44662222, 0x547e2a2a, 0x3bab9090, 0xb838888, 0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 0x283c1414, 0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb, 0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, 0x92db4949, 0xc0a0606, 0x486c2424, 0xb8e45c5c, 0x9f5dc2c2, 0xbd6ed3d3, 0x43efacac, 0xc4a66262, 0x39a89191, 0x31a49595, 0xd337e4e4, 0xf28b7979, 0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d, 0x18c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, 0xd8b46c6c, 0xacfa5656, 0xf307f4f4, 0xcf25eaea, 0xcaaf6565, 0xf48e7a7a, 0x47e9aeae, 0x10180808, 0x6fd5baba, 0xf0887878, 0x4a6f2525, 0x5c722e2e, 0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6, 0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, 0x96dd4b4b, 0x61dcbdbd, 0xd868b8b, 0xf858a8a, 0xe0907070, 0x7c423e3e, 0x71c4b5b5, 0xccaa6666, 0x90d84848, 0x6050303, 0xf701f6f6, 0x1c120e0e, 0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9, 0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e, 0xd938e1e1, 0xeb13f8f8, 0x2bb39898, 0x22331111, 0xd2bb6969, 0xa970d9d9, 0x7898e8e, 0x33a79494, 0x2db69b9b, 0x3c221e1e, 0x15928787, 0xc920e9e9, 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf, 0x38f8c8c, 0x59f8a1a1, 0x9808989, 0x1a170d0d, 0x65dabfbf, 0xd731e6e6, 0x84c64242, 0xd0b86868, 0x82c34141, 0x29b09999, 0x5a772d2d, 0x1e110f0f, 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616]
@usableFromInline static let T3_INV: Array<UInt32> = [0x5150a7f4, 0x7e536541, 0x1ac3a417, 0x3a965e27, 0x3bcb6bab, 0x1ff1459d, 0xacab58fa, 0x4b9303e3, 0x2055fa30, 0xadf66d76, 0x889176cc, 0xf5254c02, 0x4ffcd7e5, 0xc5d7cb2a, 0x26804435, 0xb58fa362, 0xde495ab1, 0x25671bba, 0x45980eea, 0x5de1c0fe, 0xc302752f, 0x8112f04c, 0x8da39746, 0x6bc6f9d3, 0x3e75f8f, 0x15959c92, 0xbfeb7a6d, 0x95da5952, 0xd42d83be, 0x58d32174, 0x492969e0, 0x8e44c8c9, 0x756a89c2, 0xf478798e, 0x996b3e58, 0x27dd71b9, 0xbeb64fe1, 0xf017ad88, 0xc966ac20, 0x7db43ace, 0x63184adf, 0xe582311a, 0x97603351, 0x62457f53, 0xb1e07764, 0xbb84ae6b, 0xfe1ca081, 0xf9942b08, 0x70586848, 0x8f19fd45, 0x94876cde, 0x52b7f87b, 0xab23d373, 0x72e2024b, 0xe3578f1f, 0x662aab55, 0xb20728eb, 0x2f03c2b5, 0x869a7bc5, 0xd3a50837, 0x30f28728, 0x23b2a5bf, 0x2ba6a03, 0xed5c8216, 0x8a2b1ccf, 0xa792b479, 0xf3f0f207, 0x4ea1e269, 0x65cdf4da, 0x6d5be05, 0xd11f6234, 0xc48afea6, 0x349d532e, 0xa2a055f3, 0x532e18a, 0xa475ebf6, 0xb39ec83, 0x40aaef60, 0x5e069f71, 0xbd51106e, 0x3ef98a21, 0x963d06dd, 0xddae053e, 0x4d46bde6, 0x91b58d54, 0x71055dc4, 0x46fd406, 0x60ff1550, 0x1924fb98, 0xd697e9bd, 0x89cc4340, 0x67779ed9, 0xb0bd42e8, 0x7888b89, 0xe7385b19, 0x79dbeec8, 0xa1470a7c, 0x7ce90f42, 0xf8c91e84, 0x0, 0x9838680, 0x3248ed2b, 0x1eac7011, 0x6c4e725a, 0xfdfbff0e, 0xf563885, 0x3d1ed5ae, 0x3627392d, 0xa64d90f, 0x6821a65c, 0x9bd1545b, 0x243a2e36, 0xcb1670a, 0x930fe757, 0xb4d296ee, 0x1b9e919b, 0x804fc5c0, 0x61a220dc, 0x5a694b77, 0x1c161a12, 0xe20aba93, 0xc0e52aa0, 0x3c43e022, 0x121d171b, 0xe0b0d09, 0xf2adc78b, 0x2db9a8b6, 0x14c8a91e, 0x578519f1, 0xaf4c0775, 0xeebbdd99, 0xa3fd607f, 0xf79f2601, 0x5cbcf572, 0x44c53b66, 0x5b347efb, 0x8b762943, 0xcbdcc623, 0xb668fced, 0xb863f1e4, 0xd7cadc31, 0x42108563, 0x13402297, 0x842011c6, 0x857d244a, 0xd2f83dbb, 0xae1132f9, 0xc76da129, 0x1d4b2f9e, 0xdcf330b2, 0xdec5286, 0x77d0e3c1, 0x2b6c16b3, 0xa999b970, 0x11fa4894, 0x472264e9, 0xa8c48cfc, 0xa01a3ff0, 0x56d82c7d, 0x22ef9033, 0x87c74e49, 0xd9c1d138, 0x8cfea2ca, 0x98360bd4, 0xa6cf81f5, 0xa528de7a, 0xda268eb7, 0x3fa4bfad, 0x2ce49d3a, 0x500d9278, 0x6a9bcc5f, 0x5462467e, 0xf6c2138d, 0x90e8b8d8, 0x2e5ef739, 0x82f5afc3, 0x9fbe805d, 0x697c93d0, 0x6fa92dd5, 0xcfb31225, 0xc83b99ac, 0x10a77d18, 0xe86e639c, 0xdb7bbb3b, 0xcd097826, 0x6ef41859, 0xec01b79a, 0x83a89a4f, 0xe6656e95, 0xaa7ee6ff, 0x2108cfbc, 0xefe6e815, 0xbad99be7, 0x4ace366f, 0xead4099f, 0x29d67cb0, 0x31afb2a4, 0x2a31233f, 0xc63094a5, 0x35c066a2, 0x7437bc4e, 0xfca6ca82, 0xe0b0d090, 0x3315d8a7, 0xf14a9804, 0x41f7daec, 0x7f0e50cd, 0x172ff691, 0x768dd64d, 0x434db0ef, 0xcc544daa, 0xe4df0496, 0x9ee3b5d1, 0x4c1b886a, 0xc1b81f2c, 0x467f5165, 0x9d04ea5e, 0x15d358c, 0xfa737487, 0xfb2e410b, 0xb35a1d67, 0x9252d2db, 0xe9335610, 0x6d1347d6, 0x9a8c61d7, 0x377a0ca1, 0x598e14f8, 0xeb893c13, 0xceee27a9, 0xb735c961, 0xe1ede51c, 0x7a3cb147, 0x9c59dfd2, 0x553f73f2, 0x1879ce14, 0x73bf37c7, 0x53eacdf7, 0x5f5baafd, 0xdf146f3d, 0x7886db44, 0xca81f3af, 0xb93ec468, 0x382c3424, 0xc25f40a3, 0x1672c31d, 0xbc0c25e2, 0x288b493c, 0xff41950d, 0x397101a8, 0x8deb30c, 0xd89ce4b4, 0x6490c156, 0x7b6184cb, 0xd570b632, 0x48745c6c, 0xd04257b8]
@usableFromInline static let U1: Array<UInt32> = [0x0, 0xb0d090e, 0x161a121c, 0x1d171b12, 0x2c342438, 0x27392d36, 0x3a2e3624, 0x31233f2a, 0x58684870, 0x5365417e, 0x4e725a6c, 0x457f5362, 0x745c6c48, 0x7f516546, 0x62467e54, 0x694b775a, 0xb0d090e0, 0xbbdd99ee, 0xa6ca82fc, 0xadc78bf2, 0x9ce4b4d8, 0x97e9bdd6, 0x8afea6c4, 0x81f3afca, 0xe8b8d890, 0xe3b5d19e, 0xfea2ca8c, 0xf5afc382, 0xc48cfca8, 0xcf81f5a6, 0xd296eeb4, 0xd99be7ba, 0x7bbb3bdb, 0x70b632d5, 0x6da129c7, 0x66ac20c9, 0x578f1fe3, 0x5c8216ed, 0x41950dff, 0x4a9804f1, 0x23d373ab, 0x28de7aa5, 0x35c961b7, 0x3ec468b9, 0xfe75793, 0x4ea5e9d, 0x19fd458f, 0x12f04c81, 0xcb6bab3b, 0xc066a235, 0xdd71b927, 0xd67cb029, 0xe75f8f03, 0xec52860d, 0xf1459d1f, 0xfa489411, 0x9303e34b, 0x980eea45, 0x8519f157, 0x8e14f859, 0xbf37c773, 0xb43ace7d, 0xa92dd56f, 0xa220dc61, 0xf66d76ad, 0xfd607fa3, 0xe07764b1, 0xeb7a6dbf, 0xda595295, 0xd1545b9b, 0xcc434089, 0xc74e4987, 0xae053edd, 0xa50837d3, 0xb81f2cc1, 0xb31225cf, 0x82311ae5, 0x893c13eb, 0x942b08f9, 0x9f2601f7, 0x46bde64d, 0x4db0ef43, 0x50a7f451, 0x5baafd5f, 0x6a89c275, 0x6184cb7b, 0x7c93d069, 0x779ed967, 0x1ed5ae3d, 0x15d8a733, 0x8cfbc21, 0x3c2b52f, 0x32e18a05, 0x39ec830b, 0x24fb9819, 0x2ff69117, 0x8dd64d76, 0x86db4478, 0x9bcc5f6a, 0x90c15664, 0xa1e2694e, 0xaaef6040, 0xb7f87b52, 0xbcf5725c, 0xd5be0506, 0xdeb30c08, 0xc3a4171a, 0xc8a91e14, 0xf98a213e, 0xf2872830, 0xef903322, 0xe49d3a2c, 0x3d06dd96, 0x360bd498, 0x2b1ccf8a, 0x2011c684, 0x1132f9ae, 0x1a3ff0a0, 0x728ebb2, 0xc25e2bc, 0x656e95e6, 0x6e639ce8, 0x737487fa, 0x78798ef4, 0x495ab1de, 0x4257b8d0, 0x5f40a3c2, 0x544daacc, 0xf7daec41, 0xfcd7e54f, 0xe1c0fe5d, 0xeacdf753, 0xdbeec879, 0xd0e3c177, 0xcdf4da65, 0xc6f9d36b, 0xafb2a431, 0xa4bfad3f, 0xb9a8b62d, 0xb2a5bf23, 0x83868009, 0x888b8907, 0x959c9215, 0x9e919b1b, 0x470a7ca1, 0x4c0775af, 0x51106ebd, 0x5a1d67b3, 0x6b3e5899, 0x60335197, 0x7d244a85, 0x7629438b, 0x1f6234d1, 0x146f3ddf, 0x97826cd, 0x2752fc3, 0x335610e9, 0x385b19e7, 0x254c02f5, 0x2e410bfb, 0x8c61d79a, 0x876cde94, 0x9a7bc586, 0x9176cc88, 0xa055f3a2, 0xab58faac, 0xb64fe1be, 0xbd42e8b0, 0xd4099fea, 0xdf0496e4, 0xc2138df6, 0xc91e84f8, 0xf83dbbd2, 0xf330b2dc, 0xee27a9ce, 0xe52aa0c0, 0x3cb1477a, 0x37bc4e74, 0x2aab5566, 0x21a65c68, 0x10856342, 0x1b886a4c, 0x69f715e, 0xd927850, 0x64d90f0a, 0x6fd40604, 0x72c31d16, 0x79ce1418, 0x48ed2b32, 0x43e0223c, 0x5ef7392e, 0x55fa3020, 0x1b79aec, 0xaba93e2, 0x17ad88f0, 0x1ca081fe, 0x2d83bed4, 0x268eb7da, 0x3b99acc8, 0x3094a5c6, 0x59dfd29c, 0x52d2db92, 0x4fc5c080, 0x44c8c98e, 0x75ebf6a4, 0x7ee6ffaa, 0x63f1e4b8, 0x68fcedb6, 0xb1670a0c, 0xba6a0302, 0xa77d1810, 0xac70111e, 0x9d532e34, 0x965e273a, 0x8b493c28, 0x80443526, 0xe90f427c, 0xe2024b72, 0xff155060, 0xf418596e, 0xc53b6644, 0xce366f4a, 0xd3217458, 0xd82c7d56, 0x7a0ca137, 0x7101a839, 0x6c16b32b, 0x671bba25, 0x5638850f, 0x5d358c01, 0x40229713, 0x4b2f9e1d, 0x2264e947, 0x2969e049, 0x347efb5b, 0x3f73f255, 0xe50cd7f, 0x55dc471, 0x184adf63, 0x1347d66d, 0xcadc31d7, 0xc1d138d9, 0xdcc623cb, 0xd7cb2ac5, 0xe6e815ef, 0xede51ce1, 0xf0f207f3, 0xfbff0efd, 0x92b479a7, 0x99b970a9, 0x84ae6bbb, 0x8fa362b5, 0xbe805d9f, 0xb58d5491, 0xa89a4f83, 0xa397468d]
@usableFromInline static let U2: Array<UInt32> = [0x0, 0xd090e0b, 0x1a121c16, 0x171b121d, 0x3424382c, 0x392d3627, 0x2e36243a, 0x233f2a31, 0x68487058, 0x65417e53, 0x725a6c4e, 0x7f536245, 0x5c6c4874, 0x5165467f, 0x467e5462, 0x4b775a69, 0xd090e0b0, 0xdd99eebb, 0xca82fca6, 0xc78bf2ad, 0xe4b4d89c, 0xe9bdd697, 0xfea6c48a, 0xf3afca81, 0xb8d890e8, 0xb5d19ee3, 0xa2ca8cfe, 0xafc382f5, 0x8cfca8c4, 0x81f5a6cf, 0x96eeb4d2, 0x9be7bad9, 0xbb3bdb7b, 0xb632d570, 0xa129c76d, 0xac20c966, 0x8f1fe357, 0x8216ed5c, 0x950dff41, 0x9804f14a, 0xd373ab23, 0xde7aa528, 0xc961b735, 0xc468b93e, 0xe757930f, 0xea5e9d04, 0xfd458f19, 0xf04c8112, 0x6bab3bcb, 0x66a235c0, 0x71b927dd, 0x7cb029d6, 0x5f8f03e7, 0x52860dec, 0x459d1ff1, 0x489411fa, 0x3e34b93, 0xeea4598, 0x19f15785, 0x14f8598e, 0x37c773bf, 0x3ace7db4, 0x2dd56fa9, 0x20dc61a2, 0x6d76adf6, 0x607fa3fd, 0x7764b1e0, 0x7a6dbfeb, 0x595295da, 0x545b9bd1, 0x434089cc, 0x4e4987c7, 0x53eddae, 0x837d3a5, 0x1f2cc1b8, 0x1225cfb3, 0x311ae582, 0x3c13eb89, 0x2b08f994, 0x2601f79f, 0xbde64d46, 0xb0ef434d, 0xa7f45150, 0xaafd5f5b, 0x89c2756a, 0x84cb7b61, 0x93d0697c, 0x9ed96777, 0xd5ae3d1e, 0xd8a73315, 0xcfbc2108, 0xc2b52f03, 0xe18a0532, 0xec830b39, 0xfb981924, 0xf691172f, 0xd64d768d, 0xdb447886, 0xcc5f6a9b, 0xc1566490, 0xe2694ea1, 0xef6040aa, 0xf87b52b7, 0xf5725cbc, 0xbe0506d5, 0xb30c08de, 0xa4171ac3, 0xa91e14c8, 0x8a213ef9, 0x872830f2, 0x903322ef, 0x9d3a2ce4, 0x6dd963d, 0xbd49836, 0x1ccf8a2b, 0x11c68420, 0x32f9ae11, 0x3ff0a01a, 0x28ebb207, 0x25e2bc0c, 0x6e95e665, 0x639ce86e, 0x7487fa73, 0x798ef478, 0x5ab1de49, 0x57b8d042, 0x40a3c25f, 0x4daacc54, 0xdaec41f7, 0xd7e54ffc, 0xc0fe5de1, 0xcdf753ea, 0xeec879db, 0xe3c177d0, 0xf4da65cd, 0xf9d36bc6, 0xb2a431af, 0xbfad3fa4, 0xa8b62db9, 0xa5bf23b2, 0x86800983, 0x8b890788, 0x9c921595, 0x919b1b9e, 0xa7ca147, 0x775af4c, 0x106ebd51, 0x1d67b35a, 0x3e58996b, 0x33519760, 0x244a857d, 0x29438b76, 0x6234d11f, 0x6f3ddf14, 0x7826cd09, 0x752fc302, 0x5610e933, 0x5b19e738, 0x4c02f525, 0x410bfb2e, 0x61d79a8c, 0x6cde9487, 0x7bc5869a, 0x76cc8891, 0x55f3a2a0, 0x58faacab, 0x4fe1beb6, 0x42e8b0bd, 0x99fead4, 0x496e4df, 0x138df6c2, 0x1e84f8c9, 0x3dbbd2f8, 0x30b2dcf3, 0x27a9ceee, 0x2aa0c0e5, 0xb1477a3c, 0xbc4e7437, 0xab55662a, 0xa65c6821, 0x85634210, 0x886a4c1b, 0x9f715e06, 0x9278500d, 0xd90f0a64, 0xd406046f, 0xc31d1672, 0xce141879, 0xed2b3248, 0xe0223c43, 0xf7392e5e, 0xfa302055, 0xb79aec01, 0xba93e20a, 0xad88f017, 0xa081fe1c, 0x83bed42d, 0x8eb7da26, 0x99acc83b, 0x94a5c630, 0xdfd29c59, 0xd2db9252, 0xc5c0804f, 0xc8c98e44, 0xebf6a475, 0xe6ffaa7e, 0xf1e4b863, 0xfcedb668, 0x670a0cb1, 0x6a0302ba, 0x7d1810a7, 0x70111eac, 0x532e349d, 0x5e273a96, 0x493c288b, 0x44352680, 0xf427ce9, 0x24b72e2, 0x155060ff, 0x18596ef4, 0x3b6644c5, 0x366f4ace, 0x217458d3, 0x2c7d56d8, 0xca1377a, 0x1a83971, 0x16b32b6c, 0x1bba2567, 0x38850f56, 0x358c015d, 0x22971340, 0x2f9e1d4b, 0x64e94722, 0x69e04929, 0x7efb5b34, 0x73f2553f, 0x50cd7f0e, 0x5dc47105, 0x4adf6318, 0x47d66d13, 0xdc31d7ca, 0xd138d9c1, 0xc623cbdc, 0xcb2ac5d7, 0xe815efe6, 0xe51ce1ed, 0xf207f3f0, 0xff0efdfb, 0xb479a792, 0xb970a999, 0xae6bbb84, 0xa362b58f, 0x805d9fbe, 0x8d5491b5, 0x9a4f83a8, 0x97468da3]
@usableFromInline static let U3: Array<UInt32> = [0x0, 0x90e0b0d, 0x121c161a, 0x1b121d17, 0x24382c34, 0x2d362739, 0x36243a2e, 0x3f2a3123, 0x48705868, 0x417e5365, 0x5a6c4e72, 0x5362457f, 0x6c48745c, 0x65467f51, 0x7e546246, 0x775a694b, 0x90e0b0d0, 0x99eebbdd, 0x82fca6ca, 0x8bf2adc7, 0xb4d89ce4, 0xbdd697e9, 0xa6c48afe, 0xafca81f3, 0xd890e8b8, 0xd19ee3b5, 0xca8cfea2, 0xc382f5af, 0xfca8c48c, 0xf5a6cf81, 0xeeb4d296, 0xe7bad99b, 0x3bdb7bbb, 0x32d570b6, 0x29c76da1, 0x20c966ac, 0x1fe3578f, 0x16ed5c82, 0xdff4195, 0x4f14a98, 0x73ab23d3, 0x7aa528de, 0x61b735c9, 0x68b93ec4, 0x57930fe7, 0x5e9d04ea, 0x458f19fd, 0x4c8112f0, 0xab3bcb6b, 0xa235c066, 0xb927dd71, 0xb029d67c, 0x8f03e75f, 0x860dec52, 0x9d1ff145, 0x9411fa48, 0xe34b9303, 0xea45980e, 0xf1578519, 0xf8598e14, 0xc773bf37, 0xce7db43a, 0xd56fa92d, 0xdc61a220, 0x76adf66d, 0x7fa3fd60, 0x64b1e077, 0x6dbfeb7a, 0x5295da59, 0x5b9bd154, 0x4089cc43, 0x4987c74e, 0x3eddae05, 0x37d3a508, 0x2cc1b81f, 0x25cfb312, 0x1ae58231, 0x13eb893c, 0x8f9942b, 0x1f79f26, 0xe64d46bd, 0xef434db0, 0xf45150a7, 0xfd5f5baa, 0xc2756a89, 0xcb7b6184, 0xd0697c93, 0xd967779e, 0xae3d1ed5, 0xa73315d8, 0xbc2108cf, 0xb52f03c2, 0x8a0532e1, 0x830b39ec, 0x981924fb, 0x91172ff6, 0x4d768dd6, 0x447886db, 0x5f6a9bcc, 0x566490c1, 0x694ea1e2, 0x6040aaef, 0x7b52b7f8, 0x725cbcf5, 0x506d5be, 0xc08deb3, 0x171ac3a4, 0x1e14c8a9, 0x213ef98a, 0x2830f287, 0x3322ef90, 0x3a2ce49d, 0xdd963d06, 0xd498360b, 0xcf8a2b1c, 0xc6842011, 0xf9ae1132, 0xf0a01a3f, 0xebb20728, 0xe2bc0c25, 0x95e6656e, 0x9ce86e63, 0x87fa7374, 0x8ef47879, 0xb1de495a, 0xb8d04257, 0xa3c25f40, 0xaacc544d, 0xec41f7da, 0xe54ffcd7, 0xfe5de1c0, 0xf753eacd, 0xc879dbee, 0xc177d0e3, 0xda65cdf4, 0xd36bc6f9, 0xa431afb2, 0xad3fa4bf, 0xb62db9a8, 0xbf23b2a5, 0x80098386, 0x8907888b, 0x9215959c, 0x9b1b9e91, 0x7ca1470a, 0x75af4c07, 0x6ebd5110, 0x67b35a1d, 0x58996b3e, 0x51976033, 0x4a857d24, 0x438b7629, 0x34d11f62, 0x3ddf146f, 0x26cd0978, 0x2fc30275, 0x10e93356, 0x19e7385b, 0x2f5254c, 0xbfb2e41, 0xd79a8c61, 0xde94876c, 0xc5869a7b, 0xcc889176, 0xf3a2a055, 0xfaacab58, 0xe1beb64f, 0xe8b0bd42, 0x9fead409, 0x96e4df04, 0x8df6c213, 0x84f8c91e, 0xbbd2f83d, 0xb2dcf330, 0xa9ceee27, 0xa0c0e52a, 0x477a3cb1, 0x4e7437bc, 0x55662aab, 0x5c6821a6, 0x63421085, 0x6a4c1b88, 0x715e069f, 0x78500d92, 0xf0a64d9, 0x6046fd4, 0x1d1672c3, 0x141879ce, 0x2b3248ed, 0x223c43e0, 0x392e5ef7, 0x302055fa, 0x9aec01b7, 0x93e20aba, 0x88f017ad, 0x81fe1ca0, 0xbed42d83, 0xb7da268e, 0xacc83b99, 0xa5c63094, 0xd29c59df, 0xdb9252d2, 0xc0804fc5, 0xc98e44c8, 0xf6a475eb, 0xffaa7ee6, 0xe4b863f1, 0xedb668fc, 0xa0cb167, 0x302ba6a, 0x1810a77d, 0x111eac70, 0x2e349d53, 0x273a965e, 0x3c288b49, 0x35268044, 0x427ce90f, 0x4b72e202, 0x5060ff15, 0x596ef418, 0x6644c53b, 0x6f4ace36, 0x7458d321, 0x7d56d82c, 0xa1377a0c, 0xa8397101, 0xb32b6c16, 0xba25671b, 0x850f5638, 0x8c015d35, 0x97134022, 0x9e1d4b2f, 0xe9472264, 0xe0492969, 0xfb5b347e, 0xf2553f73, 0xcd7f0e50, 0xc471055d, 0xdf63184a, 0xd66d1347, 0x31d7cadc, 0x38d9c1d1, 0x23cbdcc6, 0x2ac5d7cb, 0x15efe6e8, 0x1ce1ede5, 0x7f3f0f2, 0xefdfbff, 0x79a792b4, 0x70a999b9, 0x6bbb84ae, 0x62b58fa3, 0x5d9fbe80, 0x5491b58d, 0x4f83a89a, 0x468da397]
@usableFromInline static let U4: Array<UInt32> = [0x0, 0xe0b0d09, 0x1c161a12, 0x121d171b, 0x382c3424, 0x3627392d, 0x243a2e36, 0x2a31233f, 0x70586848, 0x7e536541, 0x6c4e725a, 0x62457f53, 0x48745c6c, 0x467f5165, 0x5462467e, 0x5a694b77, 0xe0b0d090, 0xeebbdd99, 0xfca6ca82, 0xf2adc78b, 0xd89ce4b4, 0xd697e9bd, 0xc48afea6, 0xca81f3af, 0x90e8b8d8, 0x9ee3b5d1, 0x8cfea2ca, 0x82f5afc3, 0xa8c48cfc, 0xa6cf81f5, 0xb4d296ee, 0xbad99be7, 0xdb7bbb3b, 0xd570b632, 0xc76da129, 0xc966ac20, 0xe3578f1f, 0xed5c8216, 0xff41950d, 0xf14a9804, 0xab23d373, 0xa528de7a, 0xb735c961, 0xb93ec468, 0x930fe757, 0x9d04ea5e, 0x8f19fd45, 0x8112f04c, 0x3bcb6bab, 0x35c066a2, 0x27dd71b9, 0x29d67cb0, 0x3e75f8f, 0xdec5286, 0x1ff1459d, 0x11fa4894, 0x4b9303e3, 0x45980eea, 0x578519f1, 0x598e14f8, 0x73bf37c7, 0x7db43ace, 0x6fa92dd5, 0x61a220dc, 0xadf66d76, 0xa3fd607f, 0xb1e07764, 0xbfeb7a6d, 0x95da5952, 0x9bd1545b, 0x89cc4340, 0x87c74e49, 0xddae053e, 0xd3a50837, 0xc1b81f2c, 0xcfb31225, 0xe582311a, 0xeb893c13, 0xf9942b08, 0xf79f2601, 0x4d46bde6, 0x434db0ef, 0x5150a7f4, 0x5f5baafd, 0x756a89c2, 0x7b6184cb, 0x697c93d0, 0x67779ed9, 0x3d1ed5ae, 0x3315d8a7, 0x2108cfbc, 0x2f03c2b5, 0x532e18a, 0xb39ec83, 0x1924fb98, 0x172ff691, 0x768dd64d, 0x7886db44, 0x6a9bcc5f, 0x6490c156, 0x4ea1e269, 0x40aaef60, 0x52b7f87b, 0x5cbcf572, 0x6d5be05, 0x8deb30c, 0x1ac3a417, 0x14c8a91e, 0x3ef98a21, 0x30f28728, 0x22ef9033, 0x2ce49d3a, 0x963d06dd, 0x98360bd4, 0x8a2b1ccf, 0x842011c6, 0xae1132f9, 0xa01a3ff0, 0xb20728eb, 0xbc0c25e2, 0xe6656e95, 0xe86e639c, 0xfa737487, 0xf478798e, 0xde495ab1, 0xd04257b8, 0xc25f40a3, 0xcc544daa, 0x41f7daec, 0x4ffcd7e5, 0x5de1c0fe, 0x53eacdf7, 0x79dbeec8, 0x77d0e3c1, 0x65cdf4da, 0x6bc6f9d3, 0x31afb2a4, 0x3fa4bfad, 0x2db9a8b6, 0x23b2a5bf, 0x9838680, 0x7888b89, 0x15959c92, 0x1b9e919b, 0xa1470a7c, 0xaf4c0775, 0xbd51106e, 0xb35a1d67, 0x996b3e58, 0x97603351, 0x857d244a, 0x8b762943, 0xd11f6234, 0xdf146f3d, 0xcd097826, 0xc302752f, 0xe9335610, 0xe7385b19, 0xf5254c02, 0xfb2e410b, 0x9a8c61d7, 0x94876cde, 0x869a7bc5, 0x889176cc, 0xa2a055f3, 0xacab58fa, 0xbeb64fe1, 0xb0bd42e8, 0xead4099f, 0xe4df0496, 0xf6c2138d, 0xf8c91e84, 0xd2f83dbb, 0xdcf330b2, 0xceee27a9, 0xc0e52aa0, 0x7a3cb147, 0x7437bc4e, 0x662aab55, 0x6821a65c, 0x42108563, 0x4c1b886a, 0x5e069f71, 0x500d9278, 0xa64d90f, 0x46fd406, 0x1672c31d, 0x1879ce14, 0x3248ed2b, 0x3c43e022, 0x2e5ef739, 0x2055fa30, 0xec01b79a, 0xe20aba93, 0xf017ad88, 0xfe1ca081, 0xd42d83be, 0xda268eb7, 0xc83b99ac, 0xc63094a5, 0x9c59dfd2, 0x9252d2db, 0x804fc5c0, 0x8e44c8c9, 0xa475ebf6, 0xaa7ee6ff, 0xb863f1e4, 0xb668fced, 0xcb1670a, 0x2ba6a03, 0x10a77d18, 0x1eac7011, 0x349d532e, 0x3a965e27, 0x288b493c, 0x26804435, 0x7ce90f42, 0x72e2024b, 0x60ff1550, 0x6ef41859, 0x44c53b66, 0x4ace366f, 0x58d32174, 0x56d82c7d, 0x377a0ca1, 0x397101a8, 0x2b6c16b3, 0x25671bba, 0xf563885, 0x15d358c, 0x13402297, 0x1d4b2f9e, 0x472264e9, 0x492969e0, 0x5b347efb, 0x553f73f2, 0x7f0e50cd, 0x71055dc4, 0x63184adf, 0x6d1347d6, 0xd7cadc31, 0xd9c1d138, 0xcbdcc623, 0xc5d7cb2a, 0xefe6e815, 0xe1ede51c, 0xf3f0f207, 0xfdfbff0e, 0xa792b479, 0xa999b970, 0xbb84ae6b, 0xb58fa362, 0x9fbe805d, 0x91b58d54, 0x83a89a4f, 0x8da39746]
/// Initialize AES with variant calculated out of key length:
/// - 16 bytes (AES-128)
/// - 24 bytes (AES-192)
/// - 32 bytes (AES-256)
///
/// - parameter key: Key. Length of the key decides on AES variant.
/// - parameter iv: Initialization Vector (Optional for some blockMode values)
/// - parameter blockMode: Cipher mode of operation
/// - parameter padding: Padding method. .pkcs7, .noPadding, .zeroPadding, ...
///
/// - throws: AES.Error
///
/// - returns: Instance
public init(key: Array<UInt8>, blockMode: BlockMode, padding: Padding = .pkcs7) throws {
self.key = Key(bytes: key)
self.blockMode = blockMode
self.padding = padding
self.keySize = self.key.count
// Validate key size
switch self.keySize * 8 {
case 128:
self.variant = .aes128
case 192:
self.variant = .aes192
case 256:
self.variant = .aes256
default:
throw Error.invalidKeySize
}
self.variantNb = self.variant.Nb
self.variantNk = self.variant.Nk
self.variantNr = self.variant.Nr
}
@inlinable
internal func encrypt(block: ArraySlice<UInt8>) -> Array<UInt8>? {
if self.blockMode.options.contains(.paddingRequired) && block.count != AES.blockSize {
return Array(block)
}
let rounds = self.variantNr
let rk = self.expandedKey
let b00 = UInt32(block[block.startIndex.advanced(by: 0)])
let b01 = UInt32(block[block.startIndex.advanced(by: 1)]) << 8
let b02 = UInt32(block[block.startIndex.advanced(by: 2)]) << 16
let b03 = UInt32(block[block.startIndex.advanced(by: 3)]) << 24
var b0 = b00 | b01 | b02 | b03
let b10 = UInt32(block[block.startIndex.advanced(by: 4)])
let b11 = UInt32(block[block.startIndex.advanced(by: 5)]) << 8
let b12 = UInt32(block[block.startIndex.advanced(by: 6)]) << 16
let b13 = UInt32(block[block.startIndex.advanced(by: 7)]) << 24
var b1 = b10 | b11 | b12 | b13
let b20 = UInt32(block[block.startIndex.advanced(by: 8)])
let b21 = UInt32(block[block.startIndex.advanced(by: 9)]) << 8
let b22 = UInt32(block[block.startIndex.advanced(by: 10)]) << 16
let b23 = UInt32(block[block.startIndex.advanced(by: 11)]) << 24
var b2 = b20 | b21 | b22 | b23
let b30 = UInt32(block[block.startIndex.advanced(by: 12)])
let b31 = UInt32(block[block.startIndex.advanced(by: 13)]) << 8
let b32 = UInt32(block[block.startIndex.advanced(by: 14)]) << 16
let b33 = UInt32(block[block.startIndex.advanced(by: 15)]) << 24
var b3 = b30 | b31 | b32 | b33
let tLength = 4
let t = UnsafeMutablePointer<UInt32>.allocate(capacity: tLength)
t.initialize(repeating: 0, count: tLength)
defer {
t.deinitialize(count: tLength)
t.deallocate()
}
for r in 0..<rounds - 1 {
t[0] = b0 ^ rk[r][0]
t[1] = b1 ^ rk[r][1]
t[2] = b2 ^ rk[r][2]
t[3] = b3 ^ rk[r][3]
let lb00 = AES.T0[Int(t[0] & 0xff)]
let lb01 = AES.T1[Int((t[1] >> 8) & 0xff)]
let lb02 = AES.T2[Int((t[2] >> 16) & 0xff)]
let lb03 = AES.T3[Int(t[3] >> 24)]
b0 = lb00 ^ lb01 ^ lb02 ^ lb03
let lb10 = AES.T0[Int(t[1] & 0xff)]
let lb11 = AES.T1[Int((t[2] >> 8) & 0xff)]
let lb12 = AES.T2[Int((t[3] >> 16) & 0xff)]
let lb13 = AES.T3[Int(t[0] >> 24)]
b1 = lb10 ^ lb11 ^ lb12 ^ lb13
let lb20 = AES.T0[Int(t[2] & 0xff)]
let lb21 = AES.T1[Int((t[3] >> 8) & 0xff)]
let lb22 = AES.T2[Int((t[0] >> 16) & 0xff)]
let lb23 = AES.T3[Int(t[1] >> 24)]
b2 = lb20 ^ lb21 ^ lb22 ^ lb23
let lb30 = AES.T0[Int(t[3] & 0xff)]
let lb31 = AES.T1[Int((t[0] >> 8) & 0xff)]
let lb32 = AES.T2[Int((t[1] >> 16) & 0xff)]
let lb33 = AES.T3[Int(t[2] >> 24)]
b3 = lb30 ^ lb31 ^ lb32 ^ lb33
}
// last round
let r = rounds - 1
t[0] = b0 ^ rk[r][0]
t[1] = b1 ^ rk[r][1]
t[2] = b2 ^ rk[r][2]
t[3] = b3 ^ rk[r][3]
// rounds
b0 = F1(t[0], t[1], t[2], t[3]) ^ rk[rounds][0]
b1 = F1(t[1], t[2], t[3], t[0]) ^ rk[rounds][1]
b2 = F1(t[2], t[3], t[0], t[1]) ^ rk[rounds][2]
b3 = F1(t[3], t[0], t[1], t[2]) ^ rk[rounds][3]
let encrypted: Array<UInt8> = [
UInt8(b0 & 0xff), UInt8((b0 >> 8) & 0xff), UInt8((b0 >> 16) & 0xff), UInt8((b0 >> 24) & 0xff),
UInt8(b1 & 0xff), UInt8((b1 >> 8) & 0xff), UInt8((b1 >> 16) & 0xff), UInt8((b1 >> 24) & 0xff),
UInt8(b2 & 0xff), UInt8((b2 >> 8) & 0xff), UInt8((b2 >> 16) & 0xff), UInt8((b2 >> 24) & 0xff),
UInt8(b3 & 0xff), UInt8((b3 >> 8) & 0xff), UInt8((b3 >> 16) & 0xff), UInt8((b3 >> 24) & 0xff)
]
return encrypted
}
@usableFromInline
internal func decrypt(block: ArraySlice<UInt8>) -> Array<UInt8>? {
if self.blockMode.options.contains(.paddingRequired) && block.count != AES.blockSize {
return Array(block)
}
let rounds = self.variantNr
let rk = self.expandedKeyInv
// Save miliseconds by not using `block.toUInt32Array()`
let b00 = UInt32(block[block.startIndex.advanced(by: 0)])
let b01 = UInt32(block[block.startIndex.advanced(by: 1)]) << 8
let b02 = UInt32(block[block.startIndex.advanced(by: 2)]) << 16
let b03 = UInt32(block[block.startIndex.advanced(by: 3)]) << 24
var b0 = b00 | b01 | b02 | b03
let b10 = UInt32(block[block.startIndex.advanced(by: 4)])
let b11 = UInt32(block[block.startIndex.advanced(by: 5)]) << 8
let b12 = UInt32(block[block.startIndex.advanced(by: 6)]) << 16
let b13 = UInt32(block[block.startIndex.advanced(by: 7)]) << 24
var b1 = b10 | b11 | b12 | b13
let b20 = UInt32(block[block.startIndex.advanced(by: 8)])
let b21 = UInt32(block[block.startIndex.advanced(by: 9)]) << 8
let b22 = UInt32(block[block.startIndex.advanced(by: 10)]) << 16
let b23 = UInt32(block[block.startIndex.advanced(by: 11)]) << 24
var b2 = b20 | b21 | b22 | b23
let b30 = UInt32(block[block.startIndex.advanced(by: 12)])
let b31 = UInt32(block[block.startIndex.advanced(by: 13)]) << 8
let b32 = UInt32(block[block.startIndex.advanced(by: 14)]) << 16
let b33 = UInt32(block[block.startIndex.advanced(by: 15)]) << 24
var b3 = b30 | b31 | b32 | b33
let tLength = 4
let t = UnsafeMutablePointer<UInt32>.allocate(capacity: tLength)
t.initialize(repeating: 0, count: tLength)
defer {
t.deinitialize(count: tLength)
t.deallocate()
}
for r in (2...rounds).reversed() {
t[0] = b0 ^ rk[r][0]
t[1] = b1 ^ rk[r][1]
t[2] = b2 ^ rk[r][2]
t[3] = b3 ^ rk[r][3]
let b00 = AES.T0_INV[Int(t[0] & 0xff)]
let b01 = AES.T1_INV[Int((t[3] >> 8) & 0xff)]
let b02 = AES.T2_INV[Int((t[2] >> 16) & 0xff)]
let b03 = AES.T3_INV[Int(t[1] >> 24)]
b0 = b00 ^ b01 ^ b02 ^ b03
let b10 = AES.T0_INV[Int(t[1] & 0xff)]
let b11 = AES.T1_INV[Int((t[0] >> 8) & 0xff)]
let b12 = AES.T2_INV[Int((t[3] >> 16) & 0xff)]
let b13 = AES.T3_INV[Int(t[2] >> 24)]
b1 = b10 ^ b11 ^ b12 ^ b13
let b20 = AES.T0_INV[Int(t[2] & 0xff)]
let b21 = AES.T1_INV[Int((t[1] >> 8) & 0xff)]
let b22 = AES.T2_INV[Int((t[0] >> 16) & 0xff)]
let b23 = AES.T3_INV[Int(t[3] >> 24)]
b2 = b20 ^ b21 ^ b22 ^ b23
let b30 = AES.T0_INV[Int(t[3] & 0xff)]
let b31 = AES.T1_INV[Int((t[2] >> 8) & 0xff)]
let b32 = AES.T2_INV[Int((t[1] >> 16) & 0xff)]
let b33 = AES.T3_INV[Int(t[0] >> 24)]
b3 = b30 ^ b31 ^ b32 ^ b33
}
// last round
t[0] = b0 ^ rk[1][0]
t[1] = b1 ^ rk[1][1]
t[2] = b2 ^ rk[1][2]
t[3] = b3 ^ rk[1][3]
// rounds
let lb00 = self.sBoxInv[Int(B0(t[0]))]
let lb01 = (sBoxInv[Int(B1(t[3]))] << 8)
let lb02 = (sBoxInv[Int(B2(t[2]))] << 16)
let lb03 = (sBoxInv[Int(B3(t[1]))] << 24)
b0 = lb00 | lb01 | lb02 | lb03 ^ rk[0][0]
let lb10 = self.sBoxInv[Int(B0(t[1]))]
let lb11 = (sBoxInv[Int(B1(t[0]))] << 8)
let lb12 = (sBoxInv[Int(B2(t[3]))] << 16)
let lb13 = (sBoxInv[Int(B3(t[2]))] << 24)
b1 = lb10 | lb11 | lb12 | lb13 ^ rk[0][1]
let lb20 = self.sBoxInv[Int(B0(t[2]))]
let lb21 = (sBoxInv[Int(B1(t[1]))] << 8)
let lb22 = (sBoxInv[Int(B2(t[0]))] << 16)
let lb23 = (sBoxInv[Int(B3(t[3]))] << 24)
b2 = lb20 | lb21 | lb22 | lb23 ^ rk[0][2]
let lb30 = self.sBoxInv[Int(B0(t[3]))]
let lb31 = (sBoxInv[Int(B1(t[2]))] << 8)
let lb32 = (sBoxInv[Int(B2(t[1]))] << 16)
let lb33 = (sBoxInv[Int(B3(t[0]))] << 24)
b3 = lb30 | lb31 | lb32 | lb33 ^ rk[0][3]
let result: Array<UInt8> = [
UInt8(b0 & 0xff), UInt8((b0 >> 8) & 0xff), UInt8((b0 >> 16) & 0xff), UInt8((b0 >> 24) & 0xff),
UInt8(b1 & 0xff), UInt8((b1 >> 8) & 0xff), UInt8((b1 >> 16) & 0xff), UInt8((b1 >> 24) & 0xff),
UInt8(b2 & 0xff), UInt8((b2 >> 8) & 0xff), UInt8((b2 >> 16) & 0xff), UInt8((b2 >> 24) & 0xff),
UInt8(b3 & 0xff), UInt8((b3 >> 8) & 0xff), UInt8((b3 >> 16) & 0xff), UInt8((b3 >> 24) & 0xff)
]
return result
}
}
extension AES {
private func expandKeyInv(_ key: Key, variant: Variant) -> Array<Array<UInt32>> {
let rounds = self.variantNr
var rk2: Array<Array<UInt32>> = self.expandKey(key, variant: variant)
for r in 1..<rounds {
for i in 0..<4 {
let w = rk2[r][i]
let u1 = AES.U1[Int(B0(w))]
let u2 = AES.U2[Int(B1(w))]
let u3 = AES.U3[Int(B2(w))]
let u4 = AES.U4[Int(B3(w))]
rk2[r][i] = u1 ^ u2 ^ u3 ^ u4
}
}
return rk2
}
private func expandKey(_ key: Key, variant _: Variant) -> Array<Array<UInt32>> {
func convertExpandedKey(_ expanded: Array<UInt8>) -> Array<Array<UInt32>> {
expanded.batched(by: 4).map({ UInt32(bytes: $0.reversed()) }).batched(by: 4).map { Array($0) }
}
/*
* Function used in the Key Expansion routine that takes a four-byte
* input word and applies an S-box to each of the four bytes to
* produce an output word.
*/
func subWord(_ word: Array<UInt8>) -> Array<UInt8> {
precondition(word.count == 4)
var result = word
for i in 0..<4 {
result[i] = UInt8(self.sBox[Int(word[i])])
}
return result
}
@inline(__always)
func subWordInPlace(_ word: inout Array<UInt8>) {
precondition(word.count == 4)
word[0] = UInt8(self.sBox[Int(word[0])])
word[1] = UInt8(self.sBox[Int(word[1])])
word[2] = UInt8(self.sBox[Int(word[2])])
word[3] = UInt8(self.sBox[Int(word[3])])
}
let wLength = self.variantNb * (self.variantNr + 1) * 4
let w = UnsafeMutablePointer<UInt8>.allocate(capacity: wLength)
w.initialize(repeating: 0, count: wLength)
defer {
w.deinitialize(count: wLength)
w.deallocate()
}
for i in 0..<self.variantNk {
for wordIdx in 0..<4 {
w[(4 * i) + wordIdx] = key[(4 * i) + wordIdx]
}
}
var tmp: Array<UInt8>
for i in self.variantNk..<self.variantNb * (self.variantNr + 1) {
tmp = Array<UInt8>(repeating: 0, count: 4)
for wordIdx in 0..<4 {
tmp[wordIdx] = w[4 * (i - 1) + wordIdx]
}
if (i % self.variantNk) == 0 {
tmp = subWord(rotateLeft(UInt32(bytes: tmp), by: 8).bytes(totalBytes: 4))
tmp[0] = tmp.first! ^ AES.Rcon[i / variantNk]
} else if self.variantNk > 6 && (i % self.variantNk) == 4 {
subWordInPlace(&tmp)
}
// xor array of bytes
for wordIdx in 0..<4 {
w[4 * i + wordIdx] = w[4 * (i - variantNk) + wordIdx] ^ tmp[wordIdx]
}
}
return convertExpandedKey(Array(UnsafeBufferPointer(start: w, count: wLength)))
}
@inline(__always)
private func B0(_ x: UInt32) -> UInt32 {
x & 0xff
}
@inline(__always)
private func B1(_ x: UInt32) -> UInt32 {
(x >> 8) & 0xff
}
@inline(__always)
private func B2(_ x: UInt32) -> UInt32 {
(x >> 16) & 0xff
}
@inline(__always)
private func B3(_ x: UInt32) -> UInt32 {
(x >> 24) & 0xff
}
@inline(__always) @usableFromInline
internal func F1(_ x0: UInt32, _ x1: UInt32, _ x2: UInt32, _ x3: UInt32) -> UInt32 {
var result: UInt32 = 0
result |= UInt32(self.B1(AES.T0[Int(x0 & 255)]))
result |= UInt32(self.B1(AES.T0[Int((x1 >> 8) & 255)])) << 8
result |= UInt32(self.B1(AES.T0[Int((x2 >> 16) & 255)])) << 16
result |= UInt32(self.B1(AES.T0[Int(x3 >> 24)])) << 24
return result
}
private func calculateSBox() -> (sBox: Array<UInt32>, invSBox: Array<UInt32>) {
let sboxLength = 256
let sbox = UnsafeMutablePointer<UInt32>.allocate(capacity: sboxLength)
let invsbox = UnsafeMutablePointer<UInt32>.allocate(capacity: sboxLength)
sbox.initialize(repeating: 0, count: sboxLength)
invsbox.initialize(repeating: 0, count: sboxLength)
defer {
sbox.deinitialize(count: sboxLength)
sbox.deallocate()
invsbox.deinitialize(count: sboxLength)
invsbox.deallocate()
}
sbox[0] = 0x63
var p: UInt8 = 1, q: UInt8 = 1
repeat {
p = p ^ (UInt8(truncatingIfNeeded: Int(p) << 1) ^ ((p & 0x80) == 0x80 ? 0x1b : 0))
q ^= q << 1
q ^= q << 2
q ^= q << 4
q ^= (q & 0x80) == 0x80 ? 0x09 : 0
let s = 0x63 ^ q ^ rotateLeft(q, by: 1) ^ rotateLeft(q, by: 2) ^ rotateLeft(q, by: 3) ^ rotateLeft(q, by: 4)
sbox[Int(p)] = UInt32(s)
invsbox[Int(s)] = UInt32(p)
} while p != 1
return (sBox: Array(UnsafeBufferPointer(start: sbox, count: sboxLength)), invSBox: Array(UnsafeBufferPointer(start: invsbox, count: sboxLength)))
}
}
// MARK: Cipher
extension AES: Cipher {
@inlinable
public func encrypt(_ bytes: ArraySlice<UInt8>) throws -> Array<UInt8> {
let blockSize = self.blockMode.customBlockSize ?? AES.blockSize
let chunks = bytes.batched(by: blockSize)
var oneTimeCryptor = try makeEncryptor()
var out = Array<UInt8>(reserveCapacity: bytes.count)
for chunk in chunks {
out += try oneTimeCryptor.update(withBytes: chunk, isLast: false)
}
// Padding may be added at the very end
out += try oneTimeCryptor.finish()
if self.blockMode.options.contains(.paddingRequired) && (out.count % AES.blockSize != 0) {
throw Error.dataPaddingRequired
}
return out
}
@inlinable
public func decrypt(_ bytes: ArraySlice<UInt8>) throws -> Array<UInt8> {
if self.blockMode.options.contains(.paddingRequired) && (bytes.count % AES.blockSize != 0) {
throw Error.dataPaddingRequired
}
var oneTimeCryptor = try makeDecryptor()
let chunks = bytes.batched(by: AES.blockSize)
if chunks.isEmpty {
throw Error.invalidData
}
var out = Array<UInt8>(reserveCapacity: bytes.count)
var lastIdx = chunks.startIndex
chunks.indices.formIndex(&lastIdx, offsetBy: chunks.count - 1)
// To properly remove padding, `isLast` has to be known when called with the last chunk of ciphertext
// Last chunk of ciphertext may contains padded data so next call to update(..) won't be able to remove it
for idx in chunks.indices {
out += try oneTimeCryptor.update(withBytes: chunks[idx], isLast: idx == lastIdx)
}
return out
}
}

View File

@ -1,87 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
// ASN1 Code inspired by Asn1Parser.swift from SwiftyRSA
import Foundation
/// A Partial ASN.1 (Abstract Syntax Notation 1) Encoder & Decoder Implementation.
///
/// - Note: This implementation is limited to a few core types and is not an exhaustive / complete ASN1 implementation
/// - Warning: This implementation has been developed for encoding and decoding DER & PEM files specifically. If you're using this Encoder/Decoder on other ASN1 structures, make sure you test the expected behavior appropriately.
enum ASN1 {
internal enum IDENTIFIERS: UInt8, Equatable {
case SEQUENCE = 0x30
case INTERGER = 0x02
case OBJECTID = 0x06
case NULL = 0x05
case BITSTRING = 0x03
case OCTETSTRING = 0x04
static func == (lhs: UInt8, rhs: IDENTIFIERS) -> Bool {
lhs == rhs.rawValue
}
var bytes: [UInt8] {
switch self {
case .NULL:
return [self.rawValue, 0x00]
default:
return [self.rawValue]
}
}
}
/// An ASN1 node
internal enum Node: CustomStringConvertible {
/// An array of more `ASN1.Node`s
case sequence(nodes: [Node])
/// An integer
/// - Note: This ASN1 Encoder makes no assumptions about the sign and bit order of the integers passed in. The conversion from Integer to Data is your responsiblity.
case integer(data: Data)
/// An objectIdentifier
case objectIdentifier(data: Data)
/// A null object
case null
/// A bitString
case bitString(data: Data)
/// An octetString
case octetString(data: Data)
var description: String {
ASN1.printNode(self, level: 0)
}
}
internal static func printNode(_ node: ASN1.Node, level: Int) -> String {
var str: [String] = []
let prefix = String(repeating: "\t", count: level)
switch node {
case .integer(let int):
str.append("\(prefix)Integer: \(int.toHexString())")
case .bitString(let bs):
str.append("\(prefix)BitString: \(bs.toHexString())")
case .null:
str.append("\(prefix)NULL")
case .objectIdentifier(let oid):
str.append("\(prefix)ObjectID: \(oid.toHexString())")
case .octetString(let os):
str.append("\(prefix)OctetString: \(os.toHexString())")
case .sequence(let nodes):
str.append("\(prefix)Sequence:")
nodes.forEach { str.append(printNode($0, level: level + 1)) }
}
return str.joined(separator: "\n")
}
}

View File

@ -1,107 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
// ASN1 Code inspired by Asn1Parser.swift from SwiftyRSA
import Foundation
extension ASN1 {
/// A simple ASN1 parser that will recursively iterate over a root node and return a Node tree.
/// The root node can be any of the supported nodes described in `Node`. If the parser encounters a sequence
/// it will recursively parse its children.
enum Decoder {
enum DecodingError: Error {
case noType
case invalidType(value: UInt8)
}
/// Parses ASN1 data and returns its root node.
///
/// - Parameter data: ASN1 data to parse
/// - Returns: Root ASN1 Node
/// - Throws: A DecodingError if anything goes wrong, or if an unknown node was encountered
static func decode(data: Data) throws -> Node {
let scanner = ASN1.Scanner(data: data)
let node = try decodeNode(scanner: scanner)
return node
}
/// Parses an ASN1 given an existing scanner.
/// @warning: this will modify the state (ie: position) of the provided scanner.
///
/// - Parameter scanner: Scanner to use to consume the data
/// - Returns: Parsed node
/// - Throws: A DecodingError if anything goes wrong, or if an unknown node was encountered
private static func decodeNode(scanner: ASN1.Scanner) throws -> Node {
let firstByte = try scanner.consume(length: 1).firstByte
switch firstByte {
case IDENTIFIERS.SEQUENCE.rawValue:
let length = try scanner.consumeLength()
let data = try scanner.consume(length: length)
let nodes = try decodeSequence(data: data)
return .sequence(nodes: nodes)
case IDENTIFIERS.INTERGER.rawValue:
let length = try scanner.consumeLength()
let data = try scanner.consume(length: length)
return .integer(data: data)
case IDENTIFIERS.OBJECTID.rawValue:
let length = try scanner.consumeLength()
let data = try scanner.consume(length: length)
return .objectIdentifier(data: data)
case IDENTIFIERS.NULL.rawValue:
_ = try scanner.consume(length: 1)
return .null
case IDENTIFIERS.BITSTRING.rawValue:
let length = try scanner.consumeLength()
// There's an extra byte (0x00) after the bit string length in all the keys I've encountered.
// I couldn't find a specification that referenced this extra byte, but let's consume it and discard it.
_ = try scanner.consume(length: 1)
let data = try scanner.consume(length: length - 1)
return .bitString(data: data)
case IDENTIFIERS.OCTETSTRING.rawValue:
let length = try scanner.consumeLength()
let data = try scanner.consume(length: length)
return .octetString(data: data)
default:
throw DecodingError.invalidType(value: firstByte)
}
}
/// Parses an ASN1 sequence and returns its child nodes
///
/// - Parameter data: ASN1 data
/// - Returns: A list of ASN1 nodes
/// - Throws: A DecodingError if anything goes wrong, or if an unknown node was encountered
private static func decodeSequence(data: Data) throws -> [Node] {
let scanner = ASN1.Scanner(data: data)
var nodes: [Node] = []
while !scanner.isComplete {
let node = try decodeNode(scanner: scanner)
nodes.append(node)
}
return nodes
}
}
}

View File

@ -1,69 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
// ASN1 Code inspired by Asn1Parser.swift from SwiftyRSA
import Foundation
extension ASN1 {
enum Encoder {
/// Encodes an ASN1Node into it's byte representation
///
/// - Parameter node: The Node to encode
/// - Returns: The encoded bytes as a UInt8 array
///
/// - Warning: This ASN.1 encoder has only been tested to work on certain ASN.1 data structures such as DER and PEM files. Before using this encoder for another application, ensure you test it's behavior accordingly.
/// - Warning: This encoder makes no assumptions regarding Integer bit layout and signage. The proper serialization of Integers is left up to the user.
public static func encode(_ node: ASN1.Node) -> [UInt8] {
switch node {
case .integer(let integer):
return IDENTIFIERS.INTERGER.bytes + self.asn1LengthPrefixed(integer.bytes)
case .bitString(let bits):
return IDENTIFIERS.BITSTRING.bytes + self.asn1LengthPrefixed([0x00] + bits.bytes)
case .octetString(let octet):
return IDENTIFIERS.OCTETSTRING.bytes + self.asn1LengthPrefixed(octet.bytes)
case .null:
return IDENTIFIERS.NULL.bytes
case .objectIdentifier(let oid):
return IDENTIFIERS.OBJECTID.bytes + self.asn1LengthPrefixed(oid.bytes)
case .sequence(let nodes):
return IDENTIFIERS.SEQUENCE.bytes + self.asn1LengthPrefixed( nodes.reduce(into: Array<UInt8>(), { partialResult, node in
partialResult += encode(node)
}))
}
}
/// Calculates and returns the ASN.1 length Prefix for a chunk of data
///
/// - Parameter bytes: The bytes to be length prefixed
/// - Returns: The ASN.1 length Prefix for this chuck of data (excluding the passed in data)
private static func asn1LengthPrefix(_ bytes: [UInt8]) -> [UInt8] {
if bytes.count >= 0x80 {
var lengthAsBytes = withUnsafeBytes(of: bytes.count.bigEndian, Array<UInt8>.init)
while lengthAsBytes.first == 0 { lengthAsBytes.removeFirst() }
return [0x80 + UInt8(lengthAsBytes.count)] + lengthAsBytes
} else {
return [UInt8(bytes.count)]
}
}
/// Prefixes the provided bytes with the appropriate ASN.1 length prefix
///
/// - Parameter bytes: The bytes to be length prefixed
/// - Returns: The provided bytes with the appropriate ASN.1 length prefix prepended
private static func asn1LengthPrefixed(_ bytes: [UInt8]) -> [UInt8] {
self.asn1LengthPrefix(bytes) + bytes
}
}
}

View File

@ -1,123 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
// ASN1 Scanner code is from Asn1Parser.swift from SwiftyRSA
import Foundation
extension ASN1 {
/// Simple data scanner that consumes bytes from a raw data and keeps an updated position.
internal class Scanner {
enum ScannerError: Error {
case outOfBounds
}
let data: Data
var index: Int = 0
/// Returns whether there is no more data to consume
var isComplete: Bool {
return self.index >= self.data.count
}
/// Creates a scanner with provided data
///
/// - Parameter data: Data to consume
init(data: Data) {
self.data = data
}
/// Consumes data of provided length and returns it
///
/// - Parameter length: length of the data to consume
/// - Returns: data consumed
/// - Throws: ScannerError.outOfBounds error if asked to consume too many bytes
func consume(length: Int) throws -> Data {
guard length > 0 else {
return Data()
}
guard self.index + length <= self.data.count else {
throw ScannerError.outOfBounds
}
let subdata = self.data.subdata(in: self.index..<self.index + length)
self.index += length
return subdata
}
/// Consumes a primitive, definite ASN1 length and returns its value.
///
/// See http://luca.ntop.org/Teaching/Appunti/asn1.html,
///
/// - Short form. One octet. Bit 8 has value "0" and bits 7-1 give the length.
/// - Long form. Two to 127 octets. Bit 8 of first octet has value "1" and
/// bits 7-1 give the number of additional length octets.
/// Second and following octets give the length, base 256, most significant digit first.
///
/// - Returns: Length that was consumed
/// - Throws: ScannerError.outOfBounds error if asked to consume too many bytes
func consumeLength() throws -> Int {
let lengthByte = try consume(length: 1).firstByte
// If the first byte's value is less than 0x80, it directly contains the length
// so we can return it
guard lengthByte >= 0x80 else {
return Int(lengthByte)
}
// If the first byte's value is more than 0x80, it indicates how many following bytes
// will describe the length. For instance, 0x85 indicates that 0x85 - 0x80 = 0x05 = 5
// bytes will describe the length, so we need to read the 5 next bytes and get their integer
// value to determine the length.
let nextByteCount = lengthByte - 0x80
let length = try consume(length: Int(nextByteCount))
return length.integer
}
}
}
internal extension Data {
/// Returns the first byte of the current data
var firstByte: UInt8 {
var byte: UInt8 = 0
copyBytes(to: &byte, count: MemoryLayout<UInt8>.size)
return byte
}
/// Returns the integer value of the current data.
/// - Warning: This only supports data up to 4 bytes, as we can only extract 32-bit integers.
var integer: Int {
guard count > 0 else {
return 0
}
var int: UInt32 = 0
var offset: Int32 = Int32(count - 1)
forEach { byte in
let byte32 = UInt32(byte)
let shifted = byte32 << (UInt32(offset) * 8)
int = int | shifted
offset -= 1
}
return Int(int)
}
}

View File

@ -1,155 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
extension Array {
@inlinable
init(reserveCapacity: Int) {
self = Array<Element>()
self.reserveCapacity(reserveCapacity)
}
@inlinable
var slice: ArraySlice<Element> {
self[self.startIndex ..< self.endIndex]
}
@inlinable
subscript (safe index: Index) -> Element? {
return indices.contains(index) ? self[index] : nil
}
}
extension Array where Element == UInt8 {
public init(hex: String) {
self.init(reserveCapacity: hex.unicodeScalars.lazy.underestimatedCount)
var buffer: UInt8?
var skip = hex.hasPrefix("0x") ? 2 : 0
for char in hex.unicodeScalars.lazy {
guard skip == 0 else {
skip -= 1
continue
}
guard char.value >= 48 && char.value <= 102 else {
removeAll()
return
}
let v: UInt8
let c: UInt8 = UInt8(char.value)
switch c {
case let c where c <= 57:
v = c - 48
case let c where c >= 65 && c <= 70:
v = c - 55
case let c where c >= 97:
v = c - 87
default:
removeAll()
return
}
if let b = buffer {
append(b << 4 | v)
buffer = nil
} else {
buffer = v
}
}
if let b = buffer {
append(b)
}
}
public func toHexString() -> String {
`lazy`.reduce(into: "") {
var s = String($1, radix: 16)
if s.count == 1 {
s = "0" + s
}
$0 += s
}
}
}
extension Array where Element == UInt8 {
/// split in chunks with given chunk size
@available(*, deprecated)
public func chunks(size chunksize: Int) -> Array<Array<Element>> {
var words = Array<Array<Element>>()
words.reserveCapacity(count / chunksize)
for idx in stride(from: chunksize, through: count, by: chunksize) {
words.append(Array(self[idx - chunksize ..< idx])) // slow for large table
}
let remainder = suffix(count % chunksize)
if !remainder.isEmpty {
words.append(Array(remainder))
}
return words
}
public func md5() -> [Element] {
Digest.md5(self)
}
public func sha1() -> [Element] {
Digest.sha1(self)
}
public func sha224() -> [Element] {
Digest.sha224(self)
}
public func sha256() -> [Element] {
Digest.sha256(self)
}
public func sha384() -> [Element] {
Digest.sha384(self)
}
public func sha512() -> [Element] {
Digest.sha512(self)
}
public func sha2(_ variant: SHA2.Variant) -> [Element] {
Digest.sha2(self, variant: variant)
}
public func sha3(_ variant: SHA3.Variant) -> [Element] {
Digest.sha3(self, variant: variant)
}
public func crc32(seed: UInt32? = nil, reflect: Bool = true) -> UInt32 {
Checksum.crc32(self, seed: seed, reflect: reflect)
}
public func crc32c(seed: UInt32? = nil, reflect: Bool = true) -> UInt32 {
Checksum.crc32c(self, seed: seed, reflect: reflect)
}
public func crc16(seed: UInt16? = nil) -> UInt16 {
Checksum.crc16(self, seed: seed)
}
public func encrypt(cipher: Cipher) throws -> [Element] {
try cipher.encrypt(self.slice)
}
public func decrypt(cipher: Cipher) throws -> [Element] {
try cipher.decrypt(self.slice)
}
public func authenticate<A: Authenticator>(with authenticator: A) throws -> [Element] {
try authenticator.authenticate(self)
}
}

View File

@ -1,20 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
/// Message authentication code.
public protocol Authenticator {
/// Calculate Message Authentication Code (MAC) for message.
func authenticate(_ bytes: Array<UInt8>) throws -> Array<UInt8>
}

View File

@ -1,81 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
@usableFromInline
struct BatchedCollectionIndex<Base: Collection> {
let range: Range<Base.Index>
}
extension BatchedCollectionIndex: Comparable {
@usableFromInline
static func == <BaseCollection>(lhs: BatchedCollectionIndex<BaseCollection>, rhs: BatchedCollectionIndex<BaseCollection>) -> Bool {
lhs.range.lowerBound == rhs.range.lowerBound
}
@usableFromInline
static func < <BaseCollection>(lhs: BatchedCollectionIndex<BaseCollection>, rhs: BatchedCollectionIndex<BaseCollection>) -> Bool {
lhs.range.lowerBound < rhs.range.lowerBound
}
}
protocol BatchedCollectionType: Collection {
associatedtype Base: Collection
}
@usableFromInline
struct BatchedCollection<Base: Collection>: Collection {
let base: Base
let size: Int
@usableFromInline
init(base: Base, size: Int) {
self.base = base
self.size = size
}
@usableFromInline
typealias Index = BatchedCollectionIndex<Base>
private func nextBreak(after idx: Base.Index) -> Base.Index {
self.base.index(idx, offsetBy: self.size, limitedBy: self.base.endIndex) ?? self.base.endIndex
}
@usableFromInline
var startIndex: Index {
Index(range: self.base.startIndex..<self.nextBreak(after: self.base.startIndex))
}
@usableFromInline
var endIndex: Index {
Index(range: self.base.endIndex..<self.base.endIndex)
}
@usableFromInline
func index(after idx: Index) -> Index {
Index(range: idx.range.upperBound..<self.nextBreak(after: idx.range.upperBound))
}
@usableFromInline
subscript(idx: Index) -> Base.SubSequence {
self.base[idx.range]
}
}
extension Collection {
@inlinable
func batched(by size: Int) -> BatchedCollection<Self> {
BatchedCollection(base: self, size: size)
}
}

View File

@ -1,26 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
public enum Bit: Int {
case zero
case one
}
extension Bit {
@inlinable
func inverted() -> Bit {
self == .zero ? .one : .zero
}
}

View File

@ -1,18 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
protocol BlockCipher: Cipher {
static var blockSize: Int { get }
}

View File

@ -1,98 +0,0 @@
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
public class BlockDecryptor: Cryptor, Updatable {
@usableFromInline
let blockSize: Int
@usableFromInline
let padding: Padding
@usableFromInline
var worker: CipherModeWorker
@usableFromInline
var accumulated = Array<UInt8>()
@usableFromInline
init(blockSize: Int, padding: Padding, _ worker: CipherModeWorker) throws {
self.blockSize = blockSize
self.padding = padding
self.worker = worker
}
@inlinable
public func update(withBytes bytes: ArraySlice<UInt8>, isLast: Bool = false) throws -> Array<UInt8> {
self.accumulated += bytes
// If a worker (eg GCM) can combine ciphertext + tag
// we need to remove tag from the ciphertext.
if !isLast && self.accumulated.count < self.blockSize + self.worker.additionalBufferSize {
return []
}
let accumulatedWithoutSuffix: Array<UInt8>
if self.worker.additionalBufferSize > 0 {
// FIXME: how slow is that?
accumulatedWithoutSuffix = Array(self.accumulated.prefix(self.accumulated.count - self.worker.additionalBufferSize))
} else {
accumulatedWithoutSuffix = self.accumulated
}
var processedBytesCount = 0
var plaintext = Array<UInt8>(reserveCapacity: accumulatedWithoutSuffix.count)
// Processing in a block-size manner. It's good for block modes, but bad for stream modes.
for var chunk in accumulatedWithoutSuffix.batched(by: self.blockSize) {
if isLast || (accumulatedWithoutSuffix.count - processedBytesCount) >= blockSize {
let isLastChunk = processedBytesCount + chunk.count == accumulatedWithoutSuffix.count
if isLast, isLastChunk, var finalizingWorker = worker as? FinalizingDecryptModeWorker {
chunk = try finalizingWorker.willDecryptLast(bytes: chunk + accumulated.suffix(worker.additionalBufferSize)) // tag size
}
if !chunk.isEmpty {
plaintext += worker.decrypt(block: chunk)
}
if isLast, isLastChunk, var finalizingWorker = worker as? FinalizingDecryptModeWorker {
plaintext = Array(try finalizingWorker.didDecryptLast(bytes: plaintext.slice))
}
processedBytesCount += chunk.count
}
}
accumulated.removeFirst(processedBytesCount) // super-slow
if isLast {
if accumulatedWithoutSuffix.isEmpty, var finalizingWorker = worker as? FinalizingDecryptModeWorker {
try finalizingWorker.willDecryptLast(bytes: self.accumulated.suffix(self.worker.additionalBufferSize))
plaintext = Array(try finalizingWorker.didDecryptLast(bytes: plaintext.slice))
}
plaintext = self.padding.remove(from: plaintext, blockSize: self.blockSize)
}
return plaintext
}
public func seek(to position: Int) throws {
guard var worker = self.worker as? SeekableModeWorker else {
fatalError("Not supported")
}
try worker.seek(to: position)
self.worker = worker
accumulated = []
}
}

View File

@ -1,62 +0,0 @@
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
@usableFromInline
final class BlockEncryptor: Cryptor, Updatable {
private let blockSize: Int
private var worker: CipherModeWorker
private let padding: Padding
// Accumulated bytes. Not all processed bytes.
private var accumulated = Array<UInt8>(reserveCapacity: 16)
private var lastBlockRemainder = 0
@usableFromInline
init(blockSize: Int, padding: Padding, _ worker: CipherModeWorker) throws {
self.blockSize = blockSize
self.padding = padding
self.worker = worker
}
// MARK: Updatable
public func update(withBytes bytes: ArraySlice<UInt8>, isLast: Bool) throws -> Array<UInt8> {
self.accumulated += bytes
if isLast {
self.accumulated = self.padding.add(to: self.accumulated, blockSize: self.blockSize)
}
var encrypted = Array<UInt8>(reserveCapacity: accumulated.count)
for chunk in self.accumulated.batched(by: self.blockSize) {
if isLast || chunk.count == self.blockSize {
encrypted += self.worker.encrypt(block: chunk)
}
}
// Stream encrypts all, so it removes all elements
self.accumulated.removeFirst(encrypted.count)
if var finalizingWorker = worker as? FinalizingEncryptModeWorker, isLast == true {
encrypted = Array(try finalizingWorker.finalize(encrypt: encrypted.slice))
}
return encrypted
}
@usableFromInline
func seek(to: Int) throws {
fatalError("Not supported")
}
}

View File

@ -1,26 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
public typealias CipherOperationOnBlock = (_ block: ArraySlice<UInt8>) -> Array<UInt8>?
public protocol BlockMode {
var options: BlockModeOption { get }
//TODO: doesn't have to be public
@inlinable func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock, encryptionOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker
var customBlockSize: Int? { get }
}
typealias StreamMode = BlockMode

View File

@ -1,34 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
public struct BlockModeOption: OptionSet {
public let rawValue: Int
public init(rawValue: Int) {
self.rawValue = rawValue
}
@usableFromInline
static let none = BlockModeOption(rawValue: 1 << 0)
@usableFromInline
static let initializationVectorRequired = BlockModeOption(rawValue: 1 << 1)
@usableFromInline
static let paddingRequired = BlockModeOption(rawValue: 1 << 2)
@usableFromInline
static let useEncryptToDecrypt = BlockModeOption(rawValue: 1 << 3)
}

View File

@ -1,76 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
// Cipher-block chaining (CBC)
//
public struct CBC: BlockMode {
public enum Error: Swift.Error {
/// Invalid IV
case invalidInitializationVector
}
public let options: BlockModeOption = [.initializationVectorRequired, .paddingRequired]
private let iv: Array<UInt8>
public let customBlockSize: Int? = nil
public init(iv: Array<UInt8>) {
self.iv = iv
}
public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock, encryptionOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker {
if self.iv.count != blockSize {
throw Error.invalidInitializationVector
}
return CBCModeWorker(blockSize: blockSize, iv: self.iv.slice, cipherOperation: cipherOperation)
}
}
struct CBCModeWorker: BlockModeWorker {
let cipherOperation: CipherOperationOnBlock
var blockSize: Int
let additionalBufferSize: Int = 0
private let iv: ArraySlice<UInt8>
private var prev: ArraySlice<UInt8>?
@inlinable
init(blockSize: Int, iv: ArraySlice<UInt8>, cipherOperation: @escaping CipherOperationOnBlock) {
self.blockSize = blockSize
self.iv = iv
self.cipherOperation = cipherOperation
}
@inlinable
mutating func encrypt(block plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
guard let ciphertext = cipherOperation(xor(prev ?? iv, plaintext)) else {
return Array(plaintext)
}
self.prev = ciphertext.slice
return ciphertext
}
@inlinable
mutating func decrypt(block ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
guard let plaintext = cipherOperation(ciphertext) else {
return Array(ciphertext)
}
let result: Array<UInt8> = xor(prev ?? self.iv, plaintext)
self.prev = ciphertext
return result
}
}

View File

@ -1,367 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
// CCM mode combines the well known CBC-MAC with the well known counter mode of encryption.
// https://tools.ietf.org/html/rfc3610
// https://csrc.nist.gov/publications/detail/sp/800-38c/final
#if canImport(Darwin)
import Darwin
#elseif canImport(Glibc)
import Glibc
#elseif canImport(ucrt)
import ucrt
#elseif canImport(WASILibc)
import WASILibc
#endif
/// Counter with Cipher Block Chaining-Message Authentication Code
public struct CCM: StreamMode {
public enum Error: Swift.Error {
/// Invalid IV
case invalidInitializationVector
case invalidParameter
case fail
}
public let options: BlockModeOption = [.initializationVectorRequired, .useEncryptToDecrypt]
private let nonce: Array<UInt8>
private let additionalAuthenticatedData: Array<UInt8>?
private let tagLength: Int
private let messageLength: Int // total message length. need to know in advance
public let customBlockSize: Int? = nil
// `authenticationTag` nil for encryption, known tag for decryption
/// For encryption, the value is set at the end of the encryption.
/// For decryption, this is a known Tag to validate against.
public var authenticationTag: Array<UInt8>?
/// Initialize CCM
///
/// - Parameters:
/// - iv: Initialization vector. Nonce. Valid length between 7 and 13 bytes.
/// - tagLength: Authentication tag length, in bytes. Value of {4, 6, 8, 10, 12, 14, 16}.
/// - messageLength: Plaintext message length (excluding tag if attached). Length have to be provided in advance.
/// - additionalAuthenticatedData: Additional authenticated data.
public init(iv: Array<UInt8>, tagLength: Int, messageLength: Int, additionalAuthenticatedData: Array<UInt8>? = nil) {
self.nonce = iv
self.tagLength = tagLength
self.additionalAuthenticatedData = additionalAuthenticatedData
self.messageLength = messageLength // - tagLength
}
/// Initialize CCM
///
/// - Parameters:
/// - iv: Initialization vector. Nonce. Valid length between 7 and 13 bytes.
/// - tagLength: Authentication tag length, in bytes. Value of {4, 6, 8, 10, 12, 14, 16}.
/// - messageLength: Plaintext message length (excluding tag if attached). Length have to be provided in advance.
/// - authenticationTag: Authentication Tag value if not concatenated to ciphertext.
/// - additionalAuthenticatedData: Additional authenticated data.
public init(iv: Array<UInt8>, tagLength: Int, messageLength: Int, authenticationTag: Array<UInt8>, additionalAuthenticatedData: Array<UInt8>? = nil) {
self.init(iv: iv, tagLength: tagLength, messageLength: messageLength, additionalAuthenticatedData: additionalAuthenticatedData)
self.authenticationTag = authenticationTag
}
public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock, encryptionOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker {
if self.nonce.isEmpty {
throw Error.invalidInitializationVector
}
return CCMModeWorker(blockSize: blockSize, nonce: self.nonce.slice, messageLength: self.messageLength, additionalAuthenticatedData: self.additionalAuthenticatedData, tagLength: self.tagLength, cipherOperation: cipherOperation)
}
}
class CCMModeWorker: StreamModeWorker, SeekableModeWorker, CounterModeWorker, FinalizingEncryptModeWorker, FinalizingDecryptModeWorker {
typealias Counter = Int
var counter = 0
let cipherOperation: CipherOperationOnBlock
let blockSize: Int
private let tagLength: Int
private let messageLength: Int // total message length. need to know in advance
private let q: UInt8
let additionalBufferSize: Int
private var keystreamPosIdx = 0
private let nonce: Array<UInt8>
private var last_y: ArraySlice<UInt8> = []
private var keystream: Array<UInt8> = []
// Known Tag used to validate during decryption
private var expectedTag: Array<UInt8>?
public enum Error: Swift.Error {
case invalidParameter
}
init(blockSize: Int, nonce: ArraySlice<UInt8>, messageLength: Int, additionalAuthenticatedData: [UInt8]?, expectedTag: Array<UInt8>? = nil, tagLength: Int, cipherOperation: @escaping CipherOperationOnBlock) {
self.blockSize = 16 // CCM is defined for 128 block size
self.tagLength = tagLength
self.additionalBufferSize = tagLength
self.messageLength = messageLength
self.expectedTag = expectedTag
self.cipherOperation = cipherOperation
self.nonce = Array(nonce)
self.q = UInt8(15 - nonce.count) // n = 15-q
let hasAssociatedData = additionalAuthenticatedData != nil && !additionalAuthenticatedData!.isEmpty
self.processControlInformation(nonce: self.nonce, tagLength: tagLength, hasAssociatedData: hasAssociatedData)
if let aad = additionalAuthenticatedData, hasAssociatedData {
self.process(aad: aad)
}
}
// For the very first time setup new IV (aka y0) from the block0
private func processControlInformation(nonce: [UInt8], tagLength: Int, hasAssociatedData: Bool) {
let block0 = try! format(nonce: nonce, Q: UInt32(self.messageLength), q: self.q, t: UInt8(tagLength), hasAssociatedData: hasAssociatedData).slice
let y0 = self.cipherOperation(block0)!.slice
self.last_y = y0
}
private func process(aad: [UInt8]) {
let encodedAAD = format(aad: aad)
for block_i in encodedAAD.batched(by: 16) {
let y_i = self.cipherOperation(xor(block_i, self.last_y))!.slice
self.last_y = y_i
}
}
private func S(i: Int) throws -> [UInt8] {
let ctr = try format(counter: i, nonce: nonce, q: q)
return self.cipherOperation(ctr.slice)!
}
@inlinable
func seek(to position: Int) throws {
self.counter = position
self.keystream = try self.S(i: position)
let offset = position % self.blockSize
self.keystreamPosIdx = offset
}
func encrypt(block plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
var result = Array<UInt8>(reserveCapacity: plaintext.count)
var processed = 0
while processed < plaintext.count {
// Need a full block here to update keystream and do CBC
if self.keystream.isEmpty || self.keystreamPosIdx == self.blockSize {
// y[i], where i is the counter. Can encrypt 1 block at a time
self.counter += 1
guard let S = try? S(i: counter) else { return Array(plaintext) }
let plaintextP = addPadding(Array(plaintext), blockSize: blockSize)
guard let y = cipherOperation(xor(last_y, plaintextP)) else { return Array(plaintext) }
self.last_y = y.slice
self.keystream = S
self.keystreamPosIdx = 0
}
let xored: Array<UInt8> = xor(plaintext[plaintext.startIndex.advanced(by: processed)...], keystream[keystreamPosIdx...])
keystreamPosIdx += xored.count
processed += xored.count
result += xored
}
return result
}
@inlinable
func finalize(encrypt ciphertext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {
// concatenate T at the end
guard let S0 = try? S(i: 0) else { return ciphertext }
let computedTag = xor(last_y.prefix(self.tagLength), S0) as ArraySlice<UInt8>
return ciphertext + computedTag
}
// Decryption is stream
// CBC is block
private var accumulatedPlaintext: [UInt8] = []
func decrypt(block ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
var output = Array<UInt8>(reserveCapacity: ciphertext.count)
do {
var currentCounter = self.counter
var processed = 0
while processed < ciphertext.count {
// Need a full block here to update keystream and do CBC
// New keystream for a new block
if self.keystream.isEmpty || self.keystreamPosIdx == self.blockSize {
currentCounter += 1
guard let S = try? S(i: currentCounter) else { return Array(ciphertext) }
self.keystream = S
self.keystreamPosIdx = 0
}
let xored: Array<UInt8> = xor(ciphertext[ciphertext.startIndex.advanced(by: processed)...], keystream[keystreamPosIdx...]) // plaintext
keystreamPosIdx += xored.count
processed += xored.count
output += xored
self.counter = currentCounter
}
}
// Accumulate plaintext for the MAC calculations at the end.
// It would be good to process it together though, here.
self.accumulatedPlaintext += output
// Shouldn't return plaintext until validate tag.
// With incremental update, can't validate tag until all block are processed.
return output
}
@inlinable
func finalize(decrypt plaintext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {
// concatenate T at the end
let computedTag = Array(last_y.prefix(self.tagLength))
guard let expectedTag = self.expectedTag, expectedTag == computedTag else {
throw CCM.Error.fail
}
return plaintext
}
@discardableResult
func willDecryptLast(bytes ciphertext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {
// get tag of additionalBufferSize size
// `ciphertext` contains at least additionalBufferSize bytes
// overwrite expectedTag property used later for verification
guard let S0 = try? S(i: 0) else { return ciphertext }
self.expectedTag = xor(ciphertext.suffix(self.tagLength), S0) as [UInt8]
return ciphertext[ciphertext.startIndex..<ciphertext.endIndex.advanced(by: -Swift.min(tagLength, ciphertext.count))]
}
@inlinable
func didDecryptLast(bytes plaintext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {
// Calculate Tag, from the last CBC block, for accumulated plaintext.
var processed = 0
for block in self.accumulatedPlaintext.batched(by: self.blockSize) {
let blockP = addPadding(Array(block), blockSize: blockSize)
guard let y = cipherOperation(xor(last_y, blockP)) else { return plaintext }
self.last_y = y.slice
processed += block.count
}
self.accumulatedPlaintext.removeFirst(processed)
return plaintext
}
}
// Q - octet length of P
// q - octet length of Q. Maximum length (in octets) of payload. An element of {2,3,4,5,6,7,8}
// t - octet length of T (MAC length). An element of {4,6,8,10,12,14,16}
private func format(nonce N: [UInt8], Q: UInt32, q: UInt8, t: UInt8, hasAssociatedData: Bool) throws -> [UInt8] {
var flags0: UInt8 = 0
if hasAssociatedData {
// 7 bit
flags0 |= (1 << 6)
}
// 6,5,4 bit is t in 3 bits
flags0 |= (((t - 2) / 2) & 0x07) << 3
// 3,2,1 bit is q in 3 bits
flags0 |= ((q - 1) & 0x07) << 0
var block0: [UInt8] = Array<UInt8>(repeating: 0, count: 16)
block0[0] = flags0
// N in 1...(15-q) octets, n = 15-q
// n is an element of {7,8,9,10,11,12,13}
let n = 15 - Int(q)
guard (n + Int(q)) == 15 else {
// n+q == 15
throw CCMModeWorker.Error.invalidParameter
}
block0[1...n] = N[0...(n - 1)]
// Q in (16-q)...15 octets
block0[(16 - Int(q))...15] = Q.bytes(totalBytes: Int(q)).slice
return block0
}
/// Formatting of the Counter Blocks. Ctr[i]
/// The counter generation function.
/// Q - octet length of P
/// q - octet length of Q. Maximum length (in octets) of payload. An element of {2,3,4,5,6,7,8}
private func format(counter i: Int, nonce N: [UInt8], q: UInt8) throws -> [UInt8] {
var flags0: UInt8 = 0
// bit 8,7 is Reserved
// bit 4,5,6 shall be set to 0
// 3,2,1 bit is q in 3 bits
flags0 |= ((q - 1) & 0x07) << 0
var block = Array<UInt8>(repeating: 0, count: 16) // block[0]
block[0] = flags0
// N in 1...(15-q) octets, n = 15-q
// n is an element of {7,8,9,10,11,12,13}
let n = 15 - Int(q)
guard (n + Int(q)) == 15 else {
// n+q == 15
throw CCMModeWorker.Error.invalidParameter
}
block[1...n] = N[0...(n - 1)]
// [i]8q in (16-q)...15 octets
block[(16 - Int(q))...15] = i.bytes(totalBytes: Int(q)).slice
return block
}
/// Resulting can be partitioned into 16-octet blocks
private func format(aad: [UInt8]) -> [UInt8] {
let a = aad.count
switch Double(a) {
case 0..<65280: // 2^16-2^8
// [a]16
return addPadding(a.bytes(totalBytes: 2) + aad, blockSize: 16)
case 65280..<4_294_967_296: // 2^32
// [a]32
return addPadding([0xFF, 0xFE] + a.bytes(totalBytes: 4) + aad, blockSize: 16)
case 4_294_967_296..<pow(2, 64): // 2^64
// [a]64
return addPadding([0xFF, 0xFF] + a.bytes(totalBytes: 8) + aad, blockSize: 16)
default:
// Reserved
return addPadding(aad, blockSize: 16)
}
}
// If data is not a multiple of block size bytes long then the remainder is zero padded
// Note: It's similar to ZeroPadding, but it's not the same.
private func addPadding(_ bytes: Array<UInt8>, blockSize: Int) -> Array<UInt8> {
if bytes.isEmpty {
return Array<UInt8>(repeating: 0, count: blockSize)
}
let remainder = bytes.count % blockSize
if remainder == 0 {
return bytes
}
let paddingCount = blockSize - remainder
if paddingCount > 0 {
return bytes + Array<UInt8>(repeating: 0, count: paddingCount)
}
return bytes
}

View File

@ -1,102 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
// Cipher feedback (CFB)
//
public struct CFB: BlockMode {
public enum Error: Swift.Error {
/// Invalid IV
case invalidInitializationVector
}
public enum SegmentSize: Int {
case cfb8 = 1 // Encrypt byte per byte
case cfb128 = 16 // Encrypt 16 bytes per 16 bytes (default)
}
public let options: BlockModeOption = [.initializationVectorRequired, .useEncryptToDecrypt]
private let iv: Array<UInt8>
private let segmentSize: SegmentSize
public let customBlockSize: Int?
public init(iv: Array<UInt8>, segmentSize: SegmentSize = .cfb128) {
self.iv = iv
self.segmentSize = segmentSize
self.customBlockSize = segmentSize.rawValue
}
public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock, encryptionOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker {
if !(self.iv.count == blockSize || (segmentSize == .cfb8 && self.iv.count == AES.blockSize)) {
throw Error.invalidInitializationVector
}
return CFBModeWorker(blockSize: blockSize, iv: self.iv.slice, segmentSize: segmentSize, cipherOperation: cipherOperation)
}
}
struct CFBModeWorker: BlockModeWorker {
let cipherOperation: CipherOperationOnBlock
let blockSize: Int
let additionalBufferSize: Int = 0
private let iv: ArraySlice<UInt8>
private let segmentSize: CFB.SegmentSize
private var prev: ArraySlice<UInt8>?
init(blockSize: Int, iv: ArraySlice<UInt8>, segmentSize: CFB.SegmentSize, cipherOperation: @escaping CipherOperationOnBlock) {
self.blockSize = blockSize
self.iv = iv
self.segmentSize = segmentSize
self.cipherOperation = cipherOperation
}
@inlinable
mutating func encrypt(block plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
switch segmentSize {
case .cfb128:
guard let ciphertext = cipherOperation(prev ?? iv) else {
return Array(plaintext)
}
self.prev = xor(plaintext, ciphertext.slice)
return Array(self.prev ?? [])
case .cfb8:
guard let ciphertext = cipherOperation(prev ?? iv) else {
return Array(plaintext)
}
let result = [Array(plaintext)[0] ^ Array(ciphertext)[0]]
self.prev = Array((prev ?? iv).dropFirst()) + [result[0]]
return result
}
}
@inlinable
mutating func decrypt(block ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
switch segmentSize {
case .cfb128:
guard let plaintext = cipherOperation(prev ?? iv) else {
return Array(ciphertext)
}
let result: Array<UInt8> = xor(plaintext, ciphertext)
prev = ciphertext
return result
case .cfb8:
guard let plaintext = cipherOperation(prev ?? iv) else {
return Array(ciphertext)
}
self.prev = Array((prev ?? iv).dropFirst()) + [Array(ciphertext)[0]]
return [Array(ciphertext)[0] ^ Array(plaintext)[0]]
}
}
}

View File

@ -1,138 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
// Counter (CTR)
public struct CTR: StreamMode {
public enum Error: Swift.Error {
/// Invalid IV
case invalidInitializationVector
}
public let options: BlockModeOption = [.initializationVectorRequired, .useEncryptToDecrypt]
private let iv: Array<UInt8>
private let counter: Int
public let customBlockSize: Int? = nil
public init(iv: Array<UInt8>, counter: Int = 0) {
self.iv = iv
self.counter = counter
}
public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock, encryptionOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker {
if self.iv.count != blockSize {
throw Error.invalidInitializationVector
}
return CTRModeWorker(blockSize: blockSize, iv: self.iv.slice, counter: self.counter, cipherOperation: cipherOperation)
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct CTRModeWorker: StreamModeWorker, SeekableModeWorker, CounterModeWorker {
typealias Counter = CTRCounter
final class CTRCounter {
private let constPrefix: Array<UInt8>
private var value: UInt64
//TODO: make it an updatable value, computing is too slow
var bytes: Array<UInt8> {
self.constPrefix + self.value.bytes()
}
@inlinable
init(_ initialValue: Array<UInt8>) {
let halfIndex = initialValue.startIndex.advanced(by: initialValue.count / 2)
self.constPrefix = Array(initialValue[initialValue.startIndex..<halfIndex])
let suffixBytes = Array(initialValue[halfIndex...])
value = UInt64(bytes: suffixBytes)
}
convenience init(nonce: Array<UInt8>, startAt index: Int) {
self.init(buildCounterValue(nonce, counter: UInt64(index)))
}
static func += (lhs: CTRCounter, rhs: Int) {
lhs.value += UInt64(rhs)
}
}
let cipherOperation: CipherOperationOnBlock
let additionalBufferSize: Int = 0
let iv: Array<UInt8>
var counter: CTRCounter
private let blockSize: Int
// The same keystream is used for the block length plaintext
// As new data is added, keystream suffix is used to xor operation.
private var keystream: Array<UInt8>
private var keystreamPosIdx = 0
init(blockSize: Int, iv: ArraySlice<UInt8>, counter: Int, cipherOperation: @escaping CipherOperationOnBlock) {
self.cipherOperation = cipherOperation
self.blockSize = blockSize
self.iv = Array(iv)
// the first keystream is calculated from the nonce = initial value of counter
self.counter = CTRCounter(nonce: Array(iv), startAt: counter)
self.keystream = Array(cipherOperation(self.counter.bytes.slice)!)
}
@inlinable
mutating func seek(to position: Int) throws {
let offset = position % self.blockSize
self.counter = CTRCounter(nonce: self.iv, startAt: position / self.blockSize)
self.keystream = Array(self.cipherOperation(self.counter.bytes.slice)!)
self.keystreamPosIdx = offset
}
// plaintext is at most blockSize long
@inlinable
mutating func encrypt(block plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
var result = Array<UInt8>(reserveCapacity: plaintext.count)
var processed = 0
while processed < plaintext.count {
// Update keystream
if self.keystreamPosIdx == self.blockSize {
self.counter += 1
self.keystream = Array(self.cipherOperation(self.counter.bytes.slice)!)
self.keystreamPosIdx = 0
}
let xored: Array<UInt8> = xor(plaintext[plaintext.startIndex.advanced(by: processed)...], keystream[keystreamPosIdx...])
keystreamPosIdx += xored.count
processed += xored.count
result += xored
}
return result
}
mutating func decrypt(block ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
self.encrypt(block: ciphertext)
}
}
private func buildCounterValue(_ iv: Array<UInt8>, counter: UInt64) -> Array<UInt8> {
let noncePartLen = iv.count / 2
let noncePrefix = iv[iv.startIndex..<iv.startIndex.advanced(by: noncePartLen)]
let nonceSuffix = iv[iv.startIndex.advanced(by: noncePartLen)..<iv.startIndex.advanced(by: iv.count)]
let c = UInt64(bytes: nonceSuffix) + counter
return noncePrefix + c.bytes()
}

View File

@ -1,64 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
public protocol CipherModeWorker {
var cipherOperation: CipherOperationOnBlock { get }
// Additional space needed when incrementally process data
// eg. for GCM combined mode
var additionalBufferSize: Int { get }
@inlinable
mutating func encrypt(block plaintext: ArraySlice<UInt8>) -> Array<UInt8>
@inlinable
mutating func decrypt(block ciphertext: ArraySlice<UInt8>) -> Array<UInt8>
}
/// Block workers use `BlockEncryptor`
public protocol BlockModeWorker: CipherModeWorker {
var blockSize: Int { get }
}
public protocol CounterModeWorker: CipherModeWorker {
associatedtype Counter
var counter: Counter { get set }
}
public protocol SeekableModeWorker: CipherModeWorker {
mutating func seek(to position: Int) throws
}
/// Stream workers use `StreamEncryptor`
public protocol StreamModeWorker: CipherModeWorker {
}
public protocol FinalizingEncryptModeWorker: CipherModeWorker {
// Any final calculations, eg. calculate tag
// Called after the last block is encrypted
mutating func finalize(encrypt ciphertext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8>
}
public protocol FinalizingDecryptModeWorker: CipherModeWorker {
// Called before decryption, hence input is ciphertext.
// ciphertext is either a last block, or a tag (for stream workers)
@discardableResult
mutating func willDecryptLast(bytes ciphertext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8>
// Called after decryption, hence input is ciphertext
mutating func didDecryptLast(bytes plaintext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8>
// Any final calculations, eg. calculate tag
// Called after the last block is encrypted
mutating func finalize(decrypt plaintext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8>
}

View File

@ -1,53 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
// Electronic codebook (ECB)
//
public struct ECB: BlockMode {
public let options: BlockModeOption = .paddingRequired
public let customBlockSize: Int? = nil
public init() {
}
public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock, encryptionOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker {
ECBModeWorker(blockSize: blockSize, cipherOperation: cipherOperation)
}
}
struct ECBModeWorker: BlockModeWorker {
typealias Element = Array<UInt8>
let cipherOperation: CipherOperationOnBlock
let blockSize: Int
let additionalBufferSize: Int = 0
init(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock) {
self.blockSize = blockSize
self.cipherOperation = cipherOperation
}
@inlinable
mutating func encrypt(block plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
guard let ciphertext = cipherOperation(plaintext) else {
return Array(plaintext)
}
return ciphertext
}
mutating func decrypt(block ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
self.encrypt(block: ciphertext)
}
}

View File

@ -1,374 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
// Galois/Counter Mode (GCM)
// https://csrc.nist.gov/publications/detail/sp/800-38d/final
// ref: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.694.695&rep=rep1&type=pdf
//
public final class GCM: BlockMode {
public enum Mode {
/// In combined mode, the authentication tag is directly appended to the encrypted message. This is usually what you want.
case combined
/// Some applications may need to store the authentication tag and the encrypted message at different locations.
case detached
}
public let options: BlockModeOption = [.initializationVectorRequired, .useEncryptToDecrypt]
public enum Error: Swift.Error {
/// Invalid IV
case invalidInitializationVector
/// Special symbol FAIL that indicates that the inputs are not authentic.
case fail
}
private let iv: Array<UInt8>
private let additionalAuthenticatedData: Array<UInt8>?
private let mode: Mode
public let customBlockSize: Int? = nil
/// Length of authentication tag, in bytes.
/// For encryption, the value is given as init parameter.
/// For decryption, the length of given authentication tag is used.
private let tagLength: Int
// `authenticationTag` nil for encryption, known tag for decryption
/// For encryption, the value is set at the end of the encryption.
/// For decryption, this is a known Tag to validate against.
public var authenticationTag: Array<UInt8>?
// encrypt
/// Possible tag lengths: 4,8,12,13,14,15,16
public init(iv: Array<UInt8>, additionalAuthenticatedData: Array<UInt8>? = nil, tagLength: Int = 16, mode: Mode = .detached) {
self.iv = iv
self.additionalAuthenticatedData = additionalAuthenticatedData
self.mode = mode
self.tagLength = tagLength
}
// decrypt
public convenience init(iv: Array<UInt8>, authenticationTag: Array<UInt8>, additionalAuthenticatedData: Array<UInt8>? = nil, mode: Mode = .detached) {
self.init(iv: iv, additionalAuthenticatedData: additionalAuthenticatedData, tagLength: authenticationTag.count, mode: mode)
self.authenticationTag = authenticationTag
}
public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock, encryptionOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker {
if self.iv.isEmpty {
throw Error.invalidInitializationVector
}
let worker = GCMModeWorker(iv: iv.slice, aad: self.additionalAuthenticatedData?.slice, expectedTag: self.authenticationTag, tagLength: self.tagLength, mode: self.mode, cipherOperation: cipherOperation)
worker.didCalculateTag = { [weak self] tag in
self?.authenticationTag = tag
}
return worker
}
}
// MARK: - Worker
final class GCMModeWorker: BlockModeWorker, FinalizingEncryptModeWorker, FinalizingDecryptModeWorker {
let cipherOperation: CipherOperationOnBlock
// Callback called when authenticationTag is ready
var didCalculateTag: ((Array<UInt8>) -> Void)?
private let tagLength: Int
// GCM nonce is 96-bits by default. It's the most effective length for the IV
private static let nonceSize = 12
// GCM is designed for 128-bit ciphers like AES (but not really for Blowfish). 64-bit mode is not implemented.
let blockSize = 16 // 128 bit
let additionalBufferSize: Int
private let iv: ArraySlice<UInt8>
private let mode: GCM.Mode
private var counter: UInt128
private let eky0: UInt128 // move to GF?
private let h: UInt128
// Additional authenticated data
private let aad: ArraySlice<UInt8>?
// Known Tag used to validate during decryption
private var expectedTag: Array<UInt8>?
// Note: need new worker to reset instance
// Use empty aad if not specified. AAD is optional.
private lazy var gf: GF = {
if let aad = aad {
return GF(aad: Array(aad), h: h, blockSize: blockSize)
}
return GF(aad: [UInt8](), h: h, blockSize: blockSize)
}()
init(iv: ArraySlice<UInt8>, aad: ArraySlice<UInt8>? = nil, expectedTag: Array<UInt8>? = nil, tagLength: Int, mode: GCM.Mode, cipherOperation: @escaping CipherOperationOnBlock) {
self.cipherOperation = cipherOperation
self.iv = iv
self.mode = mode
self.aad = aad
self.expectedTag = expectedTag
self.tagLength = tagLength
self.h = UInt128(cipherOperation(Array<UInt8>(repeating: 0, count: self.blockSize).slice)!) // empty block
if mode == .combined {
self.additionalBufferSize = tagLength
} else {
self.additionalBufferSize = 0
}
// Assume nonce is 12 bytes long, otherwise initial counter would be calulated from GHASH
// counter = GF.ghash(aad: [UInt8](), ciphertext: nonce)
if iv.count == GCMModeWorker.nonceSize {
self.counter = makeCounter(nonce: Array(self.iv))
} else {
self.counter = GF.ghash(h: self.h, aad: [UInt8](), ciphertext: Array(iv), blockSize: self.blockSize)
}
// Set constants
self.eky0 = UInt128(cipherOperation(self.counter.bytes.slice)!)
}
func encrypt(block plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
self.counter = incrementCounter(self.counter)
guard let ekyN = cipherOperation(counter.bytes.slice) else {
return Array(plaintext)
}
// plaintext block ^ ek1
let ciphertext = xor(plaintext, ekyN) as Array<UInt8>
// update ghash incrementally
gf.ghashUpdate(block: ciphertext)
return Array(ciphertext)
}
@inlinable
func finalize(encrypt ciphertext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {
// Calculate MAC tag.
let ghash = self.gf.ghashFinish()
let tag = Array((ghash ^ self.eky0).bytes.prefix(self.tagLength))
// Notify handler
self.didCalculateTag?(tag)
switch self.mode {
case .combined:
return (ciphertext + tag).slice
case .detached:
return ciphertext
}
}
@inlinable
func decrypt(block ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
self.counter = incrementCounter(self.counter)
// update ghash incrementally
self.gf.ghashUpdate(block: Array(ciphertext))
guard let ekN = cipherOperation(counter.bytes.slice) else {
return Array(ciphertext)
}
// ciphertext block ^ ek1
let plaintext = xor(ciphertext, ekN) as Array<UInt8>
return plaintext
}
// The authenticated decryption operation has five inputs: K, IV , C, A, and T. It has only a single
// output, either the plaintext value P or a special symbol FAIL that indicates that the inputs are not
// authentic.
@discardableResult
func willDecryptLast(bytes ciphertext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {
// Validate tag
switch self.mode {
case .combined:
// overwrite expectedTag property used later for verification
self.expectedTag = Array(ciphertext.suffix(self.tagLength))
return ciphertext[ciphertext.startIndex..<ciphertext.endIndex.advanced(by: -Swift.min(tagLength, ciphertext.count))]
case .detached:
return ciphertext
}
}
@inlinable
func didDecryptLast(bytes plaintext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {
// Calculate MAC tag.
let ghash = self.gf.ghashFinish()
let computedTag = Array((ghash ^ self.eky0).bytes.prefix(self.tagLength))
// Validate tag
guard let expectedTag = self.expectedTag, computedTag == expectedTag else {
throw GCM.Error.fail
}
return plaintext
}
func finalize(decrypt plaintext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {
// do nothing
plaintext
}
}
// MARK: - Local utils
private func makeCounter(nonce: Array<UInt8>) -> UInt128 {
UInt128(nonce + [0, 0, 0, 1])
}
// Successive counter values are generated using the function incr(), which treats the rightmost 32
// bits of its argument as a nonnegative integer with the least significant bit on the right
private func incrementCounter(_ counter: UInt128) -> UInt128 {
let b = counter.i.b + 1
let a = (b == 0 ? counter.i.a + 1 : counter.i.a)
return UInt128((a, b))
}
// If data is not a multiple of block size bytes long then the remainder is zero padded
// Note: It's similar to ZeroPadding, but it's not the same.
private func addPadding(_ bytes: Array<UInt8>, blockSize: Int) -> Array<UInt8> {
if bytes.isEmpty {
return Array<UInt8>(repeating: 0, count: blockSize)
}
let remainder = bytes.count % blockSize
if remainder == 0 {
return bytes
}
let paddingCount = blockSize - remainder
if paddingCount > 0 {
return bytes + Array<UInt8>(repeating: 0, count: paddingCount)
}
return bytes
}
// MARK: - GF
/// The Field GF(2^128)
private final class GF {
static let r = UInt128(a: 0xE100000000000000, b: 0)
let blockSize: Int
let h: UInt128
// AAD won't change
let aadLength: Int
// Updated for every consumed block
var ciphertextLength: Int
// Start with 0
var x: UInt128
init(aad: [UInt8], h: UInt128, blockSize: Int) {
self.blockSize = blockSize
self.aadLength = aad.count
self.ciphertextLength = 0
self.h = h
self.x = 0
// Calculate for AAD at the begining
self.x = GF.calculateX(aad: aad, x: self.x, h: h, blockSize: blockSize)
}
@discardableResult
func ghashUpdate(block ciphertextBlock: Array<UInt8>) -> UInt128 {
self.ciphertextLength += ciphertextBlock.count
self.x = GF.calculateX(block: addPadding(ciphertextBlock, blockSize: self.blockSize), x: self.x, h: self.h, blockSize: self.blockSize)
return self.x
}
func ghashFinish() -> UInt128 {
// len(A) || len(C)
let len = UInt128(a: UInt64(aadLength * 8), b: UInt64(ciphertextLength * 8))
x = GF.multiply(self.x ^ len, self.h)
return self.x
}
// GHASH. One-time calculation
static func ghash(x startx: UInt128 = 0, h: UInt128, aad: Array<UInt8>, ciphertext: Array<UInt8>, blockSize: Int) -> UInt128 {
var x = self.calculateX(aad: aad, x: startx, h: h, blockSize: blockSize)
x = self.calculateX(ciphertext: ciphertext, x: x, h: h, blockSize: blockSize)
// len(aad) || len(ciphertext)
let len = UInt128(a: UInt64(aad.count * 8), b: UInt64(ciphertext.count * 8))
x = self.multiply(x ^ len, h)
return x
}
// Calculate Ciphertext part, for all blocks
// Not used with incremental calculation.
private static func calculateX(ciphertext: [UInt8], x startx: UInt128, h: UInt128, blockSize: Int) -> UInt128 {
let pciphertext = addPadding(ciphertext, blockSize: blockSize)
let blocksCount = pciphertext.count / blockSize
var x = startx
for i in 0..<blocksCount {
let cpos = i * blockSize
let block = pciphertext[pciphertext.startIndex.advanced(by: cpos)..<pciphertext.startIndex.advanced(by: cpos + blockSize)]
x = self.calculateX(block: Array(block), x: x, h: h, blockSize: blockSize)
}
return x
}
// block is expected to be padded with addPadding
private static func calculateX(block ciphertextBlock: Array<UInt8>, x: UInt128, h: UInt128, blockSize: Int) -> UInt128 {
let k = x ^ UInt128(ciphertextBlock)
return self.multiply(k, h)
}
// Calculate AAD part, for all blocks
private static func calculateX(aad: [UInt8], x startx: UInt128, h: UInt128, blockSize: Int) -> UInt128 {
let paad = addPadding(aad, blockSize: blockSize)
let blocksCount = paad.count / blockSize
var x = startx
for i in 0..<blocksCount {
let apos = i * blockSize
let k = x ^ UInt128(paad[paad.startIndex.advanced(by: apos)..<paad.startIndex.advanced(by: apos + blockSize)])
x = self.multiply(k, h)
}
return x
}
// Multiplication GF(2^128).
private static func multiply(_ x: UInt128, _ y: UInt128) -> UInt128 {
var z: UInt128 = 0
var v = x
var k = UInt128(a: 1 << 63, b: 0)
for _ in 0..<128 {
if y & k == k {
z = z ^ v
}
if v & 1 != 1 {
v = v >> 1
} else {
v = (v >> 1) ^ self.r
}
k = k >> 1
}
return z
}
}

View File

@ -1,398 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
// The OCB Authenticated-Encryption Algorithm
// https://tools.ietf.org/html/rfc7253
//
public final class OCB: BlockMode {
public enum Mode {
/// In combined mode, the authentication tag is directly appended to the encrypted message. This is usually what you want.
case combined
/// Some applications may need to store the authentication tag and the encrypted message at different locations.
case detached
}
public let options: BlockModeOption = [.initializationVectorRequired]
public enum Error: Swift.Error {
case invalidNonce
case fail
}
private let N: Array<UInt8>
private let additionalAuthenticatedData: Array<UInt8>?
private let mode: Mode
public let customBlockSize: Int? = nil
/// Length of authentication tag, in bytes.
/// For encryption, the value is given as init parameter.
/// For decryption, the length of given authentication tag is used.
private let tagLength: Int
// `authenticationTag` nil for encryption, known tag for decryption
/// For encryption, the value is set at the end of the encryption.
/// For decryption, this is a known Tag to validate against.
public var authenticationTag: Array<UInt8>?
// encrypt
public init(nonce N: Array<UInt8>, additionalAuthenticatedData: Array<UInt8>? = nil, tagLength: Int = 16, mode: Mode = .detached) {
self.N = N
self.additionalAuthenticatedData = additionalAuthenticatedData
self.mode = mode
self.tagLength = tagLength
}
// decrypt
@inlinable
public convenience init(nonce N: Array<UInt8>, authenticationTag: Array<UInt8>, additionalAuthenticatedData: Array<UInt8>? = nil, mode: Mode = .detached) {
self.init(nonce: N, additionalAuthenticatedData: additionalAuthenticatedData, tagLength: authenticationTag.count, mode: mode)
self.authenticationTag = authenticationTag
}
public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock, encryptionOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker {
if self.N.isEmpty || self.N.count > 15 {
throw Error.invalidNonce
}
let worker = OCBModeWorker(N: N.slice, aad: self.additionalAuthenticatedData?.slice, expectedTag: self.authenticationTag, tagLength: self.tagLength, mode: self.mode, cipherOperation: cipherOperation, encryptionOperation: encryptionOperation)
worker.didCalculateTag = { [weak self] tag in
self?.authenticationTag = tag
}
return worker
}
}
// MARK: - Worker
final class OCBModeWorker: BlockModeWorker, FinalizingEncryptModeWorker, FinalizingDecryptModeWorker {
let cipherOperation: CipherOperationOnBlock
var hashOperation: CipherOperationOnBlock!
// Callback called when authenticationTag is ready
var didCalculateTag: ((Array<UInt8>) -> Void)?
private let tagLength: Int
let blockSize = 16 // 128 bit
var additionalBufferSize: Int
private let mode: OCB.Mode
// Additional authenticated data
private let aad: ArraySlice<UInt8>?
// Known Tag used to validate during decryption
private var expectedTag: Array<UInt8>?
/*
* KEY-DEPENDENT
*/
// NOTE: elements are lazily calculated
private var l = [Array<UInt8>]()
private var lAsterisk: Array<UInt8>
private var lDollar: Array<UInt8>
/*
* PER-ENCRYPTION/DECRYPTION
*/
private var mainBlockCount: UInt64
private var offsetMain: Array<UInt8>
private var checksum: Array<UInt8>
init(N: ArraySlice<UInt8>, aad: ArraySlice<UInt8>? = nil, expectedTag: Array<UInt8>? = nil, tagLength: Int, mode: OCB.Mode, cipherOperation: @escaping CipherOperationOnBlock, encryptionOperation: @escaping CipherOperationOnBlock) {
self.cipherOperation = cipherOperation
self.hashOperation = encryptionOperation
self.mode = mode
self.aad = aad
self.expectedTag = expectedTag
self.tagLength = tagLength
if mode == .combined {
self.additionalBufferSize = tagLength
} else {
self.additionalBufferSize = 0
}
/*
* KEY-DEPENDENT INITIALIZATION
*/
let zeros = Array<UInt8>(repeating: 0, count: self.blockSize)
self.lAsterisk = self.hashOperation(zeros.slice)! /// L_* = ENCIPHER(K, zeros(128))
self.lDollar = double(self.lAsterisk) /// L_$ = double(L_*)
self.l.append(double(self.lDollar)) /// L_0 = double(L_$)
/*
* NONCE-DEPENDENT AND PER-ENCRYPTION/DECRYPTION INITIALIZATION
*/
/// Nonce = num2str(TAGLEN mod 128,7) || zeros(120-bitlen(N)) || 1 || N
var nonce = Array<UInt8>(repeating: 0, count: blockSize)
nonce[(nonce.count - N.count)...] = N
nonce[0] = UInt8(tagLength) << 4
nonce[blockSize - 1 - N.count] |= 1
/// bottom = str2num(Nonce[123..128])
let bottom = nonce[15] & 0x3F
/// Ktop = ENCIPHER(K, Nonce[1..122] || zeros(6))
nonce[15] &= 0xC0
let Ktop = self.hashOperation(nonce.slice)!
/// Stretch = Ktop || (Ktop[1..64] xor Ktop[9..72])
let Stretch = Ktop + xor(Ktop[0..<8], Ktop[1..<9])
/// Offset_0 = Stretch[1+bottom..128+bottom]
var offsetMAIN_0 = Array<UInt8>(repeating: 0, count: blockSize)
let bits = bottom % 8
let bytes = Int(bottom / 8)
if bits == 0 {
offsetMAIN_0[0..<blockSize] = Stretch[bytes..<(bytes + blockSize)]
} else {
for i in 0..<self.blockSize {
let b1 = Stretch[bytes + i]
let b2 = Stretch[bytes + i + 1]
offsetMAIN_0[i] = ((b1 << bits) | (b2 >> (8 - bits)))
}
}
self.mainBlockCount = 0
self.offsetMain = Array<UInt8>(offsetMAIN_0.slice)
self.checksum = Array<UInt8>(repeating: 0, count: self.blockSize) /// Checksum_0 = zeros(128)
}
/// L_i = double(L_{i-1}) for every integer i > 0
func getLSub(_ n: Int) -> Array<UInt8> {
while n >= self.l.count {
self.l.append(double(self.l.last!))
}
return self.l[n]
}
func computeTag() -> Array<UInt8> {
let sum = self.hashAAD()
/// Tag = ENCIPHER(K, Checksum_* xor Offset_* xor L_$) xor HASH(K,A)
return xor(self.hashOperation(xor(xor(self.checksum, self.offsetMain).slice, self.lDollar))!, sum)
}
func hashAAD() -> Array<UInt8> {
var sum = Array<UInt8>(repeating: 0, count: blockSize)
guard let aad = self.aad else {
return sum
}
var offset = Array<UInt8>(repeating: 0, count: blockSize)
var blockCount: UInt64 = 1
for aadBlock in aad.batched(by: self.blockSize) {
if aadBlock.count == self.blockSize {
/// Offset_i = Offset_{i-1} xor L_{ntz(i)}
offset = xor(offset, self.getLSub(ntz(blockCount)))
/// Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i)
sum = xor(sum, self.hashOperation(xor(aadBlock, offset))!)
} else {
if !aadBlock.isEmpty {
/// Offset_* = Offset_m xor L_*
offset = xor(offset, self.lAsterisk)
/// CipherInput = (A_* || 1 || zeros(127-bitlen(A_*))) xor Offset_*
let cipherInput: Array<UInt8> = xor(extend(aadBlock, size: blockSize), offset)
/// Sum = Sum_m xor ENCIPHER(K, CipherInput)
sum = xor(sum, self.hashOperation(cipherInput.slice)!)
}
}
blockCount += 1
}
return sum
}
func encrypt(block plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
if plaintext.count == self.blockSize {
return self.processBlock(block: plaintext, forEncryption: true)
} else {
return self.processFinalBlock(block: plaintext, forEncryption: true)
}
}
func finalize(encrypt ciphertext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {
let tag = self.computeTag()
self.didCalculateTag?(tag)
switch self.mode {
case .combined:
return ciphertext + tag
case .detached:
return ciphertext
}
}
func decrypt(block ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
if ciphertext.count == self.blockSize {
return self.processBlock(block: ciphertext, forEncryption: false)
} else {
return self.processFinalBlock(block: ciphertext, forEncryption: false)
}
}
func finalize(decrypt plaintext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {
// do nothing
plaintext
}
private func processBlock(block: ArraySlice<UInt8>, forEncryption: Bool) -> Array<UInt8> {
/*
* OCB-ENCRYPT/OCB-DECRYPT: Process any whole blocks
*/
self.mainBlockCount += 1
/// Offset_i = Offset_{i-1} xor L_{ntz(i)}
self.offsetMain = xor(self.offsetMain, self.getLSub(ntz(self.mainBlockCount)))
/// C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i)
/// P_i = Offset_i xor DECIPHER(K, C_i xor Offset_i)
var mainBlock = Array<UInt8>(block)
mainBlock = xor(mainBlock, offsetMain)
mainBlock = self.cipherOperation(mainBlock.slice)!
mainBlock = xor(mainBlock, self.offsetMain)
/// Checksum_i = Checksum_{i-1} xor P_i
if forEncryption {
self.checksum = xor(self.checksum, block)
} else {
self.checksum = xor(self.checksum, mainBlock)
}
return mainBlock
}
private func processFinalBlock(block: ArraySlice<UInt8>, forEncryption: Bool) -> Array<UInt8> {
let out: Array<UInt8>
if block.isEmpty {
/// C_* = <empty string>
/// P_* = <empty string>
out = []
} else {
/// Offset_* = Offset_m xor L_*
self.offsetMain = xor(self.offsetMain, self.lAsterisk)
/// Pad = ENCIPHER(K, Offset_*)
let Pad = self.hashOperation(self.offsetMain.slice)!
/// C_* = P_* xor Pad[1..bitlen(P_*)]
/// P_* = C_* xor Pad[1..bitlen(C_*)]
out = xor(block, Pad[0..<block.count])
/// Checksum_* = Checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*)))
let plaintext = forEncryption ? block : out.slice
self.checksum = xor(self.checksum, extend(plaintext, size: self.blockSize))
}
return out
}
// The authenticated decryption operation has five inputs: K, IV , C, A, and T. It has only a single
// output, either the plaintext value P or a special symbol FAIL that indicates that the inputs are not
// authentic.
@discardableResult
func willDecryptLast(bytes ciphertext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {
// Validate tag
switch self.mode {
case .combined:
// overwrite expectedTag property used later for verification
self.expectedTag = Array(ciphertext.suffix(self.tagLength))
return ciphertext[ciphertext.startIndex..<ciphertext.endIndex.advanced(by: -Swift.min(tagLength, ciphertext.count))]
case .detached:
return ciphertext
}
}
func didDecryptLast(bytes plaintext: ArraySlice<UInt8>) throws -> ArraySlice<UInt8> {
// Calculate MAC tag.
let computedTag = self.computeTag()
// Validate tag
guard let expectedTag = self.expectedTag, computedTag == expectedTag else {
throw OCB.Error.fail
}
return plaintext
}
}
// MARK: - Local utils
private func ntz(_ x: UInt64) -> Int {
if x == 0 {
return 64
}
var xv = x
var n = 0
while (xv & 1) == 0 {
n += 1
xv = xv >> 1
}
return n
}
private func double(_ block: Array<UInt8>) -> Array<UInt8> {
var ( carry, result) = shiftLeft(block)
/*
* NOTE: This construction is an attempt at a constant-time implementation.
*/
result[15] ^= (0x87 >> ((1 - carry) << 3))
return result
}
private func shiftLeft(_ block: Array<UInt8>) -> (UInt8, Array<UInt8>) {
var output = Array<UInt8>(repeating: 0, count: block.count)
var bit: UInt8 = 0
for i in 0..<block.count {
let b = block[block.count - 1 - i]
output[block.count - 1 - i] = ((b << 1) | bit)
bit = (b >> 7) & 1
}
return (bit, output)
}
private func extend(_ block: ArraySlice<UInt8>, size: Int) -> Array<UInt8> {
var output = Array<UInt8>(repeating: 0, count: size)
output[0..<block.count] = block
output[block.count] |= 0x80
return output
}

View File

@ -1,73 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
// Output Feedback (OFB)
//
public struct OFB: BlockMode {
public enum Error: Swift.Error {
/// Invalid IV
case invalidInitializationVector
}
public let options: BlockModeOption = [.initializationVectorRequired, .useEncryptToDecrypt]
private let iv: Array<UInt8>
public let customBlockSize: Int? = nil
public init(iv: Array<UInt8>) {
self.iv = iv
}
public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock, encryptionOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker {
if self.iv.count != blockSize {
throw Error.invalidInitializationVector
}
return OFBModeWorker(blockSize: blockSize, iv: self.iv.slice, cipherOperation: cipherOperation)
}
}
struct OFBModeWorker: BlockModeWorker {
let cipherOperation: CipherOperationOnBlock
let blockSize: Int
let additionalBufferSize: Int = 0
private let iv: ArraySlice<UInt8>
private var prev: ArraySlice<UInt8>?
init(blockSize: Int, iv: ArraySlice<UInt8>, cipherOperation: @escaping CipherOperationOnBlock) {
self.blockSize = blockSize
self.iv = iv
self.cipherOperation = cipherOperation
}
@inlinable
mutating func encrypt(block plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
guard let ciphertext = cipherOperation(prev ?? iv) else {
return Array(plaintext)
}
self.prev = ciphertext.slice
return xor(plaintext, ciphertext)
}
@inlinable
mutating func decrypt(block ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
guard let decrypted = cipherOperation(prev ?? iv) else {
return Array(ciphertext)
}
let plaintext: Array<UInt8> = xor(decrypted, ciphertext)
prev = decrypted.slice
return plaintext
}
}

View File

@ -1,74 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
// Propagating Cipher Block Chaining (PCBC)
//
public struct PCBC: BlockMode {
public enum Error: Swift.Error {
/// Invalid IV
case invalidInitializationVector
}
public let options: BlockModeOption = [.initializationVectorRequired, .paddingRequired]
private let iv: Array<UInt8>
public let customBlockSize: Int? = nil
public init(iv: Array<UInt8>) {
self.iv = iv
}
public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock, encryptionOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker {
if self.iv.count != blockSize {
throw Error.invalidInitializationVector
}
return PCBCModeWorker(blockSize: blockSize, iv: self.iv.slice, cipherOperation: cipherOperation)
}
}
struct PCBCModeWorker: BlockModeWorker {
let cipherOperation: CipherOperationOnBlock
var blockSize: Int
let additionalBufferSize: Int = 0
private let iv: ArraySlice<UInt8>
private var prev: ArraySlice<UInt8>?
@inlinable
init(blockSize: Int, iv: ArraySlice<UInt8>, cipherOperation: @escaping CipherOperationOnBlock) {
self.blockSize = blockSize
self.iv = iv
self.cipherOperation = cipherOperation
}
@inlinable
mutating func encrypt(block plaintext: ArraySlice<UInt8>) -> Array<UInt8> {
guard let ciphertext = cipherOperation(xor(prev ?? iv, plaintext)) else {
return Array(plaintext)
}
self.prev = xor(plaintext, ciphertext.slice)
return ciphertext
}
@inlinable
mutating func decrypt(block ciphertext: ArraySlice<UInt8>) -> Array<UInt8> {
guard let plaintext = cipherOperation(ciphertext) else {
return Array(ciphertext)
}
let result: Array<UInt8> = xor(prev ?? self.iv, plaintext)
self.prev = xor(result, ciphertext)
return result
}
}

View File

@ -1,545 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
// https://en.wikipedia.org/wiki/Blowfish_(cipher)
// Based on Paul Kocher implementation
//
public final class Blowfish {
public enum Error: Swift.Error {
/// Data padding is required
case dataPaddingRequired
/// Invalid key or IV
case invalidKeyOrInitializationVector
/// Invalid IV
case invalidInitializationVector
/// Invalid block mode
case invalidBlockMode
}
public static let blockSize: Int = 8 // 64 bit
public let keySize: Int
private let blockMode: BlockMode
private let padding: Padding
private var decryptWorker: CipherModeWorker!
private var encryptWorker: CipherModeWorker!
private let N = 16 // rounds
private var P: Array<UInt32>
private var S: Array<Array<UInt32>>
private let origP: Array<UInt32> = [
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822,
0x299f31d0, 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377,
0xbe5466cf, 0x34e90c6c, 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5,
0xb5470917, 0x9216d5d9, 0x8979fb1b
]
private let origS: Array<Array<UInt32>> = [
[
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
],
[
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
],
[
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
],
[
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
]
]
public init(key: Array<UInt8>, blockMode: BlockMode = CBC(iv: Array<UInt8>(repeating: 0, count: Blowfish.blockSize)), padding: Padding) throws {
precondition(key.count >= 5 && key.count <= 56)
self.blockMode = blockMode
self.padding = padding
self.keySize = key.count
self.S = self.origS
self.P = self.origP
self.expandKey(key: key)
try self.setupBlockModeWorkers()
}
private func setupBlockModeWorkers() throws {
let decryptBlock = { [weak self] (block: ArraySlice<UInt8>) -> Array<UInt8>? in
self?.decrypt(block: block)
}
let encryptBlock = { [weak self] (block: ArraySlice<UInt8>) -> Array<UInt8>? in
self?.encrypt(block: block)
}
self.encryptWorker = try self.blockMode.worker(blockSize: Blowfish.blockSize, cipherOperation: encryptBlock, encryptionOperation: encryptBlock)
if self.blockMode.options.contains(.useEncryptToDecrypt) {
self.decryptWorker = try self.blockMode.worker(blockSize: Blowfish.blockSize, cipherOperation: encryptBlock, encryptionOperation: encryptBlock)
} else {
self.decryptWorker = try self.blockMode.worker(blockSize: Blowfish.blockSize, cipherOperation: decryptBlock, encryptionOperation: encryptBlock)
}
}
private func reset() {
self.S = self.origS
self.P = self.origP
// todo expand key
}
private func expandKey(key: Array<UInt8>) {
var j = 0
for i in 0..<(self.N + 2) {
var data: UInt32 = 0x0
for _ in 0..<4 {
data = (data << 8) | UInt32(key[j])
j += 1
if j >= key.count {
j = 0
}
}
self.P[i] ^= data
}
var datal: UInt32 = 0
var datar: UInt32 = 0
for i in stride(from: 0, to: self.N + 2, by: 2) {
self.encryptBlowfishBlock(l: &datal, r: &datar)
self.P[i] = datal
self.P[i + 1] = datar
}
for i in 0..<4 {
for j in stride(from: 0, to: 256, by: 2) {
self.encryptBlowfishBlock(l: &datal, r: &datar)
self.S[i][j] = datal
self.S[i][j + 1] = datar
}
}
}
private func encrypt(block: ArraySlice<UInt8>) -> Array<UInt8>? {
var result = Array<UInt8>()
var l = UInt32(bytes: block[block.startIndex..<block.startIndex.advanced(by: 4)])
var r = UInt32(bytes: block[block.startIndex.advanced(by: 4)..<block.startIndex.advanced(by: 8)])
self.encryptBlowfishBlock(l: &l, r: &r)
// because everything is too complex to be solved in reasonable time o_O
result += [
UInt8((l >> 24) & 0xff),
UInt8((l >> 16) & 0xff)
]
result += [
UInt8((l >> 8) & 0xff),
UInt8((l >> 0) & 0xff)
]
result += [
UInt8((r >> 24) & 0xff),
UInt8((r >> 16) & 0xff)
]
result += [
UInt8((r >> 8) & 0xff),
UInt8((r >> 0) & 0xff)
]
return result
}
private func decrypt(block: ArraySlice<UInt8>) -> Array<UInt8>? {
var result = Array<UInt8>()
var l = UInt32(bytes: block[block.startIndex..<block.startIndex.advanced(by: 4)])
var r = UInt32(bytes: block[block.startIndex.advanced(by: 4)..<block.startIndex.advanced(by: 8)])
self.decryptBlowfishBlock(l: &l, r: &r)
// because everything is too complex to be solved in reasonable time o_O
result += [
UInt8((l >> 24) & 0xff),
UInt8((l >> 16) & 0xff)
]
result += [
UInt8((l >> 8) & 0xff),
UInt8((l >> 0) & 0xff)
]
result += [
UInt8((r >> 24) & 0xff),
UInt8((r >> 16) & 0xff)
]
result += [
UInt8((r >> 8) & 0xff),
UInt8((r >> 0) & 0xff)
]
return result
}
/// Encrypts the 8-byte padded buffer
///
/// - Parameters:
/// - l: left half
/// - r: right half
private func encryptBlowfishBlock(l: inout UInt32, r: inout UInt32) {
var Xl = l
var Xr = r
for i in 0..<self.N {
Xl = Xl ^ self.P[i]
Xr = self.F(x: Xl) ^ Xr
(Xl, Xr) = (Xr, Xl)
}
(Xl, Xr) = (Xr, Xl)
Xr = Xr ^ self.P[self.N]
Xl = Xl ^ self.P[self.N + 1]
l = Xl
r = Xr
}
/// Decrypts the 8-byte padded buffer
///
/// - Parameters:
/// - l: left half
/// - r: right half
private func decryptBlowfishBlock(l: inout UInt32, r: inout UInt32) {
var Xl = l
var Xr = r
for i in (2...self.N + 1).reversed() {
Xl = Xl ^ self.P[i]
Xr = self.F(x: Xl) ^ Xr
(Xl, Xr) = (Xr, Xl)
}
(Xl, Xr) = (Xr, Xl)
Xr = Xr ^ self.P[1]
Xl = Xl ^ self.P[0]
l = Xl
r = Xr
}
private func F(x: UInt32) -> UInt32 {
let f1 = self.S[0][Int(x >> 24) & 0xff]
let f2 = self.S[1][Int(x >> 16) & 0xff]
let f3 = self.S[2][Int(x >> 8) & 0xff]
let f4 = self.S[3][Int(x & 0xff)]
return ((f1 &+ f2) ^ f3) &+ f4
}
}
extension Blowfish: Cipher {
/// Encrypt the 8-byte padded buffer, block by block. Note that for amounts of data larger than a block, it is not safe to just call encrypt() on successive blocks.
///
/// - Parameter bytes: Plaintext data
/// - Returns: Encrypted data
public func encrypt<C: Collection>(_ bytes: C) throws -> Array<UInt8> where C.Element == UInt8, C.Index == Int {
let bytes = self.padding.add(to: Array(bytes), blockSize: Blowfish.blockSize) // FIXME: Array(bytes) copies
var out = Array<UInt8>()
out.reserveCapacity(bytes.count)
for chunk in bytes.batched(by: Blowfish.blockSize) {
out += self.encryptWorker.encrypt(block: chunk)
}
if self.blockMode.options.contains(.paddingRequired) && (out.count % Blowfish.blockSize != 0) {
throw Error.dataPaddingRequired
}
return out
}
/// Decrypt the 8-byte padded buffer
///
/// - Parameter bytes: Ciphertext data
/// - Returns: Plaintext data
public func decrypt<C: Collection>(_ bytes: C) throws -> Array<UInt8> where C.Element == UInt8, C.Index == Int {
if self.blockMode.options.contains(.paddingRequired) && (bytes.count % Blowfish.blockSize != 0) {
throw Error.dataPaddingRequired
}
var out = Array<UInt8>()
out.reserveCapacity(bytes.count)
for chunk in Array(bytes).batched(by: Blowfish.blockSize) {
out += self.decryptWorker.decrypt(block: chunk) // FIXME: copying here is innefective
}
out = self.padding.remove(from: out, blockSize: Blowfish.blockSize)
return out
}
}

View File

@ -1,30 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
public final class CBCMAC: CMAC {
public override func authenticate(_ bytes: Array<UInt8>) throws -> Array<UInt8> {
var inBytes = bytes
bitPadding(to: &inBytes, blockSize: CMAC.BlockSize)
let blocks = inBytes.batched(by: CMAC.BlockSize)
var lastBlockEncryptionResult: [UInt8] = CBCMAC.Zero
try blocks.forEach { block in
let aes = try AES(key: Array(key), blockMode: CBC(iv: lastBlockEncryptionResult), padding: .noPadding)
lastBlockEncryptionResult = try aes.encrypt(block)
}
return lastBlockEncryptionResult
}
}

View File

@ -1,106 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
public class CMAC: Authenticator {
public enum Error: Swift.Error {
case wrongKeyLength
}
internal let key: SecureBytes
internal static let BlockSize: Int = 16
internal static let Zero: Array<UInt8> = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
private static let Rb: Array<UInt8> = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87]
public init(key: Array<UInt8>) throws {
self.key = SecureBytes(bytes: key)
}
// MARK: Authenticator
// AES-CMAC
public func authenticate(_ bytes: Array<UInt8>) throws -> Array<UInt8> {
let cipher = try AES(key: Array(key), blockMode: CBC(iv: CMAC.Zero), padding: .noPadding)
return try self.authenticate(bytes, cipher: cipher)
}
// CMAC using a Cipher
public func authenticate(_ bytes: Array<UInt8>, cipher: Cipher) throws -> Array<UInt8> {
let l = try cipher.encrypt(CMAC.Zero)
var subKey1 = self.leftShiftOneBit(l)
if (l[0] & 0x80) != 0 {
subKey1 = xor(CMAC.Rb, subKey1)
}
var subKey2 = self.leftShiftOneBit(subKey1)
if (subKey1[0] & 0x80) != 0 {
subKey2 = xor(CMAC.Rb, subKey2)
}
let lastBlockComplete: Bool
let blockCount = (bytes.count + CMAC.BlockSize - 1) / CMAC.BlockSize
if blockCount == 0 {
lastBlockComplete = false
} else {
lastBlockComplete = bytes.count % CMAC.BlockSize == 0
}
var paddedBytes = bytes
if !lastBlockComplete {
bitPadding(to: &paddedBytes, blockSize: CMAC.BlockSize)
}
var blocks = Array(paddedBytes.batched(by: CMAC.BlockSize))
var lastBlock = blocks.popLast()!
if lastBlockComplete {
lastBlock = xor(lastBlock, subKey1)
} else {
lastBlock = xor(lastBlock, subKey2)
}
var x = Array<UInt8>(repeating: 0x00, count: CMAC.BlockSize)
var y = Array<UInt8>(repeating: 0x00, count: CMAC.BlockSize)
for block in blocks {
y = xor(block, x)
x = try cipher.encrypt(y)
}
// the difference between CMAC and CBC-MAC is that CMAC xors the final block with a secret value
y = self.process(lastBlock: lastBlock, with: x)
return try cipher.encrypt(y)
}
func process(lastBlock: ArraySlice<UInt8>, with x: [UInt8]) -> [UInt8] {
xor(lastBlock, x)
}
// MARK: Helper methods
/**
Performs left shift by one bit to the bit string aquired after concatenating al bytes in the byte array
- parameters:
- bytes: byte array
- returns: bit shifted bit string split again in array of bytes
*/
private func leftShiftOneBit(_ bytes: Array<UInt8>) -> Array<UInt8> {
var shifted = Array<UInt8>(repeating: 0x00, count: bytes.count)
let last = bytes.count - 1
for index in 0..<last {
shifted[index] = bytes[index] << 1
if (bytes[index + 1] & 0x80) != 0 {
shifted[index] += 0x01
}
}
shifted[last] = bytes[last] << 1
return shifted
}
}

View File

@ -1,126 +0,0 @@
//
// Addition.swift
// CS.BigInt
//
// Created by Károly Lőrentey on 2016-01-03.
// Copyright © 2016-2017 Károly Lőrentey.
//
extension CS.BigUInt {
//MARK: Addition
/// Add `word` to this integer in place.
/// `word` is shifted `shift` words to the left before being added.
///
/// - Complexity: O(max(count, shift))
internal mutating func addWord(_ word: Word, shiftedBy shift: Int = 0) {
precondition(shift >= 0)
var carry = word
var i = shift
while carry > 0 {
let (d, c) = self[i].addingReportingOverflow(carry)
self[i] = d
carry = (c ? 1 : 0)
i += 1
}
}
/// Add the digit `d` to this integer and return the result.
/// `d` is shifted `shift` words to the left before being added.
///
/// - Complexity: O(max(count, shift))
internal func addingWord(_ word: Word, shiftedBy shift: Int = 0) -> CS.BigUInt {
var r = self
r.addWord(word, shiftedBy: shift)
return r
}
/// Add `b` to this integer in place.
/// `b` is shifted `shift` words to the left before being added.
///
/// - Complexity: O(max(count, b.count + shift))
internal mutating func add(_ b: CS.BigUInt, shiftedBy shift: Int = 0) {
precondition(shift >= 0)
var carry = false
var bi = 0
let bc = b.count
while bi < bc || carry {
let ai = shift + bi
let (d, c) = self[ai].addingReportingOverflow(b[bi])
if carry {
let (d2, c2) = d.addingReportingOverflow(1)
self[ai] = d2
carry = c || c2
}
else {
self[ai] = d
carry = c
}
bi += 1
}
}
/// Add `b` to this integer and return the result.
/// `b` is shifted `shift` words to the left before being added.
///
/// - Complexity: O(max(count, b.count + shift))
internal func adding(_ b: CS.BigUInt, shiftedBy shift: Int = 0) -> CS.BigUInt {
var r = self
r.add(b, shiftedBy: shift)
return r
}
/// Increment this integer by one. If `shift` is non-zero, it selects
/// the word that is to be incremented.
///
/// - Complexity: O(count + shift)
internal mutating func increment(shiftedBy shift: Int = 0) {
self.addWord(1, shiftedBy: shift)
}
/// Add `a` and `b` together and return the result.
///
/// - Complexity: O(max(a.count, b.count))
public static func +(a: CS.BigUInt, b: CS.BigUInt) -> CS.BigUInt {
return a.adding(b)
}
/// Add `a` and `b` together, and store the sum in `a`.
///
/// - Complexity: O(max(a.count, b.count))
public static func +=(a: inout CS.BigUInt, b: CS.BigUInt) {
a.add(b, shiftedBy: 0)
}
}
extension CS.BigInt {
/// Add `a` to `b` and return the result.
public static func +(a: CS.BigInt, b: CS.BigInt) -> CS.BigInt {
switch (a.sign, b.sign) {
case (.plus, .plus):
return CS.BigInt(sign: .plus, magnitude: a.magnitude + b.magnitude)
case (.minus, .minus):
return CS.BigInt(sign: .minus, magnitude: a.magnitude + b.magnitude)
case (.plus, .minus):
if a.magnitude >= b.magnitude {
return CS.BigInt(sign: .plus, magnitude: a.magnitude - b.magnitude)
}
else {
return CS.BigInt(sign: .minus, magnitude: b.magnitude - a.magnitude)
}
case (.minus, .plus):
if b.magnitude >= a.magnitude {
return CS.BigInt(sign: .plus, magnitude: b.magnitude - a.magnitude)
}
else {
return CS.BigInt(sign: .minus, magnitude: a.magnitude - b.magnitude)
}
}
}
/// Add `b` to `a` in place.
public static func +=(a: inout CS.BigInt, b: CS.BigInt) {
a = a + b
}
}

View File

@ -1,78 +0,0 @@
//
// CS.BigInt.swift
// CS.BigInt
//
// Created by Károly Lőrentey on 2015-12-27.
// Copyright © 2016-2017 Károly Lőrentey.
//
//MARK: CS.BigInt
extension CS {
/// An arbitary precision signed integer type, also known as a "big integer".
///
/// Operations on big integers never overflow, but they might take a long time to execute.
/// The amount of memory (and address space) available is the only constraint to the magnitude of these numbers.
///
/// This particular big integer type uses base-2^64 digits to represent integers.
///
/// `BigInt` is essentially a tiny wrapper that extends `BigUInt` with a sign bit and provides signed integer
/// operations. Both the underlying absolute value and the negative/positive flag are available as read-write
/// properties.
///
/// Not all algorithms of `BigUInt` are available for `BigInt` values; for example, there is no square root or
/// primality test for signed integers. When you need to call one of these, just extract the absolute value:
///
/// ```Swift
/// CS.BigInt(255).abs.isPrime() // Returns false
/// ```
///
public struct BigInt: SignedInteger {
public enum Sign {
case plus
case minus
}
public typealias Magnitude = BigUInt
/// The type representing a digit in `BigInt`'s underlying number system.
public typealias Word = BigUInt.Word
public static var isSigned: Bool {
return true
}
/// The absolute value of this integer.
public var magnitude: BigUInt
/// True iff the value of this integer is negative.
public var sign: Sign
/// Initializes a new big integer with the provided absolute number and sign flag.
public init(sign: Sign, magnitude: BigUInt) {
self.sign = (magnitude.isZero ? .plus : sign)
self.magnitude = magnitude
}
/// Return true iff this integer is zero.
///
/// - Complexity: O(1)
public var isZero: Bool {
return magnitude.isZero
}
/// Returns `-1` if this value is negative and `1` if its positive; otherwise, `0`.
///
/// - Returns: The sign of this number, expressed as an integer of the same type.
public func signum() -> CS.BigInt {
switch sign {
case .plus:
return isZero ? 0 : 1
case .minus:
return -1
}
}
}
}

View File

@ -1,389 +0,0 @@
//
// BigUInt.swift
// BigInt
//
// Created by Károly Lőrentey on 2015-12-26.
// Copyright © 2016-2017 Károly Lőrentey.
//
extension CS {
/// An arbitary precision unsigned integer type, also known as a "big integer".
///
/// Operations on big integers never overflow, but they may take a long time to execute.
/// The amount of memory (and address space) available is the only constraint to the magnitude of these numbers.
///
/// This particular big integer type uses base-2^64 digits to represent integers; you can think of it as a wrapper
/// around `Array<UInt64>`. (In fact, `BigUInt` only uses an array if there are more than two digits.)
public struct BigUInt: UnsignedInteger {
/// The type representing a digit in `BigUInt`'s underlying number system.
public typealias Word = UInt
/// The storage variants of a `BigUInt`.
enum Kind {
/// Value consists of the two specified words (low and high). Either or both words may be zero.
case inline(Word, Word)
/// Words are stored in a slice of the storage array.
case slice(from: Int, to: Int)
/// Words are stored in the storage array.
case array
}
internal fileprivate (set) var kind: Kind // Internal for testing only
internal fileprivate (set) var storage: [Word] // Internal for testing only; stored separately to prevent COW copies
/// Initializes a new BigUInt with value 0.
public init() {
self.kind = .inline(0, 0)
self.storage = []
}
internal init(word: Word) {
self.kind = .inline(word, 0)
self.storage = []
}
internal init(low: Word, high: Word) {
self.kind = .inline(low, high)
self.storage = []
}
/// Initializes a new BigUInt with the specified digits. The digits are ordered from least to most significant.
public init(words: [Word]) {
self.kind = .array
self.storage = words
normalize()
}
internal init(words: [Word], from startIndex: Int, to endIndex: Int) {
self.kind = .slice(from: startIndex, to: endIndex)
self.storage = words
normalize()
}
}
}
extension CS.BigUInt {
public static var isSigned: Bool {
return false
}
/// Return true iff this integer is zero.
///
/// - Complexity: O(1)
var isZero: Bool {
switch kind {
case .inline(0, 0): return true
case .array: return storage.isEmpty
default:
return false
}
}
/// Returns `1` if this value is, positive; otherwise, `0`.
///
/// - Returns: The sign of this number, expressed as an integer of the same type.
public func signum() -> CS.BigUInt {
return isZero ? 0 : 1
}
}
extension CS.BigUInt {
mutating func ensureArray() {
switch kind {
case let .inline(w0, w1):
kind = .array
storage = w1 != 0 ? [w0, w1]
: w0 != 0 ? [w0]
: []
case let .slice(from: start, to: end):
kind = .array
storage = Array(storage[start ..< end])
case .array:
break
}
}
var capacity: Int {
guard case .array = kind else { return 0 }
return storage.capacity
}
mutating func reserveCapacity(_ minimumCapacity: Int) {
switch kind {
case let .inline(w0, w1):
kind = .array
storage.reserveCapacity(minimumCapacity)
if w1 != 0 {
storage.append(w0)
storage.append(w1)
}
else if w0 != 0 {
storage.append(w0)
}
case let .slice(from: start, to: end):
kind = .array
var words: [Word] = []
words.reserveCapacity(Swift.max(end - start, minimumCapacity))
words.append(contentsOf: storage[start ..< end])
storage = words
case .array:
storage.reserveCapacity(minimumCapacity)
}
}
/// Gets rid of leading zero digits in the digit array and converts slices into inline digits when possible.
internal mutating func normalize() {
switch kind {
case .slice(from: let start, to: var end):
assert(start >= 0 && end <= storage.count && start <= end)
while start < end, storage[end - 1] == 0 {
end -= 1
}
switch end - start {
case 0:
kind = .inline(0, 0)
storage = []
case 1:
kind = .inline(storage[start], 0)
storage = []
case 2:
kind = .inline(storage[start], storage[start + 1])
storage = []
case storage.count:
assert(start == 0)
kind = .array
default:
kind = .slice(from: start, to: end)
}
case .array where storage.last == 0:
while storage.last == 0 {
storage.removeLast()
}
default:
break
}
}
/// Set this integer to 0 without releasing allocated storage capacity (if any).
mutating func clear() {
self.load(0)
}
/// Set this integer to `value` by copying its digits without releasing allocated storage capacity (if any).
mutating func load(_ value: CS.BigUInt) {
switch kind {
case .inline, .slice:
self = value
case .array:
self.storage.removeAll(keepingCapacity: true)
self.storage.append(contentsOf: value.words)
}
}
}
extension CS.BigUInt {
//MARK: Collection-like members
/// The number of digits in this integer, excluding leading zero digits.
var count: Int {
switch kind {
case let .inline(w0, w1):
return w1 != 0 ? 2
: w0 != 0 ? 1
: 0
case let .slice(from: start, to: end):
return end - start
case .array:
return storage.count
}
}
/// Get or set a digit at a given index.
///
/// - Note: Unlike a normal collection, it is OK for the index to be greater than or equal to `endIndex`.
/// The subscripting getter returns zero for indexes beyond the most significant digit.
/// Setting these extended digits automatically appends new elements to the underlying digit array.
/// - Requires: index >= 0
/// - Complexity: The getter is O(1). The setter is O(1) if the conditions below are true; otherwise it's O(count).
/// - The integer's storage is not shared with another integer
/// - The integer wasn't created as a slice of another integer
/// - `index < count`
subscript(_ index: Int) -> Word {
get {
precondition(index >= 0)
switch (kind, index) {
case (.inline(let w0, _), 0): return w0
case (.inline(_, let w1), 1): return w1
case (.slice(from: let start, to: let end), _) where index < end - start:
return storage[start + index]
case (.array, _) where index < storage.count:
return storage[index]
default:
return 0
}
}
set(word) {
precondition(index >= 0)
switch (kind, index) {
case let (.inline(_, w1), 0):
kind = .inline(word, w1)
case let (.inline(w0, _), 1):
kind = .inline(w0, word)
case let (.slice(from: start, to: end), _) where index < end - start:
replace(at: index, with: word)
case (.array, _) where index < storage.count:
replace(at: index, with: word)
default:
extend(at: index, with: word)
}
}
}
private mutating func replace(at index: Int, with word: Word) {
ensureArray()
precondition(index < storage.count)
storage[index] = word
if word == 0, index == storage.count - 1 {
normalize()
}
}
private mutating func extend(at index: Int, with word: Word) {
guard word != 0 else { return }
reserveCapacity(index + 1)
precondition(index >= storage.count)
storage.append(contentsOf: repeatElement(0, count: index - storage.count))
storage.append(word)
}
/// Returns an integer built from the digits of this integer in the given range.
internal func extract(_ bounds: Range<Int>) -> CS.BigUInt {
switch kind {
case let .inline(w0, w1):
let bounds = bounds.clamped(to: 0 ..< 2)
if bounds == 0 ..< 2 {
return CS.BigUInt(low: w0, high: w1)
}
else if bounds == 0 ..< 1 {
return CS.BigUInt(word: w0)
}
else if bounds == 1 ..< 2 {
return CS.BigUInt(word: w1)
}
else {
return CS.BigUInt()
}
case let .slice(from: start, to: end):
let s = Swift.min(end, start + Swift.max(bounds.lowerBound, 0))
let e = Swift.max(s, (bounds.upperBound > end - start ? end : start + bounds.upperBound))
return CS.BigUInt(words: storage, from: s, to: e)
case .array:
let b = bounds.clamped(to: storage.startIndex ..< storage.endIndex)
return CS.BigUInt(words: storage, from: b.lowerBound, to: b.upperBound)
}
}
internal func extract<Bounds: RangeExpression>(_ bounds: Bounds) -> CS.BigUInt where Bounds.Bound == Int {
return self.extract(bounds.relative(to: 0 ..< Int.max))
}
}
extension CS.BigUInt {
internal mutating func shiftRight(byWords amount: Int) {
assert(amount >= 0)
guard amount > 0 else { return }
switch kind {
case let .inline(_, w1) where amount == 1:
kind = .inline(w1, 0)
case .inline(_, _):
kind = .inline(0, 0)
case let .slice(from: start, to: end):
let s = start + amount
if s >= end {
kind = .inline(0, 0)
}
else {
kind = .slice(from: s, to: end)
normalize()
}
case .array:
if amount >= storage.count {
storage.removeAll(keepingCapacity: true)
}
else {
storage.removeFirst(amount)
}
}
}
internal mutating func shiftLeft(byWords amount: Int) {
assert(amount >= 0)
guard amount > 0 else { return }
guard !isZero else { return }
switch kind {
case let .inline(w0, 0) where amount == 1:
kind = .inline(0, w0)
case let .inline(w0, w1):
let c = (w1 == 0 ? 1 : 2)
storage.reserveCapacity(amount + c)
storage.append(contentsOf: repeatElement(0, count: amount))
storage.append(w0)
if w1 != 0 {
storage.append(w1)
}
kind = .array
case let .slice(from: start, to: end):
var words: [Word] = []
words.reserveCapacity(amount + count)
words.append(contentsOf: repeatElement(0, count: amount))
words.append(contentsOf: storage[start ..< end])
storage = words
kind = .array
case .array:
storage.insert(contentsOf: repeatElement(0, count: amount), at: 0)
}
}
}
extension CS.BigUInt {
//MARK: Low and High
/// Split this integer into a high-order and a low-order part.
///
/// - Requires: count > 1
/// - Returns: `(low, high)` such that
/// - `self == low.add(high, shiftedBy: middleIndex)`
/// - `high.width <= floor(width / 2)`
/// - `low.width <= ceil(width / 2)`
/// - Complexity: Typically O(1), but O(count) in the worst case, because high-order zero digits need to be removed after the split.
internal var split: (high: CS.BigUInt, low: CS.BigUInt) {
precondition(count > 1)
let mid = middleIndex
return (self.extract(mid...), self.extract(..<mid))
}
/// Index of the digit at the middle of this integer.
///
/// - Returns: The index of the digit that is least significant in `self.high`.
internal var middleIndex: Int {
return (count + 1) / 2
}
/// The low-order half of this CS.BigUInt.
///
/// - Returns: `self[0 ..< middleIndex]`
/// - Requires: count > 1
internal var low: CS.BigUInt {
return self.extract(0 ..< middleIndex)
}
/// The high-order half of this CS.BigUInt.
///
/// - Returns: `self[middleIndex ..< count]`
/// - Requires: count > 1
internal var high: CS.BigUInt {
return self.extract(middleIndex ..< count)
}
}

View File

@ -1,121 +0,0 @@
//
// Bitwise Ops.swift
// CS.BigInt
//
// Created by Károly Lőrentey on 2016-01-03.
// Copyright © 2016-2017 Károly Lőrentey.
//
//MARK: Bitwise Operations
extension CS.BigUInt {
/// Return the ones' complement of `a`.
///
/// - Complexity: O(a.count)
public static prefix func ~(a: CS.BigUInt) -> CS.BigUInt {
return CS.BigUInt(words: a.words.map { ~$0 })
}
/// Calculate the bitwise OR of `a` and `b`, and store the result in `a`.
///
/// - Complexity: O(max(a.count, b.count))
public static func |= (a: inout CS.BigUInt, b: CS.BigUInt) {
a.reserveCapacity(b.count)
for i in 0 ..< b.count {
a[i] |= b[i]
}
}
/// Calculate the bitwise AND of `a` and `b` and return the result.
///
/// - Complexity: O(max(a.count, b.count))
public static func &= (a: inout CS.BigUInt, b: CS.BigUInt) {
for i in 0 ..< Swift.max(a.count, b.count) {
a[i] &= b[i]
}
}
/// Calculate the bitwise XOR of `a` and `b` and return the result.
///
/// - Complexity: O(max(a.count, b.count))
public static func ^= (a: inout CS.BigUInt, b: CS.BigUInt) {
a.reserveCapacity(b.count)
for i in 0 ..< b.count {
a[i] ^= b[i]
}
}
}
extension CS.BigInt {
public static prefix func ~(x: CS.BigInt) -> CS.BigInt {
switch x.sign {
case .plus:
return CS.BigInt(sign: .minus, magnitude: x.magnitude + 1)
case .minus:
return CS.BigInt(sign: .plus, magnitude: x.magnitude - 1)
}
}
public static func &(lhs: inout CS.BigInt, rhs: CS.BigInt) -> CS.BigInt {
let left = lhs.words
let right = rhs.words
// Note we aren't using left.count/right.count here; we account for the sign bit separately later.
let count = Swift.max(lhs.magnitude.count, rhs.magnitude.count)
var words: [UInt] = []
words.reserveCapacity(count)
for i in 0 ..< count {
words.append(left[i] & right[i])
}
if lhs.sign == .minus && rhs.sign == .minus {
words.twosComplement()
return CS.BigInt(sign: .minus, magnitude: CS.BigUInt(words: words))
}
return CS.BigInt(sign: .plus, magnitude: CS.BigUInt(words: words))
}
public static func |(lhs: inout CS.BigInt, rhs: CS.BigInt) -> CS.BigInt {
let left = lhs.words
let right = rhs.words
// Note we aren't using left.count/right.count here; we account for the sign bit separately later.
let count = Swift.max(lhs.magnitude.count, rhs.magnitude.count)
var words: [UInt] = []
words.reserveCapacity(count)
for i in 0 ..< count {
words.append(left[i] | right[i])
}
if lhs.sign == .minus || rhs.sign == .minus {
words.twosComplement()
return CS.BigInt(sign: .minus, magnitude: CS.BigUInt(words: words))
}
return CS.BigInt(sign: .plus, magnitude: CS.BigUInt(words: words))
}
public static func ^(lhs: inout CS.BigInt, rhs: CS.BigInt) -> CS.BigInt {
let left = lhs.words
let right = rhs.words
// Note we aren't using left.count/right.count here; we account for the sign bit separately later.
let count = Swift.max(lhs.magnitude.count, rhs.magnitude.count)
var words: [UInt] = []
words.reserveCapacity(count)
for i in 0 ..< count {
words.append(left[i] ^ right[i])
}
if (lhs.sign == .minus) != (rhs.sign == .minus) {
words.twosComplement()
return CS.BigInt(sign: .minus, magnitude: CS.BigUInt(words: words))
}
return CS.BigInt(sign: .plus, magnitude: CS.BigUInt(words: words))
}
public static func &=(lhs: inout CS.BigInt, rhs: CS.BigInt) {
lhs = lhs & rhs
}
public static func |=(lhs: inout CS.BigInt, rhs: CS.BigInt) {
lhs = lhs | rhs
}
public static func ^=(lhs: inout CS.BigInt, rhs: CS.BigInt) {
lhs = lhs ^ rhs
}
}

View File

@ -1,24 +0,0 @@
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
// To avoid name conflict with BigInt library, I choose to rename
// BigInt -> BigInteger
// BigUInt -> BigUInteger
public typealias BigInteger = CS.BigInt
public typealias BigUInteger = CS.BigUInt
public enum CS {
// namespace
}

View File

@ -1,157 +0,0 @@
//
// Codable.swift
// CS.BigInt
//
// Created by Károly Lőrentey on 2017-8-11.
// Copyright © 2016-2017 Károly Lőrentey.
//
extension CS {
// Little-endian to big-endian
struct Units<Unit: FixedWidthInteger, Words: RandomAccessCollection>: RandomAccessCollection
where Words.Element: FixedWidthInteger, Words.Index == Int {
typealias Word = Words.Element
let words: Words
init(of type: Unit.Type, _ words: Words) {
precondition(Word.bitWidth % Unit.bitWidth == 0 || Unit.bitWidth % Word.bitWidth == 0)
self.words = words
}
var count: Int { return (words.count * Word.bitWidth + Unit.bitWidth - 1) / Unit.bitWidth }
var startIndex: Int { return 0 }
var endIndex: Int { return count }
subscript(_ index: Int) -> Unit {
let index = count - 1 - index
if Unit.bitWidth == Word.bitWidth {
return Unit(words[index])
}
else if Unit.bitWidth > Word.bitWidth {
let c = Unit.bitWidth / Word.bitWidth
var unit: Unit = 0
var j = 0
for i in (c * index) ..< Swift.min(c * (index + 1), words.endIndex) {
unit |= Unit(words[i]) << j
j += Word.bitWidth
}
return unit
}
// Unit.bitWidth < Word.bitWidth
let c = Word.bitWidth / Unit.bitWidth
let i = index / c
let j = index % c
return Unit(truncatingIfNeeded: words[i] >> (j * Unit.bitWidth))
}
}
}
extension Array where Element: FixedWidthInteger {
// Big-endian to little-endian
init<Unit: FixedWidthInteger>(count: Int?, generator: () throws -> Unit?) rethrows {
typealias Word = Element
precondition(Word.bitWidth % Unit.bitWidth == 0 || Unit.bitWidth % Word.bitWidth == 0)
self = []
if Unit.bitWidth == Word.bitWidth {
if let count = count {
self.reserveCapacity(count)
}
while let unit = try generator() {
self.append(Word(unit))
}
}
else if Unit.bitWidth > Word.bitWidth {
let wordsPerUnit = Unit.bitWidth / Word.bitWidth
if let count = count {
self.reserveCapacity(count * wordsPerUnit)
}
while let unit = try generator() {
var shift = Unit.bitWidth - Word.bitWidth
while shift >= 0 {
self.append(Word(truncatingIfNeeded: unit >> shift))
shift -= Word.bitWidth
}
}
}
else {
let unitsPerWord = Word.bitWidth / Unit.bitWidth
if let count = count {
self.reserveCapacity((count + unitsPerWord - 1) / unitsPerWord)
}
var word: Word = 0
var c = 0
while let unit = try generator() {
word <<= Unit.bitWidth
word |= Word(unit)
c += Unit.bitWidth
if c == Word.bitWidth {
self.append(word)
word = 0
c = 0
}
}
if c > 0 {
self.append(word << c)
var shifted: Word = 0
for i in self.indices {
let word = self[i]
self[i] = shifted | (word >> c)
shifted = word << (Word.bitWidth - c)
}
}
}
self.reverse()
}
}
extension CS.BigInt: Codable {
public init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
// Decode sign
let sign: CS.BigInt.Sign
switch try container.decode(String.self) {
case "+":
sign = .plus
case "-":
sign = .minus
default:
throw DecodingError.dataCorrupted(.init(codingPath: container.codingPath,
debugDescription: "Invalid big integer sign"))
}
// Decode magnitude
let words = try [UInt](count: container.count?.advanced(by: -1)) { () -> UInt64? in
guard !container.isAtEnd else { return nil }
return try container.decode(UInt64.self)
}
let magnitude = CS.BigUInt(words: words)
self.init(sign: sign, magnitude: magnitude)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.unkeyedContainer()
try container.encode(sign == .plus ? "+" : "-")
let units = CS.Units(of: UInt64.self, self.magnitude.words)
if units.isEmpty {
try container.encode(0 as UInt64)
}
else {
try container.encode(contentsOf: units)
}
}
}
extension CS.BigUInt: Codable {
public init(from decoder: Decoder) throws {
let value = try CS.BigInt(from: decoder)
guard value.sign == .plus else {
throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath,
debugDescription: "BigUInt cannot hold a negative value"))
}
self = value.magnitude
}
public func encode(to encoder: Encoder) throws {
try CS.BigInt(sign: .plus, magnitude: self).encode(to: encoder)
}
}

View File

@ -1,63 +0,0 @@
//
// Comparable.swift
// CS.BigInt
//
// Created by Károly Lőrentey on 2016-01-03.
// Copyright © 2016-2017 Károly Lőrentey.
//
import Foundation
extension CS.BigUInt: Comparable {
//MARK: Comparison
/// Compare `a` to `b` and return an `NSComparisonResult` indicating their order.
///
/// - Complexity: O(count)
public static func compare(_ a: CS.BigUInt, _ b: CS.BigUInt) -> ComparisonResult {
if a.count != b.count { return a.count > b.count ? .orderedDescending : .orderedAscending }
for i in (0 ..< a.count).reversed() {
let ad = a[i]
let bd = b[i]
if ad != bd { return ad > bd ? .orderedDescending : .orderedAscending }
}
return .orderedSame
}
/// Return true iff `a` is equal to `b`.
///
/// - Complexity: O(count)
public static func ==(a: CS.BigUInt, b: CS.BigUInt) -> Bool {
return CS.BigUInt.compare(a, b) == .orderedSame
}
/// Return true iff `a` is less than `b`.
///
/// - Complexity: O(count)
public static func <(a: CS.BigUInt, b: CS.BigUInt) -> Bool {
return CS.BigUInt.compare(a, b) == .orderedAscending
}
}
extension CS.BigInt {
/// Return true iff `a` is equal to `b`.
public static func ==(a: CS.BigInt, b: CS.BigInt) -> Bool {
return a.sign == b.sign && a.magnitude == b.magnitude
}
/// Return true iff `a` is less than `b`.
public static func <(a: CS.BigInt, b: CS.BigInt) -> Bool {
switch (a.sign, b.sign) {
case (.plus, .plus):
return a.magnitude < b.magnitude
case (.plus, .minus):
return false
case (.minus, .plus):
return true
case (.minus, .minus):
return a.magnitude > b.magnitude
}
}
}

View File

@ -1,179 +0,0 @@
//
// Data Conversion.swift
// BigInt
//
// Created by Károly Lőrentey on 2016-01-04.
// Copyright © 2016-2017 Károly Lőrentey.
//
import Foundation
extension CS.BigUInt {
//MARK: NSData Conversion
/// Initialize a BigInt from bytes accessed from an UnsafeRawBufferPointer
public init(_ buffer: UnsafeRawBufferPointer) {
// This assumes Word is binary.
precondition(Word.bitWidth % 8 == 0)
self.init()
let length = buffer.count
guard length > 0 else { return }
let bytesPerDigit = Word.bitWidth / 8
var index = length / bytesPerDigit
var c = bytesPerDigit - length % bytesPerDigit
if c == bytesPerDigit {
c = 0
index -= 1
}
var word: Word = 0
for byte in buffer {
word <<= 8
word += Word(byte)
c += 1
if c == bytesPerDigit {
self[index] = word
index -= 1
c = 0
word = 0
}
}
assert(c == 0 && word == 0 && index == -1)
}
/// Initializes an integer from the bits stored inside a piece of `Data`.
/// The data is assumed to be in network (big-endian) byte order.
public init(_ data: Data) {
// This assumes Word is binary.
precondition(Word.bitWidth % 8 == 0)
self.init()
let length = data.count
guard length > 0 else { return }
let bytesPerDigit = Word.bitWidth / 8
var index = length / bytesPerDigit
var c = bytesPerDigit - length % bytesPerDigit
if c == bytesPerDigit {
c = 0
index -= 1
}
let word: Word = data.withUnsafeBytes { buffPtr in
var word: Word = 0
let p = buffPtr.bindMemory(to: UInt8.self)
for byte in p {
word <<= 8
word += Word(byte)
c += 1
if c == bytesPerDigit {
self[index] = word
index -= 1
c = 0
word = 0
}
}
return word
}
assert(c == 0 && word == 0 && index == -1)
}
/// Return a `Data` value that contains the base-256 representation of this integer, in network (big-endian) byte order.
public func serialize() -> Data {
// This assumes Digit is binary.
precondition(Word.bitWidth % 8 == 0)
let byteCount = (self.bitWidth + 7) / 8
guard byteCount > 0 else { return Data() }
var data = Data(count: byteCount)
data.withUnsafeMutableBytes { buffPtr in
let p = buffPtr.bindMemory(to: UInt8.self)
var i = byteCount - 1
for var word in self.words {
for _ in 0 ..< Word.bitWidth / 8 {
p[i] = UInt8(word & 0xFF)
word >>= 8
if i == 0 {
assert(word == 0)
break
}
i -= 1
}
}
}
return data
}
}
extension CS.BigInt {
/// Initialize a BigInt from bytes accessed from an UnsafeRawBufferPointer,
/// where the first byte indicates sign (0 for positive, 1 for negative)
public init(_ buffer: UnsafeRawBufferPointer) {
// This assumes Word is binary.
precondition(Word.bitWidth % 8 == 0)
self.init()
let length = buffer.count
// Serialized data for a BigInt should contain at least 2 bytes: one representing
// the sign, and another for the non-zero magnitude. Zero is represented by an
// empty Data struct, and negative zero is not supported.
guard length > 1, let firstByte = buffer.first else { return }
// The first byte gives the sign
// This byte is compared to a bitmask to allow additional functionality to be added
// to this byte in the future.
self.sign = firstByte & 0b1 == 0 ? .plus : .minus
self.magnitude = CS.BigUInt(UnsafeRawBufferPointer(rebasing: buffer.dropFirst(1)))
}
/// Initializes an integer from the bits stored inside a piece of `Data`.
/// The data is assumed to be in network (big-endian) byte order with a first
/// byte to represent the sign (0 for positive, 1 for negative)
public init(_ data: Data) {
// This assumes Word is binary.
// This is the same assumption made when initializing CS.BigUInt from Data
precondition(Word.bitWidth % 8 == 0)
self.init()
// Serialized data for a BigInt should contain at least 2 bytes: one representing
// the sign, and another for the non-zero magnitude. Zero is represented by an
// empty Data struct, and negative zero is not supported.
guard data.count > 1, let firstByte = data.first else { return }
// The first byte gives the sign
// This byte is compared to a bitmask to allow additional functionality to be added
// to this byte in the future.
self.sign = firstByte & 0b1 == 0 ? .plus : .minus
// The remaining bytes are read and stored as the magnitude
self.magnitude = CS.BigUInt(data.dropFirst(1))
}
/// Return a `Data` value that contains the base-256 representation of this integer, in network (big-endian) byte order and a prepended byte to indicate the sign (0 for positive, 1 for negative)
public func serialize() -> Data {
// Create a data object for the magnitude portion of the BigInt
let magnitudeData = self.magnitude.serialize()
// Similar to CS.BigUInt, a value of 0 should return an initialized, empty Data struct
guard magnitudeData.count > 0 else { return magnitudeData }
// Create a new Data struct for the signed BigInt value
var data = Data(capacity: magnitudeData.count + 1)
// The first byte should be 0 for a positive value, or 1 for a negative value
// i.e., the sign bit is the LSB
data.append(self.sign == .plus ? 0 : 1)
data.append(magnitudeData)
return data
}
}

View File

@ -1,375 +0,0 @@
//
// Division.swift
// CS.BigInt
//
// Created by Károly Lőrentey on 2016-01-03.
// Copyright © 2016-2017 Károly Lőrentey.
//
//MARK: Full-width multiplication and division
// TODO: Return to `where Magnitude == Self` when SR-13491 is resolved
extension FixedWidthInteger {
private var halfShift: Self {
return Self(Self.bitWidth / 2)
}
private var high: Self {
return self &>> halfShift
}
private var low: Self {
let mask: Self = 1 &<< halfShift - 1
return self & mask
}
private var upshifted: Self {
return self &<< halfShift
}
private var split: (high: Self, low: Self) {
return (self.high, self.low)
}
private init(_ value: (high: Self, low: Self)) {
self = value.high.upshifted + value.low
}
/// Divide the double-width integer `dividend` by `self` and return the quotient and remainder.
///
/// - Requires: `dividend.high < self`, so that the result will fit in a single digit.
/// - Complexity: O(1) with 2 divisions, 6 multiplications and ~12 or so additions/subtractions.
internal func fastDividingFullWidth(_ dividend: (high: Self, low: Self.Magnitude)) -> (quotient: Self, remainder: Self) {
// Division is complicated; doing it with single-digit operations is maddeningly complicated.
// This is a Swift adaptation for "divlu2" in Hacker's Delight,
// which is in turn a C adaptation of Knuth's Algorithm D (TAOCP vol 2, 4.3.1).
precondition(dividend.high < self)
// This replaces the implementation in stdlib, which is much slower.
// FIXME: Speed up stdlib. It should use full-width idiv on Intel processors, and
// fall back to a reasonably fast algorithm elsewhere.
// The trick here is that we're actually implementing a 4/2 long division using half-words,
// with the long division loop unrolled into two 3/2 half-word divisions.
// Luckily, 3/2 half-word division can be approximated by a single full-word division operation
// that, when the divisor is normalized, differs from the correct result by at most 2.
/// Find the half-word quotient in `u / vn`, which must be normalized.
/// `u` contains three half-words in the two halves of `u.high` and the lower half of
/// `u.low`. (The weird distribution makes for a slightly better fit with the input.)
/// `vn` contains the normalized divisor, consisting of two half-words.
///
/// - Requires: u.high < vn && u.low.high == 0 && vn.leadingZeroBitCount == 0
func quotient(dividing u: (high: Self, low: Self), by vn: Self) -> Self {
let (vn1, vn0) = vn.split
// Get approximate quotient.
let (q, r) = u.high.quotientAndRemainder(dividingBy: vn1)
let p = q * vn0
// q is often already correct, but sometimes the approximation overshoots by at most 2.
// The code that follows checks for this while being careful to only perform single-digit operations.
if q.high == 0 && p <= r.upshifted + u.low { return q }
let r2 = r + vn1
if r2.high != 0 { return q - 1 }
if (q - 1).high == 0 && p - vn0 <= r2.upshifted + u.low { return q - 1 }
//assert((r + 2 * vn1).high != 0 || p - 2 * vn0 <= (r + 2 * vn1).upshifted + u.low)
return q - 2
}
/// Divide 3 half-digits by 2 half-digits to get a half-digit quotient and a full-digit remainder.
///
/// - Requires: u.high < v && u.low.high == 0 && vn.width = width(Digit)
func quotientAndRemainder(dividing u: (high: Self, low: Self), by v: Self) -> (quotient: Self, remainder: Self) {
let q = quotient(dividing: u, by: v)
// Note that `uh.low` masks off a couple of bits, and `q * v` and the
// subtraction are likely to overflow. Despite this, the end result (remainder) will
// still be correct and it will fit inside a single (full) Digit.
let r = Self(u) &- q &* v
assert(r < v)
return (q, r)
}
// Normalize the dividend and the divisor (self) such that the divisor has no leading zeroes.
let z = Self(self.leadingZeroBitCount)
let w = Self(Self.bitWidth) - z
let vn = self << z
let un32 = (z == 0 ? dividend.high : (dividend.high &<< z) | ((dividend.low as! Self) &>> w)) // No bits are lost
let un10 = dividend.low &<< z
let (un1, un0) = un10.split
// Divide `(un32,un10)` by `vn`, splitting the full 4/2 division into two 3/2 ones.
let (q1, un21) = quotientAndRemainder(dividing: (un32, (un1 as! Self)), by: vn)
let (q0, rn) = quotientAndRemainder(dividing: (un21, (un0 as! Self)), by: vn)
// Undo normalization of the remainder and combine the two halves of the quotient.
let mod = rn >> z
let div = Self((q1, q0))
return (div, mod)
}
/// Return the quotient of the 3/2-word division `x/y` as a single word.
///
/// - Requires: (x.0, x.1) <= y && y.0.high != 0
/// - Returns: The exact value when it fits in a single word, otherwise `Self`.
static func approximateQuotient(dividing x: (Self, Self, Self), by y: (Self, Self)) -> Self {
// Start with q = (x.0, x.1) / y.0, (or Word.max on overflow)
var q: Self
var r: Self
if x.0 == y.0 {
q = Self.max
let (s, o) = x.0.addingReportingOverflow(x.1)
if o { return q }
r = s
}
else {
(q, r) = y.0.fastDividingFullWidth((x.0, (x.1 as! Magnitude)))
}
// Now refine q by considering x.2 and y.1.
// Note that since y is normalized, q * y - x is between 0 and 2.
let (ph, pl) = q.multipliedFullWidth(by: y.1)
if ph < r || (ph == r && pl <= x.2) { return q }
let (r1, ro) = r.addingReportingOverflow(y.0)
if ro { return q - 1 }
let (pl1, so) = pl.subtractingReportingOverflow((y.1 as! Magnitude))
let ph1 = (so ? ph - 1 : ph)
if ph1 < r1 || (ph1 == r1 && pl1 <= x.2) { return q - 1 }
return q - 2
}
}
extension CS.BigUInt {
//MARK: Division
/// Divide this integer by the word `y`, leaving the quotient in its place and returning the remainder.
///
/// - Requires: y > 0
/// - Complexity: O(count)
internal mutating func divide(byWord y: Word) -> Word {
precondition(y > 0)
if y == 1 { return 0 }
var remainder: Word = 0
for i in (0 ..< count).reversed() {
let u = self[i]
(self[i], remainder) = y.fastDividingFullWidth((remainder, u))
}
return remainder
}
/// Divide this integer by the word `y` and return the resulting quotient and remainder.
///
/// - Requires: y > 0
/// - Returns: (quotient, remainder) where quotient = floor(x/y), remainder = x - quotient * y
/// - Complexity: O(x.count)
internal func quotientAndRemainder(dividingByWord y: Word) -> (quotient: CS.BigUInt, remainder: Word) {
var div = self
let mod = div.divide(byWord: y)
return (div, mod)
}
/// Divide `x` by `y`, putting the quotient in `x` and the remainder in `y`.
/// Reusing integers like this reduces the number of allocations during the calculation.
static func divide(_ x: inout CS.BigUInt, by y: inout CS.BigUInt) {
// This is a Swift adaptation of "divmnu" from Hacker's Delight, which is in
// turn a C adaptation of Knuth's Algorithm D (TAOCP vol 2, 4.3.1).
precondition(!y.isZero)
// First, let's take care of the easy cases.
if x < y {
(x, y) = (0, x)
return
}
if y.count == 1 {
// The single-word case reduces to a simpler loop.
y = CS.BigUInt(x.divide(byWord: y[0]))
return
}
// In the hard cases, we will perform the long division algorithm we learned in school.
// It works by successively calculating the single-word quotient of the top y.count + 1
// words of x divided by y, replacing the top of x with the remainder, and repeating
// the process one word lower.
//
// The tricky part is that the algorithm needs to be able to do n+1/n word divisions,
// but we only have a primitive for dividing two words by a single
// word. (Remember that this step is also tricky when we do it on paper!)
//
// The solution is that the long division can be approximated by a single full division
// using just the most significant words. We can then use multiplications and
// subtractions to refine the approximation until we get the correct quotient word.
//
// We could do this by doing a simple 2/1 full division, but Knuth goes one step further,
// and implements a 3/2 division. This results in an exact approximation in the
// vast majority of cases, eliminating an extra subtraction over big integers.
//
// The function `approximateQuotient` above implements Knuth's 3/2 division algorithm.
// It requires that the divisor's most significant word is larger than
// Word.max / 2. This ensures that the approximation has tiny error bounds,
// which is what makes this entire approach viable.
// To satisfy this requirement, we will normalize the division by multiplying
// both the divisor and the dividend by the same (small) factor.
let z = y.leadingZeroBitCount
y <<= z
x <<= z // We'll calculate the remainder in the normalized dividend.
var quotient = CS.BigUInt()
assert(y.leadingZeroBitCount == 0)
// We're ready to start the long division!
let dc = y.count
let d1 = y[dc - 1]
let d0 = y[dc - 2]
var product: CS.BigUInt = 0
for j in (dc ... x.count).reversed() {
// Approximate dividing the top dc+1 words of `remainder` using the topmost 3/2 words.
let r2 = x[j]
let r1 = x[j - 1]
let r0 = x[j - 2]
let q = Word.approximateQuotient(dividing: (r2, r1, r0), by: (d1, d0))
// Multiply the entire divisor with `q` and subtract the result from remainder.
// Normalization ensures the 3/2 quotient will either be exact for the full division, or
// it may overshoot by at most 1, in which case the product will be greater
// than the remainder.
product.load(y)
product.multiply(byWord: q)
if product <= x.extract(j - dc ..< j + 1) {
x.subtract(product, shiftedBy: j - dc)
quotient[j - dc] = q
}
else {
// This case is extremely rare -- it has a probability of 1/2^(Word.bitWidth - 1).
x.add(y, shiftedBy: j - dc)
x.subtract(product, shiftedBy: j - dc)
quotient[j - dc] = q - 1
}
}
// The remainder's normalization needs to be undone, but otherwise we're done.
x >>= z
y = x
x = quotient
}
/// Divide `x` by `y`, putting the remainder in `x`.
mutating func formRemainder(dividingBy y: CS.BigUInt, normalizedBy shift: Int) {
precondition(!y.isZero)
assert(y.leadingZeroBitCount == 0)
if y.count == 1 {
let remainder = self.divide(byWord: y[0] >> shift)
self.load(CS.BigUInt(remainder))
return
}
self <<= shift
if self >= y {
let dc = y.count
let d1 = y[dc - 1]
let d0 = y[dc - 2]
var product: CS.BigUInt = 0
for j in (dc ... self.count).reversed() {
let r2 = self[j]
let r1 = self[j - 1]
let r0 = self[j - 2]
let q = Word.approximateQuotient(dividing: (r2, r1, r0), by: (d1, d0))
product.load(y)
product.multiply(byWord: q)
if product <= self.extract(j - dc ..< j + 1) {
self.subtract(product, shiftedBy: j - dc)
}
else {
self.add(y, shiftedBy: j - dc)
self.subtract(product, shiftedBy: j - dc)
}
}
}
self >>= shift
}
/// Divide this integer by `y` and return the resulting quotient and remainder.
///
/// - Requires: `y > 0`
/// - Returns: `(quotient, remainder)` where `quotient = floor(self/y)`, `remainder = self - quotient * y`
/// - Complexity: O(count^2)
public func quotientAndRemainder(dividingBy y: CS.BigUInt) -> (quotient: CS.BigUInt, remainder: CS.BigUInt) {
var x = self
var y = y
CS.BigUInt.divide(&x, by: &y)
return (x, y)
}
/// Divide `x` by `y` and return the quotient.
///
/// - Note: Use `divided(by:)` if you also need the remainder.
public static func /(x: CS.BigUInt, y: CS.BigUInt) -> CS.BigUInt {
return x.quotientAndRemainder(dividingBy: y).quotient
}
/// Divide `x` by `y` and return the remainder.
///
/// - Note: Use `divided(by:)` if you also need the remainder.
public static func %(x: CS.BigUInt, y: CS.BigUInt) -> CS.BigUInt {
var x = x
let shift = y.leadingZeroBitCount
x.formRemainder(dividingBy: y << shift, normalizedBy: shift)
return x
}
/// Divide `x` by `y` and store the quotient in `x`.
///
/// - Note: Use `divided(by:)` if you also need the remainder.
public static func /=(x: inout CS.BigUInt, y: CS.BigUInt) {
var y = y
CS.BigUInt.divide(&x, by: &y)
}
/// Divide `x` by `y` and store the remainder in `x`.
///
/// - Note: Use `divided(by:)` if you also need the remainder.
public static func %=(x: inout CS.BigUInt, y: CS.BigUInt) {
let shift = y.leadingZeroBitCount
x.formRemainder(dividingBy: y << shift, normalizedBy: shift)
}
}
extension CS.BigInt {
/// Divide this integer by `y` and return the resulting quotient and remainder.
///
/// - Requires: `y > 0`
/// - Returns: `(quotient, remainder)` where `quotient = floor(self/y)`, `remainder = self - quotient * y`
/// - Complexity: O(count^2)
public func quotientAndRemainder(dividingBy y: CS.BigInt) -> (quotient: CS.BigInt, remainder: CS.BigInt) {
var a = self.magnitude
var b = y.magnitude
CS.BigUInt.divide(&a, by: &b)
return ( CS.BigInt(sign: self.sign == y.sign ? .plus : .minus, magnitude: a),
CS.BigInt(sign: self.sign, magnitude: b))
}
/// Divide `a` by `b` and return the quotient. Traps if `b` is zero.
public static func /(a: CS.BigInt, b: CS.BigInt) -> CS.BigInt {
return CS.BigInt(sign: a.sign == b.sign ? .plus : .minus, magnitude: a.magnitude / b.magnitude)
}
/// Divide `a` by `b` and return the remainder. The result has the same sign as `a`.
public static func %(a: CS.BigInt, b: CS.BigInt) -> CS.BigInt {
return CS.BigInt(sign: a.sign, magnitude: a.magnitude % b.magnitude)
}
/// Return the result of `a` mod `b`. The result is always a nonnegative integer that is less than the absolute value of `b`.
public func modulus(_ mod: CS.BigInt) -> CS.BigInt {
let remainder = self.magnitude % mod.magnitude
return CS.BigInt(
self.sign == .minus && !remainder.isZero
? mod.magnitude - remainder
: remainder)
}
}
extension CS.BigInt {
/// Divide `a` by `b` storing the quotient in `a`.
public static func /=(a: inout CS.BigInt, b: CS.BigInt) { a = a / b }
/// Divide `a` by `b` storing the remainder in `a`.
public static func %=(a: inout CS.BigInt, b: CS.BigInt) { a = a % b }
}

View File

@ -1,119 +0,0 @@
//
// Exponentiation.swift
// CS.BigInt
//
// Created by Károly Lőrentey on 2016-01-03.
// Copyright © 2016-2017 Károly Lőrentey.
//
extension CS.BigUInt {
//MARK: Exponentiation
/// Returns this integer raised to the power `exponent`.
///
/// This function calculates the result by [successively squaring the base while halving the exponent][expsqr].
///
/// [expsqr]: https://en.wikipedia.org/wiki/Exponentiation_by_squaring
///
/// - Note: This function can be unreasonably expensive for large exponents, which is why `exponent` is
/// a simple integer value. If you want to calculate big exponents, you'll probably need to use
/// the modulo arithmetic variant.
/// - Returns: 1 if `exponent == 0`, otherwise `self` raised to `exponent`. (This implies that `0.power(0) == 1`.)
/// - SeeAlso: `BigUInt.power(_:, modulus:)`
/// - Complexity: O((exponent * self.count)^log2(3)) or somesuch. The result may require a large amount of memory, too.
public func power(_ exponent: Int) -> CS.BigUInt {
if exponent == 0 { return 1 }
if exponent == 1 { return self }
if exponent < 0 {
precondition(!self.isZero)
return self == 1 ? 1 : 0
}
if self <= 1 { return self }
var result = CS.BigUInt(1)
var b = self
var e = exponent
while e > 0 {
if e & 1 == 1 {
result *= b
}
e >>= 1
b *= b
}
return result
}
/// Returns the remainder of this integer raised to the power `exponent` in modulo arithmetic under `modulus`.
///
/// Uses the [right-to-left binary method][rtlb].
///
/// [rtlb]: https://en.wikipedia.org/wiki/Modular_exponentiation#Right-to-left_binary_method
///
/// - Complexity: O(exponent.count * modulus.count^log2(3)) or somesuch
public func power(_ exponent: CS.BigUInt, modulus: CS.BigUInt) -> CS.BigUInt {
precondition(!modulus.isZero)
if modulus == (1 as CS.BigUInt) { return 0 }
let shift = modulus.leadingZeroBitCount
let normalizedModulus = modulus << shift
var result = CS.BigUInt(1)
var b = self
b.formRemainder(dividingBy: normalizedModulus, normalizedBy: shift)
for var e in exponent.words {
for _ in 0 ..< Word.bitWidth {
if e & 1 == 1 {
result *= b
result.formRemainder(dividingBy: normalizedModulus, normalizedBy: shift)
}
e >>= 1
b *= b
b.formRemainder(dividingBy: normalizedModulus, normalizedBy: shift)
}
}
return result
}
}
extension CS.BigInt {
/// Returns this integer raised to the power `exponent`.
///
/// This function calculates the result by [successively squaring the base while halving the exponent][expsqr].
///
/// [expsqr]: https://en.wikipedia.org/wiki/Exponentiation_by_squaring
///
/// - Note: This function can be unreasonably expensive for large exponents, which is why `exponent` is
/// a simple integer value. If you want to calculate big exponents, you'll probably need to use
/// the modulo arithmetic variant.
/// - Returns: 1 if `exponent == 0`, otherwise `self` raised to `exponent`. (This implies that `0.power(0) == 1`.)
/// - SeeAlso: `BigUInt.power(_:, modulus:)`
/// - Complexity: O((exponent * self.count)^log2(3)) or somesuch. The result may require a large amount of memory, too.
public func power(_ exponent: Int) -> CS.BigInt {
return CS.BigInt(sign: self.sign == .minus && exponent & 1 != 0 ? .minus : .plus,
magnitude: self.magnitude.power(exponent))
}
/// Returns the remainder of this integer raised to the power `exponent` in modulo arithmetic under `modulus`.
///
/// Uses the [right-to-left binary method][rtlb].
///
/// [rtlb]: https://en.wikipedia.org/wiki/Modular_exponentiation#Right-to-left_binary_method
///
/// - Complexity: O(exponent.count * modulus.count^log2(3)) or somesuch
public func power(_ exponent: CS.BigInt, modulus: CS.BigInt) -> CS.BigInt {
precondition(!modulus.isZero)
if modulus.magnitude == 1 { return 0 }
if exponent.isZero { return 1 }
if exponent == 1 { return self.modulus(modulus) }
if exponent < 0 {
precondition(!self.isZero)
guard magnitude == 1 else { return 0 }
guard sign == .minus else { return 1 }
guard exponent.magnitude[0] & 1 != 0 else { return 1 }
return CS.BigInt(modulus.magnitude - 1)
}
let power = self.magnitude.power(exponent.magnitude,
modulus: modulus.magnitude)
if self.sign == .plus || exponent.magnitude[0] & 1 == 0 || power.isZero {
return CS.BigInt(power)
}
return CS.BigInt(modulus.magnitude - power)
}
}

View File

@ -1,73 +0,0 @@
//
// Floating Point Conversion.swift
// CS.BigInt
//
// Created by Károly Lőrentey on 2017-08-11.
// Copyright © 2016-2017 Károly Lőrentey.
//
extension CS.BigUInt {
public init?<T: BinaryFloatingPoint>(exactly source: T) {
guard source.isFinite else { return nil }
guard !source.isZero else { self = 0; return }
guard source.sign == .plus else { return nil }
let value = source.rounded(.towardZero)
guard value == source else { return nil }
assert(value.floatingPointClass == .positiveNormal)
assert(value.exponent >= 0)
let significand = value.significandBitPattern
self = (CS.BigUInt(1) << value.exponent) + CS.BigUInt(significand) >> (T.significandBitCount - Int(value.exponent))
}
public init<T: BinaryFloatingPoint>(_ source: T) {
self.init(exactly: source.rounded(.towardZero))!
}
}
extension CS.BigInt {
public init?<T: BinaryFloatingPoint>(exactly source: T) {
switch source.sign{
case .plus:
guard let magnitude = CS.BigUInt(exactly: source) else { return nil }
self = CS.BigInt(sign: .plus, magnitude: magnitude)
case .minus:
guard let magnitude = CS.BigUInt(exactly: -source) else { return nil }
self = CS.BigInt(sign: .minus, magnitude: magnitude)
}
}
public init<T: BinaryFloatingPoint>(_ source: T) {
self.init(exactly: source.rounded(.towardZero))!
}
}
extension BinaryFloatingPoint where RawExponent: FixedWidthInteger, RawSignificand: FixedWidthInteger {
public init(_ value: CS.BigInt) {
guard !value.isZero else { self = 0; return }
let v = value.magnitude
let bitWidth = v.bitWidth
var exponent = bitWidth - 1
let shift = bitWidth - Self.significandBitCount - 1
var significand = value.magnitude >> (shift - 1)
if significand[0] & 3 == 3 { // Handle rounding
significand >>= 1
significand += 1
if significand.trailingZeroBitCount >= Self.significandBitCount {
exponent += 1
}
}
else {
significand >>= 1
}
let bias = 1 << (Self.exponentBitCount - 1) - 1
guard exponent <= bias else { self = Self.infinity; return }
significand &= 1 << Self.significandBitCount - 1
self = Self.init(sign: value.sign == .plus ? .plus : .minus,
exponentBitPattern: RawExponent(bias + exponent),
significandBitPattern: RawSignificand(significand))
}
public init(_ value: CS.BigUInt) {
self.init(CS.BigInt(sign: .plus, magnitude: value))
}
}

View File

@ -1,80 +0,0 @@
//
// GCD.swift
// CS.BigInt
//
// Created by Károly Lőrentey on 2016-01-03.
// Copyright © 2016-2017 Károly Lőrentey.
//
extension CS.BigUInt {
//MARK: Greatest Common Divisor
/// Returns the greatest common divisor of `self` and `b`.
///
/// - Complexity: O(count^2) where count = max(self.count, b.count)
public func greatestCommonDivisor(with b: CS.BigUInt) -> CS.BigUInt {
// This is Stein's algorithm: https://en.wikipedia.org/wiki/Binary_GCD_algorithm
if self.isZero { return b }
if b.isZero { return self }
let az = self.trailingZeroBitCount
let bz = b.trailingZeroBitCount
let twos = Swift.min(az, bz)
var (x, y) = (self >> az, b >> bz)
if x < y { swap(&x, &y) }
while !x.isZero {
x >>= x.trailingZeroBitCount
if x < y { swap(&x, &y) }
x -= y
}
return y << twos
}
/// Returns the [multiplicative inverse of this integer in modulo `modulus` arithmetic][inverse],
/// or `nil` if there is no such number.
///
/// [inverse]: https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Modular_integers
///
/// - Returns: If `gcd(self, modulus) == 1`, the value returned is an integer `a < modulus` such that `(a * self) % modulus == 1`. If `self` and `modulus` aren't coprime, the return value is `nil`.
/// - Requires: modulus > 1
/// - Complexity: O(count^3)
public func inverse(_ modulus: CS.BigUInt) -> CS.BigUInt? {
precondition(modulus > 1)
var t1 = CS.BigInt(0)
var t2 = CS.BigInt(1)
var r1 = modulus
var r2 = self
while !r2.isZero {
let quotient = r1 / r2
(t1, t2) = (t2, t1 - CS.BigInt(quotient) * t2)
(r1, r2) = (r2, r1 - quotient * r2)
}
if r1 > 1 { return nil }
if t1.sign == .minus { return modulus - t1.magnitude }
return t1.magnitude
}
}
extension CS.BigInt {
/// Returns the greatest common divisor of `a` and `b`.
///
/// - Complexity: O(count^2) where count = max(a.count, b.count)
public func greatestCommonDivisor(with b: CS.BigInt) -> CS.BigInt {
return CS.BigInt(self.magnitude.greatestCommonDivisor(with: b.magnitude))
}
/// Returns the [multiplicative inverse of this integer in modulo `modulus` arithmetic][inverse],
/// or `nil` if there is no such number.
///
/// [inverse]: https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Modular_integers
///
/// - Returns: If `gcd(self, modulus) == 1`, the value returned is an integer `a < modulus` such that `(a * self) % modulus == 1`. If `self` and `modulus` aren't coprime, the return value is `nil`.
/// - Requires: modulus.magnitude > 1
/// - Complexity: O(count^3)
public func inverse(_ modulus: CS.BigInt) -> CS.BigInt? {
guard let inv = self.magnitude.inverse(modulus.magnitude) else { return nil }
return CS.BigInt(self.sign == .plus || inv.isZero ? inv : modulus.magnitude - inv)
}
}

View File

@ -1,26 +0,0 @@
//
// Hashable.swift
// BigInt
//
// Created by Károly Lőrentey on 2016-01-03.
// Copyright © 2016-2017 Károly Lőrentey.
//
extension CS.BigUInt: Hashable {
//MARK: Hashing
/// Append this `BigUInt` to the specified hasher.
public func hash(into hasher: inout Hasher) {
for word in self.words {
hasher.combine(word)
}
}
}
extension CS.BigInt: Hashable {
/// Append this `BigInt` to the specified hasher.
public func hash(into hasher: inout Hasher) {
hasher.combine(sign)
hasher.combine(magnitude)
}
}

View File

@ -1,89 +0,0 @@
//
// Integer Conversion.swift
// CS.BigInt
//
// Created by Károly Lőrentey on 2017-08-11.
// Copyright © 2016-2017 Károly Lőrentey.
//
extension CS.BigUInt {
public init?<T: BinaryInteger>(exactly source: T) {
guard source >= (0 as T) else { return nil }
if source.bitWidth <= 2 * Word.bitWidth {
var it = source.words.makeIterator()
self.init(low: it.next() ?? 0, high: it.next() ?? 0)
precondition(it.next() == nil, "Length of BinaryInteger.words is greater than its bitWidth")
}
else {
self.init(words: source.words)
}
}
public init<T: BinaryInteger>(_ source: T) {
precondition(source >= (0 as T), "BigUInt cannot represent negative values")
self.init(exactly: source)!
}
public init<T: BinaryInteger>(truncatingIfNeeded source: T) {
self.init(words: source.words)
}
public init<T: BinaryInteger>(clamping source: T) {
if source <= (0 as T) {
self.init()
}
else {
self.init(words: source.words)
}
}
}
extension CS.BigInt {
public init() {
self.init(sign: .plus, magnitude: 0)
}
/// Initializes a new signed big integer with the same value as the specified unsigned big integer.
public init(_ integer: CS.BigUInt) {
self.magnitude = integer
self.sign = .plus
}
public init<T>(_ source: T) where T : BinaryInteger {
if source >= (0 as T) {
self.init(sign: .plus, magnitude: CS.BigUInt(source))
}
else {
var words = Array(source.words)
words.twosComplement()
self.init(sign: .minus, magnitude: CS.BigUInt(words: words))
}
}
public init?<T>(exactly source: T) where T : BinaryInteger {
self.init(source)
}
public init<T>(clamping source: T) where T : BinaryInteger {
self.init(source)
}
public init<T>(truncatingIfNeeded source: T) where T : BinaryInteger {
self.init(source)
}
}
extension CS.BigUInt: ExpressibleByIntegerLiteral {
/// Initialize a new big integer from an integer literal.
public init(integerLiteral value: UInt64) {
self.init(value)
}
}
extension CS.BigInt: ExpressibleByIntegerLiteral {
/// Initialize a new big integer from an integer literal.
public init(integerLiteral value: Int64) {
self.init(value)
}
}

View File

@ -1,165 +0,0 @@
//
// Multiplication.swift
// CS.BigInt
//
// Created by Károly Lőrentey on 2016-01-03.
// Copyright © 2016-2017 Károly Lőrentey.
//
extension CS.BigUInt {
//MARK: Multiplication
/// Multiply this big integer by a single word, and store the result in place of the original big integer.
///
/// - Complexity: O(count)
public mutating func multiply(byWord y: Word) {
guard y != 0 else { self = 0; return }
guard y != 1 else { return }
var carry: Word = 0
let c = self.count
for i in 0 ..< c {
let (h, l) = self[i].multipliedFullWidth(by: y)
let (low, o) = l.addingReportingOverflow(carry)
self[i] = low
carry = (o ? h + 1 : h)
}
self[c] = carry
}
/// Multiply this big integer by a single Word, and return the result.
///
/// - Complexity: O(count)
public func multiplied(byWord y: Word) -> CS.BigUInt {
var r = self
r.multiply(byWord: y)
return r
}
/// Multiply `x` by `y`, and add the result to this integer, optionally shifted `shift` words to the left.
///
/// - Note: This is the fused multiply/shift/add operation; it is more efficient than doing the components
/// individually. (The fused operation doesn't need to allocate space for temporary big integers.)
/// - Returns: `self` is set to `self + (x * y) << (shift * 2^Word.bitWidth)`
/// - Complexity: O(count)
public mutating func multiplyAndAdd(_ x: CS.BigUInt, _ y: Word, shiftedBy shift: Int = 0) {
precondition(shift >= 0)
guard y != 0 && x.count > 0 else { return }
guard y != 1 else { self.add(x, shiftedBy: shift); return }
var mulCarry: Word = 0
var addCarry = false
let xc = x.count
var xi = 0
while xi < xc || addCarry || mulCarry > 0 {
let (h, l) = x[xi].multipliedFullWidth(by: y)
let (low, o) = l.addingReportingOverflow(mulCarry)
mulCarry = (o ? h + 1 : h)
let ai = shift + xi
let (sum1, so1) = self[ai].addingReportingOverflow(low)
if addCarry {
let (sum2, so2) = sum1.addingReportingOverflow(1)
self[ai] = sum2
addCarry = so1 || so2
}
else {
self[ai] = sum1
addCarry = so1
}
xi += 1
}
}
/// Multiply this integer by `y` and return the result.
///
/// - Note: This uses the naive O(n^2) multiplication algorithm unless both arguments have more than
/// `BigUInt.directMultiplicationLimit` words.
/// - Complexity: O(n^log2(3))
public func multiplied(by y: CS.BigUInt) -> CS.BigUInt {
// This method is mostly defined for symmetry with the rest of the arithmetic operations.
return self * y
}
/// Multiplication switches to an asymptotically better recursive algorithm when arguments have more words than this limit.
public static var directMultiplicationLimit: Int = 1024
/// Multiply `a` by `b` and return the result.
///
/// - Note: This uses the naive O(n^2) multiplication algorithm unless both arguments have more than
/// `BigUInt.directMultiplicationLimit` words.
/// - Complexity: O(n^log2(3))
public static func *(x: CS.BigUInt, y: CS.BigUInt) -> CS.BigUInt {
let xc = x.count
let yc = y.count
if xc == 0 { return CS.BigUInt() }
if yc == 0 { return CS.BigUInt() }
if yc == 1 { return x.multiplied(byWord: y[0]) }
if xc == 1 { return y.multiplied(byWord: x[0]) }
if Swift.min(xc, yc) <= CS.BigUInt.directMultiplicationLimit {
// Long multiplication.
let left = (xc < yc ? y : x)
let right = (xc < yc ? x : y)
var result = CS.BigUInt()
for i in (0 ..< right.count).reversed() {
result.multiplyAndAdd(left, right[i], shiftedBy: i)
}
return result
}
if yc < xc {
let (xh, xl) = x.split
var r = xl * y
r.add(xh * y, shiftedBy: x.middleIndex)
return r
}
else if xc < yc {
let (yh, yl) = y.split
var r = yl * x
r.add(yh * x, shiftedBy: y.middleIndex)
return r
}
let shift = x.middleIndex
// Karatsuba multiplication:
// x * y = <a,b> * <c,d> = <ac, ac + bd - (a-b)(c-d), bd> (ignoring carry)
let (a, b) = x.split
let (c, d) = y.split
let high = a * c
let low = b * d
let xp = a >= b
let yp = c >= d
let xm = (xp ? a - b : b - a)
let ym = (yp ? c - d : d - c)
let m = xm * ym
var r = low
r.add(high, shiftedBy: 2 * shift)
r.add(low, shiftedBy: shift)
r.add(high, shiftedBy: shift)
if xp == yp {
r.subtract(m, shiftedBy: shift)
}
else {
r.add(m, shiftedBy: shift)
}
return r
}
/// Multiply `a` by `b` and store the result in `a`.
public static func *=(a: inout CS.BigUInt, b: CS.BigUInt) {
a = a * b
}
}
extension CS.BigInt {
/// Multiply `a` with `b` and return the result.
public static func *(a: CS.BigInt, b: CS.BigInt) -> CS.BigInt {
return CS.BigInt(sign: a.sign == b.sign ? .plus : .minus, magnitude: a.magnitude * b.magnitude)
}
/// Multiply `a` with `b` in place.
public static func *=(a: inout CS.BigInt, b: CS.BigInt) { a = a * b }
}

View File

@ -1,153 +0,0 @@
//
// Prime Test.swift
// CS.BigInt
//
// Created by Károly Lőrentey on 2016-01-04.
// Copyright © 2016-2017 Károly Lőrentey.
//
/// The first several [prime numbers][primes].
///
/// [primes]: https://oeis.org/A000040
let primes: [CS.BigUInt.Word] = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41]
/// The ith element in this sequence is the smallest composite number that passes the strong probable prime test
/// for all of the first (i+1) primes.
///
/// This is sequence [A014233](http://oeis.org/A014233) on the [Online Encyclopaedia of Integer Sequences](http://oeis.org).
let pseudoPrimes: [CS.BigUInt] = [
/* 2 */ 2_047,
/* 3 */ 1_373_653,
/* 5 */ 25_326_001,
/* 7 */ 3_215_031_751,
/* 11 */ 2_152_302_898_747,
/* 13 */ 3_474_749_660_383,
/* 17 */ 341_550_071_728_321,
/* 19 */ 341_550_071_728_321,
/* 23 */ 3_825_123_056_546_413_051,
/* 29 */ 3_825_123_056_546_413_051,
/* 31 */ 3_825_123_056_546_413_051,
/* 37 */ "318665857834031151167461",
/* 41 */ "3317044064679887385961981",
]
extension CS.BigUInt {
//MARK: Primality Testing
/// Returns true iff this integer passes the [strong probable prime test][sppt] for the specified base.
///
/// [sppt]: https://en.wikipedia.org/wiki/Probable_prime
public func isStrongProbablePrime(_ base: CS.BigUInt) -> Bool {
precondition(base > (1 as CS.BigUInt))
precondition(self > (0 as CS.BigUInt))
let dec = self - 1
let r = dec.trailingZeroBitCount
let d = dec >> r
var test = base.power(d, modulus: self)
if test == 1 || test == dec { return true }
if r > 0 {
let shift = self.leadingZeroBitCount
let normalized = self << shift
for _ in 1 ..< r {
test *= test
test.formRemainder(dividingBy: normalized, normalizedBy: shift)
if test == 1 {
return false
}
if test == dec { return true }
}
}
return false
}
/// Returns true if this integer is probably prime. Returns false if this integer is definitely not prime.
///
/// This function performs a probabilistic [Miller-Rabin Primality Test][mrpt], consisting of `rounds` iterations,
/// each calculating the strong probable prime test for a random base. The number of rounds is 10 by default,
/// but you may specify your own choice.
///
/// To speed things up, the function checks if `self` is divisible by the first few prime numbers before
/// diving into (slower) Miller-Rabin testing.
///
/// Also, when `self` is less than 82 bits wide, `isPrime` does a deterministic test that is guaranteed to
/// return a correct result.
///
/// [mrpt]: https://en.wikipedia.org/wiki/MillerRabin_primality_test
public func isPrime(rounds: Int = 10) -> Bool {
if count <= 1 && self[0] < 2 { return false }
if count == 1 && self[0] < 4 { return true }
// Even numbers above 2 aren't prime.
if self[0] & 1 == 0 { return false }
// Quickly check for small primes.
for i in 1 ..< primes.count {
let p = primes[i]
if self.count == 1 && self[0] == p {
return true
}
if self.quotientAndRemainder(dividingByWord: p).remainder == 0 {
return false
}
}
/// Give an exact answer when we can.
if self < pseudoPrimes.last! {
for i in 0 ..< pseudoPrimes.count {
guard isStrongProbablePrime(CS.BigUInt(primes[i])) else {
break
}
if self < pseudoPrimes[i] {
// `self` is below the lowest pseudoprime corresponding to the prime bases we tested. It's a prime!
return true
}
}
return false
}
/// Otherwise do as many rounds of random SPPT as required.
for _ in 0 ..< rounds {
let random = CS.BigUInt.randomInteger(lessThan: self - 2) + 2
guard isStrongProbablePrime(random) else {
return false
}
}
// Well, it smells primey to me.
return true
}
}
extension CS.BigInt {
//MARK: Primality Testing
/// Returns true iff this integer passes the [strong probable prime test][sppt] for the specified base.
///
/// [sppt]: https://en.wikipedia.org/wiki/Probable_prime
public func isStrongProbablePrime(_ base: CS.BigInt) -> Bool {
precondition(base.sign == .plus)
if self.sign == .minus { return false }
return self.magnitude.isStrongProbablePrime(base.magnitude)
}
/// Returns true if this integer is probably prime. Returns false if this integer is definitely not prime.
///
/// This function performs a probabilistic [Miller-Rabin Primality Test][mrpt], consisting of `rounds` iterations,
/// each calculating the strong probable prime test for a random base. The number of rounds is 10 by default,
/// but you may specify your own choice.
///
/// To speed things up, the function checks if `self` is divisible by the first few prime numbers before
/// diving into (slower) Miller-Rabin testing.
///
/// Also, when `self` is less than 82 bits wide, `isPrime` does a deterministic test that is guaranteed to
/// return a correct result.
///
/// [mrpt]: https://en.wikipedia.org/wiki/MillerRabin_primality_test
public func isPrime(rounds: Int = 10) -> Bool {
if self.sign == .minus { return false }
return self.magnitude.isPrime(rounds: rounds)
}
}

View File

@ -1,101 +0,0 @@
//
// Random.swift
// CS.BigInt
//
// Created by Károly Lőrentey on 2016-01-04.
// Copyright © 2016-2017 Károly Lőrentey.
//
extension CS.BigUInt {
/// Create a big unsigned integer consisting of `width` uniformly distributed random bits.
///
/// - Parameter width: The maximum number of one bits in the result.
/// - Parameter generator: The source of randomness.
/// - Returns: A big unsigned integer less than `1 << width`.
public static func randomInteger<RNG: RandomNumberGenerator>(withMaximumWidth width: Int, using generator: inout RNG) -> CS.BigUInt {
var result = CS.BigUInt.zero
var bitsLeft = width
var i = 0
let wordsNeeded = (width + Word.bitWidth - 1) / Word.bitWidth
if wordsNeeded > 2 {
result.reserveCapacity(wordsNeeded)
}
while bitsLeft >= Word.bitWidth {
result[i] = generator.next()
i += 1
bitsLeft -= Word.bitWidth
}
if bitsLeft > 0 {
let mask: Word = (1 << bitsLeft) - 1
result[i] = (generator.next() as Word) & mask
}
return result
}
/// Create a big unsigned integer consisting of `width` uniformly distributed random bits.
///
/// - Note: I use a `SystemRandomGeneratorGenerator` as the source of randomness.
///
/// - Parameter width: The maximum number of one bits in the result.
/// - Returns: A big unsigned integer less than `1 << width`.
public static func randomInteger(withMaximumWidth width: Int) -> CS.BigUInt {
var rng = SystemRandomNumberGenerator()
return randomInteger(withMaximumWidth: width, using: &rng)
}
/// Create a big unsigned integer consisting of `width-1` uniformly distributed random bits followed by a one bit.
///
/// - Note: If `width` is zero, the result is zero.
///
/// - Parameter width: The number of bits required to represent the answer.
/// - Parameter generator: The source of randomness.
/// - Returns: A random big unsigned integer whose width is `width`.
public static func randomInteger<RNG: RandomNumberGenerator>(withExactWidth width: Int, using generator: inout RNG) -> CS.BigUInt {
// width == 0 -> return 0 because there is no room for a one bit.
// width == 1 -> return 1 because there is no room for any random bits.
guard width > 1 else { return CS.BigUInt(width) }
var result = randomInteger(withMaximumWidth: width - 1, using: &generator)
result[(width - 1) / Word.bitWidth] |= 1 << Word((width - 1) % Word.bitWidth)
return result
}
/// Create a big unsigned integer consisting of `width-1` uniformly distributed random bits followed by a one bit.
///
/// - Note: If `width` is zero, the result is zero.
/// - Note: I use a `SystemRandomGeneratorGenerator` as the source of randomness.
///
/// - Returns: A random big unsigned integer whose width is `width`.
public static func randomInteger(withExactWidth width: Int) -> CS.BigUInt {
var rng = SystemRandomNumberGenerator()
return randomInteger(withExactWidth: width, using: &rng)
}
/// Create a uniformly distributed random unsigned integer that's less than the specified limit.
///
/// - Precondition: `limit > 0`.
///
/// - Parameter limit: The upper bound on the result.
/// - Parameter generator: The source of randomness.
/// - Returns: A random big unsigned integer that is less than `limit`.
public static func randomInteger<RNG: RandomNumberGenerator>(lessThan limit: CS.BigUInt, using generator: inout RNG) -> CS.BigUInt {
precondition(limit > 0, "\(#function): 0 is not a valid limit")
let width = limit.bitWidth
var random = randomInteger(withMaximumWidth: width, using: &generator)
while random >= limit {
random = randomInteger(withMaximumWidth: width, using: &generator)
}
return random
}
/// Create a uniformly distributed random unsigned integer that's less than the specified limit.
///
/// - Precondition: `limit > 0`.
/// - Note: I use a `SystemRandomGeneratorGenerator` as the source of randomness.
///
/// - Parameter limit: The upper bound on the result.
/// - Returns: A random big unsigned integer that is less than `limit`.
public static func randomInteger(lessThan limit: CS.BigUInt) -> CS.BigUInt {
var rng = SystemRandomNumberGenerator()
return randomInteger(lessThan: limit, using: &rng)
}
}

View File

@ -1,211 +0,0 @@
//
// Shifts.swift
// CS.BigInt
//
// Created by Károly Lőrentey on 2016-01-03.
// Copyright © 2016-2017 Károly Lőrentey.
//
extension CS.BigUInt {
//MARK: Shift Operators
internal func shiftedLeft(by amount: Word) -> CS.BigUInt {
guard amount > 0 else { return self }
let ext = Int(amount / Word(Word.bitWidth)) // External shift amount (new words)
let up = Word(amount % Word(Word.bitWidth)) // Internal shift amount (subword shift)
let down = Word(Word.bitWidth) - up
var result = CS.BigUInt()
if up > 0 {
var i = 0
var lowbits: Word = 0
while i < self.count || lowbits > 0 {
let word = self[i]
result[i + ext] = word << up | lowbits
lowbits = word >> down
i += 1
}
}
else {
for i in 0 ..< self.count {
result[i + ext] = self[i]
}
}
return result
}
internal mutating func shiftLeft(by amount: Word) {
guard amount > 0 else { return }
let ext = Int(amount / Word(Word.bitWidth)) // External shift amount (new words)
let up = Word(amount % Word(Word.bitWidth)) // Internal shift amount (subword shift)
let down = Word(Word.bitWidth) - up
if up > 0 {
var i = 0
var lowbits: Word = 0
while i < self.count || lowbits > 0 {
let word = self[i]
self[i] = word << up | lowbits
lowbits = word >> down
i += 1
}
}
if ext > 0 && self.count > 0 {
self.shiftLeft(byWords: ext)
}
}
internal func shiftedRight(by amount: Word) -> CS.BigUInt {
guard amount > 0 else { return self }
guard amount < self.bitWidth else { return 0 }
let ext = Int(amount / Word(Word.bitWidth)) // External shift amount (new words)
let down = Word(amount % Word(Word.bitWidth)) // Internal shift amount (subword shift)
let up = Word(Word.bitWidth) - down
var result = CS.BigUInt()
if down > 0 {
var highbits: Word = 0
for i in (ext ..< self.count).reversed() {
let word = self[i]
result[i - ext] = highbits | word >> down
highbits = word << up
}
}
else {
for i in (ext ..< self.count).reversed() {
result[i - ext] = self[i]
}
}
return result
}
internal mutating func shiftRight(by amount: Word) {
guard amount > 0 else { return }
guard amount < self.bitWidth else { self.clear(); return }
let ext = Int(amount / Word(Word.bitWidth)) // External shift amount (new words)
let down = Word(amount % Word(Word.bitWidth)) // Internal shift amount (subword shift)
let up = Word(Word.bitWidth) - down
if ext > 0 {
self.shiftRight(byWords: ext)
}
if down > 0 {
var i = self.count - 1
var highbits: Word = 0
while i >= 0 {
let word = self[i]
self[i] = highbits | word >> down
highbits = word << up
i -= 1
}
}
}
public static func >>=<Other: BinaryInteger>(lhs: inout CS.BigUInt, rhs: Other) {
if rhs < (0 as Other) {
lhs <<= (0 - rhs)
}
else if rhs >= lhs.bitWidth {
lhs.clear()
}
else {
lhs.shiftRight(by: UInt(rhs))
}
}
public static func <<=<Other: BinaryInteger>(lhs: inout CS.BigUInt, rhs: Other) {
if rhs < (0 as Other) {
lhs >>= (0 - rhs)
return
}
lhs.shiftLeft(by: Word(exactly: rhs)!)
}
public static func >><Other: BinaryInteger>(lhs: CS.BigUInt, rhs: Other) -> CS.BigUInt {
if rhs < (0 as Other) {
return lhs << (0 - rhs)
}
if rhs > Word.max {
return 0
}
return lhs.shiftedRight(by: UInt(rhs))
}
public static func <<<Other: BinaryInteger>(lhs: CS.BigUInt, rhs: Other) -> CS.BigUInt {
if rhs < (0 as Other) {
return lhs >> (0 - rhs)
}
return lhs.shiftedLeft(by: Word(exactly: rhs)!)
}
}
extension CS.BigInt {
func shiftedLeft(by amount: Word) -> CS.BigInt {
return CS.BigInt(sign: self.sign, magnitude: self.magnitude.shiftedLeft(by: amount))
}
mutating func shiftLeft(by amount: Word) {
self.magnitude.shiftLeft(by: amount)
}
func shiftedRight(by amount: Word) -> CS.BigInt {
let m = self.magnitude.shiftedRight(by: amount)
return CS.BigInt(sign: self.sign, magnitude: self.sign == .minus && m.isZero ? 1 : m)
}
mutating func shiftRight(by amount: Word) {
magnitude.shiftRight(by: amount)
if sign == .minus, magnitude.isZero {
magnitude.load(1)
}
}
public static func &<<(left: CS.BigInt, right: CS.BigInt) -> CS.BigInt {
return left.shiftedLeft(by: right.words[0])
}
public static func &<<=(left: inout CS.BigInt, right: CS.BigInt) {
left.shiftLeft(by: right.words[0])
}
public static func &>>(left: CS.BigInt, right: CS.BigInt) -> CS.BigInt {
return left.shiftedRight(by: right.words[0])
}
public static func &>>=(left: inout CS.BigInt, right: CS.BigInt) {
left.shiftRight(by: right.words[0])
}
public static func <<<Other: BinaryInteger>(lhs: CS.BigInt, rhs: Other) -> CS.BigInt {
guard rhs >= (0 as Other) else { return lhs >> (0 - rhs) }
return lhs.shiftedLeft(by: Word(rhs))
}
public static func <<=<Other: BinaryInteger>(lhs: inout CS.BigInt, rhs: Other) {
if rhs < (0 as Other) {
lhs >>= (0 - rhs)
}
else {
lhs.shiftLeft(by: Word(rhs))
}
}
public static func >><Other: BinaryInteger>(lhs: CS.BigInt, rhs: Other) -> CS.BigInt {
guard rhs >= (0 as Other) else { return lhs << (0 - rhs) }
return lhs.shiftedRight(by: Word(rhs))
}
public static func >>=<Other: BinaryInteger>(lhs: inout CS.BigInt, rhs: Other) {
if rhs < (0 as Other) {
lhs <<= (0 - rhs)
}
else {
lhs.shiftRight(by: Word(rhs))
}
}
}

View File

@ -1,41 +0,0 @@
//
// Square Root.swift
// CS.BigInt
//
// Created by Károly Lőrentey on 2016-01-03.
// Copyright © 2016-2017 Károly Lőrentey.
//
//MARK: Square Root
extension CS.BigUInt {
/// Returns the integer square root of a big integer; i.e., the largest integer whose square isn't greater than `value`.
///
/// - Returns: floor(sqrt(self))
public func squareRoot() -> CS.BigUInt {
// This implementation uses Newton's method.
guard !self.isZero else { return CS.BigUInt() }
var x = CS.BigUInt(1) << ((self.bitWidth + 1) / 2)
var y: CS.BigUInt = 0
while true {
y.load(self)
y /= x
y += x
y >>= 1
if x == y || x == y - 1 { break }
x = y
}
return x
}
}
extension CS.BigInt {
/// Returns the integer square root of a big integer; i.e., the largest integer whose square isn't greater than `value`.
///
/// - Requires: self >= 0
/// - Returns: floor(sqrt(self))
public func squareRoot() -> CS.BigInt {
precondition(self.sign == .plus)
return CS.BigInt(sign: .plus, magnitude: self.magnitude.squareRoot())
}
}

View File

@ -1,38 +0,0 @@
//
// Strideable.swift
// CS.BigInt
//
// Created by Károly Lőrentey on 2017-08-11.
// Copyright © 2016-2017 Károly Lőrentey.
//
extension CS.BigUInt: Strideable {
/// A type that can represent the distance between two values ofa `BigUInt`.
public typealias Stride = CS.BigInt
/// Adds `n` to `self` and returns the result. Traps if the result would be less than zero.
public func advanced(by n: CS.BigInt) -> CS.BigUInt {
return n.sign == .minus ? self - n.magnitude : self + n.magnitude
}
/// Returns the (potentially negative) difference between `self` and `other` as a `BigInt`. Never traps.
public func distance(to other: CS.BigUInt) -> CS.BigInt {
return CS.BigInt(other) - CS.BigInt(self)
}
}
extension CS.BigInt: Strideable {
public typealias Stride = CS.BigInt
/// Returns `self + n`.
public func advanced(by n: Stride) -> CS.BigInt {
return self + n
}
/// Returns `other - self`.
public func distance(to other: CS.BigInt) -> Stride {
return other - self
}
}

View File

@ -1,240 +0,0 @@
//
// String Conversion.swift
// CS.BigInt
//
// Created by Károly Lőrentey on 2016-01-03.
// Copyright © 2016-2017 Károly Lőrentey.
//
extension CS.BigUInt {
//MARK: String Conversion
/// Calculates the number of numerals in a given radix that fit inside a single `Word`.
///
/// - Returns: (chars, power) where `chars` is highest that satisfy `radix^chars <= 2^Word.bitWidth`. `power` is zero
/// if radix is a power of two; otherwise `power == radix^chars`.
fileprivate static func charsPerWord(forRadix radix: Int) -> (chars: Int, power: Word) {
var power: Word = 1
var overflow = false
var count = 0
while !overflow {
let (high,low) = power.multipliedFullWidth(by: Word(radix))
if high > 0 {
overflow = true
}
if !overflow || (high == 1 && low == 0) {
count += 1
power = low
}
}
return (count, power)
}
/// Initialize a big integer from an ASCII representation in a given radix. Numerals above `9` are represented by
/// letters from the English alphabet.
///
/// - Requires: `radix > 1 && radix < 36`
/// - Parameter `text`: A string consisting of characters corresponding to numerals in the given radix. (0-9, a-z, A-Z)
/// - Parameter `radix`: The base of the number system to use, or 10 if unspecified.
/// - Returns: The integer represented by `text`, or nil if `text` contains a character that does not represent a numeral in `radix`.
public init?<S: StringProtocol>(_ text: S, radix: Int = 10) {
precondition(radix > 1 && radix < 36)
guard !text.isEmpty else { return nil }
let (charsPerWord, power) = CS.BigUInt.charsPerWord(forRadix: radix)
var words: [Word] = []
var end = text.endIndex
var start = end
var count = 0
while start != text.startIndex {
start = text.index(before: start)
count += 1
if count == charsPerWord {
guard let d = Word.init(text[start ..< end], radix: radix) else { return nil }
words.append(d)
end = start
count = 0
}
}
if start != end {
guard let d = Word.init(text[start ..< end], radix: radix) else { return nil }
words.append(d)
}
if power == 0 {
self.init(words: words)
}
else {
self.init()
for d in words.reversed() {
self.multiply(byWord: power)
self.addWord(d)
}
}
}
}
extension CS.BigInt {
/// Initialize a big integer from an ASCII representation in a given radix. Numerals above `9` are represented by
/// letters from the English alphabet.
///
/// - Requires: `radix > 1 && radix < 36`
/// - Parameter `text`: A string optionally starting with "-" or "+" followed by characters corresponding to numerals in the given radix. (0-9, a-z, A-Z)
/// - Parameter `radix`: The base of the number system to use, or 10 if unspecified.
/// - Returns: The integer represented by `text`, or nil if `text` contains a character that does not represent a numeral in `radix`.
public init?<S: StringProtocol>(_ text: S, radix: Int = 10) {
var magnitude: CS.BigUInt?
var sign: Sign = .plus
if text.first == "-" {
sign = .minus
let text = text.dropFirst()
magnitude = CS.BigUInt(text, radix: radix)
}
else if text.first == "+" {
let text = text.dropFirst()
magnitude = CS.BigUInt(text, radix: radix)
}
else {
magnitude = CS.BigUInt(text, radix: radix)
}
guard let m = magnitude else { return nil }
self.magnitude = m
self.sign = m.isZero ? .plus : sign
}
}
extension String {
/// Initialize a new string with the base-10 representation of an unsigned big integer.
///
/// - Complexity: O(v.count^2)
public init(_ v: CS.BigUInt) { self.init(v, radix: 10, uppercase: false) }
/// Initialize a new string representing an unsigned big integer in the given radix (base).
///
/// Numerals greater than 9 are represented as letters from the English alphabet,
/// starting with `a` if `uppercase` is false or `A` otherwise.
///
/// - Requires: radix > 1 && radix <= 36
/// - Complexity: O(count) when radix is a power of two; otherwise O(count^2).
public init(_ v: CS.BigUInt, radix: Int, uppercase: Bool = false) {
precondition(radix > 1)
let (charsPerWord, power) = CS.BigUInt.charsPerWord(forRadix: radix)
guard !v.isZero else { self = "0"; return }
var parts: [String]
if power == 0 {
parts = v.words.map { String($0, radix: radix, uppercase: uppercase) }
}
else {
parts = []
var rest = v
while !rest.isZero {
let mod = rest.divide(byWord: power)
parts.append(String(mod, radix: radix, uppercase: uppercase))
}
}
assert(!parts.isEmpty)
self = ""
var first = true
for part in parts.reversed() {
let zeroes = charsPerWord - part.count
assert(zeroes >= 0)
if !first && zeroes > 0 {
// Insert leading zeroes for mid-Words
self += String(repeating: "0", count: zeroes)
}
first = false
self += part
}
}
/// Initialize a new string representing a signed big integer in the given radix (base).
///
/// Numerals greater than 9 are represented as letters from the English alphabet,
/// starting with `a` if `uppercase` is false or `A` otherwise.
///
/// - Requires: radix > 1 && radix <= 36
/// - Complexity: O(count) when radix is a power of two; otherwise O(count^2).
public init(_ value: CS.BigInt, radix: Int = 10, uppercase: Bool = false) {
self = String(value.magnitude, radix: radix, uppercase: uppercase)
if value.sign == .minus {
self = "-" + self
}
}
}
extension CS.BigUInt: ExpressibleByStringLiteral {
/// Initialize a new big integer from a Unicode scalar.
/// The scalar must represent a decimal digit.
public init(unicodeScalarLiteral value: UnicodeScalar) {
self = CS.BigUInt(String(value), radix: 10)!
}
/// Initialize a new big integer from an extended grapheme cluster.
/// The cluster must consist of a decimal digit.
public init(extendedGraphemeClusterLiteral value: String) {
self = CS.BigUInt(value, radix: 10)!
}
/// Initialize a new big integer from a decimal number represented by a string literal of arbitrary length.
/// The string must contain only decimal digits.
public init(stringLiteral value: StringLiteralType) {
self = CS.BigUInt(value, radix: 10)!
}
}
extension CS.BigInt: ExpressibleByStringLiteral {
/// Initialize a new big integer from a Unicode scalar.
/// The scalar must represent a decimal digit.
public init(unicodeScalarLiteral value: UnicodeScalar) {
self = CS.BigInt(String(value), radix: 10)!
}
/// Initialize a new big integer from an extended grapheme cluster.
/// The cluster must consist of a decimal digit.
public init(extendedGraphemeClusterLiteral value: String) {
self = CS.BigInt(value, radix: 10)!
}
/// Initialize a new big integer from a decimal number represented by a string literal of arbitrary length.
/// The string must contain only decimal digits.
public init(stringLiteral value: StringLiteralType) {
self = CS.BigInt(value, radix: 10)!
}
}
extension CS.BigUInt: CustomStringConvertible {
/// Return the decimal representation of this integer.
public var description: String {
return String(self, radix: 10)
}
}
extension CS.BigInt: CustomStringConvertible {
/// Return the decimal representation of this integer.
public var description: String {
return String(self, radix: 10)
}
}
extension CS.BigUInt: CustomPlaygroundDisplayConvertible {
/// Return the playground quick look representation of this integer.
public var playgroundDescription: Any {
let text = String(self)
return text + " (\(self.bitWidth) bits)"
}
}
extension CS.BigInt: CustomPlaygroundDisplayConvertible {
/// Return the playground quick look representation of this integer.
public var playgroundDescription: Any {
let text = String(self)
return text + " (\(self.magnitude.bitWidth) bits)"
}
}

View File

@ -1,169 +0,0 @@
//
// Subtraction.swift
// CS.BigInt
//
// Created by Károly Lőrentey on 2016-01-03.
// Copyright © 2016-2017 Károly Lőrentey.
//
extension CS.BigUInt {
//MARK: Subtraction
/// Subtract `word` from this integer in place, returning a flag indicating if the operation
/// caused an arithmetic overflow. `word` is shifted `shift` words to the left before being subtracted.
///
/// - Note: If the result indicates an overflow, then `self` becomes the two's complement of the absolute difference.
/// - Complexity: O(count)
internal mutating func subtractWordReportingOverflow(_ word: Word, shiftedBy shift: Int = 0) -> Bool {
precondition(shift >= 0)
var carry: Word = word
var i = shift
let count = self.count
while carry > 0 && i < count {
let (d, c) = self[i].subtractingReportingOverflow(carry)
self[i] = d
carry = (c ? 1 : 0)
i += 1
}
return carry > 0
}
/// Subtract `word` from this integer, returning the difference and a flag that is true if the operation
/// caused an arithmetic overflow. `word` is shifted `shift` words to the left before being subtracted.
///
/// - Note: If `overflow` is true, then the returned value is the two's complement of the absolute difference.
/// - Complexity: O(count)
internal func subtractingWordReportingOverflow(_ word: Word, shiftedBy shift: Int = 0) -> (partialValue: CS.BigUInt, overflow: Bool) {
var result = self
let overflow = result.subtractWordReportingOverflow(word, shiftedBy: shift)
return (result, overflow)
}
/// Subtract a digit `d` from this integer in place.
/// `d` is shifted `shift` digits to the left before being subtracted.
///
/// - Requires: self >= d * 2^shift
/// - Complexity: O(count)
internal mutating func subtractWord(_ word: Word, shiftedBy shift: Int = 0) {
let overflow = subtractWordReportingOverflow(word, shiftedBy: shift)
precondition(!overflow)
}
/// Subtract a digit `d` from this integer and return the result.
/// `d` is shifted `shift` digits to the left before being subtracted.
///
/// - Requires: self >= d * 2^shift
/// - Complexity: O(count)
internal func subtractingWord(_ word: Word, shiftedBy shift: Int = 0) -> CS.BigUInt {
var result = self
result.subtractWord(word, shiftedBy: shift)
return result
}
/// Subtract `other` from this integer in place, and return a flag indicating if the operation caused an
/// arithmetic overflow. `other` is shifted `shift` digits to the left before being subtracted.
///
/// - Note: If the result indicates an overflow, then `self` becomes the twos' complement of the absolute difference.
/// - Complexity: O(count)
public mutating func subtractReportingOverflow(_ b: CS.BigUInt, shiftedBy shift: Int = 0) -> Bool {
precondition(shift >= 0)
var carry = false
var bi = 0
let bc = b.count
let count = self.count
while bi < bc || (shift + bi < count && carry) {
let ai = shift + bi
let (d, c) = self[ai].subtractingReportingOverflow(b[bi])
if carry {
let (d2, c2) = d.subtractingReportingOverflow(1)
self[ai] = d2
carry = c || c2
}
else {
self[ai] = d
carry = c
}
bi += 1
}
return carry
}
/// Subtract `other` from this integer, returning the difference and a flag indicating arithmetic overflow.
/// `other` is shifted `shift` digits to the left before being subtracted.
///
/// - Note: If `overflow` is true, then the result value is the twos' complement of the absolute value of the difference.
/// - Complexity: O(count)
public func subtractingReportingOverflow(_ other: CS.BigUInt, shiftedBy shift: Int) -> (partialValue: CS.BigUInt, overflow: Bool) {
var result = self
let overflow = result.subtractReportingOverflow(other, shiftedBy: shift)
return (result, overflow)
}
/// Subtracts `other` from `self`, returning the result and a flag indicating arithmetic overflow.
///
/// - Note: When the operation overflows, then `partialValue` is the twos' complement of the absolute value of the difference.
/// - Complexity: O(count)
public func subtractingReportingOverflow(_ other: CS.BigUInt) -> (partialValue: CS.BigUInt, overflow: Bool) {
return self.subtractingReportingOverflow(other, shiftedBy: 0)
}
/// Subtract `other` from this integer in place.
/// `other` is shifted `shift` digits to the left before being subtracted.
///
/// - Requires: self >= other * 2^shift
/// - Complexity: O(count)
public mutating func subtract(_ other: CS.BigUInt, shiftedBy shift: Int = 0) {
let overflow = subtractReportingOverflow(other, shiftedBy: shift)
precondition(!overflow)
}
/// Subtract `b` from this integer, and return the difference.
/// `b` is shifted `shift` digits to the left before being subtracted.
///
/// - Requires: self >= b * 2^shift
/// - Complexity: O(count)
public func subtracting(_ other: CS.BigUInt, shiftedBy shift: Int = 0) -> CS.BigUInt {
var result = self
result.subtract(other, shiftedBy: shift)
return result
}
/// Decrement this integer by one.
///
/// - Requires: !isZero
/// - Complexity: O(count)
public mutating func decrement(shiftedBy shift: Int = 0) {
self.subtract(1, shiftedBy: shift)
}
/// Subtract `b` from `a` and return the result.
///
/// - Requires: a >= b
/// - Complexity: O(a.count)
public static func -(a: CS.BigUInt, b: CS.BigUInt) -> CS.BigUInt {
return a.subtracting(b)
}
/// Subtract `b` from `a` and store the result in `a`.
///
/// - Requires: a >= b
/// - Complexity: O(a.count)
public static func -=(a: inout CS.BigUInt, b: CS.BigUInt) {
a.subtract(b)
}
}
extension CS.BigInt {
public mutating func negate() {
guard !magnitude.isZero else { return }
self.sign = self.sign == .plus ? .minus : .plus
}
/// Subtract `b` from `a` and return the result.
public static func -(a: CS.BigInt, b: CS.BigInt) -> CS.BigInt {
return a + -b
}
/// Subtract `b` from `a` in place.
public static func -=(a: inout CS.BigInt, b: CS.BigInt) { a = a - b }
}

View File

@ -1,202 +0,0 @@
//
// Words and Bits.swift
// CS.BigInt
//
// Created by Károly Lőrentey on 2017-08-11.
// Copyright © 2016-2017 Károly Lőrentey.
//
extension Array where Element == UInt {
mutating func twosComplement() {
var increment = true
for i in 0 ..< self.count {
if increment {
(self[i], increment) = (~self[i]).addingReportingOverflow(1)
}
else {
self[i] = ~self[i]
}
}
}
}
extension CS.BigUInt {
public subscript(bitAt index: Int) -> Bool {
get {
precondition(index >= 0)
let (i, j) = index.quotientAndRemainder(dividingBy: Word.bitWidth)
return self[i] & (1 << j) != 0
}
set {
precondition(index >= 0)
let (i, j) = index.quotientAndRemainder(dividingBy: Word.bitWidth)
if newValue {
self[i] |= 1 << j
}
else {
self[i] &= ~(1 << j)
}
}
}
}
extension CS.BigUInt {
/// The minimum number of bits required to represent this integer in binary.
///
/// - Returns: floor(log2(2 * self + 1))
/// - Complexity: O(1)
public var bitWidth: Int {
guard count > 0 else { return 0 }
return count * Word.bitWidth - self[count - 1].leadingZeroBitCount
}
/// The number of leading zero bits in the binary representation of this integer in base `2^(Word.bitWidth)`.
/// This is useful when you need to normalize a `BigUInt` such that the top bit of its most significant word is 1.
///
/// - Note: 0 is considered to have zero leading zero bits.
/// - Returns: A value in `0...(Word.bitWidth - 1)`.
/// - SeeAlso: width
/// - Complexity: O(1)
public var leadingZeroBitCount: Int {
guard count > 0 else { return 0 }
return self[count - 1].leadingZeroBitCount
}
/// The number of trailing zero bits in the binary representation of this integer.
///
/// - Note: 0 is considered to have zero trailing zero bits.
/// - Returns: A value in `0...width`.
/// - Complexity: O(count)
public var trailingZeroBitCount: Int {
guard count > 0 else { return 0 }
let i = self.words.firstIndex { $0 != 0 }!
return i * Word.bitWidth + self[i].trailingZeroBitCount
}
}
extension CS.BigInt {
public var bitWidth: Int {
guard !magnitude.isZero else { return 0 }
return magnitude.bitWidth + 1
}
public var trailingZeroBitCount: Int {
// Amazingly, this works fine for negative numbers
return magnitude.trailingZeroBitCount
}
}
extension CS.BigUInt {
public struct Words: RandomAccessCollection {
private let value: CS.BigUInt
fileprivate init(_ value: CS.BigUInt) { self.value = value }
public var startIndex: Int { return 0 }
public var endIndex: Int { return value.count }
public subscript(_ index: Int) -> Word {
return value[index]
}
}
public var words: Words { return Words(self) }
public init<Words: Sequence>(words: Words) where Words.Element == Word {
let uc = words.underestimatedCount
if uc > 2 {
self.init(words: Array(words))
}
else {
var it = words.makeIterator()
guard let w0 = it.next() else {
self.init()
return
}
guard let w1 = it.next() else {
self.init(word: w0)
return
}
if let w2 = it.next() {
var words: [UInt] = []
words.reserveCapacity(Swift.max(3, uc))
words.append(w0)
words.append(w1)
words.append(w2)
while let word = it.next() {
words.append(word)
}
self.init(words: words)
}
else {
self.init(low: w0, high: w1)
}
}
}
}
extension CS.BigInt {
public struct Words: RandomAccessCollection {
public typealias Indices = CountableRange<Int>
private let value: CS.BigInt
private let decrementLimit: Int
fileprivate init(_ value: CS.BigInt) {
self.value = value
switch value.sign {
case .plus:
self.decrementLimit = 0
case .minus:
assert(!value.magnitude.isZero)
self.decrementLimit = value.magnitude.words.firstIndex(where: { $0 != 0 })!
}
}
public var count: Int {
switch value.sign {
case .plus:
if let high = value.magnitude.words.last, high >> (Word.bitWidth - 1) != 0 {
return value.magnitude.count + 1
}
return value.magnitude.count
case .minus:
let high = value.magnitude.words.last!
if high >> (Word.bitWidth - 1) != 0 {
return value.magnitude.count + 1
}
return value.magnitude.count
}
}
public var indices: Indices { return 0 ..< count }
public var startIndex: Int { return 0 }
public var endIndex: Int { return count }
public subscript(_ index: Int) -> UInt {
// Note that indices above `endIndex` are accepted.
if value.sign == .plus {
return value.magnitude[index]
}
if index <= decrementLimit {
return ~(value.magnitude[index] &- 1)
}
return ~value.magnitude[index]
}
}
public var words: Words {
return Words(self)
}
public init<S: Sequence>(words: S) where S.Element == Word {
var words = Array(words)
if (words.last ?? 0) >> (Word.bitWidth - 1) == 0 {
self.init(sign: .plus, magnitude: CS.BigUInt(words: words))
}
else {
words.twosComplement()
self.init(sign: .minus, magnitude: CS.BigUInt(words: words))
}
}
}

View File

@ -1,351 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
// https://tools.ietf.org/html/rfc7539
//
public final class ChaCha20: BlockCipher {
public enum Error: Swift.Error {
case invalidKeyOrInitializationVector
case notSupported
}
public static let blockSize = 64 // 512 / 8
public let keySize: Int
fileprivate let key: Key
fileprivate var counter: Array<UInt8>
public convenience init(key: Array<UInt8>, iv nonce: Array<UInt8>) throws {
try self.init(key: key, iv: nonce, blockCounter: 0)
}
init(key: Array<UInt8>, iv nonce: Array<UInt8>, blockCounter: UInt32 = 0) throws {
precondition(nonce.count == 12 || nonce.count == 8)
if key.count != 32 {
throw Error.invalidKeyOrInitializationVector
}
self.key = Key(bytes: key)
self.keySize = self.key.count
if nonce.count == 8 {
self.counter = blockCounter.bigEndian.bytes() + [0, 0, 0, 0] + nonce
} else {
self.counter = blockCounter.bigEndian.bytes() + nonce
}
assert(self.counter.count == 16)
}
/// https://tools.ietf.org/html/rfc7539#section-2.3.
fileprivate func core(block: inout Array<UInt8>, counter: Array<UInt8>, key: Array<UInt8>) {
precondition(block.count == ChaCha20.blockSize)
precondition(counter.count == 16)
precondition(key.count == 32)
let j0: UInt32 = 0x61707865
let j1: UInt32 = 0x3320646e // 0x3620646e sigma/tau
let j2: UInt32 = 0x79622d32
let j3: UInt32 = 0x6b206574
let j4: UInt32 = UInt32(bytes: key[0..<4]).bigEndian
let j5: UInt32 = UInt32(bytes: key[4..<8]).bigEndian
let j6: UInt32 = UInt32(bytes: key[8..<12]).bigEndian
let j7: UInt32 = UInt32(bytes: key[12..<16]).bigEndian
let j8: UInt32 = UInt32(bytes: key[16..<20]).bigEndian
let j9: UInt32 = UInt32(bytes: key[20..<24]).bigEndian
let j10: UInt32 = UInt32(bytes: key[24..<28]).bigEndian
let j11: UInt32 = UInt32(bytes: key[28..<32]).bigEndian
let j12: UInt32 = UInt32(bytes: counter[0..<4]).bigEndian
let j13: UInt32 = UInt32(bytes: counter[4..<8]).bigEndian
let j14: UInt32 = UInt32(bytes: counter[8..<12]).bigEndian
let j15: UInt32 = UInt32(bytes: counter[12..<16]).bigEndian
var (x0, x1, x2, x3, x4, x5, x6, x7) = (j0, j1, j2, j3, j4, j5, j6, j7)
var (x8, x9, x10, x11, x12, x13, x14, x15) = (j8, j9, j10, j11, j12, j13, j14, j15)
for _ in 0..<10 { // 20 rounds
x0 = x0 &+ x4
x12 ^= x0
x12 = (x12 << 16) | (x12 >> 16)
x8 = x8 &+ x12
x4 ^= x8
x4 = (x4 << 12) | (x4 >> 20)
x0 = x0 &+ x4
x12 ^= x0
x12 = (x12 << 8) | (x12 >> 24)
x8 = x8 &+ x12
x4 ^= x8
x4 = (x4 << 7) | (x4 >> 25)
x1 = x1 &+ x5
x13 ^= x1
x13 = (x13 << 16) | (x13 >> 16)
x9 = x9 &+ x13
x5 ^= x9
x5 = (x5 << 12) | (x5 >> 20)
x1 = x1 &+ x5
x13 ^= x1
x13 = (x13 << 8) | (x13 >> 24)
x9 = x9 &+ x13
x5 ^= x9
x5 = (x5 << 7) | (x5 >> 25)
x2 = x2 &+ x6
x14 ^= x2
x14 = (x14 << 16) | (x14 >> 16)
x10 = x10 &+ x14
x6 ^= x10
x6 = (x6 << 12) | (x6 >> 20)
x2 = x2 &+ x6
x14 ^= x2
x14 = (x14 << 8) | (x14 >> 24)
x10 = x10 &+ x14
x6 ^= x10
x6 = (x6 << 7) | (x6 >> 25)
x3 = x3 &+ x7
x15 ^= x3
x15 = (x15 << 16) | (x15 >> 16)
x11 = x11 &+ x15
x7 ^= x11
x7 = (x7 << 12) | (x7 >> 20)
x3 = x3 &+ x7
x15 ^= x3
x15 = (x15 << 8) | (x15 >> 24)
x11 = x11 &+ x15
x7 ^= x11
x7 = (x7 << 7) | (x7 >> 25)
x0 = x0 &+ x5
x15 ^= x0
x15 = (x15 << 16) | (x15 >> 16)
x10 = x10 &+ x15
x5 ^= x10
x5 = (x5 << 12) | (x5 >> 20)
x0 = x0 &+ x5
x15 ^= x0
x15 = (x15 << 8) | (x15 >> 24)
x10 = x10 &+ x15
x5 ^= x10
x5 = (x5 << 7) | (x5 >> 25)
x1 = x1 &+ x6
x12 ^= x1
x12 = (x12 << 16) | (x12 >> 16)
x11 = x11 &+ x12
x6 ^= x11
x6 = (x6 << 12) | (x6 >> 20)
x1 = x1 &+ x6
x12 ^= x1
x12 = (x12 << 8) | (x12 >> 24)
x11 = x11 &+ x12
x6 ^= x11
x6 = (x6 << 7) | (x6 >> 25)
x2 = x2 &+ x7
x13 ^= x2
x13 = (x13 << 16) | (x13 >> 16)
x8 = x8 &+ x13
x7 ^= x8
x7 = (x7 << 12) | (x7 >> 20)
x2 = x2 &+ x7
x13 ^= x2
x13 = (x13 << 8) | (x13 >> 24)
x8 = x8 &+ x13
x7 ^= x8
x7 = (x7 << 7) | (x7 >> 25)
x3 = x3 &+ x4
x14 ^= x3
x14 = (x14 << 16) | (x14 >> 16)
x9 = x9 &+ x14
x4 ^= x9
x4 = (x4 << 12) | (x4 >> 20)
x3 = x3 &+ x4
x14 ^= x3
x14 = (x14 << 8) | (x14 >> 24)
x9 = x9 &+ x14
x4 ^= x9
x4 = (x4 << 7) | (x4 >> 25)
}
x0 = x0 &+ j0
x1 = x1 &+ j1
x2 = x2 &+ j2
x3 = x3 &+ j3
x4 = x4 &+ j4
x5 = x5 &+ j5
x6 = x6 &+ j6
x7 = x7 &+ j7
x8 = x8 &+ j8
x9 = x9 &+ j9
x10 = x10 &+ j10
x11 = x11 &+ j11
x12 = x12 &+ j12
x13 = x13 &+ j13
x14 = x14 &+ j14
x15 = x15 &+ j15
block.replaceSubrange(0..<4, with: x0.bigEndian.bytes())
block.replaceSubrange(4..<8, with: x1.bigEndian.bytes())
block.replaceSubrange(8..<12, with: x2.bigEndian.bytes())
block.replaceSubrange(12..<16, with: x3.bigEndian.bytes())
block.replaceSubrange(16..<20, with: x4.bigEndian.bytes())
block.replaceSubrange(20..<24, with: x5.bigEndian.bytes())
block.replaceSubrange(24..<28, with: x6.bigEndian.bytes())
block.replaceSubrange(28..<32, with: x7.bigEndian.bytes())
block.replaceSubrange(32..<36, with: x8.bigEndian.bytes())
block.replaceSubrange(36..<40, with: x9.bigEndian.bytes())
block.replaceSubrange(40..<44, with: x10.bigEndian.bytes())
block.replaceSubrange(44..<48, with: x11.bigEndian.bytes())
block.replaceSubrange(48..<52, with: x12.bigEndian.bytes())
block.replaceSubrange(52..<56, with: x13.bigEndian.bytes())
block.replaceSubrange(56..<60, with: x14.bigEndian.bytes())
block.replaceSubrange(60..<64, with: x15.bigEndian.bytes())
}
// XORKeyStream
func process(bytes: ArraySlice<UInt8>, counter: inout Array<UInt8>, key: Array<UInt8>) -> Array<UInt8> {
precondition(counter.count == 16)
precondition(key.count == 32)
var block = Array<UInt8>(repeating: 0, count: ChaCha20.blockSize)
var bytesSlice = bytes
var out = Array<UInt8>(reserveCapacity: bytesSlice.count)
while bytesSlice.count >= ChaCha20.blockSize {
self.core(block: &block, counter: counter, key: key)
for (i, x) in block.enumerated() {
out.append(bytesSlice[bytesSlice.startIndex + i] ^ x)
}
var u: UInt32 = 1
for i in 0..<4 {
u += UInt32(counter[i])
counter[i] = UInt8(u & 0xff)
u >>= 8
}
bytesSlice = bytesSlice[bytesSlice.startIndex + ChaCha20.blockSize..<bytesSlice.endIndex]
}
if !bytesSlice.isEmpty {
self.core(block: &block, counter: counter, key: key)
for (i, v) in bytesSlice.enumerated() {
out.append(v ^ block[i])
}
}
return out
}
}
// MARK: Cipher
extension ChaCha20: Cipher {
public func encrypt(_ bytes: ArraySlice<UInt8>) throws -> Array<UInt8> {
self.process(bytes: bytes, counter: &self.counter, key: Array(self.key))
}
public func decrypt(_ bytes: ArraySlice<UInt8>) throws -> Array<UInt8> {
try self.encrypt(bytes)
}
}
// MARK: Encryptor
extension ChaCha20 {
public struct ChaChaEncryptor: Cryptor, Updatable {
private var accumulated = Array<UInt8>()
private let chacha: ChaCha20
init(chacha: ChaCha20) {
self.chacha = chacha
}
public mutating func update(withBytes bytes: ArraySlice<UInt8>, isLast: Bool = false) throws -> Array<UInt8> {
self.accumulated += bytes
var encrypted = Array<UInt8>()
encrypted.reserveCapacity(self.accumulated.count)
for chunk in self.accumulated.batched(by: ChaCha20.blockSize) {
if isLast || self.accumulated.count >= ChaCha20.blockSize {
encrypted += try self.chacha.encrypt(chunk)
self.accumulated.removeFirst(chunk.count) // TODO: improve performance
}
}
return encrypted
}
public func seek(to: Int) throws {
throw Error.notSupported
}
}
}
// MARK: Decryptor
extension ChaCha20 {
public struct ChaChaDecryptor: Cryptor, Updatable {
private var accumulated = Array<UInt8>()
private var offset: Int = 0
private var offsetToRemove: Int = 0
private let chacha: ChaCha20
init(chacha: ChaCha20) {
self.chacha = chacha
}
public mutating func update(withBytes bytes: ArraySlice<UInt8>, isLast: Bool = true) throws -> Array<UInt8> {
// prepend "offset" number of bytes at the beginning
if self.offset > 0 {
self.accumulated += Array<UInt8>(repeating: 0, count: self.offset) + bytes
self.offsetToRemove = self.offset
self.offset = 0
} else {
self.accumulated += bytes
}
var plaintext = Array<UInt8>()
plaintext.reserveCapacity(self.accumulated.count)
for chunk in self.accumulated.batched(by: ChaCha20.blockSize) {
if isLast || self.accumulated.count >= ChaCha20.blockSize {
plaintext += try self.chacha.decrypt(chunk)
// remove "offset" from the beginning of first chunk
if self.offsetToRemove > 0 {
plaintext.removeFirst(self.offsetToRemove) // TODO: improve performance
self.offsetToRemove = 0
}
self.accumulated.removeFirst(chunk.count)
}
}
return plaintext
}
public func seek(to: Int) throws {
throw Error.notSupported
}
}
}
// MARK: Cryptors
extension ChaCha20: Cryptors {
//TODO: Use BlockEncryptor/BlockDecryptor
public func makeEncryptor() -> Cryptor & Updatable {
ChaCha20.ChaChaEncryptor(chacha: self)
}
public func makeDecryptor() -> Cryptor & Updatable {
ChaCha20.ChaChaDecryptor(chacha: self)
}
}

View File

@ -1,208 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
/// CRC - cyclic redundancy check code.
public final class Checksum {
@usableFromInline
static let table32: Array<UInt32> = [
0x0000_0000, 0x7707_3096, 0xEE0E_612C, 0x9909_51BA, 0x076D_C419, 0x706A_F48F, 0xE963_A535, 0x9E64_95A3,
0x0EDB_8832, 0x79DC_B8A4, 0xE0D5_E91E, 0x97D2_D988, 0x09B6_4C2B, 0x7EB1_7CBD, 0xE7B8_2D07, 0x90BF_1D91,
0x1DB7_1064, 0x6AB0_20F2, 0xF3B9_7148, 0x84BE_41DE, 0x1ADA_D47D, 0x6DDD_E4EB, 0xF4D4_B551, 0x83D3_85C7,
0x136C_9856, 0x646B_A8C0, 0xFD62_F97A, 0x8A65_C9EC, 0x1401_5C4F, 0x6306_6CD9, 0xFA0F_3D63, 0x8D08_0DF5,
0x3B6E_20C8, 0x4C69_105E, 0xD560_41E4, 0xA267_7172, 0x3C03_E4D1, 0x4B04_D447, 0xD20D_85FD, 0xA50A_B56B,
0x35B5_A8FA, 0x42B2_986C, 0xDBBB_C9D6, 0xACBC_F940, 0x32D8_6CE3, 0x45DF_5C75, 0xDCD6_0DCF, 0xABD1_3D59,
0x26D9_30AC, 0x51DE_003A, 0xC8D7_5180, 0xBFD0_6116, 0x21B4_F4B5, 0x56B3_C423, 0xCFBA_9599, 0xB8BD_A50F,
0x2802_B89E, 0x5F05_8808, 0xC60C_D9B2, 0xB10B_E924, 0x2F6F_7C87, 0x5868_4C11, 0xC161_1DAB, 0xB666_2D3D,
0x76DC_4190, 0x01DB_7106, 0x98D2_20BC, 0xEFD5_102A, 0x71B1_8589, 0x06B6_B51F, 0x9FBF_E4A5, 0xE8B8_D433,
0x7807_C9A2, 0x0F00_F934, 0x9609_A88E, 0xE10E_9818, 0x7F6A_0DBB, 0x086D_3D2D, 0x9164_6C97, 0xE663_5C01,
0x6B6B_51F4, 0x1C6C_6162, 0x8565_30D8, 0xF262_004E, 0x6C06_95ED, 0x1B01_A57B, 0x8208_F4C1, 0xF50F_C457,
0x65B0_D9C6, 0x12B7_E950, 0x8BBE_B8EA, 0xFCB9_887C, 0x62DD_1DDF, 0x15DA_2D49, 0x8CD3_7CF3, 0xFBD4_4C65,
0x4DB2_6158, 0x3AB5_51CE, 0xA3BC_0074, 0xD4BB_30E2, 0x4ADF_A541, 0x3DD8_95D7, 0xA4D1_C46D, 0xD3D6_F4FB,
0x4369_E96A, 0x346E_D9FC, 0xAD67_8846, 0xDA60_B8D0, 0x4404_2D73, 0x3303_1DE5, 0xAA0A_4C5F, 0xDD0D_7CC9,
0x5005_713C, 0x2702_41AA, 0xBE0B_1010, 0xC90C_2086, 0x5768_B525, 0x206F_85B3, 0xB966_D409, 0xCE61_E49F,
0x5EDE_F90E, 0x29D9_C998, 0xB0D0_9822, 0xC7D7_A8B4, 0x59B3_3D17, 0x2EB4_0D81, 0xB7BD_5C3B, 0xC0BA_6CAD,
0xEDB8_8320, 0x9ABF_B3B6, 0x03B6_E20C, 0x74B1_D29A, 0xEAD5_4739, 0x9DD2_77AF, 0x04DB_2615, 0x73DC_1683,
0xE363_0B12, 0x9464_3B84, 0x0D6D_6A3E, 0x7A6A_5AA8, 0xE40E_CF0B, 0x9309_FF9D, 0x0A00_AE27, 0x7D07_9EB1,
0xF00F_9344, 0x8708_A3D2, 0x1E01_F268, 0x6906_C2FE, 0xF762_575D, 0x8065_67CB, 0x196C_3671, 0x6E6B_06E7,
0xFED4_1B76, 0x89D3_2BE0, 0x10DA_7A5A, 0x67DD_4ACC, 0xF9B9_DF6F, 0x8EBE_EFF9, 0x17B7_BE43, 0x60B0_8ED5,
0xD6D6_A3E8, 0xA1D1_937E, 0x38D8_C2C4, 0x4FDF_F252, 0xD1BB_67F1, 0xA6BC_5767, 0x3FB5_06DD, 0x48B2_364B,
0xD80D_2BDA, 0xAF0A_1B4C, 0x3603_4AF6, 0x4104_7A60, 0xDF60_EFC3, 0xA867_DF55, 0x316E_8EEF, 0x4669_BE79,
0xCB61_B38C, 0xBC66_831A, 0x256F_D2A0, 0x5268_E236, 0xCC0C_7795, 0xBB0B_4703, 0x2202_16B9, 0x5505_262F,
0xC5BA_3BBE, 0xB2BD_0B28, 0x2BB4_5A92, 0x5CB3_6A04, 0xC2D7_FFA7, 0xB5D0_CF31, 0x2CD9_9E8B, 0x5BDE_AE1D,
0x9B64_C2B0, 0xEC63_F226, 0x756A_A39C, 0x026D_930A, 0x9C09_06A9, 0xEB0E_363F, 0x7207_6785, 0x0500_5713,
0x95BF_4A82, 0xE2B8_7A14, 0x7BB1_2BAE, 0x0CB6_1B38, 0x92D2_8E9B, 0xE5D5_BE0D, 0x7CDC_EFB7, 0x0BDB_DF21,
0x86D3_D2D4, 0xF1D4_E242, 0x68DD_B3F8, 0x1FDA_836E, 0x81BE_16CD, 0xF6B9_265B, 0x6FB0_77E1, 0x18B7_4777,
0x8808_5AE6, 0xFF0F_6A70, 0x6606_3BCA, 0x1101_0B5C, 0x8F65_9EFF, 0xF862_AE69, 0x616B_FFD3, 0x166C_CF45,
0xA00A_E278, 0xD70D_D2EE, 0x4E04_8354, 0x3903_B3C2, 0xA767_2661, 0xD060_16F7, 0x4969_474D, 0x3E6E_77DB,
0xAED1_6A4A, 0xD9D6_5ADC, 0x40DF_0B66, 0x37D8_3BF0, 0xA9BC_AE53, 0xDEBB_9EC5, 0x47B2_CF7F, 0x30B5_FFE9,
0xBDBD_F21C, 0xCABA_C28A, 0x53B3_9330, 0x24B4_A3A6, 0xBAD0_3605, 0xCDD7_0693, 0x54DE_5729, 0x23D9_67BF,
0xB366_7A2E, 0xC461_4AB8, 0x5D68_1B02, 0x2A6F_2B94, 0xB40B_BE37, 0xC30C_8EA1, 0x5A05_DF1B, 0x2D02_EF8D
]
@usableFromInline
static let table32c: Array<UInt32> = [
0x0000_0000, 0xF26B_8303, 0xE13B_70F7, 0x1350_F3F4, 0xC79A_971F, 0x35F1_141C, 0x26A1_E7E8, 0xD4CA_64EB,
0x8AD9_58CF, 0x78B2_DBCC, 0x6BE2_2838, 0x9989_AB3B, 0x4D43_CFD0, 0xBF28_4CD3, 0xAC78_BF27, 0x5E13_3C24,
0x105E_C76F, 0xE235_446C, 0xF165_B798, 0x030E_349B, 0xD7C4_5070, 0x25AF_D373, 0x36FF_2087, 0xC494_A384,
0x9A87_9FA0, 0x68EC_1CA3, 0x7BBC_EF57, 0x89D7_6C54, 0x5D1D_08BF, 0xAF76_8BBC, 0xBC26_7848, 0x4E4D_FB4B,
0x20BD_8EDE, 0xD2D6_0DDD, 0xC186_FE29, 0x33ED_7D2A, 0xE727_19C1, 0x154C_9AC2, 0x061C_6936, 0xF477_EA35,
0xAA64_D611, 0x580F_5512, 0x4B5F_A6E6, 0xB934_25E5, 0x6DFE_410E, 0x9F95_C20D, 0x8CC5_31F9, 0x7EAE_B2FA,
0x30E3_49B1, 0xC288_CAB2, 0xD1D8_3946, 0x23B3_BA45, 0xF779_DEAE, 0x0512_5DAD, 0x1642_AE59, 0xE429_2D5A,
0xBA3A_117E, 0x4851_927D, 0x5B01_6189, 0xA96A_E28A, 0x7DA0_8661, 0x8FCB_0562, 0x9C9B_F696, 0x6EF0_7595,
0x417B_1DBC, 0xB310_9EBF, 0xA040_6D4B, 0x522B_EE48, 0x86E1_8AA3, 0x748A_09A0, 0x67DA_FA54, 0x95B1_7957,
0xCBA2_4573, 0x39C9_C670, 0x2A99_3584, 0xD8F2_B687, 0x0C38_D26C, 0xFE53_516F, 0xED03_A29B, 0x1F68_2198,
0x5125_DAD3, 0xA34E_59D0, 0xB01E_AA24, 0x4275_2927, 0x96BF_4DCC, 0x64D4_CECF, 0x7784_3D3B, 0x85EF_BE38,
0xDBFC_821C, 0x2997_011F, 0x3AC7_F2EB, 0xC8AC_71E8, 0x1C66_1503, 0xEE0D_9600, 0xFD5D_65F4, 0x0F36_E6F7,
0x61C6_9362, 0x93AD_1061, 0x80FD_E395, 0x7296_6096, 0xA65C_047D, 0x5437_877E, 0x4767_748A, 0xB50C_F789,
0xEB1F_CBAD, 0x1974_48AE, 0x0A24_BB5A, 0xF84F_3859, 0x2C85_5CB2, 0xDEEE_DFB1, 0xCDBE_2C45, 0x3FD5_AF46,
0x7198_540D, 0x83F3_D70E, 0x90A3_24FA, 0x62C8_A7F9, 0xB602_C312, 0x4469_4011, 0x5739_B3E5, 0xA552_30E6,
0xFB41_0CC2, 0x092A_8FC1, 0x1A7A_7C35, 0xE811_FF36, 0x3CDB_9BDD, 0xCEB0_18DE, 0xDDE0_EB2A, 0x2F8B_6829,
0x82F6_3B78, 0x709D_B87B, 0x63CD_4B8F, 0x91A6_C88C, 0x456C_AC67, 0xB707_2F64, 0xA457_DC90, 0x563C_5F93,
0x082F_63B7, 0xFA44_E0B4, 0xE914_1340, 0x1B7F_9043, 0xCFB5_F4A8, 0x3DDE_77AB, 0x2E8E_845F, 0xDCE5_075C,
0x92A8_FC17, 0x60C3_7F14, 0x7393_8CE0, 0x81F8_0FE3, 0x5532_6B08, 0xA759_E80B, 0xB409_1BFF, 0x4662_98FC,
0x1871_A4D8, 0xEA1A_27DB, 0xF94A_D42F, 0x0B21_572C, 0xDFEB_33C7, 0x2D80_B0C4, 0x3ED0_4330, 0xCCBB_C033,
0xA24B_B5A6, 0x5020_36A5, 0x4370_C551, 0xB11B_4652, 0x65D1_22B9, 0x97BA_A1BA, 0x84EA_524E, 0x7681_D14D,
0x2892_ED69, 0xDAF9_6E6A, 0xC9A9_9D9E, 0x3BC2_1E9D, 0xEF08_7A76, 0x1D63_F975, 0x0E33_0A81, 0xFC58_8982,
0xB215_72C9, 0x407E_F1CA, 0x532E_023E, 0xA145_813D, 0x758F_E5D6, 0x87E4_66D5, 0x94B4_9521, 0x66DF_1622,
0x38CC_2A06, 0xCAA7_A905, 0xD9F7_5AF1, 0x2B9C_D9F2, 0xFF56_BD19, 0x0D3D_3E1A, 0x1E6D_CDEE, 0xEC06_4EED,
0xC38D_26C4, 0x31E6_A5C7, 0x22B6_5633, 0xD0DD_D530, 0x0417_B1DB, 0xF67C_32D8, 0xE52C_C12C, 0x1747_422F,
0x4954_7E0B, 0xBB3F_FD08, 0xA86F_0EFC, 0x5A04_8DFF, 0x8ECE_E914, 0x7CA5_6A17, 0x6FF5_99E3, 0x9D9E_1AE0,
0xD3D3_E1AB, 0x21B8_62A8, 0x32E8_915C, 0xC083_125F, 0x1449_76B4, 0xE622_F5B7, 0xF572_0643, 0x0719_8540,
0x590A_B964, 0xAB61_3A67, 0xB831_C993, 0x4A5A_4A90, 0x9E90_2E7B, 0x6CFB_AD78, 0x7FAB_5E8C, 0x8DC0_DD8F,
0xE330_A81A, 0x115B_2B19, 0x020B_D8ED, 0xF060_5BEE, 0x24AA_3F05, 0xD6C1_BC06, 0xC591_4FF2, 0x37FA_CCF1,
0x69E9_F0D5, 0x9B82_73D6, 0x88D2_8022, 0x7AB9_0321, 0xAE73_67CA, 0x5C18_E4C9, 0x4F48_173D, 0xBD23_943E,
0xF36E_6F75, 0x0105_EC76, 0x1255_1F82, 0xE03E_9C81, 0x34F4_F86A, 0xC69F_7B69, 0xD5CF_889D, 0x27A4_0B9E,
0x79B7_37BA, 0x8BDC_B4B9, 0x988C_474D, 0x6AE7_C44E, 0xBE2D_A0A5, 0x4C46_23A6, 0x5F16_D052, 0xAD7D_5351
]
@usableFromInline
static let table16: Array<UInt16> = [
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
]
@usableFromInline
init() {
//
}
/// Polynomial: 0xEDB88320 (Reversed) - IEEE
@inlinable
func crc32(_ message: Array<UInt8>, seed: UInt32? = nil, reflect: Bool = true) -> UInt32 {
var crc: UInt32 = seed != nil ? seed! : 0xFFFF_FFFF
for chunk in message.batched(by: 256) {
for b in chunk {
let idx = Int((crc ^ UInt32(reflect ? b : reversed(b))) & 0xFF)
crc = (crc >> 8) ^ Checksum.table32[idx]
}
}
return (reflect ? crc : reversed(crc)) ^ 0xFFFF_FFFF
}
/// Polynomial: 0x82F63B78 (Reversed) - Castagnoli
@inlinable
func crc32c(_ message: Array<UInt8>, seed: UInt32? = nil, reflect: Bool = true) -> UInt32 {
var crc: UInt32 = seed != nil ? seed! : 0xFFFF_FFFF
for chunk in message.batched(by: 256) {
for b in chunk {
let idx = Int((crc ^ UInt32(reflect ? b : reversed(b))) & 0xFF)
crc = (crc >> 8) ^ Checksum.table32c[idx]
}
}
return (reflect ? crc : reversed(crc)) ^ 0xFFFF_FFFF
}
/// Polynomial: 0xA001 (Reversed) - IBM
@inlinable
func crc16(_ message: Array<UInt8>, seed: UInt16? = nil) -> UInt16 {
var crc: UInt16 = seed != nil ? seed! : 0x0000
for chunk in message.batched(by: 256) {
for b in chunk {
crc = (crc >> 8) ^ Checksum.table16[Int((crc ^ UInt16(b)) & 0xFF)]
}
}
return crc
}
}
// MARK: Public interface
public extension Checksum {
/// Calculate CRC32.
///
/// - parameter message: Message
/// - parameter seed: Seed value (Optional)
/// - parameter reflect: is reflect (default true)
///
/// - returns: Calculated code
@inlinable
static func crc32(_ message: Array<UInt8>, seed: UInt32? = nil, reflect: Bool = true) -> UInt32 {
Checksum().crc32(message, seed: seed, reflect: reflect)
}
/// Calculate CRC32C
///
/// - parameter message: Message
/// - parameter seed: Seed value (Optional)
/// - parameter reflect: is reflect (default true)
///
/// - returns: Calculated code
@inlinable
static func crc32c(_ message: Array<UInt8>, seed: UInt32? = nil, reflect: Bool = true) -> UInt32 {
Checksum().crc32c(message, seed: seed, reflect: reflect)
}
/// Calculate CRC16
///
/// - parameter message: Message
/// - parameter seed: Seed value (Optional)
///
/// - returns: Calculated code
@inlinable
static func crc16(_ message: Array<UInt8>, seed: UInt16? = nil) -> UInt16 {
Checksum().crc16(message, seed: seed)
}
}

View File

@ -1,47 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
public enum CipherError: Error {
case encrypt
case decrypt
}
public protocol Cipher: AnyObject {
var keySize: Int { get }
/// Encrypt given bytes at once
///
/// - parameter bytes: Plaintext data
/// - returns: Encrypted data
func encrypt(_ bytes: ArraySlice<UInt8>) throws -> Array<UInt8>
func encrypt(_ bytes: Array<UInt8>) throws -> Array<UInt8>
/// Decrypt given bytes at once
///
/// - parameter bytes: Ciphertext data
/// - returns: Plaintext data
func decrypt(_ bytes: ArraySlice<UInt8>) throws -> Array<UInt8>
func decrypt(_ bytes: Array<UInt8>) throws -> Array<UInt8>
}
extension Cipher {
public func encrypt(_ bytes: Array<UInt8>) throws -> Array<UInt8> {
try self.encrypt(bytes.slice)
}
public func decrypt(_ bytes: Array<UInt8>) throws -> Array<UInt8> {
try self.decrypt(bytes.slice)
}
}

View File

@ -1,61 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
extension Collection where Self.Element == UInt8, Self.Index == Int {
// Big endian order
@inlinable
func toUInt32Array() -> Array<UInt32> {
guard !isEmpty else {
return []
}
let c = strideCount(from: startIndex, to: endIndex, by: 4)
return Array<UInt32>(unsafeUninitializedCapacity: c) { buf, count in
var counter = 0
for idx in stride(from: startIndex, to: endIndex, by: 4) {
let val = UInt32(bytes: self, fromIndex: idx).bigEndian
buf[counter] = val
counter += 1
}
count = counter
assert(counter == c)
}
}
// Big endian order
@inlinable
func toUInt64Array() -> Array<UInt64> {
guard !isEmpty else {
return []
}
let c = strideCount(from: startIndex, to: endIndex, by: 8)
return Array<UInt64>(unsafeUninitializedCapacity: c) { buf, count in
var counter = 0
for idx in stride(from: startIndex, to: endIndex, by: 8) {
let val = UInt64(bytes: self, fromIndex: idx).bigEndian
buf[counter] = val
counter += 1
}
count = counter
assert(counter == c)
}
}
}
@usableFromInline
func strideCount(from: Int, to: Int, by: Int) -> Int {
let count = to - from
return count / by + (count % by > 0 ? 1 : 0)
}

View File

@ -1,25 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
#if swift(>=4.1)
// TODO: remove this file when Xcode 9.2 is no longer used
#else
extension Sequence {
@inlinable
public func compactMap<ElementOfResult>(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult] {
try flatMap(transform)
}
}
#endif

View File

@ -1,22 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
/// Cryptor (Encryptor or Decryptor)
public protocol Cryptor {
/// Seek to position in file, if block mode allows random access.
///
/// - parameter to: new value of counter
mutating func seek(to: Int) throws
}

View File

@ -1,44 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
#if canImport(Darwin)
import Darwin
#elseif canImport(Glibc)
import Glibc
#elseif canImport(ucrt)
import ucrt
#endif
/// Worker cryptor/decryptor of `Updatable` types
public protocol Cryptors: AnyObject {
/// Cryptor suitable for encryption
func makeEncryptor() throws -> Cryptor & Updatable
/// Cryptor suitable for decryption
func makeDecryptor() throws -> Cryptor & Updatable
/// Generate array of random bytes. Helper function.
static func randomIV(_ blockSize: Int) -> Array<UInt8>
}
extension Cryptors {
/// Generate array of random values.
/// Convenience helper that uses `Swift.RandomNumberGenerator`.
/// - Parameter count: Length of array
public static func randomIV(_ count: Int) -> Array<UInt8> {
(0..<count).map({ _ in UInt8.random(in: 0...UInt8.max) })
}
}

View File

@ -1,78 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
@available(*, renamed: "Digest")
public typealias Hash = Digest
/// Hash functions to calculate Digest.
public struct Digest {
/// Calculate MD5 Digest
/// - parameter bytes: input message
/// - returns: Digest bytes
public static func md5(_ bytes: Array<UInt8>) -> Array<UInt8> {
MD5().calculate(for: bytes)
}
/// Calculate SHA1 Digest
/// - parameter bytes: input message
/// - returns: Digest bytes
public static func sha1(_ bytes: Array<UInt8>) -> Array<UInt8> {
SHA1().calculate(for: bytes)
}
/// Calculate SHA2-224 Digest
/// - parameter bytes: input message
/// - returns: Digest bytes
public static func sha224(_ bytes: Array<UInt8>) -> Array<UInt8> {
self.sha2(bytes, variant: .sha224)
}
/// Calculate SHA2-256 Digest
/// - parameter bytes: input message
/// - returns: Digest bytes
public static func sha256(_ bytes: Array<UInt8>) -> Array<UInt8> {
self.sha2(bytes, variant: .sha256)
}
/// Calculate SHA2-384 Digest
/// - parameter bytes: input message
/// - returns: Digest bytes
public static func sha384(_ bytes: Array<UInt8>) -> Array<UInt8> {
self.sha2(bytes, variant: .sha384)
}
/// Calculate SHA2-512 Digest
/// - parameter bytes: input message
/// - returns: Digest bytes
public static func sha512(_ bytes: Array<UInt8>) -> Array<UInt8> {
self.sha2(bytes, variant: .sha512)
}
/// Calculate SHA2 Digest
/// - parameter bytes: input message
/// - parameter variant: SHA-2 variant
/// - returns: Digest bytes
public static func sha2(_ bytes: Array<UInt8>, variant: SHA2.Variant) -> Array<UInt8> {
SHA2(variant: variant).calculate(for: bytes)
}
/// Calculate SHA3 Digest
/// - parameter bytes: input message
/// - parameter variant: SHA-3 variant
/// - returns: Digest bytes
public static func sha3(_ bytes: Array<UInt8>, variant: SHA3.Variant) -> Array<UInt8> {
SHA3(variant: variant).calculate(for: bytes)
}
}

View File

@ -1,18 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
internal protocol DigestType {
func calculate(for bytes: Array<UInt8>) -> Array<UInt8>
}

View File

@ -1,32 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
import Foundation
extension AES {
/// Initialize with CBC block mode.
///
/// - Parameters:
/// - key: Key as a String.
/// - iv: IV as a String.
/// - padding: Padding
/// - Throws: Error
///
/// The input is a String, that is treat as sequence of bytes made directly out of String.
/// If input is Base64 encoded data (which is a String technically) it is not decoded automatically for you.
public convenience init(key: String, iv: String, padding: Padding = .pkcs7) throws {
try self.init(key: key.bytes, blockMode: CBC(iv: iv.bytes), padding: padding)
}
}

View File

@ -1,32 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
import Foundation
public extension Array where Element == UInt8 {
func toBase64(options: Data.Base64EncodingOptions = []) -> String {
Data(self).base64EncodedString(options: options)
}
init(base64: String, options: Data.Base64DecodingOptions = .ignoreUnknownCharacters) {
self.init()
guard let decodedData = Data(base64Encoded: base64, options: options) else {
return
}
append(contentsOf: decodedData.bytes)
}
}

View File

@ -1,23 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
import Foundation
extension Blowfish {
/// Initialize with CBC block mode.
public convenience init(key: String, iv: String, padding: Padding = .pkcs7) throws {
try self.init(key: key.bytes, blockMode: CBC(iv: iv.bytes), padding: padding)
}
}

View File

@ -1,22 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
import Foundation
extension ChaCha20 {
public convenience init(key: String, iv: String) throws {
try self.init(key: key.bytes, iv: iv.bytes)
}
}

View File

@ -1,92 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
import Foundation
extension Data {
/// Two octet checksum as defined in RFC-4880. Sum of all octets, mod 65536
public func checksum() -> UInt16 {
let s = self.withUnsafeBytes { buf in
return buf.lazy.map(UInt32.init).reduce(UInt32(0), +)
}
return UInt16(s % 65535)
}
public func md5() -> Data {
Data( Digest.md5(bytes))
}
public func sha1() -> Data {
Data( Digest.sha1(bytes))
}
public func sha224() -> Data {
Data( Digest.sha224(bytes))
}
public func sha256() -> Data {
Data( Digest.sha256(bytes))
}
public func sha384() -> Data {
Data( Digest.sha384(bytes))
}
public func sha512() -> Data {
Data( Digest.sha512(bytes))
}
public func sha3(_ variant: SHA3.Variant) -> Data {
Data( Digest.sha3(bytes, variant: variant))
}
public func crc32(seed: UInt32? = nil, reflect: Bool = true) -> Data {
Data( Checksum.crc32(bytes, seed: seed, reflect: reflect).bytes())
}
public func crc32c(seed: UInt32? = nil, reflect: Bool = true) -> Data {
Data( Checksum.crc32c(bytes, seed: seed, reflect: reflect).bytes())
}
public func crc16(seed: UInt16? = nil) -> Data {
Data( Checksum.crc16(bytes, seed: seed).bytes())
}
public func encrypt(cipher: Cipher) throws -> Data {
Data( try cipher.encrypt(bytes.slice))
}
public func decrypt(cipher: Cipher) throws -> Data {
Data( try cipher.decrypt(bytes.slice))
}
public func authenticate(with authenticator: Authenticator) throws -> Data {
Data( try authenticator.authenticate(bytes))
}
}
extension Data {
public init(hex: String) {
self.init(Array<UInt8>(hex: hex))
}
public var bytes: Array<UInt8> {
Array(self)
}
public func toHexString() -> String {
self.bytes.toHexString()
}
}

View File

@ -1,22 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
import Foundation
extension HMAC {
public convenience init(key: String, variant: HMAC.Variant = .md5) throws {
self.init(key: key.bytes, variant: variant)
}
}

View File

@ -1,26 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
import Foundation
extension Rabbit {
public convenience init(key: String) throws {
try self.init(key: key.bytes)
}
public convenience init(key: String, iv: String) throws {
try self.init(key: key.bytes, iv: iv.bytes)
}
}

View File

@ -1,41 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
import Foundation
extension String {
/// Return Base64 back to String
public func decryptBase64ToString(cipher: Cipher) throws -> String {
guard let decodedData = Data(base64Encoded: self, options: []) else {
throw CipherError.decrypt
}
let decrypted = try decodedData.decrypt(cipher: cipher)
if let decryptedString = String(data: decrypted, encoding: String.Encoding.utf8) {
return decryptedString
}
throw CipherError.decrypt
}
public func decryptBase64(cipher: Cipher) throws -> Array<UInt8> {
guard let decodedData = Data(base64Encoded: self, options: []) else {
throw CipherError.decrypt
}
return try decodedData.decrypt(cipher: cipher).bytes
}
}

View File

@ -1,27 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
import Foundation
func perf(_ text: String, closure: () -> Void) {
let measurementStart = Date()
closure()
let measurementStop = Date()
let executionTime = measurementStop.timeIntervalSince(measurementStart)
print("\(text) \(executionTime)")
}

View File

@ -1,29 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
import Foundation
extension XChaCha20 {
/// Convenience initializer that creates an XChaCha20 instance with the given key and IV
/// represented as hex-encoded strings.
///
/// - Parameters:
/// - key: The encryption/decryption key as a hex-encoded string.
/// - iv: The initialization vector as a hex-encoded string.
/// - Throws: An error if the provided key or IV are of invalid length, format, or not hex-encoded.
public convenience init(key: String, iv: String) throws {
try self.init(key: key.bytes, iv: iv.bytes)
}
}

View File

@ -1,43 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
/// Array of bytes. Caution: don't use directly because generic is slow.
///
/// - parameter value: integer value
/// - parameter length: length of output array. By default size of value type
///
/// - returns: Array of bytes
@_specialize(where T == Int)
@_specialize(where T == UInt)
@_specialize(where T == UInt8)
@_specialize(where T == UInt16)
@_specialize(where T == UInt32)
@_specialize(where T == UInt64)
@inlinable
func arrayOfBytes<T: FixedWidthInteger>(value: T, length totalBytes: Int = MemoryLayout<T>.size) -> Array<UInt8> {
let valuePointer = UnsafeMutablePointer<T>.allocate(capacity: 1)
valuePointer.pointee = value
let bytesPointer = UnsafeMutablePointer<UInt8>(OpaquePointer(valuePointer))
var bytes = Array<UInt8>(repeating: 0, count: totalBytes)
for j in 0..<min(MemoryLayout<T>.size, totalBytes) {
bytes[totalBytes - 1 - j] = (bytesPointer + j).pointee
}
valuePointer.deinitialize(count: 1)
valuePointer.deallocate()
return bytes
}

View File

@ -1,92 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
// https://www.ietf.org/rfc/rfc5869.txt
//
#if canImport(Darwin)
import Darwin
#elseif canImport(Glibc)
import Glibc
#elseif canImport(ucrt)
import ucrt
#elseif canImport(WASILibc)
import WASILibc
#endif
/// A key derivation function.
///
/// HKDF - HMAC-based Extract-and-Expand Key Derivation Function.
public struct HKDF {
public enum Error: Swift.Error {
case invalidInput
case derivedKeyTooLong
}
private let numBlocks: Int // l
private let dkLen: Int
private let info: Array<UInt8>
private let prk: Array<UInt8>
private let variant: HMAC.Variant
/// - parameters:
/// - variant: hash variant
/// - salt: optional salt (if not provided, it is set to a sequence of variant.digestLength zeros)
/// - info: optional context and application specific information
/// - keyLength: intended length of derived key
public init(password: Array<UInt8>, salt: Array<UInt8>? = nil, info: Array<UInt8>? = nil, keyLength: Int? = nil /* dkLen */, variant: HMAC.Variant = .sha2(.sha256)) throws {
guard !password.isEmpty else {
throw Error.invalidInput
}
let dkLen = keyLength ?? variant.digestLength
let keyLengthFinal = Double(dkLen)
let hLen = Double(variant.digestLength)
let numBlocks = Int(ceil(keyLengthFinal / hLen)) // l = ceil(keyLength / hLen)
guard numBlocks <= 255 else {
throw Error.derivedKeyTooLong
}
/// HKDF-Extract(salt, password) -> PRK
/// - PRK - a pseudo-random key; it is used by calculate()
self.prk = try HMAC(key: salt ?? [], variant: variant).authenticate(password)
self.info = info ?? []
self.variant = variant
self.dkLen = dkLen
self.numBlocks = numBlocks
}
public func calculate() throws -> Array<UInt8> {
let hmac = HMAC(key: prk, variant: variant)
var ret = Array<UInt8>()
ret.reserveCapacity(self.numBlocks * self.variant.digestLength)
var value = Array<UInt8>()
for i in 1...self.numBlocks {
value.append(contentsOf: self.info)
value.append(UInt8(i))
let bytes = try hmac.authenticate(value)
ret.append(contentsOf: bytes)
/// update value to use it as input for next iteration
value = bytes
}
return Array(ret.prefix(self.dkLen))
}
public func callAsFunction() throws -> Array<UInt8> {
try calculate()
}
}

View File

@ -1,124 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
public final class HMAC: Authenticator {
public enum Error: Swift.Error {
case authenticateError
case invalidInput
}
public enum Variant {
case md5
case sha1
case sha2(SHA2.Variant)
case sha3(SHA3.Variant)
@available(*, deprecated, message: "Use sha2(variant) instead.")
case sha256, sha384, sha512
var digestLength: Int {
switch self {
case .sha1:
return SHA1.digestLength
case .sha256:
return SHA2.Variant.sha256.digestLength
case .sha384:
return SHA2.Variant.sha384.digestLength
case .sha512:
return SHA2.Variant.sha512.digestLength
case .sha2(let variant):
return variant.digestLength
case .sha3(let variant):
return variant.digestLength
case .md5:
return MD5.digestLength
}
}
func calculateHash(_ bytes: Array<UInt8>) -> Array<UInt8> {
switch self {
case .sha1:
return Digest.sha1(bytes)
case .sha256:
return Digest.sha256(bytes)
case .sha384:
return Digest.sha384(bytes)
case .sha512:
return Digest.sha512(bytes)
case .sha2(let variant):
return Digest.sha2(bytes, variant: variant)
case .sha3(let variant):
return Digest.sha3(bytes, variant: variant)
case .md5:
return Digest.md5(bytes)
}
}
func blockSize() -> Int {
switch self {
case .md5:
return MD5.blockSize
case .sha1:
return SHA1.blockSize
case .sha256:
return SHA2.Variant.sha256.blockSize
case .sha384:
return SHA2.Variant.sha384.blockSize
case .sha512:
return SHA2.Variant.sha512.blockSize
case .sha2(let variant):
return variant.blockSize
case .sha3(let variant):
return variant.blockSize
}
}
}
var key: Array<UInt8>
let variant: Variant
public init(key: Array<UInt8>, variant: HMAC.Variant = .md5) {
self.variant = variant
self.key = key
if key.count > variant.blockSize() {
let hash = variant.calculateHash(key)
self.key = hash
}
if key.count < variant.blockSize() {
self.key = ZeroPadding().add(to: key, blockSize: variant.blockSize())
}
}
// MARK: Authenticator
public func authenticate(_ bytes: Array<UInt8>) throws -> Array<UInt8> {
var opad = Array<UInt8>(repeating: 0x5c, count: variant.blockSize())
for idx in self.key.indices {
opad[idx] = self.key[idx] ^ opad[idx]
}
var ipad = Array<UInt8>(repeating: 0x36, count: variant.blockSize())
for idx in self.key.indices {
ipad[idx] = self.key[idx] ^ ipad[idx]
}
let ipadAndMessageHash = self.variant.calculateHash(ipad + bytes)
let result = self.variant.calculateHash(opad + ipadAndMessageHash)
// return Array(result[0..<10]) // 80 bits
return result
}
}

View File

@ -1,56 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
import Foundation
/// Padding with random bytes, ending with the number of added bytes.
/// Read the [Wikipedia](https://en.wikipedia.org/wiki/Padding_(cryptography)#ISO_10126)
/// and [Crypto-IT](http://www.crypto-it.net/eng/theory/padding.html) articles for more info.
struct ISO10126Padding: PaddingProtocol {
init() {
}
@inlinable
func add(to bytes: Array<UInt8>, blockSize: Int) -> Array<UInt8> {
let padding = UInt8(blockSize - (bytes.count % blockSize))
var withPadding = bytes
if padding > 0 {
withPadding += (0..<(padding - 1)).map { _ in UInt8.random(in: 0...255) } + [padding]
}
return withPadding
}
@inlinable
func remove(from bytes: Array<UInt8>, blockSize: Int?) -> Array<UInt8> {
guard !bytes.isEmpty, let lastByte = bytes.last else {
return bytes
}
assert(!bytes.isEmpty, "Need bytes to remove padding")
let padding = Int(lastByte) // last byte
let finalLength = bytes.count - padding
if finalLength < 0 {
return bytes
}
if padding >= 1 {
return Array(bytes[0..<finalLength])
}
return bytes
}
}

View File

@ -1,44 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
import Foundation
// First byte is 0x80, rest is zero padding
// http://www.crypto-it.net/eng/theory/padding.html
// http://www.embedx.com/pdfs/ISO_STD_7816/info_isoiec7816-4%7Bed21.0%7Den.pdf
struct ISO78164Padding: PaddingProtocol {
init() {
}
@inlinable
func add(to bytes: Array<UInt8>, blockSize: Int) -> Array<UInt8> {
var padded = Array(bytes)
padded.append(0x80)
while (padded.count % blockSize) != 0 {
padded.append(0x00)
}
return padded
}
@inlinable
func remove(from bytes: Array<UInt8>, blockSize _: Int?) -> Array<UInt8> {
if let idx = bytes.lastIndex(of: 0x80) {
return Array(bytes[..<idx])
} else {
return bytes
}
}
}

View File

@ -1,33 +0,0 @@
//
// CryptoSwift
//
// Created by Marcin Krzyzanowski on 12/08/14.
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
#if canImport(Darwin)
import Darwin
#elseif canImport(Glibc)
import Glibc
#elseif canImport(ucrt)
import ucrt
#endif
extension FixedWidthInteger {
@inlinable
func bytes(totalBytes: Int = MemoryLayout<Self>.size) -> Array<UInt8> {
arrayOfBytes(value: self.littleEndian, length: totalBytes)
// TODO: adjust bytes order
// var value = self.littleEndian
// return withUnsafeBytes(of: &value, Array.init).reversed()
}
}

View File

@ -1,166 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
public final class MD5: DigestType {
static let blockSize: Int = 64
static let digestLength: Int = 16 // 128 / 8
fileprivate static let hashInitialValue: Array<UInt32> = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476]
fileprivate var accumulated = Array<UInt8>()
fileprivate var processedBytesTotalCount: Int = 0
fileprivate var accumulatedHash: Array<UInt32> = MD5.hashInitialValue
/** specifies the per-round shift amounts */
private let s: Array<UInt32> = [
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
]
/** binary integer part of the sines of integers (Radians) */
private let k: Array<UInt32> = [
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8,
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
]
public init() {
}
public func calculate(for bytes: Array<UInt8>) -> Array<UInt8> {
do {
return try update(withBytes: bytes.slice, isLast: true)
} catch {
fatalError()
}
}
public func callAsFunction(_ bytes: Array<UInt8>) -> Array<UInt8> {
calculate(for: bytes)
}
// mutating currentHash in place is way faster than returning new result
fileprivate func process(block chunk: ArraySlice<UInt8>, currentHash: inout Array<UInt32>) {
assert(chunk.count == 16 * 4)
// Initialize hash value for this chunk:
var A: UInt32 = currentHash[0]
var B: UInt32 = currentHash[1]
var C: UInt32 = currentHash[2]
var D: UInt32 = currentHash[3]
var dTemp: UInt32 = 0
// Main loop
for j in 0..<self.k.count {
var g = 0
var F: UInt32 = 0
switch j {
case 0...15:
F = (B & C) | ((~B) & D)
g = j
case 16...31:
F = (D & B) | (~D & C)
g = (5 * j + 1) % 16
case 32...47:
F = B ^ C ^ D
g = (3 * j + 5) % 16
case 48...63:
F = C ^ (B | (~D))
g = (7 * j) % 16
default:
break
}
dTemp = D
D = C
C = B
// break chunk into sixteen 32-bit words M[j], 0 j 15 and get M[g] value
let gAdvanced = g << 2
var Mg = UInt32(chunk[chunk.startIndex &+ gAdvanced])
Mg |= UInt32(chunk[chunk.startIndex &+ gAdvanced &+ 1]) << 8
Mg |= UInt32(chunk[chunk.startIndex &+ gAdvanced &+ 2]) << 16
Mg |= UInt32(chunk[chunk.startIndex &+ gAdvanced &+ 3]) << 24
B = B &+ rotateLeft(A &+ F &+ self.k[j] &+ Mg, by: self.s[j])
A = dTemp
}
currentHash[0] = currentHash[0] &+ A
currentHash[1] = currentHash[1] &+ B
currentHash[2] = currentHash[2] &+ C
currentHash[3] = currentHash[3] &+ D
}
}
extension MD5: Updatable {
public func update(withBytes bytes: ArraySlice<UInt8>, isLast: Bool = false) throws -> Array<UInt8> {
self.accumulated += bytes
if isLast {
let lengthInBits = (processedBytesTotalCount + self.accumulated.count) * 8
let lengthBytes = lengthInBits.bytes(totalBytes: 64 / 8) // A 64-bit representation of b
// Step 1. Append padding
bitPadding(to: &self.accumulated, blockSize: MD5.blockSize, allowance: 64 / 8)
// Step 2. Append Length a 64-bit representation of lengthInBits
self.accumulated += lengthBytes.reversed()
}
var processedBytes = 0
for chunk in self.accumulated.batched(by: MD5.blockSize) {
if isLast || (self.accumulated.count - processedBytes) >= MD5.blockSize {
self.process(block: chunk, currentHash: &self.accumulatedHash)
processedBytes += chunk.count
}
}
self.accumulated.removeFirst(processedBytes)
self.processedBytesTotalCount += processedBytes
// output current hash
var result = Array<UInt8>()
result.reserveCapacity(MD5.digestLength)
for hElement in self.accumulatedHash {
let hLE = hElement.littleEndian
result += Array<UInt8>(arrayLiteral: UInt8(hLE & 0xff), UInt8((hLE >> 8) & 0xff), UInt8((hLE >> 16) & 0xff), UInt8((hLE >> 24) & 0xff))
}
// reset hash value for instance
if isLast {
self.accumulatedHash = MD5.hashInitialValue
}
return result
}
}

View File

@ -1,27 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
struct NoPadding: PaddingProtocol {
init() {
}
func add(to data: Array<UInt8>, blockSize _: Int) -> Array<UInt8> {
data
}
func remove(from data: Array<UInt8>, blockSize _: Int?) -> Array<UInt8> {
data
}
}

View File

@ -1,32 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
/*
Bit shifting with overflow protection using overflow operator "&".
Approach is consistent with standard overflow operators &+, &-, &*, &/
and introduce new overflow operators for shifting: &<<, &>>
Note: Works with unsigned integers values only
Usage
var i = 1 // init
var j = i &<< 2 //shift left
j &<<= 2 //shift left and assign
@see: https://medium.com/@krzyzanowskim/swiftly-shift-bits-and-protect-yourself-be33016ce071
This fuctonality is now implemented as part of Swift 3, SE-0104 https://github.com/apple/swift-evolution/blob/master/proposals/0104-improved-integers.md
*/

View File

@ -1,90 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
import Foundation
/// Conform to this protocol if your type can both be instantiated and expressed as an ASN1 DER representation.
internal protocol DERCodable: DERDecodable, DEREncodable { }
/// Conform to this protocol if your type can be instantiated from a ASN1 DER representation
internal protocol DERDecodable {
/// Attempts to instantiate an instance of your Public Key when given a DER representation of your Public Key
///
/// - Parameter publicDER: The ASN.1 DER representation of your Public Key
init(publicDER: Array<UInt8>) throws
/// Attempts to instantiate an instance of your Private Key when given a DER representation of your Private Key
///
/// - Parameter privateDER: The ASN.1 DER representation of your Private Key
init(privateDER: Array<UInt8>) throws
/// Attempts to instantiate a Key when given the ASN1 DER encoded external representation of the Key
///
/// - Parameter rawRepresentation: The ASN1 DER Encoded external representation (either public or private)
/// - Note: The external representation is identical to that of `SecKeyCopyExternalRepresentation` function from Apple's `Security` framework
init(rawRepresentation: Data) throws
}
/// Conform to this protocol if your type can be described in an ASN1 DER representation
internal protocol DEREncodable {
/// Returns the DER encoded representation of the Public Key
func publicKeyDER() throws -> Array<UInt8>
/// Returns the DER encoded representation of the Private Key
func privateKeyDER() throws -> Array<UInt8>
/// A semantically similar function that mimics the `SecKeyCopyExternalRepresentation` function from Apple's `Security` framework
/// - Note: If called on a Private Key, this method will return the Private Keys DER Representation. Likewise, if called on a Public Key, this method will return the Public Keys DER Representation
/// - Note: If you'd like to export the Public Keys DER from a Private Key, use the `publicKeyExternalRepresentation()` function
func externalRepresentation() throws -> Data
/// A semantically similar function that mimics the `SecKeyCopyExternalRepresentation` function from Apple's `Security` framework
/// - Note: This function only ever exports the Public Key's DER representation. If called on a Private Key, the corresponding Public Key will be extracted and exported.
func publicKeyExternalRepresentation() throws -> Data
}
struct DER {
internal enum Error: Swift.Error {
/// We were provided invalid DER data
case invalidDERFormat
}
/// Integer to Octet String Primitive
/// - Parameters:
/// - x: nonnegative integer to be converted
/// - size: intended length of the resulting octet string
/// - Returns: corresponding octet string of length xLen
/// - Note: https://datatracker.ietf.org/doc/html/rfc3447#section-4.1
internal static func i2osp(x: [UInt8], size: Int) -> [UInt8] {
var modulus = x
while modulus.count < size {
modulus.insert(0x00, at: 0)
}
if modulus[0] >= 0x80 {
modulus.insert(0x00, at: 0)
}
return modulus
}
/// Integer to Octet String Primitive
/// - Parameters:
/// - x: nonnegative integer to be converted
/// - size: intended length of the resulting octet string
/// - Returns: corresponding octet string of length xLen
/// - Note: https://datatracker.ietf.org/doc/html/rfc3447#section-4.1
internal static func i2ospData(x: [UInt8], size: Int) -> Data {
return Data(DER.i2osp(x: x, size: size))
}
}

View File

@ -1,101 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
public extension PKCS5 {
/// A key derivation function.
///
/// PBKDF1 is recommended only for compatibility with existing
/// applications since the keys it produces may not be large enough for
/// some applications.
struct PBKDF1 {
public enum Error: Swift.Error {
case invalidInput
case derivedKeyTooLong
}
public enum Variant {
case md5, sha1
@usableFromInline
var size: Int {
switch self {
case .md5:
return MD5.digestLength
case .sha1:
return SHA1.digestLength
}
}
@usableFromInline
func calculateHash(_ bytes: Array<UInt8>) -> Array<UInt8> {
switch self {
case .sha1:
return Digest.sha1(bytes)
case .md5:
return Digest.md5(bytes)
}
}
}
@usableFromInline
let iterations: Int // c
@usableFromInline
let variant: Variant
@usableFromInline
let keyLength: Int
@usableFromInline
let t1: Array<UInt8>
/// - parameters:
/// - salt: salt, an eight-bytes
/// - variant: hash variant
/// - iterations: iteration count, a positive integer
/// - keyLength: intended length of derived key
public init(password: Array<UInt8>, salt: Array<UInt8>, variant: Variant = .sha1, iterations: Int = 4096 /* c */, keyLength: Int? = nil /* dkLen */ ) throws {
precondition(iterations > 0)
precondition(salt.count == 8)
let keyLength = keyLength ?? variant.size
if keyLength > variant.size {
throw Error.derivedKeyTooLong
}
let t1 = variant.calculateHash(password + salt)
self.iterations = iterations
self.variant = variant
self.keyLength = keyLength
self.t1 = t1
}
/// Apply the underlying hash function Hash for c iterations
@inlinable
public func calculate() -> Array<UInt8> {
var t = self.t1
for _ in 2...self.iterations {
t = self.variant.calculateHash(t)
}
return Array(t[0..<self.keyLength])
}
public func callAsFunction() -> Array<UInt8> {
calculate()
}
}
}

View File

@ -1,124 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
// https://www.ietf.org/rfc/rfc2898.txt
//
#if canImport(Darwin)
import Darwin
#elseif canImport(Glibc)
import Glibc
#elseif canImport(ucrt)
import ucrt
#elseif canImport(WASILibc)
import WASILibc
#endif
public extension PKCS5 {
/// A key derivation function.
///
/// PBKDF2 - Password-Based Key Derivation Function 2. Key stretching technique.
/// DK = PBKDF2(PRF, Password, Salt, c, dkLen)
struct PBKDF2 {
public enum Error: Swift.Error {
case invalidInput
case derivedKeyTooLong
}
private let salt: Array<UInt8> // S
fileprivate let iterations: Int // c
private let numBlocks: Int // l
private let dkLen: Int
fileprivate let prf: HMAC
/// - parameters:
/// - salt: salt
/// - variant: hash variant
/// - iterations: iteration count, a positive integer
/// - keyLength: intended length of derived key
/// - variant: MAC variant. Defaults to SHA256
public init(password: Array<UInt8>, salt: Array<UInt8>, iterations: Int = 4096 /* c */, keyLength: Int? = nil /* dkLen */, variant: HMAC.Variant = .sha2(.sha256)) throws {
precondition(iterations > 0)
let prf = HMAC(key: password, variant: variant)
guard iterations > 0 && !salt.isEmpty else {
throw Error.invalidInput
}
self.dkLen = keyLength ?? variant.digestLength
let keyLengthFinal = Double(dkLen)
let hLen = Double(prf.variant.digestLength)
if keyLengthFinal > (pow(2, 32) - 1) * hLen {
throw Error.derivedKeyTooLong
}
self.salt = salt
self.iterations = iterations
self.prf = prf
self.numBlocks = Int(ceil(Double(keyLengthFinal) / hLen)) // l = ceil(keyLength / hLen)
}
public func calculate() throws -> Array<UInt8> {
var ret = Array<UInt8>()
ret.reserveCapacity(self.numBlocks * self.prf.variant.digestLength)
for i in 1...self.numBlocks {
// for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter
if let value = try calculateBlock(self.salt, blockNum: i) {
ret.append(contentsOf: value)
}
}
return Array(ret.prefix(self.dkLen))
}
public func callAsFunction() throws -> Array<UInt8> {
try calculate()
}
}
}
private extension PKCS5.PBKDF2 {
func ARR(_ i: Int) -> Array<UInt8> {
var inti = Array<UInt8>(repeating: 0, count: 4)
inti[0] = UInt8((i >> 24) & 0xff)
inti[1] = UInt8((i >> 16) & 0xff)
inti[2] = UInt8((i >> 8) & 0xff)
inti[3] = UInt8(i & 0xff)
return inti
}
// F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c
// U_1 = PRF (P, S || INT (i))
func calculateBlock(_ salt: Array<UInt8>, blockNum: Int) throws -> Array<UInt8>? {
guard let u1 = try? prf.authenticate(salt + ARR(blockNum)) else { // blockNum.bytes() is slower
return nil
}
var u = u1
var ret = u
if iterations > 1 {
// U_2 = PRF (P, U_1) ,
// U_c = PRF (P, U_{c-1}) .
for _ in 2...iterations {
u = try prf.authenticate(u)
for x in 0..<ret.count {
ret[x] = ret[x] ^ u[x]
}
}
}
return ret
}
}

View File

@ -1,96 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
// PKCS is a group of public-key cryptography standards devised
// and published by RSA Security Inc, starting in the early 1990s.
//
/// EMSA PKCS1 v1.5 Padding Scheme
///
/// The EMSA Version of the PKCS1 v1.5 padding scheme is **deterministic** (it pads the messages contents with 255 value bytes)
/// ```
/// // The returned structure
/// // - PS is the applied padding
/// // - M is your original Message
/// EM = 0x00 || 0x01 || PS || 0x00 || M.
/// ```
/// - Note: This Padding scheme is intended to be used for encoding RSA Signatures
///
/// [EMSA-PKCS1v1_5 IETF Spec](https://datatracker.ietf.org/doc/html/rfc8017#section-9.2)
struct EMSAPKCS1v15Padding: PaddingProtocol {
init() {
}
@inlinable
func add(to bytes: Array<UInt8>, blockSize: Int) -> Array<UInt8> {
var r = blockSize - ((bytes.count + 3) % blockSize)
if r <= 0 { r = blockSize - 3 }
return [0x00, 0x01] + Array<UInt8>(repeating: 0xFF, count: r) + [0x00] + bytes
}
@inlinable
func remove(from bytes: Array<UInt8>, blockSize _: Int?) -> Array<UInt8> {
assert(!bytes.isEmpty, "Need bytes to remove padding")
assert(bytes.prefix(2) == [0x00, 0x01], "Invalid padding prefix")
guard let paddingLength = bytes.dropFirst(2).firstIndex(of: 0x00) else { return bytes }
guard (paddingLength + 1) <= bytes.count else { return bytes }
return Array(bytes[(paddingLength + 1)...])
}
}
/// EME PKCS1 v1.5 Padding Scheme
///
/// The EME Version of the PKCS1 v1.5 padding scheme is **non deterministic** (it pads the messages contents with psuedo-random bytes)
/// ```
/// // The returned structure
/// // - PS is the applied padding
/// // - M is your original Message
/// EM = 0x00 || 0x02 || PS || 0x00 || M.
/// ```
/// - Note: This Padding scheme is intended to be used for encoding messages before RSA Encryption
///
/// [EME-PKCS1v1_5 IETF Spec](https://datatracker.ietf.org/doc/html/rfc8017#section-7.2.1)
struct EMEPKCS1v15Padding: PaddingProtocol {
init() {
}
@inlinable
func add(to bytes: Array<UInt8>, blockSize: Int) -> Array<UInt8> {
var r = blockSize - ((bytes.count + 3) % blockSize)
if r <= 0 { r = blockSize - 3 }
return [0x00, 0x02] + (0..<r).map { _ in UInt8.random(in: 1...UInt8.max) } + [0x00] + bytes
}
@inlinable
func remove(from bytes: Array<UInt8>, blockSize _: Int?) -> Array<UInt8> {
assert(!bytes.isEmpty, "Need bytes to remove padding")
assert(bytes.prefix(2) == [0x00, 0x02], "Invalid padding prefix")
guard let paddingLength = bytes.dropFirst(2).firstIndex(of: 0x00) else { return bytes }
guard (paddingLength + 1) <= bytes.count else { return bytes }
return Array(bytes[(paddingLength + 1)...])
}
}

View File

@ -1,22 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
// PKCS is a group of public-key cryptography standards devised
// and published by RSA Security Inc, starting in the early 1990s.
//
public enum PKCS5 {
typealias Padding = PKCS7Padding
}

View File

@ -1,18 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
public enum PKCS7 {
typealias Padding = PKCS7Padding
}

View File

@ -1,62 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
// PKCS is a group of public-key cryptography standards devised
// and published by RSA Security Inc, starting in the early 1990s.
//
struct PKCS7Padding: PaddingProtocol {
enum Error: Swift.Error {
case invalidPaddingValue
}
init() {
}
@inlinable
func add(to bytes: Array<UInt8>, blockSize: Int) -> Array<UInt8> {
let padding = UInt8(blockSize - (bytes.count % blockSize))
var withPadding = bytes
if padding == 0 {
// If the original data is a multiple of N bytes, then an extra block of bytes with value N is added.
withPadding += Array<UInt8>(repeating: UInt8(blockSize), count: Int(blockSize))
} else {
// The value of each added byte is the number of bytes that are added
withPadding += Array<UInt8>(repeating: padding, count: Int(padding))
}
return withPadding
}
@inlinable
func remove(from bytes: Array<UInt8>, blockSize _: Int?) -> Array<UInt8> {
guard !bytes.isEmpty, let lastByte = bytes.last else {
return bytes
}
assert(!bytes.isEmpty, "Need bytes to remove padding")
let padding = Int(lastByte) // last byte
let finalLength = bytes.count - padding
if finalLength < 0 {
return bytes
}
if padding >= 1 {
return Array(bytes[0..<finalLength])
}
return bytes
}
}

View File

@ -1,65 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
public protocol PaddingProtocol {
func add(to: Array<UInt8>, blockSize: Int) -> Array<UInt8>
func remove(from: Array<UInt8>, blockSize: Int?) -> Array<UInt8>
}
public enum Padding: PaddingProtocol {
case noPadding, zeroPadding, pkcs7, pkcs5, eme_pkcs1v15, emsa_pkcs1v15, iso78164, iso10126
public func add(to: Array<UInt8>, blockSize: Int) -> Array<UInt8> {
switch self {
case .noPadding:
return to // NoPadding().add(to: to, blockSize: blockSize)
case .zeroPadding:
return ZeroPadding().add(to: to, blockSize: blockSize)
case .pkcs7:
return PKCS7.Padding().add(to: to, blockSize: blockSize)
case .pkcs5:
return PKCS5.Padding().add(to: to, blockSize: blockSize)
case .eme_pkcs1v15:
return EMEPKCS1v15Padding().add(to: to, blockSize: blockSize)
case .emsa_pkcs1v15:
return EMSAPKCS1v15Padding().add(to: to, blockSize: blockSize)
case .iso78164:
return ISO78164Padding().add(to: to, blockSize: blockSize)
case .iso10126:
return ISO10126Padding().add(to: to, blockSize: blockSize)
}
}
public func remove(from: Array<UInt8>, blockSize: Int?) -> Array<UInt8> {
switch self {
case .noPadding:
return from //NoPadding().remove(from: from, blockSize: blockSize)
case .zeroPadding:
return ZeroPadding().remove(from: from, blockSize: blockSize)
case .pkcs7:
return PKCS7.Padding().remove(from: from, blockSize: blockSize)
case .pkcs5:
return PKCS5.Padding().remove(from: from, blockSize: blockSize)
case .eme_pkcs1v15:
return EMEPKCS1v15Padding().remove(from: from, blockSize: blockSize)
case .emsa_pkcs1v15:
return EMSAPKCS1v15Padding().remove(from: from, blockSize: blockSize)
case .iso78164:
return ISO78164Padding().remove(from: from, blockSize: blockSize)
case .iso10126:
return ISO10126Padding().remove(from: from, blockSize: blockSize)
}
}
}

View File

@ -1,165 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
// http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04#section-4
// nacl/crypto_onetimeauth/poly1305/ref/auth.c
//
/// Poly1305 takes a 32-byte, one-time key and a message and produces a 16-byte tag that authenticates the
/// message such that an attacker has a negligible chance of producing a valid tag for an inauthentic message.
public final class Poly1305: Authenticator {
public enum Error: Swift.Error {
case authenticateError
}
public static let blockSize: Int = 16
private let key: SecureBytes
/// - parameter key: 32-byte key
public init(key: Array<UInt8>) {
self.key = SecureBytes(bytes: key)
}
private func squeeze(h: inout Array<UInt32>) {
assert(h.count == 17)
var u: UInt32 = 0
for j in 0..<16 {
u = u &+ h[j]
h[j] = u & 255
u = u >> 8
}
u = u &+ h[16]
h[16] = u & 3
u = 5 * (u >> 2)
for j in 0..<16 {
u = u &+ h[j]
h[j] = u & 255
u = u >> 8
}
u = u &+ h[16]
h[16] = u
}
private func add(h: inout Array<UInt32>, c: Array<UInt32>) {
assert(h.count == 17 && c.count == 17)
var u: UInt32 = 0
for j in 0..<17 {
u = u &+ (h[j] &+ c[j])
h[j] = u & 255
u = u >> 8
}
}
private func mulmod(h: inout Array<UInt32>, r: Array<UInt32>) {
var hr = Array<UInt32>(repeating: 0, count: 17)
var u: UInt32 = 0
for i in 0..<17 {
u = 0
for j in 0...i {
u = u &+ (h[j] * r[i &- j])
}
for j in (i + 1)..<17 {
u = u &+ (320 * h[j] * r[i &+ 17 &- j])
}
hr[i] = u
}
h = hr
self.squeeze(h: &h)
}
private func freeze(h: inout Array<UInt32>) {
let horig = h
self.add(h: &h, c: [5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252])
let negative = UInt32(bitPattern: -Int32(h[16] >> 7))
for j in 0..<17 {
h[j] ^= negative & (horig[j] ^ h[j])
}
}
/// the key is partitioned into two parts, called "r" and "s"
fileprivate func onetimeauth(message input: Array<UInt8>, key k: Array<UInt8>) -> Array<UInt8> {
// clamp
var r = Array<UInt32>(repeating: 0, count: 17)
var h = Array<UInt32>(repeating: 0, count: 17)
var c = Array<UInt32>(repeating: 0, count: 17)
r[0] = UInt32(k[0])
r[1] = UInt32(k[1])
r[2] = UInt32(k[2])
r[3] = UInt32(k[3] & 15)
r[4] = UInt32(k[4] & 252)
r[5] = UInt32(k[5])
r[6] = UInt32(k[6])
r[7] = UInt32(k[7] & 15)
r[8] = UInt32(k[8] & 252)
r[9] = UInt32(k[9])
r[10] = UInt32(k[10])
r[11] = UInt32(k[11] & 15)
r[12] = UInt32(k[12] & 252)
r[13] = UInt32(k[13])
r[14] = UInt32(k[14])
r[15] = UInt32(k[15] & 15)
r[16] = 0
var inlen = input.count
var inpos = 0
while inlen > 0 {
for j in 0..<c.count {
c[j] = 0
}
let maxj = min(inlen, 16)
for j in 0..<maxj {
c[j] = UInt32(input[inpos + j])
}
c[maxj] = 1
inpos = inpos + maxj
inlen = inlen - maxj
self.add(h: &h, c: c)
self.mulmod(h: &h, r: r)
}
self.freeze(h: &h)
for j in 0..<16 {
c[j] = UInt32(k[j + 16])
}
c[16] = 0
self.add(h: &h, c: c)
return h[0..<16].map {
UInt8($0 & 0xff)
}
}
// MARK: - Authenticator
/**
Calculate Message Authentication Code (MAC) for message.
Calculation context is discarder on instance deallocation.
- parameter bytes: Message
- returns: 16-byte tag that authenticates the message
*/
public func authenticate(_ bytes: Array<UInt8>) throws -> Array<UInt8> {
self.onetimeauth(message: bytes, key: Array(self.key))
}
}

View File

@ -1,128 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
import Foundation
// MARK: Cipher
extension RSA: Cipher {
@inlinable
public func encrypt(_ bytes: ArraySlice<UInt8>) throws -> Array<UInt8> {
return try self.encrypt(Array<UInt8>(bytes), variant: .pksc1v15)
}
@inlinable
public func encrypt(_ bytes: Array<UInt8>, variant: RSAEncryptionVariant) throws -> Array<UInt8> {
// Prepare the data for the specified variant
let preparedData = try variant.prepare(bytes, blockSize: self.keySizeBytes)
// Encrypt the prepared data
return try variant.formatEncryptedBytes(self.encryptPreparedBytes(preparedData), blockSize: self.keySizeBytes)
}
@inlinable
internal func encryptPreparedBytes(_ bytes: Array<UInt8>) throws -> Array<UInt8> {
// Calculate encrypted data
return BigUInteger(Data(bytes)).power(self.e, modulus: self.n).serialize().bytes
}
@inlinable
public func decrypt(_ bytes: ArraySlice<UInt8>) throws -> Array<UInt8> {
return try self.decrypt(Array<UInt8>(bytes), variant: .pksc1v15)
}
@inlinable
public func decrypt(_ bytes: Array<UInt8>, variant: RSAEncryptionVariant) throws -> Array<UInt8> {
// Decrypt the data
let decrypted = try self.decryptPreparedBytes(bytes)
// Remove padding / unstructure data and return the raw plaintext
return variant.removePadding(decrypted, blockSize: self.keySizeBytes)
}
@inlinable
internal func decryptPreparedBytes(_ bytes: Array<UInt8>) throws -> Array<UInt8> {
// Check for Private Exponent presence
guard let d = d else { throw RSA.Error.noPrivateKey }
// Calculate decrypted data
return BigUInteger(Data(bytes)).power(d, modulus: self.n).serialize().bytes
}
}
extension RSA {
/// RSA Encryption Block Types
/// - [RFC2313 8.1 - Encryption block formatting](https://datatracker.ietf.org/doc/html/rfc2313#section-8.1)
@frozen
public enum RSAEncryptionVariant {
/// The `unsafe` encryption variant, is fully deterministic and doesn't format the inbound data in any way.
///
/// - Warning: This is considered an unsafe method of encryption.
case unsafe
/// The `raw` encryption variant formats the inbound data with a deterministic padding scheme.
///
/// - Warning: This is also considered to be an unsafe method of encryption, but matches the `Security` frameworks functionality.
case raw
/// The `pkcs1v15` encryption variant formats the inbound data with a non deterministic pseudo random padding scheme.
///
/// [EME PKCS1v1.5 Padding Scheme Spec](https://datatracker.ietf.org/doc/html/rfc2313#section-8.1)
case pksc1v15
@inlinable
internal func prepare(_ bytes: Array<UInt8>, blockSize: Int) throws -> Array<UInt8> {
switch self {
case .unsafe:
return bytes
case .raw:
// We need at least 11 bytes of padding in order to safely encrypt messages
// - block types 1 and 2 have this minimum padding requirement, block type 0 isn't specified, but we enforce the minimum padding length here to be safe.
guard blockSize >= bytes.count + 11 else { throw RSA.Error.invalidMessageLengthForEncryption }
return Array(repeating: 0x00, count: blockSize - bytes.count) + bytes
case .pksc1v15:
// The `Security` framework refuses to encrypt a zero byte message using the pkcs1v15 padding scheme, so we do the same
guard !bytes.isEmpty else { throw RSA.Error.invalidMessageLengthForEncryption }
// We need at least 11 bytes of random padding in order to safely encrypt messages (RFC2313 Section 8.1 - Note 6)
guard blockSize >= bytes.count + 11 else { throw RSA.Error.invalidMessageLengthForEncryption }
return Padding.eme_pkcs1v15.add(to: bytes, blockSize: blockSize)
}
}
@inlinable
internal func formatEncryptedBytes(_ bytes: Array<UInt8>, blockSize: Int) -> Array<UInt8> {
switch self {
case .unsafe:
return bytes
case .raw, .pksc1v15:
// Format the encrypted bytes before returning
return Array<UInt8>(repeating: 0x00, count: blockSize - bytes.count) + bytes
}
}
@inlinable
internal func removePadding(_ bytes: Array<UInt8>, blockSize: Int) -> Array<UInt8> {
switch self {
case .unsafe:
return bytes
case .raw:
return bytes
case .pksc1v15:
// Convert the Octet String into an Integer Primitive using the BigInteger `serialize` method
// (this effectively just prefixes the data with a 0x00 byte indicating that its a positive integer)
return Padding.eme_pkcs1v15.remove(from: [0x00] + bytes, blockSize: blockSize)
}
}
}
}

View File

@ -1,262 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
import Foundation
// MARK: Signatures & Verification
extension RSA: Signature {
public func sign(_ bytes: ArraySlice<UInt8>) throws -> Array<UInt8> {
try self.sign(Array(bytes), variant: .message_pkcs1v15_SHA256)
}
/// Signs the data using the Private key and the specified signature variant
/// - Parameters:
/// - bytes: The data to be signed
/// - variant: The variant to use (`digest` variants expect a pre-hashed digest matching that of the specified hash function, `message` variants will hash the data using the specified hash function before signing it)
/// - Returns: The signature of the data
public func sign(_ bytes: Array<UInt8>, variant: SignatureVariant) throws -> Array<UInt8> {
// Check for Private Exponent presence
guard let d = d else { throw RSA.Error.noPrivateKey }
// Hash & Encode Message
let hashedAndEncoded = try RSA.hashedAndEncoded(bytes, variant: variant, keySizeInBytes: self.keySizeBytes)
/// Calculate the Signature
let signedData = BigUInteger(Data(hashedAndEncoded)).power(d, modulus: self.n).serialize().bytes
return variant.formatSignedBytes(signedData, blockSize: self.keySizeBytes)
}
public func verify(signature: ArraySlice<UInt8>, for expectedData: ArraySlice<UInt8>) throws -> Bool {
try self.verify(signature: Array(signature), for: Array(expectedData), variant: .message_pkcs1v15_SHA256)
}
/// Verifies whether a Signature is valid for the provided data
/// - Parameters:
/// - signature: The signature to verify
/// - expectedData: The original data that you expected to have been signed
/// - variant: The variant used to sign the data
/// - Returns: `True` when the signature is valid for the expected data, `False` otherwise.
///
/// [IETF Verification Spec](https://datatracker.ietf.org/doc/html/rfc8017#section-8.2.2)
public func verify(signature: Array<UInt8>, for bytes: Array<UInt8>, variant: SignatureVariant) throws -> Bool {
/// Step 1: Ensure the signature is the same length as the key's modulus
guard signature.count == self.keySizeBytes else { throw Error.invalidSignatureLength }
/// Prepare the expected message for signature comparison
var expectedData = try RSA.hashedAndEncoded(bytes, variant: variant, keySizeInBytes: self.keySizeBytes)
if expectedData.count == self.keySizeBytes && expectedData.prefix(1) == [0x00] { expectedData = Array(expectedData.dropFirst()) }
/// Step 2: 'Decrypt' the signature
let signatureResult = BigUInteger(Data(signature)).power(self.e, modulus: self.n).serialize().bytes
/// Step 3: Compare the 'decrypted' signature with the prepared / encoded expected message....
guard signatureResult == expectedData else { return false }
return true
}
/// Hashes and Encodes a message for signing and verifying
///
/// - Note: [EMSA-PKCS1-v1_5](https://datatracker.ietf.org/doc/html/rfc8017#section-9.2)
fileprivate static func hashedAndEncoded(_ bytes: [UInt8], variant: SignatureVariant, keySizeInBytes: Int) throws -> Array<UInt8> {
/// 1. Apply the hash function to the message M to produce a hash
let hashedMessage = variant.calculateHash(bytes)
guard variant.enforceLength(hashedMessage, keySizeInBytes: keySizeInBytes) else { throw RSA.Error.invalidMessageLengthForSigning }
/// 2. Encode the algorithm ID for the hash function and the hash value into an ASN.1 value of type DigestInfo
/// PKCS#1_15 DER Structure (OID == sha256WithRSAEncryption)
let t = variant.encode(hashedMessage)
if case .raw = variant { return t }
/// 3. If emLen < tLen + 11, output "intended encoded message length too short" and stop
if keySizeInBytes < t.count + 11 { throw RSA.Error.invalidMessageLengthForSigning }
/// 4. Generate an octet string PS consisting of emLen - tLen - 3
/// octets with hexadecimal value 0xff. The length of PS will be
/// at least 8 octets.
/// 5. Concatenate PS, the DER encoding T, and other padding to form
/// the encoded message EM as EM = 0x00 || 0x01 || PS || 0x00 || T.
let padded = variant.pad(bytes: t, to: keySizeInBytes)
/// Ensure the signature is of the correct length
guard padded.count == keySizeInBytes else { throw RSA.Error.invalidMessageLengthForSigning }
return padded
}
}
extension RSA {
public enum SignatureVariant {
/// rsaSignatureRaw
case raw
/// Hashes the raw message using MD5 before signing the data
case message_pkcs1v15_MD5
/// Hashes the raw message using SHA1 before signing the data
case message_pkcs1v15_SHA1
/// Hashes the raw message using SHA224 before signing the data
case message_pkcs1v15_SHA224
/// Hashes the raw message using SHA256 before signing the data
case message_pkcs1v15_SHA256
/// Hashes the raw message using SHA384 before signing the data
case message_pkcs1v15_SHA384
/// Hashes the raw message using SHA512 before signing the data
case message_pkcs1v15_SHA512
/// Hashes the raw message using SHA512-224 before signing the data
case message_pkcs1v15_SHA512_224
/// Hashes the raw message using SHA512-256 before signing the data
case message_pkcs1v15_SHA512_256
/// This variant isn't supported yet
case digest_pkcs1v15_RAW
/// This variant expects that the data to be signed is a valid MD5 Hash Digest
case digest_pkcs1v15_MD5
/// This variant expects that the data to be signed is a valid SHA1 Hash Digest
case digest_pkcs1v15_SHA1
/// This variant expects that the data to be signed is a valid SHA224 Hash Digest
case digest_pkcs1v15_SHA224
/// This variant expects that the data to be signed is a valid SHA256 Hash Digest
case digest_pkcs1v15_SHA256
/// This variant expects that the data to be signed is a valid SHA384 Hash Digest
case digest_pkcs1v15_SHA384
/// This variant expects that the data to be signed is a valid SHA512 Hash Digest
case digest_pkcs1v15_SHA512
/// This variant expects that the data to be signed is a valid SHA512-224 Hash Digest
case digest_pkcs1v15_SHA512_224
/// This variant expects that the data to be signed is a valid SHA512-256 Hash Digest
case digest_pkcs1v15_SHA512_256
internal var identifier: Array<UInt8> {
switch self {
case .raw, .digest_pkcs1v15_RAW: return []
case .message_pkcs1v15_MD5, .digest_pkcs1v15_MD5: return Array<UInt8>(arrayLiteral: 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05)
case .message_pkcs1v15_SHA1, .digest_pkcs1v15_SHA1: return Array<UInt8>(arrayLiteral: 0x2b, 0x0e, 0x03, 0x02, 0x1a)
case .message_pkcs1v15_SHA256, .digest_pkcs1v15_SHA256: return Array<UInt8>(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01)
case .message_pkcs1v15_SHA384, .digest_pkcs1v15_SHA384: return Array<UInt8>(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02)
case .message_pkcs1v15_SHA512, .digest_pkcs1v15_SHA512: return Array<UInt8>(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03)
case .message_pkcs1v15_SHA224, .digest_pkcs1v15_SHA224: return Array<UInt8>(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04)
case .message_pkcs1v15_SHA512_224, .digest_pkcs1v15_SHA512_224: return Array<UInt8>(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05)
case .message_pkcs1v15_SHA512_256, .digest_pkcs1v15_SHA512_256: return Array<UInt8>(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06)
}
}
internal func calculateHash(_ bytes: Array<UInt8>) -> Array<UInt8> {
switch self {
case .message_pkcs1v15_MD5:
return Digest.md5(bytes)
case .message_pkcs1v15_SHA1:
return Digest.sha1(bytes)
case .message_pkcs1v15_SHA224:
return Digest.sha224(bytes)
case .message_pkcs1v15_SHA256:
return Digest.sha256(bytes)
case .message_pkcs1v15_SHA384:
return Digest.sha384(bytes)
case .message_pkcs1v15_SHA512:
return Digest.sha512(bytes)
case .message_pkcs1v15_SHA512_224:
return Digest.sha2(bytes, variant: .sha224)
case .message_pkcs1v15_SHA512_256:
return Digest.sha2(bytes, variant: .sha256)
case .raw,
.digest_pkcs1v15_RAW,
.digest_pkcs1v15_MD5,
.digest_pkcs1v15_SHA1,
.digest_pkcs1v15_SHA224,
.digest_pkcs1v15_SHA256,
.digest_pkcs1v15_SHA384,
.digest_pkcs1v15_SHA512,
.digest_pkcs1v15_SHA512_224,
.digest_pkcs1v15_SHA512_256:
return bytes
}
}
internal func enforceLength(_ bytes: Array<UInt8>, keySizeInBytes: Int) -> Bool {
switch self {
case .raw, .digest_pkcs1v15_RAW:
return bytes.count <= keySizeInBytes
case .digest_pkcs1v15_MD5:
return bytes.count <= 16
case .digest_pkcs1v15_SHA1:
return bytes.count <= 20
case .digest_pkcs1v15_SHA224:
return bytes.count <= 28
case .digest_pkcs1v15_SHA256:
return bytes.count <= 32
case .digest_pkcs1v15_SHA384:
return bytes.count <= 48
case .digest_pkcs1v15_SHA512:
return bytes.count <= 64
case .digest_pkcs1v15_SHA512_224:
return bytes.count <= 28
case .digest_pkcs1v15_SHA512_256:
return bytes.count <= 32
case .message_pkcs1v15_MD5,
.message_pkcs1v15_SHA1,
.message_pkcs1v15_SHA224,
.message_pkcs1v15_SHA256,
.message_pkcs1v15_SHA384,
.message_pkcs1v15_SHA512,
.message_pkcs1v15_SHA512_224,
.message_pkcs1v15_SHA512_256:
return true
}
}
internal func encode(_ bytes: Array<UInt8>) -> Array<UInt8> {
switch self {
case .raw, .digest_pkcs1v15_RAW:
return bytes
default:
let asn: ASN1.Node = .sequence(nodes: [
.sequence(nodes: [
.objectIdentifier(data: Data(self.identifier)),
.null
]),
.octetString(data: Data(bytes))
])
return ASN1.Encoder.encode(asn)
}
}
/// Right now the only Padding Scheme supported is [EMCS-PKCS1v15](https://www.rfc-editor.org/rfc/rfc8017#section-9.2) (others include [EMSA-PSS](https://www.rfc-editor.org/rfc/rfc8017#section-9.1))
internal func pad(bytes: Array<UInt8>, to blockSize: Int) -> Array<UInt8> {
switch self {
case .raw:
return bytes
default:
return Padding.emsa_pkcs1v15.add(to: bytes, blockSize: blockSize)
}
}
/// Zero pads a signature to the specified block size
/// - Parameters:
/// - bytes: The signed bytes
/// - blockSize: The block size to pad until
/// - Returns: A zero padded (prepended) bytes array of length blockSize
internal func formatSignedBytes(_ bytes: Array<UInt8>, blockSize: Int) -> Array<UInt8> {
switch self {
default:
// Format the encrypted bytes before returning
return Array<UInt8>(repeating: 0x00, count: blockSize - bytes.count) + bytes
}
}
}
}

View File

@ -1,428 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
// Foundation is required for `Data` to be found
import Foundation
// Note: The `BigUInt` struct was copied from:
// https://github.com/attaswift/BigInt
// It allows fast calculation for RSA big numbers
public final class RSA: DERCodable {
/// RSA Key Errors
public enum Error: Swift.Error {
/// No private key specified
case noPrivateKey
/// Failed to calculate the inverse e and phi
case invalidInverseNotCoprimes
/// We only support Version 0 RSA keys (we don't support Version 1 introduced in RFC 3447)
case unsupportedRSAVersion
/// Failed to verify primes during initialiization (the provided primes don't reproduce the provided private exponent)
case invalidPrimes
/// We attempted to export a private key without our underlying primes
case noPrimes
/// Unable to calculate the coefficient during a private key import / export
case unableToCalculateCoefficient
/// The signature to verify is of an invalid length
case invalidSignatureLength
/// The message to be signed is of an invalid length
case invalidMessageLengthForSigning
/// The message to be encrypted is of an invalid length
case invalidMessageLengthForEncryption
/// The error thrown when Decryption fails
case invalidDecryption
}
/// RSA Modulus
public let n: BigUInteger
/// RSA Public Exponent
public let e: BigUInteger
/// RSA Private Exponent
public let d: BigUInteger?
/// The size of the modulus, in bits
public let keySize: Int
/// The size of the modulus, in bytes (rounded up to the nearest full byte)
public let keySizeBytes: Int
/// The underlying primes used to generate the Private Exponent
private let primes: (p: BigUInteger, q: BigUInteger)?
/// Initialize with RSA parameters
/// - Parameters:
/// - n: The RSA Modulus
/// - e: The RSA Public Exponent
/// - d: The RSA Private Exponent (or nil if unknown, e.g. if only public key is known)
public init(n: BigUInteger, e: BigUInteger, d: BigUInteger? = nil) {
self.n = n
self.e = e
self.d = d
self.primes = nil
self.keySize = n.bitWidth
self.keySizeBytes = n.byteWidth
}
/// Initialize with RSA parameters
/// - Parameters:
/// - n: The RSA Modulus
/// - e: The RSA Public Exponent
/// - d: The RSA Private Exponent (or nil if unknown, e.g. if only public key is known)
public convenience init(n: Array<UInt8>, e: Array<UInt8>, d: Array<UInt8>? = nil) {
if let d = d {
self.init(n: BigUInteger(Data(n)), e: BigUInteger(Data(e)), d: BigUInteger(Data(d)))
} else {
self.init(n: BigUInteger(Data(n)), e: BigUInteger(Data(e)))
}
}
/// Initialize with a generated key pair
/// - Parameter keySize: The size of the modulus
public convenience init(keySize: Int) throws {
// Generate prime numbers
let p = BigUInteger.generatePrime(keySize / 2)
let q = BigUInteger.generatePrime(keySize / 2)
// Calculate modulus
let n = p * q
// Calculate public and private exponent
let e: BigUInteger = 65537
let phi = (p - 1) * (q - 1)
guard let d = e.inverse(phi) else {
throw RSA.Error.invalidInverseNotCoprimes
}
// Initialize
try self.init(n: n, e: e, d: d, p: p, q: q)
}
/// Initialize with RSA parameters
/// - Parameters:
/// - n: The RSA Modulus
/// - e: The RSA Public Exponent
/// - d: The RSA Private Exponent
/// - p: The 1st Prime used to generate the Private Exponent
/// - q: The 2nd Prime used to generate the Private Exponent
public init(n: BigUInteger, e: BigUInteger, d: BigUInteger, p: BigUInteger, q: BigUInteger) throws {
// Ensure the supplied parameters are correct...
// Calculate modulus
guard n == p * q else { throw Error.invalidPrimes }
// Calculate public and private exponent
let phi = (p - 1) * (q - 1)
guard d == e.inverse(phi) else { throw Error.invalidPrimes }
// Regular initialization
self.n = n
self.e = e
self.d = d
self.primes = (p, q)
self.keySize = n.bitWidth
self.keySizeBytes = n.byteWidth
}
}
// MARK: BigUInt Extension
internal extension CS.BigUInt {
/// The minimum number of bytes required to represent this integer in binary.
var byteWidth: Int {
let bytes = self.bitWidth / 8
return self.bitWidth % 8 == 0 ? bytes : bytes + 1
}
}
// MARK: DER Initializers (See #892)
extension RSA {
/// Decodes the provided data into a Public RSA Key
///
/// [IETF Spec RFC2313](https://datatracker.ietf.org/doc/html/rfc2313#section-7.1)
/// ```
/// =========================
/// RSA PublicKey Structure
/// =========================
///
/// RSAPublicKey ::= SEQUENCE {
/// modulus INTEGER, -- n
/// publicExponent INTEGER, -- e
/// }
/// ```
internal convenience init(publicDER der: Array<UInt8>) throws {
let asn = try ASN1.Decoder.decode(data: Data(der))
// Enforce the above ASN Structure
guard case .sequence(let params) = asn else { throw DER.Error.invalidDERFormat }
guard params.count == 2 else { throw DER.Error.invalidDERFormat }
guard case .integer(let modulus) = params[0] else { throw DER.Error.invalidDERFormat }
guard case .integer(let publicExponent) = params[1] else { throw DER.Error.invalidDERFormat }
self.init(n: BigUInteger(modulus), e: BigUInteger(publicExponent))
}
/// Decodes the provided data into a Private RSA Key
///
/// [IETF Spec RFC2313](https://datatracker.ietf.org/doc/html/rfc2313#section-7.2)
/// ```
/// ==========================
/// RSA PrivateKey Structure
/// ==========================
///
/// RSAPrivateKey ::= SEQUENCE {
/// version Version,
/// modulus INTEGER, -- n
/// publicExponent INTEGER, -- e
/// privateExponent INTEGER, -- d
/// prime1 INTEGER, -- p
/// prime2 INTEGER, -- q
/// exponent1 INTEGER, -- d mod (p-1)
/// exponent2 INTEGER, -- d mod (q-1)
/// coefficient INTEGER, -- (inverse of q) mod p
/// }
/// ```
internal convenience init(privateDER der: Array<UInt8>) throws {
let asn = try ASN1.Decoder.decode(data: Data(der))
// Enforce the above ASN Structure (do we need to extract and verify the eponents and coefficients?)
guard case .sequence(let params) = asn else { throw DER.Error.invalidDERFormat }
guard params.count == 9 else { throw DER.Error.invalidDERFormat }
guard case .integer(let version) = params[0] else { throw DER.Error.invalidDERFormat }
guard case .integer(let modulus) = params[1] else { throw DER.Error.invalidDERFormat }
guard case .integer(let publicExponent) = params[2] else { throw DER.Error.invalidDERFormat }
guard case .integer(let privateExponent) = params[3] else { throw DER.Error.invalidDERFormat }
guard case .integer(let prime1) = params[4] else { throw DER.Error.invalidDERFormat }
guard case .integer(let prime2) = params[5] else { throw DER.Error.invalidDERFormat }
guard case .integer(let exponent1) = params[6] else { throw DER.Error.invalidDERFormat }
guard case .integer(let exponent2) = params[7] else { throw DER.Error.invalidDERFormat }
guard case .integer(let coefficient) = params[8] else { throw DER.Error.invalidDERFormat }
// We only support version 0x00 == RFC2313 at the moment
// - TODO: Support multiple primes 0x01 version defined in [RFC3447](https://www.rfc-editor.org/rfc/rfc3447#appendix-A.1.2)
guard version == Data(hex: "0x00") else { throw Error.unsupportedRSAVersion }
// Calculate public and private exponent
let phi = (BigUInteger(prime1) - 1) * (BigUInteger(prime2) - 1)
guard let d = BigUInteger(publicExponent).inverse(phi) else { throw Error.invalidPrimes }
guard BigUInteger(privateExponent) == d else { throw Error.invalidPrimes }
// Ensure the provided coefficient is correct (derived from the primes)
guard let calculatedCoefficient = BigUInteger(prime2).inverse(BigUInteger(prime1)) else { throw RSA.Error.unableToCalculateCoefficient }
guard calculatedCoefficient == BigUInteger(coefficient) else { throw RSA.Error.invalidPrimes }
// Ensure the provided exponents are correct as well
guard (d % (BigUInteger(prime1) - 1)) == BigUInteger(exponent1) else { throw RSA.Error.invalidPrimes }
guard (d % (BigUInteger(prime2) - 1)) == BigUInteger(exponent2) else { throw RSA.Error.invalidPrimes }
// Proceed with regular initialization
try self.init(n: BigUInteger(modulus), e: BigUInteger(publicExponent), d: BigUInteger(privateExponent), p: BigUInteger(prime1), q: BigUInteger(prime2))
}
/// Attempts to instantiate an RSA Key when given the ASN1 DER encoded external representation of the Key
///
/// An example of importing a SecKey RSA key (from Apple's `Security` framework) for use within CryptoSwift
/// ```
/// /// Starting with a SecKey RSA Key
/// let rsaSecKey:SecKey
///
/// /// Copy the External Representation
/// var externalRepError:Unmanaged<CFError>?
/// guard let externalRep = SecKeyCopyExternalRepresentation(rsaSecKey, &externalRepError) as? Data else {
/// /// Failed to copy external representation for RSA SecKey
/// return
/// }
///
/// /// Instantiate the RSA Key from the raw external representation
/// let rsaKey = try RSA(rawRepresentation: externalRep)
///
/// /// You now have a CryptoSwift RSA Key
/// // rsaKey.encrypt(...)
/// // rsaKey.decrypt(...)
/// // rsaKey.sign(...)
/// // rsaKey.verify(...)
/// ```
public convenience init(rawRepresentation raw: Data) throws {
do { try self.init(privateDER: raw.bytes) } catch {
try self.init(publicDER: raw.bytes)
}
}
}
// MARK: DER Exports (See #892)
extension RSA {
/// The DER representation of this public key
///
/// [IETF Spec RFC2313](https://datatracker.ietf.org/doc/html/rfc2313#section-7.1)
/// ```
/// =========================
/// RSA PublicKey Structure
/// =========================
///
/// RSAPublicKey ::= SEQUENCE {
/// modulus INTEGER, -- n
/// publicExponent INTEGER -- e
/// }
/// ```
func publicKeyDER() throws -> Array<UInt8> {
let mod = self.n.serialize()
let pubKeyAsnNode: ASN1.Node =
.sequence(nodes: [
.integer(data: DER.i2ospData(x: mod.bytes, size: self.keySizeBytes)),
.integer(data: DER.i2ospData(x: self.e.serialize().bytes, size: 3))
])
return ASN1.Encoder.encode(pubKeyAsnNode)
}
/// The DER representation of this private key
///
/// [IETF Spec RFC2313](https://datatracker.ietf.org/doc/html/rfc2313#section-7.2)
/// ```
/// ==========================
/// RSA PrivateKey Structure
/// ==========================
///
/// RSAPrivateKey ::= SEQUENCE {
/// version Version,
/// modulus INTEGER, -- n
/// publicExponent INTEGER, -- e
/// privateExponent INTEGER, -- d
/// prime1 INTEGER, -- p
/// prime2 INTEGER, -- q
/// exponent1 INTEGER, -- d mod (p-1)
/// exponent2 INTEGER, -- d mod (q-1)
/// coefficient INTEGER, -- (inverse of q) mod p
/// }
/// ```
func privateKeyDER() throws -> Array<UInt8> {
// Make sure we have a private key
guard let d = d else { throw RSA.Error.noPrivateKey }
// Make sure we have access to our primes
guard let primes = primes else { throw RSA.Error.noPrimes }
// Make sure we can calculate our coefficient (inverse of q mod p)
guard let coefficient = primes.q.inverse(primes.p) else { throw RSA.Error.unableToCalculateCoefficient }
let paramWidth = self.keySizeBytes / 2
// Structure the data (according to RFC2313, version 0x00 RSA Private Key Syntax)
let mod = self.n.serialize()
let privateKeyAsnNode: ASN1.Node =
.sequence(nodes: [
.integer(data: Data(hex: "0x00")),
.integer(data: DER.i2ospData(x: mod.bytes, size: self.keySizeBytes)),
.integer(data: DER.i2ospData(x: self.e.serialize().bytes, size: 3)),
.integer(data: DER.i2ospData(x: d.serialize().bytes, size: self.keySizeBytes)),
.integer(data: DER.i2ospData(x: primes.p.serialize().bytes, size: paramWidth)),
.integer(data: DER.i2ospData(x: primes.q.serialize().bytes, size: paramWidth)),
.integer(data: DER.i2ospData(x: (d % (primes.p - 1)).serialize().bytes, size: paramWidth)),
.integer(data: DER.i2ospData(x: (d % (primes.q - 1)).serialize().bytes, size: paramWidth)),
.integer(data: DER.i2ospData(x: coefficient.serialize().bytes, size: paramWidth))
])
// Encode and return the data
return ASN1.Encoder.encode(privateKeyAsnNode)
}
/// This method returns the DER encoding of the RSA Key.
///
/// - Returns: The ASN1 DER Encoding of the Public or Private RSA Key
/// - Note: If the RSA Key is a private key, the private key representation is returned
/// - Note: If the RSA Key is a public key, the public key representation is returned
/// - Note: If you'd like to only export the public DER of an RSA Key call the `publicKeyExternalRepresentation()` method
/// - Note: This method returns the same data as Apple's `SecKeyCopyExternalRepresentation` method.
///
/// An example of converting a CryptoSwift RSA key to a SecKey RSA key
/// ```
/// /// Starting with a CryptoSwift RSA Key
/// let rsaKey = try RSA(keySize: 1024)
///
/// /// Define your Keys attributes
/// let attributes: [String:Any] = [
/// kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
/// kSecAttrKeyClass as String: kSecAttrKeyClassPrivate, // or kSecAttrKeyClassPublic
/// kSecAttrKeySizeInBits as String: 1024, // The appropriate bits
/// kSecAttrIsPermanent as String: false
/// ]
/// var error:Unmanaged<CFError>? = nil
/// guard let rsaSecKey = try SecKeyCreateWithData(rsaKey.externalRepresentation() as CFData, attributes as CFDictionary, &error) else {
/// /// Error constructing SecKey from raw key data
/// return
/// }
///
/// /// You now have an RSA SecKey for use with Apple's Security framework
/// ```
///
/// An example of converting a SecKey RSA key to a CryptoSwift RSA key
/// ```
/// /// Starting with a SecKey RSA Key
/// let rsaSecKey:SecKey
///
/// /// Copy External Representation
/// var externalRepError:Unmanaged<CFError>?
/// guard let cfdata = SecKeyCopyExternalRepresentation(rsaSecKey, &externalRepError) else {
/// /// Failed to copy external representation for RSA SecKey
/// return
/// }
///
/// /// Instantiate the RSA Key from the raw external representation
/// let rsaKey = try RSA(rawRepresentation: cfdata as Data)
///
/// /// You now have a CryptoSwift RSA Key
/// ```
///
public func externalRepresentation() throws -> Data {
if self.primes != nil {
return try Data(self.privateKeyDER())
} else {
return try Data(self.publicKeyDER())
}
}
public func publicKeyExternalRepresentation() throws -> Data {
return try Data(self.publicKeyDER())
}
}
// MARK: CS.BigUInt extension
extension BigUInteger {
public static func generatePrime(_ width: Int) -> BigUInteger {
// Note: Need to find a better way to generate prime numbers
while true {
var random = BigUInteger.randomInteger(withExactWidth: width)
random |= BigUInteger(1)
if random.isPrime() {
return random
}
}
}
}
// MARK: CustomStringConvertible Conformance
extension RSA: CustomStringConvertible {
public var description: String {
if self.d != nil {
return "CryptoSwift.RSA.PrivateKey<\(self.keySize)>"
} else {
return "CryptoSwift.RSA.PublicKey<\(self.keySize)>"
}
}
}

View File

@ -1,221 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
public final class Rabbit: BlockCipher {
public enum Error: Swift.Error {
case invalidKeyOrInitializationVector
}
/// Size of IV in bytes
public static let ivSize = 64 / 8
/// Size of key in bytes
public static let keySize = 128 / 8
/// Size of block in bytes
public static let blockSize = 128 / 8
public var keySize: Int {
self.key.count
}
/// Key
private let key: Key
/// IV (optional)
private let iv: Array<UInt8>?
/// State variables
private var x = Array<UInt32>(repeating: 0, count: 8)
/// Counter variables
private var c = Array<UInt32>(repeating: 0, count: 8)
/// Counter carry
private var p7: UInt32 = 0
/// 'a' constants
private var a: Array<UInt32> = [
0x4d34d34d,
0xd34d34d3,
0x34d34d34,
0x4d34d34d,
0xd34d34d3,
0x34d34d34,
0x4d34d34d,
0xd34d34d3
]
// MARK: - Initializers
public convenience init(key: Array<UInt8>) throws {
try self.init(key: key, iv: nil)
}
public init(key: Array<UInt8>, iv: Array<UInt8>?) throws {
self.key = Key(bytes: key)
self.iv = iv
guard key.count == Rabbit.keySize && (iv == nil || iv!.count == Rabbit.ivSize) else {
throw Error.invalidKeyOrInitializationVector
}
}
// MARK: -
fileprivate func setup() {
self.p7 = 0
// Key divided into 8 subkeys
let k = Array<UInt32>(unsafeUninitializedCapacity: 8) { buf, count in
for j in 0..<8 {
buf[j] = UInt32(self.key[Rabbit.blockSize - (2 * j + 1)]) | (UInt32(self.key[Rabbit.blockSize - (2 * j + 2)]) << 8)
}
count = 8
}
// Initialize state and counter variables from subkeys
for j in 0..<8 {
if j % 2 == 0 {
self.x[j] = (k[(j + 1) % 8] << 16) | k[j]
self.c[j] = (k[(j + 4) % 8] << 16) | k[(j + 5) % 8]
} else {
self.x[j] = (k[(j + 5) % 8] << 16) | k[(j + 4) % 8]
self.c[j] = (k[j] << 16) | k[(j + 1) % 8]
}
}
// Iterate system four times
self.nextState()
self.nextState()
self.nextState()
self.nextState()
// Reinitialize counter variables
for j in 0..<8 {
self.c[j] = self.c[j] ^ self.x[(j + 4) % 8]
}
if let iv = iv {
self.setupIV(iv)
}
}
private func setupIV(_ iv: Array<UInt8>) {
// 63...56 55...48 47...40 39...32 31...24 23...16 15...8 7...0 IV bits
// 0 1 2 3 4 5 6 7 IV bytes in array
let iv0 = UInt32(bytes: [iv[4], iv[5], iv[6], iv[7]])
let iv1 = UInt32(bytes: [iv[0], iv[1], iv[4], iv[5]])
let iv2 = UInt32(bytes: [iv[0], iv[1], iv[2], iv[3]])
let iv3 = UInt32(bytes: [iv[2], iv[3], iv[6], iv[7]])
// Modify the counter state as function of the IV
c[0] = self.c[0] ^ iv0
self.c[1] = self.c[1] ^ iv1
self.c[2] = self.c[2] ^ iv2
self.c[3] = self.c[3] ^ iv3
self.c[4] = self.c[4] ^ iv0
self.c[5] = self.c[5] ^ iv1
self.c[6] = self.c[6] ^ iv2
self.c[7] = self.c[7] ^ iv3
// Iterate system four times
self.nextState()
self.nextState()
self.nextState()
self.nextState()
}
private func nextState() {
// Before an iteration the counters are incremented
var carry = self.p7
for j in 0..<8 {
let prev = self.c[j]
self.c[j] = prev &+ self.a[j] &+ carry
carry = prev > self.c[j] ? 1 : 0 // detect overflow
}
self.p7 = carry // save last carry bit
// Iteration of the system
self.x = Array<UInt32>(unsafeUninitializedCapacity: 8) { newX, count in
newX[0] = self.g(0) &+ rotateLeft(self.g(7), by: 16) &+ rotateLeft(self.g(6), by: 16)
newX[1] = self.g(1) &+ rotateLeft(self.g(0), by: 8) &+ self.g(7)
newX[2] = self.g(2) &+ rotateLeft(self.g(1), by: 16) &+ rotateLeft(self.g(0), by: 16)
newX[3] = self.g(3) &+ rotateLeft(self.g(2), by: 8) &+ self.g(1)
newX[4] = self.g(4) &+ rotateLeft(self.g(3), by: 16) &+ rotateLeft(self.g(2), by: 16)
newX[5] = self.g(5) &+ rotateLeft(self.g(4), by: 8) &+ self.g(3)
newX[6] = self.g(6) &+ rotateLeft(self.g(5), by: 16) &+ rotateLeft(self.g(4), by: 16)
newX[7] = self.g(7) &+ rotateLeft(self.g(6), by: 8) &+ self.g(5)
count = 8
}
}
private func g(_ j: Int) -> UInt32 {
let sum = self.x[j] &+ self.c[j]
let square = UInt64(sum) * UInt64(sum)
return UInt32(truncatingIfNeeded: square ^ (square >> 32))
}
fileprivate func nextOutput() -> Array<UInt8> {
self.nextState()
var output16 = Array<UInt16>(repeating: 0, count: Rabbit.blockSize / 2)
output16[7] = UInt16(truncatingIfNeeded: self.x[0]) ^ UInt16(truncatingIfNeeded: self.x[5] >> 16)
output16[6] = UInt16(truncatingIfNeeded: self.x[0] >> 16) ^ UInt16(truncatingIfNeeded: self.x[3])
output16[5] = UInt16(truncatingIfNeeded: self.x[2]) ^ UInt16(truncatingIfNeeded: self.x[7] >> 16)
output16[4] = UInt16(truncatingIfNeeded: self.x[2] >> 16) ^ UInt16(truncatingIfNeeded: self.x[5])
output16[3] = UInt16(truncatingIfNeeded: self.x[4]) ^ UInt16(truncatingIfNeeded: self.x[1] >> 16)
output16[2] = UInt16(truncatingIfNeeded: self.x[4] >> 16) ^ UInt16(truncatingIfNeeded: self.x[7])
output16[1] = UInt16(truncatingIfNeeded: self.x[6]) ^ UInt16(truncatingIfNeeded: self.x[3] >> 16)
output16[0] = UInt16(truncatingIfNeeded: self.x[6] >> 16) ^ UInt16(truncatingIfNeeded: self.x[1])
var output8 = Array<UInt8>(repeating: 0, count: Rabbit.blockSize)
for j in 0..<output16.count {
output8[j * 2] = UInt8(truncatingIfNeeded: output16[j] >> 8)
output8[j * 2 + 1] = UInt8(truncatingIfNeeded: output16[j])
}
return output8
}
}
// MARK: Cipher
extension Rabbit: Cipher {
public func encrypt(_ bytes: ArraySlice<UInt8>) throws -> Array<UInt8> {
self.setup()
return Array<UInt8>(unsafeUninitializedCapacity: bytes.count) { result, count in
var output = self.nextOutput()
var byteIdx = 0
var outputIdx = 0
while byteIdx < bytes.count {
if outputIdx == Rabbit.blockSize {
output = self.nextOutput()
outputIdx = 0
}
result[byteIdx] = bytes[byteIdx] ^ output[outputIdx]
byteIdx += 1
outputIdx += 1
}
count = bytes.count
}
}
public func decrypt(_ bytes: ArraySlice<UInt8>) throws -> Array<UInt8> {
try self.encrypt(bytes)
}
}

View File

@ -1,162 +0,0 @@
//
// CryptoSwift
//
// Copyright (C) 2014-2022 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
// This software is provided 'as-is', without any express or implied warranty.
//
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
//
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// - This notice may not be removed or altered from any source or binary distribution.
//
public final class SHA1: DigestType {
@usableFromInline
static let digestLength: Int = 20 // 160 / 8
@usableFromInline
static let blockSize: Int = 64
@usableFromInline
static let hashInitialValue: ContiguousArray<UInt32> = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0]
@usableFromInline
var accumulated = Array<UInt8>()
@usableFromInline
var processedBytesTotalCount: Int = 0
@usableFromInline
var accumulatedHash: ContiguousArray<UInt32> = SHA1.hashInitialValue
public init() {
}
@inlinable
public func calculate(for bytes: Array<UInt8>) -> Array<UInt8> {
do {
return try update(withBytes: bytes.slice, isLast: true)
} catch {
return []
}
}
public func callAsFunction(_ bytes: Array<UInt8>) -> Array<UInt8> {
calculate(for: bytes)
}
@usableFromInline
func process(block chunk: ArraySlice<UInt8>, currentHash hh: inout ContiguousArray<UInt32>) {
// break chunk into sixteen 32-bit words M[j], 0 j 15, big-endian
// Extend the sixteen 32-bit words into eighty 32-bit words:
let M = UnsafeMutablePointer<UInt32>.allocate(capacity: 80)
M.initialize(repeating: 0, count: 80)
defer {
M.deinitialize(count: 80)
M.deallocate()
}
for x in 0..<80 {
switch x {
case 0...15:
let start = chunk.startIndex.advanced(by: x * 4) // * MemoryLayout<UInt32>.size
M[x] = UInt32(bytes: chunk, fromIndex: start)
default:
M[x] = rotateLeft(M[x - 3] ^ M[x - 8] ^ M[x - 14] ^ M[x - 16], by: 1)
}
}
var A = hh[0]
var B = hh[1]
var C = hh[2]
var D = hh[3]
var E = hh[4]
// Main loop
for j in 0...79 {
var f: UInt32 = 0
var k: UInt32 = 0
switch j {
case 0...19:
f = (B & C) | ((~B) & D)
k = 0x5a827999
case 20...39:
f = B ^ C ^ D
k = 0x6ed9eba1
case 40...59:
f = (B & C) | (B & D) | (C & D)
k = 0x8f1bbcdc
case 60...79:
f = B ^ C ^ D
k = 0xca62c1d6
default:
break
}
let temp = rotateLeft(A, by: 5) &+ f &+ E &+ M[j] &+ k
E = D
D = C
C = rotateLeft(B, by: 30)
B = A
A = temp
}
hh[0] = hh[0] &+ A
hh[1] = hh[1] &+ B
hh[2] = hh[2] &+ C
hh[3] = hh[3] &+ D
hh[4] = hh[4] &+ E
}
}
extension SHA1: Updatable {
@discardableResult @inlinable
public func update(withBytes bytes: ArraySlice<UInt8>, isLast: Bool = false) throws -> Array<UInt8> {
self.accumulated += bytes
if isLast {
let lengthInBits = (processedBytesTotalCount + self.accumulated.count) * 8
let lengthBytes = lengthInBits.bytes(totalBytes: 64 / 8) // A 64-bit representation of b
// Step 1. Append padding
bitPadding(to: &self.accumulated, blockSize: SHA1.blockSize, allowance: 64 / 8)
// Step 2. Append Length a 64-bit representation of lengthInBits
self.accumulated += lengthBytes
}
var processedBytes = 0
for chunk in self.accumulated.batched(by: SHA1.blockSize) {
if isLast || (self.accumulated.count - processedBytes) >= SHA1.blockSize {
self.process(block: chunk, currentHash: &self.accumulatedHash)
processedBytes += chunk.count
}
}
self.accumulated.removeFirst(processedBytes)
self.processedBytesTotalCount += processedBytes
// output current hash
var result = Array<UInt8>(repeating: 0, count: SHA1.digestLength)
var pos = 0
for idx in 0..<self.accumulatedHash.count {
let h = self.accumulatedHash[idx]
result[pos + 0] = UInt8((h >> 24) & 0xff)
result[pos + 1] = UInt8((h >> 16) & 0xff)
result[pos + 2] = UInt8((h >> 8) & 0xff)
result[pos + 3] = UInt8(h & 0xff)
pos += 4
}
// reset hash value for instance
if isLast {
self.accumulatedHash = SHA1.hashInitialValue
}
return result
}
}

Some files were not shown because too many files have changed in this diff Show More