Skip to content

Commit 2e0f602

Browse files
authored
Remove use of unsafe flags in libraries (#14)
1 parent d7888d1 commit 2e0f602

27 files changed

+186
-70
lines changed

Benchmarks/PolyBenchmark/PolyBenchmark.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
// limitations under the License.
1414

1515
// Benchmarks for PolyRq functions.
16-
// These benchmarks can be triggered with `swift package -c release benchmark --target PolyBenchmark`
16+
// These benchmarks can be triggered with `swift package benchmark --target PolyBenchmark`
1717
// for more readable results
1818

1919
@preconcurrency import Benchmark

Benchmarks/PrivateInformationRetrievalBenchmark/PrivateInformationRetrievalBenchmark.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
// Benchmarks for Pir functions.
1616
// These benchmarks can be triggered with
17-
// `swift package -c release benchmark --target PIRBenchmark`
17+
// `swift package benchmark --target PIRBenchmark`
1818
// for more readable results
1919

2020
@preconcurrency import Benchmark

Benchmarks/RlweBenchmark/RlweBenchmark.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
// limitations under the License.
1414

1515
// Benchmarks for Rlwe functions.
16-
// These benchmarks can be triggered with `swift package -c release benchmark --target RlweBenchmark`
16+
// These benchmarks can be triggered with `swift package benchmark --target RlweBenchmark`
1717
// for more readable results
1818

1919
@preconcurrency import Benchmark

Package.resolved

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 25 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,16 @@
1515
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1616
// See the License for the specific language governing permissions and
1717
// limitations under the License.
18-
1918
import PackageDescription
2019

21-
let swiftSettings: [SwiftSetting] = [
20+
let librarySettings: [SwiftSetting] = [
2221
.enableExperimentalFeature("StrictConcurrency"),
23-
.unsafeFlags(["-cross-module-optimization"], .when(configuration: .release)),
2422
]
2523

24+
let executableSettings: [SwiftSetting] =
25+
librarySettings +
26+
[.unsafeFlags(["-cross-module-optimization"], .when(configuration: .release))]
27+
2628
let package = Package(
2729
name: "swift-homomorphic-encryption",
2830
products: [
@@ -46,7 +48,7 @@ let package = Package(
4648
dependencies: [
4749
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.2.0"),
4850
.package(url: "https://github.com/apple/swift-crypto.git", from: "3.4.0"),
49-
.package(url: "https://github.com/swiftlang/swift-docc-plugin", from: "1.0.0"),
51+
.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"),
5052
.package(url: "https://github.com/apple/swift-numerics", from: "1.0.0"),
5153
// Keep version in sync with README
5254
.package(url: "https://github.com/apple/swift-protobuf", from: "1.27.0"),
@@ -68,47 +70,41 @@ let package = Package(
6870
.product(name: "_CryptoExtras", package: "swift-crypto"),
6971
"CUtil",
7072
],
71-
swiftSettings: swiftSettings + [
72-
SwiftSetting.unsafeFlags([
73-
"-Xllvm",
74-
"-unroll-count=8",
75-
"-Xllvm",
76-
"-unroll-threshold=64",
77-
]),
78-
]),
73+
swiftSettings: librarySettings),
7974
.target(
8075
name: "HomomorphicEncryptionProtobuf",
8176
dependencies: ["HomomorphicEncryption",
8277
.product(name: "SwiftProtobuf", package: "swift-protobuf")],
8378
exclude: ["generated/README.md"],
84-
swiftSettings: swiftSettings),
79+
swiftSettings: librarySettings),
8580
.target(
8681
name: "PrivateInformationRetrieval",
8782
dependencies: ["HomomorphicEncryption",
8883
.product(name: "Numerics", package: "swift-numerics")],
89-
swiftSettings: swiftSettings),
84+
swiftSettings: librarySettings),
9085
.target(
9186
name: "PrivateInformationRetrievalProtobuf",
9287
dependencies: ["PrivateInformationRetrieval",
9388
"HomomorphicEncryption",
9489
"HomomorphicEncryptionProtobuf",
9590
.product(name: "SwiftProtobuf", package: "swift-protobuf")],
9691
exclude: ["generated/README.md", "protobuf_module_mappings.txtpb"],
97-
swiftSettings: swiftSettings),
92+
swiftSettings: librarySettings),
9893
.target(
9994
name: "TestUtilities",
10095
dependencies: [
10196
"HomomorphicEncryption",
10297
.product(name: "Numerics", package: "swift-numerics"),
103-
]),
98+
],
99+
swiftSettings: librarySettings),
104100
.executableTarget(
105101
name: "PIRGenerateDatabase",
106102
dependencies: [
107103
.product(name: "ArgumentParser", package: "swift-argument-parser"),
108104
"HomomorphicEncryption",
109105
"PrivateInformationRetrievalProtobuf",
110106
],
111-
swiftSettings: swiftSettings),
107+
swiftSettings: executableSettings),
112108
.executableTarget(
113109
name: "PIRProcessDatabase",
114110
dependencies: [
@@ -118,51 +114,51 @@ let package = Package(
118114
"HomomorphicEncryption",
119115
.product(name: "Logging", package: "swift-log"),
120116
],
121-
swiftSettings: swiftSettings),
117+
swiftSettings: executableSettings),
122118
.executableTarget(
123119
name: "PIRShardDatabase",
124120
dependencies: [
125121
.product(name: "ArgumentParser", package: "swift-argument-parser"),
126122
"HomomorphicEncryption",
127123
"PrivateInformationRetrievalProtobuf",
128124
],
129-
swiftSettings: swiftSettings),
125+
swiftSettings: executableSettings),
130126
.testTarget(
131127
name: "HomomorphicEncryptionTests",
132128
dependencies: [
133129
"HomomorphicEncryption", "TestUtilities",
134130
.product(name: "Numerics", package: "swift-numerics"),
135-
]),
131+
], swiftSettings: executableSettings),
136132
.testTarget(
137133
name: "HomomorphicEncryptionProtobufTests",
138134
dependencies: [
139135
"HomomorphicEncryption",
140136
"HomomorphicEncryptionProtobuf",
141137
"TestUtilities",
142-
]),
138+
], swiftSettings: executableSettings),
143139
.testTarget(
144140
name: "PrivateInformationRetrievalProtobufTests",
145141
dependencies: [
146142
"PrivateInformationRetrieval",
147143
"PrivateInformationRetrievalProtobuf",
148144
"TestUtilities",
149-
]),
145+
], swiftSettings: executableSettings),
150146
.testTarget(
151147
name: "PrivateInformationRetrievalTests",
152148
dependencies: [
153149
"PrivateInformationRetrieval", "TestUtilities",
154150
.product(name: "Numerics", package: "swift-numerics"),
155-
]),
151+
], swiftSettings: executableSettings),
156152
.testTarget(
157153
name: "PIRGenerateDatabaseTests",
158154
dependencies: ["PIRGenerateDatabase",
159155
"TestUtilities",
160-
.product(name: "Numerics", package: "swift-numerics")]),
156+
.product(name: "Numerics", package: "swift-numerics")], swiftSettings: executableSettings),
161157
.testTarget(
162158
name: "PIRProcessDatabaseTests",
163159
dependencies: ["PIRProcessDatabase",
164160
"TestUtilities",
165-
.product(name: "Numerics", package: "swift-numerics")]),
161+
.product(name: "Numerics", package: "swift-numerics")], swiftSettings: executableSettings),
166162
])
167163

