PureBasic 6.00 released !

Developed or developing a new product in PureBasic? Tell the world about it.
Fred
Administrator
Administrator
Posts: 16619
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: PureBasic 6.00 Beta 5 released !

Post by Fred »

It would break code, as you would have invalid access if you use structured map access. I agree it's not optimal, but at least it's consistent. If you are unsure if the element exists or not, better use FindMapElement() in your comparison first.
User avatar
mk-soft
Always Here
Always Here
Posts: 5335
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: PureBasic 6.00 Beta 5 released !

Post by mk-soft »

User_Russian wrote: Mon Mar 07, 2022 12:51 pm What's this? Why inactive? I can't clean the check mark. Is it a bug?

Image
Its only aviable for macOS
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
nsstudios
Enthusiast
Enthusiast
Posts: 274
Joined: Wed Aug 28, 2019 1:01 pm
Location: Serbia
Contact:

Re: PureBasic 6.00 Beta 5 released !

Post by nsstudios »

Fred wrote: Mon Mar 07, 2022 12:54 pm It would break code, as you would have invalid access if you use structured map access. I agree it's not optimal, but at least it's consistent. If you are unsure if the element exists or not, better use FindMapElement() in your comparison first.
Thank you for clarifying, Fred!
I am still not sure why that would break anything. Does this have to do anything with pb having an identical assignment and equality operators (x=5 and if x=5)?
Fred
Administrator
Administrator
Posts: 16619
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: PureBasic 6.00 Beta 5 released !

Post by Fred »

Consider this:

Code: Select all

If YourMap("Test")\Name = "Timo" : EndIf
If the map element "Test" doesn't exists, it will return NULL, and then the \Name accessor will crash your program (IMA).
User_Russian
Addict
Addict
Posts: 1443
Joined: Wed Nov 12, 2008 5:01 pm
Location: Russia

Re: PureBasic 6.00 Beta 5 released !

Post by User_Russian »

mk-soft wrote: Mon Mar 07, 2022 2:11 pmIts only aviable for macOS
Then on Windows and Linux do not need this checkbox. He must be absent.
Or the checkmark should not be. Because now is turned on unsupported function that cannot be turned off!
nsstudios
Enthusiast
Enthusiast
Posts: 274
Joined: Wed Aug 28, 2019 1:01 pm
Location: Serbia
Contact:

Re: PureBasic 6.00 Beta 5 released !

Post by nsstudios »

I understand now! Thank you for the clarification.
I believe that if you're trying to access an undefined map element, you should get a debugger warning like with array out of bounds, and if you compile, then if you try to work with an undefined map element, on error would tell you that you broke something somewhere. Maybe there's a legitimate case for where it would be desireable for an element to be created, but in my mind creating new elements when testing for equality can only lead to hard to debug "bugs" just like with non-explicit mode, where if you make a typo everything's seemingly fine, there's no warning, but your program most likely than not just doesn't work properly, not to mention you could easily be spawning many useless map elements by accident. In my mind, it makes maps really unreliable to work with.
Perhaps maps could work differently based on the EnableExplicit/DisableExplicit setting?
I guess there could also be some speed difference... Here's a test program I made, which also shows that optimized c backend is... slower? :shock:

Code: Select all

DisableDebugger
EnableExplicit
NewMap m()
#cycles=10000000
Define i, j
For j=1 To 10
m("test"+j)=1
Next
Define t1start.q=ElapsedMilliseconds()
For i=0 To #cycles
For j=1 To 10
If m("test"+j): EndIf
Next j
Next i
Define t1end.q=ElapsedMilliseconds()
Define t2start.q=ElapsedMilliseconds()
For i=0 To #cycles
For j=1 To 10
If FindMapElement(m(), "test"+j)
EndIf
Next j
Next i
Define t2end.q=ElapsedMilliseconds()
Define.q t1=t1end-t1start, t2=t2end-t2start, tDiff=Abs(t1-t2)
MessageRequester("done", ""+t1+", "+t2+", diff: "+tDiff, #PB_MessageRequester_Info)
On my system, I get:
  • asm x64
    • m(element): 6577
    • FindMapElement: 7681
    • diff: 1104 (FindMapElement slower)
  • C backend x64 with optimization
    • m(element): 8364
    • FindMapElement: 8555
    • diff: 191 (FindMapElement slower)
  • c backend x64 not optimized
    • m(element): 8301
    • FindMapElement: 8514
    • diff: 213 (FindMapElement slower)
I guess that is minimal difference for 10 mil iterations, but it surprises me that the speed of c backend is worse.
Last edited by nsstudios on Tue Mar 08, 2022 8:09 am, edited 1 time in total.
User avatar
skywalk
Addict
Addict
Posts: 3972
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: PureBasic 6.00 Beta 5 released !

Post by skywalk »

You forgot to disable debugger. C+optimize is fastest.

Code: Select all

; ---------------------------
; C+optimize
; ---------------------------
; 1327, 1356, diff: 29
; ---------------------------
; C-optimize
; ---------------------------
; 1333, 1380, diff: 47
; ---------------------------
; ASM
; ---------------------------
; 1417, 1573, diff: 156
; ---------------------------
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
nsstudios
Enthusiast
Enthusiast
Posts: 274
Joined: Wed Aug 28, 2019 1:01 pm
Location: Serbia
Contact:

Re: PureBasic 6.00 Beta 5 released !

Post by nsstudios »

I told it to run without debugger, unchecked debugger from debugger menu, did DisableDebugger in the code, but it still shows what I posted: slower than the asm compilation. Really bizarre.
zikitrake
Addict
Addict
Posts: 834
Joined: Thu Mar 25, 2004 2:15 pm
Location: Spain

Re: PureBasic 6.00 Beta 5 released !

Post by zikitrake »

Code: Select all

ASM
13013, 16778, Diff: 3765

C BACKEND
12984, 14385, Diff: 1399

C BACKEND OPTIMIZED
CBO 13129, 16542, Diff: 3413

PS: looking at the numbers above, I think I should change my pc soon :lol:
Cyllceaux
Enthusiast
Enthusiast
Posts: 458
Joined: Mon Jun 23, 2014 1:18 pm
Contact:

Re: PureBasic 6.00 Beta 5 released !

Post by Cyllceaux »

skywalk wrote: Tue Mar 08, 2022 4:13 am You forgot to disable debugger. C+optimize is fastest.

Code: Select all

...
1327, 1356, diff: 29
...
WTF do you have for a PC???? I have a Ryzen 9 5950X with ~5GHz and still have around 6 seconds runtime
User avatar
Lord
Addict
Addict
Posts: 847
Joined: Tue May 26, 2009 2:11 pm

Re: PureBasic 6.00 Beta 5 released !

Post by Lord »

Cyllceaux wrote: Tue Mar 08, 2022 8:58 am
skywalk wrote: Tue Mar 08, 2022 4:13 am You forgot to disable debugger. C+optimize is fastest.

Code: Select all

...
1327, 1356, diff: 29
...
WTF do you have for a PC???? I have a Ryzen 9 5950X with ~5GHz and still have around 6 seconds runtime
He just set #cycles to 1000000?
Image
Mindphazer
Enthusiast
Enthusiast
Posts: 340
Joined: Mon Sep 10, 2012 10:41 am
Location: Savoie

Re: PureBasic 6.00 Beta 5 released !

Post by Mindphazer »

User_Russian wrote: Mon Mar 07, 2022 4:03 pm Then on Windows and Linux do not need this checkbox. He must be absent.
Or the checkmark should not be. Because now is turned on unsupported function that cannot be turned off!
Don't forget it's still a beta version
MacBook Pro 14" M1 Pro - 16 Gb - MacOS 14 - Iphone 15 Pro Max - iPad at home
...and unfortunately... Windows at work...
User avatar
skywalk
Addict
Addict
Posts: 3972
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: PureBasic 6.00 Beta 5 released !

Post by skywalk »

Yes, and I added an operation between the If statements. I have nanosecond clock cycles, so 1000s of milliseconds are enough for trends.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
idle
Always Here
Always Here
Posts: 5042
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: PureBasic 6.00 Beta 5 released !

Post by idle »

There's not much point doing speed tests where all your doing is calling library functions. Yes oddly the ASM was faster on my windows machine and I have no explanation for that or even care to look at it but if you give it some native code to optimise you will see a remarkable improvement by orders of magnitude.

For instance the validation of ec25519
Linux x64 C backend with clang tool chain and additional gccflags -O3 -mavx 11ms
Windows x64 C backend with optimized 90ms
Linux x64 Fasm 312ms
Windows x64 Fasm 315ms

10ms vs 300ms I think I'll go with the c backend thank you very much.
I can only surmise that the clang optimiser promoted the code to use avx instructions, now that's cool!

compile for console without debugger

Code: Select all

;mod EC ported by Idle, Danilo and Peter H
;implimentation of Curve25519 elliptic curve, public key function
;for use in EC Dieffie-Hellman key exchange  
;Updated 31/3/16 
;Version PB 5.42 LTS
;for production set the flag 
;#UseValidation = 0   

DeclareModule modEC

; /* Copyright 2008, Google Inc.
;  * All rights reserved.
;  *
;  * Redistribution And use in source And binary forms, With Or without
;  * modification, are permitted provided that the following conditions are
;  * met:
;  *
;  *     * Redistributions of source code must retain the above copyright
;  *       notice, this List of conditions And the following disclaimer.
;  *     * Redistributions in binary form must reproduce the above
;  *       copyright notice, this List of conditions And the following disclaimer
;  *       in the documentation And/Or other materials provided With the
;  *       distribution.
;  *     * Neither the name of Google Inc. nor the names of its
;  *       contributors may be used To endorse Or promote products derived from
;  *       this software without specific prior written permission.
;  *
;  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS And CONTRIBUTORS
;  * "AS IS" And ANY EXPRESS Or IMPLIED WARRANTIES, INCLUDING, BUT Not
;  * LIMITED To, THE IMPLIED WARRANTIES OF MERCHANTABILITY And FITNESS For
;  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
;  * OWNER Or CONTRIBUTORS BE LIABLE For ANY DIRECT, INDIRECT, INCIDENTAL,
;  * SPECIAL, EXEMPLARY, Or CONSEQUENTIAL DAMAGES (INCLUDING, BUT Not
;  * LIMITED To, PROCUREMENT OF SUBSTITUTE GOODS Or SERVICES; LOSS OF USE,
;  * Data, Or PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
;  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, Or TORT
;  * (INCLUDING NEGLIGENCE Or OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
;  * OF THIS SOFTWARE, EVEN If ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;  *
;  * curve25519-donna: Curve25519 elliptic curve, public key function
;  *
;  * http://code.google.com/p/curve25519-donna/
;  *
;  * Adam Langley <agl@imperialviolet.org>
;  *
;  * Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.To>
;  *
;  * More information about curve25519 can be found here
;  *   http://cr.yp.To/ecdh.html
;  *
;  * djb's sample implementation of curve25519 is written in a special assembly
;  * language called qhasm And uses the floating point registers.
;  *
;  * This is, almost, a clean room reimplementation from the curve25519 paper. It
;  * uses many of the tricks described therein. Only the crecip function is taken
;  * from the sample implementation.
;  */
;-Interface
;-myEc.modEC::iEC
Interface IEC 
   Genkeys.s()
   GetKey.s(public.s) 
   SaveKeys(files.s)
   LoadKeys.s(file.s) ;returns public key 
   Free() 
EndInterface 
;-Construcor
;-myEc = modEc::NewEc("salt")
Declare newEC(salt.s)
;-Use Validation 
#UseValidation = 1    ;turn this off for production 
CompilerIf #UseValidation
   Declare validate() 
CompilerEndIf
EndDeclareModule 

Module modEC 
EnableExplicit

UseSHA3Fingerprint()

Structure felem
   q.q[0]
EndStructure

Structure u8
   a.a[0]
EndStructure

Macro Comment(a) : EndMacro

; /* Sum two numbers: output += in */
Procedure fsum(*output.felem, *in.felem)
   Protected i
   While i < 10
      *output\q[  i] = (*output\q[  i] + *in\q[  i])
      *output\q[1+i] = (*output\q[1+i] + *in\q[1+i])
      i + 2
   Wend
EndProcedure


; /* Find the difference of two numbers: output = in - output
;  * (note the order of the arguments!)
;  */
Procedure fdifference(*output.felem, *in.felem)
   Protected i
   While i < 10
      *output\q[i] = (*in\q[i] - *output\q[i])
      i + 1
   Wend
EndProcedure


; /* Multiply a number my a scalar: output = in * scalar */
Procedure fscalar_product(*output.felem, *in.felem, scalar.q)
   Protected i
   While i < 10
      *output\q[i] = *in\q[i] * scalar
      i + 1
   Wend
EndProcedure


;/* Multiply two numbers: output = in2 * in
; *
; * output must be distinct to both inputs. The inputs are reduced coefficient
; * form, the output is not.
; */
Procedure fproduct(*output.felem, *in2.felem, *in.felem)
   *output\q[0] =       *in2\q[0] * *in\q[0]
   *output\q[1] =       *in2\q[0] * *in\q[1] +
                        *in2\q[1] * *in\q[0]
   *output\q[2] =  2 *  *in2\q[1] * *in\q[1] +
                   *in2\q[0] * *in\q[2] +
                   *in2\q[2] * *in\q[0]
   *output\q[3] =       *in2\q[1] * *in\q[2] +
                        *in2\q[2] * *in\q[1] +
                        *in2\q[0] * *in\q[3] +
                        *in2\q[3] * *in\q[0]
   *output\q[4] =       *in2\q[2] * *in\q[2] +
                        2 * (*in2\q[1] * *in\q[3] +
                             *in2\q[3] * *in\q[1]) +
                        *in2\q[0] * *in\q[4] +
                        *in2\q[4] * *in\q[0]
   *output\q[5] =       *in2\q[2] * *in\q[3] +
                        *in2\q[3] * *in\q[2] +
                        *in2\q[1] * *in\q[4] +
                        *in2\q[4] * *in\q[1] +
                        *in2\q[0] * *in\q[5] +
                        *in2\q[5] * *in\q[0]
   *output\q[6] =  2 * (*in2\q[3] * *in\q[3] +
                        *in2\q[1] * *in\q[5] +
                        *in2\q[5] * *in\q[1]) +
                   *in2\q[2] * *in\q[4] +
                   *in2\q[4] * *in\q[2] +
                   *in2\q[0] * *in\q[6] +
                   *in2\q[6] * *in\q[0]
   *output\q[7] =       *in2\q[3] * *in\q[4] +
                        *in2\q[4] * *in\q[3] +
                        *in2\q[2] * *in\q[5] +
                        *in2\q[5] * *in\q[2] +
                        *in2\q[1] * *in\q[6] +
                        *in2\q[6] * *in\q[1] +
                        *in2\q[0] * *in\q[7] +
                        *in2\q[7] * *in\q[0]
   *output\q[8] =       *in2\q[4] * *in\q[4] +
                        2 * (*in2\q[3] * *in\q[5] +
                             *in2\q[5] * *in\q[3] +
                             *in2\q[1] * *in\q[7] +
                             *in2\q[7] * *in\q[1]) +
                        *in2\q[2] * *in\q[6] +
                        *in2\q[6] * *in\q[2] +
                        *in2\q[0] * *in\q[8] +
                        *in2\q[8] * *in\q[0]
   *output\q[9] =       *in2\q[4] * *in\q[5] +
                        *in2\q[5] * *in\q[4] +
                        *in2\q[3] * *in\q[6] +
                        *in2\q[6] * *in\q[3] +
                        *in2\q[2] * *in\q[7] +
                        *in2\q[7] * *in\q[2] +
                        *in2\q[1] * *in\q[8] +
                        *in2\q[8] * *in\q[1] +
                        *in2\q[0] * *in\q[9] +
                        *in2\q[9] * *in\q[0]
   *output\q[10] = 2 * (*in2\q[5] * *in\q[5] +
                        *in2\q[3] * *in\q[7] +
                        *in2\q[7] * *in\q[3] +
                        *in2\q[1] * *in\q[9] +
                        *in2\q[9] * *in\q[1]) +
                   *in2\q[4] * *in\q[6] +
                   *in2\q[6] * *in\q[4] +
                   *in2\q[2] * *in\q[8] +
                   *in2\q[8] * *in\q[2]
   *output\q[11] =      *in2\q[5] * *in\q[6] +
                        *in2\q[6] * *in\q[5] +
                        *in2\q[4] * *in\q[7] +
                        *in2\q[7] * *in\q[4] +
                        *in2\q[3] * *in\q[8] +
                        *in2\q[8] * *in\q[3] +
                        *in2\q[2] * *in\q[9] +
                        *in2\q[9] * *in\q[2]
   *output\q[12] =      *in2\q[6] * *in\q[6] +
                        2 * (*in2\q[5] * *in\q[7] +
                             *in2\q[7] * *in\q[5] +
                             *in2\q[3] * *in\q[9] +
                             *in2\q[9] * *in\q[3]) +
                        *in2\q[4] * *in\q[8] +
                        *in2\q[8] * *in\q[4]
   *output\q[13] =      *in2\q[6] * *in\q[7] +
                        *in2\q[7] * *in\q[6] +
                        *in2\q[5] * *in\q[8] +
                        *in2\q[8] * *in\q[5] +
                        *in2\q[4] * *in\q[9] +
                        *in2\q[9] * *in\q[4]
   *output\q[14] = 2 * (*in2\q[7] * *in\q[7] +
                        *in2\q[5] * *in\q[9] +
                        *in2\q[9] * *in\q[5]) +
                   *in2\q[6] * *in\q[8] +
                   *in2\q[8] * *in\q[6]
   *output\q[15] =      *in2\q[7] * *in\q[8] +
                        *in2\q[8] * *in\q[7] +
                        *in2\q[6] * *in\q[9] +
                        *in2\q[9] * *in\q[6]
   *output\q[16] =      *in2\q[8] * *in\q[8] +
                        2 * (*in2\q[7] * *in\q[9] +
                             *in2\q[9] * *in\q[7])
   *output\q[17] =      *in2\q[8] * *in\q[9] +
                        *in2\q[9] * *in\q[8]
   *output\q[18] = 2 *  *in2\q[9] * *in\q[9]
EndProcedure


;/* Reduce a long form to a short form by taking the input mod 2^255 - 19. */
Procedure freduce_degree(*output.felem)
   *output\q[8] + (19 * *output\q[18])
   *output\q[7] + (19 * *output\q[17])
   *output\q[6] + (19 * *output\q[16])
   *output\q[5] + (19 * *output\q[15])
   *output\q[4] + (19 * *output\q[14])
   *output\q[3] + (19 * *output\q[13])
   *output\q[2] + (19 * *output\q[12])
   *output\q[1] + (19 * *output\q[11])
   *output\q[0] + (19 * *output\q[10])
EndProcedure


;/* Reduce all coefficients of the short form input to be -2**25 <= x <= 2**25
Procedure freduce_coefficients(*output.felem)
   Protected i, over.q, over2.q ; over and over2 = felem
   Repeat
      *output\q[10] = 0
      
      i=0
      While i < 10
         over = *output\q[i] / $2000000
         over2 = (over + ((over >> 63) * 2) + 1) / 2
         *output\q[i+1] + over2
         *output\q[i] - (over2 * $4000000)
         
         over = *output\q[i+1] / $2000000
         *output\q[i+2] + over
         *output\q[i+1] - (over * $2000000)
         i + 2
      Wend
      *output\q[0] + (19 * *output\q[10])
   Until Not *output\q[10]
EndProcedure


;/* A helpful wrapper around fproduct: output = in * in2.
; *
; * output must be distinct to both inputs. The output is reduced degree and
; * reduced coefficient.
; */
Procedure fmul(*output.felem, *in.felem, *in2.felem)
   Dim t.q(19) ; felem
   fproduct(@t(), *in, *in2);
   freduce_degree(@t())
   freduce_coefficients(@t())
   CopyMemory(@t(), *output, SizeOf(Quad) * 10) ; SizeOf(felem)
EndProcedure


Procedure fsquare_inner(*output.felem, *in.felem)
   *output\q[0] =       *in\q[0] * *in\q[0]
   *output\q[1] =  2 *  *in\q[0] * *in\q[1]
   *output\q[2] =  2 * (*in\q[1] * *in\q[1] +
                        *in\q[0] * *in\q[2])
   *output\q[3] =  2 * (*in\q[1] * *in\q[2] +
                        *in\q[0] * *in\q[3])
   *output\q[4] =       *in\q[2] * *in\q[2] +
                        4 *  *in\q[1] * *in\q[3] +
                        2 *  *in\q[0] * *in\q[4]
   *output\q[5] =  2 * (*in\q[2] * *in\q[3] +
                        *in\q[1] * *in\q[4] +
                        *in\q[0] * *in\q[5])
   *output\q[6] =  2 * (*in\q[3] * *in\q[3] +
                        *in\q[2] * *in\q[4] +
                        *in\q[0] * *in\q[6] +
                        2 *  *in\q[1] * *in\q[5])
   *output\q[7] =  2 * (*in\q[3] * *in\q[4] +
                        *in\q[2] * *in\q[5] +
                        *in\q[1] * *in\q[6] +
                        *in\q[0] * *in\q[7])
   *output\q[8] =       *in\q[4] * *in\q[4] +
                        2 * (*in\q[2] * *in\q[6] +
                             *in\q[0] * *in\q[8] +
                             2 * (*in\q[1] * *in\q[7] +
                                  *in\q[3] * *in\q[5]))
   *output\q[9] =  2 * (*in\q[4] * *in\q[5] +
                        *in\q[3] * *in\q[6] +
                        *in\q[2] * *in\q[7] +
                        *in\q[1] * *in\q[8] +
                        *in\q[0] * *in\q[9])
   *output\q[10] = 2 * (*in\q[5] * *in\q[5] +
                        *in\q[4] * *in\q[6] +
                        *in\q[2] * *in\q[8] +
                        2 * (*in\q[3] * *in\q[7] +
                             *in\q[1] * *in\q[9]))
   *output\q[11] = 2 * (*in\q[5] * *in\q[6] +
                        *in\q[4] * *in\q[7] +
                        *in\q[3] * *in\q[8] +
                        *in\q[2] * *in\q[9])
   *output\q[12] =      *in\q[6] * *in\q[6] +
                        2 * (*in\q[4] * *in\q[8] +
                             2 * (*in\q[5] * *in\q[7] +
                                  *in\q[3] * *in\q[9]))
   *output\q[13] = 2 * (*in\q[6] * *in\q[7] +
                        *in\q[5] * *in\q[8] +
                        *in\q[4] * *in\q[9])
   *output\q[14] = 2 * (*in\q[7] * *in\q[7] +
                        *in\q[6] * *in\q[8] +
                        2 *  *in\q[5] * *in\q[9])
   *output\q[15] = 2 * (*in\q[7] * *in\q[8] +
                        *in\q[6] * *in\q[9])
   *output\q[16] =      *in\q[8] * *in\q[8] +
                        4 *  *in\q[7] * *in\q[9]
   *output\q[17] = 2 *  *in\q[8] * *in\q[9]
   *output\q[18] = 2 *  *in\q[9] * *in\q[9]
EndProcedure


Procedure fsquare(*output.felem, *in.felem)
   Dim t.q(19) ; felem
   fsquare_inner(@t(), *in)
   freduce_degree(@t())
   freduce_coefficients(@t())
   CopyMemory(@t(),*output, SizeOf(Quad) * 10) ; SizeOf(felem)
EndProcedure


;/* Take a little-endian, 32-byte number and expand it into polynomial form */
Procedure fexpand(*output.felem, *input.u8)
   Protected q1.q, q2.q, q3.q, q4.q
   Macro F(n,start,shift,mask)
      q1 = (*input\a[start + 0] & $FF)
      q2 = (*input\a[start + 1] & $FF) : q2 << 8
      q3 = (*input\a[start + 2] & $FF) : q3 << 16
      q4 = (*input\a[start + 3] & $FF) : q4 << 24
      *output\q[n] = ((q1 | q2 | q3 | q4 ) >> shift) & mask
   EndMacro
   F(0, 0, 0, $3ffffff)
   F(1, 3, 2, $1ffffff)
   F(2, 6, 3, $3ffffff)
   F(3, 9, 5, $1ffffff)
   F(4, 12, 6, $3ffffff)
   F(5, 16, 0, $1ffffff)
   F(6, 19, 1, $3ffffff)
   F(7, 22, 3, $1ffffff)
   F(8, 25, 4, $3ffffff)
   F(9, 28, 6, $1ffffff)
   UndefineMacro F
EndProcedure



;/* Take a fully reduced polynomial form number and contract it into a
; * little-endian, 32-byte array
; */
Procedure fcontract(*output.u8, *input.felem)
   Protected i
   
   Repeat
      i = 0
      While i < 9
         If ((i & 1) = 1)
            While (*input\q[i] < 0)
               *input\q[i] + $2000000
               *input\q[i + 1] - 1
            Wend
         Else
            While (*input\q[i] < 0)
               *input\q[i] + $4000000
               *input\q[i + 1] - 1
            Wend
         EndIf
         i + 1
      Wend
      While (*input\q[9] < 0)
         *input\q[9] + $2000000
         *input\q[0] - 19
      Wend
   Until *input\q[0] >= 0
   
   *input\q[1] << 2
   *input\q[2] << 3
   *input\q[3] << 5
   *input\q[4] << 6
   *input\q[6] << 1
   *input\q[7] << 3
   *input\q[8] << 4
   *input\q[9] << 6
   
   Macro F(i, s)
      *output\a[s+0] | (*input\q[i] & $ff)
      *output\a[s+1] = ((*input\q[i] >>  8) & $ff)
      *output\a[s+2] = ((*input\q[i] >> 16) & $ff)
      *output\a[s+3] = ((*input\q[i] >> 24) & $ff)
   EndMacro
   
   *output\a[0]  = 0
   *output\a[16] = 0
   F(0,0)
   F(1,3)
   F(2,6)
   F(3,9)
   F(4,12)
   F(5,16)
   F(6,19)
   F(7,22)
   F(8,25)
   F(9,28)
   
   UndefineMacro F
   
EndProcedure


;/* Input: Q, Q', Q-Q'
; * Output: 2Q, Q+Q'
; *
; *   x2 z3: long form
; *   x3 z3: long form
; *   x z: short form, destroyed
; *   xprime zprime: short form, destroyed
; *   qmqp: short form, preserved
; */
Procedure fmonty(*x2.felem, *z2.felem          Comment("/* output 2Q     */") ,
                 *x3.felem, *z3.felem          Comment("/* output Q + Q' */") ,
                 *x.felem , *z.felem           Comment("/* input Q       */") ,
                 *xprime.felem, *zprime.felem  Comment("/* input Q'      */") ,
                 *qmqp.felem                   Comment("/* input Q - Q'  */") )
   ; following Dim's are all of type felem
   Dim origx.q(10)   : Dim origxprime.q(10)
   Dim zzz.q(19)     : Dim xx.q(19)         : Dim zz.q(19)
   Dim xxprime.q(19) : Dim zzprime.q(19)    : Dim zzzprime.q(19) : Dim xxxprime.q(19)
   
   CopyMemory(*x, @origx(), 10 * SizeOf(Quad)) ; SizeOf(felem)
   fsum(*x, *z)
   fdifference(*z, @origx())  ; does x - z
   
   CopyMemory(*xprime, @origxprime(), SizeOf(Quad) * 10) ; SizeOf(felem)
   fsum(*xprime, *zprime)
   fdifference(*zprime, @origxprime())
   fproduct(@xxprime(), *xprime, *z)
   fproduct(@zzprime(), *x, *zprime)
   freduce_degree(@xxprime())
   freduce_coefficients(@xxprime())
   freduce_degree(@zzprime())
   freduce_coefficients(@zzprime())
   CopyMemory(@xxprime(), @origxprime(), SizeOf(Quad) * 10) ; SizeOf(felem)
   fsum(@xxprime(), @zzprime())
   fdifference(@zzprime(), @origxprime())
   fsquare(@xxxprime(), @xxprime())
   fsquare(@zzzprime(), @zzprime())
   fproduct(@zzprime(), @zzzprime(), *qmqp)
   freduce_degree(@zzprime())
   freduce_coefficients(@zzprime())
   CopyMemory(@xxxprime(), *x3, SizeOf(Quad) * 10) ; SizeOf(felem)
   CopyMemory(@zzprime() , *z3, SizeOf(Quad) * 10) ; SizeOf(felem)
   
   fsquare(@xx(), *x)
   fsquare(@zz(), *z)
   fproduct(*x2, @xx(), @zz())
   freduce_degree(*x2)
   freduce_coefficients(*x2)
   fdifference(@zz(), @xx())  ; does zz = xx - zz
   FillMemory(@zzz()+10*SizeOf(Quad), SizeOf(Quad) * 9, 0, #PB_Byte) ; SizeOf(felem)
   fscalar_product(@zzz(), @zz(), 121665)
   freduce_degree(@zzz())
   freduce_coefficients(@zzz())
   fsum(@zzz(), @xx())
   fproduct(*z2, @zz(), @zzz())
   freduce_degree(*z2)
   freduce_coefficients(*z2)
EndProcedure


;/* Calculates nQ where Q is the x-coordinate of a point on the curve
; *
; *   resultx/resultz: the x coordinate of the resulting curve Point (short form)
; *   n: a little endian, 32-byte number
; *   q: a point of the curve (short form)
; */
Procedure cmult(*resultx.felem, *resultz.felem, *n.u8, *q.felem)
   Protected i, j, byte.a
   
   ; all of type felem
   Dim a.q(19)
   Dim b.q(19) : b(0) = 1
   Dim c.q(19) : c(0) = 1
   Dim d.q(19)
   
   Protected *nqpqx.felem = @a(), *nqpqz.felem = @b(), *nqx.felem = @c(), *nqz.felem = @d()  ;, *t.felem
   
   Dim e.q(19)
   Dim f.q(19) : f(0) = 1
   Dim g.q(19)
   Dim h.q(19) : h(0) = 1
   
   Protected *nqpqx2.felem = @e(), *nqpqz2.felem = @f(), *nqx2.felem = @g(), *nqz2.felem = @h()
   
   CopyMemory(*q, *nqpqx, SizeOf(Quad) * 10) ; Sizeof(felem)
   
   i = 0
   While i < 32
      byte = *n\a[31 - i] & $FF ; byte = type u8
      j = 0
      While j < 8
         If (byte & $80)
            fmonty(*nqpqx2, *nqpqz2,
                   *nqx2, *nqz2,
                   *nqpqx, *nqpqz,
                   *nqx, *nqz,
                   *q)
         Else
            fmonty(*nqx2, *nqz2,
                   *nqpqx2, *nqpqz2,
                   *nqx, *nqz,
                   *nqpqx, *nqpqz,
                   *q)
         EndIf
         
         ;*t = *nqx           ; can be replaced with Swap in PB
         ;*nqx = *nqx2
         ;*nqx2 = *t
         Swap *nqx, *nqx2
         
         ;*t = *nqz
         ;*nqz = *nqz2
         ;*nqz2 = *t
         Swap *nqz, *nqz2
         
         ;*t = *nqpqx
         ;*nqpqx = *nqpqx2
         ;*nqpqx2 = *t
         Swap *nqpqx, *nqpqx2
         
         ;*t = *nqpqz
         ;*nqpqz = *nqpqz2
         ;*nqpqz2 = *t
         Swap *nqpqz, *nqpqz2
         
         byte = (byte << 1)
         j + 1
      Wend
      i + 1
   Wend
   
   CopyMemory(*nqx, *resultx, SizeOf(Quad) * 10) ; SizeOf(felem)
   CopyMemory(*nqz, *resultz, SizeOf(Quad) * 10) ; SizeOf(felem)
EndProcedure


;// -----------------------------------------------------------------------------
;// Shamelessly copied from djb's code
;// -----------------------------------------------------------------------------
Procedure crecip(*out.felem, *z.felem)
   ; all Dim of type felem:
   Dim z2.q(10)
   Dim z9.q(10)
   Dim z11.q(10)
   Dim z2_5_0.q(10)
   Dim z2_10_0.q(10)
   Dim z2_20_0.q(10)
   Dim z2_50_0.q(10)
   Dim z2_100_0.q(10)
   Dim t0.q(10)
   Dim t1.q(10)
   
   Protected i
   
   Comment("/* 2              */") fsquare(@z2(),*z)
   Comment("/* 4              */") fsquare(@t1(),@z2())
   Comment("/* 8              */") fsquare(@t0(),@t1())
   Comment("/* 9              */") fmul(@z9(),@t0(),*z)
   Comment("/* 11             */") fmul(@z11(),@z9(),@z2())
   Comment("/* 22             */") fsquare(@t0(),@z11())
   Comment("/* 2^5 - 2^0 = 31 */") fmul(@z2_5_0(),@t0(),@z9())
   
   Comment("/* 2^6 - 2^1      */") fsquare(@t0(),@z2_5_0())
   Comment("/* 2^7 - 2^2      */") fsquare(@t1(),@t0())
   Comment("/* 2^8 - 2^3      */") fsquare(@t0(),@t1())
   Comment("/* 2^9 - 2^4      */") fsquare(@t1(),@t0())
   Comment("/* 2^10 - 2^5     */") fsquare(@t0(),@t1())
   Comment("/* 2^10 - 2^0     */") fmul(@z2_10_0(),@t0(),@z2_5_0())
   
   Comment("/* 2^11 - 2^1     */") fsquare(@t0(),@z2_10_0())
   Comment("/* 2^12 - 2^2     */") fsquare(@t1(),@t0())
   Comment("/* 2^20 - 2^10    */") i=2 : While i < 10 : fsquare(@t0(),@t1()) : fsquare(@t1(),@t0()) : i + 2 : Wend
   Comment("/* 2^20 - 2^0     */") fmul(@z2_20_0(),@t1(),@z2_10_0())
   
   Comment("/* 2^21 - 2^1     */") fsquare(@t0(),@z2_20_0())
   Comment("/* 2^22 - 2^2     */") fsquare(@t1(),@t0())
   Comment("/* 2^40 - 2^20    */") i=2 : While i < 20 : fsquare(@t0(),@t1()) : fsquare(@t1(),@t0()) : i + 2 : Wend
   Comment("/* 2^40 - 2^0     */") fmul(@t0(),@t1(),@z2_20_0())
   
   Comment("/* 2^41 - 2^1     */") fsquare(@t1(),@t0())
   Comment("/* 2^42 - 2^2     */") fsquare(@t0(),@t1())
   Comment("/* 2^50 - 2^10    */") i=2 : While i < 10 : fsquare(@t1(),@t0()) : fsquare(@t0(),@t1()) : i + 2 : Wend
   Comment("/* 2^50 - 2^0     */") fmul(@z2_50_0(),@t0(),@z2_10_0())
   
   Comment("/* 2^51 - 2^1     */") fsquare(@t0(),@z2_50_0())
   Comment("/* 2^52 - 2^2     */") fsquare(@t1(),@t0())
   Comment("/* 2^100 - 2^50   */") i=2 : While i < 50 : fsquare(@t0(),@t1()) : fsquare(@t1(),@t0()) : i + 2 : Wend
   Comment("/* 2^100 - 2^0    */") fmul(@z2_100_0(),@t1(),@z2_50_0())
   
   Comment("/* 2^101 - 2^1    */") fsquare(@t1(),@z2_100_0())
   Comment("/* 2^102 - 2^2    */") fsquare(@t0(),@t1())
   Comment("/* 2^200 - 2^100  */") i=2 : While i < 100 : fsquare(@t1(),@t0()) : fsquare(@t0(),@t1()): i + 2 : Wend
   Comment("/* 2^200 - 2^0    */") fmul(@t1(),@t0(),@z2_100_0())
   
   Comment("/* 2^201 - 2^1    */") fsquare(@t0(),@t1())
   Comment("/* 2^202 - 2^2    */") fsquare(@t1(),@t0())
   Comment("/* 2^250 - 2^50   */") i=2 : While i < 50 : fsquare(@t0(),@t1()) : fsquare(@t1(),@t0()) : i + 2 : Wend
   Comment("/* 2^250 - 2^0    */") fmul(@t0(),@t1(),@z2_50_0())
   
   Comment("/* 2^251 - 2^1    */") fsquare(@t1(),@t0())
   Comment("/* 2^252 - 2^2    */") fsquare(@t0(),@t1())
   Comment("/* 2^253 - 2^3    */") fsquare(@t1(),@t0())
   Comment("/* 2^254 - 2^4    */") fsquare(@t0(),@t1())
   Comment("/* 2^255 - 2^5    */") fsquare(@t1(),@t0())
   Comment("/* 2^255 - 21     */") fmul(*out,@t1(),@z11())
EndProcedure

Procedure.i curve25519_donna(*mypublic.u8, *secret.u8, *basepoint.u8)
   ; Dim of type felem:
   Dim bp.q(10)
   Dim x.q(10)
   Dim z.q(10)
   Dim zmone.q(10)
   
   ; Dim of type uint8_t
   Dim e.a(32)
   
   Protected i
   
   i = 0
   While i < 32
      e(i) = *secret\a[i]
      i + 1
   Wend
   
   
   e(0)  & 248
   e(31) & 127
   e(31) | 64
   
   
   fexpand(@bp(), *basepoint)
   cmult(@x(), @z(), @e(), @bp())
   crecip(@zmone(), @z())
   fmul(@z(), @x(), @zmone())
   fcontract(*mypublic, @z())
   ProcedureReturn 0
EndProcedure

Enumeration 1 
   #DHStateGenKeys
   #DHStateSendPublic
   #DHStateGenShared
   #DHStateComplete
EndEnumeration 

Structure DHKeys 
   Ksecret.a[32]
   Kpublic.a[32]
   Kshared.a[32]
   kBase.a[32] 
EndStructure 

Structure EC 
   *vt 
   salt.a[32]
   keys.DHkeys 
   status.i 
EndStructure 

Procedure NewEC(salt.s) 
   Protected *this.EC,SHA3.s,b,a  
   *this = AllocateMemory(SizeOf(EC)) 
   If *this 
      *this\vt = ?EC_vt 
      If salt <> "" 
         SHA3 = Fingerprint(@salt,Len(salt),#PB_Cipher_SHA3,256) 
         For a = 1 To 64 Step 2
            *this\salt[b] = Val("$"+Mid(SHA3,a,2))
            b+1
         Next 
      EndIf    
      ProcedureReturn *this 
   EndIf 
EndProcedure   

Procedure.s EC_GenKeys(*this.EC) 
   Protected *ptr.Ascii ,a,sout.s
   If OpenCryptRandom()  
      CryptRandomData(@*this\keys\Ksecret,32)
      CloseCryptRandom() 
      *ptr = @*this\keys\Ksecret 
      *ptr\a  & 248 
      *ptr+31
      *ptr\a & 127 
      *ptr\a | 64 
      FillMemory(@*this\keys\kBase,32) 
      FillMemory(@*this\keys\Kpublic,32) 
      *this\keys\kBase[0]=9 
      curve25519_donna(@*this\keys\Kpublic,@*this\keys\Ksecret,@*this\keys\kBase)
      
      For a=0 To 31
         *this\keys\kpublic[a] ! *this\salt[a] 
         sout+ RSet(Hex(*this\keys\Kpublic[a],#PB_Byte),2,"0")
      Next  
      
      ProcedureReturn sout  
   EndIf      
EndProcedure  

Procedure EC_SaveKeys(*this.EC,file.s) 
  Protected *ptr.Ascii,fn 
  If Not *this\keys\Ksecret 
    If OpenCryptRandom()  
      CryptRandomData(@*this\keys\Ksecret,32)
      CloseCryptRandom() 
      *ptr = @*this\keys\Ksecret 
      *ptr\a  & 248 
      *ptr+31
      *ptr\a & 127 
      *ptr\a | 64 
      FillMemory(@*this\keys\kBase,32) 
      FillMemory(@*this\keys\Kpublic,32) 
      *this\keys\kBase[0]=9 
      curve25519_donna(@*this\keys\Kpublic,@*this\keys\Ksecret,@*this\keys\kBase)
    EndIf 
  EndIf
  
  fn = OpenFile(#PB_Any,file)
  If fn 
    WriteData(fn,@*this\keys\Ksecret,32)
    WriteData(fn,@*this\keys\kBase,32) 
    WriteData(fn,@*this\keys\Kpublic,32) 
    CloseFile(fn) 
  EndIf   
        
EndProcedure 

Procedure.s EC_LoadKeys(*this.EC,file.s)
  Protected fn,a,sout.s
  fn = ReadFile(#PB_Any,file)
  If fn 
    ReadData(fn,@*this\keys\Ksecret,32)
    ReadData(fn,@*this\keys\kBase,32)
    ReadData(fn,@*this\keys\Kpublic,32) 
    CloseFile(fn) 
    For a=0 To 31
      sout+ RSet(Hex(*this\keys\Kpublic[a],#PB_Byte),2,"0")
    Next  
    ProcedureReturn sout 
  EndIf 
EndProcedure   

Procedure.s EC_GetKey(*this.EC,public.s) 
   Protected sout.s ,a.i,*mem,*key.Ascii,b  
   *mem = AllocateMemory(32) 
   *key= *mem 
   For a = 1 To 64 Step 2
      *key\a = Val("$"+Mid(public,a,2))
      *key\a ! *this\salt[b] 
      *key+1
      b+1
   Next 
   curve25519_donna(@*this\keys\Kshared,@*this\keys\Ksecret,*mem)
   For a=0 To 31
      sout+ RSet(Hex(*this\keys\Kshared[a],#PB_Byte),2,"0")
   Next  
   FreeMemory(*mem) 
   ProcedureReturn sout 
EndProcedure   

Procedure EC_Free(*this.EC) 
   FreeMemory(*this)
EndProcedure   
;-Curve validation code for testing purposes 
CompilerIf #UseValidation
   ;Test procedure for validation of the curve 
   Procedure.i Validation(*mypublic.u8, *secret.u8, *basepoint.u8)
      Dim bp.q(10)
      Dim x.q(10)
      Dim z.q(10)
      Dim zmone.q(10)
      Dim e.a(32)
      
      Protected i
      
      i = 0
      While i < 32
         e(i) = *secret\a[i]
         i + 1
      Wend
      
      fexpand(@bp(), *basepoint)
      cmult(@x(), @z(), @e(), @bp())
      crecip(@zmone(), @z())
      fmul(@z(), @x(), @zmone())
      fcontract(*mypublic, @z())
      ProcedureReturn 0
   EndProcedure
   ;
   Procedure validate()
      ;validation test of curve25519 
      
      Protected i,loop
      Protected et,st 
      
      st=ElapsedMilliseconds() 
      Protected Dim e1.a(31)
      Protected Dim e2.a(31)
      Protected Dim k.a(31)
      Protected Dim e1k.a(31)
      Protected Dim e2k.a(31)
      Protected Dim e1e2k.a(31)
      Protected Dim e2e1k.a(31)
      Protected Dim expp.a(31)
      
      e1(0) = 3
      e2(0) = 5
      k(0)  = 9
      
      expp( 0) = $be:expp( 1) = $4c:expp( 2) = $62:expp( 3) = $08:expp( 4) = $29:expp( 5) = $3f:expp( 6) = $81:expp( 7) = $1a
      expp( 8) = $15:expp( 9) = $4b:expp(10) = $9c:expp(11) = $42:expp(12) = $f7:expp(13) = $87:expp(14) = $dd:expp(15) = $90
      expp(16) = $9f:expp(17) = $07:expp(18) = $5c:expp(19) = $61:expp(20) = $1b:expp(21) = $82:expp(22) = $c3:expp(23) = $03
      expp(24) = $50:expp(25) = $ed:expp(26) = $c9:expp(27) = $fe:expp(28) = $6e:expp(29) = $83:expp(30) = $ad:expp(31) = $4a
      
      For loop=0 To 9
         Validation(@e1k(),  @e1(),  @k())
         Validation(@e2e1k(),@e2(),  @e1k())
         Validation(@e2k(),  @e2(),  @k())
         Validation(@e1e2k(),@e1(),  @e2k())
         
         For i=0 To 31
            If e1e2k(i) <> e2e1k(i)
               
               ProcedureReturn #False
            EndIf
         Next
         
         For i=0 To 31 : e1(i) = e1(i) ! e2k(i)   : Next i
         For i=0 To 31 : e2(i) = e2(i) ! e1k(i)   : Next i
         For i=0 To 31 : k (i) = k (i) ! e1e2k(i) : Next i
         
      Next loop
      
      For i=0 To 31
         If e1e2k(i) <> expp(i)
            
            ProcedureReturn #False
         EndIf
      Next
      
      et=ElapsedMilliseconds() 
      ProcedureReturn et-st ;#True
      
   EndProcedure   
CompilerEndIf 
;-end of validation code 

DataSection  : EC_vt: 
   Data.i @EC_Genkeys()
   Data.i @EC_GetKey()
   Data.i @EC_SaveKeys() 
   Data.i @EC_LoadKeys()
   Data.i @EC_Free() 
EndDataSection 

EndModule 

CompilerIf #PB_Compiler_IsMainFile
  
  CompilerIf #PB_Compiler_Backend = #PB_Backend_C 
    !//gccflags -O3 -mavx ;
    !//UseClang ;  
  CompilerEndIf 
  
   Define.modEC::iEC  client,server,man_client,man_server 
   Global clients_public_key.s, clients_shared_secret.s, servers_public_key.s,servers_shared_secret.s
   Global man_client_public_key.s,man_client_shared_secret.s,verify.s
   Global man_server_public_key.s,man_Server_shared_secret.s   
   
   OpenConsole()
   ConsoleTitle("Curve25519 Test")
   
   client = modEC::NewEC("salt n pepper")  ;Create new EC context with out of channel passphrase 
   server  = modEC::NewEC("salt n pepper") 
   
   clients_public_key = client\GenKeys()   ;Client generates keys  -> sends the public key  to server 
   servers_public_key = server\GenKeys()  ; Server generates keys -> returns the public key to client  
   
   client\SaveKeys("EC_Keys")   ;test save: saves the whole keyset    
   clients_public_key = client\LoadKeys("EC_Keys") ;loads a whole key set and returns the public key  
      
   PrintN("servers public key:" + servers_public_key)
   PrintN("clients public  key:" + clients_public_key)    
   
   Clients_shared_secret = client\getkey(servers_public_key)  ;Client plugs in the servers public key to get the secret encyption key   
   Servers_shared_secret = server\getkey(clients_public_key)  ;Server plugs in the Clients public key to get the secret encryption key 
   
   ;from this point the client and server can now use the encyption key to transfer encypted data to perform a log in...  
   ;the pass phrase mitigates the risk of a man in the middle attack
   
   PrintN("clients encryption key : " + clients_shared_secret)    
   PrintN("servers encyrption key : " + servers_shared_secret) 
      
   If clients_shared_secret = servers_shared_secret 
      PrintN("keys equal")
   Else
      PrintN("keys failed")
   EndIf
   
   client\free()
   server\Free() 
   
   ;Simulate a man in the middle attack without salt the process will succeed 
   PrintN("")
   PrintN("simulate man in the middle attack without a salt the process will succeed")
   
   client = modEC::NewEC("")   ;create a new EC context without a pass phrase 
   server  = modEC::NewEC("")
   man_client = modEC::newEC("")    ;man in the middle creates EC contexts between client and server 
   man_server = modEC::newEC("")
   
   clients_public_key = client\GenKeys()   ;Client generates keys  -> sends the public key  to server  but will get intercepted by man in middle 
   servers_public_key = server\GenKeys()  ; Server generates keys -> returns the public key but will get intercepted by man in middle   
   man_client_public_key = man_client\Genkeys()   ;man in middle creates key for the client  
   man_server_public_key = man_server\Genkeys()  ;man in middle creates key for server 
   
   Clients_shared_secret = client\getkey(man_client_public_key)  ;Client recieves man in middle key    
   man_client_shared_secret = man_client\GetKey(clients_public_key)   ; man gets shared secret with client   
   
   man_Server_shared_secret  = man_server\GetKey(servers_public_key)   ;man get's servers shared secret  
   Servers_shared_secret = server\Getkey(man_server_public_key)  ;Server gets mans shared secret  
      
   PrintN("clients shared secret: " + clients_shared_secret) 
   PrintN("man in middle secret: " + man_client_shared_secret)  
   
   If clients_shared_secret = man_client_shared_secret 
      PrintN("keys equal")
   Else
      PrintN("keys failed")
   EndIf
   
   
   PrintN("server shared secret: " + servers_shared_secret)
   PrintN("man in middle secret: " + man_Server_shared_secret)
   
   If servers_shared_secret = man_Server_shared_secret 
      PrintN("keys equal")
   Else
      PrintN("keys failed")
   EndIf
   
   client\Free()
   server\Free()
   man_client\Free()
   man_server\Free()
   
   ;simulate man in the middle attack with salt the process will fail 
   PrintN("")
   PrintN("simulate man in the middle attack wit salt the process will fail")
   
   client = modEC::NewEC("salt n pepper")   ;create a new EC context with an out of channel pass phrase which is only known to client and server know 
   server  = modEC::NewEC("salt n pepper")
   man_client = modEC::newEC("")    ;man in the middle creates EC contexts between client and server 
   man_server = modEC::newEC("")
   
   clients_public_key = client\GenKeys()   ;Client generates keys  -> sends the public key  to server  but will get intercepted by man in middle 
   servers_public_key = server\GenKeys()  ; Server generates keys -> returns the public key but will get intercepted by man in middle   
   man_client_public_key = man_client\Genkeys()   ;man in middle creates key for the client  
   man_server_public_key = man_server\Genkeys()  ;man in middle creates key for server 
   
   Clients_shared_secret = client\getkey(man_client_public_key)  ;Client recieves man in middle key    
   man_client_shared_secret = man_client\GetKey(clients_public_key)   ; man gets shared secret with client   
   
   man_Server_shared_secret  = man_server\Getkey(servers_public_key)   ;man get's servers shared secret  
   Servers_shared_secret = server\Getkey(man_server_public_key)  ;Server gets mans shared secret  
   
   
   PrintN("clients shared secret: " + clients_shared_secret) 
   PrintN("man in middle secret: " + man_client_shared_secret)  
   
   If clients_shared_secret = man_client_shared_secret 
      PrintN("keys equal")
   Else
      PrintN("keys failed")
   EndIf
   
   
   PrintN("server shared secret: " + servers_shared_secret)
   PrintN("man in middle secret: " + man_Server_shared_secret)
   
   If servers_shared_secret = man_Server_shared_secret 
      PrintN("keys equal")
   Else
      PrintN("keys failed")
   EndIf
   
   client\Free()
   server\Free()
        
   man_client\Free()
   man_server\Free()
   
   PrintN("")
   PrintN("Do validation test")
   Global validate 
   validate = modEC::validate() 
   If validate 
      PrintN("validated in " + validate)
   Else 
      PrintN("failed")
   EndIf     
   
   
   PrintN("")
   PrintN("PRESS 'RETURN' TO QUIT.")
   Input()
   CloseConsole()
   
CompilerEndIf 
User avatar
skywalk
Addict
Addict
Posts: 3972
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: PureBasic 6.00 Beta 5 released !

Post by skywalk »

Yes, it's pretty clear c+optimizer shrinks the "what language did you use" debate. :wink:
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
Post Reply