Tuesday, September 18, 2012

Interview with an Embedded Engineer?


1) What is the question that confused you the most?

When I was asked what is "Endian"? I was confused the most. I know Indian, but what is endian? Does it have printed with misspelled?

2) What do you think your great achievment with your more than 8 years experience in the embedded field?

Often, I used to be proud of myself that I have not burnt even one board withgiving wrong power supply connection, though I have handled many boards and different power adapters at the same time.

3) What was the happiest moment in your embedded carrier?

Yeah. For the first time, I went abroad for a 1 and half month on-site assignment. Finishing the project and finally escaping to the airport from the customer was the most happiest moment in my life.

4) What was the most depressing moment in your embedded carrier?

When the above said abroad customer called me back to on-site, when they found that I had returned back to my home country without implementing a functionality in that project.

5) Which one you most like in embedded development?

When I find a controller is exctly same with another one which had driver already developed. Really I like and enjoy that moment.

6) Which one you most hate?

When I heard that your code works fine. But, it throws exception when operating at very high speed.

7) Most dislike words in embedded?

PLL setting, SDRAM clock configuration, Exception

8) Forgotten keywords after getting into embedded?

scanf()

9) The word you like the most?

porting

10) What is your future goal?

I used to think why so many different platforms like ARM, PowerPC, SuperH? Let them merge all and make a single platform with single program for everything. Let the embedded engineers enjoy their life by doing simple porting. And, very intelligent run-time Exception Handling CPU and OS platforms. They should clearly say what was the problem.

Embedded Jokes

① Engineer's logic

An Engineer was asked to design a device. What the device should do is, if you give a book name and book store name, it should call the book store and inquire about availability of the book. He finished the assignment and kept the device for demo.
One guy came and input a book name and a store name. The device called the store, asked for the book and gave him the result. He went happily. Another guy came. He too input a book name and a store name. Immediately, a message was showed by the device as "Could not get contact number of the store!". He thought of trying another store. So, he input an another store name. This time, the device called the store and asked for the contact number of the previous store.

② Why is it very difficult to meet deadlines in embedded?

In embedded, the "target" itself is not fixed one and that can be easily reset.

③ Why did they keep name "Daughter" card, you know?

Though they are cute, it is very difficult to understand the connection. They will bring tears in your eyes one day, when you fully understand the relationship.

Monday, September 17, 2012

i.MX51/i.MX53: Interrupt occurs with no bit set in HIPND


Problem:

In my program, whenever interrupt occurs, I read HIPND0, HIPND1, HIPND2, HIPND3, registers to decide the interrupt number of the interrupt source.

But, when there are frequent interrupts, sometimes all of HIPND0, HIPND1, HIPND2, HIPND3 registers read zero(0). Because of this, I could not decide the interrupt number/source. Are they spurious interrupts? There is nothing specified about the spurious interrupts in i.MX51 Reference Manual.

In other words, none of interrupt bits are set in HIPNDx registers, inside my interrupt service routine. Or, interrupt occurs without any bit set in HIPNDx registers. Thus, reading of HIPND results in interrupt number of 0.

Solution:

What happens?

They are not spurious interrupts. There are no spurious interrupts in i.MX51. Problem is in your program. If your program reads HIPNDx registers in series as follows, there is chance that the contents of HIPND registers changed whenever a higher priority interrupt occurs.

For example, assume that interrupt occurs and HIPND2 register is set 0x80000000 and all other registers are set to zero. When you are reading HIPND1, there is chance that a higher priority interrupt occurs and HIPND0 register will become set to 0x40000000 and HIPND2 register will become set to 0. So, your reading will result that all are HIPND registers are zero.

    int intr_number;

    if (register_read(HIPND0) != 0)
        intr_number = 0;
    else  if (register_read(HIPND1) != 0)
        intr_number = 32;
    else  if (register_read(HIPND2) != 0)
        intr_number = 64;
    else  if (register_read(HIPND3) != 0)
        intr_number = 96;
//    else
//        printf("Error: All are set to zero\n");

Howto correct it?

1) Reread the HIPND registers as follows:

    int retry = 0;

    for (;;) {
        if (register_read(HIPND0) != 0)
            intr_number = 0;
        else  if (register_read(HIPND1) != 0)
            intr_number = 32;
        else  if (register_read(HIPND2) != 0)
            intr_number = 64;
        else  if (register_read(HIPND3) != 0)
            intr_number = 96;
        else if (retry++ < NUMBER_OF_PRIORITY_LEVELS)
            continue;
    }

2) Use PND registers to read the pending interrupts, if your program do not worry about interrupt priority.

3) Set all interrupts same priority.

It applies to iMX series processors i.MX515, i.MX535, etc,. Give your comments to improve this post. Have a nice day!

Thursday, May 24, 2012

What is Hard Real Time OS?

There is no particular specification for Hard Real-Time OS kernel. But, it can be defined as "a Real-Time OS kernel which can be used to build a Hard Real-Time System". What is a Real-Time System? Hard Real-Time System is a combination of Hardware plus Software which has been designed so that it will meet all of its deadlines even when the system is loaded to the maximum. 

As a simple example, you have an hardware target board in which you run TCP application which just downloads the data at High priority. And, it has a periodic Task at Low priority which blinks the status LED at 1 second interval. If you can make the status LED to stop blinking by downloading a big amount of data, then it is not a Hard Real-Time system. If you have designed the system so that the LED never stops blinking even if you download a big amount of data continuously, that is called Hard Real-Time System. It does not matter whether you use an RTOS or not, whether you use an Single core or Multi-core. If an RTOS kernel can help such a system, then it can be called Hard Real-Time OS kernel. So, what are all the requirements to be met to help to build such a system? You can say a OS is a Hard Real-Time OS, if

① The execution time of each and every system call of the kernel, interrupt latency and the task switching time have been defined/measured accurately. They are predetermined.

② Priority-based pre-emptive kernel. The Kernel always runs the tasks, interrupt service routines according to the priority. At any point of time, it runs the highest priority task or ISR of the current moment.

③ The system never gets into deadlock. Priority inversion has been implemented by Mutex.

The application should be designed according to the Rate Monotonic Algorithm to be Hard Real-Time.


Finally, I can define a Hard Real-Time OS as follows. The requirements are as specified above:

A Real-Time OS Kernel which facilitates to build an application that can meet all of its deadlines even when the system is loaded to the maximum is called a Hard Real-Time Operating System.
 
------
1) Rate Monotonic Scheduling Algorithm
It is about two things. One is about priority assignment. Second is total CPU utilization.
 
a) the shorter cycle duration is, the higher is the job's priority
 
Assume you will have enough time to complete all tasks. But, if you finish the job, who will come to you first, it will be safe. So, whose deadline is shorted, finish it first.
 
b) Overall CPU utilization has to be maximum of 69.3 % to meet all deadlines assuming infinite number of tasks.
 
This assumes all the tasks are periodic, Ti specifies the cycle period and Ci specifies the worst-case execution time. So, utilization specifies howmany percentage in one second is utilized by each task. Addition of all specifies the total utilization.
 
U = C1/T1 + C2/T2 + C3/T3 +....

Saturday, May 12, 2012

Linux Questions

How linux porting is done? What are all the challenges?

build → make config
         make dep
         make
Change of memory map → Where?




Kernel Boot flow?

http://milindchoudhary.wordpress.com/2009/03/30/linux-boot-process

vmlinux image is compressed and zImage is created.

_zimage_start → ELF ENTRY → arch/powerpc/boot/zImage.lds.S
  ordered as text, data, dtb(embedded Device tree blob), vmlinux, initrd, bss
  To extract the kernel vmlinux, System.map, .config or initrd from the zImage binary:
    objcopy -j .kernel:vmlinux -O binary zImage vmlinux.gz
    objcopy -j .kernel:System.map -O binary zImage System.map.gz
    objcopy -j .kernel:.config -O binary zImage config.gz
    objcopy -j .kernel:initrd -O binary zImage.initrd initrd.gz
  
_zimage_start → arch/powerpc/boot/crt0.S
  Initialized stack, bss and C environment
  call platform_init
  branch to start
platform_init → arch/powerpc/boot/redboot-8xx.c
  initialize serial console
  display clock-frequency
  assign the command line to loader_info
start → arch/powerpc/boot/main.c
  "\n\rzImage starting: loaded at 0x%p (sp: 0x%p)\n\r"
  prepare kernel (prep_kernel())
     unzip _vmlinux_start, _vmlinux_end
      "Allocating 0x%lx bytes for kernel ...\n\r"
    "gunzipping (0x%p <- 0x%p:0x%p)..."
      "done 0x%x bytes\n\r"
  prepare ramdisk (prep_initrd())
    "Attached initrd image at 0x%p-0x%p\n\r"
        or
    "Using loader supplied ramdisk at 0x%lx-0x%lx\n\r"
    "Allocating 0x%lx bytes for initrd ...\n\r"
    "Relocating initrd 0x%lx <- 0x%p (0x%lx bytes)\n\r"
    /* Tell the kernel initrd address via device tree */
    "linux,initrd-start" "linux,initrd-end"

  prepare command line (prep_cmdline())
    "bootargs" "\n\rLinux/PowerPC load: %s"
    /* If possible, edit the command line */
    /* Put the command line back into the devtree for the kernel */
    "bootargs", cmdline
Function pointer _vmlinux_start((unsigned long)initrd.addr, initrd.size, loader_info.promptr);
(Find the initial symbol of vmlinux image. Find vmlinux.lds. Makefile at top of Linux source.)
ENTRY(_stext) → arch/powerpc/kernel/vmlinux.lds
ENTRY(_stext) → arch/powerpc/kernel/head_8xx.S
  to map the first 8M 1:1
  call initial_mmu
  call turn_on_mmu
  /* Decide what sort of machine this is and initialize the MMU */
  bl      machine_init
  bl      MMU_init
  branch to start_kernel
start_kernel → init/main.c
  tick_init();
  boot_cpu_init();
  print linux banner
    "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
     LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n";
  setup_command_line(command_line);
  printk(KERN_NOTICE "Kernel command line: %s\n", boot_command_line);
  sched_init();
  init_IRQ();
  init_timers();
  sched_clock_init();
  calibrate_delay();
  rest_init();
rest_init();
  rcu_scheduler_starting();
  /*
  * We need to spawn init first so that it obtains pid 1, however
  * the init task will end up wanting to create kthreads, which, if
  * we schedule it before we create kthreadd, will OOPS.
  */
  kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
  pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
  schedule();
  /* Call into cpu_idle with preempt disabled */
  preempt_disable();
  cpu_idle();
kernel_init → init/main.c
  wait for kthreadd to complete
  smp_init();
  sched_init_smp();
  do_basic_setup();
  init_post();
init_post() → init/main.c
  /* shell specified in cmd prompt or defaults */
  run_init_process("/sbin/init");

 
Howto list, load, unload modules?
What is use of mmap?
Howto allocate physical memory and virtual memory space?
Where is the assembly part of the scheduler?
what are the challenges you face when you port the kernel?
How will you debug kernel crash?
Now I give you a new CPU and board. How will you port Linux to it? What are all the steps you do to make the Linux to work on that?


Linux WiFi stack and Bluetooth stack names?

Howto debug Linux kernel in virtual memory mapping?

How uClinux is different from other flavor of Linux?


http://www.eetimes.com/electronics-news/4134390/How-uClinux-provides-MMU-less-processors-with-an-alternative

uClinux is for MCU with NO mmu.

Differences between uClinux and Linux
・little kernel and user space software is affected with NO mmu
・lack of both memory protection and of a virtual memory model
  ・One consequence of operating without memory protection is that an invalid
    pointer reference by even an unprivileged process may trigger an address
    error, and potentially corrupt or even shut down the system.
  ・three primary consequences of running Linux without virtual memory
    1) processes which are loaded by the kernel must be able to run
      independently of their position in memory. One way to achieve this is to
      "fix up" address references in a program once it is loaded into RAM. The
      other is to generate code that uses only relative addressing (referred to
      as PIC, or Position Independent Code) - uClinux supports both of these
      methods.
    2) memory allocation and deallocation occurs within a flat memory model.
       Very dynamic memory allocation can result in fragmentation which can
       starve the system. One way to improve the robustness of applications
       that perform dynamic memory allocation is to replace malloc() calls with
       requests from a preallocated buffer pool.
    3) swapping pages in and out of memory is not implemented, since it cannot
       be guaranteed that the pages would be loaded to the same location in
       RAM. In embedded systems it is also unlikely that it would be acceptable
       to suspend an application in order to use more RAM than is physically
       available.
・absence of the fork() and brk() system calls.
  ・Under Linux, fork() is implemented using copy-on-write pages. Without an
    MMU, uClinux cannot completely and reliably clone a process, nor does it
    have access to copy-on-write. uClinux implements vfork() in order to
    compensate for the lack of fork(). When a parent process calls vfork() to
    create a child, both processes share all their memory space including the
    stack. vfork() then suspends the parent's execution until the child process
    either calls exit() or execve(). Note that multitasking is not otherwise
    affected. It does, however, mean that older-style network daemons that make
    extensive use of fork() must be modified. Since child processes run in the
    same address space as their parents, the behaviour of both processes may
    require modification in particular situations.
  ・uClinux has neither an autogrow stack nor brk() and so user space programs
    must use the mmap() command to allocate memory. For convenience, our C
    library implements malloc() as a wrapper to mmap(). There is a compile-time
    option to set the stack size of a program.
・Program loaders which support position independent code (PIC) were added.
  A new binary object code format, named 'flat' was created, which supports PIC
  and which has a very compact header. Other program loaders, such as that for
  ELF, were modified to support other formats which, instead of using PIC, use
  absolute references which it is the responsibility of the kernel to 'fix up'
  at run time. Each method has advantages and disadvantages. Traditional PIC is
  quick and compact but has a size restriction on some architectures. For
  example, the 16-bit relative jump in Motorola 68k architectures limits PIC
  programs to 32K. The runtime fix-up technique removes this size restriction,
  but incurs overhead when the program is loaded by the kernel.

How a system call is processed?

Through Supervisor call, get into the Kernel space.

How does ping do not flood at user rights?
Code for Linux Semaphore, Spin lock, Interrupt Disabling, Kernel preemption disabling.
 

Monday, May 07, 2012

Howto program unsupported Flash using Computex CSIDE

First refer to the board user manual and check the bus width of the Flash interface. Select the bus width in the configuration of Flash address space and select an arbitrary Flash device.

Restart the configuration. CSIDE will show the actual Makers ID and Device ID that is read from the flash. Now, search from the following links whether the Maker and the Device are supported. If the maker is not supported, try the Matching device configurations.


I had EON EN29LV3320AB Flash device installed in my board. But, I selected Spansion MBM29LV320BE in CSIDE and successfully programmed Flash. Because both have the same Device ID 0x22F9.

Sunday, May 06, 2012

STM32F4: Exception occurs when enabling prefetch queue and branch caches

Problem:

On STM32F407IG, when I enable/set Prefetch queue (PRFTEN bit) and branch cache (DCEN and ICEN bits) in Flash access control register (FLASH_ACR) and I execute my program, exception occurs. The exception differs each time between Hard Fault, Bus Fault, and Usage Fault exceptions. If I enable only either Prefetch queue or branch cache, there is no such problem.

Or, when I execute my program through single-step using debugger, there is no exception occurs. But, when I 'Run' from reset-handler, either HardFault or BusFault or UsageFault occurs.

Solution:

Check the LATENCY bit setting. If it has been set to Three wait states (0x3), try to increase it to Four wait states (0x4) or more.

The clock speed has been increased to 168 MHz in STM32F4, in comparison with 120 MHz clock speed in STM32F2. So, the number of wait states has to be increased, if you port a program from STM32F2 to STM32F4 family MCUs.

When the cache is enabled, "Cache Fill" reads more faster from Flash memory. So, if the number of wait states is not more enough, the read data or instruction will be inconsistent. Same phenomenon occurs, when 'Run'ning a program using debugger instead of single-step execution. 'When 'Run'ning a program, memory will be read more faster. So, make sure that enough wait states has been introduced.

Leave your comments to improve this post!

Wednesday, April 25, 2012

Packet dumps: Sample packet data

IPv6:

Router Advertisement:

0000  33 33 00 00 00 01 00 d0  2b 64 a9 1b 86 dd 6e 00   33...... +d....n.
0010  00 00 00 40 3a ff fe 80  00 00 00 00 00 00 02 d0   ...@:... ........
0020  2b ff fe 64 a9 1b ff 02  00 00 00 00 00 00 00 00   +..d.... ........
0030  00 00 00 00 00 01 86 00  e1 78 40 00 07 08 00 00   ........ .x@.....
0040  00 00 00 00 00 00 01 01  00 d0 2b 64 a9 1b 05 01   ........ ..+d....
0050  00 00 00 00 05 dc 03 04  40 c0 00 00 03 84 00 00   ........ @.......
0060  03 84 00 00 00 00 20 01  0c 90 14 48 10 5c 00 00   ...... . ...H.\..
0070  00 00 00 00 00 00                                  ......          

ICMPv6 Echo Request:

0000  00 10 dc 3f 53 10 00 00  00 00 01 83 86 dd 60 00   ...?S... ......`.
0010  00 00 00 18 3a 40 fe 80  00 00 00 00 00 00 02 00   ....:@.. ........
0020  00 ff fe 00 01 83 fe 80  00 00 00 00 00 00 02 10   ........ ........
0030  dc ff fe 3f 53 10 80 00  4f c8 00 00 00 00 ff ff   ...?S... O.......
0040  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff         ........ ...... 

ICMPv6 Neighbor Solicitation:

0000  33 33 ff 64 a9 1b 00 90  99 18 27 05 86 dd 60 00   33.d.... ..'...`.
0010  00 00 00 20 3a ff fe 80  00 00 00 00 00 00 55 7c   ... :... ......U|
0020  39 cd 79 48 8d 6f ff 02  00 00 00 00 00 00 00 00   9.yH.o.. ........
0030  00 01 ff 64 a9 1b 87 00  a6 1e 00 00 00 00 fe 80   ...d.... ........
0040  00 00 00 00 00 00 02 d0  2b ff fe 64 a9 1b 01 01   ........ +..d....
0050  00 90 99 18 27 05                                  ....'.          

ICMPv6 Neighbor Advertisement:

0000  33 33 00 00 00 01 00 00  00 00 01 83 86 dd 60 00   33...... ......`.
0010  00 00 00 18 3a ff fe 80  00 00 00 00 00 00 02 00   ....:... ........
0020  00 ff fe 00 01 83 ff 02  00 00 00 00 00 00 00 00   ........ ........
0030  00 00 00 00 00 01 88 00  36 a1 40 00 00 00 fe 80   ........ 6.@.....
0040  00 00 00 00 00 00 02 00  00 ff fe 00 01 83         ........ ...... 

MLD Query: ICMPv6 Multicast Listener Query:

0000  33 33 00 00 00 01 00 10  dc 93 46 d4 86 dd 60 00   33...... ..F...`.
0010  00 00 00 20 00 01 fe 80  00 00 00 00 00 00 02 10   ... .... ........
0020  dc ff fe 93 46 d4 ff 02  00 00 00 00 00 00 00 00   ....F... ........
0030  00 00 00 00 00 01 3a 00  01 00 05 02 00 00 82 00   ......:. ........
0040  34 a0 27 10 00 00 00 00  00 00 00 00 00 00 00 00   4.'..... ........
0050  00 00 00 00 00 00                                  ......          

MLD Address Specific Multicast Listener Query:

0000  33 33 80 00 90 00 08 00  46 be 93 8e 86 dd 60 00   33...... F.....`.
0010  00 00 00 24 00 01 fe 80  00 00 00 00 00 00 00 90   ...$.... ........
0020  1a 00 01 40 1f ce ff 3e  00 00 00 00 00 00 00 00   ...@...> ........
0030  00 00 80 00 90 00 3a 00  05 02 00 00 01 00 82 00   ......:. ........
0040  1e a5 03 e8 00 00 ff 3e  00 00 00 00 00 00 00 00   .......> ........
0050  00 00 80 00 90 00 02 7d  00 00                     .......} ..     

UDP multicast packet: Destination IP ff38::300/ Source & Destination Ports 1500

0000  ff ff ff ff ff ff 08 00  46 be 93 8e 86 dd 60 00   ........ F.....`.
0010  00 00 00 20 11 ff 20 01  00 00 00 00 00 00 00 00   ... .. . ........
0020  00 00 00 00 22 22 ff 38  00 00 00 00 00 00 00 00   ...."".8 ........
0030  00 00 00 00 03 00 05 dc  05 dc 00 20 70 b5 ab cd   ........ ... p...
0040  de ad ab cd de ad ab cd  de ad ab cd de ad ab cd   ........ ........
0050  de ad ab cd de ad                                  ......          

IPv4:

IGMPv1 Membership Query:

0000  33 33 00 00 00 01 00 10  dc 93 46 d4 08 00 46 00   33...... ..F...F.
0010  00 20 08 44 00 00 01 02  7b 72 c0 a8 00 78 e0 00   . .D.... {r...x..
0020  00 01 94 04 00 00 11 00  ee ff 00 00 00 00 00 00   ........ ........


IGMPv2 General Membership Query:

0000  ff ff ff ff ff ff 08 00  46 be 93 8e 08 00 45 00   ........ F.....E.
0010  00 1c ec b7 00 00 01 02  2c 36 c0 a8 00 49 e0 00   ........ ,6...I..
0020  00 01 11 64 ee 9b 00 00  00 00 4e 4f 54 49 46 59   ...d.... ..NOTIFY
0030  20 2a 20 48 54 54 50 2f  31 2e 31 0d                * HTTP/ 1.1.   

IGMPv2 Multicast Address specific Membership Query / Join Group 224.0.0.171

0000  33 33 00 00 00 01 00 10  dc 93 46 d4 08 00 46 00   33...... ..F...F.
0010  00 20 08 44 00 00 01 02  7b 72 c0 a8 00 78 e0 00   . .D.... {r...x..
0020  00 01 94 04 00 00 11 64  0d f0 e0 00 00 ab 00 00   .......d ........

IGMPv2 Membership Report / Join Group 239.255.255.250

0000  01 00 5e 7f ff fa 00 90  99 18 27 05 08 00 46 00   ..^..... ..'...F.
0010  00 20 37 ff 00 00 01 02  3c 33 c0 a8 00 03 ef ff   . 7..... <3......
0020  ff fa 94 04 00 00 16 00  fa 04 ef ff ff fa 00 00   ........ ........
0030  00 00 00 00 00 00 00 00  00 00 00 00               ........ ....   

IGMPv3 General Membership Query:

0000  33 33 00 00 00 01 00 10  dc 93 46 d4 08 00 46 00   33...... ..F...F.
0010  00 24 08 44 00 00 01 02  7b 6e c0 a8 00 78 e0 00   .$.D.... {n...x..
0020  00 01 94 04 00 00 11 64  ec 1e 00 00 00 00 02 7d   .......d .......}
0030  00 00 00 00                                        ....            

IGMPv3  Membership Query: Specific for group 230.230.230.231

0000  33 33 00 00 00 01 00 10  dc 93 46 d4 08 00 46 00   33...... ..F...F.
0010  00 24 08 44 00 00 01 02  7b 6e c0 a8 00 78 e0 00   .$.D.... {n...x..
0020  00 01 94 04 00 00 11 32  1e 9b e6 e6 e6 e7 02 64   .......2 .......d
0030  00 00 00 00                                        ....            

IGMPv3 Membership Query: Source and Group Specific/ for group 230.230.230.230, for sources 192.168.0.5 and 192.168.184.5

0000  33 33 00 00 00 01 00 10  dc 93 46 d4 08 00 46 00   33...... ..F...F.
0010  00 2c 08 44 00 00 01 02  7b 66 c0 a8 00 78 e0 00   .,.D.... {f...x..
0020  00 01 94 04 00 00 11 32  9d 2e e6 e6 e6 e6 02 64   .......2 .......d
0030  00 02 c0 a8 00 05 c0 b8  00 05                     ........ ..     

VLAN packet:

0000  01 00 5e 00 00 01 00 10  dc 93 46 d4 81 00 98 76   ..^..... ..F....v
0010  08 00 46 00 00 24 08 44  00 00 01 02 7b 6e c0 a8   ..F..$.D ....{n..
0020  00 78 e0 00 00 01 94 04  00 00 11 64 ec 1e 00 00   .x...... ...d....
0030  00 00 02 7d 00 00 00 00                            ...}....        

DVMRP V3 Probe:

0000  01 00 5e 00 00 04 00 09  41 4d 89 b0 08 00 45 c0   ..^..... AM....E.
0010  00 20 69 40 00 00 01 02  ae 2e c0 a8 01 01 e0 00   . i@.... ........
0020  00 04 13 01 0c 8d 00 0e  ff 03 03 ab dd b4 00 00   ........ ........
0030  00 00 00 00 00 00 00 00  00 00 00 00               ........ ....   

UDP packet: Source Port 49153/ Destination Port 7121

0000  ff ff ff ff ff ff 00 0c  f4 00 2b 09 08 00 45 00   ........ ..+...E.
0010  00 5c 00 02 00 00 20 11  d9 83 c0 a8 00 64 ff ff   .\.... . .....d..
0020  ff ff c0 01 1b d1 00 48  15 3f 16 16 16 03 38 44   .......H .?....8D
0030  82 87 00 00 00 40 00 00  00 00 31 35 30 30 00 00   .....@.. ..1500..
0040  03 e9 00 cd 00 00 00 00  00 00 00 00 00 00 00 00   ........ ........
0050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ........ ........
0060  00 00 00 00 00 00 00 00  00 00                     ........ ..     

Wednesday, April 04, 2012

Difference between Bill Gates and Steve Jobs


Bill Gates invented "Drag and Drop". Steve Jobs invented "Touch and Itch"!

Tuesday, March 27, 2012

Difference between ARM and Thumb states

Thumb state is an added advantage in ARM to reduce the code size. Infact, ARM has single instruction set. Thumb is short hand 16-bit representation of a subset of those instructions. The processor fetches these 16-bit instructions and expands into 32-bit equivalent. So, ARM and Thumb differs only in how the instructions are fetched and interpreted, not in execution. So, speed is not at all changed. CPU has dedicated hardware within the chip to interpret the Thumb instructions.

ARM (Advanced RISC Machines)
Thumb ("T" in the core's full name specifies Thumb. Eg: ARM7TDMI)
Needs more memory than Thumb, since all are RISC 32-bit instructions Reduced memory consumption with 16-bit insturctions (have some 32-bit instructions too)
Totally 18 Registers: R1-R12, SP(R13), LR(R14), PC(R15), CPSR, SPSR used in exceptions Totally 12 Registers: R1-R7, SP, LR, PC, CPSR (These 12 registers have to be used to pass data between ARM and Thumb state)
T bit = 0 of CPSR represents ARM state T bit = 1 of CPSR represents Thumb state
Branch instruction (BX or BLX) to the address with LSB set to 0 enters ARM state. (Eg: BX 0x80000000) Branch instruction (BX or BLX) to the address with LSB set to 1 enters Thumb state. (Eg: BX 0x80000001)
When exception occurs, ARM state is entered. -
When return from Exception, if T bit of SPSR is set to 0, returns to ARM When return from Exception, if T bit of SPSR is set to 1, returns to Thumb
- No way (instruction) to access status or coprocessor registers
Load and store instructions of R13 register manipulates stack Has stack mnemonics PUSH, POP
- Advantages: Reduced memory, 16-bit bus can be used without compromising with speed

Disadvantages: As above said, No way (instruction) to access status or coprocessor registers. Some functions that can be accomplished in a single ARM instruction can only be simulated with a sequence of Thumb instructions.

Reference:
http://www.eetimes.com/discussion/other/4024632/Introduction-to-ARM-thumb

Saturday, March 24, 2012

Howto trace/debug an exception in Cortex-M3 and Cortex-M4

1) Take the current Link Register of the exception being serviced:

2) If BIT2 of the Link Register is set (for example, 0xfffffffd), take Process Stack Pointer (PSP).
If BIT2 of the Link Register is 0 (for example, 0xfffffff9), take Main Stack Pointer (MSP).

3) The PC stored at offset 24 (0x18) of the MSP or PSP refers to the address of the instruction that caused the exception or the instruction next to the instruction that caused the exception. If the PC is invalid, the LR stored at offset 20 (0x14) of the MSP or PSP refers to the instruction next to the instruction that caused the exception.

LR is 5 th register from MSP or PSP; PC is 6 th register from MSP or PSP, as follows:

4) Find the cause from that instruction.


Cortex-M3/M4: Hardfault at SVC instruction

If you caught Hard Fault exception and the PC value stacked for the exception points to the next instruction of SVC call, then there may be problem in Base priority(BASEPRI) value or Exception Masking Register (PRIMASK) value. The causes and corresponding solutions can be cosidered as follows:

Cause 1) : SVC priority has been masked by Base Priority Mask Register (BASEPRI) :

If SVC is executed from the context which has higher priority than SVC, Hard Fault Exception will occur. An example is, SVC is executed from a Task where BASEPRI value is set lower or equal to the SVC priority value set by System Handler Priority Register 2. Another example is, SVC is executed from a interrupt service routine of higher priority interrupt than SVC.

To solve this, always initialize the SVC priority to be higher than the executing contexts.

Cause 2) : SVC has been disabled through Exception Masking Register (PRIMASK = 1) :

When PRIMASK register is set to 1, only NMI and Hard Fault Exceptions are allowed. If SVC is executed when PRIMASK is set to 1, HardFault Exception will occur.

To solve this, instead of using PRIMASK to mask interrupts, use BASEPRI to mask particular interrupts.

Put your comments to improve this post!

Optimized AES source code for embedded systems

This AES implementation is based on rijndael-alg-fst.c (fast AES implementation) source.

Features of this AES cryptography algorithm implementation are:

1) Optimized for Embedded systems: Reduced Memory usage without compromising the Speed
2) Context-based: Uses context to support multiple sessions by saving intermediate values
3) Supports Encryption and Decryption by both CBC and ECB modes
4) Applications can use same buffer as input, as well as for output
5) Supports all 128, 192, 256 bit key sizes
6) Includes sample test application main program

AES resources can be found in the following link:
http://csrc.nist.gov/archive/aes/index.html

AES(ADVANCED ENCRYPTION STANDARD) specification can be found in the following link:
http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf

Just copy and paste aes.h and aes.c with respective file names, compile and run.

aes.h

/*
* AES Cryptographic Algorithm Header File. Include this header file in
* your source which uses these given APIs. (This source is kept under
* public domain)
*/

// AES context structure
typedef struct {
 unsigned int Ek[60];
 unsigned int Dk[60];
 unsigned int Iv[4];
 unsigned char Nr;
 unsigned char Mode;
} AesCtx;