168164
// MARK: - Benchmarks
@@ -178,7 +174,7 @@ package.targets += [
178174
"HomomorphicEncryption",
179175
],
180176
path: "Benchmarks/PolyBenchmark",
181-
swiftSettings: swiftSettings,
177+
swiftSettings: executableSettings,
182178
plugins: [
183179
.plugin(name: "BenchmarkPlugin", package: "package-benchmark"),
184180
]),
@@ -189,7 +185,7 @@ package.targets += [
189185
"HomomorphicEncryption",
190186
],
191187
path: "Benchmarks/RlweBenchmark",
192-
swiftSettings: swiftSettings,
188+
swiftSettings: executableSettings,
193189
plugins: [
194190
.plugin(name: "BenchmarkPlugin", package: "package-benchmark"),
195191
]),
@@ -203,13 +199,13 @@ package.targets += [
203199
"PrivateInformationRetrievalProtobuf",
204200
],
205201
path: "Benchmarks/PrivateInformationRetrievalBenchmark",
206-
swiftSettings: swiftSettings,
202+
swiftSettings: executableSettings,
207203
plugins: [
208204
.plugin(name: "BenchmarkPlugin", package: "package-benchmark"),
209205
]),
210206
]
211207

212208
// Set the minimum macOS version for the package
213209
package.platforms = [
214-
.macOS(.v14), // Constrained by Swift 6 support for Xcode (https://developer.apple.com/support/xcode/)
210+
.macOS(.v14), // Constrained by Swift 5.10 support for Xcode (https://developer.apple.com/support/xcode/)
215211
]

README.md

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,23 +64,35 @@ Swift Homomorphic Encryption requires:
6464
6565
Swift Homomorphic Encryption is available as a Swift Package Manager package.
6666
To use Swift Homomorphic Encryption, choose a [tag](https://github.com/apple/swift-homomorphic-encryption/tags).
67-
Then, add the following dependency in your `Package.swift`, adding the commit hash associated with the tag.
67+
Then, add the following dependency in your `Package.swift`
6868
```swift
6969
.package(
7070
url: "https://github.com/apple/swift-homomorphic-encryption",
71-
revision: "git-commit-associated-with-the-tag"),
71+
from: "tag"),
7272
```
73-
74-
> [!NOTE]
75-
> Due to the use of `unsafeFlags` in Swift Homomorphic Encryption, you shouldn't depend on a git tag, which could prevent tagged releases of downstream projects.
76-
> In particular, without the `cross-module-optimization` flag, performance degrades dramatically.
77-
> One workaround is to add `SwiftHomomorphicEncryption` as a submodule rather than a package dependency.
73+
, replacing `tag` with your chosen tag, e.g. `1.0.0-alpha.1`.
7874

7975
To use the `HomomorphicEncryption` library, add
8076
```swift
8177
.product(name: "HomomorphicEncryption", package: "swift-homomorphic-encryption"),
8278
```
8379
to your target's dependencies.
80+
81+
> [!IMPORTANT]
82+
> When linking your executable, make sure to enable `cross-module-optimization`.
83+
> Without this flag, performance of Swift Homomorphic Encryption degrades dramatically,
84+
> due to failure to specialize generics. For example,
85+
> ```swift
86+
> .executableTarget(
87+
> name: "YourTarget",
88+
> dependencies: [
89+
> .product(name: "HomomorphicEncryption", package: "swift-homomorphic-encryption"),
90+
> ],
91+
> swiftSettings: [.unsafeFlags(["-cross-module-optimization"],
92+
> .when(configuration: .release))]
93+
> )
94+
> ```
95+
8496
You can then add
8597
```swift
8698
import HomomorphicEncryption

Sources/HomomorphicEncryption/Array2d.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ extension Array2d {
156156
}
157157

158158
// Sets all the data to zero. This is useful for clearing sensitive data.
159+
@inlinable
159160
mutating func zeroize() {
160161
let zeroizeSize = data.count * MemoryLayout<T>.size
161162
data.withUnsafeMutableBytes { dataPointer in

Sources/HomomorphicEncryption/Bfv/Bfv+Decrypt.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import Foundation
1616

1717
extension Bfv {
18+
@inlinable
1819
public static func decrypt(_ ciphertext: EvalCiphertext,
1920
using secretKey: SecretKey<Bfv<T>>) throws -> CoeffPlaintext
2021
{
@@ -27,6 +28,7 @@ extension Bfv {
2728
return CoeffPlaintext(context: ciphertext.context, poly: plaintext)
2829
}
2930

31+
@inlinable
3032
public static func decrypt(_ ciphertext: CoeffCiphertext,
3133
using secretKey: SecretKey<Bfv<T>>) throws -> CoeffPlaintext
3234
{

Sources/HomomorphicEncryption/Bfv/Bfv.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public enum Bfv<T: ScalarType>: HeScheme {
2828

2929
// MARK: HE operations
3030

31+
@inlinable
3132
public static func addAssign<F: PolyFormat>(_ lhs: inout Plaintext<Bfv<T>, F>, _ rhs: Plaintext<Bfv<T>, F>) throws {
3233
try validateEquality(of: lhs.context, and: rhs.context)
3334
lhs.poly += rhs.poly
@@ -57,10 +58,12 @@ public enum Bfv<T: ScalarType>: HeScheme {
5758
lhs.clearSeed()
5859
}
5960

61+
@inlinable
6062
public static func addAssign(_ ciphertext: inout CoeffCiphertext, _ plaintext: CoeffPlaintext) throws {
6163
try plaintextTranslate(ciphertext: &ciphertext, plaintext: plaintext, op: PlaintextTranslateOp.Add)
6264
}
6365

66+
@inlinable
6467
public static func subAssign(_ ciphertext: inout CoeffCiphertext, _ plaintext: CoeffPlaintext) throws {
6568
try plaintextTranslate(ciphertext: &ciphertext, plaintext: plaintext, op: PlaintextTranslateOp.Subtract)
6669
}
@@ -98,18 +101,22 @@ public enum Bfv<T: ScalarType>: HeScheme {
98101
// These operations could be supported with extra NTT conversions, but NTTs are expensive, so we prefer to
99102
// keep NTT conversions explicit
100103

104+
@inlinable
101105
public static func addAssign(_: inout EvalCiphertext, _: EvalPlaintext) throws {
102106
throw HeError.unsupportedHeOperation()
103107
}
104108

109+
@inlinable
105110
public static func addAssign(_: inout CanonicalCiphertext, _: EvalPlaintext) throws {
106111
throw HeError.unsupportedHeOperation()
107112
}
108113

114+
@inlinable
109115
public static func subAssign(_: inout EvalCiphertext, _: EvalPlaintext) throws {
110116
throw HeError.unsupportedHeOperation()
111117
}
112118

119+
@inlinable
113120
public static func subAssign(_: inout CanonicalCiphertext, _: EvalPlaintext) throws {
114121
throw HeError.unsupportedHeOperation()
115122
}

Sources/HomomorphicEncryption/Ciphertext.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ public struct Ciphertext<Scheme: HeScheme, Format: PolyFormat>: Equatable, Senda
209209
/// ``HeScheme/zeroCiphertext(context:moduliCount:)-52gz2`` yields a transparent transparent.
210210
/// - Returns: Whether the ciphertext is transparent.
211211
/// - seealso: ``HeScheme/isTransparent(ciphertext:)-31w9f`` for an alternative API.
212+
@inlinable
212213
public func isTransparent() -> Bool where Format == Coeff {
213214
Scheme.isTransparent(ciphertext: self)
214215
}
@@ -219,6 +220,7 @@ public struct Ciphertext<Scheme: HeScheme, Format: PolyFormat>: Equatable, Senda
219220
/// ``HeScheme/zeroCiphertext(context:moduliCount:)-52gz2`` yields a transparent transparent.
220221
/// - Returns: Whether the ciphertext is transparent.
221222
/// - seealso: ``HeScheme/isTransparent(ciphertext:)-1nwgm`` for an alternative API.
223+
@inlinable
222224
public func isTransparent() -> Bool where Format == Eval {
223225
Scheme.isTransparent(ciphertext: self)
224226
}
@@ -229,6 +231,7 @@ public struct Ciphertext<Scheme: HeScheme, Format: PolyFormat>: Equatable, Senda
229231
/// ``HeScheme/zeroCiphertext(context:moduliCount:)-52gz2`` yields a transparent transparent.
230232
/// - Returns: Whether the ciphertext is transparent.
231233
/// - seealso: ``HeScheme/isTransparent(ciphertext:)-6m5nk`` for an alternative API.
234+
@inlinable
232235
public func isTransparent() -> Bool where Format == Scheme.CanonicalCiphertextFormat {
233236
Scheme.isTransparent(ciphertext: self)
234237
}
@@ -842,6 +845,7 @@ extension Ciphertext where Format == Scheme.CanonicalCiphertextFormat {
842845
/// - key: Evaluation key. Must contain Galois element `element`.
843846
/// - Throws: Error upon failure to apply the Galois transformation.
844847
/// - seealso: ``HeScheme/applyGalois(ciphertext:element:using:)`` for an alternative API and more information.
848+
@inlinable
845849
public mutating func applyGalois(element: Int, using key: EvaluationKey<Scheme>) throws {
846850
try Scheme.applyGalois(ciphertext: &self, element: element, using: key)
847851
}
@@ -851,6 +855,7 @@ extension Ciphertext where Format == Scheme.CanonicalCiphertextFormat {
851855
/// - Parameter key: Evaluation key to relinearize with. Must contain a `RelinearizationKey`.
852856
/// - Throws: Error upon failure to relinearize.
853857
/// - seealso: ``HeScheme/relinearize(_:using:)`` for an alternative API and more information.
858+
@inlinable
854859
public mutating func relinearize(using key: EvaluationKey<Scheme>) throws {
855860
try Scheme.relinearize(&self, using: key)
856861
}

0 commit comments

Comments
 (0)