mirror of
https://github.com/zama-ai/concrete.git
synced 2026-02-09 03:55:04 -05:00
fix(compiler/TFHE): Introduce bootstrap and keyswitch at the TFHE level
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>>
|
||||
}
|
||||
@@ -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>>
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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}>
|
||||
}
|
||||
@@ -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}>
|
||||
}
|
||||
@@ -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}>
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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}>
|
||||
}
|
||||
@@ -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>>
|
||||
}
|
||||
@@ -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>>
|
||||
}
|
||||
@@ -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>>
|
||||
}
|
||||
@@ -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>>
|
||||
}
|
||||
@@ -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>>
|
||||
}
|
||||
@@ -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>>
|
||||
}
|
||||
@@ -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}>
|
||||
}
|
||||
|
||||
@@ -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}>
|
||||
}
|
||||
25
compiler/tests/Dialect/TFHE/TFHE/ops.mlir
Normal file
25
compiler/tests/Dialect/TFHE/TFHE/ops.mlir
Normal 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}>
|
||||
}
|
||||
Reference in New Issue
Block a user