bdcalc - a calculator for large natural numbers
bdcalc is a command-line calculator and mini-programming language that works with very large unsigned integers,
the natural numbers ℕ = { 0,1,2,…} used to carry out computations in cryptography.
The numbers can theoretically be of unlimited size.
bdcalc has built-in functions
to carry out number theoretical computations such as modular exponentiation and modular inversion, as
used in the RSA and Diffie-Hellman algorithms. You can generate random prime numbers of a given bit length and
test for primality.
bdcalc provides a mini-programming environment with assignments to stored variables, conditional statements (if-then-else)
and control loops (for, while, repeat). See Control Flow Statments.
You can use bdcalc in interactive mode, typing commands on the console until you type quit to exit.
Alternatively you can read input directly from a script file using the -file option;
or you can enter your input in one line on the command line, perhaps as part of a batch file.
Contents
1 A quick introduction
2 A compact summary
3 Functions
3.1 Built-in functions
3.2 Notes
3.3 Examples of functions in use
3.3.1 Greatest common divisor, gcd
3.3.2 Modular inverse, modinv
3.3.3 Integer logarithm to base 2
3.3.4 Jacobi and Legendre symbol
3.3.5 Powers of 2 and shift-left
3.3.6 modpowof2
3.3.7 setbit and getbit
3.3.8 compl
3.3.9 randbits and genprime
3.3.10 sha1 and sha256
3.3.11 Byte manipulation functions
3.3.12 fillbytes()
3.4 Integers, bytes, bit strings and bit length
4 Displaying values
4.1 The printf() function
4.2 Verbose mode and showhex
5 Control flow statements
5.1 Conditional statements: if-then-fi and if-then-else-fi
5.2 Loops: while and repeat
5.3 Loops: for-do-done
6 Strings
6.1 Escape sequences
7 Expressions and operators
7.1 Arithmetic and bitwise expressions
7.2 Relational and equality operators
7.3 Logical expressions and logical operators
8 Saving and restoring session variables
8.1 The save and restore statements
9 System-related statements
9.1 The system statement
9.2 The getcwd statement
9.3 The chdir statement
10 Miscellaneous statements
10.1 The quit statement
10.2 The help statement
10.3 The version statement
10.4 The prompt statement
11 Script files
11.1 The -file command-line option
11.2 The load statement
11.3 Example scripts
11.4 Example script: Finding a quadratic residue
11.5 The assert statement
11.6 The exit(N) statement
12 The command line
12.1 Command-line syntax
12.2 Entering statements on the command line
13 Errors and error messages
13.1 Common errors
14 Using on a Linux platform
14.1 Funny characters appear when using the arrow keys
15 Reserved keywords
16 Revision history
17 About this document
1 A quick introduction
bdcalc lets you assign numbers to variables, do arithmetic and call functions in the way you would expect.
> a=99
99
> b=a*11
1089
> ? a+b
1188
> println("a=",a," b=",b)
a=99 b=1089
> p=genprime(128)
187188849449410847765185120249130623559
> !p
0x8cd342d39544246b9743c7b68d5da247
> bitlen(p)
128
> ??isprime(p)
true
Each line of input is evaluated as soon as the `Enter' key is pressed.
To type multiple statements on one line, separate with semicolon characters (;).
> x=1;y=2;z=x+y;?z
3
2 A compact summary
We know no one actually reads the manual, so here is a very brief summary of just about everything.
If something needs more explanation, see the later section.
Numbers in bdcalc are unsigned integers of arbitrary length represented by default in decimal format.
Precede a number by "0x" to specify in hexadecimal and by "0xb" to specify in binary (a string of `1's and `0's).
17 618970019642690137449562111 0x11 0b10001
Strings are used only for printing and are enclosed either in single or double quotes 'abc' "hello, world!".
Escape sequences like \n can be used inside strings to represent control characters.
More details in the Strings section.
A variable name can be any combination of letters, numbers and underscore characters, but the first character must be a letter.
Variable names are case sensitive.
Reserved keywords cannot be used as variable names.
Use an assignment to store a value in a variable, e.g. a = 42.
Variables are mutable and are zero unless assigned to. Only numbers can be stored.
A single statement is terminated by a newline character (i.e. pressing the `Enter' key).
To type multiple statements on one line, separate with semicolon characters (;).
Use a backslash (\) to continue a single statement on more than one line.
All expressions evaluate to a number. Typing a valid expression will display its value.
Expressions can contain the arithmetic operators: + to add, * to multiply, - to subtract,
and / to divide, along with parentheses (...). Only natural (unsigned) integers are permitted,
so no negative numbers, fractions or floating-point numbers.
Subtraction is cut-off subtraction where the result is always zero or more.
Division is integer division in which the fractional part is discarded.
The operator div is a synonym for /.
The mod operator as in a mod b gives the remainder when a is divided by b.
Use the % operator as a synonym for mod.
Use x++ and x-- to increment and decrement the value of a variable (subject to cut-off at zero).
The bitwise expressions a << n and a >> n perform bitwise left and right shifts, respectively,
of a by n bits.
Use the bitwise operators &, ∧ and | to perform
bitwise AND, XOR and OR of two numbers, respectively (converting them
both to bitstrings beforehand, padded with zero bits to the left if necessary).
The operators shl, shr, band, bxor and bor are synonyms for these bitwise operators.
To invert the bits in a number use the compl() function.
logical expressions are used in comparison operations.
An expression A is false if A is equal to zero; otherwise it is true.
A logical expression returns 1 if it is true and 0 if false.
Use the keywords true and false to represent true and false, e.g. B = true.
Construct logical expressions using the comparison operators == `equal to', <= `less than or equal to', != `not equal to',
>= `greater than or equal to', < `less than' and > `greater than'.
Use the logical operators and (&&), or (||) and xor to
specify multiple conditions for a logical expression, or not to negate a condition.
The statement ?X displays the single number or string X followed by a newline.
To display a number X in hexadecimal use !X and in
binary use `X (the backtick character).
To display the result of a logical expression as true or false use ??A.
Synonymns for these quick-print statements are
puts X, puthex X, putbin X and putbool X.
The function println(S,T,...) displays the numbers or strings in the list S,T,... followed by a newline.
The print() functions does the same except without the newline character. Numbers are displayed by default in decimal.
To format a number X inside a print list, use the special functions hex(X), bin(X) or bool(X).
These special functions only work inside a print list.
For more advanced output, use the printf("format",S,T,...) function, which outputs a formatted string according to
the `format' string with number or string arguments S,T,....
The format string is of the form %[flags][width][.precision]specifier similar to that in C and Java,
except without the + flag.
Use %d and %s to display numbers and strings,
and %x, %b and %q to display the value of a number in hexadecimal, binary and boolean, respectively.
There are more details in the printf() section
The conditional statements
if B then <stmts> fi
if B then <stmts1> else <stmts2> fi
define code to be executed if a specified condition is true.
The <stmts> blocks can contain multiple statements separated by semicolons.
Don't forget the fi keyword!
The while statement
while B do <stmts> done
loops through <stmts> while the logical condition B is true.
The repeat statement
repeat <stmts> until B
loops through <stmts> until B is true.
The for statement
for X in (M,N,...,W) do <stmts> done
loops through <stmts> for each value X in the comma-separated list M,N,...,W.
The "for-X-in-a-range" loop
for X in (M..N) do <stmts> done
loops through <stmts> with the variable X incrementing (or decrementing)
by one each time in the range M to N.
Use the range operator .. literally as in (2..7).
You can break a "for-X-in-a-range" loop with
for X in (M..N) do <stmts> breakif B done
which breaks if condition B is true.
The breakif B statement can only be used as the last expression before the done keyword.
The built-in functions take arguments as specified in the Functions section.
Most functions require an exact number of arguments, but some will take a list,
e.g.
gcd(27,81,90,243)
The names of all built-in functions are in lower case letters.
Use the define statement to create user-defined functions.
The statement
define cube(x) = x*x*x
defines a function cube() that takes one argument and returns its cube.
A comment starts with either a # character or the // pair. Everything following on the
line is treated as a comment and ignored. Use comments in script files.
# This is a comment
a = 42 // this text is ignored
A script file is a plain ASCII text document containing valid statements, which are executed in order.
Statements can be terminated by a newline character or semicolon.
The statements in if-then-else and for, while and repeat loops can be broken and indented without using a
backslash continuation character,
but each statement in the <stmts> block must be terminated by a semicolon. The first part of the statement up to the do
keyword must be on one line.
Use the assert(B) or assert(B, 'msg') statement to terminate a script file if a given condition is false.
The exit(N) statement will terminate the script at the next available opportunity and return the value N to the operating system.
Using exit(N) in interactive mode will terminate the session.
Use load 'filename' to run a script in interactive mode.
The help statement will display a list of topics for which help is available.
help keyword will display help on a given keyword
(Changed in v2.2: quotes are no longer required around the keyword).
Use version to display details about the current version of bdcalc.
The statement system "string" will pass the command string to the operating system, e.g. system "dir".
Use getcwd to find the current working directory and chdir "path" to change it.
Use prompt "string" to change the interactive prompt to string. Use save to save the values of all current
variables to a file and restore to restore them.
The statement verbose off will turn off the display of values after typing a statement.
verbose on turns it back on.
The statement showhex on will display the "verbose" values in hexadecimal.
showhex off reverts back to displaying in the default decimal.
3 Functions
3.1 Built-in functions
The following functions are built in. All keywords are in lower-case.
The parameters X, Y, M, B,
n represent expressions which evaluate to large integers of theoretically unlimited size,
but n is expected to be "small".
Function | Returns | Remarks |
bitlen(X) | the bit length l of the integer X | 2l−1 ≤ x < 2l |
bytelen(X) | the length L of integer X in bytes | |
cbrt(X) | the truncated integer cube root of X | ⎣√{x} ⎦ |
compl(X,n) | the bitwise NOT of the rightmost n bits of X | |
fillbytes(n,b) | an integer of n bytes each set to b mod 256 | |
gcd(X,Y,Z,...) | the greatest common divisor of X,Y,Z,... | |
genprime(n) | a random prime p of length exactly n bits | 2n−1 ≤ p < 2n |
getbit(X,n) | value 0 or 1 of bit n of X =(bl−1…bn…b1b0) | |
getbyte(X,n) | value of byte n of X | |
iif(B,X,Y) | X if B is true, otherwise Y | [Note 1] |
isprime(X) | true if X is prime, otherwise false | [Note 2] |
jacobi(X,M) | the Jacobi symbol (X | M) in {0,1,2} | [Note 3] |
max(X,Y,Z,...) | the maximum of X,Y,Z,... | |
min(X,Y,Z,...) | the minimum of X,Y,Z,... | |
modexp(X,Y,M) | X raised to the power Y modulo M | xy mod m |
modinv(X,M) | the inverse of X modulo M | x−1 mod m |
modmul(X,Y,M) | X multiplied by Y modulo M | xy mod m |
modpowof2(X,n) | X with all bits cleared at positions ≥ n | x mod 2n |
pow(X,n) | X raised to the power n | xn |
prime(n) | the n-th prime number | 1 ≤ n ≤ 104 |
randbits(n) | a random integer r of length at most n bits | 0 ≤ r < 2n |
random(M) | an integer r generated at random from [0, M-1] | 0 ≤ r < M |
revbytes(X,[n]) | X as an n-byte integer with byte order reversed | |
setbit(X,n,b) | X =(bl−1…bn…b1b0) with bit n set to value b | b ∈ {0,1} |
setbyte(X,n,b) | X with byte n set to value b mod 256 | |
sha1(X,n) | the SHA-1 hash of the rightmost n bits of X | [Note 4] |
sha256(X,n) | the SHA-256 hash of the rightmost n bits of X | [Note 4] |
sqrt(X) | the truncated integer square root of X | ⎣√x ⎦ |
square(X) | the square of X | x2 |
3.2 Notes
- The iif(B,X,Y) function evaluates both arguments X and Y before returning.
If you don't want this behaviour, use the if-then-else statement.
- The functions isprime() and genprime() test for primality by using 64 iterations of the Rabin-Miller algorithm,
which gives a probability of error no greater than 2−128.
- The jacobi() function returns 2 instead of the usual −1, since we cannot represent negative numbers.
See Jacobi and Legendre symbol.
-
Strictly speaking, sha1(X,n) and sha256(X,n) convert the integer X to a bit string of n bits,
padding to the left with zeros if necessary, compute
the hash of this bit string, convert the 160-bit digest value back into an integer, and return this integer.
3.3 Examples of functions in use
Really useful examples use large numbers typically one or two thousand bits long.
Unfortunately these make for tedious reading in a manual, so the examples here use small numbers to illustrate the functions.
Some of the examples are perhaps a bit silly, but hopefully illustrate the core principle of the function concerned.
3.3.1 Greatest common divisor, gcd
The greatest common divisor (gcd) of 527=17×31 and 1003=17×59 is 17.
> gcd(527,1003)
17
If p,q,r are distinct primes, then the gcd of u=pq and v=pr is p.
> p=genprime(128)
> q=genprime(128)
> r=genprime(128)
> p;q;r
177567251864897131063391792740453364899
225909525713785216246109438136117714037
258078597510856248545436006399384610151
> u=p*q
> v=p*r
> g=gcd(u,v)
> g
177567251864897131063391792740453364899
> println("g==p is ",bool(g==p))
g==p is true
3.3.2 Modular inverse, modinv
One property of a modular inverse is as follows:
if p is a prime, and u=pm−1 for some integer m, then w, the inverse of u modulo p, equals p−1 and
wu mod p equals one.
> p = 177567251864897131063391792740453364899
177567251864897131063391792740453364899
> m=random(1<<32)
> m
2205954264
> u=p*m - 1
> u
391705236398131778190655979498407345592096979335
> w = modinv(u,p)
> w
177567251864897131063391792740453364898
> w*u mod p
1
3.3.3 Integer logarithm to base 2
To compute the "truncated integer logarithm" g to base 2 of the integer N, so that g=⎣log2 N⎦,
use the identity
For example, the integer logarithm to base 2 of all numbers in the range 32 to 63 is 5, but that of 64 is 6.
> for N in (32,33,62,63,64) do
g=bitlen(N)-1;println("N=",N," lg(N)=",g) done
N=32 lg(N)=5
N=33 lg(N)=5
N=62 lg(N)=5
N=63 lg(N)=5
N=64 lg(N)=6
3.3.4 Jacobi and Legendre symbol
The function jacobi(a,n) computes the Jacobi symbol (a | n), where the result 2 denotes the usual value of −1.
> jacobi(2813,9907)
1
> jacobi(1001,9907)
2
> jacobi(10000*9907,9907)
0
To work with products of Jacobi symbols, use the fact that 2 ≡ −1 mod 3 and reduce the final product modulo 3 to get the equivalent result, e.g.
−1×−1 = 1 ⇔ 2×2 = 4 ≡ 1 mod 3, and |
|
1×−1 = −1 ⇔ 1×2 = 2 ≡ −1 mod 3. |
|
If n is prime then the Jacobi symbol becomes the Legendre symbol.
In that case (a | n)=1 implies that a is a quadratic residue of n;
(a | n)=2 (usually −1) implies that a is a non-quadratic residue; and (a | n)=0 means that
a is a multiple of n.
In the example above, since 9907 is prime the result 1 means that 2813 is a quadratic residue of 9907; that is, there exists an integer x
such that x2 mod 9907=2813. The script file qr-find.bdscr described below shows how to find x
(Spoiler: the answer is x=3511).
3.3.5 Powers of 2 and shift-left
232 is equal to 1<<32 (or, should you prefer, 1 shl 32).
> !a=pow(2,32)
0x100000000
> ??a==1<<32
true
But using << is much faster.
3.3.6 modpowof2
Use modpowof2 to truncate a bitstring.
The function modpowof2(X,n) computes X mod 2n, which is equivalent to doing a bitwise AND of X with 2n−1,
which gives the rightmost n bits of X.
> !x = 0xdeadbeef01facade
0xdeadbeef01facade
> !modpowof2(x,24)
0xfacade
> !x mod (1<<24)
0xfacade
> !x band (1<<24)-1
0xfacade
3.3.7 setbit and getbit
Use setbit and getbit to set or find specific bits in a bitstring.
> a = setbit(0,15,1)|setbit(0,0,1)
> putbin a
0b1000000000000001
> bitlen(a)
16
> getbit(a,15)
1
> getbit(a,14)
0
> getbit(a,0)
1
3.3.8 compl
The compl(X,n) function returns the bitwise complement (i.e. the bitwise NOT) of the rightmost n bits
of X.
The value of X is padded out to the left with zero bits or truncated, if necessary, before complementing.
Note that the bitstring displayed by putbin does not show any leading zero bits.
> x=17
> `x
0b10001
> `compl(x,5)
0b1110
> `compl(x,6)
0b101110
> `compl(x,15)
0b111111111101110
3.3.9 randbits and genprime
Note that genprime(n) generates a random prime number of exactly n bits, so bit n-1 is always set
and the bit length of the result is always n.
But randbits(n) generates a random integer of length at most n bits, so the bit length of the result may or may
not be equal to n.
To ensure a random number of exactly n bits, either bitwise OR with 1<<(n-1) or use setbit to set bit n-1.
For example,
> n=128
> r = randbits(n)
> !r
0x54462a26347716a8cf6ee8c3c4fc20e
> bitlen(r)
123
> r = setbit(r,n-1,1)
> !r
0x854462a26347716a8cf6ee8c3c4fc20e
> bitlen(r)
128
> r = randbits(n) | 1<<(n-1)
> !r
0xaf456f1e4cc97de60abde8a2b667c8c4
> bitlen(r)
128
To ensure an odd random number, set the right-most bit using a bitwise OR with 1.
> r=randbits(128) | 0x1
> !r
0xae6f39f2e6225701338f8c77094ddf65
> r mod 2
1
3.3.10 sha1 and sha256
Use sha1(X,n) to compute the 160-bit SHA-1 hash (message digest) of a bit string
and sha256(X,n) to compute the 256-bit SHA-256 hash.
The n rightmost bits of X are hashed, suitably padded to the left with zero bits if needed.
You must specify the number of bits. In practice, n is usually a multiple of 8, representing whole bytes,
but the function will cope with an odd number of bits if that is what you want.
> !sha1(0x616263,24) # the 24-bit string representing ASCII "abc"
0xa9993e364706816aba3e25717850c26c9cd0d89d
> !sha1(0xa3,9) # the 9 bits '010100011'
0xf582fa68b71ecdf1dcfc4946019cf5a18225bd2
> !sha1(0b010100011, 9)
0xf582fa68b71ecdf1dcfc4946019cf5a18225bd2
> !sha1(0,0) # the empty string
0xda39a3ee5e6b4b0d3255bfef95601890afd80709
This example computes the SHA-256 digest of one million (1,000,000) repetitions of the character `a' (0x61).
Note the use of verbose off to avoid printing out the value of b (a huge number with 2.4 million digits).
> verbose off
> b = fillbytes(1000000, 0x61)
> ? bytelen(b)
1000000
> !sha256(b, bytelen(b)*8)
0xcdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0
3.3.11 Byte manipulation functions
The byte manipulation functions treat the integer X as an array of bytes in network ("big-endian") order.
The function bytelen(X) returns the length L of the integer X in bytes,
where L is the index of the left-most significant byte, numbered from 0 at the right.
Equivalently, the byte length of an integer X is defined as the smallest integer L satisfying X < 28L.
Use getbyte and setbyte to query and manipulate the individual bytes in an integer,
represented as a byte array, indexed from the right.
Use revbytes(X,n) to reverse the order of bytes, treating the integer X as an array of n bytes.
You can use this to represent a number in "little-endian" order.
> !a = 0xdeadbeef42
0xdeadbeef42
> bytelen(a)
5
> !getbyte(a,1)
0xef
> !b = setbyte(a,1,0x00)
0xdeadbe0042
> !revbytes(a,5)
0x42efbeadde
> !revbytes(a,2)
0x42ef
> !revbytes(a,7)
0x42efbeadde0000
Changed in v2.2: The n argument in revbytes is optional. If omitted it defaults to
bytelen(X).
> !a = 0xdeadbeef42
0xdeadbeef42
> !revbytes(a)
0x42efbeadde
Be careful, the default behaviour of revbytes(X) may not be what you want if the leading byte in X might be zero.
3.3.12 fillbytes()
Use fillbytes(n,b) to return an integer of n bytes each set to b mod 256. (New in v2.2.)
> !d = fillbytes(11,0x61)
0x6161616161616161616161
> bytelen(d)
11
3.4 Integers, bytes, bit strings and bit length
We blur a few distinctions between an integer and its corresponding bit string here, and implicitly assume a conversion between them
when it suits us to do so.
If (bl−1,…,b1,b0) represents a bit string with bi ∈ {0,1}, where bl−1 is the most significant bit
and b0 is the least significant bit, then the equivalent integer X is defined by
X = |
l−1 ∑
i=0
|
bi 2i = bl−1×2l−1 + …+ bi×2i + …+ b1 ×2 + b0 |
|
We adopt the convention of indexing the bits from right to left with the right-most bit numbered zero.
The bit length of an integer X is defined as the smallest integer l satisfying X < 2l.
Equivalently, the bit length of a bit string is the integer l where bl−1 is the left-most bit with value `1'.
Similarly, the byte manipulation functions treat the integer X as an array of bytes in network ("big-endian") order.
See Byte manipulation functions.
4 Displaying values
Type ?X to display a single number or string X followed by a newline.
> ? 2+3
5
> ? "hello world"
hello world
The function println(S,T,...) outputs the numbers or strings in the list S,T,... followed by a newline.
The print() function does the same except without the newline.
By default a space separator is inserted between each item in the list (Changed in v2.2: previously there was nothing).
> println("x=",42,"y=",43)
x= 42 y= 43
Use the setsep statement to change the default separator (New in v2.2).
> println(10,20,30)
10 20 30
> setsep ''
> println(10,20,30)
102030
> setsep ', '
> println(10,20,30)
10, 20, 30
The function printf("format",S,T,...) outputs a formatted string according to `format'
with a list of arguments S,T,....
See The printf() function.
To print a single number X in hexadecimal form, type !X. To print in binary form, use `X
(that's the backtick character (`)) and to print the boolean value true or false, use ??X.
These only work as "stand-alone" statements.
> a=17; ?a; !a; `a; ??a
17
0x11
0b10001
true
To format numbers inside a println() or print() function, use hex(), bin()
or bool(). These only work as part of a print list.
> a=33; println(a," in hex=",hex(a)," in binary=",bin(a))
33 in hex=0x21 in binary=0b100001
4.1 The printf() function
The printf() function provides a subset of the standard C print conversion specification
only for unsigned integers and strings.
%[flags][width][.precision]specifier
Format flags:
'-' = left justify
'#' = prefix (0x, 0X, 0b) on an (x, X, b) conversion
'0' = pad with leading zeros
(space and '+' not applicable)
[width][.precision]:
as per standard, including '*'
Conversion specifiers:
'd', 'i', 'u' = integer in decimal
'x' = integer in hexadecimal (lower-case)
'X' = integer in hexadecimal (upper-case)
'b', 'B' = integer as bit string
's' = string
'q' = boolean (i.e. a Question?) "true" or "false"
'%' = print a '%' character
(the length qualifiers 'h' 'l' 'L' etc are not applicable)
> a=33; printf("%d in hex=%x in binary=%b\n", a,a,a)
33 in hex=21 in binary=100001
4.2 Verbose mode and showhex
The default behaviour after typing a statement is to display the result in decimal.
> a = 123
123
Use verbose off to turn off this behaviour. You must then explicitly use a print function to display a value.
> verbose off
> b = 456789
> ?b
456789
Use verbose on to go back to the default behaviour.
To display the "verbose" values in hexadecimal, use showhex on.
To revert to displaying in decimal, use showhex off
> verbose on
> showhex on
> a
0x7b
> b
0x6f855
> showhex off
> b
456789
5 Control flow statements
5.1 Conditional statements: if-then-fi and if-then-else-fi
if B then <stmts> fi
executes the statements in <stmts> only if the boolean expression B is true.
if B then <stmts1> else <stmts2> fi
executes the statements in <stmts1> if the boolean expression B is true
otherwise the statements in <stmts2> are executed.
The <stmts> block can contain multiple statements separated by semicolons.
Do not forget the fi!
> x=7; if x<8 then ? "is true" fi
is true
> x=8; if x<8 then ? "is true" else ? "is false" fi
is false
> x=8; if x<8 then ? "huh!" fi; ? "All done"
All done
5.2 Loops: while and repeat
while B do <stmts> done
loops through <stmts> while the boolean statement B is true.
repeat <stmts> until B
loops through <stmts> until the boolean statement B is true.
> x=0; while x<=5 do ?x; x++ done
0
1
2
3
4
5
> x=4; repeat ?x; x-- until x==0
4
3
2
1
5.3 Loops: for-do-done
for X in (M,N,...,W) do <stmts> done
loops through <stmts> for each X in the list M,N,...,W.
> for p in (2,3,6,7) do ??isprime(p) done
true
true
false
true
for X in (M..N) do <stmts> done
loops through <stmts> for X incrementing (or decrementing) the value of X by one each time in the range M to N
> for x in (2..5) do ?x done
2
3
4
5
for X in (M..N) do <stmts> breakif B done
loops through <stmts> for X incrementing by one in the range M to N
stopping if the boolean statement B is true.
The breakif B statement can only be used as the last statement before the done keyword.
> for x in (1..5) do ?x breakif x==3 done; println("stopped with x=", x)
1
2
3
stopped with x=3
Loops can be nested.
> for i in (2,5) do for j in (11..7) do
println(i,' ',j,' ',pow(i,j)) done done
2 11 2048
2 10 1024
2 9 512
2 8 256
2 7 128
5 11 48828125
5 10 9765625
5 9 1953125
5 8 390625
5 7 78125
6 Strings
Strings are used in print statements and can be enclosed in either single or double quotes.
'abc'
"Hello, world!"
Use escape sequences like \n for newline, \t for tab and \\ for backslash.
To include a double quote " in a string enclose it in single quotes ', and vice versa.
> ? "abc\np\\qr\txyz"
abc
p\qr xyz
> ? "abc'xyz"
abc'xyz
6.1 Escape sequences
Escape sequence | Meaning |
\newline | Ignored |
\\ | Backslash (\) |
\n | ASCII Linefeed (LF) |
\r | ASCII Carriage return (CR) |
\t | ASCII Horizontal tab (TAB) |
\v | ASCII Vertical tab (VT) |
\f | ASCII Formfeed (FF) |
\b | ASCII Backspace (BS) |
\a | ASCII Bell (BEL) |
All unrecognized escape sequences are left in the string unchanged; that is, the backslash is left in the string.
To create a raw string, in which backslashes are not interpreted as escape characters, specify r before
the opening quote character.
> ? r"A \raw stri\ng"
A \raw stri\ng
7 Expressions and operators
7.1 Arithmetic and bitwise expressions
These are listed in decreasing order of precedence.
Operator | Synonym | Description |
a * b | | multiply a and b |
a / b | a div b | integer division: the quotient of a divided by b |
a % b | a mod b | integer modulus: the remainder of a divided by b |
a + b | | add a and b |
a - b | | subtract b from a using cut-off subtraction: a−b=0 if b ≥ a |
a << n | a shl n | bitwise left shift of a by n bits |
a >> n | a shr n | bitwise right shift of a by n bits |
a & b | a band b | bitwise AND of a and b |
a ∧ b | a bxor b | bitwise XOR of a and b |
a | b | a bor b | bitwise OR of a and b |
Symbol and text synonyms like << and shl are provided to allow the usual shorthand operators familiar to C and Java programmers
and also to include a text form permissible in command-line prompts.
7.2 Relational and equality operators
The usual relational and equality operators are provided, plus text synomyms like eq for ==,
which are useful in command-line input (or if you just don't like the C-style ones).
Operator | Synonym | Description |
a < b | a lt b | a is less than b |
a > b | a gt b | a is greater than b |
a <= b | a le b | a is less than or equal to b |
a >= b | a ge b | a is greater than or equal to b |
a == b | a eq b | a is equal to b |
a != b | a ne b | a is not equal to b |
7.3 Logical expressions and logical operators
An expression A is false if A is equal to zero; otherwise it is true.
A logical expression returns 1 if it is true and 0 if false.
To display the logical value of an expression A in text form true or false, use ??A.
The assignment A=1 will set A as true, and A=0 will set A as false.
In fact, setting A to any non-zero expression sets it as true as far as logical expressions are concerned.
You can use the keywords true and false if you wish: A=true and A=false.
Operator | Description | Returns |
not A | logical NOT | true if A is false; false if A is true |
A and B | logical AND | true only if both A and B are true |
A or B | logical OR | true if either A or B is true |
A xor B | logical XOR | true if either A or B is true, but not both |
The symbols && and || can be used instead of and and or.
There are no symbol synonyms for not or xor.
8 Saving and restoring session variables
8.1 The save and restore statements
save
save "filename"
restore
restore "filename"
The save statement will save the values of all current variables to disk.
By default, these are saved in a file called bdcalc_dat.txt in the current working directory.
Use the restore statement to restore all variables to those previously saved
(you may need to hit Enter twice after using restore).
Alternatively, you can save to and restore from an optional named file.
save '\mydir\myvars.txt'
restore '\mydir\myvars.txt'
9 System-related statements
9.1 The system statement
system "string"
The system statement passes the string to be executed by the command processor. For example, in Windows
> system "start bdcalc.pdf"
will open the PDF manual file bdcalc.pdf using the default PDF viewer application.
> system 'dir'
will list the files in the current working directory. In Linux, use system "ls".
9.2 The getcwd statement
The getcwd statement displays the name of the current working directory.
9.3 The chdir statement
chdir R"path"
The chdir statement changes the current directory to that specified in path.
Caution: Use the raw string format (r'...') in Windows to avoid problems with backslashes and escape sequences like \t.
> getcwd
C:\ProgramData\DIManagement\bdcalc
> chdir r'C:\test'
> getcwd
C:\test
10 Miscellaneous statements
10.1 The quit statement
The quit statement terminates the program immediately.
Use to quit interactive mode.
10.2 The help statement
help
help "keyword"
The help statement on its own gives you the usual generic bland statement about to get further help, with a list of keywords you can query further.
help "keyword" outputs information on the specific keyword. Note the quotes around the keyword.
> help 'modexp'
`modexp(X,Y,M)` returns X raised to the power Y modulo M
But if you forget the quotes, you get an error
> help modexp
Type help "<keyword>" for specific help on a <keyword>.
...
ERROR: syntax error (incomplete line)
help "all" outputs help on all the keywords and help "alls" outputs the list with the keywords sorted.
10.3 The version statement
The version statement in interactive mode outputs information about the current version of the program.
This is the same as typing bdcalc -v on the command line.
10.4 The prompt statement
prompt "newprompt"
Use the prompt statement to change the prompt in interactive mode. The default prompt is "> ".
> prompt "$ "
$ prompt '" '
" prompt "> "
>
11 Script files
A script file is a simple ASCII text file containing valid statements which are executed in order.
We use the extension ".bdscr" but any valid text file is OK, including ".txt".
The best language to highlight a script file in a smart text editor is Python.
11.1 The -file command-line option
You can load a text file containing any valid statements from the command line using the -file option. For example:
bdcalc -file myscriptfile.bdscr
bdcalc -file "My Dir\anotherscript.bdscr"
The program will exit on successful execution of the code or on error. There is no need for a quit statement.
Make sure there is a final newline at the end of the file.
Suppose the script file testin.bdscr is
a=3
b=4
println("a+b=",a+b)
Then typing bdcalc -file testin.bdscr on the command line will give
bdcalc -file testin.bdscr
a+b=7
11.2 The load statement
load "filename"
Use the load statement in interactive mode to load and execute a script file. For example, using the same script file as above.
> load 'testin.bdscr'
a+b=7
11.3 Example scripts
For more detailed examples of using bdcalc to perform number theoretical and cryptography calculations,
see the example script files on our
web site
(and included in the distribution). These script files include the following.
- qr_find.bdscr
- How to find a quadratic residue by exhaustive search
- discretelog.bdscr
- Compute discrete logarithm
- primes1000.bdscr
- Write out the first 1000 primes
- rsa_make.bdscr
- Make an RSA key pair and test it
- rsa_make_exact.bdscr
- Make an RSA key pair of exact bit length
- rsa_quint.bdscr
- Perform RSA calculation with private key in CRT quintuple form
- rsacrack.bdscr
- Crack RSA if used incorrectly to three recipients
- rDSA.bdscr
- Example of the rDSA algorithm from ANSI X9.31
- dsa_test.bdscr
- Example of DSA from Appendix 5 FIPS PUB 186-2
- rsa_quint.bdscr
- Perform RSA calculation with private key in CRT quintuple form
- dh_gen.bdscr
- Generate domain parameters for Diffie-Hellman
- dh_keyexch.bdscr
- Perform Diffie-Hellman key exchange using parameters generated above
- poly1305.bdscr
- Poly1305 Example and Test Vector
11.4 Example script: Finding a quadratic residue
The script file qr_find.bdscr gives an example of doing an exhaustive search for a quadratic residue.
It uses an outer for statement to loop through two values and an inner loop to search incrementally
2,3,…,p−1 until it finds a result.
################################
# SCRIPT: qr_find.bdscr [v2.0] #
################################
# 2813 is a quadratic residue mod 9907 but 1001 is not.
p=9907
print("p=",p,"\n")
# Outer loop for two values of n...
for n in (2813,1001) do
println("Testing n=",n,"...");
for x in (2..p-1) do q=(modexp(x,2,p)==n); breakif (q) done;
if(q) then
printf("%d is a QR mod %d since %d^2=%d (mod %d)\n", n, p, x, modexp(x,2,p),p);
else
printf("%d is NOT a QR mod %d\n", n, p);
fi
done
? "ALL DONE"
This gives the output:
p=9907
Testing n=2813...
2813 is a QR mod 9907 since 3511^2=2813 (mod 9907)
Testing n=1001...
1001 is NOT a QR mod 9907
ALL DONE
This example is just meant to demonstrate how you might use a loop statement in a script to find the actual number x for
which x2 mod p = n.
In practice, you find whether or not n is a quadratic residue modulo a prime p simply by using the jacobi(n,p) function.
> jacobi(2813,9907) # A quadratic residue => 1
1
> jacobi(1001,9907) # A non-quadratic residue => 2
2
11.5 The assert statement
assert(X)
assert(X, "message")
The assert statement will terminate the program with an error message if the expression X is false.
An optional message can be included as a quoted string. The program will return an exit code 1 to the operating system.
11.6 The exit(N) statement
The exit(N) statement will unconditionally terminate the program at the next convenient opportunity
and return the exit code N to the operating system.
12 The command line
12.1 Command-line syntax
Usage: BDCALC [-file filename] | "stmt[;stmts]" | [-h] | [-v]
where
-file filename load and run script in `filename`
"stmt[;stmts]" execute statements and exit
-h display this syntax and exit
-v display version info and exit
(no argument) start in interactive mode
12.2 Entering statements on the command line
bdcalc "stmt[;stmts]"
You can enter a block of statements separated by semicolons directly in one line on the command line.
The statements in the block will be executed and the program will quit automatically.
Only the first argument on the command line is read, so you must enclose the entire block in double quotes "..."
and avoid using any of the special Windows command-line characters like >, &, <, |, \ and ^.
Use the text synonyms like gt and band instead. Use the apostrophe '...' to quote strings inside the block.
In Linux, do the opposite and enclose the block in single quotes.
bdcalc "a=3;b=4;println('a + b =',a+b)"
a + b = 7
bdcalc "for a in (1..3) do ?a done"
1
2
3
bdcalc "a=0x10001;b=0x11110;printf('a band b=%#x', a band b)"
a band b=0x10000
As an example of using a loop, we can generate a random prime of 32 bits (the long way) on the command line as follows.
bdcalc "k=32;repeat p=randbits(k)|1<<(k-1)|0x1;
println('Try p=',hex(p)) until isprime(p);!p"
Try p=0x988e56c5
Try p=0xf209e0d9
Try p=0xee42d1d1
Try p=0xd09edbc1
0xd09edbc1
Enter everything on one line between the surrounding quotes
(we've broken the line above for display purposes).
Note also that this example will give a different prime result each time and may take several tries before it succeeds.
Of course we could just do
bdcalc "!genprime(32)"
0xa543796f
but you get the idea.
13 Errors and error messages
13.1 Common errors
14 Using on a Linux platform
14.1 Funny characters appear when using the arrow keys
To avoid "funny" characters like ^[[A ^[[B ^[[C ^[[D when using the arrow keys on a Linux platform,
install rlwrap and start bdcalc from the command line with
rlwrap bdcalc
This will make the arrow keys work as expected and give you a proper history of previous commands by using the `up' arrow
(just like on Windows!).
15 Reserved keywords
The following keywords, built-in function names and operator synonyms are reserved and cannot be used for variable names.
and
assert
band
bin
bitlen
bool
bor
breakif
bxor
cbrt
chdir
compl
define
div
do
done
else
eq
exit
false
fi
fillbytes
for
gcd
ge
genprime
getbit
getcwd
gt
help
hex
if
iif
in
isprime
jacobi
le
load
lt
max
min
mod
modexp
modinv
modmul
modpowof2
ne
not
off
on
or
pow
prime
print
printf
println
prompt
putbin
putbool
puthex
puts
quit
randbits
random
repeat
restore
save
setbit
sha1
sha256
shl
shr
showhex
sqrt
square
start
system
then
true
until
verbose
version
while
xor
16 Revision history
- Version 2.2.0
- (17 June 2016)
Changed behaviour of print and println to insert spaces between arguments.
Added setsep command to change print separation character.
Removed requirement to put quotes around arguments for help.
Added new functions sha256 and fillbytes.
Made second argument optional for revbytes.
Added showhex statement to switch between hexadecimal and decimal displays of the result in interactive mode.
- Version 2.1.0
- (19 January 2015)
Added support for byte manipulation.
See Byte manipulation functions.
- Version 2.0.0
- (24 October 2014)
Version 2 is a complete rewrite of version 1 with significantly different syntax.
- Version 1.0.0
- (12 May 2013)
bdcalc version 1 first published.
17 About this document
This document was last updated on Jun 17, 2016
for bdcalc version 2.2.0.
It was created in LATEX using TeXnicCenter and required the consumption of 1373 bottles of premium German lager.
> prime(220)
1373
> ??isprime(1373)
true
More information on bdcalc is available at
http://www.di-mgt.com.au/bdcalc.html
File translated from
TEX
by
TTH,
version 4.03.