Rabbit Cipher - Module

Applications, Games, Tools, User libs and useful stuff coded in PureBasic
User avatar
StarBootics
Addict
Addict
Posts: 984
Joined: Sun Jul 07, 2013 11:35 am
Location: Canada

Rabbit Cipher - Module

Post by StarBootics »

Hello everyone,

I know some of you are not fans of own implementation of cipher algorithm. So the following code is not for you then, so leave it.

For the others this is something fun to play with.

In the example I'm using the MD5 StringFingerprint() for the key and the InitVector and this is not recommended at all especially for the InitVector.
Maybe creating a CryptRandom() sets of values put into a DataSection will be better for security reasons.

As long as the key is 128 bits and the InitVector is 64 bits in length almost anything is possible to do.

EDIT 1 : This is the 3rd version of the example and this time the code is really safe to use and conform to the RFC 4503 Rabbit Encryption of May 2006 or at least conform to the Appendix B of the document. Sorry for the inconvenience of me posting a not so verified source code at the beginning. The example at the end of the code show how to store keys and Init Vectors into Data Section.

EDIT 2 : Code updated to version 4 due to some issue caused by the PeekL()/PokeL() plus other issues pointed out by Wilbert
EDIT 3 : Code updated to version 4.0.1 for Speed improvement with the Addition() procedure.

THE CODE IS NOW CONSIDERED SAFE TO USE



Best regards
StarBootics

Code: Select all

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Project Name : Rabbit Cipher
; File Name : RabbitCipher - Module.pb
; File Version : 4.0.1
; Programmation : OK
; Programmed by : StarBootics
; Creation Date : October 30th, 2020
; Last update : November 8th, 2020
; Coded for PureBasic : V5.73 Beta 2
; Platform : Windows, Linux, MacOS X
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Programming notes
;
; 1. Rabbit was designed by Martin Boesgaard, Mette Vesterager,
;    Thomas Pedersen, Jesper Christiansen and Ove Scavenius.
;
;    https://www.ecrypt.eu.org/stream/rabbitpf.html
;
; 2. Type of Algorithm : Synchronous Stream Cipher
;
; 3. Rabbit has been released into the public domain and may
;    be used freely for any purpose.
;
; 4. I deserve credit only for porting Rabbit Cipher from C to
;    PureBasic. I'm not the original designer of the algorithm
;    so no credit to me for that.
;
; 5. The software is provided "as is" without any express or
;    implied warranty. You are using it at your own risk. The
;    original authors and/or me shall not in any way be liable
;    for any use of this software.
;
; 6. Is this encryption system compatible with the RFC 4503 
;    Rabbit Encryption of May 2006 ?
;
;    The Answer is YES ! 
;
; 7. Special thanks to Wilbert for the simplification of the
;    G function procedure and other issues.
;
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

DeclareModule RabbitCipher
  
  Declare.s Normalizer(Input.s, BitsLength.l)
  Declare Encrypt(*Key, *InitVector, *PlainText, *CipheredText, StringByteLength.l)
  Declare Decrypt(*Key, *InitVector, *PlainText, *CipheredText, StringByteLength.l)
  
EndDeclareModule

Module RabbitCipher
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Structures declaration <<<<<
  
  Structure Rabbit
    
    X.q[8]
    C.q[8]
    Carry.q
    
  EndStructure
  
  Structure Rabbit_Temp
    
    g.q[8]
    OldC.q[8]
    
  EndStructure
  
  Structure Buffer
    
    Buffer.a[16]
    
  EndStructure
  
  Structure Core
    
    Master.Rabbit
    Work.Rabbit
    
  EndStructure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Macros declaration <<<<<
  
  Macro U32V(v)
    
    ((v) & $FFFFFFFF)
    
  EndMacro
  
  Macro ROTL32(v, n)
    
    ((U32V((v) << (n)) | ((v) >> (32 - (n)))))
    
  EndMacro
  
  Macro SWAP32(v)
    
    ((ROTL32((v), 8) & $00FF00FF) | (ROTL32((v), 24) & $FF00FF00))
    
  EndMacro
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Procedures declaration (Private) <<<<<
  
  Procedure.q PeekU32(*Buffer)
    
    ; Even if a quad size is 64-bit, we are
    ; interested only by the first 32-bit.
    
    CopyMemory(*Buffer, @Var.q, 4)
    
    ProcedureReturn Var
  EndProcedure
  
  Procedure PokeU32(*Buffer, Var.q)
    
    ; Even if a quad size is 64-bit, we are
    ; interested only by the first 32-bit.
    
    CopyMemory(@Var, *Buffer, 4)
    
  EndProcedure
  
  Procedure.q U8TO32_LITTLE(*p)
    
    B0.a = PeekA(*p+0)
    B1.a = PeekA(*p+1)
    B2.a = PeekA(*p+2)
    B3.a = PeekA(*p+3)
    
    ProcedureReturn U32V(B0 | B1 << 8 | B2 << 16 | B3 << 24)
  EndProcedure
  
  Procedure.q RABBIT_GFunc(x.q)
    
    x * x
    
    ProcedureReturn U32V(x ! (x >> 32))
  EndProcedure

  Procedure.q Addition(VarA.q, VarB.q, VarC.q = -1)
    
    Result.q = U32V(VarA + VarB)
    
    If VarC >= 0
      Result = U32V(Result + VarC)
    EndIf
    
    ProcedureReturn Result
  EndProcedure

  Procedure RABBIT_NextState(*Rabbit.Rabbit)
    
    ; Temporary variables
    Protected Temp.Rabbit_Temp, Index.l
    
    ; Save old counter values
    For Index = 0 To 7
      Temp\OldC[Index] = *Rabbit\C[Index]
    Next
    
    ; Calculate new counter values
    
    *Rabbit\C[0] = Addition(*Rabbit\C[0], $4D34D34D + *Rabbit\Carry)
    *Rabbit\C[1] = Addition(*Rabbit\C[1], $D34D34D3 + Bool(*Rabbit\C[0] < Temp\OldC[0]))
    *Rabbit\C[2] = Addition(*Rabbit\C[2], $34D34D34 + Bool(*Rabbit\C[1] < Temp\OldC[1]))
    *Rabbit\C[3] = Addition(*Rabbit\C[3], $4D34D34D + Bool(*Rabbit\C[2] < Temp\OldC[2]))
    *Rabbit\C[4] = Addition(*Rabbit\C[4], $D34D34D3 + Bool(*Rabbit\C[3] < Temp\OldC[3]))
    *Rabbit\C[5] = Addition(*Rabbit\C[5], $34D34D34 + Bool(*Rabbit\C[4] < Temp\OldC[4]))
    *Rabbit\C[6] = Addition(*Rabbit\C[6], $4D34D34D + Bool(*Rabbit\C[5] < Temp\OldC[5]))
    *Rabbit\C[7] = Addition(*Rabbit\C[7], $D34D34D3 + Bool(*Rabbit\C[6] < Temp\OldC[6]))
    *Rabbit\Carry = Bool(*Rabbit\C[7] < Temp\OldC[7])

    ; Calculate the g-values
    For Index = 0 To 7
      Temp\g[Index] = RABBIT_GFunc(Addition(*Rabbit\X[Index], *Rabbit\C[Index]))
    Next
    
    ; Calculate new state values
    For Index = 0 To 7
      If Index & 1 = 0
        *Rabbit\X[Index] = Addition(Temp\g[Index], ROTL32(Temp\g[(Index + 7) & 7],16), ROTL32(Temp\g[(Index + 6) & 7], 16))
      Else
        *Rabbit\X[Index] = Addition(Temp\g[Index], ROTL32(Temp\g[(Index + 7) & 7], 8), Temp\g[(Index + 6) & 7]) 
      EndIf 
    Next
    
  EndProcedure
  
  Procedure RABBIT_KeySetup(*Core.Core, *Key)
    
    ; Temporary Variables
    Protected k0.q, k1.q, k2.q, k3.q, Index.l
    
    ; Generate four subkeys
    k0 = U8TO32_LITTLE(*Key + 0)
    k1 = U8TO32_LITTLE(*Key + 4)
    k2 = U8TO32_LITTLE(*Key + 8)
    k3 = U8TO32_LITTLE(*Key + 12)
    
    ; Generate initial state variables
    *Core\Master\X[0] = k0
    *Core\Master\X[2] = k1
    *Core\Master\X[4] = k2
    *Core\Master\X[6] = k3
    *Core\Master\X[1] = U32V(k3 << 16) | (k2 >> 16)
    *Core\Master\X[3] = U32V(k0 << 16) | (k3 >> 16)
    *Core\Master\X[5] = U32V(k1 << 16) | (k0 >> 16)
    *Core\Master\X[7] = U32V(k2 << 16) | (k1 >> 16)
    
    ; Generate initial counter values
    *Core\Master\C[0] = ROTL32(k2, 16)
    *Core\Master\C[2] = ROTL32(k3, 16)
    *Core\Master\C[4] = ROTL32(k0, 16)
    *Core\Master\C[6] = ROTL32(k1, 16)
    
    *Core\Master\C[1] = (k0 & $FFFF0000) | (k1 & $FFFF)
    *Core\Master\C[3] = (k1 & $FFFF0000) | (k2 & $FFFF)
    *Core\Master\C[5] = (k2 & $FFFF0000) | (k3 & $FFFF)
    *Core\Master\C[7] = (k3 & $FFFF0000) | (k0 & $FFFF)
    
    *Core\Master\Carry = 0

    For Index = 0 To 3
      RABBIT_NextState(*Core\Master)
    Next
    
    ; Modify the counters
    For Index = 0 To 7
      *Core\Master\C[Index] ! *Core\Master\X[(Index + 4) & 7]
    Next
    
    ; Copy master instance to work instance
    
    For Index = 0 To 7
      *Core\Work\X[Index] = *Core\Master\X[Index]
      *Core\Work\C[Index] = *Core\Master\C[Index]
    Next
    
    *Core\Work\Carry = *Core\Master\Carry
    
  EndProcedure
  
  Procedure RABBIT_InitVectorSetup(*Core.Core, *InitVector)
    
    ; Temporary variables
    Protected i0.q, i1.q, i2.q, i3.q, Index.l
    
    ; Generate four subvectors
    i0 = U8TO32_LITTLE(*InitVector + 0)
    i2 = U8TO32_LITTLE(*InitVector + 4)
    i1 = (i0 >> 16) | (i2 & $FFFF0000)
    i3 = (i2 << 16) | (i0 & $0000FFFF)
    
    ; Modify counter values
    
    *Core\Work\C[0] = *Core\Master\C[0] ! i0
    *Core\Work\C[1] = *Core\Master\C[1] ! i1
    *Core\Work\C[2] = *Core\Master\C[2] ! i2
    *Core\Work\C[3] = *Core\Master\C[3] ! i3
    
    *Core\Work\C[4] = *Core\Master\C[4] ! i0
    *Core\Work\C[5] = *Core\Master\C[5] ! i1
    *Core\Work\C[6] = *Core\Master\C[6] ! i2
    *Core\Work\C[7] = *Core\Master\C[7] ! i3
    
    ; Copy state variables
    
    For Index = 0 To 7
      *Core\Work\X[Index] = *Core\Master\X[Index]
    Next
    
    *Core\Work\Carry = *Core\Master\Carry
    
    ; Iterate the system four times
    
    For index = 0 To 3
      RABBIT_NextState(*Core\Work)
    Next
    
  EndProcedure
  
  Procedure RABBIT_Process_Bytes(*Core.Core, *Input, *Output, MsgLen.l)
    
    ; Temporary variables
    
    Protected Buffer.Buffer, Index.l
    
    ; Encrypt/decrypt all full blocks
    
    While MsgLen >= 16
      
      ; Iterate the system
      RABBIT_NextState(*Core\Work)
      
      ; Encrypt/decrypt 16 bytes of data
      PokeU32(*Output + 00, PeekU32(*Input + 00) ! *Core\Work\X[0] ! (*Core\Work\X[5] >> 16) ! U32V(*Core\Work\X[3] << 16))
      PokeU32(*Output + 04, PeekU32(*Input + 04) ! *Core\Work\X[2] ! (*Core\Work\X[7] >> 16) ! U32V(*Core\Work\X[5] << 16))
      PokeU32(*Output + 08, PeekU32(*Input + 08) ! *Core\Work\X[4] ! (*Core\Work\X[1] >> 16) ! U32V(*Core\Work\X[7] << 16))
      PokeU32(*Output + 12, PeekU32(*Input + 12) ! *Core\Work\X[6] ! (*Core\Work\X[3] >> 16) ! U32V(*Core\Work\X[1] << 16))
      
      *Input + 16
      *Output + 16
      MsgLen - 16
      
    Wend
    
    ; Encrypt/decrypt remaining data
    
    If MsgLen <> 0
      
      ; Iterate the system
      RABBIT_NextState(*Core\Work)
      
      ; Generate 16 bytes of pseudo-random data */
      
      PokeU32(@Buffer + 00, *Core\Work\X[0] ! (*Core\Work\X[5]>>16) ! U32V(*Core\Work\X[3]<<16))
      PokeU32(@Buffer + 04, *Core\Work\X[2] ! (*Core\Work\X[7]>>16) ! U32V(*Core\Work\X[5]<<16))
      PokeU32(@Buffer + 06, *Core\Work\X[4] ! (*Core\Work\X[1]>>16) ! U32V(*Core\Work\X[7]<<16))
      PokeU32(@Buffer + 12, *Core\Work\X[6] ! (*Core\Work\X[3]>>16) ! U32V(*Core\Work\X[1]<<16))
      
      For Index = 0 To MsgLen - 1
        PokeA(*Output, PeekA(*Input) ! Buffer\Buffer[Index])
        *Output + 1
        *Input + 1
      Next
      
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Procedures declaration (Public) <<<<<
  
  Procedure.s Normalizer(Input.s, BitsLength.l)
    
    Bytes.l = BitsLength >> 3
    Output.s = StringFingerprint(Input, #PB_Cipher_MD5)
    
    While StringByteLength(Output) < Bytes
      Output + StringFingerprint(Output, #PB_Cipher_MD5)
    Wend
    
    ProcedureReturn Left(Output, Bytes / SizeOf(Unicode))
  EndProcedure
  
  Procedure Encrypt(*Key, *InitVector, *PlainText, *CipheredText, StringByteLength.l)
    
    RABBIT_KeySetup(Core.Core, *Key)
    
    If *InitVector <> #Null
      RABBIT_InitVectorSetup(Core, *InitVector)
    EndIf
    
    RABBIT_Process_Bytes(Core, *PlainText, *CipheredText, StringByteLength)
    
  EndProcedure
  
  Procedure Decrypt(*Key, *InitVector, *PlainText, *CipheredText, StringByteLength.l)
    
    RABBIT_KeySetup(Core.Core, *Key)
    
    If *InitVector <> #Null
      RABBIT_InitVectorSetup(Core, *InitVector)
    EndIf
    
    RABBIT_Process_Bytes(Core, *CipheredText, *PlainText, StringByteLength)
    
  EndProcedure
  
EndModule

CompilerIf #PB_Compiler_IsMainFile
  
  UseMD5Fingerprint()

  String.s = "Hello, this is a test for Rabbit Cipher !"
  
  Key.s = RabbitCipher::Normalizer("I'm the key !", 128)
  InitVector.s = RabbitCipher::Normalizer("I'm the InitVector !", 64)
  
  StringMemorySize = StringByteLength(String) + SizeOf(Character)
  
  *CipheredText = AllocateMemory(StringMemorySize)
  *CipheredText2 = AllocateMemory(StringMemorySize)
  *PlainText = AllocateMemory(StringMemorySize)
  *PlainText2 = AllocateMemory(StringMemorySize)
  
  RabbitCipher::Encrypt(@Key, @InitVector, @String, *CipheredText, StringByteLength(String))
  RabbitCipher::Encrypt(@Key, #Null, @String, *CipheredText2, StringByteLength(String))
  
  RabbitCipher::Decrypt(@Key, @InitVector, *PlainText, *CipheredText, StringByteLength(String))
  RabbitCipher::Decrypt(@Key, #Null, *PlainText2, *CipheredText2, StringByteLength(String))
  
  PlainText.s = PeekS(*PlainText)
  PlainText2.s = PeekS(*PlainText2)
  
  Debug "Test Real life : Key setup, IV setup and encryption/decryption"
  If String = PlainText
    Debug "Success"
  Else
    Debug "Failure"
  EndIf
  
  Debug "Test Real life : Key setup and encryption/decryption"
  If String = PlainText2
    Debug "Success"
  Else
    Debug "Failure"
  EndIf
  
  FreeMemory(*CipheredText)
  FreeMemory(*CipheredText2)
  FreeMemory(*PlainText)
  FreeMemory(*PlainText2)
  
CompilerEndIf

; <<<<<<<<<<<<<<<<<<<<<<<
; <<<<< END OF FILE <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<
Last edited by StarBootics on Sun Nov 08, 2020 10:11 pm, edited 3 times in total.
The Stone Age did not end due to a shortage of stones !
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Rabbit Cipher - Module

Post by Kwai chang caine »

Works nice here and can be usefull :wink:
Thanks for sharing 8)
ImageThe happiness is a road...
Not a destination
User avatar
StarBootics
Addict
Addict
Posts: 984
Joined: Sun Jul 07, 2013 11:35 am
Location: Canada

Re: Rabbit Cipher - Module

Post by StarBootics »

Hello everyone,

This is the second version of the RabbitCipher module. Now you have a choice between the original 128 bits encrypting (64 bits InitVector) or the experimental 256 bits encrypting (128 bits InitVector). I would have liked to contact one of the authors to validate the 256-bit version but apparently their website is no longer online. I hope that I didn't introduce any weaknesses by expanding the 128 bits version to 256 bits.

@Kwai chang caine : You're welcome !

EDIT 1 : Update to version 2.0.1 : Found a bug inside the RABBIT_KeySetup256() procedure.
EDIT 2 : Update to version 2.0.2 : Not really a bug but in the RABBIT_NextState256() I have change the constants.
EDIT 3 : Update to version 2.0.3 : Removed unnecessary steps in the Encrypt() and Decrypt() procedures
EDIT 4 : Update to version 2.0.4 : Error inside RABBIT_KeySetup256() and RABBIT_InitVectorSetup256() procedures.
EDIT 5 : Code suppression due to very serious issue. A new version will be posted in this topic.

Best regards
StarBootics
Last edited by StarBootics on Thu Nov 05, 2020 10:29 pm, edited 2 times in total.
The Stone Age did not end due to a shortage of stones !
User avatar
Saki
Addict
Addict
Posts: 830
Joined: Sun Apr 05, 2020 11:28 am
Location: Pandora

Re: Rabbit Cipher - Module

Post by Saki »

Nice Code

Best Regards Saki
地球上の平和
User avatar
StarBootics
Addict
Addict
Posts: 984
Joined: Sun Jul 07, 2013 11:35 am
Location: Canada

Re: Rabbit Cipher - Module

Post by StarBootics »

Hello everyone,

SEE THE FIRST POST OF THIS TOPIC

Best regards
StarBootics
Last edited by StarBootics on Thu Nov 05, 2020 10:31 pm, edited 1 time in total.
The Stone Age did not end due to a shortage of stones !
User avatar
NicTheQuick
Addict
Addict
Posts: 1224
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: Rabbit Cipher - Module

Post by NicTheQuick »

Do you have any information about the the implemented algorithm regarding its security?
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
User avatar
Saki
Addict
Addict
Posts: 830
Joined: Sun Apr 05, 2020 11:28 am
Location: Pandora

Re: Rabbit Cipher - Module

Post by Saki »

He does these codes only for the fun of it.
It is certainly not easy to make something like this work.
地球上の平和
User avatar
StarBootics
Addict
Addict
Posts: 984
Joined: Sun Jul 07, 2013 11:35 am
Location: Canada

Re: Rabbit Cipher - Module

Post by StarBootics »

NicTheQuick wrote:Do you have any information about the the implemented algorithm regarding its security?
From Wikipedia :
Security

Rabbit claims 128-bit security against attackers whose target is one specific key. If, however, the attacker targets a large number of keys at once and does not really care which one he breaks, then the small IV size results in a reduced security level of 96 bit. This is due to generic TMD trade-off attacks.[6]

A small bias in the output of Rabbit exists,[7] resulting in a distinguisher with 2^247 complexity discovered by Jean-Philippe Aumasson in December 2006. Even though this distinguisher was improved to 2^158 in 2008,[8] it's not a threat to Rabbit's security because its complexity is significantly higher than the brute-force of the key space (2^128).
So pretty secure when implemented correctly.

Best regards
StarBootics
The Stone Age did not end due to a shortage of stones !
User avatar
Saki
Addict
Addict
Posts: 830
Joined: Sun Apr 05, 2020 11:28 am
Location: Pandora

Re: Rabbit Cipher - Module

Post by Saki »

Because of the way this encryption works, implementation errors are quickly overlooked.
But with other implementations it should be easy to check if everything works correctly.
The security of the key effectively corresponds to a binary key length of 10 bytes.
地球上の平和
User avatar
StarBootics
Addict
Addict
Posts: 984
Joined: Sun Jul 07, 2013 11:35 am
Location: Canada

Re: Rabbit Cipher - Module

Post by StarBootics »

Saki wrote:He does these codes only for the fun of it.
It is certainly not easy to make something like this work.
It would be easy if the original C source code was written according to the documentation. But the main problem we have with PureBasic is the lack of unsigned long integer. Programming this Cipher algorithm is another example why we need unsigned long integer. It's a shame that in 2020 even if PureBasic is a Basic programming language we don't have all standard type available in C or C++.

What I don't understand is the fact that even if the algorithm don't work as it should it's still capable to Encrypt and Decrypt successfully.

Anyway, it's time for me to go to get some sleep.

Best regards
StarBootics
The Stone Age did not end due to a shortage of stones !
User avatar
Tenaja
Addict
Addict
Posts: 1948
Joined: Tue Nov 09, 2010 10:15 pm

Re: Rabbit Cipher - Module

Post by Tenaja »

Maybe you can talk Wilbur into contributing his assembly magic into the routine...
User avatar
StarBootics
Addict
Addict
Posts: 984
Joined: Sun Jul 07, 2013 11:35 am
Location: Canada

Re: Rabbit Cipher - Module

Post by StarBootics »

Hello everyone,

Apparently using the positive part of a Quad seem to have fixed the negative values in the counter system. That being said this implementation must be very close to the standard. This means the pseudo-random system is pretty efficient as it is and can be used relatively safely. What you can't do is to send / receive encrypted data to any one who may use a standard Rabbit cipher.

If someone is willing to try to make correction to this code to match RFC 4503 Rabbit Cipher of May 2006 you might need these documents :
I had the idea to replace the code in my first post but I have change my mind and I'm posting the version 2.0.0 down here so you can see the change I made.

THE CODE DOWN BELOW IS NOT SAFE TO USE I'M KEEPING IT HERE FOR FOLLOWING POSTS REFERENCES

See the first post of this topic for the Working version.

Best regards
StarBootics

Code: Select all

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Project Name : Rabbit Cipher
; File Name : RabbitCipher - Module.pb
; File Version : 2.0.0
; Programmation : OK
; Programmed by : StarBootics
; Creation Date : October 30th, 2020
; Last update : November 3rd, 2020
; Coded for PureBasic : V5.73 Beta 2
; Platform : Windows, Linux, MacOS X
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Programming notes
;
; 1. Rabbit was designed by Martin Boesgaard, Mette Vesterager,
;    Thomas Pedersen, Jesper Christiansen and Ove Scavenius.
;
;    https://www.ecrypt.eu.org/stream/rabbitpf.html
;
; 2. Type of Algorithm : Synchronous Stream Cipher
;
; 3. Rabbit has been released into the public domain and may
;    be used freely for any purpose.
;
; 4. I deserve credit only for porting Rabbit Cipher from C to
;    PureBasic. I'm not the original designer of the algorithm
;    so no credit to me for that.
;
; 5. The software is provided "as is" without any express or
;    implied warranty. You are using it at your own risk. The
;    original authors and/or me shall not in any way be liable
;    for any use of this software.
;
; 6. Is this encryption system compatible with the RFC 4503 
;    Rabbit Encryption of May 2006 ?
;
;    The Answer is NO ! And the reason came from the GFunc 
;    calculation procedure. We need a unsigned 64-bit integer
;    to store a result of the squaring of the x value in some
;    cases.
;
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

DeclareModule RabbitCipher
  
  Declare.s Normalizer(Input.s, BitsLength.l)
  Declare Encrypt(*Key, *InitVector, *PlainText, *CipheredText, StringByteLength.l)
  Declare Decrypt(*Key, *InitVector, *PlainText, *CipheredText, StringByteLength.l)
  
EndDeclareModule

Module RabbitCipher
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Structures declaration <<<<<
  
  Structure Rabbit
    
    X.q[8]
    C.q[8]
    Carry.q
    
  EndStructure
  
  Structure Rabbit_Temp
    
    g.q[8]
    OldC.q[8]
    
  EndStructure
  
  Structure Buffer
    
    Buffer.a[16]
    
  EndStructure
  
  Structure Core
    
    Master.Rabbit
    Work.Rabbit
    
  EndStructure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Macros declaration <<<<<
  
  Macro U32V(v)
    
    ((v) & $FFFFFFFF)
    
  EndMacro
  
  Macro ROTL32(v, n)
    
    ((U32V((v) << (n)) | ((v) >> (32 - (n)))))
    
  EndMacro
  
  Macro SWAP32(v)
    
    ((ROTL32((v), 8) & $00FF00FF) | (ROTL32((v), 24) & $FF00FF00))
    
  EndMacro
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Procedures declaration (Private) <<<<<
  
  Procedure.q U32TO32_LITTLE(v.q)
    
    Temp.q = SWAP32(v)
    
    ProcedureReturn U32V(Temp)
  EndProcedure
  
  Procedure.q U8TO32_LITTLE(*p)
    
    B0.a = PeekA(*p+0)
    B1.a = PeekA(*p+1)
    B2.a = PeekA(*p+2)
    B3.a = PeekA(*p+3)
    
    ProcedureReturn U32V(B0 | B1 << 8 | B2 << 16 | B3 << 24)
  EndProcedure
  
  Procedure.q RABBIT_GFunc(x.q)
    
    ; Temporary variables
    Protected a.q, b.q, h.q, l.q
    
    ; Construct high and low argument for squaring
    
    a = x & $FFFF
    b = x >> 16
    
    ; Calculate high and low result of squaring
    
    h = (((U32V(a*a)>>17) + U32V(a*b))>>15) + b*b
    l = x*x
    
    ; Return high XOR low
    
    ProcedureReturn U32V(h ! l)
  EndProcedure
  
  Procedure RABBIT_NextState(*Rabbit.Rabbit)
    
    ; Temporary variables
    Protected Temp.Rabbit_Temp, Index.l
    
    ; Save old counter values
    For Index = 0 To 7
      Temp\OldC[Index] = *Rabbit\C[Index]
    Next
    
    ; Calculate new counter values
    *Rabbit\C[0] = U32V(*Rabbit\C[0] + $4D34D34D + *Rabbit\Carry)
    *Rabbit\C[1] = U32V(*Rabbit\C[1] + $D34D34D3 + Bool(*Rabbit\C[0] < Temp\OldC[0]))
    *Rabbit\C[2] = U32V(*Rabbit\C[2] + $34D34D34 + Bool(*Rabbit\C[1] < Temp\OldC[1]))
    *Rabbit\C[3] = U32V(*Rabbit\C[3] + $4D34D34D + Bool(*Rabbit\C[2] < Temp\OldC[2]))
  
    *Rabbit\C[4] = U32V(*Rabbit\C[4] + $D34D34D3 + Bool(*Rabbit\C[3] < Temp\OldC[3])) 
    *Rabbit\C[5] = U32V(*Rabbit\C[5] + $34D34D34 + Bool(*Rabbit\C[4] < Temp\OldC[4]))
    *Rabbit\C[6] = U32V(*Rabbit\C[6] + $4D34D34D + Bool(*Rabbit\C[5] < Temp\OldC[5]))
    *Rabbit\C[7] = U32V(*Rabbit\C[7] + $D34D34D3 + Bool(*Rabbit\C[6] < Temp\OldC[6]))
    
    *Rabbit\Carry = Bool(*Rabbit\C[7] < Temp\OldC[7])

    ; Calculate the g-values
    
    For Index = 0 To 7
      Temp\g[Index] = RABBIT_GFunc(*Rabbit\X[Index] + *Rabbit\C[Index])
    Next
    
    ; Calculate new state values
    For Index = 0 To 7
      If Index & 1 = 0
        *Rabbit\X[Index] = U32V(Temp\g[Index] + ROTL32(Temp\g[(Index + 7) & 7],16) + ROTL32(Temp\g[(Index + 6) & 7], 16))
      Else
        *Rabbit\X[Index] = U32V(Temp\g[Index] + ROTL32(Temp\g[(Index + 7) & 7], 8) + Temp\g[(Index + 6) & 7])
      EndIf 
    Next
    
  EndProcedure
  
  Procedure RABBIT_KeySetup(*Core.Core, *Key)
    
    ; Temporary Variables
    Protected k0.q, k1.q, k2.q, k3.q, Index.l
    
    ; Generate four subkeys
    k0 = U8TO32_LITTLE(*Key + 0)
    k1 = U8TO32_LITTLE(*Key + 4)
    k2 = U8TO32_LITTLE(*Key + 8)
    k3 = U8TO32_LITTLE(*Key + 12)
    
    ; Generate initial state variables
    *Core\Master\X[0] = k0
    *Core\Master\X[2] = k1
    *Core\Master\X[4] = k2
    *Core\Master\X[6] = k3
    *Core\Master\X[1] = U32V(k3 << 16) | (k2 >> 16)
    *Core\Master\X[3] = U32V(k0 << 16) | (k3 >> 16)
    *Core\Master\X[5] = U32V(k1 << 16) | (k0 >> 16)
    *Core\Master\X[7] = U32V(k2 << 16) | (k1 >> 16)
    
    ; Generate initial counter values
    *Core\Master\C[0] = ROTL32(k2, 16)
    *Core\Master\C[2] = ROTL32(k3, 16)
    *Core\Master\C[4] = ROTL32(k0, 16)
    *Core\Master\C[6] = ROTL32(k1, 16)
    
    *Core\Master\C[1] = (k0 & $FFFF0000) | (k1 & $FFFF)
    *Core\Master\C[3] = (k1 & $FFFF0000) | (k2 & $FFFF)
    *Core\Master\C[5] = (k2 & $FFFF0000) | (k3 & $FFFF)
    *Core\Master\C[7] = (k3 & $FFFF0000) | (k0 & $FFFF)
   
    *Core\Master\Carry = 0

    For Index = 0 To 3
      RABBIT_NextState(*Core\Master)
    Next
    
    ; Modify the counters
    For Index = 0 To 7
      *Core\Master\C[Index] ! *Core\Master\X[(Index + 4) & 7]
    Next
    
    ; Copy master instance to work instance
    
    For Index = 0 To 7
      *Core\Work\X[Index] = *Core\Master\X[Index]
      *Core\Work\C[Index] = *Core\Master\C[Index]
    Next
    
    *Core\Work\Carry = *Core\Master\Carry
    
  EndProcedure
  
  Procedure RABBIT_InitVectorSetup(*Core.Core, *InitVector)
    
    ; Temporary variables
    Protected i0.q, i1.q, i2.q, i3.q, Index.l
    
    ; Generate four subvectors
    i0 = U8TO32_LITTLE(*InitVector + 0)
    i2 = U8TO32_LITTLE(*InitVector + 4)
    i1 = (i0 >> 16) | (i2 & $FFFF0000)
    i3 = (i2 << 16) | (i0 & $0000FFFF)
    
    ; Modify counter values
    
    *Core\Work\C[0] = *Core\Master\C[0] ! i0
    *Core\Work\C[1] = *Core\Master\C[1] ! i1
    *Core\Work\C[2] = *Core\Master\C[2] ! i2
    *Core\Work\C[3] = *Core\Master\C[3] ! i3
    
    *Core\Work\C[4] = *Core\Master\C[4] ! i0
    *Core\Work\C[5] = *Core\Master\C[5] ! i1
    *Core\Work\C[6] = *Core\Master\C[6] ! i2
    *Core\Work\C[7] = *Core\Master\C[7] ! i3
    
    ; Copy state variables
    
    For Index = 0 To 7
      *Core\Work\X[Index] = *Core\Master\X[Index]
    Next
    
    *Core\Work\Carry = *Core\Master\Carry
    
    ; Iterate the system four times
    
    For index = 0 To 3
      RABBIT_NextState(*Core\Work)
    Next
    
  EndProcedure
  
  Procedure RABBIT_Process_Bytes(*Core.Core, *Input, *Output, MsgLen.l)
    
    ; Temporary variables
    
    Protected Buffer.Buffer, Index.l
    
    ; Encrypt/decrypt all full blocks
    
    While MsgLen >= 16
      
      ; Iterate the system
      RABBIT_NextState(*Core\Work)
      
      ; Encrypt/decrypt 16 bytes of data
      PokeL(*Output + 00, PeekL(*Input + 00) ! U32TO32_LITTLE(*Core\Work\X[0] ! (*Core\Work\X[5] >> 16) ! U32V(*Core\Work\X[3] << 16)))
      PokeL(*Output + 04, PeekL(*Input + 04) ! U32TO32_LITTLE(*Core\Work\X[2] ! (*Core\Work\X[7] >> 16) ! U32V(*Core\Work\X[5] << 16)))
      PokeL(*Output + 08, PeekL(*Input + 08) ! U32TO32_LITTLE(*Core\Work\X[4] ! (*Core\Work\X[1] >> 16) ! U32V(*Core\Work\X[7] << 16)))
      PokeL(*Output + 12, PeekL(*Input + 12) ! U32TO32_LITTLE(*Core\Work\X[6] ! (*Core\Work\X[3] >> 16) ! U32V(*Core\Work\X[1] << 16)))
      
      *Input + 16
      *Output + 16
      MsgLen - 16
      
    Wend
    
    ; Encrypt/decrypt remaining data
    
    If MsgLen <> 0
      
      ; Iterate the system
      RABBIT_NextState(*Core\Work)
      
      ; Generate 16 bytes of pseudo-random data */
      
      PokeL(@Buffer + 00, U32TO32_LITTLE(*Core\Work\X[0] ! (*Core\Work\X[5]>>16) ! U32V(*Core\Work\X[3]<<16)))
      PokeL(@Buffer + 04, U32TO32_LITTLE(*Core\Work\X[2] ! (*Core\Work\X[7]>>16) ! U32V(*Core\Work\X[5]<<16)))
      PokeL(@Buffer + 06, U32TO32_LITTLE(*Core\Work\X[4] ! (*Core\Work\X[1]>>16) ! U32V(*Core\Work\X[7]<<16)))
      PokeL(@Buffer + 12, U32TO32_LITTLE(*Core\Work\X[6] ! (*Core\Work\X[3]>>16) ! U32V(*Core\Work\X[1]<<16)))
      
      For Index = 0 To MsgLen - 1
        PokeA(*Output, PeekA(*Input) ! Buffer\Buffer[Index])
        *Output + 1
        *Input + 1
      Next
      
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Procedures declaration (Public) <<<<<
  
  Procedure.s Normalizer(Input.s, BitsLength.l)
    
    Bytes.l = BitsLength >> 3
    Output.s = StringFingerprint(Input, #PB_Cipher_MD5)
    
    While StringByteLength(Output) < Bytes
      Output + StringFingerprint(Output, #PB_Cipher_MD5)
    Wend
    
    ProcedureReturn Left(Output, Bytes / SizeOf(Unicode))
  EndProcedure
  
  Procedure Encrypt(*Key, *InitVector, *PlainText, *CipheredText, StringByteLength.l)
    
    RABBIT_KeySetup(Core.Core, *Key)
    
    If *InitVector <> #Null
      RABBIT_InitVectorSetup(Core, *InitVector)
    EndIf
    
    For Index = 0 To 7
      Debug Core\Work\X[Index]
    Next
    Debug ""
    For Index = 0 To 7
      Debug Core\Work\C[Index]
    Next
    
    RABBIT_Process_Bytes(Core, *PlainText, *CipheredText, StringByteLength)
    
  EndProcedure
  
  Procedure Decrypt(*Key, *InitVector, *PlainText, *CipheredText, StringByteLength.l)
    
    RABBIT_KeySetup(Core.Core, *Key)
    
    If *InitVector <> #Null
      RABBIT_InitVectorSetup(Core, *InitVector)
    EndIf
    
    RABBIT_Process_Bytes(Core, *CipheredText, *PlainText, StringByteLength)
    
  EndProcedure
  
EndModule

CompilerIf #PB_Compiler_IsMainFile
  
  UseMD5Fingerprint()

  *Key2 = AllocateMemory(?Key2Stop - ?Key2Start)
  CopyMemory(?Key2start, *Key2, MemorySize(*Key2))
  *InitVector2 = #Null 
  *out2 = AllocateMemory(?out2stop - ?out2start)
  CopyMemory(?out2start, *out2, MemorySize(*out2))
  *Ciphered = AllocateMemory(MemorySize(*out2))
  *Deciphered = AllocateMemory(MemorySize(*out2))
  
  RabbitCipher::Encrypt(*Key2, #Null, *out2, *Ciphered, MemorySize(*out2))
  RabbitCipher::Decrypt(*Key2, #Null, *Deciphered, *Ciphered, MemorySize(*out2))
  
  Debug "Test 2: Key setup and encryption/decryption"
  
  If CompareMemory(*out2, *Deciphered, MemorySize(*out2))
    Debug "Success"
  Else
    Debug "Failure"
  EndIf
  
  FreeMemory(*Ciphered)
  FreeMemory(*Deciphered)
  
  
  *Key4 = AllocateMemory(128/8)
  *InitVector4 = AllocateMemory(64/8)  
  *out4 = AllocateMemory(?out4stop - ?out4start)
  CopyMemory(?out4start, *out4, MemorySize(*out4))
  *Ciphered = AllocateMemory(MemorySize(*out4))
  *Deciphered = AllocateMemory(MemorySize(*out4))
  
  RabbitCipher::Encrypt(*Key4, *InitVector4, *out4, *Ciphered, MemorySize(*out4))
  RabbitCipher::Decrypt(*Key4, *InitVector4, *Deciphered, *Ciphered, MemorySize(*out4))
  
  Debug "Test 4: Key setup, iv setup and encryption/decryption"
  If CompareMemory(*out4, *Deciphered, MemorySize(*out4))
    Debug "Success"
  Else
    Debug "Failure"
  EndIf
  
  FreeMemory(*Ciphered)
  FreeMemory(*Deciphered)
  
  *Key5 = AllocateMemory(128/8)
  *InitVector5 = AllocateMemory(?iv5Stop - ?iv5start)  
  CopyMemory(?iv5start, *InitVector5, MemorySize(*InitVector5))
  
  *out5 = AllocateMemory(?out5stop - ?out5start)
  CopyMemory(?out5start, *out5, MemorySize(*out5))
  *Ciphered = AllocateMemory(MemorySize(*out5))
  *Deciphered = AllocateMemory(MemorySize(*out5))
  
  RabbitCipher::Encrypt(*Key5, *InitVector5, *out5, *Ciphered, MemorySize(*out5))
  RabbitCipher::Decrypt(*Key5, *InitVector5, *Deciphered, *Ciphered, MemorySize(*out5))
  
  Debug "Test 5: Key setup, iv setup and encryption/decryption"
  If CompareMemory(*out5, *Deciphered, MemorySize(*out5))
    Debug "Success"
  Else
    Debug "Failure"
  EndIf
  
  
  String.s = "Hello, this is a test for Rabbit Cipher !"
  
  Key.s = RabbitCipher::Normalizer("I'm the key !", 128)
  InitVector.s = RabbitCipher::Normalizer("I'm the InitVector !", 64)
  
  StringMemorySize = StringByteLength(String) + SizeOf(Character)
  
  *CipheredText = AllocateMemory(StringMemorySize)
  *CipheredText2 = AllocateMemory(StringMemorySize)
  *PlainText = AllocateMemory(StringMemorySize)
  *PlainText2 = AllocateMemory(StringMemorySize)
  
  RabbitCipher::Encrypt(@Key, @InitVector, @String, *CipheredText, StringByteLength(String))
  RabbitCipher::Encrypt(@Key, #Null, @String, *CipheredText2, StringByteLength(String))
  
  RabbitCipher::Decrypt(@Key, @InitVector, *PlainText, *CipheredText, StringByteLength(String))
  RabbitCipher::Decrypt(@Key, #Null, *PlainText2, *CipheredText2, StringByteLength(String))
  
  PlainText.s = PeekS(*PlainText)
  PlainText2.s = PeekS(*PlainText2)
  
  Debug "Test Real life : Key setup, IV setup and encryption/decryption"
  If String = PlainText
    Debug "Success"
  Else
    Debug "Failure"
  EndIf
  
  Debug "Test Real life : Key setup and encryption/decryption"
  If String = PlainText2
    Debug "Success"
  Else
    Debug "Failure"
  EndIf
  
  FreeMemory(*CipheredText)
  FreeMemory(*CipheredText2)
  FreeMemory(*PlainText)
  FreeMemory(*PlainText2)
  
  
  DataSection
    
    Key2Start:
    Data.a $C2, $1F, $CF, $38, $81, $CD, $5E, $E8, $62, $8A, $CC, $B0, $A9, $89, $0D, $F8
    Key2Stop:
    
    out2Start:
    Data.a $3D, $02, $E0, $C7, $30, $55, $91, $12, $B4, $73, $B7, $90, $DE, $E0, $18, $DF
    Data.a $CD, $6D, $73, $0C, $E5, $4E, $19, $F0, $C3, $5E, $C4, $79, $0E, $B6, $C7, $4A
    Data.a $9F, $B4, $92, $E1, $B5, $40, $36, $3A, $E3, $83, $C0, $1F, $9F, $A2, $26, $1A
    out2Stop:
    
    
    out4start:
    Data.a $ED, $B7, $05, $67, $37, $5D, $CD, $7C, $D8, $95, $54, $F8, $5E, $27, $A7, $C6
    Data.a $8D, $4A, $DC, $70, $32, $29, $8F, $7B, $D4, $EF, $F5, $04, $AC, $A6, $29, $5F
    Data.a $66, $8F, $BF, $47, $8A, $DB, $2B, $E5, $1E, $6C, $DE, $29, $2B, $82, $DE, $2A
    out4stop:
    
    
    iv5Start:
    Data.s $59, $7E, $26, $C1, $75, $F5, $73, $C3
    iv5Stop:
    
    out5start:
    Data.a $6D, $7D, $01, $22, $92, $CC, $DC, $E0, $E2, $12, $00, $58, $B9, $4E, $CD, $1F
    Data.a $2E, $6F, $93, $ED, $FF, $99, $24, $7B, $01, $25, $21, $D1, $10, $4E, $5F, $A7
    Data.a $A7, $9B, $02, $12, $D0, $BD, $56, $23, $39, $38, $E7, $93, $C3, $12, $C1, $EB
    out5stop:
    
    
  EndDataSection
  
CompilerEndIf

; <<<<<<<<<<<<<<<<<<<<<<<
; <<<<< END OF FILE <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<
Last edited by StarBootics on Thu Nov 05, 2020 10:36 pm, edited 1 time in total.
The Stone Age did not end due to a shortage of stones !
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Rabbit Cipher - Module

Post by wilbert »

Using PureBasic for an algorithm like this is complicated.
The lack of unsigned integers causes a lot of problems.
That's one of the reasons besides speed I prefer to use inline asm.

Your carry detection for example is wrong.

Code: Select all

Bool(*Rabbit\C[0] < Temp\OldC[0]))
For an unsigned 32 bit integer, the point where the new C value is smaller as the old one, is when it crosses 0xFFFFFFFF.
For a signed 32 bit (Long) or signed 64 bit integer (Quad) this isn't the case.
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
Saki
Addict
Addict
Posts: 830
Joined: Sun Apr 05, 2020 11:28 am
Location: Pandora

Re: Rabbit Cipher - Module

Post by Saki »

For myself it is a mystery why unsigned is not fully supported.
But you can see, if you browse here something, that this is also comprehensively desired.
It is a barrier, which only causes problems, it makes simple things complicated.
This is my own opinion.
地球上の平和
User avatar
StarBootics
Addict
Addict
Posts: 984
Joined: Sun Jul 07, 2013 11:35 am
Location: Canada

Re: Rabbit Cipher - Module

Post by StarBootics »

Hello everyone,

There is the original C code I have used as a reference :

Code: Select all

static void RABBIT_next_state(RABBIT_ctx *p_instance)
{
   /* Temporary variables */
   u32 g[8], c_old[8], i;

   /* Save old counter values */
   for (i=0; i<8; i++)
      c_old[i] = p_instance->c[i];

   /* Calculate new counter values */
   p_instance->c[0] = U32V(p_instance->c[0] + 0x4D34D34D + p_instance->carry);
   p_instance->c[1] = U32V(p_instance->c[1] + 0xD34D34D3 + (p_instance->c[0] < c_old[0]));
   p_instance->c[2] = U32V(p_instance->c[2] + 0x34D34D34 + (p_instance->c[1] < c_old[1]));
   p_instance->c[3] = U32V(p_instance->c[3] + 0x4D34D34D + (p_instance->c[2] < c_old[2]));
   p_instance->c[4] = U32V(p_instance->c[4] + 0xD34D34D3 + (p_instance->c[3] < c_old[3]));
   p_instance->c[5] = U32V(p_instance->c[5] + 0x34D34D34 + (p_instance->c[4] < c_old[4]));
   p_instance->c[6] = U32V(p_instance->c[6] + 0x4D34D34D + (p_instance->c[5] < c_old[5]));
   p_instance->c[7] = U32V(p_instance->c[7] + 0xD34D34D3 + (p_instance->c[6] < c_old[6]));
   p_instance->carry = (p_instance->c[7] < c_old[7]);
   
   /* Calculate the g-values */
   for (i=0;i<8;i++)
      g[i] = RABBIT_g_func(U32V(p_instance->x[i] + p_instance->c[i]));

   /* Calculate new state values */
   p_instance->x[0] = U32V(g[0] + ROTL32(g[7],16) + ROTL32(g[6], 16));
   p_instance->x[1] = U32V(g[1] + ROTL32(g[0], 8) + g[7]);
   p_instance->x[2] = U32V(g[2] + ROTL32(g[1],16) + ROTL32(g[0], 16));
   p_instance->x[3] = U32V(g[3] + ROTL32(g[2], 8) + g[1]);
   p_instance->x[4] = U32V(g[4] + ROTL32(g[3],16) + ROTL32(g[2], 16));
   p_instance->x[5] = U32V(g[5] + ROTL32(g[4], 8) + g[3]);
   p_instance->x[6] = U32V(g[6] + ROTL32(g[5],16) + ROTL32(g[4], 16));
   p_instance->x[7] = U32V(g[7] + ROTL32(g[6], 8) + g[5]);
}
@Wilbert : You are saying that the original C code was wrong as well ?

@Saki : Unsigned integers, unsigned long and unsigned quad are not supported in PureBasic because they have, as Fred said in the past, performance issues. How C and C++ compilers have solve this problem because they have it in these languages ? That's the question that I have for years without any answers.

Best regards
StarBootics
The Stone Age did not end due to a shortage of stones !
Post Reply