NONZERO.TXT
/
Copyright 2007,2008 aa, Adrian H. and Ray AF.
Private property of PT Softindo JAKARTA
All rights reserved.
last rev. 2008.05.26
/
A use of natural integer number
-------------------------------
C family language does not handle string as well as Pascal did
with her string type. actually all string operations in c will be
felt-down when encounter 0, an ASCIIZ string in Pascal is not as
important as it did in C, although recognized (as in Delphi and fpc),
Pascal doesn't give a damn about what the content of string since
she has already have the length of the string in string header.
since the 0 (null) denoted as end of asciiz string, this will lead
to us the rule#1:
the asciiz string must not contains a 0 (null) character
note.
although the concept will also work with 2 or 4 byte character
we will assume that the string in this article is an asciiz
string of 1 byte character for easy understanding.
in database-centric applications (which almost certainly
written in C) we could only pass the decimal representation as
a non-null string, most often with conversion first from an
integer to string, which means an overfluous call to another
slow C string handling routines.
note:
the term slow is compared to pascal's string routines.
don't be amazed by this fact, we'll give you an overview:
to get the length of string (the most primitive and most often
called string function) in Pascal, is a blatantly mere simple
stupid plain instruction: mov eax,[S-4] (or as such in other
platform other than intel's), while in C by strlen, you must
scan the whole string from the beginning of pointer 'till
the end, until it found null (and still, consequently, that's
only works with asciiz string, not an arbitrary bytes stream
as it does in pascal).
of course, we talk only of bult-in support by the language, as
a matter of fact, either dancing with Pascal or laboured by C,
you can do anything as you could imagine.
so how to embed an integer type number into an asciiz string?
as promulgated by the rule#1above, we have to make sure that
every single character within the integer we wish to embed into
an asciiz string is not a null character. if a character is
1-byte wide, then all of bytes of integer must not be 0.
the most easy way to implement (against each bytes of integer
storage) is to:
1. always set the highest bit, and
2. use the remaining bits for number
this means we could only used half of maximum capacity per character
(as it did back to '80 era), the obvious shortage will be exponentially
increased by the size of integer type we use.
------------------------------------------------------
type length max-capacity stripped ratio
------------------------------------------------------
byte 1 256^1 = 256 128^1 = 128 1:2
word 2 256^2 = 65536 128^2 = 16384 1:4
integer 4 256^4 = 4G 128^4 = 256M 1:16
bigint 8 256^8 = 16E 128^8 = 64P 1:256
------------------------------------------------------
note:
64P = 72057594037927936
16E = 18446744073709551616
but then there's another way, or more properly said, is the general
concept of natural number reformulation of integer stated as:
for every single element of integer as a representation of
character for the null-terminated-string:
apply different exponential base number (base), and then
normalize/reorder/recompose, so it will not be represented
as a null-character
- the highest base is at most 1-less of maximum capacity of character
- the lowest base is 2 (equal with binary number)
(in the previous example, we actually choose 128 as different base
for number, and set the highest bit to normalize it).
the most space efficient is the highest different base allowed (255
for 1-byte wide character, 65535 for 2-byte wide, and so on), this might
or might not be desirable (for example you'd better pick an even number
for the new base, a perfect square of 2 is the best, since it is cheap
and much easier to maintain, but if you do need all the space you can get,
you will pick the highest allowed value instead).
note:
it's a classic dilema of price (of space) vs. performace, when using
perfect 2 fold you can substitute a costly div/mod instruction with
much cheaper shift instruction.
Capacity loss = (C ^ N) - (C' ^ N)
where:
^ = power
C = original capacity of character (eg. 256 for byte)
C' = capacity of character after rebase
N = number of characters in integer-type (eg. 4 for type
long/cardinal in bytes)
comparison of different base number capacity
------------------------------------------------------------------------------
type size 2 4 8 16 32 64 96 128
------------------------------------------------------------------------------
byte 1 2 4 8 16 32 64 96 128
word 2 4 16 64 256 1024 4096 9216 16384
integer 4 16 256 4096 65536 1M 16M 81M 256M
bigint 8 256 65536 16M 4G 1T 256T 6.4P 64P
------------------------------------------------------------------------------
comparison of different base number capacity (continued), next 16 fold
------------------------------------------------------------------------------
type size 144 160 176 192 208 224 240 256
------------------------------------------------------------------------------
byte 1 144 160 176 192 208 224 240 256
word 2 20736 25600 30976 36864 43264 50176 57600 65536
integer 4 410M 625M 915M 1.27G 1.74G 2.34G 3.09G 4G
bigint 8 164P 380P 817.7P 1.6E 3.04E 5.4E 9.55E 16E
------------------------------------------------------------------------------
comparison of different base number capacity (continued), esoterics
------------------------------------------------------------------------------
type size 50 100 120 140 180 200 250 255
------------------------------------------------------------------------------
byte 1 50 100 120 140 180 200 250 255
word 2 2500 10000 14400 19600 32400 40000 62500 65025
integer 4 5.96M 95.24M 197.75M 366.36M 1.001G 1.49G 3.64G 3.94G
bigint 8 35.53T 8.88P 38.19P 131.08P 978.77P 2.22E 13.23E 15.5E
------------------------------------------------------------------------------
note:
Kilo = 1024
Mega = 1024 1024 = 1024^2 = 1048576
Giga = 1024 3 = 1073741824
Tera = 1024^4 = 1099511627776
Peta = 1024^5 = 1125899906842624
Exa = 1024^6 = 1152921504606846976
zeta,yota
reminder...
64P = 65536.T = 72057594037927936
16E = 16384.P = 18446744073709551616
physical storage of (intel's little-endian) integer compared to
non-zero integer number base 128 (before normalized):
-------------------------------------------------------------------------
byte #0#1#2#3 beforenormalized highest bit set )
------------------------------------------------------------------------
0 0 0 0 0 0 0 0 0 - - - -
128 128 0 0 0 0 1 0 0 - 129 - -
256 0 1 0 0 0 2 0 0 - 130 - -
32768 0 128 0 0 0 0 1 0 - - 129 -
65536 0 0 1 0 0 0 4 0 - - 132 -
------------------------------------------------------------------------
note: ) all - (DASH) marks means 128, for the sake of readability
physical storage of (intel's little-endian) integer compared to
non-zero integer number base 255 (before normalized):
------------------------------------------------------------------------
byte #0#1#2#3 beforenormalized method: add +1 )
------------------------------------------------------------------------
0 0 0 0 0 0 0 0 0 - - - -
255 255 0 0 0 0 1 0 0 - 2 - -
256 0 1 0 0 1 1 0 0 2 2 - -
65025 1 254 0 0 0 0 1 0 - - 2 -
65536 0 0 1 0 1 2 1 0 2 3 2 -
------------------------------------------------------------------------
note: ) all - (DASH) marks means 1, for the sake of readability
...
handling negative value:
when we say about integer here, that means a POSITIVE number,
negative integer is nothing more than a half truncated integer
capacity with the highest bit (in the highest char) set.
if you intend to use negative value then you'll have to manually
extend the sign when the highest bit (in the highest byte) is
set, fortunately this only happen if you pick base below the
half of maximum capacity (which questionably chosen) as for
base value equal or greater than half maximum, the sign bit
will be automatically carried within normalized value.
{ code: }
{ 1. sample code }
function DivMod(const Dividend: cardinal;
const Divisor: byte; var Reminder: byte): cardinal;
begin
Result := Dividend div Divisor;
Reminder := Dividend mod Divisor;
end;
function inttoNZN(I: cardinal; const base: byte = high(byte)): cardinal;
const
ByteOnes = $01010101;
type
tInt4Chars = packed record
ch0, ch1, ch2, ch3: byte;
end;
begin
Result := 0;
I := divMod(I, base, tInt4Chars(Result).ch0);
if I > 0 then
I := divMod(I, base, tInt4Chars(Result).ch1);
if I > 0 then
tInt4Chars(Result).ch3 := divMod(I, base, tInt4Chars(Result).ch2);
Result := Result + ByteOnes; // normalize
end;
{ as could bee seen in this code, replacing exponent base }
{ with constant number will help performance a LOT )
function NZNtoInt(NZN: cardinal; const base: byte = high(byte)): cardinal;
const
ByteOnes = $01010101;
type
tInt4Chars = packed record
ch0, ch1, ch2, ch3: byte;
end;
begin
Result := NZN - ByteOnes;
if Result > 0 then
Result :=
tInt4Chars(Result).ch3 base base base +
tInt4Chars(Result).ch2 base base +
tInt4Chars(Result).ch1 base +
tInt4Chars(Result).ch0
end;
{ 2. optimized sample code }
{ note: }
{ we have to avoid using expensive div/mod as could as possible. }
{ the code below although longer, should be faster than above }
{ (out of branch mis-prediction penalty). }
function inttoNZN2(I: cardinal; const base: byte = high(byte)): cardinal;
const
ByteOnes = $01010101;
type
tInt4Chars = packed record
ch0, ch1, ch2, ch3: byte;
end;
function proci(var b0, b1: byte): cardinal;
begin
Result := I;
if Result <= base then begin
if Result < base then
b0 := Result
else
b1 := 1;
Result := 0;
end
else begin
Result := divMod(Result, base, b0);
if Result < base then begin
b1 := Result;
Result := 0;
end;
I := Result;
end;
end;
begin
Result := 0;
if proci(tInt4Chars(Result).ch0, tInt4Chars(Result).ch1) >= base then
if proci(tInt4Chars(Result).ch1, tInt4Chars(Result).ch2) >= base then
proci(tInt4Chars(Result).ch2, tInt4Chars(Result).ch3);
Result := Result + ByteOnes;
end;
{ 3. asm optimized sample code }
{ when you got an urge for speed, then asm is the only choice }
function asmInttoNZN(const I: cardinal; const base: byte): integer;
const AllOnes = $01010101;
asm
test eax, not 0ffh; jnz @@0
add eax,AllOnes; ret;
@@0: movzx ecx,dl; //sanitize
//cmp eax,ecx; ja @@1
//sbb edx,edx; and eax,edx
//sete ah; add eax,AllOnes; ret;
;@@1: xor edx,edx; push edx; // Result
div ecx; mov [esp],dl;
cmp eax,ecx; ja @@2
sbb edx,edx; and eax,edx
sete dl;
mov [esp+1],al; mov [esp+2],dl;
jmp @@normalize
@@2: xor edx,edx; div ecx;
mov [esp+1],dl;
cmp eax,ecx; ja @@3
sbb edx,edx; and eax,edx
sete ah; mov [esp+2],ax;
jmp @@normalize
@@3: xor edx,edx; div ecx;
mov [esp+2],dl; mov [esp+3],al;
@@normalize:
pop eax; add eax,AllOnes;
end;
function asmNZNtoInt(const NZN: cardinal; const base: byte): integer; overload;
const AllOnes = $01010101;
asm
sub eax,AllOnes;
jnz @@0; ret
@@0:
push ebx; push eax;
movzx ebx,al; movzx ecx,dl;
test ah,ah; jz @@1;
movzx eax,ah; mul ecx;
add ebx,eax;
@@1:
movzx eax,[esp+2];
test eax,eax; jz @@2
push eax;
mov eax,ecx; mul ecx;
pop edx; mul edx;
add ebx,eax;
@@2:
movzx eax,[esp+3];
test eax,eax; jz @@3
push eax;
mov eax,ecx; mul ecx; mul ecx;
pop edx; mul edx;
add ebx,eax
@@3:
pop eax; mov eax,ebx;
pop ebx;
end;
function asmDivMod(const Dividend: cardinal;
const Divisor: byte; var Reminder: byte): cardinal;
asm
push ecx; movzx ecx,dl;
xor edx,edx; div ecx;
pop ecx; mov [ecx],dl;
end;
function mod255(const I: cardinal): byte;
asm
movzx edx,al; movzx ecx,ah
bswap eax
add ecx,edx; movzx edx,ah
movzx eax,al; add edx,ecx
add eax,edx;
add al,ah; xor ah,ah;
end;
{ when base is constant = 255, we could replace mul with cheaper shift/sub }
function asmNZNtoInt(const NZN: cardinal): integer; overload; // base = 255
// the 2nd byte need to be multiplied by 255 or (100h - 1)
// the 3rd byte need to be multiplied by 255 255 or (100h - 1) (100h - 1)
// the 4rd byte need to be multiplied by 255^3 or (100h - 1)^3
// and so on.. for integer more than 4 bytes wide
const AllOnes = $01010101;
const m0 = 0; m1 = $FF; m2 = $FE01; m3 = $00FD02FF;
const m1neg = 1;
const m2neg = $01FF; // // = 200 - 1
const m3neg = $0002FD01; // = 30000 - 2FF = 30000 - (300 - 1)
// = 30000 - 300 + 1
// = 3 (10000 - 100) + 1
// = 3 100 (100 - 1) + 1
asm
{ the branch prediction failure's penalty is absurdly high }
{ we'd better let all inst. pass rather than jcc }
sub eax,AllOnes; //jnz @@begin; ret
//test eax, not $ff; jnz @@begin; ret
;@@begin:
push ebx; mov ebx,eax;
movzx edx,ah; sub ebx,edx;
shr eax,16; jz @@end
movzx ecx,al; movzx edx,al;
shl ecx,8+1; sub ecx,edx;
sub ebx,ecx;
and eax,not 0ffh; jz @@end;
mov ecx,eax; movzx edx,ah;
shl ecx,8; sub ebx,edx;
sub ecx,eax; mov eax,ecx;
add ecx,ecx; add ecx,eax;
sub ebx,ecx;
@@end: mov eax,ebx; pop ebx;
end;
EOF.
dbzCrypt.pasunit dbzCrypt;
{$WEAKPACKAGEUNIT ON}
{
Copyright (c) 2004, aa, Adrian H. & Inge DR.
Property of PT SOFTINDO Jakarta.
All rights reserved.
mailto:aa|AT|softindo|DOT|net,
http://delphi.softindo.net
Version: 1.0.0.000
Dated: 2005.01.01
LastRev: 2007.01.01
LastRev: 2008.05.01 - using new algorithm ID capacity now upto 16581375 (~16M)
}
{
indexed Nonzero encrypt. include additional index infomation
in the encrypted string. need additional 4 bytes as index
(encrypted string will be 4 characters longer than original)
useful to retain field index/order
note:
since index will be hi-stripped, 3 bytes wide, then max. value
of index is: 128 128128-1 = 2097151 (roughly 2 million) --obsolete
should be enough for most of database --obsolete
(it could be up to 268435455 if you're not using random salt-key)
+ 2007.0.0: (untested!) added NZidEncrypt64/NZidDecrypt64 #deprecated
to overcome 2M limitation as noticed above. #deprecated
-------------------------------------------------------------------------
2008.05.01: implementation of natural (non-zero positive) integer number
(see artcle attached)
now max.ID (3 bytes) capacity upto: 255255 255 = 16,581,375
and thus CRID64 NZidEncrypt64/NZidDecrypt64 is deprecated,
i think 16M just quite enough, i'm not planning to index for
monster database as google or wiki's
}
interface
type
THexString = string; //mod32's string xor32
function XOR32(const S: string): string;
function XOR32encrypt(const Str: string): THexString; // encrypt TO hexStr
function XOR32decrypt(const HexStr: THexString): string; // decrypt FROM hexStr
// encrypt S without containing#0in the result, useful for pchar
// or database string field which does not accept#0within string
function NZDecrypt(const S: string): string;
function NZEncrypt(const S: string): string;
function NZDecryptOfHexStr(const HexStr: THexString): string;
function NZEncryptToHexStr(const Str: string): THexString;
function NZidDecrypt(const S: string): string;
function NZidEncrypt(const S: string; const ID: integer = 0): string;
function NZidDecryptOfHexStr(const HexStr: THexString): string;
function NZidEncryptToHexStr(const Str: string; const ID: integer = 0): THexString;
// NZ_PIX will be used as key seed generator
function HexStrtoStr(const HexStr: string): string;
function StrtoHexStr(const Str: string): string;
const
NZ_PIX: int64 = trunc(PI 1E18);
MAX_NZID = high(byte) high(byte) high(byte) cardinal(high(byte)); // max capacity of nzid
function asmInttoNZN(const I: cardinal; const base: byte = 255): integer;
function asmNZNtoInt(const NZN: cardinal): integer; overload; // constant base = 255
function asmNZNtoInt(const NZN: cardinal; const base: byte): integer; overload;
implementation
//uses Ordinals;
type
r64 = packed record
case Integer of
0: (Lo, Hi: Cardinal);
1: (Cardinals: array[0..1] of Cardinal);
2: (Words: array[0..3] of Word);
3: (Bytes: array[0..7] of Byte);
end;
function rol(const I: integer): integer; overload asm rol I, 1 end;
function rol(const I: Int64): Int64; overload asm
mov edx, I.r64.hi // using register is faster than directly accessing memory
mov eax, I.r64.lo // in Pentium they could also be run parallelized
shl eax, 1; rcl edx, 1
jnc @done; or eax, 1
@done: //popfd
end;
function ror(const I: integer): integer; overload asm ror I, 1 end;
function ror(const I: Int64): Int64; overload asm
mov edx, I.r64.hi // using register is faster than directly accessing memory
mov eax, I.r64.lo // in Pentium they could also be run parallelized
shr edx, 1; rcr eax, 1
jnc @done; or edx, 1 shl 31
@done: //popfd
end;
function rol(const I: Int64; const ShiftCount: integer): Int64; overload register asm
mov ecx, ShiftCount // as Intel says, upon shift this value will be taken MODULO 32
mov edx, I.r64.hi // using register is faster than directly accessing memory
mov eax, I.r64.lo // in Pentium they could also be run parallelized
and ecx, $3f; jz @exit
cmp cl, 32; jb @begin
//xchg eax, edx // avoid LOCK prefixed xchg instruction
mov eax, edx // simple move should be faster & pairing enable
mov edx, I.r64.lo //
jz @exit
@begin:
push ebx; mov ebx, eax
shld eax, edx, cl
shld edx, ebx, cl
@done: pop ebx
@exit:
end;
function ror(const I: Int64; const ShiftCount: integer): Int64; overload register asm
mov ecx, ShiftCount // as Intel says, upon shift this value will be taken MODULO 32
mov edx, I.r64.hi // using register is faster than directly accessing memory
mov eax, I.r64.lo // in Pentium they could also be run parallelized
and ecx, $3f; jz @exit
cmp cl, 32; jb @begin
//xchg eax, edx // avoid LOCK prefixed xchg instruction
mov eax, edx // simple move should be faster & pairing enable
mov edx, I.r64.lo //
jz @exit
@begin:
push ebx; mov ebx, edx
shrd edx, eax, cl
shrd eax, ebx, cl
@done: pop ebx
@exit:
end;
function rol(const I: integer; const ShiftCount: integer): integer; overload register asm
mov ecx, ShiftCount; rol I, cl
end;
function ror(const I: integer; const ShiftCount: integer): integer; overload register asm
mov ecx, ShiftCount; ror I, cl
end;
function asmInttoNZN(const I: cardinal; const base: byte = 255): integer;
const AllOnes = $01010101;
asm
test eax, not 0ffh; jnz @@0
add eax,AllOnes; ret;
@@0: movzx ecx,dl; //sanitize
//cmp eax,ecx; ja @@1
//sbb edx,edx; and eax,edx
//sete ah; add eax,AllOnes; ret;
;@@1: xor edx,edx; push edx; // Result
div ecx; mov [esp],dl;
cmp eax,ecx; ja @@2
sbb edx,edx; and eax,edx
sete dl;
mov [esp+1],al; mov [esp+2],dl;
jmp @@normalize
@@2: xor edx,edx; div ecx;
mov [esp+1],dl;
cmp eax,ecx; ja @@3
sbb edx,edx; and eax,edx
sete ah; mov [esp+2],ax;
jmp @@normalize
@@3: xor edx,edx; div ecx;
mov [esp+2],dl; mov [esp+3],al;
@@normalize:
pop eax; add eax,AllOnes;
end;
function asmNZNtoInt(const NZN: cardinal; const base: byte): integer; overload;
const AllOnes = $01010101;
asm
sub eax,AllOnes;
jnz @@0; ret
@@0:
push ebx; push eax;
movzx ebx,al; movzx ecx,dl;
test ah,ah; jz @@1;
movzx eax,ah; mul ecx;
add ebx,eax;
@@1:
movzx eax,[esp+2];
test eax,eax; jz @@2
push eax;
mov eax,ecx; mul ecx;
pop edx; mul edx;
add ebx,eax;
@@2:
movzx eax,[esp+3];
test eax,eax; jz @@3
push eax;
mov eax,ecx; mul ecx; mul ecx;
pop edx; mul edx;
add ebx,eax
@@3:
pop eax; mov eax,ebx;
pop ebx;
end;
{ when base is constant = 255, we could replace mul with cheaper shift/sub }
function div255(const I: cardinal): byte;
asm
end;
function mod255(const I: cardinal): byte;
asm
movzx edx,al; movzx ecx,ah
bswap eax
add ecx,edx; movzx edx,ah
movzx eax,al; add edx,ecx
add eax,edx; add al,ah
xor ah,ah
end;
function asmNZNtoInt(const NZN: cardinal): integer; overload; // constant base = 255
const AllOnes = $01010101;
const m1 = $FF; m2 = $FE01; m3 = $00FD02FF;
const m2neg = $1FF; // // = 200 - 1
const m3neg = $0002FD01; // = 30000 - 2FF = 30000 - 300 + 1
// = 3 (10000 - 100) + 1
// = 3 100 (100 - 1) + 1
asm
{ the branch prediction failure's penalty is absurdly high }
{ we'd better let all inst. pass rather than jcc }
sub eax,AllOnes; //jnz @@begin; ret
//test eax, not $ff; jnz @@begin; ret
;@@0:
push ebx; mov ebx,eax;
movzx edx,ah; sub ebx,edx;
shr eax,16; jz @@end
movzx ecx,al; movzx edx,al;
shl ecx,8+1; sub ecx,edx;
sub ebx,ecx;
and eax,not 0ffh; jz @@end;
mov ecx,eax; movzx edx,ah;
shl ecx,8; sub ebx,edx;
sub ecx,eax; mov eax,ecx;
add ecx,ecx; add ecx,eax;
sub ebx,ecx;
@@end: mov eax,ebx; pop ebx;
end;
// StrToHexStr and HexStrToStr functions are made to remove dependency to
// bigshit ordinals unit (also made by us). if you are using ordinals unit
// then this stupid little craps are not needed. use much-much-much more capable
// ordinals.hexs routines instead;
function StrtoHexStr(const Str: string): string;
// returns HexString (byte-per-byte in hexdigits) representation of string
const hexdigit = '0123456789ABCDEF';
var
i, b: integer;
begin
Result := '';
for i := 1 to length(Str) do begin
b := ord(Str[i]);
Result := result +
hexdigit[(b shr 4) and $0F + 1] + hexdigit[b and $0F + 1];
end;
end;
function HexStrtoStr(const HexStr: THexString): string;
// convert array of each 2 hex digits ['0'..'9','a'..'f', 'A'..'F']
// pairs to their respective character counterpart (make them a string)
// (any invalid hex digits will be skipped)
// length should be an even number, unpaired last digit
// (if length is an odd number), will also be skipped.
const HEXDIGITS = ['0'..'9', 'A'..'F', 'a'..'f'];
function StrToIntDef(const S: string; Default: Integer): Integer;
var E: Integer;
begin
Val(S, Result, E);
if E <> 0 then Result := Default;
end;
var
i, n: integer;
vHex, sn: string;
begin
vHex := ''; //(Validated HexStr)
for i := 1 to length(HexStr) do
if HexStr[i] in HEXDIGITS then
vHex := vHex + HexStr[i];
Result := '';
for i := 0 to length(vHex) div 2 - 1 do begin
sn := '$' + copy(vHex, i 2 + 1, 2);
n := strToIntDef(sn, 0);
Result := Result + char(n);
end;
end;
function XOR32(const S: string): string;
var
i: integer;
begin
i := length(S);
setLength(Result, i);
for i := 1 to i do
Result[i] := char(ord(s[i]) xor (i and $1F));
end;
function XOR32encrypt(const Str: string): THexString; begin // encrypt TO hexStr
Result := StrtoHexStr(XOR32(Str));
end;
function XOR32decrypt(const HexStr: THexString): string; begin // decrypt FROM hexStr
Result := XOR32(HexStrtoStr(HexStr));
end;
function NZEncrypt(const S: string): string;
var
i, l: integer;
Key: integer; //64;
b: byte;
begin
l := length(S);
setlength(Result, l);
if l > 0 then begin
Key := l NZ_PIX;
for i := l downto 1 do begin
b := ord(S[i]);
if b <> byte(Key) then b := b xor (Key);
Key := rol(Key, (b or 1));
Result[l - i + 1] := char(b);
end;
end;
end;
function NZDecrypt(const S: string): string;
var
i, l: integer;
Key: integer; //int64;
b0, b: byte;
begin
l := length(S);
setlength(Result, l);
if l > 0 then begin
Key := l NZ_PIX;
for i := 1 to l do begin
b0 := ord(S[i]);
if b0 = byte(Key) then b := Key // do NOT forget byte(Key) typecast!
else b := b0 xor Key;
Key := rol(Key, (b0 or 1));
Result[l - i + 1] := char(b);
end;
end;
end;
function NZEncryptToHexStr(const Str: string): string;
begin
Result := StrtoHexStr(NZEncrypt(Str));
end;
function NZDecryptOfHexStr(const HexStr: string): string;
begin
Result := NZDecrypt(HexStrtoStr(HexStr));
end;
type
TCrIDType = type integer; // decoded: (Key) + (3 7 bits)
// max = 128 128128-1 = 2097151
const
PREFIXLEN = sizeof(TCrIDType);
PREFIXLEN2 = PREFIXLEN 2;
// ID use only 3 bytes, the most significant byte of ID will not be used!
function getCrID(const ID: integer; OpenChar: char): integer; overload;
var
Key: byte;
function BigEndian3bytes(const I: integer): integer; asm bswap eax; shr eax,8; end; // only 3 bytes used + 2 bits
begin
repeat Key := random(high(Key) + 1)
until (byte(key) > 0) and (byte(Key) <> ord(OpenChar));
Result := asmInttoNZN(ID);
Result := BigEndian3bytes(Result) or (Key shl 24)
end;
function NZidDecrypt(const S: string): string; {$Q-} // no-overflow-checking
var
i, l: integer;
Key: int64;
b0, b: byte;
begin
l := length(S) - PREFIXLEN;
if l < 1 then Result := ''
else begin
setlength(Result, l);
move(S[1], I, sizeof(PREFIXLEN));
Key := I NZ_PIX;
RandSeed := Key;
Key := Key integer(Random(MaxInt));
for i := 1 to l do begin
b0 := ord(S[i + PREFIXLEN]);
//OK.
//if (Key and $60) > 0 then
// b := b0 xor (Key and $9F)
//else b := b0 xor Key;
if b0 = byte(Key) then b := byte(Key) // do NOT forget byte(Key) typecast!
else b := b0 xor Key;
Key := rol(Key, (b0 or 1));
Result[l - i + 1] := char(b);
end;
end;
end;
function NZidEncrypt(const S: string; const ID: integer = 0): string; {$Q-} // no-overflow-checking
var
i, l, X: integer;
Key: int64;
b: byte;
begin
l := length(S);
if l < 1 then Result := ''
else begin
setlength(Result, l + PREFIXLEN);
X := getCrID(ID, S[l]);
move(X, Result[1], PREFIXLEN);
Key := X NZ_PIX;
RandSeed := Key;
Key := Key integer(Random(MaxInt));
for i := l downto 1 do begin
b := ord(S[i]);
//OK.
//if (Key and $60) > 0 then
// b := b xor (Key and $9F)
//else b := b xor Key;
//b := b xor Key;
//if b = 0 then b := Key;
if b <> byte(Key) then b := b xor (Key);
Key := rol(Key, (b or 1));
Result[l - i + PREFIXLEN + 1] := char(b);
end;
end;
end;
function NZidEncryptToHexStr(const Str: string; const ID: integer = 0): THexString;
begin
Result := StrtoHexStr(NZidEncrypt(Str, ID));
end;
function NZidDecryptOfHexStr(const HexStr: THexString): string;
begin
Result := NZidDecrypt(HexStrtoStr(HexStr));
end;
end.
Random Articles
- Tips: Syncro-Edit in Lazarus
- Simulasi Infeksi Virus 1.0 - OpenSource
- Mengambil aktif caption bar suatu aplikasi
- open Ms-Exell dari delphi
- Komponen --> Progress Bar
- PascalClass #3: Web Development with Free Pascal
- Membuat kontrol db aware
- Castle Game Engine for Web
- Combobox didalam cell stringgrid dan radio butto didalam listbox
- Kulgram : Instalasi Lazarus di Perangkat Berbasis ARM
AI Forward

๐ We're thrilled to partner with Alibaba Cloud for "AI Forward - Alibaba Cloud Global Developer Summit 2025" in Jakarta! Join us and explore the future of AI. Register now:
https://int.alibabacloud.com/m/1000400772/
#AlibabaCloud #DeveloperSummit #Jakarta #AIFORWARD
Last Articles
Recent Topic
- PascalTalk #6: (Podcast) Kuliah IT di luar negeri, susah gak sih?
by LuriDarmawan in Tutorial & Community Project more 4 years ago - PascalTalk #5: UX: Research, Design and Engineer
by LuriDarmawan in Tutorial & Community Project more 4 years ago - PascalTalk #4: Obrolan Ringan Seputar IT
by LuriDarmawan in Tutorial & Community Project more 4 years ago - PascalTalk #2: Membuat Sendiri SMART HOME
by LuriDarmawan in Tutorial & Community Project more 4 years ago - PascalTalk #3: RADically Fast and Easy Mobile Apps Development with Delphi
by LuriDarmawan in Tutorial & Community Project more 4 years ago - PascalTalk #1: Pemanfaatan Artificial Intelligence di Masa Covid-19
by LuriDarmawan in Tutorial & Community Project more 4 years ago - Tempat Latihan Posting
by LuriDarmawan in OOT more 5 years ago - Archive
- Looping lagi...
by idhiel in Hal umum tentang Pascal Indonesia more 12 years ago - [ask] koneksi ke ODBC user Dsn saat runtime dengan ado
by halimanh in FireBird more 12 years ago - Validasi menggunakan data tanggal
by mas_kofa in Hal umum tentang Pascal Indonesia more 12 years ago