import { CipherText, CipherTextConstructorOptions } from './cipher-text'
import { Context } from './context'
import { Exception, SealError } from './exception'
import { GaloisKeys } from './galois-keys'
import { MemoryPoolHandle } from './memory-pool-handle'
import { ParmsIdType } from './parms-id-type'
import { PlainText, PlainTextConstructorOptions } from './plain-text'
import { RelinKeys } from './relin-keys'
import { SchemeType } from './scheme-type'
import { Instance, Library, LoaderOptions } from './seal'
export type EvaluatorDependencyOptions = {
readonly Exception: Exception
readonly MemoryPoolHandle: MemoryPoolHandle
readonly CipherText: CipherTextConstructorOptions
readonly PlainText: PlainTextConstructorOptions
}
export type EvaluatorDependencies = {
({
Exception,
MemoryPoolHandle,
CipherText,
PlainText
}: EvaluatorDependencyOptions): EvaluatorConstructorOptions
}
export type EvaluatorConstructorOptions = {
(context: Context): Evaluator
}
export type Evaluator = {
readonly instance: Instance
readonly unsafeInject: (instance: Instance) => void
readonly delete: () => void
readonly negate: (
encrypted: CipherText,
destination?: CipherText
) => CipherText | void
readonly add: (
a: CipherText,
b: CipherText,
destination?: CipherText
) => CipherText | void
readonly sub: (
a: CipherText,
b: CipherText,
destination?: CipherText
) => CipherText | void
readonly multiply: (
a: CipherText,
b: CipherText,
destination?: CipherText,
pool?: MemoryPoolHandle
) => CipherText | void
readonly square: (
encrypted: CipherText,
destination?: CipherText,
pool?: MemoryPoolHandle
) => CipherText | void
readonly relinearize: (
encrypted: CipherText,
relinKeys: RelinKeys,
destination?: CipherText,
pool?: MemoryPoolHandle
) => CipherText | void
readonly cipherModSwitchToNext: (
encrypted: CipherText,
destination?: CipherText,
pool?: MemoryPoolHandle
) => CipherText | void
readonly cipherModSwitchTo: (
encrypted: CipherText,
parmsId: ParmsIdType,
destination?: CipherText,
pool?: MemoryPoolHandle
) => CipherText | void
readonly plainModSwitchToNext: (
plain: PlainText,
destination?: PlainText
) => PlainText | void
readonly plainModSwitchTo: (
plain: PlainText,
parmsId: ParmsIdType,
destination?: PlainText
) => PlainText | void
readonly rescaleToNext: (
encrypted: CipherText,
destination?: CipherText,
pool?: MemoryPoolHandle
) => CipherText | void
readonly rescaleTo: (
encrypted: CipherText,
parmsId: ParmsIdType,
destination?: CipherText,
pool?: MemoryPoolHandle
) => CipherText | void
readonly modReduceToNext: (
encrypted: CipherText,
destination?: CipherText,
pool?: MemoryPoolHandle
) => CipherText | void
readonly modReduceTo: (
encrypted: CipherText,
parmsId: ParmsIdType,
destination?: CipherText,
pool?: MemoryPoolHandle
) => CipherText | void
readonly exponentiate: (
encrypted: CipherText,
exponent: number,
relinKeys: RelinKeys,
destination?: CipherText,
pool?: MemoryPoolHandle
) => CipherText | void
readonly addPlain: (
encrypted: CipherText,
plain: PlainText,
destination?: CipherText,
pool?: MemoryPoolHandle
) => CipherText | void
readonly subPlain: (
encrypted: CipherText,
plain: PlainText,
destination?: CipherText,
pool?: MemoryPoolHandle
) => CipherText | void
readonly multiplyPlain: (
encrypted: CipherText,
plain: PlainText,
destination?: CipherText,
pool?: MemoryPoolHandle
) => CipherText | void
readonly plainTransformToNtt: (
plain: PlainText,
parmsId: ParmsIdType,
destinationNtt?: PlainText,
pool?: MemoryPoolHandle
) => PlainText | void
readonly cipherTransformToNtt: (
encrypted: CipherText,
destinationNtt?: CipherText
) => CipherText | void
readonly cipherTransformFromNtt: (
encryptedNtt: CipherText,
destination?: CipherText
) => CipherText | void
readonly applyGalois: (
encrypted: CipherText,
galoisElt: number,
galoisKeys: GaloisKeys,
destination?: CipherText,
pool?: MemoryPoolHandle
) => CipherText | void
readonly rotateRows: (
encrypted: CipherText,
steps: number,
galoisKeys: GaloisKeys,
destination?: CipherText,
pool?: MemoryPoolHandle
) => CipherText | void
readonly rotateColumns: (
encrypted: CipherText,
galoisKeys: GaloisKeys,
destination?: CipherText,
pool?: MemoryPoolHandle
) => CipherText | void
readonly rotateVector: (
encrypted: CipherText,
steps: number,
galoisKeys: GaloisKeys,
destination?: CipherText,
pool?: MemoryPoolHandle
) => CipherText | void
readonly complexConjugate: (
encrypted: CipherText,
galoisKeys: GaloisKeys,
destination?: CipherText,
pool?: MemoryPoolHandle
) => CipherText | void
readonly sumElements: (
encrypted: CipherText,
galoisKeys: GaloisKeys,
scheme: SchemeType,
destination?: CipherText,
pool?: MemoryPoolHandle
) => CipherText | void
readonly dotProduct: (
a: CipherText,
b: CipherText,
relinKeys: RelinKeys,
galoisKeys: GaloisKeys,
scheme: SchemeType,
destination?: CipherText,
pool?: MemoryPoolHandle
) => CipherText | void
readonly dotProductPlain: (
a: CipherText,
b: PlainText,
galoisKeys: GaloisKeys,
scheme: SchemeType,
destination?: CipherText,
pool?: MemoryPoolHandle
) => CipherText | void
}
const EvaluatorConstructor =
(library: Library): EvaluatorDependencies =>
({
Exception,
MemoryPoolHandle,
CipherText,
PlainText
}: EvaluatorDependencyOptions): EvaluatorConstructorOptions =>
(context): Evaluator => {
const Constructor = library.Evaluator
let _instance: Instance
try {
_instance = new Constructor(context.instance)
} catch (e) {
throw Exception.safe(e as SealError)
}
/**
* @implements Evaluator
*/
/**
* @interface Evaluator
*/
return {
/**
* Get the underlying WASM instance
*
* @private
* @readonly
* @name Evaluator#instance
* @type {Instance}
*/
get instance() {
return _instance
},
/**
* Inject this object with a raw WASM instance. No type checking is performed.
*
* @private
* @function
* @name Evaluator#unsafeInject
* @param {Instance} instance WASM instance
*/
unsafeInject(instance: Instance) {
if (_instance) {
_instance.delete()
_instance = undefined
}
_instance = instance
},
/**
* Delete the underlying WASM instance.
*
* Should be called before dereferencing this object to prevent the
* WASM heap from growing indefinitely.
* @function
* @name Evaluator#delete
*/
delete() {
if (_instance) {
_instance.delete()
_instance = undefined
}
},
/**
* Negates a CipherText and stores the result in the destination parameter.
*
* @function
* @name Evaluator#negate
* @param {CipherText} encrypted CipherText to negate
* @param {CipherText} [destination] CipherText to store the negated results
* @returns {CipherText|void} CipherText containing the result or void if a destination was supplied
* @example
* const cipherText = seal.CipherText()
* // ... after encrypting some data ...
* const resultCipher = evaluator.negate(cipherText)
* // or
* const cipherDest = seal.CipherText()
* evaluator.negate(encrypted, cipherDest)
*/
negate(
encrypted: CipherText,
destination?: CipherText
): CipherText | void {
try {
if (destination) {
_instance.negate(encrypted.instance, destination.instance)
return
}
const temp = CipherText()
_instance.negate(encrypted.instance, temp.instance)
return temp
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Adds two CipherTexts. This function adds together a and b
* and stores the result in the destination parameter.
*
* @function
* @name Evaluator#add
* @param {CipherText} a CipherText operand A
* @param {CipherText} b CipherText operand B
* @param {CipherText} [destination] CipherText destination to store the sum
* @returns {CipherText|void} CipherText containing the result or void if a destination was supplied
* @example
* const cipherTextA = seal.CipherText()
* const cipherTextB = seal.CipherText()
* // ... after encrypting some data ...
* const resultCipher = evaluator.add(cipherTextA, cipherTextB)
* // or
* const cipherDest = seal.CipherText()
* evaluator.add(cipherTextA, cipherTextB, cipherDest)
*/
add(
a: CipherText,
b: CipherText,
destination?: CipherText
): CipherText | void {
try {
if (destination) {
_instance.add(a.instance, b.instance, destination.instance)
return
}
const temp = CipherText()
_instance.add(a.instance, b.instance, temp.instance)
return temp
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Subtracts two CipherTexts. This function computes the difference of a
* and b and stores the result in the destination parameter.
*
* @function
* @name Evaluator#sub
* @param {CipherText} a CipherText operand A
* @param {CipherText} b CipherText operand B
* @param {CipherText} [destination] CipherText destination to store the difference
* @returns {CipherText|void} CipherText containing the result or void if a destination was supplied
* @example
* const cipherTextA = seal.CipherText()
* const cipherTextB = seal.CipherText()
* // ... after encrypting some data ...
* const resultCipher = evaluator.sub(cipherTextA, cipherTextB)
* // or
* const cipherDest = seal.CipherText()
* evaluator.sub(cipherTextA, cipherTextB, cipherDest)
*/
sub(
a: CipherText,
b: CipherText,
destination?: CipherText
): CipherText | void {
try {
if (destination) {
_instance.sub(a.instance, b.instance, destination.instance)
return
}
const temp = CipherText()
_instance.sub(a.instance, b.instance, temp.instance)
return temp
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Multiplies two CipherTexts. This functions computes the product of a
* and b and stores the result in the destination parameter. Dynamic
* memory allocations in the process are allocated from the memory pool pointed
* to by the given MemoryPoolHandle.
*
* @function
* @name Evaluator#multiply
* @param {CipherText} a CipherText operand A
* @param {CipherText} b CipherText operand B
* @param {CipherText} [destination] CipherText destination to store the product
* @param {MemoryPoolHandle} [pool={@link MemoryPoolHandle.global}] MemoryPool to use
* @returns {CipherText|void} CipherText containing the result or void if a destination was supplied
* @example
* const cipherTextA = seal.CipherText()
* const cipherTextB = seal.CipherText()
* // ... after encrypting some data ...
* const resultCipher = evaluator.multiply(cipherTextA, cipherTextB)
* // or
* const cipherDest = seal.CipherText()
* evaluator.multiply(cipherTextA, cipherTextB, cipherDest)
*/
multiply(
a: CipherText,
b: CipherText,
destination?: CipherText,
pool: MemoryPoolHandle = MemoryPoolHandle.global
): CipherText | void {
try {
if (destination) {
_instance.multiply(
a.instance,
b.instance,
destination.instance,
pool
)
return
}
const temp = CipherText()
_instance.multiply(a.instance, b.instance, temp.instance, pool)
return temp
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Squares a CipherText. This functions computes the square of encrypted and
* stores the result in the destination parameter. Dynamic memory allocations
* in the process are allocated from the memory pool pointed to by the given
* MemoryPoolHandle.
*
* @function
* @name Evaluator#square
* @param {CipherText} encrypted CipherText to square
* @param {CipherText} [destination] CipherText destination to store the squared result
* @param {MemoryPoolHandle} [pool={@link MemoryPoolHandle.global}] MemoryPool to use
* @returns {CipherText|void} CipherText containing the result or void if a destination was supplied
* @example
* const cipherTextA = seal.CipherText()
* // ... after encrypting some data ...
* const resultCipher = evaluator.square(cipherTextA, cipherTextB)
* // or
* const cipherDest = seal.CipherText()
* evaluator.square(cipherTextA, cipherDest)
*/
square(
encrypted: CipherText,
destination?: CipherText,
pool: MemoryPoolHandle = MemoryPoolHandle.global
): CipherText | void {
try {
if (destination) {
_instance.square(encrypted.instance, destination.instance, pool)
return
}
const temp = CipherText()
_instance.square(encrypted.instance, temp.instance, pool)
return temp
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Relinearizes a CipherText. This functions relinearizes encrypted, reducing
* its size down to 2, and stores the result in the destination parameter.
* If the size of encrypted is K+1, the given relinearization keys need to
* have size at least K-1. Dynamic memory allocations in the process are allocated
* from the memory pool pointed to by the given MemoryPoolHandle.
*
* @function
* @name Evaluator#relinearize
* @param {CipherText} encrypted CipherText to relinearize
* @param {RelinKeys} relinKeys RelinKey used to perform relinearization
* @param {CipherText} [destination] CipherText destination to store the relinearized result
* @param {MemoryPoolHandle} [pool={@link MemoryPoolHandle.global}] MemoryPool to use
* @returns {CipherText|void} CipherText containing the result or void if a destination was supplied
* @example
* const relinKeys = keyGenerator.createRelinKeys()
* const cipherTextA = seal.CipherText()
* // ... after encrypting some data ...
* const resultCipher = evaluator.relinearize(cipherTextA, relinKeys)
* // or
* const cipherDest = seal.CipherText()
* evaluator.relinearize(cipherTextA, relinKeys, cipherDest)
*/
relinearize(
encrypted: CipherText,
relinKeys: RelinKeys,
destination?: CipherText,
pool: MemoryPoolHandle = MemoryPoolHandle.global
): CipherText | void {
try {
if (destination) {
_instance.relinearize(
encrypted.instance,
relinKeys.instance,
destination.instance,
pool
)
return
}
const temp = CipherText()
_instance.relinearize(
encrypted.instance,
relinKeys.instance,
temp.instance,
pool
)
return temp
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Given a CipherText encrypted modulo q_1...q_k, this function switches the
* modulus down to q_1...q_{k-1} and stores the result in the destination
* parameter. Dynamic memory allocations in the process are allocated from
* the memory pool pointed to by the given MemoryPoolHandle.
*
* @function
* @name Evaluator#cipherModSwitchToNext
* @param {CipherText} encrypted CipherText to switch its modulus down
* @param {CipherText} [destination] CipherText destination to store the switched result
* @param {MemoryPoolHandle} [pool={@link MemoryPoolHandle.global}] MemoryPool to use
* @returns {CipherText|void} CipherText containing the result or void if a destination was supplied
* @example
* const cipherTextA = seal.CipherText()
* // ... after encrypting some data ...
* const resultCipher = evaluator.cipherModSwitchToNext(cipherTextA)
* // or
* const cipherDest = seal.CipherText()
* evaluator.cipherModSwitchToNext(cipherTextA, cipherDest)
*/
cipherModSwitchToNext(
encrypted: CipherText,
destination?: CipherText,
pool: MemoryPoolHandle = MemoryPoolHandle.global
): CipherText | void {
try {
if (destination) {
_instance.cipherModSwitchToNext(
encrypted.instance,
destination.instance,
pool
)
return
}
const temp = CipherText()
_instance.cipherModSwitchToNext(
encrypted.instance,
temp.instance,
pool
)
return temp
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Given a CipherText encrypted modulo q_1...q_k, this function switches the
* modulus down until the parameters reach the given parmsId and stores the
* result in the destination parameter. Dynamic memory allocations in the process
* are allocated from the memory pool pointed to by the given MemoryPoolHandle.
*
* @function
* @name Evaluator#cipherModSwitchTo
* @param {CipherText} encrypted CipherText to switch its modulus down
* @param {ParmsIdType} parmsId Target parmsId to switch to
* @param {CipherText} [destination] CipherText destination to store the switched result
* @param {MemoryPoolHandle} [pool={@link MemoryPoolHandle.global}] MemoryPool to use
* @returns {CipherText|void} CipherText containing the result or void if a destination was supplied
* @example
* const context = seal.Context(encParms, true)
* const cipherTextA = seal.CipherText()
* // ... after encrypting some data ...
* const parmsId = context.lastParmsId
* const resultCipher = evaluator.cipherModSwitchTo(cipherTextA, parmsId)
* // or
* const cipherDest = seal.CipherText()
* evaluator.cipherModSwitchTo(cipherTextA, parmsId, cipherDest)
*/
cipherModSwitchTo(
encrypted: CipherText,
parmsId: ParmsIdType,
destination?: CipherText,
pool: MemoryPoolHandle = MemoryPoolHandle.global
): CipherText | void {
try {
if (destination) {
_instance.cipherModSwitchTo(
encrypted.instance,
parmsId.instance,
destination.instance,
pool
)
return
}
const temp = CipherText()
_instance.cipherModSwitchTo(
encrypted.instance,
parmsId.instance,
temp.instance,
pool
)
return temp
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Modulus switches an NTT transformed PlainText from modulo q_1...q_k down
* to modulo q_1...q_{k-1} and stores the result in the destination parameter.
*
* @function
* @name Evaluator#plainModSwitchToNext
* @param {PlainText} plain PlainText to switch its modulus down
* @param {PlainText} [destination] PlainText destination to store the switched result
* @returns {PlainText|void} PlainText containing the result or void if a destination was supplied
* @example
* const plainTextA = seal.PlainText()
* // ... after encoding some data ...
* const resultCipher = evaluator.plainModSwitchToNext(plainTextA)
* // or
* const plainDest = seal.PlainText()
* evaluator.plainModSwitchToNext(plainTextA, plainDest)
*/
plainModSwitchToNext(
plain: PlainText,
destination?: PlainText
): PlainText | void {
try {
if (destination) {
_instance.plainModSwitchToNext(plain.instance, destination.instance)
return
}
const temp = PlainText()
_instance.plainModSwitchToNext(plain.instance, temp.instance)
return temp
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Given an NTT transformed PlainText modulo q_1...q_k, this function switches
* the modulus down until the parameters reach the given parmsId and stores
* the result in the destination parameter.
*
* @function
* @name Evaluator#plainModSwitchTo
* @param {PlainText} plain PlainText to switch its modulus down
* @param {ParmsIdType} parmsId Target parmsId to switch to
* @param {PlainText} [destination] PlainText destination to store the switched result
* @returns {PlainText|void} PlainText containing the result or void if a destination was supplied
* @example
* const context = seal.Context(encParms, true)
* const plainTextA = seal.PlainText()
* // ... after encoding some data ...
* const parmsId = context.lastParmsId
* const resultCipher = evaluator.plainModSwitchTo(plainTextA, parmsId)
* // or
* const plainDest = seal.PlainText()
* evaluator.plainModSwitchTo(plainTextA, parmsId, plainDest)
*/
plainModSwitchTo(
plain: PlainText,
parmsId: ParmsIdType,
destination?: PlainText
): PlainText | void {
try {
if (destination) {
_instance.plainModSwitchTo(
plain.instance,
parmsId.instance,
destination.instance
)
return
}
const temp = PlainText()
_instance.plainModSwitchTo(
plain.instance,
parmsId.instance,
temp.instance
)
return temp
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Given a CipherText encrypted modulo q_1...q_k, this function switches the
* modulus down to q_1...q_{k-1}, scales the message down accordingly, and
* stores the result in the destination parameter. Dynamic memory allocations
* in the process are allocated from the memory pool pointed to by the given
* MemoryPoolHandle.
*
* @function
* @name Evaluator#rescaleToNext
* @param {CipherText} encrypted CipherText to rescale
* @param {CipherText} [destination] CipherText destination to store the rescaled result
* @param {MemoryPoolHandle} [pool={@link MemoryPoolHandle.global}] MemoryPool to use
* @returns {CipherText|void} CipherText containing the result or void if a destination was supplied
* @example
* const cipherTextA = seal.CipherText()
* // ... after encrypting some data ...
* const resultCipher = evaluator.rescaleToNext(cipherTextA)
* // or
* const cipherDest = seal.CipherText()
* evaluator.rescaleToNext(cipherTextA, cipherDest)
*/
rescaleToNext(
encrypted: CipherText,
destination?: CipherText,
pool: MemoryPoolHandle = MemoryPoolHandle.global
): CipherText | void {
try {
if (destination) {
_instance.rescaleToNext(
encrypted.instance,
destination.instance,
pool
)
return
}
const temp = CipherText()
_instance.rescaleToNext(encrypted.instance, temp.instance, pool)
return temp
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Given a CipherText encrypted modulo q_1...q_k, this function switches the
* modulus down until the parameters reach the given parmsId, scales the message
* down accordingly, and stores the result in the destination parameter. Dynamic
* memory allocations in the process are allocated from the memory pool pointed
* to by the given MemoryPoolHandle.
*
* @function
* @name Evaluator#rescaleTo
* @param {CipherText} encrypted CipherText to rescale
* @param {ParmsIdType} parmsId Target parmsId to rescale to
* @param {CipherText} [destination] CipherText destination to store the rescaled result
* @param {MemoryPoolHandle} [pool={@link MemoryPoolHandle.global}] MemoryPool to use
* @returns {CipherText|void} CipherText containing the result or void if a destination was supplied
* @example
* const context = seal.Context(encParms, true)
* const cipherTextA = seal.CipherText()
* // ... after encrypting some data ...
* const parmsId = context.lastParmsId
* const resultCipher = evaluator.rescaleTo(cipherTextA, parmsId)
* // or
* const cipherDest = seal.CipherText()
* evaluator.rescaleTo(cipherTextA, parmsId, cipherDest)
*/
rescaleTo(
encrypted: CipherText,
parmsId: ParmsIdType,
destination?: CipherText,
pool: MemoryPoolHandle = MemoryPoolHandle.global
): CipherText | void {
try {
if (destination) {
_instance.rescaleTo(
encrypted.instance,
parmsId.instance,
destination.instance,
pool
)
return
}
const temp = CipherText()
_instance.rescaleTo(
encrypted.instance,
parmsId.instance,
temp.instance,
pool
)
return temp
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Given a ciphertext encrypted modulo q_1...q_k, this function switches
* the modulus down to q_1...q_{k-1}, scales the message down accordingly,
* and stores the result in the destination parameter. Dynamic memory
* allocations in the process are allocated from the memory pool pointed
* to by the given MemoryPoolHandle.
*
* @function
* @name Evaluator#modReduceToNext
* @param {CipherText} encrypted CipherText to reduce
* @param {CipherText} [destination] CipherText destination to store the
* reduced result
* @param {MemoryPoolHandle} [pool={@link MemoryPoolHandle.global}]
* MemoryPool to use
* @returns {CipherText|void} CipherText containing the result or void if
* a destination was supplied
* @example
* const cipherTextA = seal.CipherText()
* // ... after encrypting some data ...
* const resultCipher = evaluator.modReduceToNext(cipherTextA)
* // or
* const cipherDest = seal.CipherText()
* evaluator.modReduceToNext(cipherTextA, cipherDest)
*/
modReduceToNext(
encrypted: CipherText,
destination?: CipherText,
pool: MemoryPoolHandle = MemoryPoolHandle.global
): CipherText | void {
try {
if (destination) {
_instance.modReduceToNext(
encrypted.instance,
destination.instance,
pool
)
return
}
const temp = CipherText()
_instance.modReduceToNext(encrypted.instance, temp.instance, pool)
return temp
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Given a ciphertext encrypted modulo q_1...q_k, this function reduces
* the modulus down until the parameters reach the given parms_id and
* stores the result in the destination parameter. Dynamic memory
* allocations in the process are allocated from the memory pool pointed
* to by the given MemoryPoolHandle.
*
* @function
* @name Evaluator#modReduceTo
* @param {CipherText} encrypted CipherText to reduce
* @param {ParmsIdType} parmsId Target parmsId to reduce to
* @param {CipherText} [destination] CipherText destination to store the
* reduced result
* @param {MemoryPoolHandle} [pool={@link MemoryPoolHandle.global}]
* MemoryPool to use
* @returns {CipherText|void} CipherText containing the result or void if
* a destination was supplied
* @example
* const context = seal.Context(encParms, true)
* const cipherTextA = seal.CipherText()
* // ... after encrypting some data ...
* const parmsId = context.lastParmsId
* const resultCipher = evaluator.modReduceTo(cipherTextA, parmsId)
* // or
* const cipherDest = seal.CipherText()
* evaluator.modReduceTo(cipherTextA, parmsId, cipherDest)
*/
modReduceTo(
encrypted: CipherText,
parmsId: ParmsIdType,
destination?: CipherText,
pool: MemoryPoolHandle = MemoryPoolHandle.global
): CipherText | void {
try {
if (destination) {
_instance.modReduceTo(
encrypted.instance,
parmsId.instance,
destination.instance,
pool
)
return
}
const temp = CipherText()
_instance.modReduceTo(
encrypted.instance,
parmsId.instance,
temp.instance,
pool
)
return temp
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Exponentiates a CipherText. This functions raises encrypted to a power and
* stores the result in the destination parameter. Dynamic memory allocations
* in the process are allocated from the memory pool pointed to by the given
* MemoryPoolHandle. The exponentiation is done in a depth-optimal order, and
* relinearization is performed automatically after every multiplication in
* the process. In relinearization the given relinearization keys are used.
*
* @function
* @name Evaluator#exponentiate
* @param {CipherText} encrypted CipherText to exponentiate
* @param {number} exponent Positive integer to exponentiate the CipherText
* @param {RelinKeys} relinKeys RelinKeys used to perform relinearization after each exponentiation
* @param {CipherText} [destination] CipherText destination to store the exponentiated result
* @param {MemoryPoolHandle} [pool={@link MemoryPoolHandle.global}] MemoryPool to use
* @returns {CipherText|void} CipherText containing the result or void if a destination was supplied
* @example
* const relinKeys = keyGenerator.createRelinKeys()
* const cipherTextA = seal.CipherText()
* // ... after encrypting some data ...
* const resultCipher = evaluator.exponentiate(cipherTextA, 3, relinKeys)
* // or
* const cipherDest = seal.CipherText()
* evaluator.exponentiate(cipherTextA, 3, relinKeys, cipherDest)
*/
exponentiate(
encrypted: CipherText,
exponent: number,
relinKeys: RelinKeys,
destination?: CipherText,
pool: MemoryPoolHandle = MemoryPoolHandle.global
): CipherText | void {
try {
if (destination) {
_instance.exponentiate(
encrypted.instance,
exponent,
relinKeys.instance,
destination.instance,
pool
)
return
}
const temp = CipherText()
_instance.exponentiate(
encrypted.instance,
exponent,
relinKeys.instance,
temp.instance,
pool
)
return temp
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Adds a CipherText and a PlainText. This function adds a CipherText and
* a PlainText and stores the result in the destination parameter. The PlainText
* must be valid for the current encryption parameters.
*
* @function
* @name Evaluator#addPlain
* @param {CipherText} encrypted CipherText operand A
* @param {PlainText} plain PlainText operand B
* @param {CipherText} [destination] CipherText destination to store the sum
* @param {MemoryPoolHandle} [pool={@link MemoryPoolHandle.global}] MemoryPool to use
* @returns {CipherText|void} CipherText containing the result or void if a destination was supplied
* @example
* const cipherTextA = seal.CipherText()
* const plainTextB = seal.PlainText()
* // ... after encrypting/encoding some data ...
* const resultCipher = evaluator.addPlain(cipherTextA, plainTextB)
* // or
* const cipherDest = seal.CipherText()
* evaluator.addPlain(cipherTextA, plainTextB, cipherDest)
*/
addPlain(
encrypted: CipherText,
plain: PlainText,
destination?: CipherText,
pool: MemoryPoolHandle = MemoryPoolHandle.global
): CipherText | void {
try {
if (destination) {
_instance.addPlain(
encrypted.instance,
plain.instance,
destination.instance,
pool
)
return
}
const temp = CipherText()
_instance.addPlain(
encrypted.instance,
plain.instance,
temp.instance,
pool
)
return temp
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Subtracts a PlainText from a CipherText. This function subtracts a PlainText
* from a CipherText and stores the result in the destination parameter. The
* PlainText must be valid for the current encryption parameters.
*
* @function
* @name Evaluator#subPlain
* @param {CipherText} encrypted CipherText operand A
* @param {PlainText} plain PlainText operand B
* @param {CipherText} [destination] CipherText destination to store the difference
* @param {MemoryPoolHandle} [pool={@link MemoryPoolHandle.global}] MemoryPool to use
* @returns {CipherText|void} CipherText containing the result or void if a destination was supplied
* @example
* const cipherTextA = seal.CipherText()
* const plainTextB = seal.PlainText()
* // ... after encrypting/encoding some data ...
* const resultCipher = evaluator.subPlain(cipherTextA, plainTextB)
* // or
* const cipherDest = seal.CipherText()
* evaluator.subPlain(cipherTextA, plainTextB, cipherDest)
*/
subPlain(
encrypted: CipherText,
plain: PlainText,
destination?: CipherText,
pool: MemoryPoolHandle = MemoryPoolHandle.global
): CipherText | void {
try {
if (destination) {
_instance.subPlain(
encrypted.instance,
plain.instance,
destination.instance,
pool
)
return
}
const temp = CipherText()
_instance.subPlain(
encrypted.instance,
plain.instance,
temp.instance,
pool
)
return temp
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Multiplies a CipherText with a PlainText. This function multiplies
* a CipherText with a PlainText and stores the result in the destination
* parameter. The PlainText must be a valid for the current encryption parameters,
* and cannot be identially 0. Dynamic memory allocations in the process are
* allocated from the memory pool pointed to by the given MemoryPoolHandle.
*
* @function
* @name Evaluator#multiplyPlain
* @param {CipherText} encrypted CipherText operand A
* @param {PlainText} plain PlainText operand B
* @param {CipherText} [destination] CipherText destination to store the product
* @param {MemoryPoolHandle} [pool={@link MemoryPoolHandle.global}] MemoryPool to use
* @returns {CipherText?} CipherText containing the result or void if a destination was supplied
* @example
* const cipherTextA = seal.CipherText()
* const plainTextB = seal.PlainText()
* // ... after encrypting/encoding some data ...
* const resultCipher = evaluator.multiplyPlain(cipherTextA, plainTextB)
* // or
* const cipherDest = seal.CipherText()
* evaluator.multiplyPlain(cipherTextA, plainTextB, cipherDest)
*/
multiplyPlain(
encrypted: CipherText,
plain: PlainText,
destination?: CipherText,
pool: MemoryPoolHandle = MemoryPoolHandle.global
): CipherText | void {
try {
if (destination) {
_instance.multiplyPlain(
encrypted.instance,
plain.instance,
destination.instance,
pool
)
return
}
const temp = CipherText()
_instance.multiplyPlain(
encrypted.instance,
plain.instance,
temp.instance,
pool
)
return temp
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Transforms a PlainText to NTT domain. This functions applies the number
* Theoretic Transform to a PlainText by first embedding integers modulo the
* PlainText modulus to integers modulo the coefficient modulus and then
* performing David Harvey's NTT on the resulting polynomial. The transformation
* is done with respect to encryption parameters corresponding to a given
* parmsId. The result is stored in the destinationNtt parameter. For the
* operation to be valid, the PlainText must have degree less than PolyModulusDegree
* and each coefficient must be less than the PlainText modulus, i.e., the PlainText
* must be a valid PlainText under the current encryption parameters. Dynamic
* memory allocations in the process are allocated from the memory pool pointed
* to by the given MemoryPoolHandle.
*
* @function
* @name Evaluator#plainTransformToNtt
* @param {PlainText} plain PlainText to transform
* @param {ParmsIdType} parmsId target parmsId to perform NTT transformation
* @param {PlainText} [destinationNtt] PlainText destination to store the transformed result
* @param {MemoryPoolHandle} [pool={@link MemoryPoolHandle.global}] MemoryPool to use
* @returns {PlainText|void} PlainText containing the result or void if a destination was supplied
* @example
* const context = seal.Context(encParms, true)
* const plainTextA = seal.PlainText()
* // ... after encoding some data ...
* const parmsId = context.lastParmsId
* const resultCipher = evaluator.plainTransformToNtt(plainTextA, parmsId)
* // or
* const plainDest = seal.PlainText()
* evaluator.plainTransformToNtt(plainTextA, parmsId, plainDest)
*/
plainTransformToNtt(
plain: PlainText,
parmsId: ParmsIdType,
destinationNtt?: PlainText,
pool: MemoryPoolHandle = MemoryPoolHandle.global
): PlainText | void {
try {
if (destinationNtt) {
_instance.plainTransformToNtt(
plain.instance,
parmsId.instance,
destinationNtt.instance,
pool
)
return
}
const temp = PlainText()
_instance.plainTransformToNtt(
plain.instance,
parmsId.instance,
temp.instance,
pool
)
return temp
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Transforms a CipherText to NTT domain. This functions applies David Harvey's
* number Theoretic Transform separately to each polynomial of a CipherText.
* The result is stored in the destinationNtt parameter.
*
* @function
* @name Evaluator#cipherTransformToNtt
* @param {CipherText} encrypted CipherText to transform
* @param {CipherText} [destinationNtt] CipherText destination to store the transformed result
* @returns {CipherText|void} CipherText containing the result or void if a destination was supplied
* @example
* const cipherTextA = seal.CipherText()
* // ... after encrypting some data ...
* const resultCipher = evaluator.cipherTransformToNtt(cipherTextA)
* // or
* const cipherDest = seal.CipherText()
* evaluator.cipherTransformToNtt(cipherTextA, cipherDest)
*/
cipherTransformToNtt(
encrypted: CipherText,
destinationNtt?: CipherText
): CipherText | void {
try {
if (destinationNtt) {
_instance.cipherTransformToNtt(
encrypted.instance,
destinationNtt.instance
)
return
}
const temp = CipherText()
_instance.cipherTransformToNtt(encrypted.instance, temp.instance)
return temp
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Transforms a CipherText back from NTT domain. This functions applies the
* inverse of David Harvey's number Theoretic Transform separately to each
* polynomial of a CipherText. The result is stored in the destination parameter.
*
* @function
* @name Evaluator#cipherTransformFromNtt
* @param {CipherText} encryptedNtt CipherText to transform
* @param {CipherText} [destination] CipherText destination to store the transformed result
* @returns {CipherText|void} CipherText containing the result or void if a destination was supplied
* @example
* // ... after cipherTransformToNtt ...
* const resultCipher = evaluator.cipherTransformFromNtt(cipherTextANtt)
* // or
* const cipherDest = seal.CipherText()
* evaluator.cipherTransformFromNtt(cipherTextANtt, cipherDest)
*/
cipherTransformFromNtt(
encryptedNtt: CipherText,
destination?: CipherText
): CipherText | void {
try {
if (destination) {
_instance.cipherTransformFromNtt(
encryptedNtt.instance,
destination.instance
)
return
}
const temp = CipherText()
_instance.cipherTransformFromNtt(encryptedNtt.instance, temp.instance)
return temp
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Applies a Galois automorphism to a CipherText and writes the result to the
* destination parameter. To evaluate the Galois automorphism, an appropriate
* set of Galois keys must also be provided. Dynamic memory allocations in
* the process are allocated from the memory pool pointed to by the given
* MemoryPoolHandle.
*
* The desired Galois automorphism is given as a Galois element, and must be
* an odd integer in the interval [1, M-1], where M = 2*N, and N = degree(poly_modulus).
* Used with batching, a Galois element 3^i % M corresponds to a cyclic row
* rotation i steps to the left, and a Galois element 3^(N/2-i) % M corresponds
* to a cyclic row rotation i steps to the right. The Galois element M-1 corresponds
* to a column rotation (row swap) in BFV, and complex conjugation in CKKS.
* In the polynomial view (not batching), a Galois automorphism by a Galois
* element p changes Enc(plain(x)) to Enc(plain(x^p)).
*
* @function
* @name Evaluator#applyGalois
* @param {CipherText} encrypted CipherText to apply the automorphism
* @param {number} galoisElt number representing the Galois element
* @param {GaloisKeys} galoisKeys GaloisKeys used to perform rotations
* @param {CipherText} [destination] CipherText destination to store the result
* @param {MemoryPoolHandle} [pool={@link MemoryPoolHandle.global}] MemoryPool to use
* @returns {CipherText|void} CipherText containing the result or void if a destination was supplied
* @example
* ...
* const evaluator = seal.Evaluator(context)
* const arr = Int32Array.from({ length: encoder.slotCount }, (_, i) => i)
* const plain = encoder.encode(arr)
* const cipher = encryptor.encrypt(plain)
* const cipherDest = seal.CipherText()
* const galElt = 2 * parms.polyModulusDegree - 1
* evaluator.applyGalois(cipher, galElt, galoisKeys, cipherDest)
*/
applyGalois(
encrypted: CipherText,
galoisElt: number,
galoisKeys: GaloisKeys,
destination?: CipherText,
pool: MemoryPoolHandle = MemoryPoolHandle.global
): CipherText | void {
try {
if (destination) {
_instance.applyGalois(
encrypted.instance,
galoisElt,
galoisKeys.instance,
destination.instance,
pool
)
return
}
const temp = CipherText()
_instance.applyGalois(
encrypted.instance,
galoisElt,
galoisKeys.instance,
temp.instance,
pool
)
return temp
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Rotates PlainText matrix rows cyclically. When batching is used with the
* BFV/BGV scheme, this function rotates the encrypted PlainText matrix rows
* cyclically to the left (steps > 0) or to the right (steps < 0) and writes
* the result to the destination parameter. Since the size of the batched
* matrix is 2-by-(N/2), where N is the degree of the polynomial modulus,
* the number of steps to rotate must have absolute value at most N/2-1. Dynamic
* memory allocations in the process are allocated from the memory pool pointed
* to by the given MemoryPoolHandle.
*
* @function
* @name Evaluator#rotateRows
* @param {CipherText} encrypted CipherText to rotate rows
* @param {number} steps Int representing steps to rotate (negative = right, positive = left)
* @param {GaloisKeys} galoisKeys GaloisKeys used to perform rotations
* @param {CipherText} [destination] CipherText destination to store the rotated result
* @param {MemoryPoolHandle} [pool={@link MemoryPoolHandle.global}] MemoryPool to use
* @returns {CipherText|void} CipherText containing the result or void if a destination was supplied
* @example
* const galoisKeys = keyGenerator.createGaloisKeys()
* const cipherTextA = seal.CipherText()
* // ... after encrypting some data ...
* const resultCipher = evaluator.rotateRows(cipherTextA, 3, galoisKeys)
* // or
* const cipherDest = seal.CipherText()
* evaluator.rotateRows(cipherTextA, 3, galoisKeys, cipherDest)
*/
rotateRows(
encrypted: CipherText,
steps: number,
galoisKeys: GaloisKeys,
destination?: CipherText,
pool: MemoryPoolHandle = MemoryPoolHandle.global
): CipherText | void {
try {
if (destination) {
_instance.rotateRows(
encrypted.instance,
steps,
galoisKeys.instance,
destination.instance,
pool
)
return
}
const temp = CipherText()
_instance.rotateRows(
encrypted.instance,
steps,
galoisKeys.instance,
temp.instance,
pool
)
return temp
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Rotates PlainText matrix columns cyclically. When batching is used with
* the BFV scheme, this function rotates the encrypted PlainText matrix columns
* cyclically, and writes the result to the destination parameter. Since the
* size of the batched matrix is 2-by-(N/2), where N is the degree of the
* polynomial modulus, this means simply swapping the two rows. Dynamic memory
* allocations in the process are allocated from the memory pool pointed to
* by the given MemoryPoolHandle.
*
* @function
* @name Evaluator#rotateColumns
* @param {CipherText} encrypted CipherText to rotate columns
* @param {GaloisKeys} galoisKeys GaloisKeys used to perform rotations
* @param {CipherText} [destination] CipherText destination to store the rotated result
* @param {MemoryPoolHandle} [pool={@link MemoryPoolHandle.global}] MemoryPool to use
* @returns {CipherText|void} CipherText containing the result or void if a destination was supplied
* @example
* const galoisKeys = keyGenerator.createGaloisKeys()
* const cipherTextA = seal.CipherText()
* // ... after encrypting some data ...
* const resultCipher = evaluator.rotateColumns(cipherTextA, galoisKeys)
* // or
* const cipherDest = seal.CipherText()
* evaluator.rotateColumns(cipherTextA, galoisKeys, cipherDest)
*/
rotateColumns(
encrypted: CipherText,
galoisKeys: GaloisKeys,
destination?: CipherText,
pool: MemoryPoolHandle = MemoryPoolHandle.global
): CipherText | void {
try {
if (destination) {
_instance.rotateColumns(
encrypted.instance,
galoisKeys.instance,
destination.instance,
pool
)
return
}
const temp = CipherText()
_instance.rotateColumns(
encrypted.instance,
galoisKeys.instance,
temp.instance,
pool
)
return temp
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Rotates PlainText vector cyclically. When using the CKKS scheme, this function
* rotates the encrypted PlainText vector cyclically to the left (steps > 0)
* or to the right (steps < 0) and writes the result to the destination parameter.
* Since the size of the batched matrix is 2-by-(N/2), where N is the degree
* of the polynomial modulus, the number of steps to rotate must have absolute
* value at most N/2-1. Dynamic memory allocations in the process are allocated
* from the memory pool pointed to by the given MemoryPoolHandle.
*
* @function
* @name Evaluator#rotateVector
* @param {CipherText} encrypted CipherText to rotate the entire vector
* @param {number} steps Int representing steps to rotate (negative = right, positive = left)
* @param {GaloisKeys} galoisKeys GaloisKeys used to perform rotations
* @param {CipherText} [destination] CipherText destination to store the rotated result
* @param {MemoryPoolHandle} [pool={@link MemoryPoolHandle.global}] MemoryPool to use
* @returns {CipherText|void} CipherText containing the result or void if a destination was supplied
* @example
* const galoisKeys = keyGenerator.createGaloisKeys()
* const cipherTextA = seal.CipherText()
* // ... after encrypting some data ...
* const resultCipher = evaluator.rotateVector(cipherTextA, 3, galoisKeys)
* // or
* const cipherDest = seal.CipherText()
* evaluator.rotateVector(cipherTextA, 3, galoisKeys, cipherDest)
*/
rotateVector(
encrypted: CipherText,
steps: number,
galoisKeys: GaloisKeys,
destination?: CipherText,
pool: MemoryPoolHandle = MemoryPoolHandle.global
): CipherText | void {
try {
if (destination) {
_instance.rotateVector(
encrypted.instance,
steps,
galoisKeys.instance,
destination.instance,
pool
)
return
}
const temp = CipherText()
_instance.rotateVector(
encrypted.instance,
steps,
galoisKeys.instance,
temp.instance,
pool
)
return temp
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Complex conjugates PlainText slot values. When using the CKKS scheme, this
* function complex conjugates all values in the underlying PlainText, and
* writes the result to the destination parameter. Dynamic memory allocations
* in the process are allocated from the memory pool pointed to by the given
* MemoryPoolHandle.
*
* @function
* @name Evaluator#complexConjugate
* @param {CipherText} encrypted CipherText to complex conjugate
* @param {GaloisKeys} galoisKeys GaloisKeys used to perform rotations
* @param {CipherText} [destination] CipherText destination to store the conjugated result
* @param {MemoryPoolHandle} [pool={@link MemoryPoolHandle.global}] MemoryPool to use
* @returns {CipherText|void} CipherText containing the result or void if a destination was supplied
* @example
* const galoisKeys = keyGenerator.createGaloisKeys()
* const cipherTextA = seal.CipherText()
* // ... after encrypting some data ...
* const resultCipher = evaluator.complexConjugate(cipherTextA, galoisKeys)
* // or
* const cipherDest = seal.CipherText()
* evaluator.complexConjugate(cipherTextA, galoisKeys, cipherDest)
*/
complexConjugate(
encrypted: CipherText,
galoisKeys: GaloisKeys,
destination?: CipherText,
pool: MemoryPoolHandle = MemoryPoolHandle.global
): CipherText | void {
try {
if (destination) {
_instance.complexConjugate(
encrypted.instance,
galoisKeys.instance,
destination.instance,
pool
)
return
}
const temp = CipherText()
_instance.complexConjugate(
encrypted.instance,
galoisKeys.instance,
temp.instance,
pool
)
return temp
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Sum all elements in the encrypted CipherText. The resulting CipherText contains the sum in every element.
*
* @function
* @name Evaluator#sumElements
* @param {CipherText} encrypted CipherText to sum elements
* @param {GaloisKeys} galoisKeys GaloisKeys used to perform rotations
* @param {SchemeType} scheme Scheme that was used for encryption
* @param {CipherText} [destination] CipherText destination to store the result
* @param {MemoryPoolHandle} [pool={@link MemoryPoolHandle.global}] MemoryPool to use
* @returns {CipherText|void} CipherText containing the result or void if a destination was supplied
* @example
* const galoisKeys = keyGenerator.createGaloisKeys()
* const cipherTextA = seal.CipherText()
* // ... after encrypting some data ...
* const resultCipher = evaluator.sumElements(cipherTextA, galoisKeys, seal.SchemeTypes.BFV)
* // or
* const cipherDest = seal.CipherText()
* evaluator.sumElements(cipherTextA, galoisKeys, seal.SchemeTypes.BFV, cipherDest)
*/
sumElements(
encrypted: CipherText,
galoisKeys: GaloisKeys,
scheme: SchemeType,
destination?: CipherText,
pool: MemoryPoolHandle = MemoryPoolHandle.global
): CipherText | void {
try {
if (destination) {
_instance.sumElements(
encrypted.instance,
galoisKeys.instance,
scheme,
destination.instance,
pool
)
return
}
const newDest = CipherText()
_instance.sumElements(
encrypted.instance,
galoisKeys.instance,
scheme,
newDest.instance,
pool
)
return newDest
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Perform the dot product (A.B) of two CipherTexts The resulting CipherText contains the dot product in every
* element.
*
* @function
* @name Evaluator#dotProduct
* @param {CipherText} a CipherText operand A
* @param {CipherText} b CipherText operand B
* @param {RelinKeys} relinKeys RelinKeys used to perform relinearization after multiplication
* @param {GaloisKeys} galoisKeys GaloisKeys used to perform rotations
* @param {SchemeType} scheme Scheme that was used for encryption
* @param {CipherText} [destination] CipherText destination to store the result
* @param {MemoryPoolHandle} [pool={@link MemoryPoolHandle.global}] MemoryPool to use
* @returns {CipherText|void} CipherText containing the result or void if a destination was supplied
* @example
* const relinKeys = keyGenerator.createRelinKeys()
* const galoisKeys = keyGenerator.createGaloisKeys()
* const cipherTextA = seal.CipherText()
* const cipherTextB = seal.CipherText()
* // ... after encrypting some data ...
* const resultCipher = evaluator.dotProduct(cipherTextA, cipherTextB, relinKeys, galoisKeys, seal.SchemeTypes.BFV)
* // or
* const cipherDest = seal.CipherText()
* evaluator.dotProduct(cipherTextA, cipherTextB, relinKeys, galoisKeys, seal.SchemeTypes.BFV, cipherDest)
*/
dotProduct(
a: CipherText,
b: CipherText,
relinKeys: RelinKeys,
galoisKeys: GaloisKeys,
scheme: SchemeType,
destination?: CipherText,
pool: MemoryPoolHandle = MemoryPoolHandle.global
): CipherText | void {
try {
if (destination) {
_instance.multiply(
a.instance,
b.instance,
destination.instance,
pool
)
_instance.relinearize(
destination.instance,
relinKeys.instance,
destination.instance,
pool
)
_instance.sumElements(
destination.instance,
galoisKeys.instance,
scheme,
destination.instance,
pool
)
return
}
const newDest = CipherText()
_instance.multiply(a.instance, b.instance, newDest.instance, pool)
_instance.relinearize(
newDest.instance,
relinKeys.instance,
newDest.instance,
pool
)
_instance.sumElements(
newDest.instance,
galoisKeys.instance,
scheme,
newDest.instance,
pool
)
return newDest
} catch (e) {
throw Exception.safe(e as SealError)
}
},
/**
* Perform the dot product (A.B) of CipherText (A) and PlainText (B). The resulting CipherText contains the dot
* product in every element.
*
* @function
* @name Evaluator#dotProductPlain
* @param {CipherText} a CipherText operand A
* @param {PlainText} b PlainText operand B
* @param {GaloisKeys} galoisKeys GaloisKeys used to perform rotations
* @param {SchemeType} scheme Scheme that was used for encryption
* @param {CipherText} [destination] CipherText destination to store the result
* @param {MemoryPoolHandle} [pool={@link MemoryPoolHandle.global}] MemoryPool to use
* @returns {CipherText|void} CipherText containing the result or void if a destination was supplied
* @example
* const galoisKeys = keyGenerator.createGaloisKeys()
* const cipherTextA = seal.CipherText()
* const plainTextB = seal.PlainText()
* // ... after encoding / encrypting some data ...
* const resultCipher = evaluator.dotProductPlain(cipherTextA, plainTextB, galoisKeys, seal.SchemeTypes.BFV)
* // or
* const cipherDest = seal.CipherText()
* evaluator.dotProductPlain(cipherTextA, plainTextB, galoisKeys, seal.SchemeTypes.BFV, cipherDest)
*/
dotProductPlain(
a: CipherText,
b: PlainText,
galoisKeys: GaloisKeys,
scheme: SchemeType,
destination?: CipherText,
pool: MemoryPoolHandle = MemoryPoolHandle.global
): CipherText | void {
try {
if (destination) {
_instance.multiplyPlain(
a.instance,
b.instance,
destination.instance,
pool
)
_instance.sumElements(
destination.instance,
galoisKeys.instance,
scheme,
destination.instance,
pool
)
return
}
const newDest = CipherText()
_instance.multiplyPlain(
a.instance,
b.instance,
newDest.instance,
pool
)
_instance.sumElements(
newDest.instance,
galoisKeys.instance,
scheme,
newDest.instance,
pool
)
return newDest
} catch (e) {
throw Exception.safe(e as SealError)
}
}
}
}
export const EvaluatorInit = ({
loader
}: LoaderOptions): EvaluatorDependencies => {
const library: Library = loader.library
return EvaluatorConstructor(library)
}
Source