Close
0%
0%

PEAC Pisano with End-Around Carry algorithm

Add X to Y and Y to X, says the song. And carry on.

Similar projects worth following
A purely additive, non-cryptographic, fast and minimalistic checksum/PRNG/scrambler.

The sweet spot is a 32-bit checksum with a pair of 16-bit registers,
- very small, using only ADD,
- without the flaws of Adler32 and Fletcher, yet the same size and complexity,
- as good as CRC32, which it may replace when the memory footprint is critical
- can't be 0-crashed
- very easy to implement in digital circuits as well as microcontrollers,
- suitable for the detection of trivial corruption in network packets or files.
- not patented
- "as is", inappropriate for cryptography (though could inspire someone)

Lately, gPEAC with m=741454 (39 bits of entropy) has been found, a bit slower but with better avalanche than the PEAC with w16, more suitable for hash tables.

French article in GNU/Linux Magazine France

If you wonder why, just click and read the log.

For the what, check Definitions and Draft as well as PEAC vs LFSR for a comparison.

The original algo/project name was "Fibonacci checksum" but it later appeared that it was not the most accurate choice because Leonardo Pisano (the real name of Fibonacci) is the name associated to the periodicity of the sequence under modulo. All I did was add the tiny detail of "end-around carry", or "1-complement addition", which changed everything.

 
-o-O-0-O-o-
 

As for how I came to this system...

In 2012, Piano Magic released their album "Life Has Not Finished with Me Yet". One song contains a weird repeating pattern...

Glen Johnson's lyrics are often cryptic and more evocative than objective, but any geek's mind would cling on this mantra at the end:

"Add X to Y and Y to X"

This is really weird but... Why ? What's the point in this obscure "song" with no precise theme or clear subject ? And what does it do ? This last question is the most easily answered : just follow the damned algorithm.

C'est parti...

X=1, Y=0
Y+=X => 0+1=1
X+=Y => 1+1=2
Y+=X => 1+2=3
X+=Y => 2+3=5
Y+=X => 3+5=8
X+=Y => 5+8=13
X+=Y => 8+13=21
Y+=X => 13+21=34
X+=Y => 21+34=55
...

No need to go further, most of you should have recognised http://oeis.org/A000045, the famous Fibonacci sequence.

This gave me a compelling idea to modify the old Fletcher & Adler algorithms, keeping their very low footprint and minimalistic computational complexity. Both of these well known algos use a pair of values and have a similar structure. The trick is that rearranging the data dependency graph provides the equivalent of a minimalistic polynomial checksum, because the result is fed back on itself, in a more robust way than Fletcher's algo.

At first glance, this new checksum loop's body becomes something like :

Y += ( X + datum[i  ] );
X += ( Y + datum[i+1] );
i+=2;

This loop body is totally trivial to unroll. As trivial is the design of the corresponding digital circuit. This early version seemed to contain the whole checksum entropy in the last computed value but now X and Y are part of the signature. And the really important enhancement is the use of the carry!

For superscalar 32 bits CPUs, the following code seems to work well though the missing carry hardware (and/or lack of language support) requires more instructions to emulate:

t = X + Y + C;    Y = X + data;
C = t >> 16;      X = t & 0xFFFF;

A more efficient variation exists which does not use a temporary variable:

C += X + Y;
Y = X + data;
X = C & MASK;
C = C >> WIDTH;

In this worst case, without support of a carry flag, that's 5 basic operations (not counting memory loads) that fit in 4 registers and 3 cycles, to process 2 bytes. Not too bad. I'll let you deal with alignment. But is it really safe or safer?

The following logs will show how the idea evolves and the performance increases, through discussions about carry wrap-around, register widths, scheduling, avalanche, parallelism, orbits, structure, and escaping black holes...

 
-o-O-0-O-o-
 

