-
Notifications
You must be signed in to change notification settings - Fork 76
BGV: Symbolic Noise Analysis for Dependency Tracking #1817
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the design of these symbolic classes could be improved somewhat.
Some issues I see:
- Storing this map on each instance of this class is quite wasteful.
- The repeated calls to
updateMonomials
andupdateSymbols
seem like they could have performance issues.
I think a more typical design for a symbolic expression system would involve separating the syntax from the semantics in the following sense:
Symbol
is an abstract opaque concept that has a kind and a name, but noparam
. Two symbols are compared for equality purely by their name.Expression
is a syntactic combination of symbols according to one of multiple options. The multivariate polynomial class you made is basically there, but the design choice here would be to separate the evaluation step from the representation of the expression itself.- Another option (which may be simpler and more reusable, but slightly more work right now) would be to represent the symbolic expression more generically as a tree, with leaf nodes for symbols and constants, and interior nodes for add, mul, variance, etc., and then before evaluating it you could identify critical substructures like
Var(s^j e^k)
and collapse them into a distinguished node type.
- Another option (which may be simpler and more reusable, but slightly more work right now) would be to represent the symbolic expression more generically as a tree, with leaf nodes for symbols and constants, and interior nodes for add, mul, variance, etc., and then before evaluating it you could identify critical substructures like
Interpreter
(a new class) provides a mapping from symbols to concrete values, replacing the role of param as a member variable on Symbol, and has anevaluate
method that can evaluate expressions and symbols recursively. An instance of Interpreter would be attached to the noise model and invoked insidetoLogBound
with the concrete parameters known at that time.
With this design, any combination of two symbolic expressions need only concern itself with its internal representation of the expression (i.e., grouping like terms), and the interpreter handles the implementation detail of using NoiseState to run the evaluation (or it could do something else).
In my view, there are going to be a number of places in HEIR that will want symbolic expression trees (operation rebalancer, this noise model, polynomial evaluation lowerings). I think it may be worthwhile to combine all those partial solutions into one shared library, and the design I sketched above would be close to what we do. So having this PR align closer to that ideal is what I'm after.
The basic structure just represents a (leaf-type-agnostic) tree of operations and provides a mechanism to create a visitor using std::visit. This is needed for lower_eval to separate the construction of the lowered arithmetic tree from the materialization of the IR. However, I think it will (with adaptations) be useful for other situations as well: - Symbolic noise analysis in #1817 - To simplify the core routine in operation-balancer (https://github.com/google/heir/blob/b0cf72da113e6c7282733f8ba6bfcb7754a7495c/lib/Transforms/OperationBalancer/OperationBalancer.cpp#L74) PiperOrigin-RevId: 770267746
The basic structure just represents a (leaf-type-agnostic) tree of operations and provides a mechanism to create a visitor using std::visit. This is needed for lower_eval to separate the construction of the lowered arithmetic tree from the materialization of the IR. However, I think it will (with adaptations) be useful for other situations as well: - Symbolic noise analysis in #1817 - To simplify the core routine in operation-balancer (https://github.com/google/heir/blob/b0cf72da113e6c7282733f8ba6bfcb7754a7495c/lib/Transforms/OperationBalancer/OperationBalancer.cpp#L74) PiperOrigin-RevId: 770267746
The basic structure just represents a (leaf-type-agnostic) tree of operations and provides a mechanism to create a visitor using std::visit. This is needed for lower_eval to separate the construction of the lowered arithmetic tree from the materialization of the IR. However, I think it will (with adaptations) be useful for other situations as well: - Symbolic noise analysis in #1817 - To simplify the core routine in operation-balancer (https://github.com/google/heir/blob/b0cf72da113e6c7282733f8ba6bfcb7754a7495c/lib/Transforms/OperationBalancer/OperationBalancer.cpp#L74) PiperOrigin-RevId: 770267746
The basic structure just represents a (leaf-type-agnostic) tree of operations and provides a mechanism to create a visitor using std::visit. This is needed for lower_eval to separate the construction of the lowered arithmetic tree from the materialization of the IR. However, I think it will (with adaptations) be useful for other situations as well: - Symbolic noise analysis in #1817 - To simplify the core routine in operation-balancer (https://github.com/google/heir/blob/b0cf72da113e6c7282733f8ba6bfcb7754a7495c/lib/Transforms/OperationBalancer/OperationBalancer.cpp#L74) PiperOrigin-RevId: 770267746
The basic structure just represents a (leaf-type-agnostic) tree of operations and provides a mechanism to create a visitor using std::visit. This is needed for lower_eval to separate the construction of the lowered arithmetic tree from the materialization of the IR. However, I think it will (with adaptations) be useful for other situations as well: - Symbolic noise analysis in #1817 - To simplify the core routine in operation-balancer (https://github.com/google/heir/blob/b0cf72da113e6c7282733f8ba6bfcb7754a7495c/lib/Transforms/OperationBalancer/OperationBalancer.cpp#L74) PiperOrigin-RevId: 770267746
Status
This PR is intended for the symbolic part
Symbolic.h/Symbolic.cpp
, as this part is big enough.Also it should be rebased after #1816 is in.
The BGV adoption of it is not comprehensive as it only supports addition/multiplication but it is enough to demonstrate along with (#1782, which would be another PR). Its complete version supporting modulus switching/key switching needs another PR regarding
SelectVariableNames
. Its extension to BFV is already in a branch (also needSelectVariableNames
). CKKS noise analysis could also benefit from it but lets wait until all the TODOs in #1685.Backgrounds
Recent attacks like GNSJ24, CCP+24, CSBB24 demonstrated that the ability for noise analysis to handle dependent ciphertext is crucial for security.
These attacks exploited the fact that dependency among ciphertext will lead to faster noise growth, and former average-case analysis is not so able to handle them (strong independency assumption).
This approach could handle it but there are some issues. One obvious issue is that is could not scale-up as the number of symbolic terms grows exponentially with the number of multiplication (though there are some optimizations).
HEIR formerly has a pass called
openfhe-count-add-and-key-switch
in #1254 that could in spirit handle those attacks but it is standalone and not connected to the NoiseAnalysis inside HEIR.Some experiments
Multiplication of Independent ciphertext
MP24 model
Symbol model: able to handle common dependency like secret key and error in public key (namely #1782)
Multiplication of same ciphertext
MP24: the same as above
Symbol: even higher noise
Addition of 4 indep ciphertext
MP24
Symbol (should align with MP24)
Addition of same ciphertext 4 times
MP24 (unable to handle faster growth)
Symbol