fix(compiler/TFHE): Introduce bootstrap and keyswitch at the TFHE level

This commit is contained in:
Quentin Bourgerie
2022-04-06 15:15:20 +02:00
parent 7cc0c01326
commit 35d8489b9c
29 changed files with 362 additions and 468 deletions

View File

@@ -66,36 +66,6 @@ mlir::Value createGLWEOpFromFHE(mlir::PatternRewriter &rewriter,
return op.getODSResults(0).front();
}
mlir::Value createApplyLookupTableGLWEOpFromFHE(mlir::PatternRewriter &rewriter,
mlir::Location loc,
mlir::Value arg0,
mlir::Value arg1,
mlir::OpResult result) {
mlir::SmallVector<mlir::Value, 2> args{arg0, arg1};
auto context = rewriter.getContext();
auto unset = mlir::IntegerAttr::get(IntegerType::get(context, 32), -1);
mlir::SmallVector<mlir::NamedAttribute, 6> attrs{
mlir::NamedAttribute(mlir::Identifier::get("glweDimension", context),
unset),
mlir::NamedAttribute(mlir::Identifier::get("polynomialSize", context),
unset),
mlir::NamedAttribute(mlir::Identifier::get("levelKS", context), unset),
mlir::NamedAttribute(mlir::Identifier::get("baseLogKS", context), unset),
mlir::NamedAttribute(mlir::Identifier::get("levelBS", context), unset),
mlir::NamedAttribute(mlir::Identifier::get("baseLogBS", context), unset),
mlir::NamedAttribute(mlir::Identifier::get("outputSizeKS", context),
unset),
};
auto eint =
result.getType().cast<mlir::concretelang::FHE::EncryptedIntegerType>();
mlir::SmallVector<mlir::Type, 1> resTypes{
convertTypeEncryptedIntegerToGLWE(rewriter.getContext(), eint)};
auto op = rewriter.create<concretelang::TFHE::ApplyLookupTable>(loc, resTypes,
args, attrs);
return op.getODSResults(0).front();
}
} // namespace concretelang
} // namespace mlir

View File

@@ -41,10 +41,4 @@ def MulEintIntPattern : Pat<
(MulEintIntOp:$result $arg0, $arg1),
(createMulGLWEIntOp $arg0, $arg1, $result)>;
def createApplyLookupTableGLWEOp : NativeCodeCall<"mlir::concretelang::createApplyLookupTableGLWEOpFromFHE($_builder, $_loc, $0, $1, $2)">;
def ApplyLookupTableEintPattern : Pat<
(ApplyLookupTableEintOp:$result $arg0, $arg1),
(createApplyLookupTableGLWEOp $arg0, $arg1, $result)>;
#endif

View File

@@ -184,110 +184,6 @@ mlir::Value createMulClearLweCiphertext(mlir::PatternRewriter &rewriter,
return op.getODSResults(0).front();
}
// This is the rewritting of the FHE::ApplyLookupTable operation, it will be
// rewritten as 3 new operations:
// - Create the required GLWE ciphertext out of the plain lookup table
// - Keyswitch the input ciphertext to match the input key of the bootstrapping
// - Bootstrap the keyswitched ciphertext with the constructed GLWE ciphertext
// Example:
// from:
// ```
// "%result = TFHE.apply_lookup_table"(% arg0, % tlu){
// glweDimension = 1 : i32,
// polynomialSize = 2048 : i32,
// levelKS = 3 : i32,
// baseLogKS = 2 : i32,
// levelBS = 5 : i32,
// baseLogBS = 4 : i32,
// outputSizeKS = 600 : i32
// } : (!TFHE.glwe<{2048, 1, 64} {4}>, tensor<16xi4>)
// ->(!TFHE.glwe<{2048, 1, 64} {4}>)
// ```
// to:
// ```
// % accumulator =
// "Concrete.glwe_from_table"(
// % [[TABLE]]){glweDimension = 1 : i32, p = 4 : i32, polynomialSize =
// 2048 : i32}
// : (tensor<16xi4>)
// ->!Concrete.glwe_ciphertext<2048, 1, 4>
// % keyswitched = "Concrete.keyswitch_lwe"(% arg0){
// baseLog = 2 : i32,
// level = 3 : i32
// } : (!Concrete.lwe_ciphertext<2048, 4>)
// ->!Concrete.lwe_ciphertext<600, 4>
// % result = "Concrete.bootstrap_lwe"(% keyswitched, % accumulator){
// baseLog = 4 : i32,
// glweDimension = 1 : i32,
// level = 5 : i32,
// polynomialSize = 2048 : i32
// } : (!Concrete.lwe_ciphertext<600, 4>, !Concrete.glwe_ciphertext<2048, 1, 4>)
// ->!Concrete.lwe_ciphertext<2048, 4>
// ```
mlir::Value createPBS(mlir::PatternRewriter &rewriter, mlir::Location loc,
mlir::Value ct, mlir::Value table,
mlir::IntegerAttr glweDimension,
mlir::IntegerAttr polynomialSize,
mlir::IntegerAttr levelKS, mlir::IntegerAttr baseLogKS,
mlir::IntegerAttr levelBS, mlir::IntegerAttr baseLogBS,
mlir::IntegerAttr outputDimensionKS,
mlir::OpResult result) {
// convert result type
LweCiphertextType lwe_type =
convertTypeToLWE(rewriter.getContext(), result.getType());
// fill the the table in the GLWE accumulator
mlir::IntegerAttr precision = rewriter.getI32IntegerAttr(lwe_type.getP());
mlir::Value accumulator =
rewriter
.create<mlir::concretelang::Concrete::GlweFromTable>(
loc,
Concrete::GlweCiphertextType::get(
rewriter.getContext(), polynomialSize.getInt(),
glweDimension.getInt(), lwe_type.getP()),
table)
.result();
// keyswitch
mlir::SmallVector<mlir::Value> ksArgs{ct};
mlir::SmallVector<mlir::NamedAttribute> ksAttrs{
mlir::NamedAttribute(
mlir::Identifier::get("level", rewriter.getContext()), levelKS),
mlir::NamedAttribute(
mlir::Identifier::get("baseLog", rewriter.getContext()), baseLogKS),
};
// convert result type
LweCiphertextType ksOutType = LweCiphertextType::get(
rewriter.getContext(), outputDimensionKS.getInt(), precision.getInt());
convertTypeToLWE(rewriter.getContext(), result.getType());
mlir::Value keyswitched =
rewriter
.create<mlir::concretelang::Concrete::KeySwitchLweOp>(loc, ksOutType,
ksArgs, ksAttrs)
.result();
// bootstrap operation
mlir::SmallVector<mlir::Value> bsArgs{keyswitched, accumulator};
mlir::SmallVector<mlir::NamedAttribute> bsAttrs{
mlir::NamedAttribute(
mlir::Identifier::get("glweDimension", rewriter.getContext()),
glweDimension),
mlir::NamedAttribute(
mlir::Identifier::get("polynomialSize", rewriter.getContext()),
polynomialSize),
mlir::NamedAttribute(
mlir::Identifier::get("level", rewriter.getContext()), levelBS),
mlir::NamedAttribute(
mlir::Identifier::get("baseLog", rewriter.getContext()), baseLogBS),
};
mlir::Value bootstrapped =
rewriter
.create<mlir::concretelang::Concrete::BootstrapLweOp>(loc, lwe_type,
bsArgs, bsAttrs)
.result();
return bootstrapped;
}
} // namespace concretelang
} // namespace mlir

View File

@@ -42,10 +42,4 @@ def NegGLWEPattern : Pat<
(NegGLWEOp:$result $arg0),
(createNegLweOp $arg0, $result)>;
def createPBS : NativeCodeCall<"mlir::concretelang::createPBS($_builder, $_loc, $0, $1, $2, $3, $4, $5, $6, $7, $8, $9)">;
def ApplyLookupTableGLWEPattern : Pat<
(ApplyLookupTable:$result $ct, $table, $glweDimension, $polynomialSize, $levelKS, $baseLogKS, $levelBS, $baseLogBS, $outputDimensionKS),
(createPBS $ct, $table, $glweDimension, $polynomialSize, $levelKS, $baseLogKS, $levelBS, $baseLogBS, $outputDimensionKS, $result)>;
#endif

View File

@@ -68,8 +68,8 @@ struct GenericTypeAndOpConverterPattern : public mlir::OpRewritePattern<OldOp> {
resultTypes[i] = converter.convertType(result.getType());
}
}
rewriter.replaceOpWithNewOp<NewOp>(oldOp, resultTypes,
oldOp->getOperands());
rewriter.replaceOpWithNewOp<NewOp>(oldOp, resultTypes, oldOp->getOperands(),
oldOp->getAttrs());
return mlir::success();
}

View File

@@ -62,9 +62,7 @@ def GlweFromTable : Concrete_Op<"glwe_from_table"> {
def BootstrapLweOp : Concrete_Op<"bootstrap_lwe"> {
let summary = "Bootstraps a LWE ciphertext with a GLWE trivial encryption of the lookup table";
let arguments = (ins
// LweBootstrapKeyType:$bootstrap_key,
LweCiphertextType:$input_ciphertext,
GlweCiphertextType:$accumulator,
I32Attr:$glweDimension,
@@ -79,7 +77,6 @@ def KeySwitchLweOp : Concrete_Op<"keyswitch_lwe"> {
let summary = "Keyswitches a LWE ciphertext";
let arguments = (ins
// LweKeySwitchKeyType:$keyswitch_key,
LweCiphertextType:$ciphertext,
I32Attr:$level,
I32Attr:$baseLog

View File

@@ -88,23 +88,37 @@ def MulGLWEIntOp : TFHE_Op<"mul_glwe_int"> {
}];
}
def KeySwitchGLWEOp : TFHE_Op<"keyswitch_glwe"> {
let summary = "Change the encryption parameters of a glwe ciphertext by applying a keyswitch";
let arguments = (ins
GLWECipherTextType:$ciphertext,
I32Attr:$level,
I32Attr:$baseLog
);
def ApplyLookupTable : TFHE_Op<"apply_lookup_table"> {
let summary = "Applies a lookup table to a GLWE ciphertext";
let results = (outs GLWECipherTextType:$result);
}
let arguments = (ins GLWECipherTextType:$ct,
TensorOf<[AnyInteger]>:$l_cst,
I32Attr:$glweDimension, I32Attr:$polynomialSize,
I32Attr:$levelKS, I32Attr:$baseLogKS,
I32Attr:$levelBS, I32Attr:$baseLogBS,
I32Attr:$outputSizeKS);
let results = (outs GLWECipherTextType);
def GLWEFromTableOp : TFHE_Op<"glwe_from_table"> {
let summary = "Creates a GLWE ciphertext which is the trivial encrytion of a the input table interpreted as a polynomial (to use later in a bootstrap)";
let verifier = [{
return ::mlir::concretelang::TFHE::verifyApplyLookupTable(*this);
}];
let arguments = (ins 1DTensorOf<[I64]>:$table);
let results = (outs GLWECipherTextType:$result);
}
def BootstrapGLWEOp : TFHE_Op<"bootstrap_glwe"> {
let summary = "Programmable bootstraping of a GLWE ciphertext with a lookup table";
let arguments = (ins
GLWECipherTextType:$ciphertext,
GLWECipherTextType:$lookup_table,
I32Attr:$glweDimension,
I32Attr:$polynomialSize,
I32Attr:$level,
I32Attr:$baseLog
);
let results = (outs GLWECipherTextType: $result);
}
#endif

View File

@@ -18,6 +18,9 @@
#include "concretelang/Dialect/TFHE/IR/TFHEDialect.h"
#include "concretelang/Dialect/TFHE/IR/TFHETypes.h"
namespace FHE = mlir::concretelang::FHE;
namespace TFHE = mlir::concretelang::TFHE;
namespace {
struct FHEToTFHEPass : public FHEToTFHEBase<FHEToTFHEPass> {
void runOnOperation() final;
@@ -53,6 +56,58 @@ public:
}
};
// This rewrite pattern transforms any instance of `FHE.apply_lookup_table`
// operators.
//
// Example:
//
// ```mlir
// %0 = "FHE.apply_lookup_table"(%ct, %lut): (!FHE.eint<2>, tensor<4xi64>)
// ->(!FHE.eint<2>)
// ```
//
// becomes:
//
// ```mlir
// %glwe_lut = "TFHE.glwe_from_table"(%lut)
// : (tensor<4xi64>) -> !TFHE.glwe<{_,_,_}{2}>
// %glwe_ks = "TFHE.keyswitch_glwe"(%ct)
// {baseLog = -1 : i32, level = -1 : i32}
// : (!TFHE.glwe<{_,_,_}{2}>) -> !TFHE.glwe<{_,_,_}{2}>
// %0 = "TFHE.bootstrap_glwe"(%glwe_ks, %glwe_lut)
// {baseLog = -1 : i32, glweDimension = -1 : i32, level = -1 : i32,
// polynomialSize = -1 : i32}
// : (!TFHE.glwe<{_,_,_}{2}>, !TFHE.glwe<{_,_,_}{2}>) ->
// !TFHE.glwe<{_,_,_}{2}>
// ```
struct ApplyLookupTableEintOpPattern
: public mlir::OpRewritePattern<FHE::ApplyLookupTableEintOp> {
ApplyLookupTableEintOpPattern(mlir::MLIRContext *context,
mlir::PatternBenefit benefit = 1)
: ::mlir::OpRewritePattern<FHE::ApplyLookupTableEintOp>(context,
benefit) {}
::mlir::LogicalResult
matchAndRewrite(FHE::ApplyLookupTableEintOp lutOp,
mlir::PatternRewriter &rewriter) const override {
FHEToTFHETypeConverter converter;
auto inputTy = converter.convertType(lutOp.a().getType())
.cast<TFHE::GLWECipherTextType>();
auto resultTy = converter.convertType(lutOp.getType());
// %glwe_lut = "TFHE.glwe_from_table"(%lut)
auto glweLut = rewriter.create<TFHE::GLWEFromTableOp>(lutOp.getLoc(),
inputTy, lutOp.lut());
// %glwe_ks = "TFHE.keyswitch_glwe"(%ct)
auto glweKs = rewriter.create<TFHE::KeySwitchGLWEOp>(
lutOp.getLoc(), inputTy, lutOp.a(), -1, -1);
// %0 = "TFHE.bootstrap_glwe"(%glwe_ks, %glwe_lut)
rewriter.replaceOpWithNewOp<TFHE::BootstrapGLWEOp>(lutOp, resultTy, glweKs,
glweLut, -1, -1, -1, -1);
return ::mlir::success();
};
};
void FHEToTFHEPass::runOnOperation() {
auto op = this->getOperation();
@@ -85,6 +140,7 @@ void FHEToTFHEPass::runOnOperation() {
mlir::OwningRewritePatternList patterns(&getContext());
populateWithGeneratedFHEToTFHE(patterns);
patterns.add<ApplyLookupTableEintOpPattern>(&getContext());
patterns.add<RegionOpTypeConverterPattern<mlir::linalg::GenericOp,
FHEToTFHETypeConverter>>(
&getContext(), converter);

View File

@@ -15,6 +15,8 @@
#include "concretelang/Dialect/TFHE/IR/TFHETypes.h"
#include "concretelang/Support/Constants.h"
namespace TFHE = mlir::concretelang::TFHE;
namespace {
struct TFHEGlobalParametrizationPass
: public TFHEGlobalParametrizationBase<TFHEGlobalParametrizationPass> {
@@ -89,91 +91,114 @@ private:
mlir::TypeConverter &typeConverter;
};
struct TFHEApplyLookupTableParametrizationPattern
: public mlir::OpRewritePattern<
mlir::concretelang::TFHE::ApplyLookupTable> {
TFHEApplyLookupTableParametrizationPattern(
mlir::MLIRContext *context, mlir::TypeConverter &typeConverter,
mlir::concretelang::V0Parameter &v0Parameter,
mlir::PatternBenefit benefit =
mlir::concretelang::DEFAULT_PATTERN_BENEFIT)
: mlir::OpRewritePattern<mlir::concretelang::TFHE::ApplyLookupTable>(
context, benefit),
typeConverter(typeConverter), v0Parameter(v0Parameter) {}
struct KeySwitchGLWEOpPattern
: public mlir::OpRewritePattern<TFHE::KeySwitchGLWEOp> {
KeySwitchGLWEOpPattern(mlir::MLIRContext *context,
mlir::TypeConverter &converter,
mlir::concretelang::V0FHEContext &fheContext,
mlir::PatternBenefit benefit =
mlir::concretelang::DEFAULT_PATTERN_BENEFIT)
: mlir::OpRewritePattern<TFHE::KeySwitchGLWEOp>(context, benefit),
converter(converter), fheContext(fheContext) {}
mlir::LogicalResult
matchAndRewrite(mlir::concretelang::TFHE::ApplyLookupTable op,
matchAndRewrite(TFHE::KeySwitchGLWEOp ksOp,
mlir::PatternRewriter &rewriter) const override {
mlir::SmallVector<mlir::Type, 1> newResultTypes;
if (typeConverter.convertTypes(op->getResultTypes(), newResultTypes)
.failed()) {
return mlir::failure();
}
mlir::SmallVector<mlir::NamedAttribute, 6> newAttributes{
mlir::NamedAttribute(
rewriter.getIdentifier("glweDimension"),
rewriter.getI32IntegerAttr(v0Parameter.glweDimension)),
mlir::NamedAttribute(
rewriter.getIdentifier("polynomialSize"),
// TODO remove the shift when we have true polynomial size
rewriter.getI32IntegerAttr(1 << v0Parameter.logPolynomialSize)),
mlir::NamedAttribute(rewriter.getIdentifier("levelKS"),
rewriter.getI32IntegerAttr(v0Parameter.ksLevel)),
mlir::NamedAttribute(rewriter.getIdentifier("baseLogKS"),
rewriter.getI32IntegerAttr(v0Parameter.ksLogBase)),
mlir::NamedAttribute(rewriter.getIdentifier("levelBS"),
rewriter.getI32IntegerAttr(v0Parameter.brLevel)),
mlir::NamedAttribute(rewriter.getIdentifier("baseLogBS"),
rewriter.getI32IntegerAttr(v0Parameter.brLogBase)),
mlir::NamedAttribute(rewriter.getIdentifier("outputSizeKS"),
rewriter.getI32IntegerAttr(v0Parameter.nSmall)),
};
rewriter.replaceOpWithNewOp<mlir::concretelang::TFHE::ApplyLookupTable>(
op, newResultTypes, op->getOperands(), newAttributes);
auto inputTy = ksOp.ciphertext().getType().cast<TFHE::GLWECipherTextType>();
auto outputTy = rewriter.getType<TFHE::GLWECipherTextType>(
fheContext.parameter.glweDimension, fheContext.parameter.nSmall, 64,
inputTy.getP());
rewriter.replaceOpWithNewOp<TFHE::KeySwitchGLWEOp>(
ksOp, outputTy, ksOp.ciphertext(), fheContext.parameter.ksLevel,
fheContext.parameter.ksLogBase);
return mlir::success();
};
private:
mlir::TypeConverter &typeConverter;
mlir::concretelang::V0Parameter &v0Parameter;
mlir::TypeConverter &converter;
mlir::concretelang::V0FHEContext &fheContext;
};
struct TFHEApplyLookupTablePaddingPattern
: public mlir::OpRewritePattern<
mlir::concretelang::TFHE::ApplyLookupTable> {
TFHEApplyLookupTablePaddingPattern(
mlir::MLIRContext *context,
mlir::PatternBenefit benefit =
mlir::concretelang::DEFAULT_PATTERN_BENEFIT)
: mlir::OpRewritePattern<mlir::concretelang::TFHE::ApplyLookupTable>(
context, benefit) {}
struct BootstrapGLWEOpPattern
: public mlir::OpRewritePattern<TFHE::BootstrapGLWEOp> {
BootstrapGLWEOpPattern(mlir::MLIRContext *context,
mlir::TypeConverter &converter,
mlir::concretelang::V0FHEContext &fheContext,
mlir::PatternBenefit benefit =
mlir::concretelang::DEFAULT_PATTERN_BENEFIT)
: mlir::OpRewritePattern<TFHE::BootstrapGLWEOp>(context, benefit),
converter(converter), fheContext(fheContext) {}
mlir::LogicalResult
matchAndRewrite(mlir::concretelang::TFHE::ApplyLookupTable op,
matchAndRewrite(TFHE::BootstrapGLWEOp bsOp,
mlir::PatternRewriter &rewriter) const override {
auto glweInType = op.getOperandTypes()[0]
.cast<mlir::concretelang::TFHE::GLWECipherTextType>();
auto tabulatedLambdaType =
op.l_cst().getType().cast<mlir::RankedTensorType>();
rewriter.replaceOpWithNewOp<TFHE::BootstrapGLWEOp>(
bsOp, converter.convertType(bsOp.result().getType()), bsOp.ciphertext(),
bsOp.lookup_table(), fheContext.parameter.glweDimension,
1 << fheContext.parameter.logPolynomialSize,
fheContext.parameter.brLevel, fheContext.parameter.brLogBase);
return mlir::success();
};
auto expectedSize = 1 << glweInType.getP();
if (tabulatedLambdaType.getShape()[0] < expectedSize) {
private:
mlir::TypeConverter &converter;
mlir::concretelang::V0FHEContext &fheContext;
};
// This rewrite pattern transforms any instance of `TFHE.glwe_from_table` by
// parametrize GLWE return type and pad the table if the precision has been
// changed.
//
// Example:
//
// ```mlir
// %lut = arith.constant dense<[0, 1, 2, 3]> : tensor<4xi64>
// %0 = "TFHE.glwe_from_table" (%lut) : (tensor<4xi64>) ->
// !TFHE.glwe<{_,_,_}{2}>
// ```
//
// becomes:
//
// ```mlir
// %lut = arith.constant dense<[0, 1, 2, 3, 0, 1, 2, 3]> : tensor<8xi64>
// %0 = "TFHE.glwe_from_table" (%lut) : (tensor<8xi64>) ->
// !TFHE.glwe<{_,_,_}{3}>
// ```
struct GLWEFromTablePattern
: public mlir::OpRewritePattern<TFHE::GLWEFromTableOp> {
GLWEFromTablePattern(mlir::MLIRContext *context,
mlir::TypeConverter &converter,
mlir::concretelang::V0FHEContext &fheContext,
mlir::PatternBenefit benefit =
mlir::concretelang::DEFAULT_PATTERN_BENEFIT)
: mlir::OpRewritePattern<TFHE::GLWEFromTableOp>(context, benefit),
converter(converter), fheContext(fheContext) {}
mlir::LogicalResult
matchAndRewrite(TFHE::GLWEFromTableOp glweOp,
mlir::PatternRewriter &rewriter) const override {
auto newTy = converter.convertType(glweOp.getType())
.cast<TFHE::GLWECipherTextType>();
auto lutOp = glweOp.table();
auto tableTy = lutOp.getType().cast<mlir::RankedTensorType>();
auto expectedSize = 1 << newTy.getP();
if (tableTy.getShape()[0] < expectedSize) {
// Create a new padded lookup table
auto constantOp = mlir::dyn_cast_or_null<mlir::arith::ConstantOp>(
op.l_cst().getDefiningOp());
lutOp.getDefiningOp());
if (constantOp == nullptr) {
op.emitError() << "padding for non-constant operator is NYI";
glweOp.emitError() << "padding for non-constant operator is NYI";
return mlir::failure();
}
mlir::DenseIntElementsAttr denseVals =
constantOp->getAttrOfType<mlir::DenseIntElementsAttr>("value");
if (denseVals == nullptr) {
op.emitError() << "value should be dense";
constantOp.emitError() << "value should be dense";
return mlir::failure();
}
// Create the new constant dense op with padding
auto integerSize = 64;
llvm::SmallVector<llvm::APInt> rawNewDenseVals(
expectedSize, llvm::APInt(integerSize, 0));
@@ -187,19 +212,17 @@ struct TFHEApplyLookupTablePaddingPattern
{expectedSize}, rewriter.getIntegerType(integerSize));
auto newDenseVals =
mlir::DenseIntElementsAttr::get(newDenseValsType, rawNewDenseVals);
auto newConstantOp = rewriter.create<mlir::arith::ConstantOp>(
constantOp.getLoc(), newDenseVals);
// Replace the apply_lookup_table with the new constant
mlir::SmallVector<mlir::Type> newResultTypes{op.getType()};
llvm::SmallVector<mlir::Value> newOperands{op.ct(), newConstantOp};
llvm::ArrayRef<mlir::NamedAttribute> newAttrs = op->getAttrs();
rewriter.replaceOpWithNewOp<mlir::concretelang::TFHE::ApplyLookupTable>(
op, newResultTypes, newOperands, newAttrs);
return mlir::success();
// Replace the lutOp by the new padded lookup table
lutOp = rewriter.create<mlir::arith::ConstantOp>(constantOp.getLoc(),
newDenseVals);
}
rewriter.replaceOpWithNewOp<TFHE::GLWEFromTableOp>(glweOp, newTy, lutOp);
return mlir::success();
};
private:
mlir::TypeConverter &converter;
mlir::concretelang::V0FHEContext &fheContext;
};
template <typename Op>
@@ -212,44 +235,6 @@ void populateWithTFHEOpTypeConversionPattern(
[&](Op op) { return typeConverter.isLegal(op->getResultTypes()); });
}
void populateWithTFHEApplyLookupTableParametrizationPattern(
mlir::RewritePatternSet &patterns, mlir::ConversionTarget &target,
mlir::TypeConverter &typeConverter,
mlir::concretelang::V0Parameter &v0Parameter) {
patterns.add<TFHEApplyLookupTableParametrizationPattern>(
patterns.getContext(), typeConverter, v0Parameter);
target.addDynamicallyLegalOp<mlir::concretelang::TFHE::ApplyLookupTable>(
[&](mlir::concretelang::TFHE::ApplyLookupTable op) {
if (op.glweDimension() != v0Parameter.glweDimension ||
// TODO remove the shift when we have true polynomial size
op.polynomialSize() !=
((uint32_t)1 << v0Parameter.logPolynomialSize) ||
op.levelKS() != v0Parameter.ksLevel ||
op.baseLogKS() != v0Parameter.ksLogBase ||
op.levelBS() != v0Parameter.brLevel ||
op.baseLogBS() != v0Parameter.brLogBase) {
return false;
}
return typeConverter.isLegal(op->getResultTypes());
});
}
void populateWithTFHEApplyLookupTablePaddingPattern(
mlir::RewritePatternSet &patterns, mlir::ConversionTarget &target) {
patterns.add<TFHEApplyLookupTablePaddingPattern>(patterns.getContext());
target.addLegalOp<mlir::arith::ConstantOp>();
target.addDynamicallyLegalOp<mlir::concretelang::TFHE::ApplyLookupTable>(
[&](mlir::concretelang::TFHE::ApplyLookupTable op) {
auto glweInType =
op.getOperandTypes()[0]
.cast<mlir::concretelang::TFHE::GLWECipherTextType>();
auto tabulatedLambdaType =
op.getOperandTypes()[1].cast<mlir::RankedTensorType>();
return tabulatedLambdaType.getShape()[0] == 1 << glweInType.getP();
});
}
/// Populate the RewritePatternSet with all patterns that rewrite Concrete
/// operators to the corresponding function call to the `Concrete C API`.
void populateWithTFHEOpTypeConversionPatterns(
@@ -271,8 +256,6 @@ void populateWithTFHEOpTypeConversionPatterns(
patterns, target, typeConverter);
populateWithTFHEOpTypeConversionPattern<
mlir::concretelang::TFHE::MulGLWEIntOp>(patterns, target, typeConverter);
populateWithTFHEApplyLookupTableParametrizationPattern(
patterns, target, typeConverter, v0Parameter);
}
void TFHEGlobalParametrizationPass::runOnOperation() {
@@ -292,6 +275,24 @@ void TFHEGlobalParametrizationPass::runOnOperation() {
});
mlir::populateFuncOpTypeConversionPattern(patterns, converter);
// Parametrize keyswitch bootstrap
patterns.add<GLWEFromTablePattern>(&getContext(), converter, fheContext);
target.addDynamicallyLegalOp<TFHE::GLWEFromTableOp>(
[&](TFHE::GLWEFromTableOp op) {
return converter.isLegal(op->getResultTypes());
});
target.addLegalOp<mlir::arith::ConstantOp>();
patterns.add<KeySwitchGLWEOpPattern>(&getContext(), converter, fheContext);
target.addDynamicallyLegalOp<TFHE::KeySwitchGLWEOp>(
[&](TFHE::KeySwitchGLWEOp op) {
return op.level() != (uint32_t)-1 && op.baseLog() != (uint32_t)-1;
});
patterns.add<BootstrapGLWEOpPattern>(&getContext(), converter, fheContext);
target.addDynamicallyLegalOp<TFHE::BootstrapGLWEOp>(
[&](TFHE::BootstrapGLWEOp op) {
return converter.isLegal(op->getResultTypes());
});
// Add all patterns to convert TFHE types
populateWithTFHEOpTypeConversionPatterns(patterns, target, converter,
fheContext.parameter);
@@ -320,20 +321,6 @@ void TFHEGlobalParametrizationPass::runOnOperation() {
this->signalPassFailure();
}
}
// Pad lookup table
{
mlir::ConversionTarget target(getContext());
mlir::OwningRewritePatternList patterns(&getContext());
populateWithTFHEApplyLookupTablePaddingPattern(patterns, target);
// Apply conversion
if (mlir::applyPartialConversion(op, target, std::move(patterns))
.failed()) {
this->signalPassFailure();
}
}
}
namespace mlir {

View File

@@ -18,6 +18,9 @@
#include "concretelang/Dialect/TFHE/IR/TFHEDialect.h"
#include "concretelang/Dialect/TFHE/IR/TFHETypes.h"
namespace TFHE = mlir::concretelang::TFHE;
namespace Concrete = mlir::concretelang::Concrete;
namespace {
struct TFHEToConcretePass : public TFHEToConcreteBase<TFHEToConcretePass> {
void runOnOperation() final;
@@ -50,6 +53,26 @@ public:
}
};
struct GLWEFromTableOpPattern
: public mlir::OpRewritePattern<TFHE::GLWEFromTableOp> {
GLWEFromTableOpPattern(mlir::MLIRContext *context,
mlir::PatternBenefit benefit = 1)
: ::mlir::OpRewritePattern<TFHE::GLWEFromTableOp>(context, benefit) {}
::mlir::LogicalResult
matchAndRewrite(TFHE::GLWEFromTableOp glweOp,
mlir::PatternRewriter &rewriter) const override {
auto oldTy = glweOp.getType().cast<TFHE::GLWECipherTextType>();
auto newTy = rewriter.getType<Concrete::GlweCiphertextType>(
oldTy.getDimension(), oldTy.getPolynomialSize(), oldTy.getP());
rewriter.replaceOpWithNewOp<Concrete::GlweFromTable>(glweOp, newTy,
glweOp.table());
return ::mlir::success();
};
};
void TFHEToConcretePass::runOnOperation() {
auto op = this->getOperation();
@@ -84,6 +107,13 @@ void TFHEToConcretePass::runOnOperation() {
patterns.add<mlir::concretelang::GenericTypeAndOpConverterPattern<
mlir::concretelang::TFHE::ZeroTensorGLWEOp,
mlir::concretelang::Concrete::ZeroTensorLWEOp>>(&getContext(), converter);
patterns.add<GLWEFromTableOpPattern>(&getContext());
patterns.add<mlir::concretelang::GenericTypeAndOpConverterPattern<
TFHE::BootstrapGLWEOp, Concrete::BootstrapLweOp>>(&getContext(),
converter);
patterns.add<mlir::concretelang::GenericTypeAndOpConverterPattern<
TFHE::KeySwitchGLWEOp, Concrete::KeySwitchLweOp>>(&getContext(),
converter);
patterns.add<RegionOpTypeConverterPattern<mlir::linalg::GenericOp,
TFHEToConcreteTypeConverter>>(
&getContext(), converter);

View File

@@ -141,28 +141,6 @@ mlir::LogicalResult verifyUnaryGLWEOperator(Operator &op) {
return mlir::success();
}
/// verifyApplyLookupTable verify the GLWE parameters follow the rules:
/// - The l_cst argument must be a memref of one dimension of size 2^p
/// - The lookup table contains integer values of the same width of the output
mlir::LogicalResult verifyApplyLookupTable(ApplyLookupTable &op) {
auto ct = op.ct().getType().cast<GLWECipherTextType>();
auto l_cst = op.l_cst().getType().cast<RankedTensorType>();
// Check the shape of l_cst argument
auto width = ct.getP();
auto expectedSize = 1 << width;
mlir::SmallVector<int64_t, 1> expectedShape{expectedSize};
if (!l_cst.hasStaticShape(expectedShape)) {
FHE::emitErrorBadLutSize(op, "l_cst", "ct", expectedSize, width);
return mlir::failure();
}
if (!l_cst.getElementType().isInteger(64)) {
op.emitOpError() << "should have the i64 constant";
return mlir::failure();
}
return mlir::success();
}
} // namespace TFHE
} // namespace concretelang
} // namespace mlir

View File

@@ -1,23 +1,24 @@
// RUN: concretecompiler %s --action=dump-tfhe 2>&1 | FileCheck %s
// RUN: concretecompiler %s --action=dump-tfhe --passes fhe-tensor-ops-to-linalg 2>&1 | FileCheck %s
//CHECK-LABEL: #map0 = affine_map<(d0, d1) -> (d0, d1)>
//CHECK: #map0 = affine_map<(d0, d1) -> (d0, d1)>
//CHECK-NEXT: #map1 = affine_map<(d0, d1) -> (d0, d1, 0)>
//CHECK-NEXT: #map2 = affine_map<(d0, d1) -> (d0, d1, 1)>
//CHECK-NEXT: #map3 = affine_map<(d0, d1) -> (d0, d1, 2)>
//CHECK-NEXT: #map4 = affine_map<(d0, d1) -> (d0, d1, 3)>
//CHECK-NEXT: module {
//CHECK-NEXT: func @multi_lut(%arg0: tensor<4x4x!TFHE.glwe<{_,_,_}{2}>>, %arg1: tensor<4x4x4xi64>) -> tensor<4x4x!TFHE.glwe<{_,_,_}{2}>> {
//CHECK-NEXT: %[[V0:.*]] = linalg.init_tensor [4, 4] : tensor<4x4x!TFHE.glwe<{_,_,_}{2}>>
//CHECK-NEXT: %[[V1:.*]] = linalg.generic {indexing_maps = [#map0, #map1, #map2, #map3, #map4, #map0], iterator_types = ["parallel", "parallel"]} ins(%arg0, %arg1, %arg1, %arg1, %arg1 : tensor<4x4x!TFHE.glwe<{_,_,_}{2}>>, tensor<4x4x4xi64>, tensor<4x4x4xi64>, tensor<4x4x4xi64>, tensor<4x4x4xi64>) outs(%[[V0]] : tensor<4x4x!TFHE.glwe<{_,_,_}{2}>>) {
//CHECK-NEXT: ^bb0(%arg2: !TFHE.glwe<{_,_,_}{2}>, %arg3: i64, %arg4: i64, %arg5: i64, %arg6: i64, %arg7: !TFHE.glwe<{_,_,_}{2}>): // no predecessors
//CHECK-NEXT: %[[V2:.*]] = tensor.from_elements %arg3, %arg4, %arg5, %arg6 : tensor<4xi64>
//CHECK-NEXT: %[[V3:.*]] = "TFHE.apply_lookup_table"(%arg2, %[[V2]]) {baseLogBS = -1 : i32, baseLogKS = -1 : i32, glweDimension = -1 : i32, levelBS = -1 : i32, levelKS = -1 : i32, outputSizeKS = -1 : i32, polynomialSize = -1 : i32} : (!TFHE.glwe<{_,_,_}{2}>, tensor<4xi64>) -> !TFHE.glwe<{_,_,_}{2}>
//CHECK-NEXT: linalg.yield %[[V3]] : !TFHE.glwe<{_,_,_}{2}>
//CHECK-NEXT: } -> tensor<4x4x!TFHE.glwe<{_,_,_}{2}>>
//CHECK-NEXT: return %[[V1]] : tensor<4x4x!TFHE.glwe<{_,_,_}{2}>>
//CHECK-NEXT: func @multi_lut(%[[A0:.*]]: tensor<4x4x!FHE.eint<2>>, %[[A1:.*]]: tensor<4x4x4xi64>) -> tensor<4x4x!FHE.eint<2>> {
//CHECK-NEXT: %[[V0:.*]] = linalg.init_tensor [4, 4] : tensor<4x4x!FHE.eint<2>>
//CHECK-NEXT: %[[V1:.*]] = linalg.generic {indexing_maps = [#map0, #map1, #map2, #map3, #map4, #map0], iterator_types = ["parallel", "parallel"]} ins(%[[A0]], %[[A1]], %[[A1]], %[[A1]], %[[A1]] : tensor<4x4x!FHE.eint<2>>, tensor<4x4x4xi64>, tensor<4x4x4xi64>, tensor<4x4x4xi64>, tensor<4x4x4xi64>) outs(%[[V0]] : tensor<4x4x!FHE.eint<2>>) {
//CHECK-NEXT: ^bb0(%[[A2:.*]]: !FHE.eint<2>, %[[A3:.*]]: i64, %[[A4:.*]]: i64, %[[A5:.*]]: i64, %[[A6:.*]]: i64, %[[A7:.*]]: !FHE.eint<2>): // no predecessors
//CHECK-NEXT: %[[V2:.*]] = tensor.from_elements %[[A3]], %[[A4]], %[[A5]], %[[A6]] : tensor<4xi64>
//CHECK-NEXT: %[[V3:.*]] = "FHE.apply_lookup_table"(%[[A2]], %[[V2]]) : (!FHE.eint<2>, tensor<4xi64>) -> !FHE.eint<2>
//CHECK-NEXT: linalg.yield %[[V3]] : !FHE.eint<2>
//CHECK-NEXT: } -> tensor<4x4x!FHE.eint<2>>
//CHECK-NEXT: return %[[V1]] : tensor<4x4x!FHE.eint<2>>
//CHECK-NEXT: }
//CHECK-NEXT: }
func @multi_lut(%arg0: tensor<4x4x!FHE.eint<2>>, %arg1: tensor<4x4x4xi64>) -> tensor<4x4x!FHE.eint<2>> {
%1 = "FHELinalg.apply_multi_lookup_table"(%arg0, %arg1): (tensor<4x4x!FHE.eint<2>>, tensor<4x4x4xi64>) -> tensor<4x4x!FHE.eint<2>>
return %1: tensor<4x4x!FHE.eint<2>>
%0 = "FHELinalg.apply_multi_lookup_table"(%arg0, %arg1): (tensor<4x4x!FHE.eint<2>>, tensor<4x4x4xi64>) -> tensor<4x4x!FHE.eint<2>>
return %0: tensor<4x4x!FHE.eint<2>>
}

View File

@@ -1,22 +1,23 @@
// RUN: concretecompiler %s --action=dump-tfhe 2>&1 | FileCheck %s
// RUN: concretecompiler %s --action=dump-tfhe --passes fhe-tensor-ops-to-linalg 2>&1 | FileCheck %s
//CHECK-LABEL: #map0 = affine_map<(d0, d1) -> (d0, d1)>
//CHECK: #map0 = affine_map<(d0, d1) -> (d0, d1)>
//CHECK-NEXT: #map1 = affine_map<(d0, d1) -> (d1, 0)>
//CHECK-NEXT: #map2 = affine_map<(d0, d1) -> (d1, 1)>
//CHECK-NEXT: #map3 = affine_map<(d0, d1) -> (d1, 2)>
//CHECK-NEXT: #map4 = affine_map<(d0, d1) -> (d1, 3)>
//CHECK-NEXT: module {
//CHECK-NEXT: func @multi_lut(%arg0: tensor<4x3x!TFHE.glwe<{_,_,_}{2}>>, %arg1: tensor<3x4xi64>) -> tensor<4x3x!TFHE.glwe<{_,_,_}{2}>> {
//CHECK-NEXT: %[[V0:.*]] = linalg.init_tensor [4, 3] : tensor<4x3x!TFHE.glwe<{_,_,_}{2}>>
//CHECK-NEXT: %[[V1:.*]] = linalg.generic {indexing_maps = [#map0, #map1, #map2, #map3, #map4, #map0], iterator_types = ["parallel", "parallel"]} ins(%arg0, %arg1, %arg1, %arg1, %arg1 : tensor<4x3x!TFHE.glwe<{_,_,_}{2}>>, tensor<3x4xi64>, tensor<3x4xi64>, tensor<3x4xi64>, tensor<3x4xi64>) outs(%[[V0]] : tensor<4x3x!TFHE.glwe<{_,_,_}{2}>>) {
//CHECK-NEXT: ^bb0(%arg2: !TFHE.glwe<{_,_,_}{2}>, %arg3: i64, %arg4: i64, %arg5: i64, %arg6: i64, %arg7: !TFHE.glwe<{_,_,_}{2}>): // no predecessors
//CHECK-NEXT: %[[V2:.*]] = tensor.from_elements %arg3, %arg4, %arg5, %arg6 : tensor<4xi64>
//CHECK-NEXT: %[[V3:.*]] = "TFHE.apply_lookup_table"(%arg2, %[[V2]]) {baseLogBS = -1 : i32, baseLogKS = -1 : i32, glweDimension = -1 : i32, levelBS = -1 : i32, levelKS = -1 : i32, outputSizeKS = -1 : i32, polynomialSize = -1 : i32} : (!TFHE.glwe<{_,_,_}{2}>, tensor<4xi64>) -> !TFHE.glwe<{_,_,_}{2}>
//CHECK-NEXT: linalg.yield %[[V3]] : !TFHE.glwe<{_,_,_}{2}>
//CHECK-NEXT: } -> tensor<4x3x!TFHE.glwe<{_,_,_}{2}>>
//CHECK-NEXT: return %[[V1]] : tensor<4x3x!TFHE.glwe<{_,_,_}{2}>>
//CHECK-NEXT: func @multi_lut(%[[A0:.*]]: tensor<4x3x!FHE.eint<2>>, %[[A1:.*]]: tensor<3x4xi64>) -> tensor<4x3x!FHE.eint<2>> {
//CHECK-NEXT: %[[V0:.*]] = linalg.init_tensor [4, 3] : tensor<4x3x!FHE.eint<2>>
//CHECK-NEXT: %[[V1:.*]] = linalg.generic {indexing_maps = [#map0, #map1, #map2, #map3, #map4, #map0], iterator_types = ["parallel", "parallel"]} ins(%[[A0]], %[[A1]], %[[A1]], %[[A1]], %[[A1]] : tensor<4x3x!FHE.eint<2>>, tensor<3x4xi64>, tensor<3x4xi64>, tensor<3x4xi64>, tensor<3x4xi64>) outs(%[[V0]] : tensor<4x3x!FHE.eint<2>>) {
//CHECK-NEXT: ^bb0(%[[A2:.*]]: !FHE.eint<2>, %[[A3:.*]]: i64, %[[A4:.*]]: i64, %[[A5:.*]]: i64, %[[A6:.*]]: i64, %[[A7:.*]]: !FHE.eint<2>): // no predecessors
//CHECK-NEXT: %[[V2:.*]] = tensor.from_elements %[[A3]], %[[A4]], %[[A5]], %[[A6]] : tensor<4xi64>
//CHECK-NEXT: %[[V3:.*]] = "FHE.apply_lookup_table"(%[[A2]], %[[V2]]) : (!FHE.eint<2>, tensor<4xi64>) -> !FHE.eint<2>
//CHECK-NEXT: linalg.yield %[[V3]] : !FHE.eint<2>
//CHECK-NEXT: } -> tensor<4x3x!FHE.eint<2>>
//CHECK-NEXT: return %[[V1]] : tensor<4x3x!FHE.eint<2>>
//CHECK-NEXT: }
//CHECK-NEXT: }
func @multi_lut(%arg0: tensor<4x3x!FHE.eint<2>>, %arg1: tensor<3x4xi64>) -> tensor<4x3x!FHE.eint<2>> {
%1 = "FHELinalg.apply_multi_lookup_table"(%arg0, %arg1): (tensor<4x3x!FHE.eint<2>>, tensor<3x4xi64>) -> tensor<4x3x!FHE.eint<2>>
return %1: tensor<4x3x!FHE.eint<2>>

View File

@@ -1,10 +1,11 @@
// RUN: concretecompiler %s --passes fhe-to-tfhe --action=dump-tfhe 2>&1| FileCheck %s
// CHECK-LABEL: func @apply_lookup_table(%arg0: !TFHE.glwe<{_,_,_}{2}>, %arg1: tensor<4xi64>) -> !TFHE.glwe<{_,_,_}{2}>
func @apply_lookup_table(%arg0: !FHE.eint<2>, %arg1: tensor<4xi64>) -> !FHE.eint<2> {
// CHECK-NEXT: %[[V1:.*]] = "TFHE.apply_lookup_table"(%arg0, %arg1) {baseLogBS = -1 : i32, baseLogKS = -1 : i32, glweDimension = -1 : i32, levelBS = -1 : i32, levelKS = -1 : i32, outputSizeKS = -1 : i32, polynomialSize = -1 : i32} : (!TFHE.glwe<{_,_,_}{2}>, tensor<4xi64>) -> !TFHE.glwe<{_,_,_}{2}>
// CHECK-NEXT: return %[[V1]] : !TFHE.glwe<{_,_,_}{2}>
%1 = "FHE.apply_lookup_table"(%arg0, %arg1): (!FHE.eint<2>, tensor<4xi64>) -> (!FHE.eint<2>)
return %1: !FHE.eint<2>
}
// CHECK: func @apply_lookup_table(%[[A0:.*]]: !TFHE.glwe<{_,_,_}{2}>, %[[LUT:.*]]: tensor<4xi64>) -> !TFHE.glwe<{_,_,_}{3}> {
// CHECK-NEXT: %[[V0:.*]] = "TFHE.glwe_from_table"(%[[LUT]]) : (tensor<4xi64>) -> !TFHE.glwe<{_,_,_}{2}>
// CHECK-NEXT: %[[V1:.*]] = "TFHE.keyswitch_glwe"(%[[A0]]) {baseLog = -1 : i32, level = -1 : i32} : (!TFHE.glwe<{_,_,_}{2}>) -> !TFHE.glwe<{_,_,_}{2}>
// CHECK-NEXT: %[[V2:.*]] = "TFHE.bootstrap_glwe"(%[[V1]], %[[V0]]) {baseLog = -1 : i32, glweDimension = -1 : i32, level = -1 : i32, polynomialSize = -1 : i32} : (!TFHE.glwe<{_,_,_}{2}>, !TFHE.glwe<{_,_,_}{2}>) -> !TFHE.glwe<{_,_,_}{3}>
// CHECK-NEXT: return %[[V2]] : !TFHE.glwe<{_,_,_}{3}>
func @apply_lookup_table(%arg0: !FHE.eint<2>, %arg1: tensor<4xi64>) -> !FHE.eint<3> {
%1 = "FHE.apply_lookup_table"(%arg0, %arg1): (!FHE.eint<2>, tensor<4xi64>) -> (!FHE.eint<3>)
return %1: !FHE.eint<3>
}

View File

@@ -1,10 +1,13 @@
// RUN: concretecompiler %s --passes fhe-to-tfhe --action=dump-tfhe 2>&1| FileCheck %s
// CHECK-LABEL: func @apply_lookup_table_cst(%arg0: !TFHE.glwe<{_,_,_}{7}>) -> !TFHE.glwe<{_,_,_}{7}>
//CHECK: func @apply_lookup_table_cst(%[[A0:.*]]: !TFHE.glwe<{_,_,_}{7}>) -> !TFHE.glwe<{_,_,_}{7}> {
//CHECK-NEXT: %cst = arith.constant dense<"0x00000000000000000100000000000000020000000000000003000000000000000400000000000000050000000000000006000000000000000700000000000000080000000000000009000000000000000A000000000000000B000000000000000C000000000000000D000000000000000E000000000000000F0000000000000010000000000000001100000000000000120000000000000013000000000000001400000000000000150000000000000016000000000000001700000000000000180000000000000019000000000000001A000000000000001B000000000000001C000000000000001D000000000000001E000000000000001F0000000000000020000000000000002100000000000000220000000000000023000000000000002400000000000000250000000000000026000000000000002700000000000000280000000000000029000000000000002A000000000000002B000000000000002C000000000000002D000000000000002E000000000000002F0000000000000030000000000000003100000000000000320000000000000033000000000000003400000000000000350000000000000036000000000000003700000000000000380000000000000039000000000000003A000000000000003B000000000000003C000000000000003D000000000000003E000000000000003F0000000000000040000000000000004100000000000000420000000000000043000000000000004400000000000000450000000000000046000000000000004700000000000000480000000000000049000000000000004A000000000000004B000000000000004C000000000000004D000000000000004E000000000000004F0000000000000050000000000000005100000000000000520000000000000053000000000000005400000000000000550000000000000056000000000000005700000000000000580000000000000059000000000000005A000000000000005B000000000000005C000000000000005D000000000000005E000000000000005F0000000000000060000000000000006100000000000000620000000000000063000000000000006400000000000000650000000000000066000000000000006700000000000000680000000000000069000000000000006A000000000000006B000000000000006C000000000000006D000000000000006E000000000000006F0000000000000070000000000000007100000000000000720000000000000073000000000000007400000000000000750000000000000076000000000000007700000000000000780000000000000079000000000000007A000000000000007B000000000000007C000000000000007D000000000000007E000000000000007F00000000000000"> : tensor<128xi64>
//CHECK-NEXT: %[[V0:.*]] = "TFHE.glwe_from_table"(%cst) : (tensor<128xi64>) -> !TFHE.glwe<{_,_,_}{7}>
//CHECK-NEXT: %[[V1:.*]] = "TFHE.keyswitch_glwe"(%[[A0]]) {baseLog = -1 : i32, level = -1 : i32} : (!TFHE.glwe<{_,_,_}{7}>) -> !TFHE.glwe<{_,_,_}{7}>
//CHECK-NEXT: %[[V2:.*]] = "TFHE.bootstrap_glwe"(%[[V1]], %[[V0]]) {baseLog = -1 : i32, glweDimension = -1 : i32, level = -1 : i32, polynomialSize = -1 : i32} : (!TFHE.glwe<{_,_,_}{7}>, !TFHE.glwe<{_,_,_}{7}>) -> !TFHE.glwe<{_,_,_}{7}>
//CHECK-NEXT: return %[[V2]] : !TFHE.glwe<{_,_,_}{7}>
//CHECK-NEXT: }
func @apply_lookup_table_cst(%arg0: !FHE.eint<7>) -> !FHE.eint<7> {
// CHECK-NEXT: %[[TABLE:.*]] = arith.constant dense<"0x00000000000000000100000000000000020000000000000003000000000000000400000000000000050000000000000006000000000000000700000000000000080000000000000009000000000000000A000000000000000B000000000000000C000000000000000D000000000000000E000000000000000F0000000000000010000000000000001100000000000000120000000000000013000000000000001400000000000000150000000000000016000000000000001700000000000000180000000000000019000000000000001A000000000000001B000000000000001C000000000000001D000000000000001E000000000000001F0000000000000020000000000000002100000000000000220000000000000023000000000000002400000000000000250000000000000026000000000000002700000000000000280000000000000029000000000000002A000000000000002B000000000000002C000000000000002D000000000000002E000000000000002F0000000000000030000000000000003100000000000000320000000000000033000000000000003400000000000000350000000000000036000000000000003700000000000000380000000000000039000000000000003A000000000000003B000000000000003C000000000000003D000000000000003E000000000000003F0000000000000040000000000000004100000000000000420000000000000043000000000000004400000000000000450000000000000046000000000000004700000000000000480000000000000049000000000000004A000000000000004B000000000000004C000000000000004D000000000000004E000000000000004F0000000000000050000000000000005100000000000000520000000000000053000000000000005400000000000000550000000000000056000000000000005700000000000000580000000000000059000000000000005A000000000000005B000000000000005C000000000000005D000000000000005E000000000000005F0000000000000060000000000000006100000000000000620000000000000063000000000000006400000000000000650000000000000066000000000000006700000000000000680000000000000069000000000000006A000000000000006B000000000000006C000000000000006D000000000000006E000000000000006F0000000000000070000000000000007100000000000000720000000000000073000000000000007400000000000000750000000000000076000000000000007700000000000000780000000000000079000000000000007A000000000000007B000000000000007C000000000000007D000000000000007E000000000000007F00000000000000"> : tensor<128xi64>
// CHECK-NEXT: %[[V0:.*]] = "TFHE.apply_lookup_table"(%arg0, %[[TABLE]]) {baseLogBS = -1 : i32, baseLogKS = -1 : i32, glweDimension = -1 : i32, levelBS = -1 : i32, levelKS = -1 : i32, outputSizeKS = -1 : i32, polynomialSize = -1 : i32} : (!TFHE.glwe<{_,_,_}{7}>, tensor<128xi64>) -> !TFHE.glwe<{_,_,_}{7}>
// CHECK-NEXT: return %[[V0]] : !TFHE.glwe<{_,_,_}{7}>
%tlu = arith.constant dense<[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127]> : tensor<128xi64>
%1 = "FHE.apply_lookup_table"(%arg0, %tlu): (!FHE.eint<7>, tensor<128xi64>) -> (!FHE.eint<7>)
return %1: !FHE.eint<7>

View File

@@ -1,11 +0,0 @@
// RUN: concretecompiler --passes tfhe-to-concrete --action=dump-concrete %s 2>&1| FileCheck %s
// CHECK-LABEL: func @apply_lookup_table(%arg0: !Concrete.lwe_ciphertext<1024,4>, %arg1: tensor<16xi64>) -> !Concrete.lwe_ciphertext<1024,4>
func @apply_lookup_table(%arg0: !TFHE.glwe<{1024,1,64}{4}>, %arg1: tensor<16xi64>) -> !TFHE.glwe<{1024,1,64}{4}> {
// CHECK-NEXT: %[[V1:.*]] = "Concrete.glwe_from_table"(%arg1) : (tensor<16xi64>) -> !Concrete.glwe_ciphertext<1024,1,4>
// CHECK-NEXT: %[[V2:.*]] = "Concrete.keyswitch_lwe"(%arg0) {baseLog = 2 : i32, level = 3 : i32} : (!Concrete.lwe_ciphertext<1024,4>) -> !Concrete.lwe_ciphertext<600,4>
// CHECK-NEXT: %[[V3:.*]] = "Concrete.bootstrap_lwe"(%[[V2]], %[[V1]]) {baseLog = 4 : i32, glweDimension = 1 : i32, level = 5 : i32, polynomialSize = 1024 : i32} : (!Concrete.lwe_ciphertext<600,4>, !Concrete.glwe_ciphertext<1024,1,4>) -> !Concrete.lwe_ciphertext<1024,4>
// CHECK-NEXT: return %[[V3]] : !Concrete.lwe_ciphertext<1024,4>
%1 = "TFHE.apply_lookup_table"(%arg0, %arg1){glweDimension=1:i32, polynomialSize=1024:i32, levelKS=3:i32, baseLogKS=2:i32, levelBS=5:i32, baseLogBS=4:i32, outputSizeKS=600:i32}: (!TFHE.glwe<{1024,1,64}{4}>, tensor<16xi64>) -> (!TFHE.glwe<{1024,1,64}{4}>)
return %1: !TFHE.glwe<{1024,1,64}{4}>
}

View File

@@ -1,13 +0,0 @@
// RUN: concretecompiler --passes tfhe-to-concrete --action=dump-concrete %s 2>&1| FileCheck %s
// CHECK-LABEL: func @apply_lookup_table_cst(%arg0: !Concrete.lwe_ciphertext<2048,4>) -> !Concrete.lwe_ciphertext<2048,4>
func @apply_lookup_table_cst(%arg0: !TFHE.glwe<{2048,1,64}{4}>) -> !TFHE.glwe<{2048,1,64}{4}> {
// CHECK-NEXT: %[[TABLE:.*]] = arith.constant dense<[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]> : tensor<16xi64>
// CHECK-NEXT: %[[V1:.*]] = "Concrete.glwe_from_table"(%[[TABLE]]) : (tensor<16xi64>) -> !Concrete.glwe_ciphertext<2048,1,4>
// CHECK-NEXT: %[[V2:.*]] = "Concrete.keyswitch_lwe"(%arg0) {baseLog = 2 : i32, level = 3 : i32} : (!Concrete.lwe_ciphertext<2048,4>) -> !Concrete.lwe_ciphertext<600,4>
// CHECK-NEXT: %[[V3:.*]] = "Concrete.bootstrap_lwe"(%[[V2]], %[[V1]]) {baseLog = 4 : i32, glweDimension = 1 : i32, level = 5 : i32, polynomialSize = 2048 : i32} : (!Concrete.lwe_ciphertext<600,4>, !Concrete.glwe_ciphertext<2048,1,4>) -> !Concrete.lwe_ciphertext<2048,4>
// CHECK-NEXT: return %[[V3]] : !Concrete.lwe_ciphertext<2048,4>
%tlu = arith.constant dense<[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]> : tensor<16xi64>
%1 = "TFHE.apply_lookup_table"(%arg0, %tlu){glweDimension=1:i32, polynomialSize=2048:i32, levelKS=3:i32, baseLogKS=2:i32, levelBS=5:i32, baseLogBS=4:i32, outputSizeKS=600:i32}: (!TFHE.glwe<{2048,1,64}{4}>, tensor<16xi64>) -> (!TFHE.glwe<{2048,1,64}{4}>)
return %1: !TFHE.glwe<{2048,1,64}{4}>
}

View File

@@ -0,0 +1,14 @@
// RUN: concretecompiler --passes tfhe-to-concrete --action=dump-concrete %s 2>&1| FileCheck %s
//CHECK: func @bootstrap_lwe(%[[A0:.*]]: !Concrete.lwe_ciphertext<1024,7>) -> !Concrete.lwe_ciphertext<1024,4> {
//CHECK-NEXT: %cst = arith.constant dense<"0x00000000000000000100000000000000020000000000000003000000000000000400000000000000050000000000000006000000000000000700000000000000080000000000000009000000000000000A000000000000000B000000000000000C000000000000000D000000000000000E000000000000000F0000000000000010000000000000001100000000000000120000000000000013000000000000001400000000000000150000000000000016000000000000001700000000000000180000000000000019000000000000001A000000000000001B000000000000001C000000000000001D000000000000001E000000000000001F0000000000000020000000000000002100000000000000220000000000000023000000000000002400000000000000250000000000000026000000000000002700000000000000280000000000000029000000000000002A000000000000002B000000000000002C000000000000002D000000000000002E000000000000002F0000000000000030000000000000003100000000000000320000000000000033000000000000003400000000000000350000000000000036000000000000003700000000000000380000000000000039000000000000003A000000000000003B000000000000003C000000000000003D000000000000003E000000000000003F0000000000000040000000000000004100000000000000420000000000000043000000000000004400000000000000450000000000000046000000000000004700000000000000480000000000000049000000000000004A000000000000004B000000000000004C000000000000004D000000000000004E000000000000004F0000000000000050000000000000005100000000000000520000000000000053000000000000005400000000000000550000000000000056000000000000005700000000000000580000000000000059000000000000005A000000000000005B000000000000005C000000000000005D000000000000005E000000000000005F0000000000000060000000000000006100000000000000620000000000000063000000000000006400000000000000650000000000000066000000000000006700000000000000680000000000000069000000000000006A000000000000006B000000000000006C000000000000006D000000000000006E000000000000006F0000000000000070000000000000007100000000000000720000000000000073000000000000007400000000000000750000000000000076000000000000007700000000000000780000000000000079000000000000007A000000000000007B000000000000007C000000000000007D000000000000007E000000000000007F00000000000000"> : tensor<128xi64>
//CHECK-NEXT: %[[V0:.*]] = "Concrete.glwe_from_table"(%cst) : (tensor<128xi64>) -> !Concrete.glwe_ciphertext<1,1024,7>
//CHECK-NEXT: %[[V1:.*]] = "Concrete.bootstrap_lwe"(%[[A0]], %[[V0]]) {baseLog = 1 : i32, glweDimension = 1 : i32, level = 3 : i32, polynomialSize = 1024 : i32} : (!Concrete.lwe_ciphertext<1024,7>, !Concrete.glwe_ciphertext<1,1024,7>) -> !Concrete.lwe_ciphertext<1024,4>
//CHECK-NEXT: return %[[V1]] : !Concrete.lwe_ciphertext<1024,4>
//CHECK-NEXT: }
func @bootstrap_lwe(%ciphertext: !TFHE.glwe<{1,1024,64}{7}>) -> !TFHE.glwe<{1,1024,64}{4}> {
%cst = arith.constant dense<"0x00000000000000000100000000000000020000000000000003000000000000000400000000000000050000000000000006000000000000000700000000000000080000000000000009000000000000000A000000000000000B000000000000000C000000000000000D000000000000000E000000000000000F0000000000000010000000000000001100000000000000120000000000000013000000000000001400000000000000150000000000000016000000000000001700000000000000180000000000000019000000000000001A000000000000001B000000000000001C000000000000001D000000000000001E000000000000001F0000000000000020000000000000002100000000000000220000000000000023000000000000002400000000000000250000000000000026000000000000002700000000000000280000000000000029000000000000002A000000000000002B000000000000002C000000000000002D000000000000002E000000000000002F0000000000000030000000000000003100000000000000320000000000000033000000000000003400000000000000350000000000000036000000000000003700000000000000380000000000000039000000000000003A000000000000003B000000000000003C000000000000003D000000000000003E000000000000003F0000000000000040000000000000004100000000000000420000000000000043000000000000004400000000000000450000000000000046000000000000004700000000000000480000000000000049000000000000004A000000000000004B000000000000004C000000000000004D000000000000004E000000000000004F0000000000000050000000000000005100000000000000520000000000000053000000000000005400000000000000550000000000000056000000000000005700000000000000580000000000000059000000000000005A000000000000005B000000000000005C000000000000005D000000000000005E000000000000005F0000000000000060000000000000006100000000000000620000000000000063000000000000006400000000000000650000000000000066000000000000006700000000000000680000000000000069000000000000006A000000000000006B000000000000006C000000000000006D000000000000006E000000000000006F0000000000000070000000000000007100000000000000720000000000000073000000000000007400000000000000750000000000000076000000000000007700000000000000780000000000000079000000000000007A000000000000007B000000000000007C000000000000007D000000000000007E000000000000007F00000000000000"> : tensor<128xi64>
%glwe_lut = "TFHE.glwe_from_table"(%cst) : (tensor<128xi64>) -> !TFHE.glwe<{1,1024,64}{7}>
%bootstraped = "TFHE.bootstrap_glwe"(%ciphertext, %glwe_lut) {baseLog = 1 : i32, glweDimension = 1 : i32, level = 3 : i32, polynomialSize = 1024 : i32} : (!TFHE.glwe<{1,1024,64}{7}>, !TFHE.glwe<{1,1024,64}{7}>) -> !TFHE.glwe<{1,1024,64}{4}>
return %bootstraped : !TFHE.glwe<{1,1024,64}{4}>
}

View File

@@ -0,0 +1,12 @@
// RUN: concretecompiler --passes tfhe-to-concrete --action=dump-concrete %s 2>&1| FileCheck %s
//CHECK: func @glwe_from_table() {
//CHECK-NEXT: %[[V0:.*]] = arith.constant dense<"0x00000000000000000100000000000000020000000000000003000000000000000400000000000000050000000000000006000000000000000700000000000000080000000000000009000000000000000A000000000000000B000000000000000C000000000000000D000000000000000E000000000000000F0000000000000010000000000000001100000000000000120000000000000013000000000000001400000000000000150000000000000016000000000000001700000000000000180000000000000019000000000000001A000000000000001B000000000000001C000000000000001D000000000000001E000000000000001F0000000000000020000000000000002100000000000000220000000000000023000000000000002400000000000000250000000000000026000000000000002700000000000000280000000000000029000000000000002A000000000000002B000000000000002C000000000000002D000000000000002E000000000000002F0000000000000030000000000000003100000000000000320000000000000033000000000000003400000000000000350000000000000036000000000000003700000000000000380000000000000039000000000000003A000000000000003B000000000000003C000000000000003D000000000000003E000000000000003F0000000000000040000000000000004100000000000000420000000000000043000000000000004400000000000000450000000000000046000000000000004700000000000000480000000000000049000000000000004A000000000000004B000000000000004C000000000000004D000000000000004E000000000000004F0000000000000050000000000000005100000000000000520000000000000053000000000000005400000000000000550000000000000056000000000000005700000000000000580000000000000059000000000000005A000000000000005B000000000000005C000000000000005D000000000000005E000000000000005F0000000000000060000000000000006100000000000000620000000000000063000000000000006400000000000000650000000000000066000000000000006700000000000000680000000000000069000000000000006A000000000000006B000000000000006C000000000000006D000000000000006E000000000000006F0000000000000070000000000000007100000000000000720000000000000073000000000000007400000000000000750000000000000076000000000000007700000000000000780000000000000079000000000000007A000000000000007B000000000000007C000000000000007D000000000000007E000000000000007F00000000000000"> : tensor<128xi64>
//CHECK-NEXT: %[[V1:.*]] = "Concrete.glwe_from_table"(%[[V0]]) : (tensor<128xi64>) -> !Concrete.glwe_ciphertext<1,1024,7>
//CHECK-NEXT: return
//CHECK-NEXT: }
func @glwe_from_table() {
%cst = arith.constant dense<"0x00000000000000000100000000000000020000000000000003000000000000000400000000000000050000000000000006000000000000000700000000000000080000000000000009000000000000000A000000000000000B000000000000000C000000000000000D000000000000000E000000000000000F0000000000000010000000000000001100000000000000120000000000000013000000000000001400000000000000150000000000000016000000000000001700000000000000180000000000000019000000000000001A000000000000001B000000000000001C000000000000001D000000000000001E000000000000001F0000000000000020000000000000002100000000000000220000000000000023000000000000002400000000000000250000000000000026000000000000002700000000000000280000000000000029000000000000002A000000000000002B000000000000002C000000000000002D000000000000002E000000000000002F0000000000000030000000000000003100000000000000320000000000000033000000000000003400000000000000350000000000000036000000000000003700000000000000380000000000000039000000000000003A000000000000003B000000000000003C000000000000003D000000000000003E000000000000003F0000000000000040000000000000004100000000000000420000000000000043000000000000004400000000000000450000000000000046000000000000004700000000000000480000000000000049000000000000004A000000000000004B000000000000004C000000000000004D000000000000004E000000000000004F0000000000000050000000000000005100000000000000520000000000000053000000000000005400000000000000550000000000000056000000000000005700000000000000580000000000000059000000000000005A000000000000005B000000000000005C000000000000005D000000000000005E000000000000005F0000000000000060000000000000006100000000000000620000000000000063000000000000006400000000000000650000000000000066000000000000006700000000000000680000000000000069000000000000006A000000000000006B000000000000006C000000000000006D000000000000006E000000000000006F0000000000000070000000000000007100000000000000720000000000000073000000000000007400000000000000750000000000000076000000000000007700000000000000780000000000000079000000000000007A000000000000007B000000000000007C000000000000007D000000000000007E000000000000007F00000000000000"> : tensor<128xi64>
%0 = "TFHE.glwe_from_table"(%cst) : (tensor<128xi64>) -> !TFHE.glwe<{1,1024,64}{7}>
return
}

View File

@@ -0,0 +1,10 @@
// RUN: concretecompiler --passes tfhe-to-concrete --action=dump-concrete %s 2>&1| FileCheck %s
// CHECK: func @keyswitch_glwe(%[[A0:.*]]: !Concrete.lwe_ciphertext<1024,2>) -> !Concrete.lwe_ciphertext<567,2> {
// CHECK-NEXT: %[[V0:.*]] = "Concrete.keyswitch_lwe"(%[[A0]]) {baseLog = 3 : i32, level = 2 : i32} : (!Concrete.lwe_ciphertext<1024,2>) -> !Concrete.lwe_ciphertext<567,2>
// CHECK-NEXT: return %[[V0]] : !Concrete.lwe_ciphertext<567,2>
// CHECK-NEXT: }
func @keyswitch_glwe(%arg0: !TFHE.glwe<{1,1024,64}{2}>) -> !TFHE.glwe<{1,567,64}{2}> {
%0 = "TFHE.keyswitch_glwe"(%arg0) {baseLog = 3 : i32, level = 2 : i32} : (!TFHE.glwe<{1,1024,64}{2}>) -> !TFHE.glwe<{1,567,64}{2}>
return %0 : !TFHE.glwe<{1,567,64}{2}>
}

View File

@@ -0,0 +1,11 @@
// RUN: concretecompiler %s --action=roundtrip 2>&1 | FileCheck %s
//CHECK: func @mapped_lut(%[[A0:.*]]: tensor<2x3x!FHE.eint<2>>, %[[A1:.*]]: tensor<5x4xi64>, %[[A2:.*]]: tensor<2x3xindex>) -> tensor<2x3x!FHE.eint<2>> {
//CHECK-NEXT: %[[V0:.*]] = "FHELinalg.apply_mapped_lookup_table"(%[[A0]], %[[A1]], %[[A2]]) : (tensor<2x3x!FHE.eint<2>>, tensor<5x4xi64>, tensor<2x3xindex>) -> tensor<2x3x!FHE.eint<2>>
//CHECK-NEXT: return %[[V0]] : tensor<2x3x!FHE.eint<2>>
//CHECK-NEXT: }
func @mapped_lut(%t: tensor<2x3x!FHE.eint<2>>, %luts: tensor<5x4xi64>, %map: tensor<2x3xindex>) -> tensor<2x3x!FHE.eint<2>> {
%0 = "FHELinalg.apply_mapped_lookup_table"(%t, %luts, %map): (tensor<2x3x!FHE.eint<2>>, tensor<5x4xi64>, tensor<2x3xindex>) -> tensor<2x3x!FHE.eint<2>>
return %0: tensor<2x3x!FHE.eint<2>>
}

View File

@@ -1,31 +0,0 @@
// RUN: concretecompiler %s --action=dump-tfhe 2>&1 | FileCheck %s
//CHECK-LABEL: #map = affine_map<(d0, d1) -> (d0, d1)>
//CHECK-NEXT:module {
//CHECK-NEXT: func @mapped_lut(%arg0: tensor<2x3x!TFHE.glwe<{_,_,_}{2}>>, %[[LUTS:.*]]: tensor<5x4xi64>, %arg2: tensor<2x3xindex>) -> tensor<2x3x!TFHE.glwe<{_,_,_}{2}>> {
//CHECK-NEXT: %[[C0:.*]] = arith.constant 0 : index
//CHECK-NEXT: %[[C1:.*]] = arith.constant 1 : index
//CHECK-NEXT: %[[C2:.*]] = arith.constant 2 : index
//CHECK-NEXT: %[[C3:.*]] = arith.constant 3 : index
//CHECK-NEXT: %[[V0:.*]] = linalg.init_tensor [2, 3] : tensor<2x3x!TFHE.glwe<{_,_,_}{2}>>
//CHECK-NEXT: %[[V1:.*]] = linalg.generic {indexing_maps = [#map, #map, #map], iterator_types = ["parallel", "parallel"]} ins(%arg0, %arg2 : tensor<2x3x!TFHE.glwe<{_,_,_}{2}>>, tensor<2x3xindex>) outs(%0 : tensor<2x3x!TFHE.glwe<{_,_,_}{2}>>) {
//CHECK-NEXT: ^bb0(%arg3: !TFHE.glwe<{_,_,_}{2}>, %[[LUTIDX:.*]]: index, %arg5: !TFHE.glwe<{_,_,_}{2}>): // no predecessors
//DISABLED-CHECK-NEXT: %[[V3:.*]] = tensor.extract_slice %arg1[%[[LUTIDX]], 0] [1, 4] [1, 1] : tensor<5x4xi64> to tensor<4xi64>
//WORKAROUND BEGIN
//CHECK-NEXT: %[[E0:.*]] = tensor.extract %[[LUTS]][%[[LUTIDX]], %[[C0]]] : tensor<5x4xi64>
//CHECK-NEXT: %[[E1:.*]] = tensor.extract %[[LUTS]][%[[LUTIDX]], %[[C1]]] : tensor<5x4xi64>
//CHECK-NEXT: %[[E2:.*]] = tensor.extract %[[LUTS]][%[[LUTIDX]], %[[C2]]] : tensor<5x4xi64>
//CHECK-NEXT: %[[E3:.*]] = tensor.extract %[[LUTS]][%[[LUTIDX]], %[[C3]]] : tensor<5x4xi64>
//CHECK-NEXT: %[[LUT:.*]] = tensor.from_elements %[[E0]], %[[E1]], %[[E2]], %[[E3]] : tensor<4xi64>
//WORKAROUND END
//CHECK-NEXT: %[[V4:.*]] = "TFHE.apply_lookup_table"(%arg3, %[[LUT]]) {baseLogBS = -1 : i32, baseLogKS = -1 : i32, glweDimension = -1 : i32, levelBS = -1 : i32, levelKS = -1 : i32, outputSizeKS = -1 : i32, polynomialSize = -1 : i32} : (!TFHE.glwe<{_,_,_}{2}>, tensor<4xi64>) -> !TFHE.glwe<{_,_,_}{2}>
//CHECK-NEXT: linalg.yield %[[V4]] : !TFHE.glwe<{_,_,_}{2}>
//CHECK-NEXT: } -> tensor<2x3x!TFHE.glwe<{_,_,_}{2}>>
//CHECK-NEXT: return %[[V1]] : tensor<2x3x!TFHE.glwe<{_,_,_}{2}>>
//CHECK-NEXT: }
//CHECK-NEXT: }
func @mapped_lut(%t: tensor<2x3x!FHE.eint<2>>, %luts: tensor<5x4xi64>, %map: tensor<2x3xindex>) -> tensor<2x3x!FHE.eint<2>> {
%1 = "FHELinalg.apply_mapped_lookup_table"(%t, %luts, %map): (tensor<2x3x!FHE.eint<2>>, tensor<5x4xi64>, tensor<2x3xindex>) -> tensor<2x3x!FHE.eint<2>>
return %1: tensor<2x3x!FHE.eint<2>>
}

View File

@@ -0,0 +1,10 @@
// RUN: concretecompiler %s --action=roundtrip 2>&1 | FileCheck %s
//CHECK: func @multi_lut(%[[A0:.*]]: tensor<4x4x!FHE.eint<2>>, %[[A1:.*]]: tensor<4x4x4xi64>) -> tensor<4x4x!FHE.eint<2>> {
//CHECK-NEXT: %[[V0:.*]] = "FHELinalg.apply_multi_lookup_table"(%[[A0]], %[[A1]]) : (tensor<4x4x!FHE.eint<2>>, tensor<4x4x4xi64>) -> tensor<4x4x!FHE.eint<2>>
//CHECK-NEXT: return %[[V0]] : tensor<4x4x!FHE.eint<2>>
//CHECK-NEXT: }
func @multi_lut(%arg0: tensor<4x4x!FHE.eint<2>>, %arg1: tensor<4x4x4xi64>) -> tensor<4x4x!FHE.eint<2>> {
%1 = "FHELinalg.apply_multi_lookup_table"(%arg0, %arg1): (tensor<4x4x!FHE.eint<2>>, tensor<4x4x4xi64>) -> tensor<4x4x!FHE.eint<2>>
return %1: tensor<4x4x!FHE.eint<2>>
}

View File

@@ -0,0 +1,10 @@
// RUN: concretecompiler %s --action=roundtrip 2>&1 | FileCheck %s
//CHECK: func @multi_lut(%[[A0:.*]]: tensor<4x3x!FHE.eint<2>>, %[[A1:.*]]: tensor<3x4xi64>) -> tensor<4x3x!FHE.eint<2>> {
//CHECK-NEXT: %[[V0:.*]] = "FHELinalg.apply_multi_lookup_table"(%[[A0]], %[[A1]]) : (tensor<4x3x!FHE.eint<2>>, tensor<3x4xi64>) -> tensor<4x3x!FHE.eint<2>>
//CHECK-NEXT: return %[[V0]] : tensor<4x3x!FHE.eint<2>>
//CHECK-NEXT: }
func @multi_lut(%arg0: tensor<4x3x!FHE.eint<2>>, %arg1: tensor<3x4xi64>) -> tensor<4x3x!FHE.eint<2>> {
%1 = "FHELinalg.apply_multi_lookup_table"(%arg0, %arg1): (tensor<4x3x!FHE.eint<2>>, tensor<3x4xi64>) -> tensor<4x3x!FHE.eint<2>>
return %1: tensor<4x3x!FHE.eint<2>>
}

View File

@@ -1,23 +0,0 @@
// RUN: concretecompiler %s --action=dump-tfhe 2>&1 | FileCheck %s
//CHECK-LABEL: #map0 = affine_map<(d0, d1) -> (d0, d1)>
//CHECK-NEXT: #map1 = affine_map<(d0, d1) -> (d0, d1, 0)>
//CHECK-NEXT: #map2 = affine_map<(d0, d1) -> (d0, d1, 1)>
//CHECK-NEXT: #map3 = affine_map<(d0, d1) -> (d0, d1, 2)>
//CHECK-NEXT: #map4 = affine_map<(d0, d1) -> (d0, d1, 3)>
//CHECK-NEXT: module {
//CHECK-NEXT: func @multi_lut(%arg0: tensor<4x4x!TFHE.glwe<{_,_,_}{2}>>, %arg1: tensor<4x4x4xi64>) -> tensor<4x4x!TFHE.glwe<{_,_,_}{2}>> {
//CHECK-NEXT: %[[V0:.*]] = linalg.init_tensor [4, 4] : tensor<4x4x!TFHE.glwe<{_,_,_}{2}>>
//CHECK-NEXT: %[[V1:.*]] = linalg.generic {indexing_maps = [#map0, #map1, #map2, #map3, #map4, #map0], iterator_types = ["parallel", "parallel"]} ins(%arg0, %arg1, %arg1, %arg1, %arg1 : tensor<4x4x!TFHE.glwe<{_,_,_}{2}>>, tensor<4x4x4xi64>, tensor<4x4x4xi64>, tensor<4x4x4xi64>, tensor<4x4x4xi64>) outs(%[[V0]] : tensor<4x4x!TFHE.glwe<{_,_,_}{2}>>) {
//CHECK-NEXT: ^bb0(%arg2: !TFHE.glwe<{_,_,_}{2}>, %arg3: i64, %arg4: i64, %arg5: i64, %arg6: i64, %arg7: !TFHE.glwe<{_,_,_}{2}>): // no predecessors
//CHECK-NEXT: %[[V2:.*]] = tensor.from_elements %arg3, %arg4, %arg5, %arg6 : tensor<4xi64>
//CHECK-NEXT: %[[V3:.*]] = "TFHE.apply_lookup_table"(%arg2, %[[V2]]) {baseLogBS = -1 : i32, baseLogKS = -1 : i32, glweDimension = -1 : i32, levelBS = -1 : i32, levelKS = -1 : i32, outputSizeKS = -1 : i32, polynomialSize = -1 : i32} : (!TFHE.glwe<{_,_,_}{2}>, tensor<4xi64>) -> !TFHE.glwe<{_,_,_}{2}>
//CHECK-NEXT: linalg.yield %[[V3]] : !TFHE.glwe<{_,_,_}{2}>
//CHECK-NEXT: } -> tensor<4x4x!TFHE.glwe<{_,_,_}{2}>>
//CHECK-NEXT: return %[[V1]] : tensor<4x4x!TFHE.glwe<{_,_,_}{2}>>
//CHECK-NEXT: }
//CHECK-NEXT: }
func @multi_lut(%arg0: tensor<4x4x!FHE.eint<2>>, %arg1: tensor<4x4x4xi64>) -> tensor<4x4x!FHE.eint<2>> {
%1 = "FHELinalg.apply_multi_lookup_table"(%arg0, %arg1): (tensor<4x4x!FHE.eint<2>>, tensor<4x4x4xi64>) -> tensor<4x4x!FHE.eint<2>>
return %1: tensor<4x4x!FHE.eint<2>>
}

View File

@@ -1,23 +0,0 @@
// RUN: concretecompiler %s --action=dump-tfhe 2>&1 | FileCheck %s
//CHECK-LABEL: #map0 = affine_map<(d0, d1) -> (d0, d1)>
//CHECK-NEXT: #map1 = affine_map<(d0, d1) -> (d1, 0)>
//CHECK-NEXT: #map2 = affine_map<(d0, d1) -> (d1, 1)>
//CHECK-NEXT: #map3 = affine_map<(d0, d1) -> (d1, 2)>
//CHECK-NEXT: #map4 = affine_map<(d0, d1) -> (d1, 3)>
//CHECK-NEXT: module {
//CHECK-NEXT: func @multi_lut(%arg0: tensor<4x3x!TFHE.glwe<{_,_,_}{2}>>, %arg1: tensor<3x4xi64>) -> tensor<4x3x!TFHE.glwe<{_,_,_}{2}>> {
//CHECK-NEXT: %[[V0:.*]] = linalg.init_tensor [4, 3] : tensor<4x3x!TFHE.glwe<{_,_,_}{2}>>
//CHECK-NEXT: %[[V1:.*]] = linalg.generic {indexing_maps = [#map0, #map1, #map2, #map3, #map4, #map0], iterator_types = ["parallel", "parallel"]} ins(%arg0, %arg1, %arg1, %arg1, %arg1 : tensor<4x3x!TFHE.glwe<{_,_,_}{2}>>, tensor<3x4xi64>, tensor<3x4xi64>, tensor<3x4xi64>, tensor<3x4xi64>) outs(%[[V0]] : tensor<4x3x!TFHE.glwe<{_,_,_}{2}>>) {
//CHECK-NEXT: ^bb0(%arg2: !TFHE.glwe<{_,_,_}{2}>, %arg3: i64, %arg4: i64, %arg5: i64, %arg6: i64, %arg7: !TFHE.glwe<{_,_,_}{2}>): // no predecessors
//CHECK-NEXT: %[[V2:.*]] = tensor.from_elements %arg3, %arg4, %arg5, %arg6 : tensor<4xi64>
//CHECK-NEXT: %[[V3:.*]] = "TFHE.apply_lookup_table"(%arg2, %[[V2]]) {baseLogBS = -1 : i32, baseLogKS = -1 : i32, glweDimension = -1 : i32, levelBS = -1 : i32, levelKS = -1 : i32, outputSizeKS = -1 : i32, polynomialSize = -1 : i32} : (!TFHE.glwe<{_,_,_}{2}>, tensor<4xi64>) -> !TFHE.glwe<{_,_,_}{2}>
//CHECK-NEXT: linalg.yield %[[V3]] : !TFHE.glwe<{_,_,_}{2}>
//CHECK-NEXT: } -> tensor<4x3x!TFHE.glwe<{_,_,_}{2}>>
//CHECK-NEXT: return %[[V1]] : tensor<4x3x!TFHE.glwe<{_,_,_}{2}>>
//CHECK-NEXT: }
//CHECK-NEXT: }
func @multi_lut(%arg0: tensor<4x3x!FHE.eint<2>>, %arg1: tensor<3x4xi64>) -> tensor<4x3x!FHE.eint<2>> {
%1 = "FHELinalg.apply_multi_lookup_table"(%arg0, %arg1): (tensor<4x3x!FHE.eint<2>>, tensor<3x4xi64>) -> tensor<4x3x!FHE.eint<2>>
return %1: tensor<4x3x!FHE.eint<2>>
}

View File

@@ -1,9 +0,0 @@
// RUN: concretecompiler --split-input-file --verify-diagnostics --action=roundtrip %s
// Bad dimension of the lookup table
func @apply_lookup_table(%arg0: !TFHE.glwe<{1024,12,64}{7}>, %arg1: tensor<4xi2>) -> !TFHE.glwe<{512,10,64}{2}> {
// expected-error @+1 {{'TFHE.apply_lookup_table' op : `l_cst` (operand #2) inner dimension should have size 128(=2^7) to match `ct` (operand #1) elements bitwidth (7)}}
%1 = "TFHE.apply_lookup_table"(%arg0, %arg1) {glweDimension = 1 : i32, polynomialSize = 1024 : i32, levelKS = 2 : i32, baseLogKS = -82 : i32, levelBS = 3 : i32, baseLogBS = -83 : i32, outputSizeKS = 600 : i32}: (!TFHE.glwe<{1024,12,64}{7}>, tensor<4xi2>) -> (!TFHE.glwe<{512,10,64}{2}>)
return %1: !TFHE.glwe<{512,10,64}{2}>
}

View File

@@ -1,10 +0,0 @@
// RUN: concretecompiler --action=roundtrip %s 2>&1| FileCheck %s
// CHECK-LABEL: func @apply_lookup_table(%arg0: !TFHE.glwe<{1024,12,64}{7}>, %arg1: tensor<128xi64>) -> !TFHE.glwe<{512,10,64}{2}>
func @apply_lookup_table(%arg0: !TFHE.glwe<{1024,12,64}{7}>, %arg1: tensor<128xi64>) -> !TFHE.glwe<{512,10,64}{2}> {
// CHECK-NEXT: %[[V1:.*]] = "TFHE.apply_lookup_table"(%arg0, %arg1) {baseLogBS = -83 : i32, baseLogKS = -82 : i32, glweDimension = 1 : i32, levelBS = 3 : i32, levelKS = 2 : i32, outputSizeKS = 600 : i32, polynomialSize = 1024 : i32} : (!TFHE.glwe<{1024,12,64}{7}>, tensor<128xi64>) -> !TFHE.glwe<{512,10,64}{2}>
// CHECK-NEXT: return %[[V1]] : !TFHE.glwe<{512,10,64}{2}>
%1 = "TFHE.apply_lookup_table"(%arg0, %arg1) {glweDimension = 1 : i32, polynomialSize = 1024 : i32, levelKS = 2 : i32, baseLogKS = -82 : i32, levelBS = 3 : i32, baseLogBS = -83 : i32, outputSizeKS = 600 : i32} : (!TFHE.glwe<{1024,12,64}{7}>, tensor<128xi64>) -> (!TFHE.glwe<{512,10,64}{2}>)
return %1: !TFHE.glwe<{512,10,64}{2}>
}

View File

@@ -0,0 +1,25 @@
// RUN: concretecompiler --action=roundtrip %s 2>&1| FileCheck %s
// CHECK: func @keyswitch_glwe(%[[A0:.*]]: !TFHE.glwe<{1,1024,64}{7}>) -> !TFHE.glwe<{1,527,64}{7}>
func @keyswitch_glwe(%arg0: !TFHE.glwe<{1,1024,64}{7}>) -> !TFHE.glwe<{1,527,64}{7}> {
// CHECK-NEXT: %[[V0:.*]] = "TFHE.keyswitch_glwe"(%[[A0]]) {baseLog = 2 : i32, level = 3 : i32} : (!TFHE.glwe<{1,1024,64}{7}>) -> !TFHE.glwe<{1,527,64}{7}>
// CHECK-NEXT: return %[[V0]] : !TFHE.glwe<{1,527,64}{7}
%0 = "TFHE.keyswitch_glwe"(%arg0) {baseLog = 2 : i32, level = 3 : i32} : (!TFHE.glwe<{1,1024,64}{7}>) -> !TFHE.glwe<{1,527,64}{7}>
return %0: !TFHE.glwe<{1,527,64}{7}>
}
// CHECK: func @bootstrap_glwe(%[[GLWE:.*]]: !TFHE.glwe<{1,527,64}{7}>, %[[LUT:.*]]: !TFHE.glwe<{1,527,64}{7}>) -> !TFHE.glwe<{1,1024,64}{7}>
func @bootstrap_glwe(%glwe: !TFHE.glwe<{1,527,64}{7}>, %lookup_table_glwe: !TFHE.glwe<{1,527,64}{7}>) -> !TFHE.glwe<{1,1024,64}{7}> {
// CHECK-NEXT: %[[V0:.*]] = "TFHE.bootstrap_glwe"(%[[GLWE]], %[[LUT]]) {baseLog = 2 : i32, glweDimension = 1 : i32, level = 3 : i32, polynomialSize = 2048 : i32} : (!TFHE.glwe<{1,527,64}{7}>, !TFHE.glwe<{1,527,64}{7}>) -> !TFHE.glwe<{1,1024,64}{7}>
// CHECK-NEXT: return %[[V0]] : !TFHE.glwe<{1,1024,64}{7}>
%0 = "TFHE.bootstrap_glwe"(%glwe, %lookup_table_glwe) {baseLog = 2 : i32, glweDimension = 1 : i32, level = 3 : i32, polynomialSize = 2048 : i32} : (!TFHE.glwe<{1,527,64}{7}>, !TFHE.glwe<{1,527,64}{7}>) -> !TFHE.glwe<{1,1024,64}{7}>
return %0 : !TFHE.glwe<{1,1024,64}{7}>
}
// CHECK: func @glwe_from_table(%[[LUT:.*]]: tensor<128xi64>) -> !TFHE.glwe<{1,1024,64}{7}>
func @glwe_from_table(%lookup_table: tensor<128xi64>) -> !TFHE.glwe<{1,1024,64}{7}> {
// CHECK-NEXT: %[[V0:.*]] = "TFHE.glwe_from_table"(%[[LUT]]) : (tensor<128xi64>) -> !TFHE.glwe<{1,1024,64}{7}>
// CHECK-NEXT: return %[[V0]] : !TFHE.glwe<{1,1024,64}{7}>
%0 = "TFHE.glwe_from_table"(%lookup_table) : (tensor<128xi64>) -> !TFHE.glwe<{1,1024,64}{7}>
return %0 : !TFHE.glwe<{1,1024,64}{7}>
}