Logs:
1. The variable
2. Datapath
3. Adler32 weakness
4. Easy circuit
5. Periodicity
6. A promising 32-bit checksum
7. Progress
8. Why
9. Orbital mechanics
10. Orbits, trajectories and that damned carry bit
11. Two hairy orbits
12. How to deal with black holes
13. Anteriority
14. Moonlighting as a PRNG
15. A new name
16. More orbits !
17. First image
18. Structure and extrapolations
19. Even more orbits !
20. Start and stop
21. Some theory
22. Some more theory
23. Even more theory.
24. A little enhancement
25. sdrawkcab gnioG
26. Further theorising
27. What is it ?
28. A bigger enhancement
29. Going both ways
30. Can you add states ?
31. Please, GCC !
32. _|_||_||_|______|______|____|_|___|_________|||_|__
33. Carry on with GCC
34. A good compromise
35. The new non-masking algorithm
36. Add or XOR ?
37. A 32/64-bit version
38. Closing the trajectories
39....

Read more »

ygrand.tgz

a POSIX-conformant replacement for rand() and srand(). Also provides a "fake" generator (pulling data from /dev/random) to help with statistical comparisons.

x-compressed-tar - 1.81 kB - 02/10/2025 at 03:43

Download

Checksum_PEAC64_asm.c

64-bit checksum, 7 instructions and 128 bits per iteration, in asm for x86-64

x-csrc - 2.73 kB - 11/04/2024 at 06:34

Download

PEACLS_20241013-2.tgz

PEACLS : scrambler and descrambler finished, detect errors

x-compressed-tar - 20.95 kB - 10/13/2024 at 20:11

Download

PEACLS_20241013.tgz

PEAC Line Scrambler, first VHDL version (the prefix check is still missing)

x-compressed-tar - 20.48 kB - 10/13/2024 at 06:08

Download

orbit_resume_64.c

sequential scanner adapted to 64-bit values. Can disable MSB masking.

x-csrc - 2.13 kB - 10/01/2024 at 05:22

Download

View all 71 files

  • Stutter

    Yann Guidon / YGDES02/11/2025 at 11:38 0 comments

    Playing a bit with PEAC w4 :

    #include <stdint.h>
    
    uint8_t PEAC_XC=1,  // the 5-bit part
            PEAC_Y=0;   // 4-bit
    
    #include <stdio.h>
    
    int main() {
      int i=0;
    
      do {
        printf("% 3d:   % 3d  % 3d \n", i, PEAC_XC, PEAC_Y);
    
        // split
        uint8_t PEAC_X = PEAC_XC & 15;
        PEAC_XC >>= 4;
    
        // PEAC scrambler
        PEAC_XC +=   PEAC_X + PEAC_Y;
        PEAC_Y   = ( PEAC_X + 0 ) & 15;
    
        i++;
      } while (i <= 136);
    
      return 0;
    }
    

    W4 is a maximal, not perfect, orbit so there are "only" 135 iterations. But the output sequence, either PEAC_Y or PEAC_XC, shows that some numbers repeat but only in consecutive pairs

            XC    Y
      0:     1    0 
      1:     1    1
      2:     2    1
      3:     3    2 
      4:     5    3 
      5:     8    5 
      6:    13    8 
      7:    21   13 
      8:    19    5 
      9:     9    3 
     10:    12    9 
     11:    21   12 
     12:    18    5 
     13:     8    2 
     14:    10    8 
     15:    18   10 
     16:    13    2 
     17:    15   13 
     18:    28   15 
     19:    28   12
     20:    25   12
     21:    22    9 
     22:    16    6 
     23:     7    0 
     24:     7    7
     25:    14    7
     26:    21   14 
     27:    20    5 
     28:    10    4 
     29:    14   10 
     30:    24   14 
     31:    23    8 
     32:    16    7 
     33:     8    0 
     34:     8    8 
     35:    16    8 
     36:     9    0 
     37:     9    9 
     38:    18    9 
     39:    12    2 
     40:    14   12
    

    This "stutter" might be a sort of "signature" of a PEAC PRNG, which is why PEAC is better used as a scrambler IMHO.

    Now, is this "stutter" a defect ? Not really. On the primary orbit of w4 above,

    •  the number 2 appears 11 times and "stutters" 2 times.
    •  3 appears 9 times and stutters 1×.
    • 4 appears 12 times and stutters 1×

    So in a maximal (and not perfect) orbit, there are some imbalances.

    .

  • Init vectors

    Yann Guidon / YGDES02/08/2025 at 14:34 0 comments

    Until now I use 0xABCD and 0x4567 to initialise the PEAC16x2 algorithms, but they don't propagate the carries enough. This comes from the fact that even and odd hex digits are "aligned" so there are at least 4 bits that are identical at each position. Ideally : X|Y=1 for each bit position.

    One way to solve this is to offset the digits by one position : X=0xBCDE and Y=0x4567

    This is slightly better:

    >>> hex( 0xABCD | 0x4567 )
    '0xefef'
    >>> hex( 0xBCDE | 0x4567 )
    '0xfdff'

    Time to update all the other references...

  • a POSIXy rand()

    Yann Guidon / YGDES02/07/2025 at 18:09 0 comments

    After the last log, here's a first draft of a POSIX-compliant PRNG to replace the dumb congruential generator. The combined period should exceed 2^64 yet no heavy operation (like multiplies or moduli) are used. Of course I should test the quality of the output...

    #include <stdint.h>
    
    #define RAND_MAX 32767
    
    /* From the spec: If rand() is called before any calls
       to srand() are made, the same sequence shall
       be generated as when srand() is first called
       with a seed value of 1. */
    uint32_t rand_LFSR    =  1,
             rand_PEAC_XC =  1;
    uint16_t rand_PEAC_Y  =  0;
    
    void srand(unsigned seed) {
      if (seed) rand_LFSR = seed;
          else  rand_LFSR = 0x89ABCDEFUL;
      rand_PEAC_XC  =  seed;
      rand_PEAC_Y   = ~seed & 1;
    }
    
    int rand(void) {
      // LFSR PRNG :
      uint32_t t = rand_LFSR & 1;
      rand_LFSR >>= 1;
      if (t)
        rand_LFSR ^= 0x82608EDB; // CRC32 poly
    
      // PEAC scrambler :
      uint16_t rand_X = rand_PEAC_XC; // 16 LSB
      rand_PEAC_XC = (rand_PEAC_XC >> 16)
                   + rand_X + rand_PEAC_Y;
      rand_PEAC_Y  = rand_X + rand_LFSR; // 16 LSB
    
      return rand_PEAC_XC & RAND_MAX;
    }

    Let's see how far this one flies.

    The first compile and run go smoothly:

    [yg@ygrand]$ gcc -Wall -Os -o test_ygrand test_ygrand.c  && ./test_ygrand 
    0000000000000001
    0000111011011101
    0101100010010100
    0100110001001101
    0110000110011000
    0000110001000000
    0000111111001111
    0110110100001010
    0110001101111111
    0100001111011101
    0001111011001111
    0001111001100110
    0101000000111101
    0011010111111011
    0010100111100101
    0111000110110111
    0110010010000111
    0000000011101101
    0011101011001100
    0010000000101001
    0100110100101110
    0110011001110011
    ...
    

    The PRNG is not even initialised, only using the default value of 1, and it immediately reached a high scrambling state. Calling srand() is a must though, and should call rand() a few times itself for "better results".

    Initialising with srand(0) also gives a good-looking sequence with the help of some extra calls to rand().

    The Hamming distance between consecutive numbers looks good after 10000000000 iterations. Note that slot 16 is cleared because only 15 bits are provided at each step.

      0 : 305938
      1 : 4575646
      2 : 32047057
      3 : 138854426
      4 : 416575520
      5 : 916453074
      6 : 1527396508
      7 : 1963876973
      8 : 1963793753
      9 : 1527393214
     10 : 916423856
     11 : 416545995
     12 : 138835287
     13 : 32036947
     14 : 4580472
     15 : 305334
     16 : 0
    

    The peak is well centered around slots 7 and 8, the histogram is nicely symmetrical.

    For comparison, I made a "fake PRNG" that pulls data out of /dev/random and here is the histogram:

      0 : 305586d
      1 : 4579839d
      2 : 32047565d
      3 : 138857968d
      4 : 416545970d
      5 : 916470025d
      6 : 1527349897d
      7 : 1963799989d
      8 : 1963842436d
      9 : 1527391622d
     10 : 916495473d
     11 : 416539621d
     12 : 138850583d
     13 : 32042754d
     14 : 4575830d
     15 : 304842d
     16 : 0d

    It's pretty spot on but that's only one of many aspects to check.

    ___________________________________________________

    Update : I fixed the init values so it matches srand(1) after 3 calls to rand().

    uint32_t rand_LFSR    =  0x61A864DB,
             rand_PEAC_XC =  0x00015894;
    uint16_t rand_PEAC_Y  =  0xF3B8;

    I've put the files there  ygrand.tgz

  • a rand()... or so.

    Yann Guidon / YGDES02/03/2025 at 15:11 0 comments

    I have recently received inquiries from two projects :

    • Defora (anything at this point is better than this)
    • TrapC (in need of a good library/implementation)

    Both are interested by a new/better implementation of the rand() function and it would be beneficial to merge these two requests.

    First, I need a good definition of the requirements : size of the state, width of the registers... I'll first try a typical version with two variables, not much larger than the historic implementation (congruential generators have only one register). I suppose that the variable seed must be adapted...

    Already, a limitation : POSIX defines rand() as returning an int limited by RAND_MAX>=32767

    The <stdlib.h> header shall define the following macros which shall expand
     to integer constant expressions:
    {RAND_MAX}
        Maximum value returned by rand(); at least 32767.

    On my local installation, /usr/include/stdlib.h says

    /* The largest number rand will return (same as INT_MAX).  */
    #define RAND_MAX        2147483647

    (Note: yet another reason that POSIX IS DEAD ! You CAN'T know your local size until you test the system, instead of being sure to have a certain width that lets you program comfortably everywhere).
     .
    Now, the recent libc has more than one function :

    void          srand(unsigned);
    void          srand48(long);
    void          srandom(unsigned);
    ....
    int           rand(void);
    int           rand_r(unsigned *);
    long          jrand48(unsigned short [3]);
    long          lrand48(void);
    long          mrand48(void);
    long          nrand48(unsigned short [3]);
    long          random(void);
    double        drand48(void);
    double        erand48(unsigned short [3]);
    

    So it's a whole crazy mess... and https://pubs.opengroup.org/onlinepubs/9699919799/functions/srand.html adds more mess. But who uses it anyway ?

    For TrapC,

    We need

    • a crypto random for crypto stuff,
    • a streaming random for telecom stuff,
    • a repeatable random for scientific stuff,
    • and a good checksum hash that isn't random for hash tables...
         crypto_random_t cr;// for casino real-money gaming
         packet_random_t sr;// for encrypted streaming transmission
         pseudo_random_t rr("test 1");// for repeatable A/B testing
         hash32_t h32("hello world");
         hash64_t h64("hello world");

    And constructors to automatically do the right thing to seed generators. An application programmer doesn't need to know how they work to use them.

    .

    Let's go back to POSIX.

  • Checksum w16 on 6309

    Yann Guidon / YGDES02/02/2025 at 01:02 0 comments

    My friend François designed a SBC sporting a Hitachi 6309E, a faster and extended version of the venerable Motorola 6809. Looking at its instruction set table, I find that it has instructions that handle 16 bits at once on the D register (made of the A and B byte accumulators). This is actually pretty suitable for a PEAC16×2 algorithm, which is way better than the xorsum currently used...

    But François said :

    • the program must use the LEAST number of bytes
    • the checksum is reduced down to one byte
    • the scanning range can be from one to 2^16 bytes.

    PEAC16×2 works with pairs of bytes so the eventual extra odd byte must be handled separately at the end. And there is no notion of alignment, but the 6809 is a Big Endian machine. Since the constraint is placed on the code size and not the speed, the algorithm loop would work on individual bytes, not 16-bit words.

    At first look, the algorithm is more complex and larger than xorsum but a first enhancement would replace the xor with add, and reuse the carry: this is not foolproof but requires very little effort to implement.

    Replacing xor8 with adc8 divides the error rate by two :

    .

  • PEAC modulo

    Yann Guidon / YGDES11/05/2024 at 13:43 0 comments

    The log 122. Funky modulo has some funny/funky/hackmemesque observations for lower-level implementations, but what about the higher level ?

    It only occured to me today, thinking about gPEAC, that the wraparound of the sum S goes like

    S' = (S / m) + (S % m)

    Not sure how it's going to help with analysing the large-scale behaviour though, it's above my pay grade.

  • Hashing with PEAC39/2

    Yann Guidon / YGDES11/04/2024 at 06:02 0 comments

    Look at the logs
    155. More candidates and 741454
    156. The good numbers
    163. Hash enhancements

    The scan has harvested a very interesting number:

    • m= 2^(39/2)-1 = 741454 = 2×7×211×251 = 10110101000001001110b is known perfect, using 20-bit registers.
    • orbit = 549.754.775.568 = 111111111111111111100000010100000010000 in binary, takes about 8 minutes to scan.
    • offset: o = 0111.11010101.11010101 = 7D5D5h = 513493 = 107×4799

    With these parameters, we get a very effective hash algorithm for text strings, 2 bytes at a time (among others). Aside from the PEAC structure itself and its Fibonacci/Pisano scrambling with the addition,

    • The modulus is conditional and increases the scrambling by seeding avalanche with 8 more bits,
    • The offset is unconditional and increases the avalanche in normal ASCII characters, while also triggering "End Around Carry" much more often than normally with empty input.

    TODO

    • Check common divisors of 741454 | 513493 : none !
    • Check the orbit length of PRNG with offset 513493

    For this, the "scanner" must be modified to add the offset, which creates all kinds of ... hmmm algorithmic questions. Fortunately there are two ways to design a checksum with PEAC : single-carry or dual-carry. Single-carry is less parallel but uses a bit fewer operations. It's easy to adapt with the binary PEAC but I realise it's the first time I do this operation on a gPEAC: it's my first gPEAC checksum.

    .

    .

  • PEAC w64 checksum : x86-64 edition

    Yann Guidon / YGDES10/18/2024 at 01:25 2 comments

    I did it !

    The fastest checksum (128 bits per loop) that is also solid (unlike Fletcher/Adler etc.)

    Here is the C source code:

    #include <stdint.h>
    
    #define PEAC64_INIT1 (0x7777777777777777ULL)
    #define PEAC64_INIT2 (0xDDDDDDDDDDDDDDDDULL)
    
    void w64_checksum_asm(
        uint64_t *buffer,
        uint64_t *r,
        uint64_t *s,
        uint64_t WordPairs) {
    
      uint64_t
        X=WordPairs,
        Y=PEAC64_INIT2,
        I=PEAC64_INIT1;
    
      asm volatile("\n\t"
    "  addq %[I], %[X]                \n\t" //  X += I;
    "  clc                            \n\t" //  C = 0;
    "                                 \n\t"
    "  test %[WordPairs],%[WordPairs] \n\t" // WordPairs=0?
    "  jz empty_buffer                \n\t"
    "                                 \n\t"
    "  .p2align 4                     \n\t"
    "innerloop:                       \n\t"
    "    adcq %[X] , %[Y]             \n\t" // Y += X
    "    adcq (%[buffer]), %[X]       \n\t" // X += *buffer
    "                                 \n\t"
    "    adcq %[Y], %[X]              \n\t" // X += Y
    "    adcq 8(%[buffer]), %[Y]      \n\t" // Y += buffer[1]
    "                                 \n\t"
    "    lea 16(%[buffer]), %[buffer] \n\t" // buffer+=2
    "    decq %[WordPairs]            \n\t" // WordPairs--
    "    jnz innerloop                \n\t" // while (WordPairs);
    "                                 \n\t"
    "empty_buffer:                    \n\t"
    "  adcq %[X], %[Y]                \n\t" // Y += X
    "  adcq %[I], %[X]                \n\t" // X += PEAC64_INIT1
    : // outputs
      [X] "+r" (X), [Y] "+r" (Y),
      [WordPairs] "+r" (WordPairs),
      [buffer]  "+r" (buffer)
    : // inputs
      [I] "r" (I)
    : // clobber
      "cc" );
    
      *s = X;
      *r = Y;
    } 

    And gcc -O3 -S compiles it down to:

    w64_checksum_asm:
      movabsq $-2459565876494606883, %rax
      movq    %rcx, %r9
      movabsq $8608480567731124087, %r8
      addq %r8, %rcx
      clc
      test %r9,%r9
      jz empty_buffer
      .p2align 4
    innerloop:
        adcq %rcx , %rax
        adcq (%rdi), %rcx
        adcq %rax, %rcx
        adcq 8(%rdi), %rax
        lea 16(%rdi), %rdi
        decq %r9
        jnz innerloop
    empty_buffer:
      adcq %rcx, %rax
      adcq %r8, %rcx
      movq    %rcx, (%rdx)
      movq    %rax, (%rsi)
      ret

    That's it !

    With this, you get a 128-bit signature of a memory block, which can be filled with read(2) for example. It is hard to do significantly better now, because the memory becomes the bottleneck.

    One last trick is the use of ADCX and ADOX opcodes, to implement a separate carry structure and break the 4-instruction carry chain into two halves. But it won't work because decq affects the overflow flag.

    Now I have to check the primary orbit of w64...

  • TODO: scans

    Yann Guidon / YGDES10/17/2024 at 16:48 0 comments

    Things have progressed again and a new branch of the PEAC family has appeared, tuned for SW implementations where the masking operation is simply skipped. This completely changes the mathematics of the system.

    Below are 2 examples with w26 and w31 which are "extended" (hence the "+") by not masking the sum after the addition.

    w26 is known to be "perfect" but w31 does not pass the sieve.

    However messing with the MSB(s) changes the rules and everything has to be reconsidered now. The difficulty is that the 32-bit words require immense amounts of computations and the others (based on 64-bit registers) are even worse.

    So a thorough computation exploration is required for

    • w26+
    • w31 (not holding my breath)
    • w31+
    • w63 (passes sieve)
    • w63+
    • w64

    At least a first estimate of computability of the primary orbit.

    Furthermore, another class of gPEAC needs to be evaluated: the 1.5× types, called "pseudo-binary", for use in Line Scramblers (see the previous logs such as 167. Line encoding with PEAC: it's alive) : the 2 MSB of the modulo are 1 and the rest is 0. These are powers of 2 multiplied by 3, so the subtraction only requires processing a few MSB and not the whole word. At least a few of these numbers should be in the list of the moduli I had scanned last year. I have found 3 only...

    a=3 ; for i in $(seq 40); do a=$(($a*2)); echo $a; done
    6 : perfect
    12 : 10P
    24 : maximal
    48 : maximal
    96 : maximal
    192 : 191M 186P
    384 : 380M, 378P, 374P
    768 : 763M, 761M, 754P, 750P, 746P (w8)
    1536 : 1528M, 1526P, 1516M, 1511M, 1504M, 1501M, 1498P
    3072 : 3060M, 3038P, 3036M, 3018P
    6144 : 6128M, 6118P, 6106P
    12288 : 12280M, 12254P
    24576 : 24563M, 24551M, 24549M, 24546P
    49152 : 49050, 49084, 49094, 49128
    98304  : 98300, 98298, 98285 98264 98254
    196608 : 196605M 196598P 196594P          (w16)
    393216 : 393208M 393195M 393186P 
    786432 : 786418P  786403M 786388M 786390P 786391M
    1572864
    3145728
    6291456
    12582912
    25165824
    50331648
    100663296
    201326592
    402653184
    805306368
    1610612736
    3221225472
    6442450944
    12884901888
    25769803776
    51539607552
    103079215104
    206158430208
    412316860416
    824633720832
    1649267441664
    3298534883328
    ...
    

    ...

    Stay tuned.

  • PEACLS error detection (and correction?)

    Yann Guidon / YGDES10/13/2024 at 17:49 4 comments

    I added error detection, it was in fact very simple and it seems to work very well.

    I started playing with it, for example adding one bit of noise on the channel (in bold, scroll the listing).

    Init=1 In=0000000000000000 Scr:10-0000000000000000 Sc2:10-0000000000000000  Out=0000000000000000 OK=U  
    Init=0 In=0000000000000000 Scr:00-0000000000000001 Sc2:00-0000001000000001  Out=0000001000000000 OK=1  
    Init=0 In=0000000000000000 Scr:00-0000000000000001 Sc2:00-0000000000000001  Out=0000000000000000 OK=1  
    Init=0 In=0000000000000000 Scr:00-0000000000000010 Sc2:00-0000000000000010  Out=1111111000000000 OK=0
    Init=0 In=0000000000000000 Scr:00-0000000000000011 Sc2:00-0000000000000011  Out=1111110111111111 OK=0
    Init=0 In=0000000000000000 Scr:00-0000000000000101 Sc2:00-0000000000000101  Out=1111110111111111 OK=0
    Init=0 In=0000000000000000 Scr:00-0000000000001000 Sc2:00-0000000000001000  Out=1111110111111111 OK=0  
    Init=0 In=0000000000000000 Scr:00-0000000000001101 Sc2:00-0000000000001101  Out=1111110111111111 OK=0
    Init=0 In=0000000000000000 Scr:00-0000000000010101 Sc2:00-0000000000010101  Out=1111110111111111 OK=0
    Init=0 In=0000000000000000 Scr:00-0000000000100010 Sc2:00-0000000000100010  Out=1111110111111111 OK=0

    The error is not detected immediately but the OK flag is consistently stuck to 0 afterwards.

    What this means is : the epilogue of a packet should have 2 padding words to ensure the last data word has been correctly transmitted.

    Another interesting aspect is the efficiency of the 2 prefix bits : even though they are not flipped during transmission, the reconstructed bits mismatch anyway ! So it does not matter so much that the prefix does not use the whole coding range, error detection occurs anyway and the carries help prevent all-0 words.

    Even more interesting is the bit pattern of the altered reconstructed word: after 3 words, the output contains the inverse of the alteration ! Is this an opportunity for error correction ?

    Further wiggling shows that it's a corner case, but finishing the packet with 2 blank words certainly detects multiple errors. Get the source code here.

View all 178 project logs

Enjoy this project?

Share

Discussions

Yann Guidon / YGDES wrote 09/21/2022 at 17:14 point

https://www.youtube.com/watch?v=EWgts6EiJA0 has some relevant ideas here and there :-)

  Are you sure? yes | no

Yann Guidon / YGDES wrote 07/28/2022 at 16:03 point

TODO : check the distribution and periodicity of each rank of bit to show they don't exhibit the flaws of https://en.wikipedia.org/wiki/Linear_congruential_generator#m_a_power_of_2,_c_=_0

  Are you sure? yes | no

Yann Guidon / YGDES wrote 04/08/2022 at 11:41 point

https://en.wikipedia.org/wiki/Cyclic_code

It seems that PEAC is a cyclic code (in a loose way because it's not using Galois fields but still interesting)

  Are you sure? yes | no

Ezra Wolf wrote 01/21/2022 at 23:18 point

Wow !

  Are you sure? yes | no

Yann Guidon / YGDES wrote 01/26/2022 at 05:27 point

Hi Ezra, feel free to elaborate :-)

  Are you sure? yes | no

Yann Guidon / YGDES wrote 01/17/2022 at 08:49 point

Correction to some of my statements here and there (and my videos) : φ is not transcendental but an irrational number that is a solution to the quadratic equation x² − x − 1 = 0. Mea culpa, but at least I learned something from one of the Bogdanoff brothers' countless errors and confusions :-D

  Are you sure? yes | no

Yann Guidon / YGDES wrote 01/14/2022 at 16:55 point

Oh my !

https://en.wikichip.org/wiki/x86/adx

Now, THAT's a hack :-)

And I can see how it could increase the speed of some algorithms, even this one...

  Are you sure? yes | no

Tim wrote 01/14/2022 at 19:44 point

On ever other architecture, yes. On x86 is does not add notably to the entropy :)

  Are you sure? yes | no

Yann Guidon / YGDES wrote 01/15/2022 at 12:04 point

  Are you sure? yes | no

Yann Guidon / YGDES wrote 10/23/2021 at 21:33 point

Interesting !

https://research.nccgroup.com/2021/10/15/cracking-random-number-generators-using-machine-learning-part-1-xorshift128/

https://research.nccgroup.com/2021/10/18/cracking-random-number-generators-using-machine-learning-part-2-mersenne-twister/

  Are you sure? yes | no

[deleted]

[this comment has been deleted]

Yann Guidon / YGDES wrote 10/13/2021 at 14:39 point

so far, half a year and 50£.

  Are you sure? yes | no

Yann Guidon / YGDES wrote 09/14/2021 at 04:16 point

George Marsaglia and Arif Zaman got quite a lot figured out in 1991:
https://projecteuclid.org/download/pdf_1/euclid.aoap/1177005878

Why didn't this catch up, but they focus on extremely large sequences with tens of registers of lag, and didn't look enough at just a pair of registers. They also didn't look at the link with checksums.

  Are you sure? yes | no

Yann Guidon / YGDES wrote 09/08/2021 at 07:28 point

Funny !

https://en.wikipedia.org/wiki/Lagged_Fibonacci_generator

Toward a universal random number generator, G.Marsaglia, A.Zaman

  Are you sure? yes | no

Yann Guidon / YGDES wrote 08/05/2021 at 23:24 point

https://www.researchgate.net/profile/Michael_Greenwald/publication/3334567_Performance_of_checksums_and_CRCs_over_real_data/links/53f4b15f0cf2888a749113c5/Performance-of-checksums-and-CRCs-over-real-data.pdf

"In practice, TCP trailer sums outperform even Fletcher header sums."

Ouch.

  Are you sure? yes | no

Yann Guidon / YGDES wrote 08/08/2021 at 00:51 point

"Ones complement (with EAC) Fletcher, however, has a weakness that sometimes offsets its probabilistic advantage: since bytes containing either 255 or 0 are considered identical by the checksum, certain common pathological cases cause total failure of Fletcher-255."

Re-ouch.

  Are you sure? yes | no

Yann Guidon / YGDES wrote 08/05/2021 at 23:09 point

http://users-tima.imag.fr/cdsi/guyot/Cours/Oparithm/english/Modulo.htm and others say that special adders exist to compute mod 2^n-1.

But this is not necessary because the carry is explicitly integrated in the next cycle.

  Are you sure? yes | no

Yann Guidon / YGDES wrote 08/05/2021 at 22:20 point

https://www.cs.auckland.ac.nz/compsci314s1t/resources/Checksums.pdf  is a nice beginner-level overview of error detection basics. Polynomial checks are mentioned, as well as 1s complement / end-around-carry and Fletcher is well explained but no sight of Fibonacci.

  Are you sure? yes | no

Yann Guidon / YGDES wrote 05/24/2021 at 03:52 point

Oh, nice !

https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html#Integer-Overflow-Builtins

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates