#!/usr/bin/perl -w # Proof of concept for encoding to LFSR stream encoded in preprocessor. use strict; # Initialize random number generator. if( $#ARGV < 0 ) { die "$0 \n"; } my $seed = shift @ARGV; if( $seed !~ /^\d+$/ || $seed < 1 || $seed > 65535 ) { die "PIN must be in the range of [1, 65535]\n"; } # Select random bit positions. my @indices = (0 .. 15); for(my $i = 15; $i > 1; $i--) { my $j = int(rand($i + 1)); @indices[$i, $j] = @indices[$j, $i]; } $#indices = 7; sub CollectBits() { my $o = 0; for(my $i = 0; $i < 8; $i++) { if( ($seed & (1 << $indices[$i])) != 0 ) { $o |= 1 << $i; } } return $o; } # Output decoder header. print <<"EOT"; #ifndef PIN \t#error Please compile with -DPIN= #else \t#ifndef _ \t\t#define _ __FILE__ EOT for(my $bit = 0; $bit < 16; $bit++) { print "\t\t#if PIN % ", (1 << ($bit + 1)), " > ", (1 << $bit) - 1, "\n", "\t\t\t#define BIT$bit\n", "\t\t#endif\n"; } print <<"EOT"; \t\tstatic const unsigned char data[] = {0 EOT # Translate input bytes. my $max_delta_bits = 1; my $size = 0; while( my $line = <> ) { foreach my $byte (unpack 'C*', $line) { # Run random number generator until the bits match the byte we # wanted. Note that we always step forward at least one step, # so that consecutive duplicate bytes will still advance the # random number seed. my $min_steps = int(rand(8) + 1); my $steps = 0; for(; $steps < $min_steps || CollectBits() != $byte; $steps++) { my $bit = $seed ^ ($seed >> 2) ^ ($seed >> 3) ^ ($seed >> 5); $seed = (($seed >> 1) | ($bit << 15)) & 0xffff; } $steps > 0 or die; # Output directives to advance some number of steps and output byte. print "\t\t\t#define OUTPUT_BYTE\n"; my $delta_bits = 0; for(; $steps >= (1 << $delta_bits); $delta_bits++) { if( ($steps & (1 << $delta_bits)) != 0 ) { print "\t\t\t#define STEP$delta_bits\n"; } } if( $max_delta_bits < $delta_bits ) { $max_delta_bits = $delta_bits; } print "\t\t\t#include _\n"; $size++; } } # Output decoder footer. print <<"EOT"; \t\t}; \t\t#include \t\tint main() { return !fwrite(data, $size, 1, stdout); } \t#else \t\t#ifdef OUTPUT_BYTE \t\t\t#undef OUTPUT_BYTE \t\t\t#include _ EOT for(my $i = 0; $i < 8; $i++) { print "\t\t\t#ifdef BIT", $indices[$i], "\n", "\t\t\t|", (1 << $i), "\n", "\t\t\t#endif\n"; } print <<"EOT"; \t\t\t,0 \t\t#else EOT for(my $i = $max_delta_bits - 1; $i > 0; $i--) { print "\t\t\t#ifdef STEP$i\n", "\t\t\t\t#undef STEP$i\n", "\t\t\t\t#include _\n", "\t\t\t\t#define STEP", $i - 1, "\n", "\t\t\t\t#include _\n", "\t\t\t\t#define STEP", $i - 1, "\n", "\t\t\t#endif\n"; } print <<"EOT"; \t\t\t#ifdef STEP0 \t\t\t\t#undef STEP0 \t\t\t\t#undef BIT16 \t\t\t\t#ifdef BIT0 EOT for(my $bit0 = 1; $bit0 >= 0; $bit0--) { print "\t\t\t\t#else\n" if $bit0 == 0; for(my $bit2 = 1; $bit2 >= 0; $bit2--) { print "\t\t\t\t\t", ($bit2 == 1 ? "#ifdef BIT2" : "#else"), "\n"; for(my $bit3 = 1; $bit3 >= 0; $bit3--) { print "\t\t\t\t\t\t", ($bit3 == 1 ? "#ifdef BIT3" : "#else"), "\n"; my $xor = $bit0 ^ $bit2 ^ $bit3; print "\t\t\t\t\t\t\t", ($xor == 0 ? "#ifdef" : "#ifndef"), " BIT5\n", "\t\t\t\t\t\t\t\t#define BIT16\n", "\t\t\t\t\t\t\t#endif\n"; print "\t\t\t\t\t\t#endif\n" if $bit3 == 0; } print "\t\t\t\t\t#endif\n" if $bit2 == 0; } } print <<"EOT"; \t\t\t\t#endif EOT for(my $bit = 0; $bit < 16; $bit++) { print "\t\t\t\t#undef BIT$bit\n", "\t\t\t\t#ifdef BIT", $bit + 1, "\n", "\t\t\t\t\t#define BIT$bit\n", "\t\t\t\t#endif\n"; } print <<"EOT"; \t\t\t#endif \t\t#endif \t#endif #endif EOT