Skip to content

Commit 87bf557

Browse files
committed
feat(bn) mathematics, bit shift and comparasion operations
1 parent da21f64 commit 87bf557

File tree

6 files changed

+1044
-57
lines changed

6 files changed

+1044
-57
lines changed

README.md

+235-24
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,18 @@ Table of Contents
3333
+ [bn.new](#bnnew)
3434
+ [bn.dup](#bndup)
3535
+ [bn.istype](#bnistype)
36-
+ [bn.from_binary](#bnfrom_binary)
37-
+ [bn:to_binary](#bnto_binary)
38-
+ [bn:to_hex](#bnto_hex)
36+
+ [bn.from_binary, bn:to_binary](#bnfrom_binary-bnto_binary)
37+
+ [bn.from_hex, bn:to_hex](#bnfrom_hex-bnto_hex)
38+
+ [bn.from_dec, bn:to_dec](#bnfrom_dec-bnto_dec)
39+
+ [bn:to_number](#bnto_number)
40+
+ [bn:__metamethods](#bn__metamethods)
41+
+ [bn:add, bn:sub, bn:mul, bn:div, bn:exp, bn:mod, bn:gcd](#bnadd-bnsub-bnmul-bndiv-bnexp-bnmod-bngcd)
42+
+ [bn:sqr](#bnsqr)
43+
+ [bn:mod_add, bn:mod_sub, bn:mod_mul, bn:mod_exp](#bnmod_add-bnmod_sub-bnmod_mul-bnmod_exp)
44+
+ [bn:mod_sqr](#bnmod_sqr)
45+
+ [bn:lshift, bn:rshift](#bnlshift-bnrshift)
46+
+ [bn:is_zero, bn:is_one, bn:is_odd, bn:is_word](#bnis_zero-bnis_one-bnis_odd-bnis_word)
47+
+ [bn:is_prime](#bnis_prime)
3948
* [resty.openssl.cipher](#restyopensslcipher)
4049
+ [cipher.new](#ciphernew)
4150
+ [cipher.istype](#cipheristype)
@@ -371,8 +380,8 @@ parameter of RSA key is supported. Each value of the returned table is a
371380
local pk, err = require("resty.openssl").pkey.new()
372381
local parameters, err = pk:get_parameters()
373382
local e = parameters.e
374-
ngx.say(ngx.encode_base64(e:to_binary()))
375-
-- outputs 'AQAB' (65537) by default
383+
ngx.say(e:to_number())
384+
-- outputs 65537
376385
```
377386

378387
[Back to TOC](#table-of-contents)
@@ -444,10 +453,10 @@ local pub_pem = privkey:to_PEM("public")
444453
local pubkey, err = pkey.new(pub_pem)
445454
local s, err = pubkey:encrypt("🦢", pkey.PADDINGS.RSA_PKCS1_PADDING)
446455
ngx.say(#s)
447-
-- Outputs 256
456+
-- outputs 256
448457
local decrypted, err = privkey:decrypt(s)
449458
ngx.say(decrypted)
450-
-- Outputs "🦢"
459+
-- outputs "🦢"
451460
```
452461

453462
[Back to TOC](#table-of-contents)
@@ -465,7 +474,8 @@ By default, it returns the public key.
465474

466475
## resty.openssl.bn
467476

468-
Module to expose BIGNUM structure.
477+
Module to expose BIGNUM structure. Note bignum is a big integer, no float operations
478+
(like square root) are supported.
469479

470480
[Back to TOC](#table-of-contents)
471481

@@ -494,10 +504,16 @@ Returns `true` if table is an instance of `bn`. Returns `false` otherwise.
494504

495505
[Back to TOC](#table-of-contents)
496506

497-
### bn.from_binary
507+
### bn.from_binary, bn:to_binary
508+
509+
**syntax**: *bn, err = bn.from_binary(bin)*
510+
511+
**syntax**: *bin, err = bn:to_binary()*
498512

499513
Creates a `bn` instance from binary string.
500514

515+
Exports the BIGNUM value in binary string.
516+
501517
```lua
502518
local b, err = require("resty.openssl.bn").from_binary(ngx.decode_base64("WyU="))
503519
local bin, err = b:to_binary()
@@ -507,33 +523,228 @@ ngx.say(ngx.encode_base64(bin))
507523

508524
[Back to TOC](#table-of-contents)
509525

510-
### bn:to_binary
526+
### bn.from_hex, bn:to_hex
511527

512-
**syntax**: *bin, err = bn:to_binary()*
528+
**syntax**: *bn, err = bn.from_hex(hex)*
513529

514-
Export the BIGNUM value in binary string.
530+
**syntax**: *hex, err = bn:to_hex()*
531+
532+
Creates a `bn` instance from hex encoded string. Note that the leading `0x` should not be
533+
included. A leading `-` indicating the sign may be included.
534+
535+
Exports the `bn` instance to hex encoded string.
515536

537+
```lua
538+
local bn = require("resty.openssl.bn")
539+
local b = bn.from_hex("5B25")
540+
local hex, err = b:to_hex()
541+
ngx.say(hex)
542+
-- outputs "5B25"
543+
```
516544

517545
[Back to TOC](#table-of-contents)
518546

519-
### bn:to_hex
547+
### bn.from_dec, bn:to_dec
520548

521-
**syntax**: *hex, err = bn:to_hex()*
549+
**syntax**: *bn, err = bn.from_dec(dec)*
522550

523-
Export the BIGNUM value in hex encoded string.
551+
**syntax**: *dec, err = bn:to_dec()*
552+
553+
Creates a `bn` instance from decimal string. A leading `-` indicating the sign may be included.
554+
555+
Exports the `bn` instance to decimal string.
524556

525557
```lua
526-
local b, err = require("resty.openssl.bn").new(23333)
527-
local bin, err = b:to_binary()
528-
ngx.say(ngx.encode_base64(bin))
529-
-- outputs "WyU="
530-
local hex, err = b:to_hex()
531-
ngx.say(hex)
532-
-- outputs "5B25"
558+
local bn = require("resty.openssl.bn")
559+
local b = bn.from_dec("23333")
560+
local dec, err = b:to_dec()
561+
ngx.say(dec)
562+
-- outputs "23333"
563+
```
564+
565+
[Back to TOC](#table-of-contents)
566+
567+
### bn:to_number
568+
569+
**syntax**: *n, err = bn:to_number()*
570+
571+
**syntax**: *n, err = bn:tonumber()*
572+
573+
Export the lowest 32 bits or 64 bits part (based on the ABI) of `bn` instance
574+
to a number. This is useful when user wants to perform bitwise operations.
575+
576+
```lua
577+
local bn = require("resty.openssl.bn")
578+
local b = bn.from_dec("23333")
579+
local n, err = b:to_number()
580+
ngx.say(n)
581+
-- outputs 23333
582+
ngx.say(type(n))
583+
-- outputs "number"
584+
```
585+
586+
[Back to TOC](#table-of-contents)
587+
588+
### bn:__metamethods
589+
590+
Various mathematical operations can be performed as if it's a number.
591+
592+
```lua
593+
local bn = require("resty.openssl.bn")
594+
local a = bn.new(123456)
595+
local b = bn.new(222)
596+
-- the following returns a bn
597+
local r
598+
r = -a
599+
r = a + b
600+
r = a - b
601+
r = a * b
602+
r = a / b -- equal to bn:idiv, returns floor division
603+
r = a % b
604+
-- all operations can be performed between number and bignum
605+
r = a + 222
606+
r = 222 + a
607+
-- the following returns a bool
608+
local bool
609+
bool = a < b
610+
bool = a >= b
611+
-- compare between number will not work
612+
-- WRONG: bool = a < 222
613+
```
614+
615+
[Back to TOC](#table-of-contents)
616+
617+
### bn:add, bn:sub, bn:mul, bn:div, bn:exp, bn:mod, bn:gcd
618+
619+
**syntax**: *r = a:op(b)*
620+
621+
**syntax**: *r = bn.op(a, b)*
622+
623+
Perform mathematical operations `op`.
624+
625+
- `add`: add
626+
- `sub`: subtract
627+
- `mul`: multiply
628+
- `div`, `idiv`: floor division (division with rounding down to nearest integer)
629+
- `exp`, `pow`: the `b`-th power of `a`, this function is faster than repeated `a * a * ...`.
630+
- `mod`: modulo
631+
- `gcd`: the greatest common divider of `a` and `b`.
632+
633+
Note that `add`, `sub`, `mul`, `div`, `mod` is also available with `+, -, *, /, %` operaters.
634+
See [above section](#bn__metamethods) for examples.
635+
636+
```lua
637+
local bn = require("resty.openssl.bn")
638+
local a = bn.new(123456)
639+
local b = bn.new(9876)
640+
local r
641+
-- the followings are equal
642+
r = a:add(b)
643+
r = bn.add(a, b)
644+
r = a:add(9876)
645+
r = bn.add(a, 9876)
646+
r = bn.add(123456, b)
647+
r = bn.add(123456, 9876)
648+
```
649+
650+
[Back to TOC](#table-of-contents)
651+
652+
### bn:sqr
653+
654+
**syntax**: *r = a:sqr()*
655+
656+
**syntax**: *r = bn.sqr(a)*
657+
658+
Computes the 2-th power of `a`. This function is faster than `r = a * a`.
659+
660+
[Back to TOC](#table-of-contents)
661+
662+
### bn:mod_add, bn:mod_sub, bn:mod_mul, bn:mod_exp
663+
664+
**syntax**: *r = a:op(b, m)*
665+
666+
**syntax**: *r = bn.op(a, b, m)*
667+
668+
Perform modulo mathematical operations `op`.
669+
670+
- `mod_add`: adds `a` to `b` modulo `m`
671+
- `mod_sub`: substracts `b` from `a` modulo `m`
672+
- `mod_mul`: multiplies `a` by `b` and finds the non-negative remainder respective to modulus `m`
673+
- `mod_exp`, `mod_pow`: computes `a` to the `b`-th power modulo `m` (r=a^b % m). This function uses less
674+
time and space than `exp`. Do not call this function when `m` is even and any of the parameters
675+
have the `BN_FLG_CONSTTIME` flag set.
676+
677+
```lua
678+
local bn = require("resty.openssl.bn")
679+
local a = bn.new(123456)
680+
local b = bn.new(9876)
681+
local r
682+
-- the followings are equal
683+
r = a:mod_add(b, 3)
684+
r = bn.mod_add(a, b, 3)
685+
r = a:mod_add(9876, 3)
686+
r = bn.mod_add(a, 9876, 3)
687+
r = bn.mod_add(123456, b, 3)
688+
r = bn.mod_add(123456, 9876, 3)
533689
```
534690

535691
[Back to TOC](#table-of-contents)
536692

693+
### bn:mod_sqr
694+
695+
**syntax**: *r = a:mod_sqr(m)*
696+
697+
**syntax**: *r = bn.mod_sqr(a, m)*
698+
699+
Takes the square of `a` modulo `m`.
700+
701+
[Back to TOC](#table-of-contents)
702+
703+
### bn:lshift, bn:rshift
704+
705+
**syntax**: *r = bn:lshift(bit)*
706+
707+
**syntax**: *r = bn.lshift(a, bit)*
708+
709+
**syntax**: *r = bn:rshift(bit)*
710+
711+
**syntax**: *r = bn.rshift(a, bit)*
712+
713+
Bit shift `a` to `bit` bits.
714+
715+
[Back to TOC](#table-of-contents)
716+
717+
### bn:is_zero, bn:is_one, bn:is_odd, bn:is_word
718+
719+
**syntax**: *ok = bn:is_zero()*
720+
721+
**syntax**: *ok = bn:is_one()*
722+
723+
**syntax**: *ok = bn:is_odd()*
724+
725+
**syntax**: *ok, err = bn:is_word(n)*
726+
727+
Checks if `bn` is `0`, `1`, and odd number or a number `n` respectively.
728+
729+
[Back to TOC](#table-of-contents)
730+
731+
### bn:is_prime
732+
733+
**syntax**: *ok, err = bn:is_prime(nchecks?)*
734+
735+
Checks if `bn` is a prime number. Returns `true` if it is prime with an
736+
error probability of less than 0.25^`nchecks` and error if any. If omitted,
737+
`nchecks` is set to 0 which means to select number of iterations basedon the
738+
size of the number
739+
740+
> This function perform a Miller-Rabin probabilistic primality test with nchecks iterations. If nchecks == BN_prime_checks (0), a number of iterations is used that yields a false positive rate of at most 2^-64 for random input. The error rate depends on the size of the prime and goes down for bigger primes. The rate is 2^-80 starting at 308 bits, 2^-112 at 852 bits, 2^-128 at 1080 bits, 2^-192 at 3747 bits and 2^-256 at 6394 bits.
741+
742+
> When the source of the prime is not random or not trusted, the number of checks needs to be much higher to reach the same level of assurance: It should equal half of the targeted security level in bits (rounded up to the next integer if necessary). For instance, to reach the 128 bit security level, nchecks should be set to 64.
743+
744+
See also [BN_is_prime](https://www.openssl.org/docs/man1.1.1/man3/BN_is_prime.html).
745+
746+
[Back to TOC](#table-of-contents)
747+
537748
## resty.openssl.cipher
538749

539750
Module to interact with symmetric cryptography (EVP_CIPHER).
@@ -831,7 +1042,7 @@ local key, err = kdf.derive({
8311042
pbkdf2_iter = 1000,
8321043
})
8331044
ngx.say(ngx.encode_base64(key))
834-
-- Outputs "cDRFLQ7NWt+AP4i0TdBzog=="
1045+
-- outputs "cDRFLQ7NWt+AP4i0TdBzog=="
8351046

8361047
key, err = kdf.derive({
8371048
type = "scrypt",
@@ -842,7 +1053,7 @@ key, err = kdf.derive({
8421053
scrypt_p = 16,
8431054
})
8441055
ngx.say(ngx.encode_base64(key))
845-
-- Outputs "9giFtxace5sESmRb8qxuOw=="
1056+
-- outputs "9giFtxace5sESmRb8qxuOw=="
8461057
```
8471058

8481059
[Back to TOC](#table-of-contents)

0 commit comments

Comments
 (0)