From 4ecae140cacbb422026cc14f4e2124549f4d983e Mon Sep 17 00:00:00 2001 From: Quentin Bourgerie Date: Tue, 4 Jan 2022 20:55:18 +0100 Subject: [PATCH] doc(compiler): Enhance FHE Dialect documentation --- .../concretelang/Dialect/FHE/IR/FHEOps.td | 109 +++++++++++++++++- .../concretelang/Dialect/FHE/IR/FHETypes.td | 8 +- compiler/lib/Dialect/FHE/IR/FHEOps.cpp | 14 +-- .../op_apply_lookup_table_bad_dimension.mlir | 2 +- 4 files changed, 120 insertions(+), 13 deletions(-) diff --git a/compiler/include/concretelang/Dialect/FHE/IR/FHEOps.td b/compiler/include/concretelang/Dialect/FHE/IR/FHEOps.td index 4549e600c..643372cd7 100644 --- a/compiler/include/concretelang/Dialect/FHE/IR/FHEOps.td +++ b/compiler/include/concretelang/Dialect/FHE/IR/FHEOps.td @@ -18,9 +18,17 @@ include "concretelang/Dialect/FHE/IR/FHETypes.td" class FHE_Op traits = []> : Op; -// Generates an encrypted zero constant def ZeroEintOp : FHE_Op<"zero", [NoSideEffect]> { - let summary = "Return an encryption of 0"; + let summary = "Returns a trivial encrypted integer of 0"; + + let description = [{ + Returns a trivial encrypted integer of 0 + + Example: + ```mlir + "FHE.zero"() : () -> !FHE.eint<2> + ``` + }]; let arguments = (ins); let results = (outs EncryptedIntegerType:$out); @@ -30,6 +38,22 @@ def AddEintIntOp : FHE_Op<"add_eint_int"> { let summary = "Adds an encrypted integer and a clear integer"; + let description = [{ + Adds an encrypted integer and a clear integer. + The clear integer must have at most one more bit than the encrypted integer + and the result must have the same width than the encrypted integer. + + Example: + ```mlir + // ok + "FHE.add_eint_int"(%a, %i) : (!FHE.eint<2>, i3) -> !FHE.eint<2> + + // error + "FHE.add_eint_int"(%a, %i) : (!FHE.eint<2>, i4) -> !FHE.eint<2> + "FHE.add_eint_int"(%a, %i) : (!FHE.eint<2>, i3) -> !FHE.eint<3> + ``` + }]; + let arguments = (ins EncryptedIntegerType:$a, AnyInteger:$b); let results = (outs EncryptedIntegerType); @@ -48,6 +72,21 @@ def AddEintOp : FHE_Op<"add_eint"> { let summary = "Adds two encrypted integers"; + let description = [{ + Adds two encrypted integers + The encrypted integers and the result must have the same width. + + Example: + ```mlir + // ok + "FHE.add_eint"(%a, %b): (!FHE.eint<2>, !FHE.eint<2>) -> (!FHE.eint<2>) + + // error + "FHE.add_eint"(%a, %b): (!FHE.eint<2>, !FHE.eint<3>) -> (!FHE.eint<2>) + "FHE.add_eint"(%a, %b): (!FHE.eint<2>, !FHE.eint<2>) -> (!FHE.eint<3>) + ``` + }]; + let arguments = (ins EncryptedIntegerType:$a, EncryptedIntegerType:$b); let results = (outs EncryptedIntegerType); @@ -66,6 +105,22 @@ def SubIntEintOp : FHE_Op<"sub_int_eint"> { let summary = "Substract a clear integer and an encrypted integer"; + let description = [{ + Substract a clear integer and an encrypted integer. + The clear integer must have at most one more bit than the encrypted integer + and the result must have the same width than the encrypted integer. + + Example: + ```mlir + // ok + "FHE.sub_int_eint"(%i, %a) : (i3, !FHE.eint<2>) -> !FHE.eint<2> + + // error + "FHE.sub_int_eint"(%i, %a) : (i4, !FHE.eint<2>) -> !FHE.eint<2> + "FHE.sub_int_eint"(%i, %a) : (i3, !FHE.eint<2>) -> !FHE.eint<3> + ``` + }]; + let arguments = (ins AnyInteger:$a, EncryptedIntegerType:$b); let results = (outs EncryptedIntegerType); @@ -84,6 +139,20 @@ def NegEintOp : FHE_Op<"neg_eint"> { let summary = "Negates an encrypted integer"; + let description = [{ + Negates an encrypted integer. + The result must have the same width than the encrypted integer. + + Example: + ```mlir + // ok + "FHE.neg_eint"(%a): (!FHE.eint<2>) -> (!FHE.eint<2>) + + // error + "FHE.neg_eint"(%a): (!FHE.eint<2>) -> (!FHE.eint<3>) + ``` + }]; + let arguments = (ins EncryptedIntegerType:$a); let results = (outs EncryptedIntegerType); @@ -102,6 +171,22 @@ def MulEintIntOp : FHE_Op<"mul_eint_int"> { let summary = "Mulitplies an encrypted integer and a clear integer"; + let description = [{ + Mulitplies an encrypted integer and a clear integer. + The clear integer must have at most one more bit than the encrypted integer + and the result must have the same width than the encrypted integer. + + Example: + ```mlir + // ok + "FHE.mul_eint_int"(%a, %i) : (!FHE.eint<2>, i3) -> !FHE.eint<2> + + // error + "FHE.mul_eint_int"(%a, %i) : (!FHE.eint<2>, i4) -> !FHE.eint<2> + "FHE.mul_eint_int"(%a, %i) : (!FHE.eint<2>, i3) -> !FHE.eint<3> + ``` + }]; + let arguments = (ins EncryptedIntegerType:$a, AnyInteger:$b); let results = (outs EncryptedIntegerType); @@ -120,8 +205,24 @@ def ApplyLookupTableEintOp : FHE_Op<"apply_lookup_table"> { let summary = "Applies a clear lookup table to an encrypted integer"; - let arguments = (ins EncryptedIntegerType:$ct, - TensorOf<[AnyInteger]>:$l_cst); + let description = [{ + Applies a clear lookup table to an encrypted integer, the width of the result can be different than the width of the operand. + The lookup table must be a tensor of size equals to `2^p` where `p` is the width of the encrypted integer. + + Example: + ```mlir + // ok + "FHE.apply_lookup_table"(%a, %lut): (!FHE.eint<2>, tensor<4xi64>) -> (!FHE.eint<2>) + "FHE.apply_lookup_table"(%a, %lut): (!FHE.eint<2>, tensor<4xi64>) -> (!FHE.eint<3>) + "FHE.apply_lookup_table"(%a, %lut): (!FHE.eint<3>, tensor<4xi64>) -> (!FHE.eint<2>) + + // error + "FHE.apply_lookup_table"(%a, %lut): (!FHE.eint<2>, tensor<8xi64>) -> (!FHE.eint<2>) + ``` + }]; + + let arguments = (ins EncryptedIntegerType:$a, + TensorOf<[AnyInteger]>:$lut); let results = (outs EncryptedIntegerType); let verifier = [{ diff --git a/compiler/include/concretelang/Dialect/FHE/IR/FHETypes.td b/compiler/include/concretelang/Dialect/FHE/IR/FHETypes.td index 0a4a25ba0..7ed0ccacc 100644 --- a/compiler/include/concretelang/Dialect/FHE/IR/FHETypes.td +++ b/compiler/include/concretelang/Dialect/FHE/IR/FHETypes.td @@ -14,7 +14,13 @@ def EncryptedIntegerType : FHE_Type<"EncryptedInteger", let summary = "An encrypted integer"; let description = [{ - An encrypted integer with clear precision of width. + An encrypted integer with `width` bits to performs FHE Operations. + + Examples: + ```mlir + !FHE.eint<7> + !FHE.eint<6> + ``` }]; let parameters = (ins "unsigned":$width); diff --git a/compiler/lib/Dialect/FHE/IR/FHEOps.cpp b/compiler/lib/Dialect/FHE/IR/FHEOps.cpp index 21f3a698e..6b0ab6b25 100644 --- a/compiler/lib/Dialect/FHE/IR/FHEOps.cpp +++ b/compiler/lib/Dialect/FHE/IR/FHEOps.cpp @@ -107,20 +107,20 @@ bool verifyEncryptedIntegerInputsConsistency(::mlir::OpState &op, } ::mlir::LogicalResult verifyApplyLookupTable(ApplyLookupTableEintOp &op) { - auto ct = op.ct().getType().cast(); - auto l_cst = op.l_cst().getType().cast(); + auto ct = op.a().getType().cast(); + auto lut = op.lut().getType().cast(); auto result = op.getResult().getType().cast(); - // Check the shape of l_cst argument + // Check the shape of lut argument auto width = ct.getWidth(); auto expectedSize = 1 << width; - auto lCstShape = l_cst.getShape(); + auto lCstShape = lut.getShape(); mlir::SmallVector expectedShape{expectedSize}; - if (!l_cst.hasStaticShape(expectedShape)) { - emitErrorBadLutSize(op, "l_cst", "ct", expectedSize, width); + if (!lut.hasStaticShape(expectedShape)) { + emitErrorBadLutSize(op, "lut", "ct", expectedSize, width); return mlir::failure(); } - if (!l_cst.getElementType().isInteger(64)) { + if (!lut.getElementType().isInteger(64)) { op.emitOpError() << "should have the i64 constant"; return mlir::failure(); } diff --git a/compiler/tests/Dialect/FHE/FHE/op_apply_lookup_table_bad_dimension.mlir b/compiler/tests/Dialect/FHE/FHE/op_apply_lookup_table_bad_dimension.mlir index 8739451ac..f6e33ea8f 100644 --- a/compiler/tests/Dialect/FHE/FHE/op_apply_lookup_table_bad_dimension.mlir +++ b/compiler/tests/Dialect/FHE/FHE/op_apply_lookup_table_bad_dimension.mlir @@ -1,6 +1,6 @@ // RUN: not concretecompiler --action=roundtrip %s 2>&1| FileCheck %s -// CHECK-LABEL: error: 'FHE.apply_lookup_table' op : `l_cst` (operand #2) inner dimension should have size 4(=2^2) to match `ct` (operand #1) elements bitwidth (2) +// CHECK-LABEL: error: 'FHE.apply_lookup_table' op : `lut` (operand #2) inner dimension should have size 4(=2^2) to match `ct` (operand #1) elements bitwidth (2) func @apply_lookup_table(%arg0: !FHE.eint<2>, %arg1: tensor<8xi3>) -> !FHE.eint<2> { %1 = "FHE.apply_lookup_table"(%arg0, %arg1): (!FHE.eint<2>, tensor<8xi3>) -> (!FHE.eint<2>) return %1: !FHE.eint<2>