// key length in bytes
#define KEY128 16
#define KEY192 24
#define KEY256 32
// block size in bytes
#define BLOCKSZ 16
// mode
#define EBC 0
#define CBC 1

// AES API function prototype

int AesCtxIni(AesCtx *pCtx, unsigned char *pIV, unsigned char *pKey, unsigned int KeyLen, unsigned char Mode);
int AesEncrypt(AesCtx *pCtx, unsigned char *pData, unsigned char *pCipher, unsigned int DataLen);
int AesDecrypt(AesCtx *pCtx, unsigned char *pCipher, unsigned char *pData, unsigned int CipherLen);


aes.c


#include "stdio.h"
#include "aes.h"

static const unsigned int Te0[256] = {
    0xc66363a5UL, 0xf87c7c84UL, 0xee777799UL, 0xf67b7b8dUL,
    0xfff2f20dUL, 0xd66b6bbdUL, 0xde6f6fb1UL, 0x91c5c554UL,
    0x60303050UL, 0x02010103UL, 0xce6767a9UL, 0x562b2b7dUL,
    0xe7fefe19UL, 0xb5d7d762UL, 0x4dababe6UL, 0xec76769aUL,
    0x8fcaca45UL, 0x1f82829dUL, 0x89c9c940UL, 0xfa7d7d87UL,
    0xeffafa15UL, 0xb25959ebUL, 0x8e4747c9UL, 0xfbf0f00bUL,
    0x41adadecUL, 0xb3d4d467UL, 0x5fa2a2fdUL, 0x45afafeaUL,
    0x239c9cbfUL, 0x53a4a4f7UL, 0xe4727296UL, 0x9bc0c05bUL,
    0x75b7b7c2UL, 0xe1fdfd1cUL, 0x3d9393aeUL, 0x4c26266aUL,
    0x6c36365aUL, 0x7e3f3f41UL, 0xf5f7f702UL, 0x83cccc4fUL,
    0x6834345cUL, 0x51a5a5f4UL, 0xd1e5e534UL, 0xf9f1f108UL,
    0xe2717193UL, 0xabd8d873UL, 0x62313153UL, 0x2a15153fUL,
    0x0804040cUL, 0x95c7c752UL, 0x46232365UL, 0x9dc3c35eUL,
    0x30181828UL, 0x379696a1UL, 0x0a05050fUL, 0x2f9a9ab5UL,
    0x0e070709UL, 0x24121236UL, 0x1b80809bUL, 0xdfe2e23dUL,
    0xcdebeb26UL, 0x4e272769UL, 0x7fb2b2cdUL, 0xea75759fUL,
    0x1209091bUL, 0x1d83839eUL, 0x582c2c74UL, 0x341a1a2eUL,
    0x361b1b2dUL, 0xdc6e6eb2UL, 0xb45a5aeeUL, 0x5ba0a0fbUL,
    0xa45252f6UL, 0x763b3b4dUL, 0xb7d6d661UL, 0x7db3b3ceUL,
    0x5229297bUL, 0xdde3e33eUL, 0x5e2f2f71UL, 0x13848497UL,
    0xa65353f5UL, 0xb9d1d168UL, 0x00000000UL, 0xc1eded2cUL,
    0x40202060UL, 0xe3fcfc1fUL, 0x79b1b1c8UL, 0xb65b5bedUL,
    0xd46a6abeUL, 0x8dcbcb46UL, 0x67bebed9UL, 0x7239394bUL,
    0x944a4adeUL, 0x984c4cd4UL, 0xb05858e8UL, 0x85cfcf4aUL,
    0xbbd0d06bUL, 0xc5efef2aUL, 0x4faaaae5UL, 0xedfbfb16UL,
    0x864343c5UL, 0x9a4d4dd7UL, 0x66333355UL, 0x11858594UL,
    0x8a4545cfUL, 0xe9f9f910UL, 0x04020206UL, 0xfe7f7f81UL,
    0xa05050f0UL, 0x783c3c44UL, 0x259f9fbaUL, 0x4ba8a8e3UL,
    0xa25151f3UL, 0x5da3a3feUL, 0x804040c0UL, 0x058f8f8aUL,
    0x3f9292adUL, 0x219d9dbcUL, 0x70383848UL, 0xf1f5f504UL,
    0x63bcbcdfUL, 0x77b6b6c1UL, 0xafdada75UL, 0x42212163UL,
    0x20101030UL, 0xe5ffff1aUL, 0xfdf3f30eUL, 0xbfd2d26dUL,
    0x81cdcd4cUL, 0x180c0c14UL, 0x26131335UL, 0xc3ecec2fUL,
    0xbe5f5fe1UL, 0x359797a2UL, 0x884444ccUL, 0x2e171739UL,
    0x93c4c457UL, 0x55a7a7f2UL, 0xfc7e7e82UL, 0x7a3d3d47UL,
    0xc86464acUL, 0xba5d5de7UL, 0x3219192bUL, 0xe6737395UL,
    0xc06060a0UL, 0x19818198UL, 0x9e4f4fd1UL, 0xa3dcdc7fUL,
    0x44222266UL, 0x542a2a7eUL, 0x3b9090abUL, 0x0b888883UL,
    0x8c4646caUL, 0xc7eeee29UL, 0x6bb8b8d3UL, 0x2814143cUL,
    0xa7dede79UL, 0xbc5e5ee2UL, 0x160b0b1dUL, 0xaddbdb76UL,
    0xdbe0e03bUL, 0x64323256UL, 0x743a3a4eUL, 0x140a0a1eUL,
    0x924949dbUL, 0x0c06060aUL, 0x4824246cUL, 0xb85c5ce4UL,
    0x9fc2c25dUL, 0xbdd3d36eUL, 0x43acacefUL, 0xc46262a6UL,
    0x399191a8UL, 0x319595a4UL, 0xd3e4e437UL, 0xf279798bUL,
    0xd5e7e732UL, 0x8bc8c843UL, 0x6e373759UL, 0xda6d6db7UL,
    0x018d8d8cUL, 0xb1d5d564UL, 0x9c4e4ed2UL, 0x49a9a9e0UL,
    0xd86c6cb4UL, 0xac5656faUL, 0xf3f4f407UL, 0xcfeaea25UL,
    0xca6565afUL, 0xf47a7a8eUL, 0x47aeaee9UL, 0x10080818UL,
    0x6fbabad5UL, 0xf0787888UL, 0x4a25256fUL, 0x5c2e2e72UL,
    0x381c1c24UL, 0x57a6a6f1UL, 0x73b4b4c7UL, 0x97c6c651UL,
    0xcbe8e823UL, 0xa1dddd7cUL, 0xe874749cUL, 0x3e1f1f21UL,
    0x964b4bddUL, 0x61bdbddcUL, 0x0d8b8b86UL, 0x0f8a8a85UL,
    0xe0707090UL, 0x7c3e3e42UL, 0x71b5b5c4UL, 0xcc6666aaUL,
    0x904848d8UL, 0x06030305UL, 0xf7f6f601UL, 0x1c0e0e12UL,
    0xc26161a3UL, 0x6a35355fUL, 0xae5757f9UL, 0x69b9b9d0UL,
    0x17868691UL, 0x99c1c158UL, 0x3a1d1d27UL, 0x279e9eb9UL,
    0xd9e1e138UL, 0xebf8f813UL, 0x2b9898b3UL, 0x22111133UL,
    0xd26969bbUL, 0xa9d9d970UL, 0x078e8e89UL, 0x339494a7UL,
    0x2d9b9bb6UL, 0x3c1e1e22UL, 0x15878792UL, 0xc9e9e920UL,
    0x87cece49UL, 0xaa5555ffUL, 0x50282878UL, 0xa5dfdf7aUL,
    0x038c8c8fUL, 0x59a1a1f8UL, 0x09898980UL, 0x1a0d0d17UL,
    0x65bfbfdaUL, 0xd7e6e631UL, 0x844242c6UL, 0xd06868b8UL,
    0x824141c3UL, 0x299999b0UL, 0x5a2d2d77UL, 0x1e0f0f11UL,
    0x7bb0b0cbUL, 0xa85454fcUL, 0x6dbbbbd6UL, 0x2c16163aUL,
};
static const unsigned int Te1[256] = {
    0xa5c66363UL, 0x84f87c7cUL, 0x99ee7777UL, 0x8df67b7bUL,
    0x0dfff2f2UL, 0xbdd66b6bUL, 0xb1de6f6fUL, 0x5491c5c5UL,
    0x50603030UL, 0x03020101UL, 0xa9ce6767UL, 0x7d562b2bUL,
    0x19e7fefeUL, 0x62b5d7d7UL, 0xe64dababUL, 0x9aec7676UL,
    0x458fcacaUL, 0x9d1f8282UL, 0x4089c9c9UL, 0x87fa7d7dUL,
    0x15effafaUL, 0xebb25959UL, 0xc98e4747UL, 0x0bfbf0f0UL,
    0xec41adadUL, 0x67b3d4d4UL, 0xfd5fa2a2UL, 0xea45afafUL,
    0xbf239c9cUL, 0xf753a4a4UL, 0x96e47272UL, 0x5b9bc0c0UL,
    0xc275b7b7UL, 0x1ce1fdfdUL, 0xae3d9393UL, 0x6a4c2626UL,
    0x5a6c3636UL, 0x417e3f3fUL, 0x02f5f7f7UL, 0x4f83ccccUL,
    0x5c683434UL, 0xf451a5a5UL, 0x34d1e5e5UL, 0x08f9f1f1UL,
    0x93e27171UL, 0x73abd8d8UL, 0x53623131UL, 0x3f2a1515UL,
    0x0c080404UL, 0x5295c7c7UL, 0x65462323UL, 0x5e9dc3c3UL,
    0x28301818UL, 0xa1379696UL, 0x0f0a0505UL, 0xb52f9a9aUL,
    0x090e0707UL, 0x36241212UL, 0x9b1b8080UL, 0x3ddfe2e2UL,
    0x26cdebebUL, 0x694e2727UL, 0xcd7fb2b2UL, 0x9fea7575UL,
    0x1b120909UL, 0x9e1d8383UL, 0x74582c2cUL, 0x2e341a1aUL,
    0x2d361b1bUL, 0xb2dc6e6eUL, 0xeeb45a5aUL, 0xfb5ba0a0UL,
    0xf6a45252UL, 0x4d763b3bUL, 0x61b7d6d6UL, 0xce7db3b3UL,
    0x7b522929UL, 0x3edde3e3UL, 0x715e2f2fUL, 0x97138484UL,
    0xf5a65353UL, 0x68b9d1d1UL, 0x00000000UL, 0x2cc1ededUL,
    0x60402020UL, 0x1fe3fcfcUL, 0xc879b1b1UL, 0xedb65b5bUL,
    0xbed46a6aUL, 0x468dcbcbUL, 0xd967bebeUL, 0x4b723939UL,
    0xde944a4aUL, 0xd4984c4cUL, 0xe8b05858UL, 0x4a85cfcfUL,
    0x6bbbd0d0UL, 0x2ac5efefUL, 0xe54faaaaUL, 0x16edfbfbUL,
    0xc5864343UL, 0xd79a4d4dUL, 0x55663333UL, 0x94118585UL,
    0xcf8a4545UL, 0x10e9f9f9UL, 0x06040202UL, 0x81fe7f7fUL,
    0xf0a05050UL, 0x44783c3cUL, 0xba259f9fUL, 0xe34ba8a8UL,
    0xf3a25151UL, 0xfe5da3a3UL, 0xc0804040UL, 0x8a058f8fUL,
    0xad3f9292UL, 0xbc219d9dUL, 0x48703838UL, 0x04f1f5f5UL,
    0xdf63bcbcUL, 0xc177b6b6UL, 0x75afdadaUL, 0x63422121UL,
    0x30201010UL, 0x1ae5ffffUL, 0x0efdf3f3UL, 0x6dbfd2d2UL,
    0x4c81cdcdUL, 0x14180c0cUL, 0x35261313UL, 0x2fc3ececUL,
    0xe1be5f5fUL, 0xa2359797UL, 0xcc884444UL, 0x392e1717UL,
    0x5793c4c4UL, 0xf255a7a7UL, 0x82fc7e7eUL, 0x477a3d3dUL,
    0xacc86464UL, 0xe7ba5d5dUL, 0x2b321919UL, 0x95e67373UL,
    0xa0c06060UL, 0x98198181UL, 0xd19e4f4fUL, 0x7fa3dcdcUL,
    0x66442222UL, 0x7e542a2aUL, 0xab3b9090UL, 0x830b8888UL,
    0xca8c4646UL, 0x29c7eeeeUL, 0xd36bb8b8UL, 0x3c281414UL,
    0x79a7dedeUL, 0xe2bc5e5eUL, 0x1d160b0bUL, 0x76addbdbUL,
    0x3bdbe0e0UL, 0x56643232UL, 0x4e743a3aUL, 0x1e140a0aUL,
    0xdb924949UL, 0x0a0c0606UL, 0x6c482424UL, 0xe4b85c5cUL,
    0x5d9fc2c2UL, 0x6ebdd3d3UL, 0xef43acacUL, 0xa6c46262UL,
    0xa8399191UL, 0xa4319595UL, 0x37d3e4e4UL, 0x8bf27979UL,
    0x32d5e7e7UL, 0x438bc8c8UL, 0x596e3737UL, 0xb7da6d6dUL,
    0x8c018d8dUL, 0x64b1d5d5UL, 0xd29c4e4eUL, 0xe049a9a9UL,
    0xb4d86c6cUL, 0xfaac5656UL, 0x07f3f4f4UL, 0x25cfeaeaUL,
    0xafca6565UL, 0x8ef47a7aUL, 0xe947aeaeUL, 0x18100808UL,
    0xd56fbabaUL, 0x88f07878UL, 0x6f4a2525UL, 0x725c2e2eUL,
    0x24381c1cUL, 0xf157a6a6UL, 0xc773b4b4UL, 0x5197c6c6UL,
    0x23cbe8e8UL, 0x7ca1ddddUL, 0x9ce87474UL, 0x213e1f1fUL,
    0xdd964b4bUL, 0xdc61bdbdUL, 0x860d8b8bUL, 0x850f8a8aUL,
    0x90e07070UL, 0x427c3e3eUL, 0xc471b5b5UL, 0xaacc6666UL,
    0xd8904848UL, 0x05060303UL, 0x01f7f6f6UL, 0x121c0e0eUL,
    0xa3c26161UL, 0x5f6a3535UL, 0xf9ae5757UL, 0xd069b9b9UL,
    0x91178686UL, 0x5899c1c1UL, 0x273a1d1dUL, 0xb9279e9eUL,
    0x38d9e1e1UL, 0x13ebf8f8UL, 0xb32b9898UL, 0x33221111UL,
    0xbbd26969UL, 0x70a9d9d9UL, 0x89078e8eUL, 0xa7339494UL,
    0xb62d9b9bUL, 0x223c1e1eUL, 0x92158787UL, 0x20c9e9e9UL,
    0x4987ceceUL, 0xffaa5555UL, 0x78502828UL, 0x7aa5dfdfUL,
    0x8f038c8cUL, 0xf859a1a1UL, 0x80098989UL, 0x171a0d0dUL,
    0xda65bfbfUL, 0x31d7e6e6UL, 0xc6844242UL, 0xb8d06868UL,
    0xc3824141UL, 0xb0299999UL, 0x775a2d2dUL, 0x111e0f0fUL,
    0xcb7bb0b0UL, 0xfca85454UL, 0xd66dbbbbUL, 0x3a2c1616UL,
};
static const unsigned int Te2[256] = {
    0x63a5c663UL, 0x7c84f87cUL, 0x7799ee77UL, 0x7b8df67bUL,
    0xf20dfff2UL, 0x6bbdd66bUL, 0x6fb1de6fUL, 0xc55491c5UL,
    0x30506030UL, 0x01030201UL, 0x67a9ce67UL, 0x2b7d562bUL,
    0xfe19e7feUL, 0xd762b5d7UL, 0xabe64dabUL, 0x769aec76UL,
    0xca458fcaUL, 0x829d1f82UL, 0xc94089c9UL, 0x7d87fa7dUL,
    0xfa15effaUL, 0x59ebb259UL, 0x47c98e47UL, 0xf00bfbf0UL,
    0xadec41adUL, 0xd467b3d4UL, 0xa2fd5fa2UL, 0xafea45afUL,
    0x9cbf239cUL, 0xa4f753a4UL, 0x7296e472UL, 0xc05b9bc0UL,
    0xb7c275b7UL, 0xfd1ce1fdUL, 0x93ae3d93UL, 0x266a4c26UL,
    0x365a6c36UL, 0x3f417e3fUL, 0xf702f5f7UL, 0xcc4f83ccUL,
    0x345c6834UL, 0xa5f451a5UL, 0xe534d1e5UL, 0xf108f9f1UL,
    0x7193e271UL, 0xd873abd8UL, 0x31536231UL, 0x153f2a15UL,
    0x040c0804UL, 0xc75295c7UL, 0x23654623UL, 0xc35e9dc3UL,
    0x18283018UL, 0x96a13796UL, 0x050f0a05UL, 0x9ab52f9aUL,
    0x07090e07UL, 0x12362412UL, 0x809b1b80UL, 0xe23ddfe2UL,
    0xeb26cdebUL, 0x27694e27UL, 0xb2cd7fb2UL, 0x759fea75UL,
    0x091b1209UL, 0x839e1d83UL, 0x2c74582cUL, 0x1a2e341aUL,
    0x1b2d361bUL, 0x6eb2dc6eUL, 0x5aeeb45aUL, 0xa0fb5ba0UL,
    0x52f6a452UL, 0x3b4d763bUL, 0xd661b7d6UL, 0xb3ce7db3UL,
    0x297b5229UL, 0xe33edde3UL, 0x2f715e2fUL, 0x84971384UL,
    0x53f5a653UL, 0xd168b9d1UL, 0x00000000UL, 0xed2cc1edUL,
    0x20604020UL, 0xfc1fe3fcUL, 0xb1c879b1UL, 0x5bedb65bUL,
    0x6abed46aUL, 0xcb468dcbUL, 0xbed967beUL, 0x394b7239UL,
    0x4ade944aUL, 0x4cd4984cUL, 0x58e8b058UL, 0xcf4a85cfUL,
    0xd06bbbd0UL, 0xef2ac5efUL, 0xaae54faaUL, 0xfb16edfbUL,
    0x43c58643UL, 0x4dd79a4dUL, 0x33556633UL, 0x85941185UL,
    0x45cf8a45UL, 0xf910e9f9UL, 0x02060402UL, 0x7f81fe7fUL,
    0x50f0a050UL, 0x3c44783cUL, 0x9fba259fUL, 0xa8e34ba8UL,
    0x51f3a251UL, 0xa3fe5da3UL, 0x40c08040UL, 0x8f8a058fUL,
    0x92ad3f92UL, 0x9dbc219dUL, 0x38487038UL, 0xf504f1f5UL,
    0xbcdf63bcUL, 0xb6c177b6UL, 0xda75afdaUL, 0x21634221UL,
    0x10302010UL, 0xff1ae5ffUL, 0xf30efdf3UL, 0xd26dbfd2UL,
    0xcd4c81cdUL, 0x0c14180cUL, 0x13352613UL, 0xec2fc3ecUL,
    0x5fe1be5fUL, 0x97a23597UL, 0x44cc8844UL, 0x17392e17UL,
    0xc45793c4UL, 0xa7f255a7UL, 0x7e82fc7eUL, 0x3d477a3dUL,
    0x64acc864UL, 0x5de7ba5dUL, 0x192b3219UL, 0x7395e673UL,
    0x60a0c060UL, 0x81981981UL, 0x4fd19e4fUL, 0xdc7fa3dcUL,
    0x22664422UL, 0x2a7e542aUL, 0x90ab3b90UL, 0x88830b88UL,
    0x46ca8c46UL, 0xee29c7eeUL, 0xb8d36bb8UL, 0x143c2814UL,
    0xde79a7deUL, 0x5ee2bc5eUL, 0x0b1d160bUL, 0xdb76addbUL,
    0xe03bdbe0UL, 0x32566432UL, 0x3a4e743aUL, 0x0a1e140aUL,
    0x49db9249UL, 0x060a0c06UL, 0x246c4824UL, 0x5ce4b85cUL,
    0xc25d9fc2UL, 0xd36ebdd3UL, 0xacef43acUL, 0x62a6c462UL,
    0x91a83991UL, 0x95a43195UL, 0xe437d3e4UL, 0x798bf279UL,
    0xe732d5e7UL, 0xc8438bc8UL, 0x37596e37UL, 0x6db7da6dUL,
    0x8d8c018dUL, 0xd564b1d5UL, 0x4ed29c4eUL, 0xa9e049a9UL,
    0x6cb4d86cUL, 0x56faac56UL, 0xf407f3f4UL, 0xea25cfeaUL,
    0x65afca65UL, 0x7a8ef47aUL, 0xaee947aeUL, 0x08181008UL,
    0xbad56fbaUL, 0x7888f078UL, 0x256f4a25UL, 0x2e725c2eUL,
    0x1c24381cUL, 0xa6f157a6UL, 0xb4c773b4UL, 0xc65197c6UL,
    0xe823cbe8UL, 0xdd7ca1ddUL, 0x749ce874UL, 0x1f213e1fUL,
    0x4bdd964bUL, 0xbddc61bdUL, 0x8b860d8bUL, 0x8a850f8aUL,
    0x7090e070UL, 0x3e427c3eUL, 0xb5c471b5UL, 0x66aacc66UL,
    0x48d89048UL, 0x03050603UL, 0xf601f7f6UL, 0x0e121c0eUL,
    0x61a3c261UL, 0x355f6a35UL, 0x57f9ae57UL, 0xb9d069b9UL,
    0x86911786UL, 0xc15899c1UL, 0x1d273a1dUL, 0x9eb9279eUL,
    0xe138d9e1UL, 0xf813ebf8UL, 0x98b32b98UL, 0x11332211UL,
    0x69bbd269UL, 0xd970a9d9UL, 0x8e89078eUL, 0x94a73394UL,
    0x9bb62d9bUL, 0x1e223c1eUL, 0x87921587UL, 0xe920c9e9UL,
    0xce4987ceUL, 0x55ffaa55UL, 0x28785028UL, 0xdf7aa5dfUL,
    0x8c8f038cUL, 0xa1f859a1UL, 0x89800989UL, 0x0d171a0dUL,
    0xbfda65bfUL, 0xe631d7e6UL, 0x42c68442UL, 0x68b8d068UL,
    0x41c38241UL, 0x99b02999UL, 0x2d775a2dUL, 0x0f111e0fUL,
    0xb0cb7bb0UL, 0x54fca854UL, 0xbbd66dbbUL, 0x163a2c16UL,
};
static const unsigned int Te3[256] = {
    0x6363a5c6UL, 0x7c7c84f8UL, 0x777799eeUL, 0x7b7b8df6UL,
    0xf2f20dffUL, 0x6b6bbdd6UL, 0x6f6fb1deUL, 0xc5c55491UL,
    0x30305060UL, 0x01010302UL, 0x6767a9ceUL, 0x2b2b7d56UL,
    0xfefe19e7UL, 0xd7d762b5UL, 0xababe64dUL, 0x76769aecUL,
    0xcaca458fUL, 0x82829d1fUL, 0xc9c94089UL, 0x7d7d87faUL,
    0xfafa15efUL, 0x5959ebb2UL, 0x4747c98eUL, 0xf0f00bfbUL,
    0xadadec41UL, 0xd4d467b3UL, 0xa2a2fd5fUL, 0xafafea45UL,
    0x9c9cbf23UL, 0xa4a4f753UL, 0x727296e4UL, 0xc0c05b9bUL,
    0xb7b7c275UL, 0xfdfd1ce1UL, 0x9393ae3dUL, 0x26266a4cUL,
    0x36365a6cUL, 0x3f3f417eUL, 0xf7f702f5UL, 0xcccc4f83UL,
    0x34345c68UL, 0xa5a5f451UL, 0xe5e534d1UL, 0xf1f108f9UL,
    0x717193e2UL, 0xd8d873abUL, 0x31315362UL, 0x15153f2aUL,
    0x04040c08UL, 0xc7c75295UL, 0x23236546UL, 0xc3c35e9dUL,
    0x18182830UL, 0x9696a137UL, 0x05050f0aUL, 0x9a9ab52fUL,
    0x0707090eUL, 0x12123624UL, 0x80809b1bUL, 0xe2e23ddfUL,
    0xebeb26cdUL, 0x2727694eUL, 0xb2b2cd7fUL, 0x75759feaUL,
    0x09091b12UL, 0x83839e1dUL, 0x2c2c7458UL, 0x1a1a2e34UL,
    0x1b1b2d36UL, 0x6e6eb2dcUL, 0x5a5aeeb4UL, 0xa0a0fb5bUL,
    0x5252f6a4UL, 0x3b3b4d76UL, 0xd6d661b7UL, 0xb3b3ce7dUL,
    0x29297b52UL, 0xe3e33eddUL, 0x2f2f715eUL, 0x84849713UL,
    0x5353f5a6UL, 0xd1d168b9UL, 0x00000000UL, 0xeded2cc1UL,
    0x20206040UL, 0xfcfc1fe3UL, 0xb1b1c879UL, 0x5b5bedb6UL,
    0x6a6abed4UL, 0xcbcb468dUL, 0xbebed967UL, 0x39394b72UL,
    0x4a4ade94UL, 0x4c4cd498UL, 0x5858e8b0UL, 0xcfcf4a85UL,
    0xd0d06bbbUL, 0xefef2ac5UL, 0xaaaae54fUL, 0xfbfb16edUL,
    0x4343c586UL, 0x4d4dd79aUL, 0x33335566UL, 0x85859411UL,
    0x4545cf8aUL, 0xf9f910e9UL, 0x02020604UL, 0x7f7f81feUL,
    0x5050f0a0UL, 0x3c3c4478UL, 0x9f9fba25UL, 0xa8a8e34bUL,
    0x5151f3a2UL, 0xa3a3fe5dUL, 0x4040c080UL, 0x8f8f8a05UL,
    0x9292ad3fUL, 0x9d9dbc21UL, 0x38384870UL, 0xf5f504f1UL,
    0xbcbcdf63UL, 0xb6b6c177UL, 0xdada75afUL, 0x21216342UL,
    0x10103020UL, 0xffff1ae5UL, 0xf3f30efdUL, 0xd2d26dbfUL,
    0xcdcd4c81UL, 0x0c0c1418UL, 0x13133526UL, 0xecec2fc3UL,
    0x5f5fe1beUL, 0x9797a235UL, 0x4444cc88UL, 0x1717392eUL,
    0xc4c45793UL, 0xa7a7f255UL, 0x7e7e82fcUL, 0x3d3d477aUL,
    0x6464acc8UL, 0x5d5de7baUL, 0x19192b32UL, 0x737395e6UL,
    0x6060a0c0UL, 0x81819819UL, 0x4f4fd19eUL, 0xdcdc7fa3UL,
    0x22226644UL, 0x2a2a7e54UL, 0x9090ab3bUL, 0x8888830bUL,
    0x4646ca8cUL, 0xeeee29c7UL, 0xb8b8d36bUL, 0x14143c28UL,
    0xdede79a7UL, 0x5e5ee2bcUL, 0x0b0b1d16UL, 0xdbdb76adUL,
    0xe0e03bdbUL, 0x32325664UL, 0x3a3a4e74UL, 0x0a0a1e14UL,
    0x4949db92UL, 0x06060a0cUL, 0x24246c48UL, 0x5c5ce4b8UL,
    0xc2c25d9fUL, 0xd3d36ebdUL, 0xacacef43UL, 0x6262a6c4UL,
    0x9191a839UL, 0x9595a431UL, 0xe4e437d3UL, 0x79798bf2UL,
    0xe7e732d5UL, 0xc8c8438bUL, 0x3737596eUL, 0x6d6db7daUL,
    0x8d8d8c01UL, 0xd5d564b1UL, 0x4e4ed29cUL, 0xa9a9e049UL,
    0x6c6cb4d8UL, 0x5656faacUL, 0xf4f407f3UL, 0xeaea25cfUL,
    0x6565afcaUL, 0x7a7a8ef4UL, 0xaeaee947UL, 0x08081810UL,
    0xbabad56fUL, 0x787888f0UL, 0x25256f4aUL, 0x2e2e725cUL,
    0x1c1c2438UL, 0xa6a6f157UL, 0xb4b4c773UL, 0xc6c65197UL,
    0xe8e823cbUL, 0xdddd7ca1UL, 0x74749ce8UL, 0x1f1f213eUL,
    0x4b4bdd96UL, 0xbdbddc61UL, 0x8b8b860dUL, 0x8a8a850fUL,
    0x707090e0UL, 0x3e3e427cUL, 0xb5b5c471UL, 0x6666aaccUL,
    0x4848d890UL, 0x03030506UL, 0xf6f601f7UL, 0x0e0e121cUL,
    0x6161a3c2UL, 0x35355f6aUL, 0x5757f9aeUL, 0xb9b9d069UL,
    0x86869117UL, 0xc1c15899UL, 0x1d1d273aUL, 0x9e9eb927UL,
    0xe1e138d9UL, 0xf8f813ebUL, 0x9898b32bUL, 0x11113322UL,
    0x6969bbd2UL, 0xd9d970a9UL, 0x8e8e8907UL, 0x9494a733UL,
    0x9b9bb62dUL, 0x1e1e223cUL, 0x87879215UL, 0xe9e920c9UL,
    0xcece4987UL, 0x5555ffaaUL, 0x28287850UL, 0xdfdf7aa5UL,
    0x8c8c8f03UL, 0xa1a1f859UL, 0x89898009UL, 0x0d0d171aUL,
    0xbfbfda65UL, 0xe6e631d7UL, 0x4242c684UL, 0x6868b8d0UL,
    0x4141c382UL, 0x9999b029UL, 0x2d2d775aUL, 0x0f0f111eUL,
    0xb0b0cb7bUL, 0x5454fca8UL, 0xbbbbd66dUL, 0x16163a2cUL,
};
static const unsigned int Te4[256] = {
    0x63636363UL, 0x7c7c7c7cUL, 0x77777777UL, 0x7b7b7b7bUL,
    0xf2f2f2f2UL, 0x6b6b6b6bUL, 0x6f6f6f6fUL, 0xc5c5c5c5UL,
    0x30303030UL, 0x01010101UL, 0x67676767UL, 0x2b2b2b2bUL,
    0xfefefefeUL, 0xd7d7d7d7UL, 0xababababUL, 0x76767676UL,
    0xcacacacaUL, 0x82828282UL, 0xc9c9c9c9UL, 0x7d7d7d7dUL,
    0xfafafafaUL, 0x59595959UL, 0x47474747UL, 0xf0f0f0f0UL,
    0xadadadadUL, 0xd4d4d4d4UL, 0xa2a2a2a2UL, 0xafafafafUL,
    0x9c9c9c9cUL, 0xa4a4a4a4UL, 0x72727272UL, 0xc0c0c0c0UL,
    0xb7b7b7b7UL, 0xfdfdfdfdUL, 0x93939393UL, 0x26262626UL,
    0x36363636UL, 0x3f3f3f3fUL, 0xf7f7f7f7UL, 0xccccccccUL,
    0x34343434UL, 0xa5a5a5a5UL, 0xe5e5e5e5UL, 0xf1f1f1f1UL,
    0x71717171UL, 0xd8d8d8d8UL, 0x31313131UL, 0x15151515UL,
    0x04040404UL, 0xc7c7c7c7UL, 0x23232323UL, 0xc3c3c3c3UL,
    0x18181818UL, 0x96969696UL, 0x05050505UL, 0x9a9a9a9aUL,
    0x07070707UL, 0x12121212UL, 0x80808080UL, 0xe2e2e2e2UL,
    0xebebebebUL, 0x27272727UL, 0xb2b2b2b2UL, 0x75757575UL,
    0x09090909UL, 0x83838383UL, 0x2c2c2c2cUL, 0x1a1a1a1aUL,
    0x1b1b1b1bUL, 0x6e6e6e6eUL, 0x5a5a5a5aUL, 0xa0a0a0a0UL,
    0x52525252UL, 0x3b3b3b3bUL, 0xd6d6d6d6UL, 0xb3b3b3b3UL,
    0x29292929UL, 0xe3e3e3e3UL, 0x2f2f2f2fUL, 0x84848484UL,
    0x53535353UL, 0xd1d1d1d1UL, 0x00000000UL, 0xededededUL,
    0x20202020UL, 0xfcfcfcfcUL, 0xb1b1b1b1UL, 0x5b5b5b5bUL,
    0x6a6a6a6aUL, 0xcbcbcbcbUL, 0xbebebebeUL, 0x39393939UL,
    0x4a4a4a4aUL, 0x4c4c4c4cUL, 0x58585858UL, 0xcfcfcfcfUL,
    0xd0d0d0d0UL, 0xefefefefUL, 0xaaaaaaaaUL, 0xfbfbfbfbUL,
    0x43434343UL, 0x4d4d4d4dUL, 0x33333333UL, 0x85858585UL,
    0x45454545UL, 0xf9f9f9f9UL, 0x02020202UL, 0x7f7f7f7fUL,
    0x50505050UL, 0x3c3c3c3cUL, 0x9f9f9f9fUL, 0xa8a8a8a8UL,
    0x51515151UL, 0xa3a3a3a3UL, 0x40404040UL, 0x8f8f8f8fUL,
    0x92929292UL, 0x9d9d9d9dUL, 0x38383838UL, 0xf5f5f5f5UL,
    0xbcbcbcbcUL, 0xb6b6b6b6UL, 0xdadadadaUL, 0x21212121UL,
    0x10101010UL, 0xffffffffUL, 0xf3f3f3f3UL, 0xd2d2d2d2UL,
    0xcdcdcdcdUL, 0x0c0c0c0cUL, 0x13131313UL, 0xececececUL,
    0x5f5f5f5fUL, 0x97979797UL, 0x44444444UL, 0x17171717UL,
    0xc4c4c4c4UL, 0xa7a7a7a7UL, 0x7e7e7e7eUL, 0x3d3d3d3dUL,
    0x64646464UL, 0x5d5d5d5dUL, 0x19191919UL, 0x73737373UL,
    0x60606060UL, 0x81818181UL, 0x4f4f4f4fUL, 0xdcdcdcdcUL,
    0x22222222UL, 0x2a2a2a2aUL, 0x90909090UL, 0x88888888UL,
    0x46464646UL, 0xeeeeeeeeUL, 0xb8b8b8b8UL, 0x14141414UL,
    0xdedededeUL, 0x5e5e5e5eUL, 0x0b0b0b0bUL, 0xdbdbdbdbUL,
    0xe0e0e0e0UL, 0x32323232UL, 0x3a3a3a3aUL, 0x0a0a0a0aUL,
    0x49494949UL, 0x06060606UL, 0x24242424UL, 0x5c5c5c5cUL,
    0xc2c2c2c2UL, 0xd3d3d3d3UL, 0xacacacacUL, 0x62626262UL,
    0x91919191UL, 0x95959595UL, 0xe4e4e4e4UL, 0x79797979UL,
    0xe7e7e7e7UL, 0xc8c8c8c8UL, 0x37373737UL, 0x6d6d6d6dUL,
    0x8d8d8d8dUL, 0xd5d5d5d5UL, 0x4e4e4e4eUL, 0xa9a9a9a9UL,
    0x6c6c6c6cUL, 0x56565656UL, 0xf4f4f4f4UL, 0xeaeaeaeaUL,
    0x65656565UL, 0x7a7a7a7aUL, 0xaeaeaeaeUL, 0x08080808UL,
    0xbabababaUL, 0x78787878UL, 0x25252525UL, 0x2e2e2e2eUL,
    0x1c1c1c1cUL, 0xa6a6a6a6UL, 0xb4b4b4b4UL, 0xc6c6c6c6UL,
    0xe8e8e8e8UL, 0xddddddddUL, 0x74747474UL, 0x1f1f1f1fUL,
    0x4b4b4b4bUL, 0xbdbdbdbdUL, 0x8b8b8b8bUL, 0x8a8a8a8aUL,
    0x70707070UL, 0x3e3e3e3eUL, 0xb5b5b5b5UL, 0x66666666UL,
    0x48484848UL, 0x03030303UL, 0xf6f6f6f6UL, 0x0e0e0e0eUL,
    0x61616161UL, 0x35353535UL, 0x57575757UL, 0xb9b9b9b9UL,
    0x86868686UL, 0xc1c1c1c1UL, 0x1d1d1d1dUL, 0x9e9e9e9eUL,
    0xe1e1e1e1UL, 0xf8f8f8f8UL, 0x98989898UL, 0x11111111UL,
    0x69696969UL, 0xd9d9d9d9UL, 0x8e8e8e8eUL, 0x94949494UL,
    0x9b9b9b9bUL, 0x1e1e1e1eUL, 0x87878787UL, 0xe9e9e9e9UL,
    0xcecececeUL, 0x55555555UL, 0x28282828UL, 0xdfdfdfdfUL,
    0x8c8c8c8cUL, 0xa1a1a1a1UL, 0x89898989UL, 0x0d0d0d0dUL,
    0xbfbfbfbfUL, 0xe6e6e6e6UL, 0x42424242UL, 0x68686868UL,
    0x41414141UL, 0x99999999UL, 0x2d2d2d2dUL, 0x0f0f0f0fUL,
    0xb0b0b0b0UL, 0x54545454UL, 0xbbbbbbbbUL, 0x16161616UL,
};
static const unsigned int Td0[256] = {
    0x51f4a750UL, 0x7e416553UL, 0x1a17a4c3UL, 0x3a275e96UL,
    0x3bab6bcbUL, 0x1f9d45f1UL, 0xacfa58abUL, 0x4be30393UL,
    0x2030fa55UL, 0xad766df6UL, 0x88cc7691UL, 0xf5024c25UL,
    0x4fe5d7fcUL, 0xc52acbd7UL, 0x26354480UL, 0xb562a38fUL,
    0xdeb15a49UL, 0x25ba1b67UL, 0x45ea0e98UL, 0x5dfec0e1UL,
    0xc32f7502UL, 0x814cf012UL, 0x8d4697a3UL, 0x6bd3f9c6UL,
    0x038f5fe7UL, 0x15929c95UL, 0xbf6d7aebUL, 0x955259daUL,
    0xd4be832dUL, 0x587421d3UL, 0x49e06929UL, 0x8ec9c844UL,
    0x75c2896aUL, 0xf48e7978UL, 0x99583e6bUL, 0x27b971ddUL,
    0xbee14fb6UL, 0xf088ad17UL, 0xc920ac66UL, 0x7dce3ab4UL,
    0x63df4a18UL, 0xe51a3182UL, 0x97513360UL, 0x62537f45UL,
    0xb16477e0UL, 0xbb6bae84UL, 0xfe81a01cUL, 0xf9082b94UL,
    0x70486858UL, 0x8f45fd19UL, 0x94de6c87UL, 0x527bf8b7UL,
    0xab73d323UL, 0x724b02e2UL, 0xe31f8f57UL, 0x6655ab2aUL,
    0xb2eb2807UL, 0x2fb5c203UL, 0x86c57b9aUL, 0xd33708a5UL,
    0x302887f2UL, 0x23bfa5b2UL, 0x02036abaUL, 0xed16825cUL,
    0x8acf1c2bUL, 0xa779b492UL, 0xf307f2f0UL, 0x4e69e2a1UL,
    0x65daf4cdUL, 0x0605bed5UL, 0xd134621fUL, 0xc4a6fe8aUL,
    0x342e539dUL, 0xa2f355a0UL, 0x058ae132UL, 0xa4f6eb75UL,
    0x0b83ec39UL, 0x4060efaaUL, 0x5e719f06UL, 0xbd6e1051UL,
    0x3e218af9UL, 0x96dd063dUL, 0xdd3e05aeUL, 0x4de6bd46UL,
    0x91548db5UL, 0x71c45d05UL, 0x0406d46fUL, 0x605015ffUL,
    0x1998fb24UL, 0xd6bde997UL, 0x894043ccUL, 0x67d99e77UL,
    0xb0e842bdUL, 0x07898b88UL, 0xe7195b38UL, 0x79c8eedbUL,
    0xa17c0a47UL, 0x7c420fe9UL, 0xf8841ec9UL, 0x00000000UL,
    0x09808683UL, 0x322bed48UL, 0x1e1170acUL, 0x6c5a724eUL,
    0xfd0efffbUL, 0x0f853856UL, 0x3daed51eUL, 0x362d3927UL,
    0x0a0fd964UL, 0x685ca621UL, 0x9b5b54d1UL, 0x24362e3aUL,
    0x0c0a67b1UL, 0x9357e70fUL, 0xb4ee96d2UL, 0x1b9b919eUL,
    0x80c0c54fUL, 0x61dc20a2UL, 0x5a774b69UL, 0x1c121a16UL,
    0xe293ba0aUL, 0xc0a02ae5UL, 0x3c22e043UL, 0x121b171dUL,
    0x0e090d0bUL, 0xf28bc7adUL, 0x2db6a8b9UL, 0x141ea9c8UL,
    0x57f11985UL, 0xaf75074cUL, 0xee99ddbbUL, 0xa37f60fdUL,
    0xf701269fUL, 0x5c72f5bcUL, 0x44663bc5UL, 0x5bfb7e34UL,
    0x8b432976UL, 0xcb23c6dcUL, 0xb6edfc68UL, 0xb8e4f163UL,
    0xd731dccaUL, 0x42638510UL, 0x13972240UL, 0x84c61120UL,
    0x854a247dUL, 0xd2bb3df8UL, 0xaef93211UL, 0xc729a16dUL,
    0x1d9e2f4bUL, 0xdcb230f3UL, 0x0d8652ecUL, 0x77c1e3d0UL,
    0x2bb3166cUL, 0xa970b999UL, 0x119448faUL, 0x47e96422UL,
    0xa8fc8cc4UL, 0xa0f03f1aUL, 0x567d2cd8UL, 0x223390efUL,
    0x87494ec7UL, 0xd938d1c1UL, 0x8ccaa2feUL, 0x98d40b36UL,
    0xa6f581cfUL, 0xa57ade28UL, 0xdab78e26UL, 0x3fadbfa4UL,
    0x2c3a9de4UL, 0x5078920dUL, 0x6a5fcc9bUL, 0x547e4662UL,
    0xf68d13c2UL, 0x90d8b8e8UL, 0x2e39f75eUL, 0x82c3aff5UL,
    0x9f5d80beUL, 0x69d0937cUL, 0x6fd52da9UL, 0xcf2512b3UL,
    0xc8ac993bUL, 0x10187da7UL, 0xe89c636eUL, 0xdb3bbb7bUL,
    0xcd267809UL, 0x6e5918f4UL, 0xec9ab701UL, 0x834f9aa8UL,
    0xe6956e65UL, 0xaaffe67eUL, 0x21bccf08UL, 0xef15e8e6UL,
    0xbae79bd9UL, 0x4a6f36ceUL, 0xea9f09d4UL, 0x29b07cd6UL,
    0x31a4b2afUL, 0x2a3f2331UL, 0xc6a59430UL, 0x35a266c0UL,
    0x744ebc37UL, 0xfc82caa6UL, 0xe090d0b0UL, 0x33a7d815UL,
    0xf104984aUL, 0x41ecdaf7UL, 0x7fcd500eUL, 0x1791f62fUL,
    0x764dd68dUL, 0x43efb04dUL, 0xccaa4d54UL, 0xe49604dfUL,
    0x9ed1b5e3UL, 0x4c6a881bUL, 0xc12c1fb8UL, 0x4665517fUL,
    0x9d5eea04UL, 0x018c355dUL, 0xfa877473UL, 0xfb0b412eUL,
    0xb3671d5aUL, 0x92dbd252UL, 0xe9105633UL, 0x6dd64713UL,
    0x9ad7618cUL, 0x37a10c7aUL, 0x59f8148eUL, 0xeb133c89UL,
    0xcea927eeUL, 0xb761c935UL, 0xe11ce5edUL, 0x7a47b13cUL,
    0x9cd2df59UL, 0x55f2733fUL, 0x1814ce79UL, 0x73c737bfUL,
    0x53f7cdeaUL, 0x5ffdaa5bUL, 0xdf3d6f14UL, 0x7844db86UL,
    0xcaaff381UL, 0xb968c43eUL, 0x3824342cUL, 0xc2a3405fUL,
    0x161dc372UL, 0xbce2250cUL, 0x283c498bUL, 0xff0d9541UL,
    0x39a80171UL, 0x080cb3deUL, 0xd8b4e49cUL, 0x6456c190UL,
    0x7bcb8461UL, 0xd532b670UL, 0x486c5c74UL, 0xd0b85742UL,
};
static const unsigned int Td1[256] = {
    0x5051f4a7UL, 0x537e4165UL, 0xc31a17a4UL, 0x963a275eUL,
    0xcb3bab6bUL, 0xf11f9d45UL, 0xabacfa58UL, 0x934be303UL,
    0x552030faUL, 0xf6ad766dUL, 0x9188cc76UL, 0x25f5024cUL,
    0xfc4fe5d7UL, 0xd7c52acbUL, 0x80263544UL, 0x8fb562a3UL,
    0x49deb15aUL, 0x6725ba1bUL, 0x9845ea0eUL, 0xe15dfec0UL,
    0x02c32f75UL, 0x12814cf0UL, 0xa38d4697UL, 0xc66bd3f9UL,
    0xe7038f5fUL, 0x9515929cUL, 0xebbf6d7aUL, 0xda955259UL,
    0x2dd4be83UL, 0xd3587421UL, 0x2949e069UL, 0x448ec9c8UL,
    0x6a75c289UL, 0x78f48e79UL, 0x6b99583eUL, 0xdd27b971UL,
    0xb6bee14fUL, 0x17f088adUL, 0x66c920acUL, 0xb47dce3aUL,
    0x1863df4aUL, 0x82e51a31UL, 0x60975133UL, 0x4562537fUL,
    0xe0b16477UL, 0x84bb6baeUL, 0x1cfe81a0UL, 0x94f9082bUL,
    0x58704868UL, 0x198f45fdUL, 0x8794de6cUL, 0xb7527bf8UL,
    0x23ab73d3UL, 0xe2724b02UL, 0x57e31f8fUL, 0x2a6655abUL,
    0x07b2eb28UL, 0x032fb5c2UL, 0x9a86c57bUL, 0xa5d33708UL,
    0xf2302887UL, 0xb223bfa5UL, 0xba02036aUL, 0x5ced1682UL,
    0x2b8acf1cUL, 0x92a779b4UL, 0xf0f307f2UL, 0xa14e69e2UL,
    0xcd65daf4UL, 0xd50605beUL, 0x1fd13462UL, 0x8ac4a6feUL,
    0x9d342e53UL, 0xa0a2f355UL, 0x32058ae1UL, 0x75a4f6ebUL,
    0x390b83ecUL, 0xaa4060efUL, 0x065e719fUL, 0x51bd6e10UL,
    0xf93e218aUL, 0x3d96dd06UL, 0xaedd3e05UL, 0x464de6bdUL,
    0xb591548dUL, 0x0571c45dUL, 0x6f0406d4UL, 0xff605015UL,
    0x241998fbUL, 0x97d6bde9UL, 0xcc894043UL, 0x7767d99eUL,
    0xbdb0e842UL, 0x8807898bUL, 0x38e7195bUL, 0xdb79c8eeUL,
    0x47a17c0aUL, 0xe97c420fUL, 0xc9f8841eUL, 0x00000000UL,
    0x83098086UL, 0x48322bedUL, 0xac1e1170UL, 0x4e6c5a72UL,
    0xfbfd0effUL, 0x560f8538UL, 0x1e3daed5UL, 0x27362d39UL,
    0x640a0fd9UL, 0x21685ca6UL, 0xd19b5b54UL, 0x3a24362eUL,
    0xb10c0a67UL, 0x0f9357e7UL, 0xd2b4ee96UL, 0x9e1b9b91UL,
    0x4f80c0c5UL, 0xa261dc20UL, 0x695a774bUL, 0x161c121aUL,
    0x0ae293baUL, 0xe5c0a02aUL, 0x433c22e0UL, 0x1d121b17UL,
    0x0b0e090dUL, 0xadf28bc7UL, 0xb92db6a8UL, 0xc8141ea9UL,
    0x8557f119UL, 0x4caf7507UL, 0xbbee99ddUL, 0xfda37f60UL,
    0x9ff70126UL, 0xbc5c72f5UL, 0xc544663bUL, 0x345bfb7eUL,
    0x768b4329UL, 0xdccb23c6UL, 0x68b6edfcUL, 0x63b8e4f1UL,
    0xcad731dcUL, 0x10426385UL, 0x40139722UL, 0x2084c611UL,
    0x7d854a24UL, 0xf8d2bb3dUL, 0x11aef932UL, 0x6dc729a1UL,
    0x4b1d9e2fUL, 0xf3dcb230UL, 0xec0d8652UL, 0xd077c1e3UL,
    0x6c2bb316UL, 0x99a970b9UL, 0xfa119448UL, 0x2247e964UL,
    0xc4a8fc8cUL, 0x1aa0f03fUL, 0xd8567d2cUL, 0xef223390UL,
    0xc787494eUL, 0xc1d938d1UL, 0xfe8ccaa2UL, 0x3698d40bUL,
    0xcfa6f581UL, 0x28a57adeUL, 0x26dab78eUL, 0xa43fadbfUL,
    0xe42c3a9dUL, 0x0d507892UL, 0x9b6a5fccUL, 0x62547e46UL,
    0xc2f68d13UL, 0xe890d8b8UL, 0x5e2e39f7UL, 0xf582c3afUL,
    0xbe9f5d80UL, 0x7c69d093UL, 0xa96fd52dUL, 0xb3cf2512UL,
    0x3bc8ac99UL, 0xa710187dUL, 0x6ee89c63UL, 0x7bdb3bbbUL,
    0x09cd2678UL, 0xf46e5918UL, 0x01ec9ab7UL, 0xa8834f9aUL,
    0x65e6956eUL, 0x7eaaffe6UL, 0x0821bccfUL, 0xe6ef15e8UL,
    0xd9bae79bUL, 0xce4a6f36UL, 0xd4ea9f09UL, 0xd629b07cUL,
    0xaf31a4b2UL, 0x312a3f23UL, 0x30c6a594UL, 0xc035a266UL,
    0x37744ebcUL, 0xa6fc82caUL, 0xb0e090d0UL, 0x1533a7d8UL,
    0x4af10498UL, 0xf741ecdaUL, 0x0e7fcd50UL, 0x2f1791f6UL,
    0x8d764dd6UL, 0x4d43efb0UL, 0x54ccaa4dUL, 0xdfe49604UL,
    0xe39ed1b5UL, 0x1b4c6a88UL, 0xb8c12c1fUL, 0x7f466551UL,
    0x049d5eeaUL, 0x5d018c35UL, 0x73fa8774UL, 0x2efb0b41UL,
    0x5ab3671dUL, 0x5292dbd2UL, 0x33e91056UL, 0x136dd647UL,
    0x8c9ad761UL, 0x7a37a10cUL, 0x8e59f814UL, 0x89eb133cUL,
    0xeecea927UL, 0x35b761c9UL, 0xede11ce5UL, 0x3c7a47b1UL,
    0x599cd2dfUL, 0x3f55f273UL, 0x791814ceUL, 0xbf73c737UL,
    0xea53f7cdUL, 0x5b5ffdaaUL, 0x14df3d6fUL, 0x867844dbUL,
    0x81caaff3UL, 0x3eb968c4UL, 0x2c382434UL, 0x5fc2a340UL,
    0x72161dc3UL, 0x0cbce225UL, 0x8b283c49UL, 0x41ff0d95UL,
    0x7139a801UL, 0xde080cb3UL, 0x9cd8b4e4UL, 0x906456c1UL,
    0x617bcb84UL, 0x70d532b6UL, 0x74486c5cUL, 0x42d0b857UL,
};
static const unsigned int Td2[256] = {
    0xa75051f4UL, 0x65537e41UL, 0xa4c31a17UL, 0x5e963a27UL,
    0x6bcb3babUL, 0x45f11f9dUL, 0x58abacfaUL, 0x03934be3UL,
    0xfa552030UL, 0x6df6ad76UL, 0x769188ccUL, 0x4c25f502UL,
    0xd7fc4fe5UL, 0xcbd7c52aUL, 0x44802635UL, 0xa38fb562UL,
    0x5a49deb1UL, 0x1b6725baUL, 0x0e9845eaUL, 0xc0e15dfeUL,
    0x7502c32fUL, 0xf012814cUL, 0x97a38d46UL, 0xf9c66bd3UL,
    0x5fe7038fUL, 0x9c951592UL, 0x7aebbf6dUL, 0x59da9552UL,
    0x832dd4beUL, 0x21d35874UL, 0x692949e0UL, 0xc8448ec9UL,
    0x896a75c2UL, 0x7978f48eUL, 0x3e6b9958UL, 0x71dd27b9UL,
    0x4fb6bee1UL, 0xad17f088UL, 0xac66c920UL, 0x3ab47dceUL,
    0x4a1863dfUL, 0x3182e51aUL, 0x33609751UL, 0x7f456253UL,
    0x77e0b164UL, 0xae84bb6bUL, 0xa01cfe81UL, 0x2b94f908UL,
    0x68587048UL, 0xfd198f45UL, 0x6c8794deUL, 0xf8b7527bUL,
    0xd323ab73UL, 0x02e2724bUL, 0x8f57e31fUL, 0xab2a6655UL,
    0x2807b2ebUL, 0xc2032fb5UL, 0x7b9a86c5UL, 0x08a5d337UL,
    0x87f23028UL, 0xa5b223bfUL, 0x6aba0203UL, 0x825ced16UL,
    0x1c2b8acfUL, 0xb492a779UL, 0xf2f0f307UL, 0xe2a14e69UL,
    0xf4cd65daUL, 0xbed50605UL, 0x621fd134UL, 0xfe8ac4a6UL,
    0x539d342eUL, 0x55a0a2f3UL, 0xe132058aUL, 0xeb75a4f6UL,
    0xec390b83UL, 0xefaa4060UL, 0x9f065e71UL, 0x1051bd6eUL,
    0x8af93e21UL, 0x063d96ddUL, 0x05aedd3eUL, 0xbd464de6UL,
    0x8db59154UL, 0x5d0571c4UL, 0xd46f0406UL, 0x15ff6050UL,
    0xfb241998UL, 0xe997d6bdUL, 0x43cc8940UL, 0x9e7767d9UL,
    0x42bdb0e8UL, 0x8b880789UL, 0x5b38e719UL, 0xeedb79c8UL,
    0x0a47a17cUL, 0x0fe97c42UL, 0x1ec9f884UL, 0x00000000UL,
    0x86830980UL, 0xed48322bUL, 0x70ac1e11UL, 0x724e6c5aUL,
    0xfffbfd0eUL, 0x38560f85UL, 0xd51e3daeUL, 0x3927362dUL,
    0xd9640a0fUL, 0xa621685cUL, 0x54d19b5bUL, 0x2e3a2436UL,
    0x67b10c0aUL, 0xe70f9357UL, 0x96d2b4eeUL, 0x919e1b9bUL,
    0xc54f80c0UL, 0x20a261dcUL, 0x4b695a77UL, 0x1a161c12UL,
    0xba0ae293UL, 0x2ae5c0a0UL, 0xe0433c22UL, 0x171d121bUL,
    0x0d0b0e09UL, 0xc7adf28bUL, 0xa8b92db6UL, 0xa9c8141eUL,
    0x198557f1UL, 0x074caf75UL, 0xddbbee99UL, 0x60fda37fUL,
    0x269ff701UL, 0xf5bc5c72UL, 0x3bc54466UL, 0x7e345bfbUL,
    0x29768b43UL, 0xc6dccb23UL, 0xfc68b6edUL, 0xf163b8e4UL,
    0xdccad731UL, 0x85104263UL, 0x22401397UL, 0x112084c6UL,
    0x247d854aUL, 0x3df8d2bbUL, 0x3211aef9UL, 0xa16dc729UL,
    0x2f4b1d9eUL, 0x30f3dcb2UL, 0x52ec0d86UL, 0xe3d077c1UL,
    0x166c2bb3UL, 0xb999a970UL, 0x48fa1194UL, 0x642247e9UL,
    0x8cc4a8fcUL, 0x3f1aa0f0UL, 0x2cd8567dUL, 0x90ef2233UL,
    0x4ec78749UL, 0xd1c1d938UL, 0xa2fe8ccaUL, 0x0b3698d4UL,
    0x81cfa6f5UL, 0xde28a57aUL, 0x8e26dab7UL, 0xbfa43fadUL,
    0x9de42c3aUL, 0x920d5078UL, 0xcc9b6a5fUL, 0x4662547eUL,
    0x13c2f68dUL, 0xb8e890d8UL, 0xf75e2e39UL, 0xaff582c3UL,
    0x80be9f5dUL, 0x937c69d0UL, 0x2da96fd5UL, 0x12b3cf25UL,
    0x993bc8acUL, 0x7da71018UL, 0x636ee89cUL, 0xbb7bdb3bUL,
    0x7809cd26UL, 0x18f46e59UL, 0xb701ec9aUL, 0x9aa8834fUL,
    0x6e65e695UL, 0xe67eaaffUL, 0xcf0821bcUL, 0xe8e6ef15UL,
    0x9bd9bae7UL, 0x36ce4a6fUL, 0x09d4ea9fUL, 0x7cd629b0UL,
    0xb2af31a4UL, 0x23312a3fUL, 0x9430c6a5UL, 0x66c035a2UL,
    0xbc37744eUL, 0xcaa6fc82UL, 0xd0b0e090UL, 0xd81533a7UL,
    0x984af104UL, 0xdaf741ecUL, 0x500e7fcdUL, 0xf62f1791UL,
    0xd68d764dUL, 0xb04d43efUL, 0x4d54ccaaUL, 0x04dfe496UL,
    0xb5e39ed1UL, 0x881b4c6aUL, 0x1fb8c12cUL, 0x517f4665UL,
    0xea049d5eUL, 0x355d018cUL, 0x7473fa87UL, 0x412efb0bUL,
    0x1d5ab367UL, 0xd25292dbUL, 0x5633e910UL, 0x47136dd6UL,
    0x618c9ad7UL, 0x0c7a37a1UL, 0x148e59f8UL, 0x3c89eb13UL,
    0x27eecea9UL, 0xc935b761UL, 0xe5ede11cUL, 0xb13c7a47UL,
    0xdf599cd2UL, 0x733f55f2UL, 0xce791814UL, 0x37bf73c7UL,
    0xcdea53f7UL, 0xaa5b5ffdUL, 0x6f14df3dUL, 0xdb867844UL,
    0xf381caafUL, 0xc43eb968UL, 0x342c3824UL, 0x405fc2a3UL,
    0xc372161dUL, 0x250cbce2UL, 0x498b283cUL, 0x9541ff0dUL,
    0x017139a8UL, 0xb3de080cUL, 0xe49cd8b4UL, 0xc1906456UL,
    0x84617bcbUL, 0xb670d532UL, 0x5c74486cUL, 0x5742d0b8UL,
};
static const unsigned int Td3[256] = {
    0xf4a75051UL, 0x4165537eUL, 0x17a4c31aUL, 0x275e963aUL,
    0xab6bcb3bUL, 0x9d45f11fUL, 0xfa58abacUL, 0xe303934bUL,
    0x30fa5520UL, 0x766df6adUL, 0xcc769188UL, 0x024c25f5UL,
    0xe5d7fc4fUL, 0x2acbd7c5UL, 0x35448026UL, 0x62a38fb5UL,
    0xb15a49deUL, 0xba1b6725UL, 0xea0e9845UL, 0xfec0e15dUL,
    0x2f7502c3UL, 0x4cf01281UL, 0x4697a38dUL, 0xd3f9c66bUL,
    0x8f5fe703UL, 0x929c9515UL, 0x6d7aebbfUL, 0x5259da95UL,
    0xbe832dd4UL, 0x7421d358UL, 0xe0692949UL, 0xc9c8448eUL,
    0xc2896a75UL, 0x8e7978f4UL, 0x583e6b99UL, 0xb971dd27UL,
    0xe14fb6beUL, 0x88ad17f0UL, 0x20ac66c9UL, 0xce3ab47dUL,
    0xdf4a1863UL, 0x1a3182e5UL, 0x51336097UL, 0x537f4562UL,
    0x6477e0b1UL, 0x6bae84bbUL, 0x81a01cfeUL, 0x082b94f9UL,
    0x48685870UL, 0x45fd198fUL, 0xde6c8794UL, 0x7bf8b752UL,
    0x73d323abUL, 0x4b02e272UL, 0x1f8f57e3UL, 0x55ab2a66UL,
    0xeb2807b2UL, 0xb5c2032fUL, 0xc57b9a86UL, 0x3708a5d3UL,
    0x2887f230UL, 0xbfa5b223UL, 0x036aba02UL, 0x16825cedUL,
    0xcf1c2b8aUL, 0x79b492a7UL, 0x07f2f0f3UL, 0x69e2a14eUL,
    0xdaf4cd65UL, 0x05bed506UL, 0x34621fd1UL, 0xa6fe8ac4UL,
    0x2e539d34UL, 0xf355a0a2UL, 0x8ae13205UL, 0xf6eb75a4UL,
    0x83ec390bUL, 0x60efaa40UL, 0x719f065eUL, 0x6e1051bdUL,
    0x218af93eUL, 0xdd063d96UL, 0x3e05aeddUL, 0xe6bd464dUL,
    0x548db591UL, 0xc45d0571UL, 0x06d46f04UL, 0x5015ff60UL,
    0x98fb2419UL, 0xbde997d6UL, 0x4043cc89UL, 0xd99e7767UL,
    0xe842bdb0UL, 0x898b8807UL, 0x195b38e7UL, 0xc8eedb79UL,
    0x7c0a47a1UL, 0x420fe97cUL, 0x841ec9f8UL, 0x00000000UL,
    0x80868309UL, 0x2bed4832UL, 0x1170ac1eUL, 0x5a724e6cUL,
    0x0efffbfdUL, 0x8538560fUL, 0xaed51e3dUL, 0x2d392736UL,
    0x0fd9640aUL, 0x5ca62168UL, 0x5b54d19bUL, 0x362e3a24UL,
    0x0a67b10cUL, 0x57e70f93UL, 0xee96d2b4UL, 0x9b919e1bUL,
    0xc0c54f80UL, 0xdc20a261UL, 0x774b695aUL, 0x121a161cUL,
    0x93ba0ae2UL, 0xa02ae5c0UL, 0x22e0433cUL, 0x1b171d12UL,
    0x090d0b0eUL, 0x8bc7adf2UL, 0xb6a8b92dUL, 0x1ea9c814UL,
    0xf1198557UL, 0x75074cafUL, 0x99ddbbeeUL, 0x7f60fda3UL,
    0x01269ff7UL, 0x72f5bc5cUL, 0x663bc544UL, 0xfb7e345bUL,
    0x4329768bUL, 0x23c6dccbUL, 0xedfc68b6UL, 0xe4f163b8UL,
    0x31dccad7UL, 0x63851042UL, 0x97224013UL, 0xc6112084UL,
    0x4a247d85UL, 0xbb3df8d2UL, 0xf93211aeUL, 0x29a16dc7UL,
    0x9e2f4b1dUL, 0xb230f3dcUL, 0x8652ec0dUL, 0xc1e3d077UL,
    0xb3166c2bUL, 0x70b999a9UL, 0x9448fa11UL, 0xe9642247UL,
    0xfc8cc4a8UL, 0xf03f1aa0UL, 0x7d2cd856UL, 0x3390ef22UL,
    0x494ec787UL, 0x38d1c1d9UL, 0xcaa2fe8cUL, 0xd40b3698UL,
    0xf581cfa6UL, 0x7ade28a5UL, 0xb78e26daUL, 0xadbfa43fUL,
    0x3a9de42cUL, 0x78920d50UL, 0x5fcc9b6aUL, 0x7e466254UL,
    0x8d13c2f6UL, 0xd8b8e890UL, 0x39f75e2eUL, 0xc3aff582UL,
    0x5d80be9fUL, 0xd0937c69UL, 0xd52da96fUL, 0x2512b3cfUL,
    0xac993bc8UL, 0x187da710UL, 0x9c636ee8UL, 0x3bbb7bdbUL,
    0x267809cdUL, 0x5918f46eUL, 0x9ab701ecUL, 0x4f9aa883UL,
    0x956e65e6UL, 0xffe67eaaUL, 0xbccf0821UL, 0x15e8e6efUL,
    0xe79bd9baUL, 0x6f36ce4aUL, 0x9f09d4eaUL, 0xb07cd629UL,
    0xa4b2af31UL, 0x3f23312aUL, 0xa59430c6UL, 0xa266c035UL,
    0x4ebc3774UL, 0x82caa6fcUL, 0x90d0b0e0UL, 0xa7d81533UL,
    0x04984af1UL, 0xecdaf741UL, 0xcd500e7fUL, 0x91f62f17UL,
    0x4dd68d76UL, 0xefb04d43UL, 0xaa4d54ccUL, 0x9604dfe4UL,
    0xd1b5e39eUL, 0x6a881b4cUL, 0x2c1fb8c1UL, 0x65517f46UL,
    0x5eea049dUL, 0x8c355d01UL, 0x877473faUL, 0x0b412efbUL,
    0x671d5ab3UL, 0xdbd25292UL, 0x105633e9UL, 0xd647136dUL,
    0xd7618c9aUL, 0xa10c7a37UL, 0xf8148e59UL, 0x133c89ebUL,
    0xa927eeceUL, 0x61c935b7UL, 0x1ce5ede1UL, 0x47b13c7aUL,
    0xd2df599cUL, 0xf2733f55UL, 0x14ce7918UL, 0xc737bf73UL,
    0xf7cdea53UL, 0xfdaa5b5fUL, 0x3d6f14dfUL, 0x44db8678UL,
    0xaff381caUL, 0x68c43eb9UL, 0x24342c38UL, 0xa3405fc2UL,
    0x1dc37216UL, 0xe2250cbcUL, 0x3c498b28UL, 0x0d9541ffUL,
    0xa8017139UL, 0x0cb3de08UL, 0xb4e49cd8UL, 0x56c19064UL,
    0xcb84617bUL, 0x32b670d5UL, 0x6c5c7448UL, 0xb85742d0UL,
};
static const unsigned int Td4[256] = {
    0x52525252UL, 0x09090909UL, 0x6a6a6a6aUL, 0xd5d5d5d5UL,
    0x30303030UL, 0x36363636UL, 0xa5a5a5a5UL, 0x38383838UL,
    0xbfbfbfbfUL, 0x40404040UL, 0xa3a3a3a3UL, 0x9e9e9e9eUL,
    0x81818181UL, 0xf3f3f3f3UL, 0xd7d7d7d7UL, 0xfbfbfbfbUL,
    0x7c7c7c7cUL, 0xe3e3e3e3UL, 0x39393939UL, 0x82828282UL,
    0x9b9b9b9bUL, 0x2f2f2f2fUL, 0xffffffffUL, 0x87878787UL,
    0x34343434UL, 0x8e8e8e8eUL, 0x43434343UL, 0x44444444UL,
    0xc4c4c4c4UL, 0xdedededeUL, 0xe9e9e9e9UL, 0xcbcbcbcbUL,
    0x54545454UL, 0x7b7b7b7bUL, 0x94949494UL, 0x32323232UL,
    0xa6a6a6a6UL, 0xc2c2c2c2UL, 0x23232323UL, 0x3d3d3d3dUL,
    0xeeeeeeeeUL, 0x4c4c4c4cUL, 0x95959595UL, 0x0b0b0b0bUL,
    0x42424242UL, 0xfafafafaUL, 0xc3c3c3c3UL, 0x4e4e4e4eUL,
    0x08080808UL, 0x2e2e2e2eUL, 0xa1a1a1a1UL, 0x66666666UL,
    0x28282828UL, 0xd9d9d9d9UL, 0x24242424UL, 0xb2b2b2b2UL,
    0x76767676UL, 0x5b5b5b5bUL, 0xa2a2a2a2UL, 0x49494949UL,
    0x6d6d6d6dUL, 0x8b8b8b8bUL, 0xd1d1d1d1UL, 0x25252525UL,
    0x72727272UL, 0xf8f8f8f8UL, 0xf6f6f6f6UL, 0x64646464UL,
    0x86868686UL, 0x68686868UL, 0x98989898UL, 0x16161616UL,
    0xd4d4d4d4UL, 0xa4a4a4a4UL, 0x5c5c5c5cUL, 0xccccccccUL,
    0x5d5d5d5dUL, 0x65656565UL, 0xb6b6b6b6UL, 0x92929292UL,
    0x6c6c6c6cUL, 0x70707070UL, 0x48484848UL, 0x50505050UL,
    0xfdfdfdfdUL, 0xededededUL, 0xb9b9b9b9UL, 0xdadadadaUL,
    0x5e5e5e5eUL, 0x15151515UL, 0x46464646UL, 0x57575757UL,
    0xa7a7a7a7UL, 0x8d8d8d8dUL, 0x9d9d9d9dUL, 0x84848484UL,
    0x90909090UL, 0xd8d8d8d8UL, 0xababababUL, 0x00000000UL,
    0x8c8c8c8cUL, 0xbcbcbcbcUL, 0xd3d3d3d3UL, 0x0a0a0a0aUL,
    0xf7f7f7f7UL, 0xe4e4e4e4UL, 0x58585858UL, 0x05050505UL,
    0xb8b8b8b8UL, 0xb3b3b3b3UL, 0x45454545UL, 0x06060606UL,
    0xd0d0d0d0UL, 0x2c2c2c2cUL, 0x1e1e1e1eUL, 0x8f8f8f8fUL,
    0xcacacacaUL, 0x3f3f3f3fUL, 0x0f0f0f0fUL, 0x02020202UL,
    0xc1c1c1c1UL, 0xafafafafUL, 0xbdbdbdbdUL, 0x03030303UL,
    0x01010101UL, 0x13131313UL, 0x8a8a8a8aUL, 0x6b6b6b6bUL,
    0x3a3a3a3aUL, 0x91919191UL, 0x11111111UL, 0x41414141UL,
    0x4f4f4f4fUL, 0x67676767UL, 0xdcdcdcdcUL, 0xeaeaeaeaUL,
    0x97979797UL, 0xf2f2f2f2UL, 0xcfcfcfcfUL, 0xcecececeUL,
    0xf0f0f0f0UL, 0xb4b4b4b4UL, 0xe6e6e6e6UL, 0x73737373UL,
    0x96969696UL, 0xacacacacUL, 0x74747474UL, 0x22222222UL,
    0xe7e7e7e7UL, 0xadadadadUL, 0x35353535UL, 0x85858585UL,
    0xe2e2e2e2UL, 0xf9f9f9f9UL, 0x37373737UL, 0xe8e8e8e8UL,
    0x1c1c1c1cUL, 0x75757575UL, 0xdfdfdfdfUL, 0x6e6e6e6eUL,
    0x47474747UL, 0xf1f1f1f1UL, 0x1a1a1a1aUL, 0x71717171UL,
    0x1d1d1d1dUL, 0x29292929UL, 0xc5c5c5c5UL, 0x89898989UL,
    0x6f6f6f6fUL, 0xb7b7b7b7UL, 0x62626262UL, 0x0e0e0e0eUL,
    0xaaaaaaaaUL, 0x18181818UL, 0xbebebebeUL, 0x1b1b1b1bUL,
    0xfcfcfcfcUL, 0x56565656UL, 0x3e3e3e3eUL, 0x4b4b4b4bUL,
    0xc6c6c6c6UL, 0xd2d2d2d2UL, 0x79797979UL, 0x20202020UL,
    0x9a9a9a9aUL, 0xdbdbdbdbUL, 0xc0c0c0c0UL, 0xfefefefeUL,
    0x78787878UL, 0xcdcdcdcdUL, 0x5a5a5a5aUL, 0xf4f4f4f4UL,
    0x1f1f1f1fUL, 0xddddddddUL, 0xa8a8a8a8UL, 0x33333333UL,
    0x88888888UL, 0x07070707UL, 0xc7c7c7c7UL, 0x31313131UL,
    0xb1b1b1b1UL, 0x12121212UL, 0x10101010UL, 0x59595959UL,
    0x27272727UL, 0x80808080UL, 0xececececUL, 0x5f5f5f5fUL,
    0x60606060UL, 0x51515151UL, 0x7f7f7f7fUL, 0xa9a9a9a9UL,
    0x19191919UL, 0xb5b5b5b5UL, 0x4a4a4a4aUL, 0x0d0d0d0dUL,
    0x2d2d2d2dUL, 0xe5e5e5e5UL, 0x7a7a7a7aUL, 0x9f9f9f9fUL,
    0x93939393UL, 0xc9c9c9c9UL, 0x9c9c9c9cUL, 0xefefefefUL,
    0xa0a0a0a0UL, 0xe0e0e0e0UL, 0x3b3b3b3bUL, 0x4d4d4d4dUL,
    0xaeaeaeaeUL, 0x2a2a2a2aUL, 0xf5f5f5f5UL, 0xb0b0b0b0UL,
    0xc8c8c8c8UL, 0xebebebebUL, 0xbbbbbbbbUL, 0x3c3c3c3cUL,
    0x83838383UL, 0x53535353UL, 0x99999999UL, 0x61616161UL,
    0x17171717UL, 0x2b2b2b2bUL, 0x04040404UL, 0x7e7e7e7eUL,
    0xbabababaUL, 0x77777777UL, 0xd6d6d6d6UL, 0x26262626UL,
    0xe1e1e1e1UL, 0x69696969UL, 0x14141414UL, 0x63636363UL,
    0x55555555UL, 0x21212121UL, 0x0c0c0c0cUL, 0x7d7d7d7dUL,
};
static const unsigned int rcon[] = {
    0x01000000UL, 0x02000000UL, 0x04000000UL, 0x08000000UL,
    0x10000000UL, 0x20000000UL, 0x40000000UL, 0x80000000UL,
    0x1B000000UL, 0x36000000UL,
};

#define GETU32(pt) (((unsigned int)(pt)[0] << 24) ^ \
                    ((unsigned int)(pt)[1] << 16) ^ \
                    ((unsigned int)(pt)[2] <<  8) ^ \
                    ((unsigned int)(pt)[3]))

#define PUTU32(ct, st) { (ct)[0] = (unsigned char)((st) >> 24); \
                         (ct)[1] = (unsigned char)((st) >> 16); \
                         (ct)[2] = (unsigned char)((st) >>  8); \
                         (ct)[3] = (unsigned char)(st); }

/*
* Expand the cipher key into the encryption key schedule and return the
* number of rounds for the given cipher key size.
*/
int aes_setkey_enc(unsigned int rk[], const unsigned char cipherKey[], int keyBytes)
{
    int i = 0;
    unsigned int temp;

    rk[0] = GETU32(cipherKey     );
    rk[1] = GETU32(cipherKey +  4);
    rk[2] = GETU32(cipherKey +  8);
    rk[3] = GETU32(cipherKey + 12);
    if (keyBytes == 16) { // 128 bits
        for (;;) {
            temp  = rk[3];
            rk[4] = rk[0] ^
                (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
                (Te4[(temp >>  8) & 0xff] & 0x00ff0000) ^
                (Te4[(temp      ) & 0xff] & 0x0000ff00) ^
                (Te4[(temp >> 24)       ] & 0x000000ff) ^
                rcon[i];
            rk[5] = rk[1] ^ rk[4];
            rk[6] = rk[2] ^ rk[5];
            rk[7] = rk[3] ^ rk[6];
            if (++i == 10) {
                return 10;
            }
            rk += 4;
        }
    }
    rk[4] = GETU32(cipherKey + 16);
    rk[5] = GETU32(cipherKey + 20);
    if (keyBytes == 24) { // 192 bits
        for (;;) {
            temp = rk[ 5];
            rk[ 6] = rk[ 0] ^
                (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
                (Te4[(temp >>  8) & 0xff] & 0x00ff0000) ^
                (Te4[(temp      ) & 0xff] & 0x0000ff00) ^
                (Te4[(temp >> 24)       ] & 0x000000ff) ^
                rcon[i];
            rk[ 7] = rk[ 1] ^ rk[ 6];
            rk[ 8] = rk[ 2] ^ rk[ 7];
            rk[ 9] = rk[ 3] ^ rk[ 8];
            if (++i == 8) {
                return 12;
            }
            rk[10] = rk[ 4] ^ rk[ 9];
            rk[11] = rk[ 5] ^ rk[10];
            rk += 6;
        }
    }
    rk[6] = GETU32(cipherKey + 24);
    rk[7] = GETU32(cipherKey + 28);
    if (keyBytes == 32) { // 256 bits
        for (;;) {
            temp = rk[ 7];
            rk[ 8] = rk[ 0] ^
                (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
                (Te4[(temp >>  8) & 0xff] & 0x00ff0000) ^
                (Te4[(temp      ) & 0xff] & 0x0000ff00) ^
                (Te4[(temp >> 24)       ] & 0x000000ff) ^
                rcon[i];
            rk[ 9] = rk[ 1] ^ rk[ 8];
            rk[10] = rk[ 2] ^ rk[ 9];
            rk[11] = rk[ 3] ^ rk[10];
            if (++i == 7) {
                return 14;
            }
            temp = rk[11];
            rk[12] = rk[ 4] ^
                (Te4[(temp >> 24)       ] & 0xff000000) ^
                (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^
                (Te4[(temp >>  8) & 0xff] & 0x0000ff00) ^
                (Te4[(temp      ) & 0xff] & 0x000000ff);
            rk[13] = rk[ 5] ^ rk[12];
            rk[14] = rk[ 6] ^ rk[13];
            rk[15] = rk[ 7] ^ rk[14];

            rk += 8;
        }
    }
    return 0;
}

/*
* Expand the cipher key into encryption and decryption key schedule and
* return the number of rounds for the given cipher key size.
*/
int AesGenKeySched(unsigned int rk[], unsigned int rrk[], const unsigned char cipherKey[], int keyBytes)
{
    int Nr, i;

    // expand the cipher key
    Nr = aes_setkey_enc(rk, cipherKey, keyBytes);
    // invert the order of the first round keys
    rrk += Nr * 4;
    rrk[0] = rk[0];
    rrk[1] = rk[1];
    rrk[2] = rk[2];
    rrk[3] = rk[3];

   /*
    * apply the inverse MixColumn transform to all round keys but the first
    * and the last
    */
    for (i = 1; i < Nr; i++) {
        rrk -= 4;
        rk += 4;
        rrk[0] =
            Td0[Te4[(rk[0] >> 24)       ] & 0xff] ^
            Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^
            Td2[Te4[(rk[0] >>  8) & 0xff] & 0xff] ^
            Td3[Te4[(rk[0]      ) & 0xff] & 0xff];
        rrk[1] =
            Td0[Te4[(rk[1] >> 24)       ] & 0xff] ^
            Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^
            Td2[Te4[(rk[1] >>  8) & 0xff] & 0xff] ^
            Td3[Te4[(rk[1]      ) & 0xff] & 0xff];
        rrk[2] =
            Td0[Te4[(rk[2] >> 24)       ] & 0xff] ^
            Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^
            Td2[Te4[(rk[2] >>  8) & 0xff] & 0xff] ^
            Td3[Te4[(rk[2]      ) & 0xff] & 0xff];
        rrk[3] =
            Td0[Te4[(rk[3] >> 24)       ] & 0xff] ^
            Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^
            Td2[Te4[(rk[3] >>  8) & 0xff] & 0xff] ^
            Td3[Te4[(rk[3]      ) & 0xff] & 0xff];
    }
    // invert the order of the last round keys
    rrk -= 4;
    rk += 4;
    rrk[0] = rk[0];
    rrk[1] = rk[1];
    rrk[2] = rk[2];
    rrk[3] = rk[3];

    return Nr;
}

/*
* Encrypt the plain text into cipher
*/
void AesEncBlk(AesCtx *pCtx, const unsigned char pt[], unsigned char ct[])
{
    unsigned int s0, s1, s2, s3, t0, t1, t2, t3, *iv;
    const unsigned int *rk;
    int r;

    rk = pCtx->Ek;
    iv = pCtx->Iv;
    /*
     * map byte array block to cipher state
     * and add initial round key:
     */
    s0 = GETU32(pt     ) ^ rk[0];
    s1 = GETU32(pt +  4) ^ rk[1];
    s2 = GETU32(pt +  8) ^ rk[2];
    s3 = GETU32(pt + 12) ^ rk[3];
    if (pCtx->Mode) {
        s0 = s0 ^ iv[0];
        s1 = s1 ^ iv[1];
        s2 = s2 ^ iv[2];
        s3 = s3 ^ iv[3];
    }
    /*
     * Nr - 1 full rounds:
     */
    r = pCtx->Nr >> 1;
    for (;;) {
        t0 =
            Te0[(s0 >> 24)       ] ^
            Te1[(s1 >> 16) & 0xff] ^
            Te2[(s2 >>  8) & 0xff] ^
            Te3[(s3      ) & 0xff] ^
            rk[4];
        t1 =
            Te0[(s1 >> 24)       ] ^
            Te1[(s2 >> 16) & 0xff] ^
            Te2[(s3 >>  8) & 0xff] ^
            Te3[(s0      ) & 0xff] ^
            rk[5];
        t2 =
            Te0[(s2 >> 24)       ] ^
            Te1[(s3 >> 16) & 0xff] ^
            Te2[(s0 >>  8) & 0xff] ^
            Te3[(s1      ) & 0xff] ^
            rk[6];
        t3 =
            Te0[(s3 >> 24)       ] ^
            Te1[(s0 >> 16) & 0xff] ^
            Te2[(s1 >>  8) & 0xff] ^
            Te3[(s2      ) & 0xff] ^
            rk[7];

        rk += 8;
        if (--r == 0) {
            break;
        }

        s0 =
            Te0[(t0 >> 24)       ] ^
            Te1[(t1 >> 16) & 0xff] ^
            Te2[(t2 >>  8) & 0xff] ^
            Te3[(t3      ) & 0xff] ^
            rk[0];
        s1 =
            Te0[(t1 >> 24)       ] ^
            Te1[(t2 >> 16) & 0xff] ^
            Te2[(t3 >>  8) & 0xff] ^
            Te3[(t0      ) & 0xff] ^
            rk[1];
        s2 =
            Te0[(t2 >> 24)       ] ^
            Te1[(t3 >> 16) & 0xff] ^
            Te2[(t0 >>  8) & 0xff] ^
            Te3[(t1      ) & 0xff] ^
            rk[2];
        s3 =
            Te0[(t3 >> 24)       ] ^
            Te1[(t0 >> 16) & 0xff] ^
            Te2[(t1 >>  8) & 0xff] ^
            Te3[(t2      ) & 0xff] ^
            rk[3];
    }
    /*
     * apply last round and
     * map cipher state to byte array block:
     */
    s0 =
        (Te4[(t0 >> 24)       ] & 0xff000000) ^
        (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
        (Te4[(t2 >>  8) & 0xff] & 0x0000ff00) ^
        (Te4[(t3      ) & 0xff] & 0x000000ff) ^
        rk[0];
    PUTU32(ct     , s0);
    s1 =
        (Te4[(t1 >> 24)       ] & 0xff000000) ^
        (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
        (Te4[(t3 >>  8) & 0xff] & 0x0000ff00) ^
        (Te4[(t0      ) & 0xff] & 0x000000ff) ^
        rk[1];
    PUTU32(ct +  4, s1);
    s2 =
        (Te4[(t2 >> 24)       ] & 0xff000000) ^
        (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
        (Te4[(t0 >>  8) & 0xff] & 0x0000ff00) ^
        (Te4[(t1      ) & 0xff] & 0x000000ff) ^
        rk[2];
    PUTU32(ct +  8, s2);
    s3 =
        (Te4[(t3 >> 24)       ] & 0xff000000) ^
        (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
        (Te4[(t1 >>  8) & 0xff] & 0x0000ff00) ^
        (Te4[(t2      ) & 0xff] & 0x000000ff) ^
        rk[3];
    PUTU32(ct + 12, s3);

    if (pCtx->Mode) {
        iv[0] = s0;
        iv[1] = s1;
        iv[2] = s2;
        iv[3] = s3;
    }
}

/*
* Decrypt the cipher into plain text
*/
void AesDecBlk(AesCtx *pCtx, const unsigned char ct[], unsigned char pt[])
{
    unsigned int s0, s1, s2, s3, t0, t1, t2, t3, v0, v1, v2, v3, *iv;
    const unsigned int *rk;
    int r;

    rk = pCtx->Dk;
    iv = pCtx->Iv;
    /*
     * map byte array block to cipher state
     * and add initial round key:
     */
    v0 = GETU32(ct     );    s0 = v0 ^ rk[0];
    v1 = GETU32(ct +  4);    s1 = v1 ^ rk[1];
    v2 = GETU32(ct +  8);    s2 = v2 ^ rk[2];
    v3 = GETU32(ct + 12);    s3 = v3 ^ rk[3];
    /*
     * Nr - 1 full rounds:
     */
    r = pCtx->Nr >> 1;
    for (;;) {
        t0 =
            Td0[(s0 >> 24)       ] ^
            Td1[(s3 >> 16) & 0xff] ^
            Td2[(s2 >>  8) & 0xff] ^
            Td3[(s1      ) & 0xff] ^
            rk[4];
        t1 =
            Td0[(s1 >> 24)       ] ^
            Td1[(s0 >> 16) & 0xff] ^
            Td2[(s3 >>  8) & 0xff] ^
            Td3[(s2      ) & 0xff] ^
            rk[5];
        t2 =
            Td0[(s2 >> 24)       ] ^
            Td1[(s1 >> 16) & 0xff] ^
            Td2[(s0 >>  8) & 0xff] ^
            Td3[(s3      ) & 0xff] ^
            rk[6];
        t3 =
            Td0[(s3 >> 24)       ] ^
            Td1[(s2 >> 16) & 0xff] ^
            Td2[(s1 >>  8) & 0xff] ^
            Td3[(s0      ) & 0xff] ^
            rk[7];

        rk += 8;
        if (--r == 0) {
            break;
        }

        s0 =
            Td0[(t0 >> 24)       ] ^
            Td1[(t3 >> 16) & 0xff] ^
            Td2[(t2 >>  8) & 0xff] ^
            Td3[(t1      ) & 0xff] ^
            rk[0];
        s1 =
            Td0[(t1 >> 24)       ] ^
            Td1[(t0 >> 16) & 0xff] ^
            Td2[(t3 >>  8) & 0xff] ^
            Td3[(t2      ) & 0xff] ^
            rk[1];
        s2 =
            Td0[(t2 >> 24)       ] ^
            Td1[(t1 >> 16) & 0xff] ^
            Td2[(t0 >>  8) & 0xff] ^
            Td3[(t3      ) & 0xff] ^
            rk[2];
        s3 =
            Td0[(t3 >> 24)       ] ^
            Td1[(t2 >> 16) & 0xff] ^
            Td2[(t1 >>  8) & 0xff] ^
            Td3[(t0      ) & 0xff] ^
            rk[3];
    }
    /*
     * apply last round and
     * map cipher state to byte array block:
     */
    s0 =
        (Td4[(t0 >> 24)       ] & 0xff000000) ^
        (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
        (Td4[(t2 >>  8) & 0xff] & 0x0000ff00) ^
        (Td4[(t1      ) & 0xff] & 0x000000ff) ^
        rk[0];
    s1 =
        (Td4[(t1 >> 24)       ] & 0xff000000) ^
        (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
        (Td4[(t3 >>  8) & 0xff] & 0x0000ff00) ^
        (Td4[(t2      ) & 0xff] & 0x000000ff) ^
        rk[1];
    s2 =
        (Td4[(t2 >> 24)       ] & 0xff000000) ^
        (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
        (Td4[(t0 >>  8) & 0xff] & 0x0000ff00) ^
        (Td4[(t3      ) & 0xff] & 0x000000ff) ^
        rk[2];
    s3 =
        (Td4[(t3 >> 24)       ] & 0xff000000) ^
        (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
        (Td4[(t1 >>  8) & 0xff] & 0x0000ff00) ^
        (Td4[(t0      ) & 0xff] & 0x000000ff) ^
        rk[3];

    if (pCtx->Mode) {
        s0 = s0 ^ iv[0];    iv[0] = v0;
        s1 = s1 ^ iv[1];    iv[1] = v1;
        s2 = s2 ^ iv[2];    iv[2] = v2;
        s3 = s3 ^ iv[3];    iv[3] = v3;
    }

    PUTU32(pt     , s0);
    PUTU32(pt +  4, s1);
    PUTU32(pt +  8, s2);
    PUTU32(pt + 12, s3);
}

//////////////////////////////////////////////////////////////////////////////
// API functions                                                            //
//////////////////////////////////////////////////////////////////////////////

/*
* initialize AES context
*/
int AesCtxIni(AesCtx *pCtx, unsigned char *pIV, unsigned char *pKey, unsigned int KeyLen, unsigned char Mode)
{
    if (pKey == 0 || pCtx == 0 || (KeyLen != KEY128 && KeyLen != KEY192 && KeyLen != KEY256))
        return -1;

    // generate key schedule
    pCtx->Nr = AesGenKeySched(pCtx->Ek,  pCtx->Dk, pKey, KeyLen);

    // initialize IV
    if (pIV != 0) {
        pCtx->Iv[0] = GETU32(pIV     );
        pCtx->Iv[1] = GETU32(pIV + 4 );
        pCtx->Iv[2] = GETU32(pIV + 8 );
        pCtx->Iv[3] = GETU32(pIV + 12);
    }

    // mode
    pCtx->Mode = Mode;

    return 0;
}

/*
* Encrypt plain text
*/
int AesEncrypt(AesCtx *pCtx, unsigned char *pData, unsigned char *pCipher, unsigned int DataLen)
{
    int i;

    if (pData == 0 || pCipher == 0 || pCtx == 0 || (DataLen & 0xf) != 0)
        return -1;

    for (i = 0; i < DataLen; i += BLOCKSZ) {
        // encrypt block by block
        AesEncBlk(pCtx, pData, pCipher);
        pCipher += BLOCKSZ;
        pData += BLOCKSZ;
    }
    return DataLen;
}

/*
* Decrypt cipher
*/
int AesDecrypt(AesCtx *pCtx, unsigned char *pCipher, unsigned char *pData, unsigned int CipherLen)
{
    int i;

    if (pData == 0 || pCipher == 0 || pCtx == 0 || (CipherLen & 0xf) != 0)
        return -1;

    for (i = 0; i < CipherLen; i += BLOCKSZ) {
        // decrypt block by block
        AesDecBlk(pCtx, pCipher, pData);
        pCipher += BLOCKSZ;
        pData += BLOCKSZ;
    }
    return CipherLen;
}

//////////////////////////////////////////////////////////////////////////////
// Sample main program                                                      //
//////////////////////////////////////////////////////////////////////////////

#ifndef EMBEDDED
int main()
{
    AesCtx ctx;
    unsigned char iv[] = "INI VECTINI VECT";
    unsigned char key[] = "This is a sample AESKey";
    unsigned char databuf[] = "Data : AES Test"; // must be in multiple of 16

    // initialize context and encrypt data at one end

    if( AesCtxIni(&ctx, iv, key, KEY128, CBC) < 0)
        printf("init error\n");

    if (AesEncrypt(&ctx, databuf, databuf, sizeof databuf) < 0)
        printf("error in encryption\n");

    // initialize context and decrypt cipher at other end

    if( AesCtxIni(&ctx, iv, key, KEY128, CBC) < 0)
        printf("init error\n");

    if (AesDecrypt(&ctx, databuf, databuf, sizeof databuf) < 0)
        printf("error in decryption\n");

    printf("%s\n", databuf);

    return 0;
}
#endif