Skip to content
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

MSR-to-ProVerif: Pulling out formula negations #631

Open
wants to merge 9 commits into
base: develop
Choose a base branch
from

Conversation

yavivanov
Copy link
Contributor

Hi!

As requested by @rkunnema, I have implemented a function that pulls the negations in lemma formulas as much to the front as possible. In the ideal case, the function transforms a given formula into a logically equivalent formula that contains only one negation at the formula's start. So, for a given formula F that has negations, we try to obtain a formula in the form ¬F' having only one negation.
The transformation benefits the MSR-to-ProVerif translation by allowing us to translate/analyze the obtained F' with ProVerif.
If such a transformation is not entirely possible for a given formula, the functionality outputs a translation warning showing how far it has transformed the formula.
Note that the translation uses the transformed formula (no matter how far transformed it is).

The changes are confined to the Export.hs file in the export module and only affect the MSR to ProVerif translation.

notsArePulledOut' (Qua _ _ p ) = notsArePulledOut' p
notsArePulledOut' _ = True

pullnots' f = if f /= pullStep f then pullnots' (pullStep f) else f
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yavivanov: What does this function do?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is that pullStep and pullnots' work together to pull the negations to the front. So, I'm going to go into both of them.
pullStep pulls the negations in a sub-formula "one sub-formula/level" to the front once (if that's possible). Essentially, it does only one step to the front wherever possible. This is why the cases where we have negations that we can pull to the front are not recursive - they just pull the negation in the sub-formula one level above and don't go deeper. If no negation can somehow be pulled to the front, then the function returns the same formula without any changes.
pullnots' is what pulls the negations to the front recursively. Originally, all should've been done by pullStep, i.e. the recursion should've been there. The problem was that we recurse on the formula top-down (to smaller sub-formulas), but we change the smaller sub-formulas as we pull the negations. Moreover, we cannot go back up to a bigger sub-formula, see what has changed, pull the negations further (from the level of the larger sub-formula[s] to the level of even larger sub-formulas) and then dive in at where we left. Potentially, we might need to go all the way back to the highest level to be able to pull negations or we need to "wait" for the negations three levels down to be pulled to the same level so that we can pull negations at the current one. I didn't manage to get it to consider such cases during the top-down recursion on the formula. Thus, having everything in pullStep meant that some transformations where not "seen". Thus, I made it so that pullStep does only one step to the front and pullnots' makes sure we exhaustively do all steps and each time consider the results of the different steps.
pullnots' checks if we have pulled all negations as much as possible (if f /= pullStep f). In this case, calling pullStep doesn't pull anything - it returns the same formula again, and so does pullnots' (else-branch). If the formula was changed by the pullStep call, then we have pulled some negations in it one level above their respective levels. Thus, we try to pull the resulting negations in the formula one further level above their respective level (then-branch).

Conn And (Not p) (Not q) -> Not $ p .||. q
Conn Or (Not p) (Not q) -> Not $ p .&&. q
Conn Imp p (Not q) -> Not $ p .&&. q
Conn c p q -> Conn c (pullStep p) (pullStep q)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should exhaustively list the cases here, so if new connectives are added, we do not compute incorrect results. I think this can only be an iff, in which case ... can't we pull the Not out as well, if both sides have it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the Iff case should absolutely be there - I think that I missed it only because I somehow didn't write test formulas with it.

Copy link
Member

@rkunnema rkunnema left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've restructured the code a bit so I can understand it. I've got two comments where I was unsure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants