The square of random is less uniform (derr)

This is something obvious to statisticians but maybe less obvious to most programmers. I recently came across some code that essentially looks like this:

```x = rand() #random number uniformly distributed between [0,1]
...
x= x**n #raise x to a power
```

The programer was for some reason assuming that x was still uniform between [0,1]. Of course, this isn’t the case. Although the domain is still between [0,1] the numbers will now be squished down closer to 0.

It is easy to analyze this with a change of variables.

The frequency distribution Fx(x) = P(X<=x)=x
Y=x^n
Fy(y) = P(Y<=y) = P(x^n<=y) = P(X<=y^(1/n) = y^(1/n) for 0<=y<=1
The density function is the derivitive
Fp(y)= (1/n)*y^-(1/n) = 1/(s*sqrt(y))

The graphs of the distributions look like this, first the one generated by rand, then one with n=2:

Finished RTOS similar to FreeRTOS

This is an RTOS developed by myself, with some code taken from FreeRTOS. This is some of the most difficult code I have ever written, although it really doesn’t do anything useful. Man, context switching in C can be a bear! It’s like a programatic buffer overflow! (seriously, you do a function call and just pop off enough stuff to overwrite the instruction pointer).

Framework

The purpose of this assignment is to begin implementing our RTOS.

You are to implement the first several functions and data items listed in the UIKAPI documentation: UIKInitialize, UIKAddTask, UIKRun, UIKDelay, and the internals UIKDispatcher, UIKIdle, UIKTickHandler, UIKTicknum, UIKTickLen, and UIKIntDepth. This will also involve the implementation of the context-switching mechanism you will use inside the process of switching tasks.

In order to demonstrate your scheduler and the use of the API, you can modify some of your earlier assignments to use the API, or write new tasks. You should be able to demonstrate the current execution of at least three tasks at once, all being scheduled by your system.

The code will follow at the end, but first, a video demonstration.

Semaphores

The purpose of this assignment is to add counting semaphores to theUIKAPI. This assignment
can be done in groups of up to two people.

You are to implement the following counting ssemaphore functions:

+ UIKSem* UIKSemCreate(); – will create and initialize a new counting semaphore. The
new semaphore should be initialized to 1. The function should return a pointer to the
new semaphore, or a value of -1 if there was problem creating the semaphore.
+ void UIKSemPend(UIKSem* sem); – will perform the P(s) (wait or test or acquire) operation
on the semaphore. This function should decrement the semaphore value, and if
the result is negative, should block the requesting task.
+ void UIKSemPost(UIKSem* sem); – will perfrmthe V (s) (signal or release) operation on
the semophore. This function is the one that should be called when a task is leaving a
critical section. It should increment the semaphore value, and if the result is less than or
equal to zero, should unblock the highest priority task that is waiting on the semaphore
by changing its state to ready.
+ INT8 UIKSemValue(UIKSem* sem); – will return the current value of the semaphore.

In addition to implementing the semaphore functions, design a set of tasks that demonstrates
the proper operation of your semaphore functions.

The critical sections are implemented by disabling interrupts.  In this assignment, there is a task that delays in the middle of a semaphore lock to demonstrate the trace when two tasks are fighting for the same resource.

Alrighty, so here is a video demonstrating this:

Event Queues

The purpose of this assignment is to add event queues and the associated support routines to
the UIKAPI. This is the last piece of the UIK we will implement – yeah!

A common requirement is for a task to wait until an event occurs. An event is usually some
sort of externally-triggered operation, such as an I/O device requiring service or a timer going
off. One possibility is for an interrupt service routine to set an event flag, then allow tasks to
wait until that flag is set. Once the flag is set, the task can become ready.

An event flag group is an O/S global variable (byte) that represents events by bits. For the
purpose of this exercise, only one event flag will be defined: Bit 0 represents a timer event.
This flag should be set whenever an auxilliary timer goes off. For our implementation, this
timer can be implemented using one of the timers built into the Atmel AVR, spearate from the
timer you are using for the tick. You should write in ISR that handles an interrupt from this
timer by setting bit 0 in the event flags variable.

You are to implement the following event functions:

+ void UIKAssocEvent(int Event); – will cause the task to become ¿associated¿ with
the flag(s) specified by Event. Event is a value that specifies the bits representing one or
more events that the task should be associated with. The task should then block until the
event occurs.
+ void UIKDisassocEvent(int Event); – causes the task to no longer be associated with
the event. In other words, the task will not be scheduled when the event occurs.

In addition to implementing the semaphore functions, design an application that demonstrates
the proper operation of your event functions.

Events are fairly straightforward. project6 adds a timer0 event. taskblinky3 (in tasks.h/tasks.c) is associated with a timer0 overflow via a call to UIKAssocEvent (which sets the task to a wait state and associates the function with the flag). It uses a global flag, EVENT, to keep track of when an interupt occurs. Then, during the tick, if this EVENT flag is set then the function associated with this event will be set to ready.

Here is a video of this:

Code

lundeen_rtos.tar.gz

I guess I’ll post most of it inline here too, because why not?

```//main.c
/*
* This is a simple demonstration of the uik api.
* It schedules 3 simple tasks and lets the scheduler take over execution
*/

#include "uik.h"

/* As per the specs, TICKLEN is the number of 10^-9 seconds on a 1MHz chip */
/* as set below it 1 TICKLEN == 1/100 seconds */
const int TICKLEN = 10000;

extern UIKSem* portbsem;

void init_timer0() {
/*prescaler/64*/
TCCR0 |= ((1 << CS01) | (1 << CS00));
/*overflow mode - about every 1/61 seconds */
TIMSK |= (1 << TOIE0);
}

void main(void) {
int id;

/*Initialize the ports */
DDRB = 0xff;
DDRD = 0x00;

/*semaphore to protect portb */
portbsem = UIKSemCreate();
PORTB = 0xff;

/*Initialize the RTOS - this sets up the timer */
UIKInitialize(TICKLEN);

UIKRun(id);
UIKRun(id);
UIKRun(id);
UIKRun(id);

/*this is an external event we make use of */
init_timer0();

/*this enables interupts, so doesn't need to be done in main */
startrtos();
}

```
```//tasks.h
/*
* This is a simple demonstration of the uik api.
* It schedules 3 simple tasks and lets the scheduler take over execution
*/

#include "uik.h"

/* As per the specs, TICKLEN is the number of 10^-9 seconds on a 1MHz chip */
/* as set below it 1 TICKLEN == 1/100 seconds */
const int TICKLEN = 10000;

extern UIKSem* portbsem;

void init_timer0() {
/*prescaler/64*/
TCCR0 |= ((1 << CS01) | (1 << CS00));
/*overflow mode - about every 1/61 seconds */
TIMSK |= (1 << TOIE0);
}

void main(void) {
int id;

/*Initialize the ports */
DDRB = 0xff;
DDRD = 0x00;

/*semaphore to protect portb */
portbsem = UIKSemCreate();
PORTB = 0xff;

/*Initialize the RTOS - this sets up the timer */
UIKInitialize(TICKLEN);

UIKRun(id);
UIKRun(id);
UIKRun(id);
UIKRun(id);

/*this is an external event we make use of */
init_timer0();

/*this enables interupts, so doesn't need to be done in main */
startrtos();
}

lundeen@AnnieWilkes:~/classes/rtos/project6/project6\$ ls
/*This file contains prototypes of the tasks that will be added */

#include "uik.h"
#include

/*semaphore to protect portb */
UIKSem* portbsem;

/*declare places to save contexts */
/*flash PORTB (tested with LEDs) */

/*declare places to save contexts - this has a forced conflict with blinky*/
/*flash PORTB (tested with LEDs) */

/*declare places to save contexts */
/*flash PORTB (tested with LEDs) */

/*count the lower bytes of PORTB up from 0 to 8 */

#endif

```
```//tasks.h
/*This file contains prototypes of the tasks that will be added */

#include "uik.h"
#include

/*semaphore to protect portb */
UIKSem* portbsem;

/*declare places to save contexts */
/*flash PORTB (tested with LEDs) */

/*declare places to save contexts - this has a forced conflict with blinky*/
/*flash PORTB (tested with LEDs) */

/*declare places to save contexts */
/*flash PORTB (tested with LEDs) */

/*count the lower bytes of PORTB up from 0 to 8 */

#endif

```
```//uik.h
/*
* uik.h contains the header for the uik kernel
*/

#ifndef UIK_H
#define UIK_H

#include
#include

#include
#include

uint8_t priority;
//stack_ptr includes registers, sreg, ip, - eg context
uint8_t* stack_ptr;
//delay is the amount of time the process must wait
uint32_t delay;

/* for now, just make a static array for tcb
TODO: make tcb into something better, like a linked list */

/*saves the current context */
void savecontext( ) __attribute__((naked));
/*restores the context of the taskid */
void restorecontext(uint8_t id) __attribute__((naked));

void UIKInitialize(uint16_t ticklen);
void SIG_OUTPUT_COMPARE1A(void) __attribute__ ((signal, naked));
void tick(void);
void ticknodelay(void);
void startrtos(void) __attribute__ ((naked));
void UIKDelay(uint32_t ticks) __attribute__ ((naked));

/*semaphores */

typedef struct _UIKSem {
uint8_t value;
} UIKSem;

UIKSem* UIKSemCreate();
unsigned char semtest(UIKSem* sem);
void UIKSemPend(UIKSem* sem);
void UIKSemPost(UIKSem* sem);
uint8_t UIKSemValue(UIKSem* sem);

/*Events */

/*MAX_EVENTS cannot be larger than the size of EVENT_FLAG*/
#define MAX_EVENTS 8
#define PORT0_OVERFLOW 0
/*bit 0 of event_flag is associated with a timer0 interrupt */
unsigned char EVENT_FLAG;

uint8_t ASS_BLOCK[MAX_EVENTS];
void UIKAssocEvent(uint8_t Event);
void UIKDisassocEvent(uint8_t Event);

#endif
```
```/*
* uik.c contains the source for the uik kernel
*/

#include "uik.h"

/*0 is always the idle task, which is the default curr_task */

volatile uint8_t* currTCB;

/*
* macro for saving the context: first saves sreg, disables interrupts
* pushes all general purpose registers on the stack and saves where the
* stack is at
*/

#define savecontext()
asm volatile ( "push  r0               nt"
"in    r0, __SREG__     nt"
"cli                    nt"
"push  r0               nt"
"push  r1               nt"
"clr   r1               nt"
"push  r2               nt"
"push  r3               nt"
"push  r4               nt"
"push  r5               nt"
"push  r6               nt"
"push  r7               nt"
"push  r8               nt"
"push  r9               nt"
"push  r10              nt"
"push  r11              nt"
"push  r12              nt"
"push  r13              nt"
"push  r14              nt"
"push  r15              nt"
"push  r16              nt"
"push  r17              nt"
"push  r18              nt"
"push  r19              nt"
"push  r20              nt"
"push  r21              nt"
"push  r22              nt"
"push  r23              nt"
"push  r24              nt"
"push  r25              nt"
"push  r26              nt"
"push  r27              nt"
"push  r28              nt"
"push  r29              nt"
"push  r30              nt"
"push  r31              nt"
"lds  r26, currTCB      nt"
"lds  r27, currTCB+1    nt"
"in    r0, 0x3d         nt"
"st    x+, r0           nt"
"in    r0, 0x3e         nt"
"st    x+, r0           nt"
);

/*
* Opposite to savecontext().  Interrupts will have been disabled during
* the context save so we can write to the stack pointer.
*/

#define restorecontext()
asm volatile (    "lds    r26, currTCB               nt"
"lds    r27, currTCB+1             nt"
"ld     r28, x+                    nt"
"out    __SP_L__, r28              nt"
"ld        r29, x+                 nt"
"out    __SP_H__, r29              nt"
"pop    r31                        nt"
"pop    r30                        nt"
"pop    r29                        nt"
"pop    r28                        nt"
"pop    r27                        nt"
"pop    r26                        nt"
"pop    r25                        nt"
"pop    r24                        nt"
"pop    r23                        nt"
"pop    r22                        nt"
"pop    r21                        nt"
"pop    r20                        nt"
"pop    r19                        nt"
"pop    r18                        nt"
"pop    r17                        nt"
"pop    r16                        nt"
"pop    r15                        nt"
"pop    r14                        nt"
"pop    r13                        nt"
"pop    r12                        nt"
"pop    r11                        nt"
"pop    r10                        nt"
"pop    r9                         nt"
"pop    r8                         nt"
"pop    r7                         nt"
"pop    r6                         nt"
"pop    r5                         nt"
"pop    r4                         nt"
"pop    r3                         nt"
"pop    r2                         nt"
"pop    r1                         nt"
"pop    r0                         nt"
"out    __SREG__, r0               nt"
"pop    r0                         nt"
);
/*
* UIKInitialize sets up the timer, and adds the idle task to tcb
*/

void UIKInitialize(uint16_t ticklen) {
int i;

// setup timer - timer1 is used so we can use 16 bits
TCCR1B |= (1 << WGM12);
//enable CTC interrupt
TIMSK |= (1 << OCIE1A);
OCR1A = ticklen;

//not default:timer runs with /64 resolution
//TCCR1B |= ((1 << CS10) | (1 << CS11));
//default: timer1 runs at 1MHz on the atmega16 so ticklen can be specified in microsecs
TCCR1B |= (1 << CS10);

//initialize the ASS_BLOCK so that there are no events associated
//with anything - note interupts are not enabled yet
//error, tcb is not big enough, need to increase max_numtasks in uik.h
return (-1);
}
//setup parameters
//"initialized" could be changed to ready without much effect, but UIKRun would
//not have to be called

// place a few known bytes on the bottom - useful for debugging

// will be location of most significant part of stack address
*stack_ptr = 0x11;
stack_ptr--;
// least significant byte of stack address
*stack_ptr = 0x22;
stack_ptr--;
*stack_ptr = 0x33;
stack_ptr--;

// address of the executing function
stack_ptr--;
stack_ptr--;

//simulate stack after a call to savecontext
*stack_ptr = 0x00;  //necessary for reti to line up
stack_ptr--;
*stack_ptr = 0x00;  //r0
stack_ptr--;
*stack_ptr = 0x00;  //r1 wants to always be 0
stack_ptr--;
*stack_ptr = 0x02;  //r2
stack_ptr--;
*stack_ptr = 0x03;  //r3
stack_ptr--;
*stack_ptr = 0x04;  //r4
stack_ptr--;
*stack_ptr = 0x05;  //r5
stack_ptr--;
*stack_ptr = 0x06;  //r6
stack_ptr--;
*stack_ptr = 0x07;  //r7
stack_ptr--;
*stack_ptr = 0x08;  //r8
stack_ptr--;
*stack_ptr = 0x09;  //r9
stack_ptr--;
*stack_ptr = 0x10;  //r10
stack_ptr--;
*stack_ptr = 0x11;  //r11
stack_ptr--;
*stack_ptr = 0x12;  //r12
stack_ptr--;
*stack_ptr = 0x13;  //r13
stack_ptr--;
*stack_ptr = 0x14;  //r14
stack_ptr--;
*stack_ptr = 0x15;  //r15
stack_ptr--;
*stack_ptr = 0x16;  //r16
stack_ptr--;
*stack_ptr = 0x17;  //r17
stack_ptr--;
*stack_ptr = 0x18;  //r18
stack_ptr--;
*stack_ptr = 0x19;  //r19
stack_ptr--;
*stack_ptr = 0x20;  //r20
stack_ptr--;
*stack_ptr = 0x21;  //r21
stack_ptr--;
*stack_ptr = 0x22;  //r22
stack_ptr--;
*stack_ptr = 0x23;  //r23
stack_ptr--;
*stack_ptr = 0x24;  //r24
stack_ptr--;
*stack_ptr = 0x25;  //r25
stack_ptr--;
*stack_ptr = 0x26;  //r26
stack_ptr--;
*stack_ptr = 0x27;  //r27
stack_ptr--;
*stack_ptr = 0x28;  //r28
stack_ptr--;
*stack_ptr = 0x29;  //r29
stack_ptr--;
*stack_ptr = 0x30;  //r30
stack_ptr--;
*stack_ptr = 0x31;  //r31
stack_ptr--;

//store the address of the stack

}

/*
* UIKRun is sort of unnecessary, but since it's in the specification API we will
* force the call here, inventing a distinction between the "initialized" and
*/

//the scheduler will handle if/when it actually runs based on priority
}

/*this is the scheduler - handled in an interrupt (other interupts are disabled) */
void SIG_OUTPUT_COMPARE1A(void) {
//save the execution context - this disables interupts
savecontext();
tick();
restorecontext();
//reti re-enables interrupts
asm volatile ("reti");
}

/*
* tick increments through tcb and does 2 tasks: it increments the delays and
* finds the maximum ready task. One constraint is the tick should be long enough
* that this has a chance to complete.
*/

void tick(void) {
int i;
//and has lowest priority
int high = 0;

for(i=0; i 0) {
tcb[i].delay--;
if(tcb[i].delay == 0) {
//the state should have been waiting
}
}
//if an event needs to be dealt with by marking the task as ready
//and updating "Event"
if(EVENT_FLAG != 0) {
//if tcb[i] in ASS_BLOCK, mark tcb[i] as ready
//if xxxxxxx1
if((EVENT_FLAG & (unsigned char)0x01) != 0) {
//reset the bit to 0
EVENT_FLAG &= 0xFE;
}
see UIKAssocEvent */
}

if(tcb[i].state == ready && tcb[i].priority < tcb[high].priority) {
high = i;
}
}
//EVENT_FLAGS should all be dealt with now and their processes marked as ready
currTCB = tcb[high].stack_ptr;
}

/*
* ticknodelay is the tick without decrementing delays
* this is kind of a band-aid
*/

void ticknodelay(void) {
int i;
//and has lowest priority
int high = 0;

//if an event needs to be dealt with by marking the task as ready
//and updating "Event"
if(EVENT_FLAG != 0) {
//if tcb[i] in ASS_BLOCK, mark tcb[i] as ready
//if xxxxxxx1
if((EVENT_FLAG & (unsigned char)0x01) != 0) {
//reset the bit to 0
EVENT_FLAG &= 0xFE;
}
see UIKAssocEvent */
}

if(tcb[i].state == ready && tcb[i].priority < tcb[high].priority) {
high = i;
}
}
//EVENT_FLAGS should all be dealt with now and their processes marked as ready
currTCB = tcb[high].stack_ptr;
}

/*
* startrtos sets up the idletask, enables interrupts, and begins the idletask executing
* it will be interupted if any other tasks exist on the first tick
*/

void startrtos(void) {
currTCB = tcb[0].stack_ptr;

//this is the idle process, it will be swapped out soon enough
restorecontext();
//enable interupts with the return
asm volatile ("reti");
}

/*
* This is the interupt that is in charge of scheduling
*/

void UIKDelay(uint32_t ticks) {
//save the execution context - this disables interupts
savecontext();
//if a -1 is passed it implies no time passes tick-wise
if (ticks value = 1;
return thissem;
}

/*
* This is for UIKSemPend logic
*/

unsigned char semtest(UIKSem* sem) {
if(sem->value > 0) {
//critical secion - must retest
cli();
if(sem->value > 0) {
sem->value--;
sei(); //end critical section
return 1;
}
}
return 0;
}

/*
* This is the semaphore acquire
*/

void UIKSemPend(UIKSem* sem) {
//wait until sem > 0
while (semtest(sem) == 0) {
//delay current task, which is the one trying to access semaphore
//implies highest priority task gets semaphore first
UIKDelay(1);
}
}

/*
* This is the semaphore release
*/

void UIKSemPost(UIKSem* sem) {
//critical section
cli();
sem->value++;
sei(); //end critical section
//theoretically shouldn't have to do anything
//but just as to not have to wait for the next tick
UIKDelay(0);
}

/*
* This returns the current value of a semaphore
*/

uint8_t UIKSemValue(UIKSem* sem) {
return sem->value;
}

/*
* UIKAssocEvent associates an external event with the process that calls it
* the events are defined in uik.h
*/

void UIKAssocEvent(uint8_t Event) {
//one function can be associated with multiple events
//but an event should only be associated with one function at a time
//error checking does not exist to save space, but be wary

//if you would like to error check, just verify if(ASS_BLOCK[i] != 255) for every bit
//before setting it. also you would need to reenable interupts before returning

if(Event == 0) {
//succesfuly give them the nothing they ask for
return;
}
//ASS_BLOCK and curr_task must be protected
//unless we want a semaphore for curr_task, the best way seems to just be to disable
//interupts
cli();
//set the state for waiting, since it's waiting for the event to occur

//if xxxxxxx1
if((Event & 0x01) != 0) {
}
//if xxxxxx1x
if((Event & 0x02) != 0) {
}
//if xxxxx1xx
if((Event & 0x04) != 0) {
}
//if xxxx1xxx
if((Event & 0x08) != 0) {
}
//if xxx1xxxx
if((Event & 0x10) != 0) {
}
//if xx1xxxxx
if((Event & 0x20) != 0) {
}
//if x1xxxxxx
if((Event & 0x40) != 0) {
}
//if 1xxxxxxx
if((Event & 0x80) != 0) {
}
sei();
//give up execution - a -1 allows the other processes not to tick
UIKDelay(-1);
}

/*
* UIKDissasocEvent disassociates a task with an external event
*/

void UIKDisassocEvent(uint8_t Event) {
//a semaphore could easily be used in place of disabling interupts
cli();
//if xxxxxxx1
if((Event & 0x01) != 0) {
ASS_BLOCK[0] = 255;
}
//if xxxxxx1x
if((Event & 0x02) != 0) {
ASS_BLOCK[1] = 255;
}
//if xxxxx1xx
if((Event & 0x04) != 0) {
ASS_BLOCK[2] = 255;
}
//if xxxx1xxx
if((Event & 0x08) != 0) {
ASS_BLOCK[3] = 255;
}
//if xxx1xxxx
if((Event & 0x10) != 0) {
ASS_BLOCK[4] = 255;
}
//if xx1xxxxx
if((Event & 0x20) != 0) {
ASS_BLOCK[5] = 255;
}
//if x1xxxxxx
if((Event & 0x40) != 0) {
ASS_BLOCK[6] = 255;
}
//if 1xxxxxxx
if((Event & 0x80) != 0) {
ASS_BLOCK[7] = 255;
}
sei();
}

/*
* timer0 overflowing is a hardware event that our event functionality handles
*/

ISR(TIMER0_OVF_vect) {
//interupts are disabled since this is an interrupt so locking event_flag not necessary
//the 0th bit is associated with timer0
EVENT_FLAG |= (1 << PORT0_OVERFLOW);
}
```

Installation/Compilation

Due to the complex nature of this program, it was compiled with AVR Studio on Windows XP. Although I certainly miss my usual development tools on Linux, the AVR studio debugger was much better in my opinion.

To compile, open project6.aps, select Build->Rebuild All. To copy to the Atmega16, click on the “AVR” sprite. Under Program ->Flash, click the “Program” button and select the homework4_*.hex file.

Of course, everything should work under linux as well.

Paper Fun: Simplified Single Packet Authorization

Another paper to be presented next week at worldcomp

Port Knocking and Single Packet Authorization (SPA) are relatively new (circa 2004 and later) techniques used to enable anonymous, temporary activation of remote network services that are otherwise blocked by means of a firewall. These techniques greatly enhance the so-called “zero-day” exploit resilience of systems which properly implement them, but they have weaknesses and more importantly share a weakness common to most common security augmentation system: human nature. This paper presents a framework for securely enabling remote services in a manner which focuses on the human factor, a concept often neglected in security research and the key reason that such systems rarely see widespread usage in the real-world. The primary focus is to make SPA easier for humans to interact with.

pdf paper is here: Simplified Single Packet Authorization_1.4

Paper fun: Concerns with Time-Space Based Wireless Security

I’m presenting this at worlcomp this year.

Abstract:

Wireless ad-hoc network protocols are a  topic of much recent discussion and development. This has prompted many researchers to develop interesting and promising-sounding protocols that should be considered and examined. One such protocol, Authenticated Protocol for Wireless Ad Hoc Networks (APEC), was designed by Robert Hiromoto and Hope Forsmann[1]. APEC has been the subject of an increasing amount of scientific discussion and research around Universities, Laboratories, and professional conferences. In this paper, we examine APEC in depth and discuss many potential problems with the protocol that must be addressed if APEC is achieve widespread acceptance.

Paper: probelm_with_time_0.7

GPG Cheat Sheet

The gnu Privacy handbook has a ton of useful information, but I thought I’d make a quick reference for the gpg usage I use most. Especially because I was just an idiot and lost my gpg private key (though I do remember the passphrase) – this time there will be a backup!

List all keys

gpg –list-keys

print key to a file (mypublickey) – <keyid> is listed when you do list-keys

gpg -ao mypublickey.key –export <keyid>

show secret keys

gpg –list-secret-keys

backup secret keys

gpg -a –export-secret-keys <keyid> | gpg-aco myprivatkeyfile.key.gpg

Restoring the key

gpg –import {keyfile}

Restore an encrypted key

gpg –decrypt {privatekeyfile} | gpg –import

Sign a file

gpg –output doc.sig –sign doc

verify signature

gpg –output mydoc –decrypt doc.sig