PureBasic 6.00 released !
Re: PureBasic 6.00 Beta 5 released !
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.
Re: PureBasic 6.00 Beta 5 released !
Its only aviable for macOSUser_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?
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
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Re: PureBasic 6.00 Beta 5 released !
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)?
Re: PureBasic 6.00 Beta 5 released !
Consider this:
If the map element "Test" doesn't exists, it will return NULL, and then the \Name accessor will crash your program (IMA).
Code: Select all
If YourMap("Test")\Name = "Timo" : EndIf
-
- Addict
- Posts: 1443
- Joined: Wed Nov 12, 2008 5:01 pm
- Location: Russia
Re: PureBasic 6.00 Beta 5 released !
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?
On my system, I get:
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?
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)
- 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)
Last edited by nsstudios on Tue Mar 08, 2022 8:09 am, edited 1 time in total.
Re: PureBasic 6.00 Beta 5 released !
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
Re: PureBasic 6.00 Beta 5 released !
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.
Re: PureBasic 6.00 Beta 5 released !
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
PB 6.0x, PureVision User.
Re: PureBasic 6.00 Beta 5 released !
WTF do you have for a PC???? I have a Ryzen 9 5950X with ~5GHz and still have around 6 seconds runtimeskywalk wrote: ↑Tue Mar 08, 2022 4:13 am You forgot to disable debugger. C+optimize is fastest.Code: Select all
... 1327, 1356, diff: 29 ...
Re: PureBasic 6.00 Beta 5 released !
He just set #cycles to 1000000?Cyllceaux wrote: ↑Tue Mar 08, 2022 8:58 amWTF do you have for a PC???? I have a Ryzen 9 5950X with ~5GHz and still have around 6 seconds runtimeskywalk wrote: ↑Tue Mar 08, 2022 4:13 am You forgot to disable debugger. C+optimize is fastest.Code: Select all
... 1327, 1356, diff: 29 ...
- Mindphazer
- Enthusiast
- Posts: 344
- Joined: Mon Sep 10, 2012 10:41 am
- Location: Savoie
Re: PureBasic 6.00 Beta 5 released !
Don't forget it's still a beta versionUser_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!
MacBook Pro 14" M1 Pro - 16 Gb - MacOS 14 - Iphone 15 Pro Max - iPad at home
...and unfortunately... Windows at work...
...and unfortunately... Windows at work...
Re: PureBasic 6.00 Beta 5 released !
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
Re: PureBasic 6.00 Beta 5 released !
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
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
Re: PureBasic 6.00 Beta 5 released !
Yes, it's pretty clear c+optimizer shrinks the "what language did you use" debate.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum