1

I need some help according to follow problem which I have to implemented it using jSpin and promela language.

A home alarm system can be activated and deactivated using a personal ID key or password, after activation the system enters a waiting period of about 30 seconds, time that allows users to evacuate the secured area after which the alarm is armed, also when an intrusion is detected the alarm has a built in waiting period or delay of 15 seconds to allow the intruder to enter the password or swipe the card key thus identifying himself, in case that the identification is not made within the allocated 15 seconds the alarm will go off and will be on until an id card or password is used to deactivate it.

Here is what I tried:

mtype = {sigact, sigdeact};
chan signal = [0] of {mtype};
chan password = [0] of { int }; 
/*chan syntax for declaring and initializing message passing channels*/

int count;
bool alarm_off = true; /*The initial state of the alarm is off*/    
active proctype alarm()    
{
    off:
       if 
         :: count >= 30 -> atomic {signal!sigdeact; count = 0;alarm_off = false; goto on;}
         :: else -> atomic {count++; alarm_off = true; goto off;}
       fi;

    on:
        if
          :: count >=15 -> atomic { signal!sigact; count = 0;
    alarm_off = false; goto off;}
          :: else -> atomic {signal!sigact; alarm_off = true; goto pending;}
        fi;

    pending:

        if
           :: count >= 30 -> atomic {count = 0; alarm_off = false; goto on;}
           :: count < 30 -> atomic {count++; alarm_off = false; goto pending;}
        fi;
}

active proctype user()
{    
   password ! 1234 //1234 is the password I sent. 
   input:  atomic { signal?sigact ->  alarm_off = true; goto off; }   
}

In the user proctype I send the password

password ! 1234

How can I verify if the password is 1234 and how can I adapt it to own cases ( on, off , pending) based on the verification ?

Mihai Alexandru-Ionut
  • 47,092
  • 13
  • 101
  • 128
  • @PatrickTrentin, it works without send one given input. That's what i want to achieve. – Mihai Alexandru-Ionut Nov 13 '17 at 20:26
  • @PatrickTrentin a small comment about terminology: [Promela](https://en.wikipedia.org/wiki/Promela) is a specification language, not code. Strictly speaking, "compile" corresponds to how [SPIN](http://spinroot.com/) works, in that SPIN reads the spec and generates C code for a model checker for the given spec, which then gets compiled. However, this is an implementation detail. The spec itself isn't exactly compiled, but rather interpreted by the generated model checker (even that is inaccurate, since some parts of the state space may not need to be enumerated while checking correctness). – 0 _ Nov 13 '17 at 21:11
  • @IoannisFilippidis I guess I should say thanks ;) – Patrick Trentin Nov 13 '17 at 21:55

1 Answers1

1

As the code in the example doesn't appear to follow the specification, at least in the way I understand it, I wrote an example from scratch.

Please note that the following model (source code) is purposely very verbose and redundant in its structure, so that its easier to recognise its logic blocks and --hopefully-- understand it. In practice, one would use some inline function to handle input. I also didn't use SIGACT, SIGDEACT which appeared in the original model, since I could not figure out who was supposed to read those messages neither from the original model (source code) nor from the specification.

#define ALARM_OFF        1
#define ALARM_COUNTDOWN  2
#define ALARM_ARMED      4
#define ALARM_INTRUSION  8
#define ALARM_FIRED     16

#define INPUT_SET_PASSWORD   1
#define INPUT_CHECK_PASSWORD 2
#define INPUT_INTRUDER       4

mtype = { SIGACT, SIGDEACT };

init {
    chan alarm_out = [1] of { mtype };
    chan alarm_in =  [1] of { byte, short };

    run alarm(alarm_in, alarm_out);
    run user(alarm_in);
    run event(alarm_in);
}

proctype alarm(chan input, output)
{
    byte count;
    byte state   = ALARM_OFF;
    short passwd = 1234;
    short tmp    = 0;

off:
    if
        :: nempty(input) ->
            if
                :: input?INPUT_SET_PASSWORD(tmp) ->
                    passwd = tmp;
                :: input?INPUT_CHECK_PASSWORD(tmp) ->
                if
                    :: tmp == passwd ->
                        atomic {
                            state = ALARM_COUNTDOWN;
                            count = 0;
                            goto countdown;
                        }
                    :: else ->
                        skip;
                fi;
                :: input?INPUT_INTRUDER(tmp) ->
                    skip;
            fi;
        :: empty(input) -> skip;
    fi;
    goto off;

countdown:
    if
        :: count < 30 ->
            if
                :: nempty(input) ->
                    if
                        :: input?INPUT_SET_PASSWORD(tmp) ->
                            skip; // error: cannot be done now (?)
                        :: input?INPUT_CHECK_PASSWORD(tmp) ->
                            if
                                :: tmp == passwd ->
                                    atomic {
                                        state = ALARM_OFF;
                                        count = 0;
                                        goto off;
                                    }
                                :: else ->
                                    skip; // error: incorrect password (?)
                            fi;
                        :: input?INPUT_INTRUDER(tmp) ->
                            skip;
                    fi;
                :: empty(input) ->
                    skip;
            fi;
        :: else ->
            atomic {
                state = ALARM_ARMED;
                count = 0;
                goto armed;
            }
    fi;
    count++;
    goto countdown;

armed:
    if
        :: nempty(input) ->
            if
                :: input?INPUT_SET_PASSWORD(tmp) ->
                    skip; // error: cannot be done now (?)
                :: input?INPUT_CHECK_PASSWORD(tmp) ->
                    if
                        :: tmp == passwd ->
                            atomic {
                                state = ALARM_OFF;
                                count = 0;
                                goto off;
                            }
                        :: else ->
                            skip; // error: incorrect password (?)
                                  // maybe it should be handled like
                                  // INPUT_INTRUDER(tmp)
                    fi;
                :: input?INPUT_INTRUDER(tmp) ->
                    atomic {
                        state = ALARM_INTRUSION;
                        count = 0;
                        goto intruder_detected;
                    }
            fi;
        :: empty(input) ->
            skip;
    fi;
    goto armed;

intruder_detected:
    if
        :: count < 15 ->
            if
                :: nempty(input) ->
                    if
                        :: input?INPUT_SET_PASSWORD(tmp) ->
                            skip; // error: cannot be done now (?)
                        :: input?INPUT_CHECK_PASSWORD(tmp);
                            if
                                :: tmp == passwd ->
                                    atomic {
                                        state = ALARM_ARMED;
                                        count = 0;
                                        goto armed;
                                    }
                                :: else ->
                                    skip; // error: incorrect password (?)
                            fi;
                        :: input?INPUT_INTRUDER(tmp) ->
                            skip;
                    fi;
                :: empty(input) ->
                    skip;
            fi;
        :: count >= 15 ->
            atomic {
                state = ALARM_FIRED;
                count = 0;
                goto alarm_fired;
            }
    fi;
    count++;
    goto intruder_detected;

alarm_fired:
    if
        :: nempty(input) ->
            if
                :: input?INPUT_SET_PASSWORD(tmp) ->
                    skip; // error: cannot be done now (?)
                :: input?INPUT_CHECK_PASSWORD(tmp);
                    if
                        :: tmp == passwd ->
                            atomic {
                                state = ALARM_OFF;
                                count = 0;
                                goto off;
                            }
                        :: else ->
                            skip; // error: incorrect password (?)
                                  // warn user but keep alarm on
                    fi;
                :: input?INPUT_INTRUDER(tmp) ->
                    skip;
            fi;
        :: empty(input) ->
            skip;
    fi;
    goto alarm_fired;
};

proctype user(chan output)
{
    output ! INPUT_CHECK_PASSWORD(1234);
};

proctype event(chan output)
{
    output ! INPUT_INTRUDER(0);
};

So, basically you have to check both the input (if any!) and the value of count in order to perform a transition in the internal FSM of the alarm system.

In the example I added a proctype of name event which will randomly send a single INPUT_INTRUDER input signal to the alarm system. This, in combination with the user typing his own password, can be used to trigger the chain of events which would cause the alarm to fire.

Patrick Trentin
  • 7,126
  • 3
  • 23
  • 40
  • Thanks a lot for your time and answer. Why do we need `event` function in this situation ? – Mihai Alexandru-Ionut Nov 13 '17 at 21:48
  • 1
    @Alexandru-IonutMihai This is an *attack* scenario, so you want to model an *attacker* too: `event` serves the purpose of modelling an *intrusion* which might happen at any point in time. It sends the corresponding signal to the `alarm` system, as a `sensor` would do in a real-world scenario. If we don't provide some entity who might send such input to the `alarm` system and trigger an intrusion, then the code handling an intrusion will effectively be unreachable both in simulation and in verification. – Patrick Trentin Nov 13 '17 at 21:53
  • @Alexandru-IonutMihai to make the model more interesting, you might want to add another `user` who types his own *password* and someone else who *changes* it. – Patrick Trentin Nov 13 '17 at 22:37