Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion Sources/HomomorphicEncryption/Bfv/Bfv.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024 Apple Inc. and the Swift Homomorphic Encryption project authors
// Copyright 2024-2025 Apple Inc. and the Swift Homomorphic Encryption project authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -339,4 +339,22 @@ public enum Bfv<T: ScalarType>: HeScheme {
reduceToCiphertext(accumulator: accumulator, result: &result)
return result
}

@inlinable
public static func forwardNtt(_ ciphertext: CoeffCiphertext) throws -> EvalCiphertext {
let polys = try ciphertext.polys.map { try $0.forwardNtt() }
return Ciphertext<Bfv<T>, Eval>(context: ciphertext.context,
polys: polys,
correctionFactor: ciphertext.correctionFactor,
seed: ciphertext.seed)
}

@inlinable
public static func inverseNtt(_ ciphertext: EvalCiphertext) throws -> CoeffCiphertext {
let polys = try ciphertext.polys.map { try $0.inverseNtt() }
return Ciphertext<Bfv<T>, Coeff>(context: ciphertext.context,
polys: polys,
correctionFactor: ciphertext.correctionFactor,
seed: ciphertext.seed)
}
}
15 changes: 4 additions & 11 deletions Sources/HomomorphicEncryption/Ciphertext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -162,14 +162,12 @@ public struct Ciphertext<Scheme: HeScheme, Format: PolyFormat>: Equatable, Senda

@inlinable
package func forwardNtt() throws -> Ciphertext<Scheme, Eval> where Format == Coeff {
let polys = try polys.map { try $0.forwardNtt() }
return Ciphertext<Scheme, Eval>(context: context, polys: polys, correctionFactor: correctionFactor, seed: seed)
try Scheme.forwardNtt(self)
}

@inlinable
package func inverseNtt() throws -> Ciphertext<Scheme, Coeff> where Format == Eval {
let polys = try polys.map { try $0.inverseNtt() }
return Ciphertext<Scheme, Coeff>(context: context, polys: polys, correctionFactor: correctionFactor, seed: seed)
try Scheme.inverseNtt(self)
}

/// Converts the ciphertext to a ``HeScheme/CoeffCiphertext``.
Expand Down Expand Up @@ -296,9 +294,7 @@ public struct Ciphertext<Scheme: HeScheme, Format: PolyFormat>: Equatable, Senda
/// - seealso: ``Ciphertext/modSwitchDown()`` for more information and an alternative API.
@inlinable
public mutating func modSwitchDownToSingle() throws where Format == Scheme.CanonicalCiphertextFormat {
while moduli.count > 1 {
try Scheme.modSwitchDown(&self)
}
try Scheme.modSwitchDownToSingle(&self)
}

/// Decryption of a ciphertext.
Expand Down Expand Up @@ -485,10 +481,7 @@ extension Ciphertext where Format == Coeff {
/// - Throws: Error upon failure to compute the inverse.
@inlinable
public mutating func multiplyInversePowerOfX(power: Int) throws {
precondition(power >= 0)
for index in polys.indices {
try polys[index].multiplyInversePowerOfX(power)
}
try Scheme.multiplyInversePowerOfX(&self, power: power)
}
}

Expand Down
251 changes: 250 additions & 1 deletion Sources/HomomorphicEncryption/HeScheme.swift

Large diffs are not rendered by default.

228 changes: 228 additions & 0 deletions Sources/HomomorphicEncryption/HeSchemeAsync.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
// Copyright 2025 Apple Inc. and the Swift Homomorphic Encryption project authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/// The functions in this extension are the default implementation of async methods of HE scheme.
extension HeScheme {
// swiftlint:disable missing_docs
@inlinable
public static func rotateColumnsAsync(
of ciphertext: inout CanonicalCiphertext,
by step: Int,
using evaluationKey: EvaluationKey) async throws
{
try rotateColumns(of: &ciphertext, by: step, using: evaluationKey)
}

@inlinable
public static func swapRowsAsync(
of ciphertext: inout CanonicalCiphertext,
using evaluationKey: EvaluationKey) async throws
{
try swapRows(of: &ciphertext, using: evaluationKey)
}

@inlinable
public static func addAssignAsync(_ lhs: inout CoeffPlaintext, _ rhs: CoeffPlaintext) async throws {
try addAssign(&lhs, rhs)
}

@inlinable
public static func addAssignAsync(_ lhs: inout EvalPlaintext, _ rhs: EvalPlaintext) async throws {
try addAssign(&lhs, rhs)
}

@inlinable
public static func addAssignCoeffAsync(_ lhs: inout CoeffCiphertext, _ rhs: CoeffCiphertext) async throws {
try addAssignCoeff(&lhs, rhs)
}

@inlinable
public static func addAssignEvalAsync(_ lhs: inout EvalCiphertext, _ rhs: EvalCiphertext) async throws {
try addAssignEval(&lhs, rhs)
}

@inlinable
public static func subAssignCoeffAsync(_ lhs: inout CoeffCiphertext, _ rhs: CoeffCiphertext) async throws {
try subAssignCoeff(&lhs, rhs)
}

@inlinable
public static func subAssignEvalAsync(_ lhs: inout EvalCiphertext, _ rhs: EvalCiphertext) async throws {
try subAssignEval(&lhs, rhs)
}

@inlinable
public static func addAssignCoeffAsync(
_ ciphertext: inout CoeffCiphertext,
_ plaintext: CoeffPlaintext) async throws
{
try addAssignCoeff(&ciphertext, plaintext)
}

@inlinable
public static func addAssignEvalAsync(_ ciphertext: inout EvalCiphertext, _ plaintext: EvalPlaintext) async throws {
try addAssignEval(&ciphertext, plaintext)
}

@inlinable
public static func subAssignCoeffAsync(
_ ciphertext: inout CoeffCiphertext,
_ plaintext: CoeffPlaintext) async throws
{
try subAssignCoeff(&ciphertext, plaintext)
}

@inlinable
public static func subAssignEvalAsync(_ ciphertext: inout EvalCiphertext, _ plaintext: EvalPlaintext) async throws {
try subAssignEval(&ciphertext, plaintext)
}

@inlinable
public static func subCoeffAsync(_ plaintext: CoeffPlaintext,
_ ciphertext: CoeffCiphertext) async throws -> CoeffCiphertext
{
try subCoeff(plaintext, ciphertext)
}

@inlinable
public static func subEvalAsync(_ plaintext: EvalPlaintext,
_ ciphertext: EvalCiphertext) async throws -> EvalCiphertext
{
try subEval(plaintext, ciphertext)
}

@inlinable
public static func mulAssignAsync(_ ciphertext: inout EvalCiphertext, _ plaintext: EvalPlaintext) async throws {
try mulAssign(&ciphertext, plaintext)
}

@inlinable
public static func negAssignCoeffAsync(_ ciphertext: inout CoeffCiphertext) async {
negAssign(&ciphertext)
}

@inlinable
public static func negAssignEvalAsync(_ ciphertext: inout EvalCiphertext) async {
negAssign(&ciphertext)
}

@inlinable
public static func innerProductAsync(
_ lhs: some Collection<CanonicalCiphertext>,
_ rhs: some Collection<CanonicalCiphertext>) async throws
-> CanonicalCiphertext
{
try innerProduct(lhs, rhs)
}

@inlinable
public static func innerProductAsync(ciphertexts: some Collection<EvalCiphertext>,
plaintexts: some Collection<EvalPlaintext>) async throws -> EvalCiphertext
{
try innerProduct(ciphertexts: ciphertexts, plaintexts: plaintexts)
}

@inlinable
public static func innerProductAsync(ciphertexts: some Collection<EvalCiphertext>,
plaintexts: some Collection<EvalPlaintext?>) async throws -> EvalCiphertext
{
try innerProduct(ciphertexts: ciphertexts, plaintexts: plaintexts)
}

@inlinable
public static func mulAssignAsync(_ lhs: inout CanonicalCiphertext, _ rhs: CanonicalCiphertext) async throws {
try mulAssign(&lhs, rhs)
}

@inlinable
public static func addAssignAsync(_ lhs: inout CanonicalCiphertext, _ rhs: CanonicalCiphertext) async throws {
try addAssign(&lhs, rhs)
}

@inlinable
public static func subAssignAsync(_ lhs: inout CanonicalCiphertext, _ rhs: CanonicalCiphertext) async throws {
try subAssign(&lhs, rhs)
}

@inlinable
public static func subAssignAsync(
_ ciphertext: inout CanonicalCiphertext,
_ plaintext: CoeffPlaintext) async throws
{
try subAssign(&ciphertext, plaintext)
}

@inlinable
public static func subAssignAsync(_ ciphertext: inout CanonicalCiphertext,
_ plaintext: EvalPlaintext) async throws
{
try subAssign(&ciphertext, plaintext)
}

@inlinable
public static func subAsync(_ plaintext: CoeffPlaintext,
_ ciphertext: CanonicalCiphertext) async throws -> CanonicalCiphertext
{
try sub(plaintext, ciphertext)
}

@inlinable
public static func subAsync(_ plaintext: EvalPlaintext,
_ ciphertext: CanonicalCiphertext) async throws -> CanonicalCiphertext
{
try sub(plaintext, ciphertext)
}

@inlinable
public static func modSwitchDownAsync(_ ciphertext: inout CanonicalCiphertext) async throws {
try modSwitchDown(&ciphertext)
}

@inlinable
public static func applyGaloisAsync(
ciphertext: inout CanonicalCiphertext,
element: Int,
using key: EvaluationKey) async throws
{
try applyGalois(ciphertext: &ciphertext, element: element, using: key)
}

@inlinable
public static func relinearizeAsync(_ ciphertext: inout CanonicalCiphertext,
using key: EvaluationKey) async throws
{
try relinearize(&ciphertext, using: key)
}

@inlinable
public static func forwardNttAsync(_ ciphertext: CoeffCiphertext) async throws -> EvalCiphertext {
try forwardNtt(ciphertext)
}

@inlinable
public static func inverseNttAsync(_ ciphertext: EvalCiphertext) async throws -> CoeffCiphertext {
try inverseNtt(ciphertext)
}

@inlinable
public static func modSwitchDownToSingleAsync(_ ciphertext: inout CanonicalCiphertext) async throws {
try modSwitchDownToSingle(&ciphertext)
}

@inlinable
public static func multiplyInversePowerOfXAsync(_ ciphertext: inout CoeffCiphertext, power: Int) async throws {
try multiplyInversePowerOfX(&ciphertext, power: power)
}
// swiftlint:enable missing_docs
}
18 changes: 17 additions & 1 deletion Sources/HomomorphicEncryption/NoOpScheme.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024 Apple Inc. and the Swift Homomorphic Encryption project authors
// Copyright 2024-2025 Apple Inc. and the Swift Homomorphic Encryption project authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -302,4 +302,20 @@ public enum NoOpScheme: HeScheme {
{
minNoiseBudget
}

public static func forwardNtt(_ ciphertext: CoeffCiphertext) throws -> EvalCiphertext {
let polys = try ciphertext.polys.map { try $0.forwardNtt() }
return Ciphertext<NoOpScheme, Eval>(context: ciphertext.context,
polys: polys,
correctionFactor: ciphertext.correctionFactor,
seed: ciphertext.seed)
}

public static func inverseNtt(_ ciphertext: EvalCiphertext) throws -> CoeffCiphertext {
let polys = try ciphertext.polys.map { try $0.inverseNtt() }
return Ciphertext<NoOpScheme, Coeff>(context: ciphertext.context,
polys: polys,
correctionFactor: ciphertext.correctionFactor,
seed: ciphertext.seed)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Private Nearest Neighbor Search database generation
The resulting database can be processed with the [PNNSProcessDatabase](https://swiftpackageindex.com/apple/swift-homomorphic-encryption/main/documentation/pnnsprocessdatabase) executable.

### Requirements
First ensure sure that the `~/.swiftpm/bin` directory is on your `$PATH`.
First ensure that the `~/.swiftpm/bin` directory is on your `$PATH`.
For example, if using the `zsh` shell, add the following line to your `~/.zshrc`
```sh
export PATH="$HOME/.swiftpm/bin:$PATH"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ PNNS database processing will transform a database in preparation for hosting PN
The `PNNSProcessDatabase` binary performs the processing.

### Requirements
First ensure sure that the `~/.swiftpm/bin` directory is on your `$PATH`.
First ensure that the `~/.swiftpm/bin` directory is on your `$PATH`.
For example, if using the `zsh` shell, add the following line to your `~/.zshrc`
```sh
export PATH="$HOME/.swiftpm/bin:$PATH"
Expand Down
Loading