Array output in Messagerequester - one time pad example

Just starting out? Need help? Post your questions and find answers here.
Eggy
New User
New User
Posts: 5
Joined: Sun Feb 04, 2018 9:43 pm

Array output in Messagerequester - one time pad example

Post by Eggy »

I have just returned to Purebasic after many years away in my Amiga days!

I had a one-time pad (OTP) example I did in the J progamming language, so I thought I would translate it to PB to learn. The code below uses MessageRequester for debugging and checking. I will use windows and gadgets in the next iteration.

I have a few questions about the code.

1. How do I print the whole array in the message box without unrolling it in a For loop like I do in the body of the code? I've tried just '()', trying to cast an array to a string, but I don't know how, and at last just using a single element of the array show it works.

2. Is it worth wrapping the for loops in Procedures for portability? peformance?

3. I like tacit programming. Is there a way to do it in a functional or tacit way within PB's procedural programming?

One-time pads if implemented correctly are very secure. This however is just a learning exercise to see the modular arithmetic in use. A true OTP was based upon the key text being written down a paper pads with truly generated letters or numbers, and disposed of once used, and not re-used for another message. The key text has to be at least the length of the message text. The hard part is getting the one-time pad (physical or otherwise) to your recipient in the first place. Using an agreed upon book or text of literature is called something else.

Here's the PB code so far:

Code: Select all

Message$ = InputRequester("Message", "Your message - ALL CAPS:", "MESSAGE")

Keytext$ = InputRequester("Key Text", "Type in the KEY - ALL CAPS:","KEYTEXT")

Index.b = Len(Message$)
Divisor.i = 26 ; MOD 26

Dim Encipher.s(Index.b)

For l = 1 To Index.b
  Enc1.i = (Asc(Mid(Message$, l, 1))) + (Asc(Mid(Keytext$, l, 1)))
  Encipher.s(l) = Chr(((((Enc1.i % Divisor.i) + Divisor.i)) % Divisor.i) + 65)  ; Chain MOD to account for negative numbers
Next

Dim Decipher.s(Index.b)

MessageRequester("Enciphered!", Encipher.s(1), #PB_MessageRequester_Ok)

For i = 1 To Index.b
  Dec1.i = (Asc((Encipher.s(i))) - (Asc(Mid(Keytext$, i, 1))))
  Decipher.s(i) = Chr(((((Dec1.i % Divisor.i) + Divisor.i)) % Divisor.i) + 65)  ; Chain MOD to account for negative numbers
Next

MessageRequester("Deciphered!", Decipher.s(1), #PB_MessageRequester_Ok)
Here's the J programming code for example of terseness:

Code: Select all

Az=: a. {~ 65 +/ i.26
Mtxt=: 'THATSNOTHELPINGME'
Mn=: >: Az i. Mtxt
Kn=: ?(# Mtxt)#26
Ktxt=: Kn { Az
Cn=: 26 | (Mn + Kn)
Ctxt=: Cn { Az
Dn=: 26 | (Cn - Kn)
Dtxt=: (Dn - 1) { Az

4 3 $ 'Mtxt' ; Mtxt ; Mn ; 'Ktxt' ; Ktxt ; Kn ; 'Ctxt' ; Ctxt ; Cn ; 'Dtxt' ; Dtxt ; Dn
The J code creates a pseudo-random key text (Kn) the same length as the message text (Mtxt), and it prints the message, key text, enciphered text, and the deciphered text to the interpreter for demonstration purposes.

I would welcome any tips and suggestions and comments. Thanks! So excited to be back to basics, Purebasic!
User avatar
Demivec
Addict
Addict
Posts: 4091
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: Array output in Messagerequester - one time pad example

Post by Demivec »

Welcome back. :)

You may find the RosettaStone site helpful to see various tasks written in many different computer languages, including PureBasic and J.

http://rosettacode.org/wiki/Category:PureBasic
Eggy
New User
New User
Posts: 5
Joined: Sun Feb 04, 2018 9:43 pm

Re: Array output in Messagerequester - one time pad examplea

Post by Eggy »

Thanks!

Yes, I use rosettacode a lot for comparing and learning programming languages.

The heart of my post was about how to have an array display in MessageRequester. I tried many ways to show all of the array, but I could not. I thought maybe recasting the array to a string or list might work, but could not figure out how. I tried. I know with more refresher coding I will re-learn the ins-and-outs of PB.

I'll keep trying.
infratec
Always Here
Always Here
Posts: 6871
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Array output in Messagerequester - one time pad example

Post by infratec »

Hi,

the MessageRequester is not usable for that. But that's no restriction from PB, it's from Windows.

If you want to debug... uset the Debug output:

Code: Select all

Message$ = InputRequester("Message", "Your message - ALL CAPS:", "MESSAGE")

Keytext$ = InputRequester("Key Text", "Type in the KEY - ALL CAPS:","KEYTEXT")

Index.b = Len(Message$)
Divisor.i = 26 ; MOD 26

Dim Encipher.s(Index.b)

Debug "Encipher"
For l = 1 To Index.b
  Enc1.i = (Asc(Mid(Message$, l, 1))) + (Asc(Mid(Keytext$, l, 1)))
  Encipher.s(l) = Chr(((((Enc1.i % Divisor.i) + Divisor.i)) % Divisor.i) + 65)  ; Chain MOD to account for negative numbers
  Debug Encipher.s(l)
Next

Dim Decipher.s(Index.b)

Debug ""


Debug "Decipher"
For i = 1 To Index.b
  Dec1.i = (Asc((Encipher.s(i))) - (Asc(Mid(Keytext$, i, 1))))
  Decipher.s(i) = Chr(((((Dec1.i % Divisor.i) + Divisor.i)) % Divisor.i) + 65)  ; Chain MOD to account for negative numbers
  Debug Decipher.s(i)
Next

Bernd
#NULL
Addict
Addict
Posts: 1440
Joined: Thu Aug 30, 2007 11:54 pm
Location: right here

Re: Array output in Messagerequester - one time pad example

Post by #NULL »

How do I print the whole array in the message box without unrolling it in a For loop like I do in the body of the code? I've tried just '()', trying to cast an array to a string, but I don't know how, and at last just using a single element of the array show it works.
There is nothing like a print_r() function or .toString() mechanism in PureBasic to do that automatically, so you basically have to loop over the array and sum up a string.

Code: Select all

txt.s = ""
For i = 1 To Index.b
  txt + Decipher(i) + #CRLF$
Next
Debug txt
MessageRequester("Deciphered!", txt, #PB_MessageRequester_Ok)
If you put such code in a function the function would be specific to a particular element type because the array has to be passed with the array/element type known at compile.

Code: Select all

Procedure.s join(Array arr.s(1), str.s = #CRLF$) ; (1 = one dimension)
  Protected joined.s = ""
  Protected i
  Protected arrLen = ArraySize(arr())
  For i = 0 To arrLen
    joined + arr(i) + #CRLF$
    ;joined + Str(arr(i)) + #CRLF$  ; (if arr() had type .i)
  Next
  ProcedureReturn joined
EndProcedure

Debug join(Decipher())
MessageRequester("Deciphered!", join(Decipher()), #PB_MessageRequester_Ok)
Eggy
New User
New User
Posts: 5
Joined: Sun Feb 04, 2018 9:43 pm

Re: Array output in Messagerequester - one time pad example

Post by Eggy »

Thank you infratec. That saves me time trying to make that work without debug. Interesting it is a Windows limitation.

#NULL that works fine for now. I will eventually make a window with a gadget to display the text and buttons.

PB is a strange trip down memory lane for me, and yet the inline asm and other low-level aspects of it are exciting its future potential for my use. I am learning Zig for my C replacement, but PB is taking my time now.
Eggy
New User
New User
Posts: 5
Joined: Sun Feb 04, 2018 9:43 pm

Re: Array output in Messagerequester - one time pad example

Post by Eggy »

So now I am making a form for the program, and I have run into a seeming contradiction. I can make string gadgets, and using #PB_String_UpperCase, but if I name the variable Message$, I get a 'can't write a numeric value into a string value'. In my pb file, I have Message$, so how can I pass the input from the form to the program? I am working out the XExternal bit I need in the form.

form code:

Code: Select all

;
; This code is automatically generated by the FormDesigner.
; Manual modification is possible to adjust existing commands, but anything else will be dropped when the code is compiled.
; Event procedures needs to be put in another source file.
;

Global Window_0

Global Message, Keytext, Text_1, Text_2, Crypttext, Text_3, Button_0, Button_1


Procedure OpenWindow_0(x = 0, y = 0, width = 400, height = 400)
  Window_0 = OpenWindow(#PB_Any, x, y, width, height, "OTP by Eggy", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window_ScreenCentered)
  Message = StringGadget(#PB_Any, 150, 20, 220, 70, "", #PB_String_UpperCase)
  Keytext = StringGadget(#PB_Any, 150, 110, 220, 70, "", #PB_String_UpperCase)
  Text_1 = TextGadget(#PB_Any, 50, 40, 80, 20, "MESSAGE", #PB_Text_Center | #PB_Text_Border)
  Text_2 = TextGadget(#PB_Any, 50, 130, 80, 20, "KEY TEXT", #PB_Text_Center | #PB_Text_Border)
  Crypttext = StringGadget(#PB_Any, 150, 200, 220, 65, "", #PB_String_UpperCase)
  Text_3 = TextGadget(#PB_Any, 50, 220, 80, 25, "CRYPT TEXT", #PB_Text_Center | #PB_Text_Border)
  Button_0 = ButtonGadget(#PB_Any, 40, 310, 100, 25, "ENCIPHER")
  Button_1 = ButtonGadget(#PB_Any, 250, 310, 100, 25, "DECIPHER")
EndProcedure

Procedure Window_0_Events(event)
  Select event
    Case #PB_Event_CloseWindow
      ProcedureReturn #False

    Case #PB_Event_Menu
      Select EventMenu()
      EndSelect

    Case #PB_Event_Gadget
      Select EventGadget()
      EndSelect
  EndSelect
  ProcedureReturn #True
EndProcedure

Here is my program code, which is pretty much the code I posted in the original post, however, I have tried to put all into procedures for modularity and reusability:

Code: Select all


Global Divisor.i = 26 ; MOD 26

Procedure.s Encipher(Message$, Keytext$)
  
  Protected Index.b, txte.s
  
  Index.b = Len(Message$)
  
  Dim Encrypt.s(Index.b)
  
  For l = 1 To Index
    Enc1.i = (Asc(Mid(Message$, l, 1))) + (Asc(Mid(Keytext$, l, 1)))
    Encrypt.s(l) = Chr(((((Enc1.i % Divisor.i) + Divisor.i)) % Divisor.i) + 65)  ; Chain MOD to account for negative numbers
    txte.s = ""
    txte + Encrypt.s(l)
    Debug txte
  Next
  ProcedureReturn txte
  
EndProcedure

Procedure.s Decipher(Crypttext$, Keytext$)

  Protected Index.b, txtd.s
  
  Index.b = Len(Message$)

  Dim Decrypt.s(Indexd.b)

  For i = 1 To Indexd.b
    Dec1.i = (Asc(Mid(Cryptext$, i, 1))) - (Asc(Mid(Keytext$, i, 1)))
    Decrypt.s(i) = Chr(((((Dec1.i % Divisor.i) + Divisor.i)) % Divisor.i) + 65)  ; Chain MOD to account for negative numbers
    txtd.s = ""
    txtd + Decrypt.s(i)
    Debug txtd
  Next
  ProcedureReturn txtd
  
EndProcedure
Thanks for any assistance you may lend!

PellesC ad PureBasic are putting me back to 1978, and it feels good!
Eggy
New User
New User
Posts: 5
Joined: Sun Feb 04, 2018 9:43 pm

Re: Array output in Messagerequester - one time pad example

Post by Eggy »

Never mind. I just found the excellent tutorial in the Form Designer index! Thanks to all.
Post Reply