Does this page look familiar?
 
[home] [environment] [contact] [for sale] (code) [cars] [links] [essays]

andrew warren's home page

tiny encryption algorithm
Strong cryptography is classified as a munition by the United States statute which places export restrictions on munitions.  

That statute contains an exemption for material which is freely available in public libraries, but it's still unclear whether anonymous ftp sites and web pages qualify as "public libraries".  

Therefore, I must ask non-US users of this site not to download these files, since they contain software which could be construed to fall under US export-control law.  

Download TEA16.ZIP  
View TEA16.TXT  

Download TEA17.ZIP  
View TEA17.TXT 

 
The Tiny Encryption Algorithm (TEA) was developed by David Wheeler and Roger Needham at the Computer Laboratory of Cambridge University. 

It's very fast when implemented on 32-bit machines with barrel shifters, and even on the Microchip PIC16 -- an 8-bit accumulator-based microcontroller with neither a barrel shifter nor even an "add with carry" instruction -- it's no slouch. 

Performance specs for my implementations: 

 
 
RAM
ROM
SPEED
TEA16 40 bytes 295 words 6K bytes/sec @ 20 Mhz
TEA17 37 bytes 192 words 12K+ bytes/sec @ 33 MHz
A PIC18 version is in the works, and it'll be available here as soon as Microchip publicly releases the PIC18 instruction set. 

The TEA algorithm has been released to the public domain.  More information on the algorithm is available from the University of Bradford's Cryptography & Computer Communications Security Group, at http://vader.brad.ac.uk/tea/tea.shtml


bcd clock
Thanks to Scott Dattalo for his assistance in making this routine as small as it is. 
 
This little routine, which will run on any of the Microchip PICs including the 12-bit parts, maintains a clock whose variables are stored in packed-BCD format [that is, the numbers in the table below are hexadecimal]

Call it once per second, and it'll adjust HOURS, MINUTES, and SECONDS as shown in the table below.  As an added bonus, it'll return with the carry flag set when the HOURS register rolls over from 23 to 00. 
 

Before calling TICK
After calling TICK
HOURS
MINUTES
SECONDS
HOURS
MINUTES
SECONDS
09
00
00
09
00
01
09
59
59
10
00
00
23
59
59
00
00
00
SECONDS EQU     [any register, on any page] 
MINUTES EQU     SECONDS+1 
HOURS   EQU     MINUTES+1 

TICK:   MOVLW   SECONDS 
        MOVWF   FSR 
        CALL    SUB1 
        CALL    SUB0 
        CALL    SUB0 
        GOTO    SUB2 

SUB0:   INCF    FSR 
        SKPNC 
SUB1:   INCF    INDF 

        MOVLW   6 
        ADDWF   INDF 
        SKPDC 
        SUBWF   INDF 

        MOVLW   0100H - 060H 
SUB2:   ADDWF   INDF,W 
        SKPNC 
        CLRF    INDF 

        RETLW   0100H - 024H 


day of the week
Want to mentally calculate the day of the week for any month, day, and year? 

Here's how: 

Just remember that, in any given year, the following nine dates all fall on the same day of the week: 
 
4/4 These should be easy to remember
6/6
8/8
10/10
7/11 These can be remembered by the mnemonic, "I work at the 7-11, from 9 to 5."
11/7
9/5
5/9
last day of February Either the 28th or 29th, depending
In 1998, those nine dates all fall on Saturday.  Every year, this day advances by one, unless the year is a leap year, in which case it advances by two. 

That is... These nine dates will all fall on Sunday in 1999, on Tuesday in 2000 (because 2000 is a leap year), on Wednesday in 2001, on Thursday in 2002, etc. 

Now... If someone asks you, "Quick!  What day is August 2, 1999?", you'd think, "Hmm... 8/8 is a Saturday this year, so it'll be a Sunday next year, and six days before that would be, umm...", and answer "Monday!" 

With a little practice, you'll find that you can come up with the day of the week in just a few seconds, for any date within a few years of today. 

Since you know that the day of the week advances by five days every four years, you can easily calculate the day-of-the-week for years further in the past and future, too. 

The only thing you'll have to remember, if you're asked to prove that you're some sort of Rainman-esque idiot savant by calculating the day of the week for dates in other centuries, is that century years are only leap years if they're divisible by 400.  That is, 2000 is a leap year, but 1700, 1800, 1900, and 2100 aren't. 

That last bit is complicated, so if it were me, I'd answer those "Rainman" challenges with: "What do you think I am... An idiot savant or something?"  
 
 

Here's a little routine that'll calculate the day of the week for any date between 1 January 1995 and 31 December 2094: 

DAY     EQU     [any register] 
MONTH   EQU     [any register] 
YEAR    EQU     [any register] 
DOW     EQU     [any register] 

; FOR ANY DATE BETWEEN JANUARY 1 1995 AND DECEMBER 31 1994, 
; CALCULATE THE DAY OF THE WEEK [0=SUNDAY, 1 = MONDAY, 
; .... 6 = SATURDAY]. 
; 
; ENTER WITH MONTH [1-12] IN "MONTH", DAY-OF-MONTH [1-X] 
; IN "DAY", AND YEAR [95-99, 00-94] IN "YEAR".  IF "YEAR" 
; IS LESS THAN 95, THIS SUBROUTINE ASSUMES THAT WE'RE IN 
; THE 21ST CENTURY.  OTHERWISE, IT ASSUMES THAT WE'RE IN 
; THE 20TH. 
; 
; ON EXIT, DAY-OF-WEEK IS IN "DOW".  "DAY", "MONTH", AND 
; "YEAR" ARE UNCHANGED. 

DAYWEEK: 

; THE FOLLOWING TWO LINES ARE ONLY NECESSARY IF YOU'RE 
; USING A 14-BIT PIC (16C6X, 16C7X, 16C8X, ETC.).  FOR 
; ALL OTHER PICS, JUST MAKE SURE THAT THE "MONTHTBL" 
; SUBROUTINE IS ENTIRELY CONTAINED IN PAGE 0. 

        MOVLW   HIGH MONTHTBL   ;MAKE SURE THE "ADDWF PCL" 
        MOVWF   PCLATH          ;IN "MONTHTBL" WORKS. 

        DECF    MONTH,W         ;W = MONTH - 1. 
        CALL    MONTHTBL        ;LOOKUP THE D-O-W FOR THE 
                                ;1ST OF THIS MONTH. 

        MOVWF   DOW             ;STORE IT. 

; AGAIN, THE FOLLOWING TWO LINES ARE ONLY NECESSARY FOR 
; PARTS THAT USE "PCLATH". 

        MOVLW   $+2             ;RESTORE PCLATH. 
        MOVWF   PCLATH          ; 

        MOVLW   3               ;MONTH >= MARCH? 
        SUBWF   MONTH,W         ; 
        BNC     NOLEAP          ;IF NOT, JUMP AHEAD. 

        MOVLW   00000011B       ;OTHERWISE, IS THIS A 
        ANDWF   YEAR,W          ;LEAP YEAR? 

        BNZ     NOLEAP          ;IF NOT, JUMP AHEAD. 

; IT'S MARCH 1ST OR LATER, AND THIS YEAR'S A LEAP YEAR. 

        INCF    DOW             ;ADD A LEAP DAY. 

NOLEAP: 

        CLRC                    ;DOW = DOW + (YEAR-1)/4 
        RLF     DOW             ; 
        DECF    YEAR            ;    = 2*DOW + (YEAR-1)/2 
        RLF     YEAR,W          ;      ------------------. 
        RRF     YEAR,W          ;              2 
        INCF    YEAR            ; 
        ADDWF   DOW             ; 
        CLRC                    ; 
        RRF     DOW             ; 

        MOVF    DAY,W           ;DOW = DOW + DAY + YEAR. 
        ADDWF   YEAR,W          ; 
        ADDWF   DOW             ; 

        MOVLW   95              ;YEAR < 95? 
        SUBWF   YEAR,W          ; 
        SKPC                    ;IF NOT, SKIP AHEAD. 

        DECF    DOW             ;OTHERWISE, DOW = DOW - 1. 

        MOVLW   7               ;DOW = DOW MOD 7. 
                                ; 
        SUBWF   DOW             ; 
        SKPNC                   ; 
        GOTO    $-2             ; 
                                ; 
        ADDWF   DOW             ; 

        RETURN                  ;RETURN.  IF YOU'RE USING 
                                ;A 12-BIT PIC, MAKE THIS A 
                                ;"RETLW 0" OR SOMETHING. 

MONTHTBL: 

        ADDWF   PCL 

        DT      7,10,10,13      ;DAY-OF-WEEK FOR FIRST DAY 
        DT      8,11,13,9       ;OF EACH MONTH (IN YEAR 
        DT      12,7,10,12      ;1995). 7=SUNDAY, 8=MONDAY, 
                                ;...., 13=SATURDAY.


minimum 
Thanks to John Payson for the idea on which this routine is based. Given three values stored in registers NUM1, NUM2, and NUM3, this 
routine finds the minimum value and stores it in RESULT, leaving 
NUM1, NUM2, and NUM3 unchanged. 

9 words, 9 instruction cycles. 

;NOTE:  In the comments below, "min(A,B)" means "the lesser ;       of A and B". 

        MOVF    NUM1,W  ;Set the Carry flag if NUM1 is less 
        SUBWF   NUM2,W  ;than NUM2. 

        MOVF    NUM1,W  ;Assume that NUM1 was less than 
                        ;NUM2.  This instruction does NOT 
                        ;affect the Carry flag. 

        SKPC            ;If NUM1 really was less than NUM2, 
                        ;skip ahead with W = NUM1. 

        MOVF    NUM2,W  ;Otherwise, W = NUM2. 

;At this point, W contains min(NUM1,NUM2). 

        MOVWF   RESULT  ;Store it in RESULT. 

;At this point, both W and RESULT contain min(NUM1,NUM2). 

        SUBWF   NUM3,W  ;Set the Carry flag if W [which 
                        ;contains min(NUM1,NUM2), remember] 
                        ;is less then NUM3. 

;At this point, RESULT still holds min(NUM1,NUM2), but W now 
;contains NUM3 - min(NUM1,NUM2). 

        SKPC            ;If W really was less than NUM3, skip 
                        ;ahead. 

        ADDWF   RESULT  ;Otherwise, 
                        ;RESULT= RESULT + W 
                        ;      = min(N1,N2) + W 
                        ;      = min(N1,N2) + [N3-min(N1,N2)] 
                        ;      = N3. 
                        ; 

;At this point, RESULT holds min(NUM3,min(NUM1,NUM2)), which ;is of course equivalent to min(NUM1,NUM2,NUM3).


bcd to binary
These routines convert unpacked BCD inputs to binary. 

The first one works only on inputs in the range [0-255]; it performs the conversion in 13 cycles on any of the PIC16Cxx parts: 

        RADIX DEC 

; Enter with a BCD number in HUND, TENS, and ONES (one digit 
; per register)... We don't care if they're straight numbers 
; in the range [0-9] or ASCII values in the range 
; [0x30-0x39]. 
; 
; Exits with HUND, TENS, and ONES unchanged, and 
; W = (HUND * 100) + (TENS * 10) + ONES. 
; 
; Note that this routine ONLY works if the input BCD number 
; is in the range [0-255]. 
; 
; 13 cycles. 

BCD2BIN: 

        MOVF    ONES,W 

        BTFSC   TENS,0 
        ADDLW   10 
        BTFSC   TENS,1 
        ADDLW   20 
        BTFSC   TENS,2 
        ADDLW   40 
        BTFSC   TENS,3 
        ADDLW   80 

        BTFSC   HUND,0 
        ADDLW   100 
        BTFSC   HUND,1 
        ADDLW   200 

This one's not quite so elegant, but it's faster; it performs the conversion in 10 cycles: 

        RADIX DEC 

; Enter with a BCD number in HUND, TENS, and ONES (one digit 
; per register).  Each register (well... TENS, anyway) must 
; hold a number in the range [0-9]. 
 
; Exits with ONES and HUND unchanged, TENS scrambled, and 
; W = (HUND * 100) + (TENS * 10) + ONES. 
; 
; Note that this routine ONLY works if the input BCD number 
; is in the range [0-255]. 
; 
; 10 cycles. 

BCD2BIN: 

        CLRC  
        RLF     TENS,W 
        SWAPF   TENS  
        RRF     TENS  
        ADDWF   TENS,W  

        ADDWF   ONES,W 

        BTFSC   HUND,0 
        ADDLW   100 
        BTFSC   HUND,1 
        ADDLW   200 

If you need to deal with three-digit numbers up to 999, you could do 
something like this hideous routine (which I'm providing, because it 
amuses me to do so, with no line-by-line comments).  It requires 29 cycles: 

        RADIX DEC 

; Enter with a BCD number in HUND, TENS, and ONES (one digit 
; per register).  Each register (well... TENS, anyway) must 
; hold a number in the range [0-9]. 
; 
; Exits with ONES and HUND unchanged, TENS scrambled, and 
; HI_BYTE:LO_BYTE = (HUND * 100) + (TENS * 10) + ONES. 
; 
; This routine works for all BCD inputs in the range 
; [000-999]. 
; 
; 29 cycles. 

BCD2BIN: 

        CLRC  
        RLF     TENS,W  
        SWAPF   TENS  
        RRF     TENS  
        ADDWF   TENS,W  

        ADDWF   ONES,W 

        BTFSC   HUND,0 
        ADDLW   100 

        CLRF    HI_BYTE 

        BTFSC   HUND,1 
        ADDLW   200 
        RLF     HI_BYTE 

        BTFSC   HUND,2 
        ADDLW   LOW (400) 
        RLF     HI_BYTE 

        BTFSC   HUND,3 
        ADDLW   LOW (800) 

        MOVWF   LO_BYTE 

        MOVLW   00000001 
        ANDWF   HI_BYTE,W 
        BTFSC   HI_BYTE,1 
        ADDLW   1 
        SKPNC 
        ADDLW   1 

        BTFSC   HUND,2 
        ADDLW   HIGH (400) 

        BTFSC   HUND,3 
        ADDLW   HIGH (800) 

        MOVWF   HI_BYTE

 
All code on this page is copyright © 1998 Fast Forward Engineering
Permission is hereby granted for non-commercial use
 

go to the SiliconValley GeoPage 
© aw 1998. All rights reserved. Last modified: 13 May 1998
 
  1