set timeout=12.

YUBIKEY

The YubiKey is a simple physical authentication device with a unique button. This device, manufactured by Yubico, allows users to securely authenticate to their accounts by issuing a one-time password (OTP).

In its typical configuration, the YubiKey generates a random OTP by encrypting a secret value and a counter. This message is accepted by the server only if it decrypts under the correct key to a valid secret value containing a counter whose value is larger than the last value accepted by the server for that YubiKey.

In this model, we analyze the security of the protocol as described in [1], assuming that the server remains secure.

Yubico assigns a key k, as well as a public and a secret identifier pid, sid to each YubiKey. The counter cpt inside the YubiKey is incremented whenever the YubiKey is plugged in, as well as when an OTP is generated, i.e. when the button of the YubiKey is pressed. This OTP is obtained by encrypting the counter value and the sid of the YubiKey with the key k.

  • YubiKey -> Server : <pid,<nonce,senc(<sid,cpt>,npr,k)>>

Here, npr is the encryption randomness. The server accepts this message if it decrypts with a legitimate key k, and leads to a valid secret value sid. Lastly, the counter value obtained through decryption has to be larger than the current value stored in the server database. After this exchange, the server updates its counter with the value just received.

COMMENTS

  • The OTP is an encryption of a triple <sid, cpt, npr>. It is modelled here as a randomized encryption of a pair <sid, cpt>. According to the specification in [1], AES is used.

  • In [1], they “over-approximate in the case that the Yubikey increases the session token by allowing the adversary to instantiate the rule for any counter value that is higher than the previous one”. Here, we model the incrementation by 1 of the counter.

SECURITY PROPERTIES

The 3 security properties as stated in [1].

  • Property 1: absence of replay attacks.
  • Property 2: injective correspondence.
  • Property 3: monotonicity.

[1] R. Künnemann, "Foundations for analyzing security APIs in the symbolic and computational model’, 2014.

abstract startplug : message
abstract endplug : message
abstract startpress : message
abstract accept : message
abstract pid : index -> message

name sid : index -> message
name nonce: index -> index -> message.

Public constants (abstract) and names used in the protocol.

senc enc,dec
name k : index -> message
name npr: index -> index -> message.

Symmetric encryption scheme, using the secret key k (with index arity 1 so that each YubiKey is associated to a key) and the random npr (with index arity 2 so that each session of a YubiKey uses a new random name).

abstract myzero : message
abstract myone : message
abstract mySucc : message -> message
abstract orderOk : message
abstract (~<) : message -> message -> message.

Public constants and public functions used to model counter values.

mutable YCpt(i:index): message = myzero
mutable SCpt(i:index): message = myzero.

Mutable cells for the YubiKey and the server, initialized with myzero.

channel cT
channel cR.

Communication channels used in the protocol.

process yubikeyplug(i:index,j:index) =
in(cT, x1);
if x1 = startplug then
YCpt(i) := mySucc(YCpt(i));
out(cT,endplug).

When the key is plugged, its counter is incremented.

process yubikeypress(i:index,j:index) =
in(cT,x2);
if x2 = startpress then
let cpt = YCpt(i) in
YCpt(i) := mySucc(YCpt(i));
out(cT,<pid(i),<nonce(i,j),enc(<sid(i),cpt>,npr(i,j),k(i))>>).

When the key is pressed, an OTP is sent with the current value of the counter and the counter is incremented.

process server(ii:index) =
in(cR,y1);
try find i such that fst(y1) = pid(i) in
if dec(snd(snd(y1)),k(i)) <> fail
&& SCpt(i) ~< snd(dec(snd(snd(y1)),k(i))) = orderOk
then
SCpt(i) := snd(dec(snd(snd(y1)),k(i)));
out(cR,accept).

When the server receives a message, it checks whether it corresponds to a pid in its database, and checks also that the counter inside the OTP is strictly greater than the counter associated to the token. If so, the value inside the OTP is used to update the database. Now, the counter value associated to this token is this new value.

system
((!_i !_j Plug: yubikeyplug(i,j))
| (!_i !_j Press: yubikeypress(i,j))
| (!_ii S: server(ii))).
System before processing:

(!_i !_j Plug: yubikeyplug i j) |
((!_i !_j Press: yubikeypress i j) | (!_ii S: server ii))

System after processing:

(!_i
!_j
in(cT,x1);
if (x1 = startplug) then
YCpt(i) := mySucc(YCpt(i)); Plug: out(cT,endplug); null else
Plug1: null) |
((!_i
!_j
in(cT,x2);
if (x2 = startpress) then
let cpt = YCpt(i) in
YCpt(i) := mySucc(YCpt(i));
Press:
out(cT,
pair(pid(i),
pair(nonce(i,j),enc(pair(sid(i),cpt(i,j)),npr(i,j),k(i)))));
null else Press1: null) |
(!_ii
in(cR,y1);
find (i) such that (fst(y1) = pid(i)) in
if ((dec(snd(snd(y1)),k(i)) <> fail) &&
((SCpt(i) ~< snd(dec(snd(snd(y1)),k(i)))) = orderOk)) then
SCpt(i) := snd(dec(snd(snd(y1)),k(i))); S: out(cR,accept); null
else S1: null else S2: null))

System default registered with actions (init,Plug,Plug1,Press,Press1,S,S1,S2).

In the final system, processes can play in parallel an unbounded number of sessions.

include Basic. Goal eq_sym :
(x = y) = (y = x)
[goal> Focused goal (1/1):
System: any
Type variables: 'a
Variables: x,y:'a
----------------------------------------
(x = y) = (y = x)

[> Line 11: by (rewrite ...)
[goal> Goal eq_sym is proved
Exiting proof mode.


Goal neq_sym :
(x <> y) = (y <> x)
[goal> Focused goal (1/1):
System: any
Type variables: 'a
Variables: x,y:'a
----------------------------------------
(x <> y) = (y <> x)

[> Line 14: by (rewrite ...)
[goal> Goal neq_sym is proved
Exiting proof mode.


Goal eq_refl :
(x = x) = true
[goal> Focused goal (1/1):
System: any
Type variables: 'a
Variables: x:'a
----------------------------------------
(x = x) = true

[> Line 18: by (rewrite ...)
[goal> Goal eq_refl is proved
Exiting proof mode.


Goal false_true :
(false = true) = false
[goal> Focused goal (1/1):
System: any
----------------------------------------
(false = true) = false

[> Line 30: by (rewrite ...)
[goal> Goal false_true is proved
Exiting proof mode.


Goal eq_true :
(b = true) = b
[goal> Focused goal (1/1):
System: any
Variables: b:bool
----------------------------------------
(b = true) = b

[> Line 35: by (case b)
[goal> Goal eq_true is proved
Exiting proof mode.


Goal eq_true2 :
(true = b) = b
[goal> Focused goal (1/1):
System: any
Variables: b:bool
----------------------------------------
(true = b) = b

[> Line 39: by (case b)
[goal> Goal eq_true2 is proved
Exiting proof mode.


Goal not_not :
not(not(b)) = b
[goal> Focused goal (1/1):
System: any
Variables: b:bool
----------------------------------------
not(not(b)) = b

[> Line 54: by (case b)
[goal> Goal not_not is proved
Exiting proof mode.


Goal not_eq :
not(x = y) = (x <> y)
[goal> Focused goal (1/1):
System: any
Type variables: 'a
Variables: x,y:'a
----------------------------------------
not(x = y) = (x <> y)

[> Line 60: by (rewrite ...)
[goal> Goal not_eq is proved
Exiting proof mode.


Goal not_neq :
not(x <> y) = (x = y)
[goal> Focused goal (1/1):
System: any
Type variables: 'a
Variables: x,y:'a
----------------------------------------
not(x <> y) = (x = y)

[> Line 66: by (rewrite ...)
[goal> Goal not_neq is proved
Exiting proof mode.


Goal not_eqfalse :
(b = false) = not(b)
[goal> Focused goal (1/1):
System: any
Variables: b:bool
----------------------------------------
(b = false) = not(b)

[> Line 72: by (case b)
[goal> Goal not_eqfalse is proved
Exiting proof mode.


Goal eq_false :
((x = y) = false) = (x <> y)
[goal> Focused goal (1/1):
System: any
Type variables: 'a
Variables: x,y:'a
----------------------------------------
((x = y) = false) = (x <> y)

[> Line 80: (rewrite ...)
[goal> Focused goal (1/1):
System: any
Type variables: 'a
Variables: x,y:'a
----------------------------------------
((x = y) = false) = not(x = y)

[> Line 80: ((case (x = y));(intro _))
[goal> Focused goal (1/2):
System: any
Type variables: 'a
Variables: x,y:'a
_: x = y
----------------------------------------
(true = false) = not(true)

[> Line 80: simpl
[goal> Focused goal (1/2):
System: any
Type variables: 'a
Variables: x,y:'a
_: x = y
----------------------------------------
true

[> Line 80: auto
[goal> Focused goal (1/1):
System: any
Type variables: 'a
Variables: x,y:'a
_: not(x = y)
----------------------------------------
(false = false) = not(false)

[> Line 81: by (rewrite ...)
[goal> Goal eq_false is proved
Exiting proof mode.


Goal and_true_r :
(b && true) = b
[goal> Focused goal (1/1):
System: any
Variables: b:bool
----------------------------------------
(b && true) = b

[> Line 94: by (rewrite ... ...)
[goal> Goal and_true_r is proved
Exiting proof mode.


Goal and_false_r :
(b && false) = false
[goal> Focused goal (1/1):
System: any
Variables: b:bool
----------------------------------------
(b && false) = false

[> Line 101: by (rewrite ... ...)
[goal> Goal and_false_r is proved
Exiting proof mode.


Goal or_false_r :
(b || false) = b
[goal> Focused goal (1/1):
System: any
Variables: b:bool
----------------------------------------
(b || false) = b

[> Line 112: by (rewrite ... ...)
[goal> Goal or_false_r is proved
Exiting proof mode.


Goal or_true_r :
(b || true) = true
[goal> Focused goal (1/1):
System: any
Variables: b:bool
----------------------------------------
(b || true) = true

[> Line 119: by (rewrite ... ...)
[goal> Goal or_true_r is proved
Exiting proof mode.


Goal not_and :
not((a && b)) = (not(a) || not(b))
[goal> Focused goal (1/1):
System: any
Variables: a,b:bool
----------------------------------------
not((a && b)) = (not(a) || not(b))

[> Line 128: (rewrite ...)
[goal> Focused goal (1/1):
System: any
Variables: a,b:bool
----------------------------------------
not((a && b)) <=> not(a) || not(b)

[> Line 129: (((case a);(case b));(intro //=))
[goal> Goal not_and is proved
Exiting proof mode.


Goal not_or :
not((a || b)) = (not(a) && not(b))
[goal> Focused goal (1/1):
System: any
Variables: a,b:bool
----------------------------------------
not((a || b)) = (not(a) && not(b))

[> Line 134: (rewrite ...)
[goal> Focused goal (1/1):
System: any
Variables: a,b:bool
----------------------------------------
not((a || b)) <=> not(a) && not(b)

[> Line 135: (((case a);(case b));(intro //=))
[goal> Goal not_or is proved
Exiting proof mode.


Goal if_true :
b => if b then x else y = x
[goal> Focused goal (1/1):
System: any
Type variables: 'a
Variables: b:bool,x,y:'a
----------------------------------------
b => if b then x else y = x

[> Line 144: (intro *)
[goal> Focused goal (1/1):
System: any
Type variables: 'a
Variables: b:bool,x,y:'a
H: b
----------------------------------------
if b then x else y = x

[> Line 145: (case if b then x else y)
[goal> Focused goal (1/2):
System: any
Type variables: 'a
Variables: b:bool,x,y:'a
H: b
----------------------------------------
b && if b then x else y = x => x = x

[> Line 146: auto
[goal> Focused goal (1/1):
System: any
Type variables: 'a
Variables: b:bool,x,y:'a
H: b
----------------------------------------
not(b) && if b then x else y = y => y = x

[> Line 147: (intro [HH _])
[goal> Focused goal (1/1):
System: any
Type variables: 'a
Variables: b:bool,x,y:'a
H: b
HH: not(b)
_: if b then x else y = y
----------------------------------------
y = x

[> Line 147: by (have ... as )
[goal> Goal if_true is proved
Exiting proof mode.


Goal if_true0 :
if true then x else y = x
[goal> Focused goal (1/1):
System: any
Type variables: 'a
Variables: x,y:'a
----------------------------------------
if true then x else y = x

[> Line 153: by (rewrite ...)
[goal> Goal if_true0 is proved
Exiting proof mode.


Goal if_false :
not(b) => if b then x else y = y
[goal> Focused goal (1/1):
System: any
Type variables: 'a
Variables: b:bool,x,y:'a
----------------------------------------
not(b) => if b then x else y = y

[> Line 160: ((intro *);(case if b then x else y))
[goal> Focused goal (1/2):
System: any
Type variables: 'a
Variables: b:bool,x,y:'a
H: not(b)
----------------------------------------
b && if b then x else y = x => x = y

[> Line 161: (intro [HH _])
[goal> Focused goal (1/2):
System: any
Type variables: 'a
Variables: b:bool,x,y:'a
H: not(b)
HH: b
_: if b then x else y = x
----------------------------------------
x = y

[> Line 161: by (have ... as )
[goal> Focused goal (1/1):
System: any
Type variables: 'a
Variables: b:bool,x,y:'a
H: not(b)
----------------------------------------
not(b) && if b then x else y = y => y = y

[> Line 162: auto
[goal> Goal if_false is proved
Exiting proof mode.


Goal if_false0 :
if false then x else y = y
[goal> Focused goal (1/1):
System: any
Type variables: 'a
Variables: x,y:'a
----------------------------------------
if false then x else y = y

[> Line 168: by (rewrite ...)
[goal> Goal if_false0 is proved
Exiting proof mode.


Goal if_then_then :
if b then if b' then x else y else y = if (b && b') then x else y
[goal> Focused goal (1/1):
System: any
Type variables: 'a
Variables: b,b':bool,x,y:'a
----------------------------------------
if b then if b' then x else y else y = if (b && b') then x else y

[> Line 175: by ((case b);(case b'))
[goal> Goal if_then_then is proved
Exiting proof mode.


Goal if_then_implies :
if b then if b' then x else y else z =
if b then if (b => b') then x else y else z
[goal> Focused goal (1/1):
System: any
Type variables: 'a
Variables: b,b':bool,x,y,z:'a
----------------------------------------
if b then if b' then x else y else z =
if b then if (b => b') then x else y else z

[> Line 182: ((case b);
((intro H);((case b');((intro H');(simpl;(try auto))))))

[goal> Focused goal (1/2):
System: any
Type variables: 'a
Variables: b,b':bool,x,y,z:'a
H: b
H': b'
----------------------------------------
x = if (true => true) then x else y

[> Line 183: by (rewrite ...)
[goal> Focused goal (1/1):
System: any
Type variables: 'a
Variables: b,b':bool,x,y,z:'a
H: b
H': not(b')
----------------------------------------
y = if (true => false) then x else y

[> Line 184: (rewrite ...)
[goal> Focused goal (1/2):
System: any
Type variables: 'a
Variables: b,b':bool,x,y,z:'a
H: b
H': not(b')
----------------------------------------
not((true => false))

[> Line 185: ((intro Habs);by (have ... as ))
[goal> Focused goal (1/1):
System: any
Type variables: 'a
Variables: b,b':bool,x,y,z:'a
H: b
H': not(b')
----------------------------------------
y = y

[> Line 186: auto
[goal> Goal if_then_implies is proved
Exiting proof mode.


Goal if_same :
if b then x else x = x
[goal> Focused goal (1/1):
System: any
Type variables: 'a
Variables: b:bool,x:'a
----------------------------------------
if b then x else x = x

[> Line 192: by (case b)
[goal> Goal if_same is proved
Exiting proof mode.


Goal if_then :
b = b' => if b then if b' then x else y else z = if b then x else z
[goal> Focused goal (1/1):
System: any
Type variables: 'a
Variables: b,b':bool,x,y,z:'a
----------------------------------------
b = b' => if b then if b' then x else y else z = if b then x else z

[> Line 201: by ((intro ->);(case b'))
[goal> Goal if_then is proved
Exiting proof mode.


Goal if_else :
b = b' => if b then x else if b' then y else z = if b then x else z
[goal> Focused goal (1/1):
System: any
Type variables: 'a
Variables: b,b':bool,x,y,z:'a
----------------------------------------
b = b' => if b then x else if b' then y else z = if b then x else z

[> Line 210: by ((intro ->);(case b'))
[goal> Goal if_else is proved
Exiting proof mode.


Goal if_then_not :
b = not(b') => if b then if b' then x else y else z = if b then y else z
[goal> Focused goal (1/1):
System: any
Type variables: 'a
Variables: b,b':bool,x,y,z:'a
----------------------------------------
b = not(b') => if b then if b' then x else y else z = if b then y else z

[> Line 219: by ((intro ->);(case b'))
[goal> Goal if_then_not is proved
Exiting proof mode.


Goal if_else_not :
b = not(b') => if b then x else if b' then y else z = if b then x else y
[goal> Focused goal (1/1):
System: any
Type variables: 'a
Variables: b,b':bool,x,y,z:'a
----------------------------------------
b = not(b') => if b then x else if b' then y else z = if b then x else y

[> Line 228: by ((intro ->);(case b'))
[goal> Goal if_else_not is proved
Exiting proof mode.


Goal fst_pair :
fst(<x,y>) = x
[goal> Focused goal (1/1):
System: any
Variables: x,y:message
----------------------------------------
fst(<x,y>) = x

[> Line 236: auto
[goal> Goal fst_pair is proved
Exiting proof mode.


Goal snd_pair :
snd(<x,y>) = y
[goal> Focused goal (1/1):
System: any
Variables: x,y:message
----------------------------------------
snd(<x,y>) = y

[> Line 240: auto
[goal> Goal snd_pair is proved
Exiting proof mode.


Goal iff_refl :
(x <=> x) = true
[goal> Focused goal (1/1):
System: any
Variables: x:bool
----------------------------------------
(x <=> x) = true

[> Line 248: by (rewrite ...)
[goal> Goal iff_refl is proved
Exiting proof mode.


Goal iff_sym :
(x <=> y) = (y <=> x)
[goal> Focused goal (1/1):
System: any
Variables: x,y:bool
----------------------------------------
(x <=> y) = (y <=> x)

[> Line 254: by (rewrite ...)
[goal> Goal iff_sym is proved
Exiting proof mode.


Goal true_iff_false :
(true <=> false) = false
[goal> Focused goal (1/1):
System: any
----------------------------------------
(true <=> false) = false

[> Line 259: by (rewrite ...)
[goal> Goal true_iff_false is proved
Exiting proof mode.


Goal false_iff_true :
(false <=> true) = false
[goal> Focused goal (1/1):
System: any
----------------------------------------
(false <=> true) = false

[> Line 265: by (rewrite ...)
[goal> Goal false_iff_true is proved
Exiting proof mode.


Goal exists_false1 :
(exists (a:'a), false) = false
[goal> Focused goal (1/1):
System: any
Type variables: 'a
----------------------------------------
(exists (a:'a), false) = false

[> Line 277: by (rewrite ...)
[goal> Goal exists_false1 is proved
Exiting proof mode.


Goal exists_false2 :
(exists (a:'a,b:'b), false) = false
[goal> Focused goal (1/1):
System: any
Type variables: 'a, 'b
----------------------------------------
(exists (a:'a,b:'b), false) = false

[> Line 281: by (rewrite ...)
[goal> Goal exists_false2 is proved
Exiting proof mode.


Goal exists_false3 :
(exists (a:'a,b:'b,c:'c), false) = false
[goal> Focused goal (1/1):
System: any
Type variables: 'a, 'b, 'c
----------------------------------------
(exists (a:'a,b:'b,c:'c), false) = false

[> Line 285: by (rewrite ...)
[goal> Goal exists_false3 is proved
Exiting proof mode.


Goal exists_false4 :
(exists (a:'a,b:'b,c:'c,d:'d), false) = false
[goal> Focused goal (1/1):
System: any
Type variables: 'a, 'b, 'c, 'd
----------------------------------------
(exists (a:'a,b:'b,c:'c,d:'d), false) = false

[> Line 289: by (rewrite ...)
[goal> Goal exists_false4 is proved
Exiting proof mode.


Goal exists_false5 :
(exists (a:'a,b:'b,c:'c,d:'d,e:'e), false) = false
[goal> Focused goal (1/1):
System: any
Type variables: 'a, 'b, 'c, 'd, 'e
----------------------------------------
(exists (a:'a,b:'b,c:'c,d:'d,e:'e), false) = false

[> Line 293: by (rewrite ...)
[goal> Goal exists_false5 is proved
Exiting proof mode.


Goal exists_false6 :
(exists (a:'a,b:'b,c:'c,d:'d,e:'e,f:'f), false) = false
[goal> Focused goal (1/1):
System: any
Type variables: 'a, 'b, 'c, 'd, 'e, 'f
----------------------------------------
(exists (a:'a,b:'b,c:'c,d:'d,e:'e,f:'f), false) = false

[> Line 297: by (rewrite ...)
[goal> Goal exists_false6 is proved
Exiting proof mode.


Goal forall_true1 :
(forall (a:'a), true) = true
[goal> Focused goal (1/1):
System: any
Type variables: 'a
----------------------------------------
(forall (a:'a), true) = true

[> Line 307: auto
[goal> Goal forall_true1 is proved
Exiting proof mode.


Goal forall_true2 :
(forall (a:'a,b:'b), true) = true
[goal> Focused goal (1/1):
System: any
Type variables: 'a, 'b
----------------------------------------
(forall (a:'a,b:'b), true) = true

[> Line 311: auto
[goal> Goal forall_true2 is proved
Exiting proof mode.


Goal forall_true3 :
(forall (a:'a,b:'b,c:'c), true) = true
[goal> Focused goal (1/1):
System: any
Type variables: 'a, 'b, 'c
----------------------------------------
(forall (a:'a,b:'b,c:'c), true) = true

[> Line 315: auto
[goal> Goal forall_true3 is proved
Exiting proof mode.


Goal forall_true4 :
(forall (a:'a,b:'b,c:'c,d:'d), true) = true
[goal> Focused goal (1/1):
System: any
Type variables: 'a, 'b, 'c, 'd
----------------------------------------
(forall (a:'a,b:'b,c:'c,d:'d), true) = true

[> Line 319: auto
[goal> Goal forall_true4 is proved
Exiting proof mode.


Goal forall_true5 :
(forall (a:'a,b:'b,c:'c,d:'d,e:'e), true) = true
[goal> Focused goal (1/1):
System: any
Type variables: 'a, 'b, 'c, 'd, 'e
----------------------------------------
(forall (a:'a,b:'b,c:'c,d:'d,e:'e), true) = true

[> Line 323: auto
[goal> Goal forall_true5 is proved
Exiting proof mode.


Goal forall_true6 :
(forall (a:'a,b:'b,c:'c,d:'d,e:'e,f:'f), true) = true
[goal> Focused goal (1/1):
System: any
Type variables: 'a, 'b, 'c, 'd, 'e, 'f
----------------------------------------
(forall (a:'a,b:'b,c:'c,d:'d,e:'e,f:'f), true) = true

[> Line 327: auto
[goal> Goal forall_true6 is proved
Exiting proof mode.


[warning> loaded: Basic.sp <]

LIBRARIES

We include here some libraries, useful to help the tool with automated reasoning.



goal dec_enc (x,y,z:message) : dec(enc(x,z,y),y) = x.
Goal dec_enc :
dec(enc(x,z,y),y) = x

Proof.
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: x,y,z:message
----------------------------------------
dec(enc(x,z,y),y) = x

auto. [> Line 140: auto
[goal> Goal dec_enc is proved
Qed. Exiting proof mode.



hint rewrite dec_enc.


goal fst_apply (x,y : message) : x = y => fst(x) = fst(y).
Goal fst_apply :
x = y => fst(x) = fst(y)

Proof.
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: x,y:message
----------------------------------------
x = y => fst(x) = fst(y)

auto. [> Line 144: auto
[goal> Goal fst_apply is proved
Qed. Exiting proof mode.




goal snd_apply (x,y : message) : x = y => snd(x) = snd(y).
Goal snd_apply :
x = y => snd(x) = snd(y)

Proof.
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: x,y:message
----------------------------------------
x = y => snd(x) = snd(y)

auto. [> Line 147: auto
[goal> Goal snd_apply is proved
Qed. Exiting proof mode.




goal dec_apply (x,y,x1,y1 : message) :
x = y => x1 = y1 => dec(x,x1) = dec(y,y1).
Goal dec_apply :
x = y => x1 = y1 => dec(x,x1) = dec(y,y1)

Proof.
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: x,x1,y,y1:message
----------------------------------------
x = y => x1 = y1 => dec(x,x1) = dec(y,y1)

auto. [> Line 151: auto
[goal> Goal dec_apply is proved
Qed. Exiting proof mode.


axiom orderTrans (n1,n2,n3:message):
n1 ~< n2 = orderOk => n2 ~< n3 = orderOk => n1 ~< n3 = orderOk.

AXIOMS

The following axioms are used to reason on counter values.



axiom orderStrict (n1,n2:message):
n1 = n2 => n1 ~< n2 <> orderOk.


axiom orderSucc (n1,n2:message):
n1 = n2 => n1 ~< mySucc(n2) = orderOk.
goal counterIncreaseStrictly (ii,i:index):
happens(S(ii,i)) =>
cond@S(ii,i) =>
SCpt(i)@pred(S(ii,i)) ~< SCpt(i)@S(ii,i) = orderOk.
Goal counterIncreaseStrictly :
happens(S(ii,i)) =>
cond@S(ii,i) => SCpt(i)@pred(S(ii,i)) ~< SCpt(i)@S(ii,i) = orderOk

HELPING LEMMAS

We now prove some properties on the counter on the server side, used later in the proofs of the security properties.


The counter SCpt(i) strictly increases at each action S performed by the server with tag i.

Proof. [goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii:index
----------------------------------------
happens(S(ii,i)) =>
cond@S(ii,i) => SCpt(i)@pred(S(ii,i)) ~< SCpt(i)@S(ii,i) = orderOk

The proof is automatically done by Squirrel.

auto. [> Line 180: auto
[goal> Goal counterIncreaseStrictly is proved
Qed. Exiting proof mode.


goal counterIncrease (t:timestamp, i : index) :
happens(t) =>
(t > init && exec@t) =>
(SCpt(i)@pred(t) ~< SCpt(i)@t = orderOk) ||
SCpt(i)@t = SCpt(i)@pred(t).
Goal counterIncrease :
happens(t) =>
t > init && exec@t =>
SCpt(i)@pred(t) ~< SCpt(i)@t = orderOk || SCpt(i)@t = SCpt(i)@pred(t)

The counter SCpt(i) increases (not strictly) between pred(t) and t.


Proof.
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i:index,t:timestamp
----------------------------------------
happens(t) =>
t > init && exec@t =>
SCpt(i)@pred(t) ~< SCpt(i)@t = orderOk || SCpt(i)@t = SCpt(i)@pred(t)

intro Hap [Ht Hexec]. [> Line 195: (intro Hap [Ht Hexec])
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i:index,t:timestamp
Hap: happens(t)
Hexec: exec@t
Ht: t > init
----------------------------------------
SCpt(i)@pred(t) ~< SCpt(i)@t = orderOk || SCpt(i)@t = SCpt(i)@pred(t)

After having introduced the hypotheses, we perform a case analysis on all possible values that the timestamp t can take. Most cases are trivial and automatically handled by Squirrel (=> //) because most actions do not update SCpt(i) so we automatically have that SCpt(i)@t = SCpt(i)@pred(t).


case t => //.
[> Line 196: ((case t);(intro //))
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i:index,t:timestamp
Hap: happens(t)
Hexec: exec@t
Ht: t > init
----------------------------------------
(exists (ii,i0:index), t = S(ii,i0)) =>
SCpt(i)@pred(t) ~< SCpt(i)@t = orderOk || SCpt(i)@t = SCpt(i)@pred(t)

intro [ii i0 _]. [> Line 202: (intro [ii i0 _])
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,i0,ii:index,t:timestamp
Hap: happens(t)
Hexec: exec@t
Ht: t > init
_: t = S(ii,i0)
----------------------------------------
SCpt(i)@pred(t) ~< SCpt(i)@t = orderOk || SCpt(i)@t = SCpt(i)@pred(t)

Case where t = S(ii,i0): This is the interesting case, where t is an action that updates the mutable cell SCpt(i0). We distinguish two cases: i = i0 and i <> i0.


case (i = i0) => _.
[> Line 203: ((case (i = i0));(intro _))
[goal> Focused goal (1/2):
System: left:default/left, right:default/right
Variables: i,ii:index,t:timestamp
Hap: happens(t)
Hexec: exec@t
Ht: t > init
_: t = S(ii,i)
----------------------------------------
SCpt(i)@pred(t) ~< SCpt(i)@t = orderOk || SCpt(i)@t = SCpt(i)@pred(t)

+ by left. [> Line 207: by left
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,i0,ii:index,t:timestamp
Hap: happens(t)
Hexec: exec@t
Ht: t > init
_: not(i = i0)
_: t = S(ii,i0)
----------------------------------------
SCpt(i)@pred(t) ~< SCpt(i)@t = orderOk || SCpt(i)@t = SCpt(i)@pred(t)

The case i = i0 corresponds to the left disjunct, which is a direct consequence of the condition of the action SCpt(i). This is done automatically by Squirrel.

+ right. [> Line 213: right
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,i0,ii:index,t:timestamp
Hap: happens(t)
Hexec: exec@t
Ht: t > init
_: not(i = i0)
_: t = S(ii,i0)
----------------------------------------
SCpt(i)@t = SCpt(i)@pred(t)

The case i <> i0 corresponds to the right disjunct. When expanding the macro SCpt(i)@t, we notice that it is an if _ then _ else _ term with a condition that is always false. This can be simplified using the rewrite tactic with lemma if_false (which is included in the Basic library.


expand SCpt(i)@t.
[> Line 214: (expand SCpt(i)@t)
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,i0,ii:index,t:timestamp
Hap: happens(t)
Hexec: exec@t
Ht: t > init
_: t = S(ii,i0)
_: not(i = i0)
----------------------------------------
if (i = i0) then snd(dec(snd(snd(input@t)),k(i0))) else SCpt(i)@pred(t) =
SCpt(i)@pred(t)

by rewrite if_false. [> Line 214: by (rewrite ...)
[goal> Goal counterIncrease is proved
Qed. Exiting proof mode.


The two previous tactics can be merged into a single one: by rewrite /SCpt if_false.

goal counterIncreaseBis:
forall (t:timestamp), forall (t':timestamp), forall (i:index),
happens(t) =>
exec@t && t' < t =>
(SCpt(i)@t' ~< SCpt(i)@t = orderOk || SCpt(i)@t = SCpt(i)@t').
Goal counterIncreaseBis :
forall (t,t':timestamp,i:index),
happens(t) =>
exec@t && t' < t =>
SCpt(i)@t' ~< SCpt(i)@t = orderOk || SCpt(i)@t = SCpt(i)@t'

The counter SCpt(i) increases (not strictly) between t' and t when t' < t.

Proof. [goal> Focused goal (1/1):
System: left:default/left, right:default/right
----------------------------------------
forall (t,t':timestamp,i:index),
happens(t) =>
exec@t && t' < t =>
SCpt(i)@t' ~< SCpt(i)@t = orderOk || SCpt(i)@t = SCpt(i)@t'

This proof is done by induction, relying on the previous counterIncrease lemma to prove the induction step.


induction.
[> Line 229: induction
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
----------------------------------------
forall (t:timestamp),
(forall (t0,t':timestamp,i:index),
t0 < t =>
happens(t0) =>
exec@t0 && t' < t0 =>
SCpt(i)@t' ~< SCpt(i)@t0 = orderOk || SCpt(i)@t0 = SCpt(i)@t') =>
forall (t':timestamp,i:index),
happens(t) =>
exec@t && t' < t =>
SCpt(i)@t' ~< SCpt(i)@t = orderOk || SCpt(i)@t = SCpt(i)@t'


intro t IH0 t' i Hap [Hexec Ht'].
[> Line 230: (intro t IH0 t' i Hap [Hexec Ht'])
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i:index,t,t':timestamp
Hap: happens(t)
Hexec: exec@t
Ht': t' < t
IH0: forall (t0,t':timestamp,i:index),
t0 < t =>
happens(t0) =>
exec@t0 && t' < t0 =>
SCpt(i)@t' ~< SCpt(i)@t0 = orderOk || SCpt(i)@t0 = SCpt(i)@t'
----------------------------------------
SCpt(i)@t' ~< SCpt(i)@t = orderOk || SCpt(i)@t = SCpt(i)@t'

assert (t' = pred(t) || t' < pred(t)) as H0;
1: constraints.
[> Line 235: ((have ((t' = pred(t)) || (t' < pred(t))), H0); 1: constraints)
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i:index,t,t':timestamp
H0: t' = pred(t) || t' < pred(t)
Hap: happens(t)
Hexec: exec@t
Ht': t' < t
IH0: forall (t0,t':timestamp,i:index),
t0 < t =>
happens(t0) =>
exec@t0 && t' < t0 =>
SCpt(i)@t' ~< SCpt(i)@t0 = orderOk || SCpt(i)@t0 = SCpt(i)@t'
----------------------------------------
SCpt(i)@t' ~< SCpt(i)@t = orderOk || SCpt(i)@t = SCpt(i)@t'

We introduce a case disjunction t'. Since we already have that t' < t then the constraints tactic allows to close the goal showing that (t' = pred(t) || t' < pred(t)) is indeed satisfied.


case H0.
[> Line 236: (case H0)
[goal> Focused goal (1/2):
System: left:default/left, right:default/right
Variables: i:index,t,t':timestamp
H0: t' = pred(t)
Hap: happens(t)
Hexec: exec@t
Ht': t' < t
IH0: forall (t0,t':timestamp,i:index),
t0 < t =>
happens(t0) =>
exec@t0 && t' < t0 =>
SCpt(i)@t' ~< SCpt(i)@t0 = orderOk || SCpt(i)@t0 = SCpt(i)@t'
----------------------------------------
SCpt(i)@t' ~< SCpt(i)@t = orderOk || SCpt(i)@t = SCpt(i)@t'

+ rewrite !H0. [> Line 243: (rewrite ...)
[goal> Focused goal (1/2):
System: left:default/left, right:default/right
Variables: i:index,t,t':timestamp
H0: t' = pred(t)
Hap: happens(t)
Hexec: exec@t
Ht': t' < t
IH0: forall (t0,t':timestamp,i:index),
t0 < t =>
happens(t0) =>
exec@t0 && t' < t0 =>
SCpt(i)@t' ~< SCpt(i)@t0 = orderOk || SCpt(i)@t0 = SCpt(i)@t'
----------------------------------------
SCpt(i)@pred(t) ~< SCpt(i)@t = orderOk || SCpt(i)@t = SCpt(i)@pred(t)

Case t’ = pred(t). We first rewrite the conclusion using the equality in H0. The ! mark is here to indicate that the rewriting must be done as much as possible and at least once. Then, it is a direct consequence of the counterIncrease lemma.


by apply counterIncrease.
[> Line 244: by (apply ... )
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i:index,t,t':timestamp
H0: t' < pred(t)
Hap: happens(t)
Hexec: exec@t
Ht': t' < t
IH0: forall (t0,t':timestamp,i:index),
t0 < t =>
happens(t0) =>
exec@t0 && t' < t0 =>
SCpt(i)@t' ~< SCpt(i)@t0 = orderOk || SCpt(i)@t0 = SCpt(i)@t'
----------------------------------------
SCpt(i)@t' ~< SCpt(i)@t = orderOk || SCpt(i)@t = SCpt(i)@t'

+ use IH0 with pred(t),t',i as H1 => //. [> Line 253: ((have ... as H1);(intro //))
[goal> Focused goal (1/2):
System: left:default/left, right:default/right
Variables: i:index,t,t':timestamp
H0: t' < pred(t)
H1: SCpt(i)@t' ~< SCpt(i)@pred(t) = orderOk || SCpt(i)@pred(t) = SCpt(i)@t'
Hap: happens(t)
Hexec: exec@t
Ht': t' < t
IH0: forall (t0,t':timestamp,i:index),
t0 < t =>
happens(t0) =>
exec@t0 && t' < t0 =>
SCpt(i)@t' ~< SCpt(i)@t0 = orderOk || SCpt(i)@t0 = SCpt(i)@t'
----------------------------------------
SCpt(i)@t' ~< SCpt(i)@t = orderOk || SCpt(i)@t = SCpt(i)@t'

Case t’ < pred(t). We first apply the induction hypothesis with t' < pred(t) to obtain a relation between SCpt(i)@t' and SCpt(i)@pred(t). We then use the counterIncrease lemma, this time to obtain a relation between SCpt(i)@pred(t) and SCpt(i)@t. We will then be able to conclude by transitivity.


- use counterIncrease with t,i as H3 => //.
[> Line 254: ((have ... as H3);(intro //))
[goal> Focused goal (1/2):
System: left:default/left, right:default/right
Variables: i:index,t,t':timestamp
H0: t' < pred(t)
H1: SCpt(i)@t' ~< SCpt(i)@pred(t) = orderOk || SCpt(i)@pred(t) = SCpt(i)@t'
H3: SCpt(i)@pred(t) ~< SCpt(i)@t = orderOk || SCpt(i)@t = SCpt(i)@pred(t)
Hap: happens(t)
Hexec: exec@t
Ht': t' < t
IH0: forall (t0,t':timestamp,i:index),
t0 < t =>
happens(t0) =>
exec@t0 && t' < t0 =>
SCpt(i)@t' ~< SCpt(i)@t0 = orderOk || SCpt(i)@t0 = SCpt(i)@t'
----------------------------------------
SCpt(i)@t' ~< SCpt(i)@t = orderOk || SCpt(i)@t = SCpt(i)@t'


case H1 => //.
[> Line 255: ((case H1);(intro //))
[goal> Focused goal (1/3):
System: left:default/left, right:default/right
Variables: i:index,t,t':timestamp
H0: t' < pred(t)
H1: SCpt(i)@t' ~< SCpt(i)@pred(t) = orderOk
H3: SCpt(i)@pred(t) ~< SCpt(i)@t = orderOk || SCpt(i)@t = SCpt(i)@pred(t)
Hap: happens(t)
Hexec: exec@t
Ht': t' < t
IH0: forall (t0,t':timestamp,i:index),
t0 < t =>
happens(t0) =>
exec@t0 && t' < t0 =>
SCpt(i)@t' ~< SCpt(i)@t0 = orderOk || SCpt(i)@t0 = SCpt(i)@t'
----------------------------------------
SCpt(i)@t' ~< SCpt(i)@t = orderOk || SCpt(i)@t = SCpt(i)@t'


* (* case H1 - 1/2 *)
case H3 => //.
[> Line 257: ((case H3);(intro //))
[goal> Focused goal (1/3):
System: left:default/left, right:default/right
Variables: i:index,t,t':timestamp
H0: t' < pred(t)
H1: SCpt(i)@t' ~< SCpt(i)@pred(t) = orderOk
H3: SCpt(i)@pred(t) ~< SCpt(i)@t = orderOk
Hap: happens(t)
Hexec: exec@t
Ht': t' < t
IH0: forall (t0,t':timestamp,i:index),
t0 < t =>
happens(t0) =>
exec@t0 && t' < t0 =>
SCpt(i)@t' ~< SCpt(i)@t0 = orderOk || SCpt(i)@t0 = SCpt(i)@t'
----------------------------------------
SCpt(i)@t' ~< SCpt(i)@t = orderOk || SCpt(i)@t = SCpt(i)@t'


by left; apply orderTrans _ (SCpt(i)@pred(t)) _.
[> Line 258: by (left;(apply ... ))
[goal> Focused goal (1/2):
System: left:default/left, right:default/right
Variables: i:index,t,t':timestamp
H0: t' < pred(t)
H1: SCpt(i)@pred(t) = SCpt(i)@t'
H3: SCpt(i)@pred(t) ~< SCpt(i)@t = orderOk || SCpt(i)@t = SCpt(i)@pred(t)
Hap: happens(t)
Hexec: exec@t
Ht': t' < t
IH0: forall (t0,t':timestamp,i:index),
t0 < t =>
happens(t0) =>
exec@t0 && t' < t0 =>
SCpt(i)@t' ~< SCpt(i)@t0 = orderOk || SCpt(i)@t0 = SCpt(i)@t'
----------------------------------------
SCpt(i)@t' ~< SCpt(i)@t = orderOk || SCpt(i)@t = SCpt(i)@t'


* (* case H1 - 2/2 *)
by case H3; [1: left | 2 : right].
[> Line 260: by ((case H3); [1: left|2: right])
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i:index,t,t':timestamp
H0: t' < pred(t)
Hap: happens(t)
Hexec: exec@t
Ht': t' < t
IH0: forall (t0,t':timestamp,i:index),
t0 < t =>
happens(t0) =>
exec@t0 && t' < t0 =>
SCpt(i)@t' ~< SCpt(i)@t0 = orderOk || SCpt(i)@t0 = SCpt(i)@t'
----------------------------------------
exec@pred(t) && t' < pred(t)

- simpl. [> Line 263: simpl
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i:index,t,t':timestamp
H0: t' < pred(t)
Hap: happens(t)
Hexec: exec@t
Ht': t' < t
IH0: forall (t0,t':timestamp,i:index),
t0 < t =>
happens(t0) =>
exec@t0 && t' < t0 =>
SCpt(i)@t' ~< SCpt(i)@t0 = orderOk || SCpt(i)@t0 = SCpt(i)@t'
----------------------------------------
exec@pred(t)

It remains to show that the premises of the induction hypothesis IH0 were satisfied, relying on the fact that exec@t => exec@pred(t).


executable t => // H1.
[> Line 264: ((executable t);(intro // H1))
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i:index,t,t':timestamp
H0: t' < pred(t)
H1: forall (t0:timestamp), t0 <= t => exec@t0
Hap: happens(t)
Hexec: exec@t
Ht': t' < t
IH0: forall (t0,t':timestamp,i:index),
t0 < t =>
happens(t0) =>
exec@t0 && t' < t0 =>
SCpt(i)@t' ~< SCpt(i)@t0 = orderOk || SCpt(i)@t0 = SCpt(i)@t'
----------------------------------------
exec@pred(t)


by apply H1.
[> Line 265: by (apply ... )
[goal> Goal counterIncreaseBis is proved

Qed.
Exiting proof mode.


goal noreplayInv (ii, ii1, i:index):
happens(S(ii1,i),S(ii,i)) =>
exec@S(ii1,i) && S(ii,i) < S(ii1,i) =>
SCpt(i)@S(ii,i) ~< SCpt(i)@S(ii1,i) = orderOk.
Goal noreplayInv :
happens(S(ii,i), S(ii1,i)) =>
exec@S(ii1,i) && S(ii,i) < S(ii1,i) =>
SCpt(i)@S(ii,i) ~< SCpt(i)@S(ii1,i) = orderOk

SECURITY PROPERTIES

We now state and prove the 3 following security properties:

  • Property 1: absence of replay attacks.
  • Property 2: injective correspondence.
  • Property 3: monotonicity.

Property 1: absence of replay attacks

This property states that the server never accepts for the same YubiKey the same counter twice, i.e. if the trace is executable up until S(ii1,i), then there cannot exist a previous action S(ii,i) in the trace such that ii <> ii1 and SCpt(i)@S(ii,i) = SCpt(i)@S(ii1,i).

Note that proving this property does not rely on any assumption on cryptographic primitives: it relies only on reasonings about counter values.

We start by proving an invariant (noreplayInv) that will be useful in the main proof. This intermediate lemma states that whenever the server accepts for a given YubiKey (represented by the index i), the counter value must have increased compared to the last time the server accepted for this YubiKey.

Proof. [goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,ii1:index
----------------------------------------
happens(S(ii,i), S(ii1,i)) =>
exec@S(ii1,i) && S(ii,i) < S(ii1,i) =>
SCpt(i)@S(ii,i) ~< SCpt(i)@S(ii1,i) = orderOk

The proof relies on the previous helping lemmas reasoning on counter values.


intro Hap [Hexec Ht].
[> Line 304: (intro Hap [Hexec Ht])
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,ii1:index
Hap: happens(S(ii,i), S(ii1,i))
Hexec: exec@S(ii1,i)
Ht: S(ii,i) < S(ii1,i)
----------------------------------------
SCpt(i)@S(ii,i) ~< SCpt(i)@S(ii1,i) = orderOk


assert (S(ii,i) = pred(S(ii1,i)) || S(ii,i) < pred(S(ii1,i))) as H1;
1: constraints.
[> Line 306: ((have
((S(ii,i) = pred(S(ii1,i))) || (S(ii,i) < pred(S(ii1,i)))), H1);
1: constraints)

[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,ii1:index
H1: S(ii,i) = pred(S(ii1,i)) || S(ii,i) < pred(S(ii1,i))
Hap: happens(S(ii,i), S(ii1,i))
Hexec: exec@S(ii1,i)
Ht: S(ii,i) < S(ii1,i)
----------------------------------------
SCpt(i)@S(ii,i) ~< SCpt(i)@S(ii1,i) = orderOk


case H1.
[> Line 307: (case H1)
[goal> Focused goal (1/2):
System: left:default/left, right:default/right
Variables: i,ii,ii1:index
H1: S(ii,i) = pred(S(ii1,i))
Hap: happens(S(ii,i), S(ii1,i))
Hexec: exec@S(ii1,i)
Ht: S(ii,i) < S(ii1,i)
----------------------------------------
SCpt(i)@S(ii,i) ~< SCpt(i)@S(ii1,i) = orderOk


+ (* Case S(ii,i) = pred(S(ii1,i)).
[> Line 309: by (have ... as M0)
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,ii1:index
H1: S(ii,i) < pred(S(ii1,i))
Hap: happens(S(ii,i), S(ii1,i))
Hexec: exec@S(ii1,i)
Ht: S(ii,i) < S(ii1,i)
----------------------------------------
SCpt(i)@S(ii,i) ~< SCpt(i)@S(ii1,i) = orderOk

*)
by use counterIncreaseStrictly with ii1, i as M0.
[> Line 312: ((have ... as H2);(intro //))
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,ii1:index
H1: S(ii,i) < pred(S(ii1,i))
H2: SCpt(i)@S(ii,i) ~< SCpt(i)@pred(S(ii1,i)) = orderOk ||
SCpt(i)@pred(S(ii1,i)) = SCpt(i)@S(ii,i)
Hap: happens(S(ii,i), S(ii1,i))
Hexec: exec@S(ii1,i)
Ht: S(ii,i) < S(ii1,i)
----------------------------------------
SCpt(i)@S(ii,i) ~< SCpt(i)@S(ii1,i) = orderOk



+ (* Case S(ii,i) < pred(S(ii1,i)).
[> Line 313: ((case H2);(intro //))
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,ii1:index
H1: S(ii,i) < pred(S(ii1,i))
H2: SCpt(i)@S(ii,i) ~< SCpt(i)@pred(S(ii1,i)) = orderOk
Hap: happens(S(ii,i), S(ii1,i))
Hexec: exec@S(ii1,i)
Ht: S(ii,i) < S(ii1,i)
----------------------------------------
SCpt(i)@S(ii,i) ~< SCpt(i)@S(ii1,i) = orderOk

*)
use counterIncreaseBis with pred(S(ii1,i)),S(ii,i),i as H2 => //.
[> Line 314: by (apply ... )
[goal> Goal noreplayInv is proved

case H2 => //.
Exiting proof mode.



by apply orderTrans _ (SCpt(i)@pred(S(ii1,i))) _.
Goal noreplay :
happens(S(ii1,i)) =>
exec@S(ii1,i) && S(ii,i) <= S(ii1,i) && SCpt(i)@S(ii,i) = SCpt(i)@S(ii1,i) =>
ii = ii1

Qed.
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,ii1:index
----------------------------------------
happens(S(ii1,i)) =>
exec@S(ii1,i) && S(ii,i) <= S(ii1,i) && SCpt(i)@S(ii,i) = SCpt(i)@S(ii1,i) =>
ii = ii1



goal noreplay (ii, ii1, i:index):
happens(S(ii1,i)) =>
exec@S(ii1,i) && S(ii,i) <= S(ii1,i) && SCpt(i)@S(ii,i) = SCpt(i)@S(ii1,i) =>
ii = ii1.
[> Line 322: (intro Hap [Hexec Ht Meq])
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,ii1:index
Hap: happens(S(ii1,i))
Hexec: exec@S(ii1,i)
Ht: S(ii,i) <= S(ii1,i)
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii1,i)
----------------------------------------
ii = ii1


Proof.
[> Line 324: ((have ((S(ii,i) = S(ii1,i)) || (S(ii,i) < S(ii1,i))), H1);
1: constraints)

[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,ii1:index
H1: S(ii,i) = S(ii1,i) || S(ii,i) < S(ii1,i)
Hap: happens(S(ii1,i))
Hexec: exec@S(ii1,i)
Ht: S(ii,i) <= S(ii1,i)
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii1,i)
----------------------------------------
ii = ii1


intro Hap [Hexec Ht Meq].
[> Line 329: ((case H1);(intro //))
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,ii1:index
H1: S(ii,i) < S(ii1,i)
Hap: happens(S(ii1,i))
Hexec: exec@S(ii1,i)
Ht: S(ii,i) <= S(ii1,i)
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii1,i)
----------------------------------------
ii = ii1


assert (S(ii,i) = S(ii1,i) || S(ii,i) < S(ii1,i)) as H1;
1: constraints.
[> Line 330: ((have ... as M1);(intro //))
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,ii1:index
H1: S(ii,i) < S(ii1,i)
Hap: happens(S(ii1,i))
Hexec: exec@S(ii1,i)
Ht: S(ii,i) <= S(ii1,i)
M1: SCpt(i)@S(ii,i) ~< SCpt(i)@S(ii1,i) = orderOk
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii1,i)
----------------------------------------
ii = ii1

case H1 => //. [> Line 331: by (apply ... in Meq)
[goal> Goal noreplay is proved

The case where S(ii,i) = S(ii1,i) is trivial and automatically handled by Squirrel. For the case where S(ii,i) < S(ii1,i), we use the invariant to show that there is a contradiction with the hypothesis Meq.


use noreplayInv with ii, ii1, i as M1 => //.
Exiting proof mode.



by apply orderStrict in Meq.
Goal injective_correspondence :
happens(S(ii,i)) =>
exec@S(ii,i) =>
exists (j:index),
Press(i,j) < S(ii,i) &&
cpt(i,j)@Press(i,j) = SCpt(i)@S(ii,i) &&
forall (ii1:index),
happens(S(ii1,i)) =>
exec@S(ii1,i) => cpt(i,j)@Press(i,j) = SCpt(i)@S(ii1,i) => ii1 = ii

Qed.
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii:index
----------------------------------------
happens(S(ii,i)) =>
exec@S(ii,i) =>
exists (j:index),
Press(i,j) < S(ii,i) &&
cpt(i,j)@Press(i,j) = SCpt(i)@S(ii,i) &&
forall (ii1:index),
happens(S(ii1,i)) =>
exec@S(ii1,i) => cpt(i,j)@Press(i,j) = SCpt(i)@S(ii1,i) => ii1 = ii

goal injective_correspondence (ii,i:index):
happens(S(ii,i)) =>
exec@S(ii,i) =>
exists (j:index),
Press(i,j) < S(ii,i) && cpt(i,j)@Press(i,j) = SCpt(i)@S(ii,i) &&
forall (ii1:index),
happens(S(ii1,i)) =>
exec@S(ii1,i) =>
cpt(i,j)@Press(i,j) = SCpt(i)@S(ii1,i) =>
ii1 = ii.
[> Line 364: (intro Hap Hexec)
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii:index
Hap: happens(S(ii,i))
Hexec: exec@S(ii,i)
----------------------------------------
exists (j:index),
Press(i,j) < S(ii,i) &&
cpt(i,j)@Press(i,j) = SCpt(i)@S(ii,i) &&
forall (ii1:index),
happens(S(ii1,i)) =>
exec@S(ii1,i) => cpt(i,j)@Press(i,j) = SCpt(i)@S(ii1,i) => ii1 = ii

Property 2: injective correspondence

This property states that a successful login for the YubiKey pid(i) (i.e. the execution of action S(ii,i)) must have been preceded by a button press on this YubiKey for the same counter value (P(i,j) with cpt(i,j)@Press(i,j) = SCpt(i)@S(ii,i)), and this counter value is not involved in another successful login.

Proving this property requires to reason on counter values, but also requires the use of the INT-CTXT cryptographic assumption.

Proof. [> Line 365: ((executable S(ii,i));(intro //))
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii:index
Hap: happens(S(ii,i))
Hexec: exec@S(ii,i)
----------------------------------------
(forall (t:timestamp), t <= S(ii,i) => exec@t) =>
exists (j:index),
Press(i,j) < S(ii,i) &&
cpt(i,j)@Press(i,j) = SCpt(i)@S(ii,i) &&
forall (ii1:index),
happens(S(ii1,i)) =>
exec@S(ii1,i) => cpt(i,j)@Press(i,j) = SCpt(i)@S(ii1,i) => ii1 = ii

The high-level idea of this proof is to use the INT-CTXT assumption: if the message received by the server is a valid ciphertext, then it must be equal to an encryption that took place before.

Since the action Press(i,j) is the only one that outputs an encryption, we thus have the existence of such an action before in the trace. Then, the unicity is proved using lemmas on counter values.


intro Hap Hexec.
[> Line 366: (intro Hexec')
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii:index
Hap: happens(S(ii,i))
Hexec: exec@S(ii,i)
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
----------------------------------------
exists (j:index),
Press(i,j) < S(ii,i) &&
cpt(i,j)@Press(i,j) = SCpt(i)@S(ii,i) &&
forall (ii1:index),
happens(S(ii1,i)) =>
exec@S(ii1,i) => cpt(i,j)@Press(i,j) = SCpt(i)@S(ii1,i) => ii1 = ii


executable S(ii,i) => //.
[> Line 367: (rewrite ... ... in Hexec)
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii:index
Hap: happens(S(ii,i))
Hexec: exec@pred(S(ii,i)) &&
(dec(snd(snd(input@S(ii,i))),k(i)) <> fail &&
SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk) &&
fst(input@S(ii,i)) = pid(i)
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
----------------------------------------
exists (j:index),
Press(i,j) < S(ii,i) &&
cpt(i,j)@Press(i,j) = SCpt(i)@S(ii,i) &&
forall (ii1:index),
happens(S(ii1,i)) =>
exec@S(ii1,i) => cpt(i,j)@Press(i,j) = SCpt(i)@S(ii1,i) => ii1 = ii


intro Hexec'.
[> Line 368: (destruct Hexec, [Hexecpred [Mneq Hcpt] Hpid])
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii:index
Hap: happens(S(ii,i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
exists (j:index),
Press(i,j) < S(ii,i) &&
cpt(i,j)@Press(i,j) = SCpt(i)@S(ii,i) &&
forall (ii1:index),
happens(S(ii1,i)) =>
exec@S(ii1,i) => cpt(i,j)@Press(i,j) = SCpt(i)@S(ii1,i) => ii1 = ii


rewrite /exec /cond in Hexec.
[> Line 371: ((intctxt Mneq);(intro //))
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,j:index
Hap: happens(S(ii,i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
Press(i,j) < S(ii,i) =>
enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i))) =>
i = i =>
exists (j:index),
Press(i,j) < S(ii,i) &&
cpt(i,j)@Press(i,j) = SCpt(i)@S(ii,i) &&
forall (ii1:index),
happens(S(ii1,i)) =>
exec@S(ii1,i) => cpt(i,j)@Press(i,j) = SCpt(i)@S(ii1,i) => ii1 = ii


destruct Hexec as [Hexecpred [Mneq Hcpt] Hpid].
[> Line 372: (intro Ht M1 *)
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,j:index
Hap: happens(S(ii,i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
exists (j:index),
Press(i,j) < S(ii,i) &&
cpt(i,j)@Press(i,j) = SCpt(i)@S(ii,i) &&
forall (ii1:index),
happens(S(ii1,i)) =>
exec@S(ii1,i) => cpt(i,j)@Press(i,j) = SCpt(i)@S(ii1,i) => ii1 = ii

intctxt Mneq => //. [> Line 373: (exists j)
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,j:index
Hap: happens(S(ii,i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
Press(i,j) < S(ii,i) &&
cpt(i,j)@Press(i,j) = SCpt(i)@S(ii,i) &&
forall (ii1:index),
happens(S(ii1,i)) =>
exec@S(ii1,i) => cpt(i,j)@Press(i,j) = SCpt(i)@S(ii1,i) => ii1 = ii

We apply the INT-CTXT assumption, which directly gives the existence of an action Press(i,j) that happens before S(ii,i).


intro Ht M1 *.
[> Line 378: simpl
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,j:index
Hap: happens(S(ii,i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
cpt(i,j)@Press(i,j) = SCpt(i)@S(ii,i) &&
forall (ii1:index),
happens(S(ii1,i)) =>
exec@S(ii1,i) => cpt(i,j)@Press(i,j) = SCpt(i)@S(ii1,i) => ii1 = ii


exists j.
[> Line 379: (split; 1: auto)
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,j:index
Hap: happens(S(ii,i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
forall (ii1:index),
happens(S(ii1,i)) =>
exec@S(ii1,i) => cpt(i,j)@Press(i,j) = SCpt(i)@S(ii1,i) => ii1 = ii

simpl. [> Line 384: (intro ii' Hap' Hexec1 Eq)
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,ii',j:index
Eq: cpt(i,j)@Press(i,j) = SCpt(i)@S(ii',i)
Hap: happens(S(ii,i))
Hap': happens(S(ii',i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexec1: exec@S(ii',i)
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
ii' = ii

The two first conjucts of the conclusion are automatically proved by Squirrel (the equality of counter values is a consequence of M1 once we have expanded the macros cpt and SCpt.


split; 1: auto.
[> Line 385: ((have (SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i)));(intro //))
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,ii',j:index
Eq: cpt(i,j)@Press(i,j) = SCpt(i)@S(ii',i)
Hap: happens(S(ii,i))
Hap': happens(S(ii',i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexec1: exec@S(ii',i)
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i)
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
ii' = ii

intro ii' Hap' Hexec1 Eq. [> Line 390: ((have
((S(ii,i) = S(ii',i)) ||
((S(ii,i) < S(ii',i)) || (S(ii,i) > S(ii',i)))));
(intro //))

[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,ii',j:index
Eq: cpt(i,j)@Press(i,j) = SCpt(i)@S(ii',i)
H: S(ii,i) = S(ii',i) || S(ii,i) < S(ii',i) || S(ii,i) > S(ii',i)
Hap: happens(S(ii,i))
Hap': happens(S(ii',i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexec1: exec@S(ii',i)
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i)
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
ii' = ii

It now remains to show that the counter value cpt(i,j)@Press(i,j) is not involved in another successful login. We first show if this second successful login S(ii',i) had happened, then we must have SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i).


assert (SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i)) => //.
[> Line 391: ((case H);(intro //))
[goal> Focused goal (1/2):
System: left:default/left, right:default/right
Variables: i,ii,ii',j:index
Eq: cpt(i,j)@Press(i,j) = SCpt(i)@S(ii',i)
H: S(ii,i) < S(ii',i)
Hap: happens(S(ii,i))
Hap': happens(S(ii',i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexec1: exec@S(ii',i)
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i)
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
ii' = ii

assert (S(ii,i) = S(ii',i) || S(ii,i) < S(ii',i) || S(ii,i) > S(ii',i)) => //. [> Line 394: ((have
((S(ii,i) = pred(S(ii',i))) || (S(ii,i) < pred(S(ii',i)))));
(intro //))

[goal> Focused goal (1/2):
System: left:default/left, right:default/right
Variables: i,ii,ii',j:index
Eq: cpt(i,j)@Press(i,j) = SCpt(i)@S(ii',i)
H: S(ii,i) < S(ii',i)
H0: S(ii,i) = pred(S(ii',i)) || S(ii,i) < pred(S(ii',i))
Hap: happens(S(ii,i))
Hap': happens(S(ii',i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexec1: exec@S(ii',i)
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i)
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
ii' = ii

The proof now relies only on lemmas about counter values to show that we cannot have SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i) and S(ii,i) <> S(ii',i). We therefore a case disjunction (the first case corresponds to what we want to prove, and we will show that the 2 other cases are impossible).


case H => //.
[> Line 395: ((case H0);(intro //))
[goal> Focused goal (1/3):
System: left:default/left, right:default/right
Variables: i,ii,ii',j:index
Eq: cpt(i,j)@Press(i,j) = SCpt(i)@S(ii',i)
H: S(ii,i) < S(ii',i)
H0: S(ii,i) = pred(S(ii',i))
Hap: happens(S(ii,i))
Hap': happens(S(ii',i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexec1: exec@S(ii',i)
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i)
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
ii' = ii



+ (* 1st case: S(ii,i) < S(ii',i) *)
assert (S(ii,i) = pred(S(ii',i)) || S(ii,i) < pred(S(ii',i))) => //.
[> Line 398: ((have ... as );(intro //))
[goal> Focused goal (1/3):
System: left:default/left, right:default/right
Variables: i,ii,ii',j:index
Eq: cpt(i,j)@Press(i,j) = SCpt(i)@S(ii',i)
H: S(ii,i) < S(ii',i)
H0: S(ii,i) = pred(S(ii',i))
Hap: happens(S(ii,i))
Hap': happens(S(ii',i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexec1: exec@S(ii',i)
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i)
Meq0: SCpt(i)@pred(S(ii',i)) ~< SCpt(i)@S(ii',i) = orderOk
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
ii' = ii


case H0 => //.
[> Line 399: ((subst S(ii,i), pred(S(ii',i)));(intro //))
[goal> Focused goal (1/3):
System: left:default/left, right:default/right
Variables: i,ii,ii',j:index
Eq: cpt(i,j)@Press(i,j) = SCpt(i)@S(ii',i)
H: pred(S(ii',i)) < S(ii',i)
Hap: happens(pred(S(ii',i)))
Hap': happens(S(ii',i))
Hcpt: SCpt(i)@pred(pred(S(ii',i))) ~<
snd(dec(snd(snd(input@pred(S(ii',i)))),k(i))) = orderOk
Hexec': forall (t:timestamp), t <= pred(S(ii',i)) => exec@t
Hexec1: exec@S(ii',i)
Hexecpred: exec@pred(pred(S(ii',i)))
Hpid: fst(input@pred(S(ii',i))) = pid(i)
Ht: Press(i,j) < pred(S(ii',i))
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) =
snd(snd(input@pred(S(ii',i))))
Meq: SCpt(i)@pred(S(ii',i)) = SCpt(i)@S(ii',i)
Meq0: SCpt(i)@pred(S(ii',i)) ~< SCpt(i)@S(ii',i) = orderOk
Mneq: dec(snd(snd(input@pred(S(ii',i)))),k(i)) <> fail
----------------------------------------
ii' = ii



- (* S(ii,i) = pred(S(ii',i) < S(ii',i) *)
use counterIncreaseStrictly with ii',i => //.
[> Line 400: (by (have ... as );(intro //))
[goal> Focused goal (1/2):
System: left:default/left, right:default/right
Variables: i,ii,ii',j:index
Eq: cpt(i,j)@Press(i,j) = SCpt(i)@S(ii',i)
H: S(ii,i) < S(ii',i)
H0: S(ii,i) < pred(S(ii',i))
Hap: happens(S(ii,i))
Hap': happens(S(ii',i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexec1: exec@S(ii',i)
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i)
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
ii' = ii


subst S(ii,i), pred(S(ii',i)) => //.
[> Line 403: ((have ... as );(intro //))
[goal> Focused goal (1/2):
System: left:default/left, right:default/right
Variables: i,ii,ii',j:index
Eq: cpt(i,j)@Press(i,j) = SCpt(i)@S(ii',i)
H: S(ii,i) < S(ii',i)
H0: S(ii,i) < pred(S(ii',i))
Hap: happens(S(ii,i))
Hap': happens(S(ii',i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexec1: exec@S(ii',i)
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i)
Meq0: SCpt(i)@pred(S(ii',i)) ~< SCpt(i)@S(ii',i) = orderOk
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
ii' = ii


by use orderStrict with SCpt(i)@pred(S(ii',i)), SCpt(i)@S(ii',i) => //.
[> Line 404: ((have ... as );(intro //))
[goal> Focused goal (1/2):
System: left:default/left, right:default/right
Variables: i,ii,ii',j:index
Eq: cpt(i,j)@Press(i,j) = SCpt(i)@S(ii',i)
H: S(ii,i) < S(ii',i)
H0: S(ii,i) < pred(S(ii',i))
H1: SCpt(i)@S(ii,i) ~< SCpt(i)@pred(S(ii',i)) = orderOk ||
SCpt(i)@pred(S(ii',i)) = SCpt(i)@S(ii,i)
Hap: happens(S(ii,i))
Hap': happens(S(ii',i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexec1: exec@S(ii',i)
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i)
Meq0: SCpt(i)@pred(S(ii',i)) ~< SCpt(i)@S(ii',i) = orderOk
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
ii' = ii



- (* S(ii,i) < pred(S(ii',i)) < S(ii',i) *)
use counterIncreaseStrictly with ii',i => //.
[> Line 405: (case H1)
[goal> Focused goal (1/3):
System: left:default/left, right:default/right
Variables: i,ii,ii',j:index
Eq: cpt(i,j)@Press(i,j) = SCpt(i)@S(ii',i)
H: S(ii,i) < S(ii',i)
H0: S(ii,i) < pred(S(ii',i))
H1: SCpt(i)@S(ii,i) ~< SCpt(i)@pred(S(ii',i)) = orderOk
Hap: happens(S(ii,i))
Hap': happens(S(ii',i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexec1: exec@S(ii',i)
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i)
Meq0: SCpt(i)@pred(S(ii',i)) ~< SCpt(i)@S(ii',i) = orderOk
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
ii' = ii


use counterIncreaseBis with pred(S(ii',i)), S(ii,i), i => //.
[> Line 406: ((have ... as );(intro //))
[goal> Focused goal (1/3):
System: left:default/left, right:default/right
Variables: i,ii,ii',j:index
Eq: cpt(i,j)@Press(i,j) = SCpt(i)@S(ii',i)
H: S(ii,i) < S(ii',i)
H0: S(ii,i) < pred(S(ii',i))
H1: SCpt(i)@S(ii,i) ~< SCpt(i)@pred(S(ii',i)) = orderOk
Hap: happens(S(ii,i))
Hap': happens(S(ii',i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexec1: exec@S(ii',i)
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i)
Meq0: SCpt(i)@pred(S(ii',i)) ~< SCpt(i)@S(ii',i) = orderOk
Meq1: SCpt(i)@S(ii,i) ~< SCpt(i)@S(ii',i) = orderOk
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
ii' = ii


case H1.
[> Line 407: (by (have ... as );(intro //))
[goal> Focused goal (1/2):
System: left:default/left, right:default/right
Variables: i,ii,ii',j:index
Eq: cpt(i,j)@Press(i,j) = SCpt(i)@S(ii',i)
H: S(ii,i) < S(ii',i)
H0: S(ii,i) < pred(S(ii',i))
H1: SCpt(i)@pred(S(ii',i)) = SCpt(i)@S(ii,i)
Hap: happens(S(ii,i))
Hap': happens(S(ii',i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexec1: exec@S(ii',i)
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i)
Meq0: SCpt(i)@pred(S(ii',i)) ~< SCpt(i)@S(ii',i) = orderOk
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
ii' = ii


* use orderTrans with SCpt(i)@S(ii,i), SCpt(i)@pred(S(ii',i)), SCpt(i)@S(ii',i) => //.
[> Line 408: (subst SCpt(i)@pred(S(ii',i)), SCpt(i)@S(ii,i))
[goal> Focused goal (1/2):
System: left:default/left, right:default/right
Variables: i,ii,ii',j:index
Eq: cpt(i,j)@Press(i,j) = SCpt(i)@S(ii',i)
H: S(ii,i) < S(ii',i)
H0: S(ii,i) < pred(S(ii',i))
Hap: happens(S(ii,i))
Hap': happens(S(ii',i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexec1: exec@S(ii',i)
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i)
Meq0: SCpt(i)@S(ii,i) ~< SCpt(i)@S(ii',i) = orderOk
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
ii' = ii


by use orderStrict with SCpt(i)@S(ii,i), SCpt(i)@S(ii',i) => //.
[> Line 409: (by (have ... as );(intro //))
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,ii',j:index
Eq: cpt(i,j)@Press(i,j) = SCpt(i)@S(ii',i)
H: S(ii,i) > S(ii',i)
Hap: happens(S(ii,i))
Hap': happens(S(ii',i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexec1: exec@S(ii',i)
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i)
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
ii' = ii


* subst SCpt(i)@pred(S(ii',i)), SCpt(i)@S(ii,i).
[> Line 412: ((have
((pred(S(ii,i)) = S(ii',i)) || (pred(S(ii,i)) > S(ii',i))));
(intro //))

[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,ii',j:index
Eq: cpt(i,j)@Press(i,j) = SCpt(i)@S(ii',i)
H: S(ii,i) > S(ii',i)
H0: pred(S(ii,i)) = S(ii',i) || pred(S(ii,i)) > S(ii',i)
Hap: happens(S(ii,i))
Hap': happens(S(ii',i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexec1: exec@S(ii',i)
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i)
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
ii' = ii


by use orderStrict with SCpt(i)@S(ii,i), SCpt(i)@S(ii',i) => //.
[> Line 413: ((case H0);(intro //))
[goal> Focused goal (1/2):
System: left:default/left, right:default/right
Variables: i,ii,ii',j:index
Eq: cpt(i,j)@Press(i,j) = SCpt(i)@S(ii',i)
H: S(ii,i) > S(ii',i)
H0: pred(S(ii,i)) = S(ii',i)
Hap: happens(S(ii,i))
Hap': happens(S(ii',i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexec1: exec@S(ii',i)
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i)
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
ii' = ii



+ (* 2nd case: S(ii,i) > S(ii',i) *)
assert (pred(S(ii,i)) = S(ii',i) || pred(S(ii,i)) > S(ii',i)) => //.
[> Line 416: ((have ... as );(intro //))
[goal> Focused goal (1/2):
System: left:default/left, right:default/right
Variables: i,ii,ii',j:index
Eq: cpt(i,j)@Press(i,j) = SCpt(i)@S(ii',i)
H: S(ii,i) > S(ii',i)
H0: pred(S(ii,i)) = S(ii',i)
Hap: happens(S(ii,i))
Hap': happens(S(ii',i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexec1: exec@S(ii',i)
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i)
Meq0: SCpt(i)@pred(S(ii,i)) ~< SCpt(i)@S(ii,i) = orderOk
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
ii' = ii


case H0 => //.
[> Line 417: (subst S(ii',i), pred(S(ii,i)))
[goal> Focused goal (1/2):
System: left:default/left, right:default/right
Variables: i,ii,ii',j:index
Eq: cpt(i,j)@Press(i,j) = SCpt(i)@pred(S(ii,i))
H: S(ii,i) > pred(S(ii,i))
Hap: happens(S(ii,i))
Hap': happens(pred(S(ii,i)))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexec1: exec@pred(S(ii,i))
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Meq: SCpt(i)@S(ii,i) = SCpt(i)@pred(S(ii,i))
Meq0: SCpt(i)@pred(S(ii,i)) ~< SCpt(i)@S(ii,i) = orderOk
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
ii' = ii



- (* S(ii,i) > pred(S(ii,i)) = S(ii',i) *)
use counterIncreaseStrictly with ii,i => //.
[> Line 418: (by (have ... as );(intro //))
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,ii',j:index
Eq: cpt(i,j)@Press(i,j) = SCpt(i)@S(ii',i)
H: S(ii,i) > S(ii',i)
H0: pred(S(ii,i)) > S(ii',i)
Hap: happens(S(ii,i))
Hap': happens(S(ii',i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexec1: exec@S(ii',i)
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i)
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
ii' = ii


subst S(ii',i), pred(S(ii,i)).
[> Line 421: ((have ... as );(intro //))
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,ii',j:index
Eq: cpt(i,j)@Press(i,j) = SCpt(i)@S(ii',i)
H: S(ii,i) > S(ii',i)
H0: pred(S(ii,i)) > S(ii',i)
Hap: happens(S(ii,i))
Hap': happens(S(ii',i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexec1: exec@S(ii',i)
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i)
Meq0: SCpt(i)@pred(S(ii,i)) ~< SCpt(i)@S(ii,i) = orderOk
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
ii' = ii


by use orderStrict with SCpt(i)@pred(S(ii,i)), SCpt(i)@S(ii,i) => //.
[> Line 422: ((have ... as );(intro //))
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,ii',j:index
Eq: cpt(i,j)@Press(i,j) = SCpt(i)@S(ii',i)
H: S(ii,i) > S(ii',i)
H0: pred(S(ii,i)) > S(ii',i)
H1: SCpt(i)@S(ii',i) ~< SCpt(i)@pred(S(ii,i)) = orderOk ||
SCpt(i)@pred(S(ii,i)) = SCpt(i)@S(ii',i)
Hap: happens(S(ii,i))
Hap': happens(S(ii',i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexec1: exec@S(ii',i)
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i)
Meq0: SCpt(i)@pred(S(ii,i)) ~< SCpt(i)@S(ii,i) = orderOk
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
ii' = ii



- (* S(ii,i) > pred(S(ii,i)) > S(ii',i) *)
use counterIncreaseStrictly with ii,i => //.
[> Line 423: (case H1)
[goal> Focused goal (1/2):
System: left:default/left, right:default/right
Variables: i,ii,ii',j:index
Eq: cpt(i,j)@Press(i,j) = SCpt(i)@S(ii',i)
H: S(ii,i) > S(ii',i)
H0: pred(S(ii,i)) > S(ii',i)
H1: SCpt(i)@S(ii',i) ~< SCpt(i)@pred(S(ii,i)) = orderOk
Hap: happens(S(ii,i))
Hap': happens(S(ii',i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexec1: exec@S(ii',i)
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i)
Meq0: SCpt(i)@pred(S(ii,i)) ~< SCpt(i)@S(ii,i) = orderOk
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
ii' = ii


use counterIncreaseBis with pred(S(ii,i)), S(ii',i), i => //.
[> Line 424: ((have ... as );(intro //))
[goal> Focused goal (1/2):
System: left:default/left, right:default/right
Variables: i,ii,ii',j:index
Eq: cpt(i,j)@Press(i,j) = SCpt(i)@S(ii',i)
H: S(ii,i) > S(ii',i)
H0: pred(S(ii,i)) > S(ii',i)
H1: SCpt(i)@S(ii',i) ~< SCpt(i)@pred(S(ii,i)) = orderOk
Hap: happens(S(ii,i))
Hap': happens(S(ii',i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexec1: exec@S(ii',i)
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i)
Meq0: SCpt(i)@pred(S(ii,i)) ~< SCpt(i)@S(ii,i) = orderOk
Meq1: SCpt(i)@S(ii',i) ~< SCpt(i)@S(ii,i) = orderOk
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
ii' = ii


case H1.
[> Line 425: (by (have ... as );(intro //))
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,ii',j:index
Eq: cpt(i,j)@Press(i,j) = SCpt(i)@S(ii',i)
H: S(ii,i) > S(ii',i)
H0: pred(S(ii,i)) > S(ii',i)
H1: SCpt(i)@pred(S(ii,i)) = SCpt(i)@S(ii',i)
Hap: happens(S(ii,i))
Hap': happens(S(ii',i))
Hcpt: SCpt(i)@pred(S(ii,i)) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) =
orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexec1: exec@S(ii',i)
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i)
Meq0: SCpt(i)@pred(S(ii,i)) ~< SCpt(i)@S(ii,i) = orderOk
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
ii' = ii


* use orderTrans with SCpt(i)@S(ii',i), SCpt(i)@pred(S(ii,i)), SCpt(i)@S(ii,i) => //.
[> Line 426: (subst SCpt(i)@pred(S(ii,i)), SCpt(i)@S(ii',i))
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,ii',j:index
Eq: cpt(i,j)@Press(i,j) = SCpt(i)@S(ii',i)
H: S(ii,i) > S(ii',i)
H0: pred(S(ii,i)) > S(ii',i)
Hap: happens(S(ii,i))
Hap': happens(S(ii',i))
Hcpt: SCpt(i)@S(ii',i) ~< snd(dec(snd(snd(input@S(ii,i))),k(i))) = orderOk
Hexec': forall (t:timestamp), t <= S(ii,i) => exec@t
Hexec1: exec@S(ii',i)
Hexecpred: exec@pred(S(ii,i))
Hpid: fst(input@S(ii,i)) = pid(i)
Ht: Press(i,j) < S(ii,i)
M1: enc(<sid(i),cpt(i,j)@Press(i,j)>,npr(i,j),k(i)) = snd(snd(input@S(ii,i)))
Meq: SCpt(i)@S(ii,i) = SCpt(i)@S(ii',i)
Meq0: SCpt(i)@S(ii',i) ~< SCpt(i)@S(ii,i) = orderOk
Mneq: dec(snd(snd(input@S(ii,i))),k(i)) <> fail
----------------------------------------
ii' = ii


by use orderStrict with SCpt(i)@S(ii',i), SCpt(i)@S(ii,i) => //.
[> Line 427: (by (have ... as );(intro //))
[goal> Goal injective_correspondence is proved

* subst SCpt(i)@pred(S(ii,i)), SCpt(i)@S(ii',i).
Exiting proof mode.



by use orderStrict with SCpt(i)@S(ii',i), SCpt(i)@S(ii,i) => //.
Goal monotonicity :
happens(S(ii,i), S(ii1,i)) =>
exec@S(ii1,i) &&
exec@S(ii,i) && SCpt(i)@S(ii,i) ~< SCpt(i)@S(ii1,i) = orderOk =>
S(ii,i) < S(ii1,i)

Qed.
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,ii1:index
----------------------------------------
happens(S(ii,i), S(ii1,i)) =>
exec@S(ii1,i) &&
exec@S(ii,i) && SCpt(i)@S(ii,i) ~< SCpt(i)@S(ii1,i) = orderOk =>
S(ii,i) < S(ii1,i)

goal monotonicity (ii, ii1, i:index):
happens(S(ii1,i),S(ii,i)) =>
exec@S(ii1,i) && exec@S(ii,i)
&& SCpt(i)@S(ii,i) ~< SCpt(i)@S(ii1,i) = orderOk =>
S(ii,i) < S(ii1,i).
[> Line 445: (intro Hap [Hexec H])
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,ii1:index
H: exec@S(ii,i) && SCpt(i)@S(ii,i) ~< SCpt(i)@S(ii1,i) = orderOk
Hap: happens(S(ii,i), S(ii1,i))
Hexec: exec@S(ii1,i)
----------------------------------------
S(ii,i) < S(ii1,i)

Property 3: monotonicity

This property states that the counter values associated to successful logins are monotonically increasing in time.

Note that proving this property does not rely on any assumption on cryptographic primitives: it relies only on reasonings about counter values.


Proof.
[> Line 451: ((have
((S(ii,i) = S(ii1,i)) ||
((S(ii,i) < S(ii1,i)) || (S(ii,i) > S(ii1,i)))),
Ht);
1: constraints)

[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,ii1:index
H: exec@S(ii,i) && SCpt(i)@S(ii,i) ~< SCpt(i)@S(ii1,i) = orderOk
Hap: happens(S(ii,i), S(ii1,i))
Hexec: exec@S(ii1,i)
Ht: S(ii,i) = S(ii1,i) || S(ii,i) < S(ii1,i) || S(ii,i) > S(ii1,i)
----------------------------------------
S(ii,i) < S(ii1,i)


intro Hap [Hexec H].
[> Line 452: (case Ht)
[goal> Focused goal (1/3):
System: left:default/left, right:default/right
Variables: i,ii,ii1:index
H: exec@S(ii,i) && SCpt(i)@S(ii,i) ~< SCpt(i)@S(ii1,i) = orderOk
Hap: happens(S(ii,i), S(ii1,i))
Hexec: exec@S(ii1,i)
Ht: S(ii,i) = S(ii1,i)
----------------------------------------
S(ii,i) < S(ii1,i)

assert
(S(ii,i) = S(ii1,i) || S(ii,i) < S(ii1,i) || S(ii,i) > S(ii1,i)) as Ht;
1: constraints.
[> Line 455: by (have ... as )
[goal> Focused goal (1/2):
System: left:default/left, right:default/right
Variables: i,ii,ii1:index
H: exec@S(ii,i) && SCpt(i)@S(ii,i) ~< SCpt(i)@S(ii1,i) = orderOk
Hap: happens(S(ii,i), S(ii1,i))
Hexec: exec@S(ii1,i)
Ht: S(ii,i) < S(ii1,i)
----------------------------------------
S(ii,i) < S(ii1,i)

We introduce a case disjunction, and we will show that the cases S(ii,i) = S(ii1,i) and S(ii,i) > S(ii1,i) are not possible, relying on previous lemmas and axioms on counter values.


case Ht.
[> Line 458: assumption
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,ii1:index
H: exec@S(ii,i) && SCpt(i)@S(ii,i) ~< SCpt(i)@S(ii1,i) = orderOk
Hap: happens(S(ii,i), S(ii1,i))
Hexec: exec@S(ii1,i)
Ht: S(ii,i) > S(ii1,i)
----------------------------------------
S(ii,i) < S(ii1,i)



+ (* case S(ii,i) = S(ii1,i) *)
by use orderStrict with SCpt(i)@S(ii,i),SCpt(i)@S(ii,i).
[> Line 461: ((have ... as Meq);(intro //))
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,ii1:index
H: exec@S(ii,i) && SCpt(i)@S(ii,i) ~< SCpt(i)@S(ii1,i) = orderOk
Hap: happens(S(ii,i), S(ii1,i))
Hexec: exec@S(ii1,i)
Ht: S(ii,i) > S(ii1,i)
Meq: SCpt(i)@S(ii1,i) ~< SCpt(i)@S(ii,i) = orderOk
----------------------------------------
S(ii,i) < S(ii1,i)



+ (* case S(ii,i) < S(ii1,i) *)
assumption.
[> Line 462: ((have ... as );(intro //))
[goal> Focused goal (1/1):
System: left:default/left, right:default/right
Variables: i,ii,ii1:index
H: exec@S(ii,i) && SCpt(i)@S(ii,i) ~< SCpt(i)@S(ii1,i) = orderOk
Hap: happens(S(ii,i), S(ii1,i))
Hexec: exec@S(ii1,i)
Ht: S(ii,i) > S(ii1,i)
Meq: SCpt(i)@S(ii1,i) ~< SCpt(i)@S(ii,i) = orderOk
Meq0: SCpt(i)@S(ii,i) ~< SCpt(i)@S(ii,i) = orderOk
----------------------------------------
S(ii,i) < S(ii1,i)



+ (* case S(ii,i) > S(ii1,i) *)
use noreplayInv with ii1, ii, i as Meq => //.
[> Line 463: by (have ... as )
[goal> Goal monotonicity is proved

use orderTrans with SCpt(i)@S(ii,i),SCpt(i)@S(ii1,i), SCpt(i)@S(ii,i) => //.
Exiting proof mode.


Press the left and right arrows to do and undo an instruction.

Alternatively, you can double-click on an instruction.

This zone shows a Squirrel file. You can double-click on a comment to collapse it for better readabilility.

This zone shows the output given by Squirrel.

This zone shows the output of the previous instruction, to help identifying the change caused by the instruction.

Previously: