Snippet Scrambler

Nestharus

o-o
Reaction score
84
Statistics
As the data set increases in value or decreases in value, the average increases/decreases in value. Because of this, lower values are weighted on one side and higher values are weighted on another side with medium values in the center. This is the reason why this fails the runs test with large numbers of data.

This behavior is to be expected and is actually desirable for this =).

Within a local area of 20 or 80, the data is very even as the data set isn't large enough to cause this effect.

So given a number, you can expect it to fall within a specific range. The larger the number, the bigger the range it can fall in. As save/load codes are very large, the effect that takes away from the randomness will take much longer to occur (I was dealing with a very small value of 65536), meaning that this will pretty much generate a random number given a number.

To give you an idea of the range for larger numbers, 65536 goes between around 4500 and 1.2 million.

Why do numbers around 65000 have output between 4000 and 1.2 million?
Going above 65536, the bits in a given number is 17.

When a number is shuffled in something like base 3, 1.5 bits are moved around for every movement. Every digit in base 3 is made up of 1.5 binary digits.

In base 3: 2
In base 2: 10

In base 5: 4
In base 2: 100

In base 7: 6
In base 2: 110

In base 11: A
In base 2: 1011

So these different fractions split apart and combine binary digits, thus giving the absolutely wild ranges that can be seen coming from Scrambler.

This makes reading a number w/o knowing the algorithm used to mix it up totally impossible.

Recall that this algorithm both includes the bases used in every shuffle as well as the hash of the player's name + a string value.

Tests going over larger numbers in different scenarios to see if any patterns arose.
Code:
Base 64=	<23456789abcdefgh>+kmn=pqrs^uvwxyzABCDEFGHKLMNOPQRSTUVWXYZ@#?&%$	
Base 63=	<23456789abcdefgh>+kmn=pqrs^uvwxyzABCDEFGHKLMNOPQRSTUVWXYZ@#?&%	
2^50=	1125899906842624	
Prime=	2736653538294121	
		
64 2^50  	64 Prime	63 Prime
		
5<<<<<<<<	aOgBf2xDH	c2P%VhA2G
		
78BWPx4ak	8QvfC6w0=	9SkYRdE=Q
9ZW=HQkA?	87cb<Fe#X	947HQ^wHc
bzv3sagrd	DL6T+LaNk	KO6GE%hh+
7<ckQ5NvA	ghDcDxVC2	>kq#u<FeQ
aXX>gPEf3	hXfmUS^fW	k9<5%8%YS
7VfZ^+pp<	eb9qPFDMr	f@>s%r#d@
cy+exR<Vd	dUgsSYYsE	fzUFx8&Zh
b9dq=wZm9	7WXeu@#=h	8R<EbfxW#
cMWgrSMCa	qMfGu<>Uq	u<qY%?dGW
6>cbzR$ZK	cVCFmTk5Y	esW=DDggD
6e5KvR=cc	6A=EM&3@E	7>H23Fe>S
ecx@xfZaN	fSUkNB9E>	hRb+#WKgs
9d<d<Rrkr	d^=hvCZxU	f73CZ3MTw
dZZ#YZGVY	dAg#kdLTv	feP2xDZ^=
6Q9bC?v43	h@frwy8KR	kc=cMXxcn
gMsnqqYHO	6wKaaVf8>	7ez8KNup?
9qdE$qD?7	exY3&8YW+	gkA%#u5x0
9yb>PAnzB	cFFg#ewOs	ec>v7OzPs
d%sRLp<B2	+p&uf#rcu	mV<NF3uEg
9cDXCXaQq	gBZdwbb5m	>G?^%^z%5
7hm=GHHfa	8UU4POXV+	9Xc=@vaM+
h>@FQTn>Z	v%98dEk8%	z%K^=X5fX
h6&$Ugb&b	z6fNH9%rn	Dy&SO#m53
9a?f%h5?4	8da^GrN?D	9aQT0>^rb
bHAngfKHd	5KQCAykzL	6+Cqs8hwF
b%&AVyAd?	>L%qWZ+AR	m4YMpD?6L
9KuBGS#4=	7gSvhG736	86q33fYKL
 +FxxpdyUv	r4=v7?zqf	usepKf7F^
aHxgyVUT+	yDPW<4bY=	C?UhP>Z=a
5ey=qZ@ED	9UzLQ<V@e	b<m5N<+5Y
>T8hF#svM	bVR#p@aY<	d+G6mrC%3
k9S$bT8&g	cNwnSbS$G	e>TNGAKg6
9g+<phf4U	xUyFMrZFH	C6VP?SB=N
 +qYLsue9h	C60^LBKGy	G@ZqvCF6W
5UCc86Z+5	k>y<6y>q$	nWheVMbbm
aQT=RAm6G	c%uUZF4BN	eCQXspa+>
7sap#gBNf	9QkEp<WD9	a@EfeUq%0
dGzsYGqZ%	>KmKc%S8<	m34xnP4v%
dAmXak7S8	d3aVKvsSR	eGZpXzAAm
7w3VvCTsF	fn7536Vzm	hg&A^8KEy
6>=UEw@WP	hkwFcMg@T	 +x6Hspq=x
>Ym$xV$md	cSXCBb?3$	epVbyU^Q8
f&SNY66TY	7SGgrg8fh	8M>R=BK7%
bGn7$vrVq	9ERPfXAFy	aP?@vG9@2
c?A2xq90G	DsYPF%<uw	K^%TuW@Eb
ad=AFceY4	eG+fTqCR4	gu#yDV^>#
gUgf4FWk+	x2ncBXm7D	BcM054mAu
6&65nH=$$	=wN$Vv$fT	rxqQM7>vX
99FkycbF8	hkcx+q63X	 +wPGh76bX
aQT?AD%b@	cdc+efzZg	dLGwz7@L@

Requirements:
JASS:

library Scrambler uses /* v3.0.0.2
*************************************************************************************
*
*   Scrambles/Shuffles a BigInt given a player id.
*
*   This applies a StringHash to the player, converts that hash into base 8, and
*   then uses that as a key. The end result is that each player&#039;s code (when
*   this is used for save/load) is scrambled/shuffled differently.
*
*   Scrambling:
*               Shuffles in a specific base a number of times.
*               Useful for mixing up save/load keys (the character sets)
*               Recommend including front digit as data won&#039;t be lost for most uses
*   Shuffling:
*               Shuffles through a set of prime bases a number of times.
*               Useful for mixing up save/load codes
*
*************************************************************************************
*
*   REQUIREMENTS
*   
*       */ BigInt /*hiveworkshop.com/forums/jass-functions-413/system-bigint-188973/
*
************************************************************************************
*
*   SETTINGS
*/
    globals
    /*************************************************************************************
    *
    *                                       SALT
    *
    *   Refers to what to append to the player&#039;s name when generating scrambler keys
    *   for each player. This is essentially like a password. It&#039;s impossible for another
    *   map to descramble a number without this password.
    *
    *   This password can be any string, such as &quot;7/ah+53~r\\ZZ&quot;
    *
    *************************************************************************************/
        private constant string SALT = &quot;&quot;
    endglobals
    
    /*************************************************************************************
    *
    *                                   SetShuffleOrder
    *
    *   Creates the shuffling algorithm using 5 different prime bases.
    *
    *   Shuffling mixes a number up using a variety of bases to produce results rivaling
    *   top random number generators.
    *
    *   Different bases ensure better mixes.
    *
    *   Enabled Bases: 
    *
    *       2
    *           Will shuffle number in groups of 1 bit
    *       3
    *           Will shuffle number in groups of 1.58 bits
    *       5
    *           Will shuffle number in groups of 2.32 bits
    *       7
    *           Will shuffle in groups of 2.81 bits
    *       11
    *           Will shuffle in groups of 3.46 bits
    *
    *   Strategies:
    *
    *       1.
    *           shuffle by large1, shuffle by small1, shuffle by large2, etc
    *       2.
    *           shuffle by small1, shuffle by large1, shuffle by small2, etc
    *       3.
    *           shuffle by small1, shuffle by small2, shuffle by large1, shuffle by small3, etc
    *
    *       Keep in mind that as fractional bits are shuffled, bits split/merge, meaning that the number
    *       can drastically change by becoming much smaller or much larger.
    *
    *
    *   Shuffle Array: so
    *
    *   Ex:
    *
    *       set so[0]=3         //first mix by 1.58 bits
    *       set so[1]=2         //second mix by 1 bit
    *       set so[2]=7         //third mix by 2.81 bits
    *       set so[3]=2         //fourth mix by 1 bit
    *
    *       return 4            //return number of mixes
    *
    *************************************************************************************/
    private keyword so
    private function SetShuffleOrder takes nothing returns integer
        /*************************************************************************************
        *
        *                                       MIXES
        *
        *   array: so
        *   bases: 2,3,5,7,11
        *
        *************************************************************************************/
        set so[0]=5
        set so[1]=2
        set so[2]=3
        set so[3]=11
        set so[4]=2
        set so[5]=7
        set so[6]=3
        
        /*************************************************************************************
        *
        *                                       MIX COUNT
        *
        *************************************************************************************/
        return 7
    endfunction
/*
************************************************************************************
*
*   function Scramble takes BigInt intToScramble, integer forPlayerId, integer shuffles, Base baseToScrambleIn, boolean includeFront returns nothing
*   function Unscramble takes BigInt intToScramble, integer forPlayerId, integer shuffles, Base baseToScrambleIn, boolean includeFront returns nothing
*
*   function Shuffle takes BigInt intToScramble, integer forPlayerId, integer shuffles returns nothing
*   function Unshuffle takes BigInt intToScramble, integer forPlayerId, integer shuffles returns nothing
*
************************************************************************************
*
*   function Scramble takes BigInt intToScramble, integer forPlayerId, integer shuffles, Base baseToScrambleIn, boolean includeFront returns nothing
*
*       Scrambles a BigInt at the binary level.
*
*           intToScramble:          BigInt
*           forPlayerId:            id of human player*
*           shuffles:               how many times to shuffle number (must be &gt; 0)
*           baseToScrambleIn:       what base to scramble number in
*
************************************************************************************
*
*   function Unscramble takes BigInt intToScramble, integer forPlayerId, integer shuffles, Base baseToScrambleIn, boolean includeFront returns nothing
*
*       Unscrambles a BigInt at the binary level.
*
*           intToScramble:          BigInt
*           forPlayerId:            id of human player*
*           shuffles:               how many times to unshuffle number
*           baseToScrambleIn:       what base to shuffle number in
*           includeFront:           this determines whether to include front number or not
*
*                                   including  the front number isn&#039;t advisable as 0s 
*                                   may move to the front, meaning data can be lost
*
*                                   Scramble(1000) -&gt; 0001, or 1
*
************************************************************************************
*
*   function Shuffle takes BigInt intToScramble, integer forPlayerId, integer shuffles returns nothing
*
*       Scrambles a BigInt using user-defined algorithm.
*
*           intToScramble:          BigInt
*           forPlayerId:            id of human player*
*           shuffles:               how many times to shuffle number (must be &gt; 0)
*
************************************************************************************
*
*   function Unshuffle takes BigInt intToScramble, integer forPlayerId, integer shuffles returns nothing
*
*       Scrambles a BigInt using user-defined algorithm.
*
*           intToScramble:          BigInt
*           forPlayerId:            id of human player*
*           shuffles:               how many times to unshuffle number
*
************************************************************************************/
    globals
        private integer array ss
        private boolean array se
        private BigInt array d
        private integer i
        private integer dc
        private integer k
        private integer s1
        private integer s2
        private integer s3
        private integer pid
        private trigger mt=CreateTrigger()      //mix trigger
        private trigger dt=CreateTrigger()      //demix trigger
        private trigger st=CreateTrigger()      //scramble trigger
        private trigger ut=CreateTrigger()      //unscramble trigger
        private BigInt bi
        private Base array bs
        private integer array so
        private integer sc=0
    endglobals
    private function LNF takes BigInt int,boolean i0 returns nothing
        set dc=0
        if (i0) then
            loop
                set int=int.next
                exitwhen int.end
                set d[dc]=int
                set dc=dc+1
            endloop
        else
            loop
                set int=int.next
                exitwhen int.next.end
                set d[dc]=int
                set dc=dc + 1
            endloop
            set int=int.next
        endif
    endfunction
    private function LNB takes BigInt int,boolean i0 returns nothing
        set dc=0
        if (not i0) then
            set int=int.previous
        endif
        loop
            set int=int.previous
            exitwhen int.end
            set d[dc]=int
            set dc=dc+1
        endloop
    endfunction
    private function FLP takes integer id,integer i2 returns nothing
        //find last position
        loop
            exitwhen 0==i2
            set s1=dc
            loop
                exitwhen 0==s1
                set s1=s1-1
                if (se[k]) then
                    set k=ss[id]
                else
                    set k=k+1
                endif
            endloop
            set i2=i2-1
        endloop
    endfunction
    function Scramble takes BigInt int,integer id,integer shuffles,Base bb,boolean i0 returns nothing
        local Base b=int.base
        set pid=id
        set k=ss[id]
        set i=shuffles
        debug if (0!=ss[id]) then
            if (b!=bb) then
                set int.base=bb
            endif
            //load number
            call LNF(int,i0)
            //scramble
            call TriggerEvaluate(st)
            if (b!=bb) then
                set int.base=b
            endif
        debug else
            debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,&quot;SCRAMBLER ERROR: INVALID PLAYER &quot;+I2S(id))
        debug endif
    endfunction
    function Unscramble takes BigInt int,integer id,integer shuffles,integer bb,boolean i0 returns nothing
        local Base b=int.base
        set i=shuffles
        set pid=id
        set k=ss[id]
        debug if (0!=ss[id]) then
            if (b!=bb) then
                set int.base=bb
            endif
            //load number
            call LNB(int,i0)
            //retrieve last position
            call FLP(id,shuffles)
            //unscramble
            call TriggerEvaluate(ut)
            if (b!=bb) then
                set int.base=b
            endif
        debug else
            debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,&quot;SCRAMBLER ERROR: INVALID PLAYER &quot;+I2S(id))
        debug endif
    endfunction
    //scramble
    private function St takes nothing returns boolean
        loop
            exitwhen 0==i   //exitwhen no more shuffles
            set s1=dc       //loop through digits from left-1 to right
                            //don&#039;t shuffle left most to save a bit as
                            //left most must be 1
            loop
                exitwhen 0==s1  //exitwhen no more digits
                set s1=s1-1     //shift down as array ends at n-1
                //current digit slot - hash digit (shift right)
                set s2=s1-ss[k]
                //if s2 is negative, add total digits until positive
                loop
                    exitwhen 0&lt;=s2
                    set s2=dc+s2
                endloop
                //swap s2 and s1
                set s3=d[s2].digit
                set d[s2].digit=d[s1].digit
                set d[s1].digit=s3
                //if out of digits, go back to first digit on hash
                //otherwise, go to next digit
                //last existing digit is marked as end
                if (se[k]) then
                    set k=ss[pid]
                else
                    set k=k+1
                endif
            endloop
            set i=i-1
        endloop
        return false
    endfunction
    //unscramble
    private function Ut takes nothing returns boolean
        //go backwards
        loop
            exitwhen 0==i
            set s1 = dc
            loop
                exitwhen 0==s1
                set s1=s1-1
                set k=k-1
                if (0==ss[k]) then
                    set k=ss[pid+12]
                endif
                set s2=s1+ss[k]
                loop
                    exitwhen s2&lt;dc
                    set s2=s2-dc
                endloop
                set s3=d[s2].digit
                set d[s2].digit=d[s1].digit
                set d[s1].digit=s3
            endloop
            set i=i-1
        endloop
        return false
    endfunction
    //shuffle
    private function Mt takes nothing returns boolean
        local integer sh=0
        set k=ss[pid]
        loop
            exitwhen sh==sc
            set i=1
            set bi.base=bs[so[sh]]
            call LNF(bi,false)
            call St()
            set sh=sh+1
            set k=ss[pid]
        endloop
        return false
    endfunction
    //unshuffle
    private function Dt takes nothing returns boolean
        local integer sh=sc
        set k=ss[pid]
        loop
            exitwhen 0==sh
            set sh=sh-1
            set i=1
            set bi.base=bs[so[sh]]
            call LNB(bi,false)
            call FLP(pid,1)
            call Ut()
            set k=ss[pid]
        endloop
        return false
    endfunction
    
    function Shuffle takes BigInt int, integer id, integer h returns nothing
        local Base b=int.base
        debug if (0!=ss[id]) then
            set bi=int
            set pid=id
            loop
                exitwhen 0==h
                call TriggerEvaluate(mt)
                set h=h-1
            endloop
            set int.base=b
        debug else
            debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,&quot;SCRAMBLER ERROR: INVALID PLAYER &quot;+I2S(id))
        debug endif
    endfunction
    function Unshuffle takes BigInt int, integer id, integer h returns nothing
        local Base b=int.base
        debug if (0!=ss[id]) then
            set bi=int
            set pid=id
            loop
                exitwhen 0==h
                call TriggerEvaluate(dt)
                set h=h-1
            endloop
            set int.base=b
        debug else
            debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,&quot;SCRAMBLER ERROR: INVALID PLAYER &quot;+I2S(id))
        debug endif
    endfunction
    private module Init
        private static method onInit takes nothing returns nothing
            local integer is=11
            local integer hh
            local integer ks=25
            local Base b8=Base[&quot;012345678&quot;]
            local BigInt bg
            call TriggerAddCondition(mt,Condition(function Mt))
            call TriggerAddCondition(dt,Condition(function Dt))
            call TriggerAddCondition(st,Condition(function St))
            call TriggerAddCondition(ut,Condition(function Ut))
            set bs[2]=Base[&quot;01&quot;]
            set bs[3]=Base[&quot;012&quot;]
            set bs[5]=Base[&quot;01234&quot;]
            set bs[7]=Base[&quot;0123456&quot;]
            set bs[11]=Base[&quot;0123456789A&quot;]
            set sc=SetShuffleOrder()
            loop
                if (GetPlayerSlotState(Player(is))==PLAYER_SLOT_STATE_PLAYING and GetPlayerController(Player(is))==MAP_CONTROL_USER) then
                    set ss[is]=ks
                    set hh=StringHash(StringCase(GetPlayerName(Player(is))+SALT,false))
                    if (0&gt;hh) then
                        set hh=-hh
                    endif
                    set bg=BigInt.create(b8)
                    call bg.add(hh,0)
                    set bg=bg.previous
                    loop
                        set ss[ks]=bg.digit+1
                        set bg=bg.previous
                        exitwhen bg.end
                        set ks=ks+1
                    endloop
                    set se[ks]=true
                    set ss[is+12]=ks
                    call bg.destroy()
                    set ks=ks+2
                endif
                exitwhen 0==is
                set is=is-1
            endloop
        endmethod
    endmodule
    private struct Inits extends array
        implement Init
    endstruct
endlibrary


Demo
JASS:

globals
    constant boolean SCRAMBLE=false
    constant boolean DESHUFFLE=false
    constant integer SHUFFLES=1
    constant string NUMBER=&quot;65536&quot;
    constant integer RUNS=150
    constant integer NUM_PER_ROW=10
    constant string BASE=&quot;0123456789&quot;
    constant string SCRAMBLE_BASE=&quot;01&quot;
endglobals
struct tester extends array
    private static string c=NUMBER
    private static integer m=RUNS
    private static integer ad=0
    private static method r takes nothing returns nothing
        local Base b10=Base[BASE]
        local Base b3=Base[SCRAMBLE_BASE]
        local BigInt i
        local string s=&quot;&quot;
        local integer a=NUM_PER_ROW
        
        call DestroyTimer(GetExpiredTimer())
        loop
            exitwhen m==0
            set i=BigInt.convertString(c,b10)
            call i.add(ad,0)
            static if SCRAMBLE then
                call Scramble(i,0,SHUFFLES,b3,false)
            else
                call Shuffle(i,0,SHUFFLES)
            endif
            static if DESHUFFLE then
                static if SCRAMBLE then
                    call Unscramble(i,0,SHUFFLES,b3,false)
                else
                    call Unshuffle(i,0,SHUFFLES)
                endif
            endif
            set s=s+&quot; &quot;+i.toString()
            set a=a-1
            if (a==0) then
                set a=NUM_PER_ROW
                call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,6000,s)
                set s=&quot;&quot;
            endif
            set ad=ad+1
            set m=m-1
            call i.destroy()
        endloop
        if (a&lt;NUM_PER_ROW) then
            call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,6000,s)
        endif
    endmethod
    private static method onInit takes nothing returns nothing
        call TimerStart(CreateTimer(),0,false,function thistype.r)
    endmethod
endstruct
 

tooltiperror

Super Moderator
Reaction score
231
Salt should return a BigInt so you can do this stuff.

JASS:

function SaltForPlayer takes BigInt code, player p returns BigInt
    return Salt(code,GetPlayerId(p),3)
endfunction


Oh and I wish for a more interesting name for the library. Keep the function Salt but I think the proper term is desalt. And name it Sodium, that'd be hot.
 

Nestharus

o-o
Reaction score
84
Well, if you want to do that, then make a copy =).

JASS:

function SaltForPlayer takes BigInt code, player p returns BigInt
    set code = code.copy()
    call Salt(code,GetPlayerId(p),3)
    return code
endfunction


but in actual save/load stuff, you'd never need to make a copy >.<, lol, so I don't see the point ;P.

Also, I googled both Desalt and Unsalt and nothing turned up, so I dunno ;P.

And the library is not being named Sodium ^_^.

edit
I think at this point that BigInt should be the standard for save/load, lol.
 

tooltiperror

Super Moderator
Reaction score
231
I think the problem is that no one wants to use such an ugly interface.

I'd rather use ASCII and standard JASS2 functions instead of this.
 

tooltiperror

Super Moderator
Reaction score
231
No, not Salt, BigInt. I don't want to use this because I have to deal with those pesky BigInts. Not to mention BigInt is such an ugly name, anyways.
 

Sevion

The DIY Ninja
Reaction score
413
Meh. It could be called "long". It's not exactly the same, but meh. It at least makes sense and is less ugly.

JASS:
function blah takes nothing returns nothing
    local long l = long.create()
    // do stuff
endfunction
 

Risen

New Member
Reaction score
4
We should have a separate part of the forums, one new systems must undergo before being submitted.

The forum should be called "System Naming 101."
 

Sevion

The DIY Ninja
Reaction score
413
Why would that make any sense at all? The system thread is for discussing the system. (Which actually the previous discussion should be in the BigInt thread). The above discussion is about the system. Makes sense...
 

Jesus4Lyf

Good Idea™
Reaction score
397
//Salts a BigInt given a player id. Salting is a term in cryptography
//that means scrambling a number at the binary level given a hash.
No, it isn't. Salting in cryptography is appending random junk to a string before hashing it? This is not salting...

Salting has as much to do with hashing or scrambling as apples have to do with blenders.. so this is like saying "Apple is a term used to describe the process of producing apple juice with a blender".
 

Nestharus

o-o
Reaction score
84
I'll update to Scramble then : ).

Someone told me that scrambling was salting, but I guess I won't believe other coders from now on =).
 

Nestharus

o-o
Reaction score
84
Fixed a bug and removed a useless array ;D.

edit
Put debug in front of the display error message stuff (spaced out on that)
 

Nestharus

o-o
Reaction score
84
Updated to 3.0.0.1

This update just increases the speed of Scrambler.

I had too many trigger evals >: P
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top