Difference between revisions of "Talk:Key Compression"
Jump to navigation
Jump to search
Pedro Oval (talk | contribs) m (oops, how did that get there?) |
Pedro Oval (talk | contribs) (→Base 32768 optimized for size in Mono: new section) |
||
Line 42: | Line 42: | ||
integer2hex(llBase64ToInteger(llGetSubString(s,20,21)+"AA"))); | integer2hex(llBase64ToInteger(llGetSubString(s,20,21)+"AA"))); | ||
}</source> | }</source> | ||
== Base 32768 optimized for size in Mono == | |||
<source lang="lsl2"> | |||
// Copyright (C) 2009 Adam Wozniak and Doran Zemlja | |||
// Copyright (C) 2015 Pedro Oval | |||
// Released into the public domain. | |||
// Free for anyone to use for any purpose they like. | |||
// | |||
// INTERNALLY, strings are represented as UTF-16, and internal memory | |||
// is what we actually care about | |||
// | |||
// going for maximum compression, we should be able to get a 128 bit key | |||
// down to 8 x 16 bit characters | |||
// | |||
// we'll do this by encoding integers as UTF-8 URL escaped characters, | |||
// and calling llUnescapeURL to convert them to strings. | |||
// | |||
// unfortunately, UTF-16 has some unallowed codepoints. In particular, | |||
// llEscapeURL/llUnescapeURL fails on the following code points: | |||
// | |||
// 0000, D800-DFFF, FDD0-FDEF, FFFE, FFFF | |||
// | |||
// Let's just make our lives easy and go with 15 bits per character. | |||
// We'll encode 0000-7FFF as 0100-8100 to avoid null characters and leave | |||
// all ASCII characters available as serialisation seperators. | |||
// Also, let's go easy and just save up the 8 MSB as a final character at | |||
// the end. | |||
// | |||
// this gives us a quick and easy 9 character key | |||
// MOD: To make life even easier, use the range 0x800-0x8800 as they all | |||
// start with the same UTF-8 range and there are no bits to test. | |||
// (range is %E0-%EF) | |||
string bhex(integer in) | |||
{ | |||
return llGetSubString("0123456789abcdef", (in>>4) & 0xF, (in>>4) & 0xF) | |||
+ llGetSubString("0123456789abcdef", in & 0xF, in & 0xF); | |||
} | |||
integer utf2i(string c) | |||
{ | |||
integer ret = (integer)("0x" + (string)llParseString2List(llEscapeURL(c), (list)"%", [])); | |||
return ((ret & 0x0F0000) >> 4) + ((ret & 0x3F00) >> 2) + (ret & 0x3F) + (integer)-0x800; | |||
} | |||
string i2url(integer i) | |||
{ | |||
i += 0x800; | |||
return "%" + bhex(0xE0 | (i >> 12)) | |||
+ "%" + bhex(0x80 | ((i >> 6) & 0x3F)) | |||
+ "%" + bhex(0x80 | (i & 0x3F)) | |||
; | |||
} | |||
string compress_key(string k) | |||
{ | |||
k = (string)llParseString2List(k, (list)"-", []); | |||
string ret; | |||
integer i = (integer)-9; | |||
integer msbs; | |||
integer word; | |||
while (++i) | |||
{ | |||
word = (integer) ("0x" + llGetSubString(k, 4*i, ~(4*~i))); | |||
msbs = (msbs | (word & 0x8000)) >> 1; | |||
ret += i2url(word & 0x7FFF); | |||
} | |||
return llUnescapeURL(i2url(msbs) + ret); | |||
} | |||
string uncompress_key(string s) | |||
{ | |||
integer i = (integer)-9; | |||
integer value; | |||
integer msbs = utf2i(llGetSubString(s, value, value)); | |||
string ret; | |||
while (++i) | |||
{ | |||
value = utf2i(llGetSubString(s, i, i)) + ((msbs << (-i)) & 0x8000); | |||
ret += bhex(value>>8) + bhex(value); | |||
} | |||
i = 24; | |||
while ((i += (integer)-4) & (integer)-8) | |||
ret = llInsertString(ret, i, "-"); | |||
return ret; | |||
} | |||
// Example usage: generate a key, compress, uncompress, and check if it matches. | |||
default | |||
{ | |||
state_entry() | |||
{ | |||
string k = llGenerateKey(); | |||
string s = uncompress_key(compress_key(k)); | |||
llOwnerSay((string)(k==s)+"\n"+k + "\n" + s); | |||
} | |||
} | |||
</source> |
Revision as of 16:03, 5 February 2015
Recommending the following for base64 example for compatibility:
string keyToBase64(string s) {
s = llDumpList2String(llParseString2List(s, ["-"], []), "");
return
llGetSubString(llIntegerToBase64((integer)("0x"+llGetSubString(s,0,5))<<8),0,3) +
llGetSubString(llIntegerToBase64((integer)("0x"+llGetSubString(s,6,11))<<8),0,3) +
llGetSubString(llIntegerToBase64((integer)("0x"+llGetSubString(s,12,17))<<8),0,3) +
llGetSubString(llIntegerToBase64((integer)("0x"+llGetSubString(s,18,23))<<8),0,3) +
llGetSubString(llIntegerToBase64((integer)("0x"+llGetSubString(s,24,29))<<8),0,3) +
llGetSubString(llIntegerToBase64((integer)("0x"+llGetSubString(s,30,31))<<24),0,1);
}
string integer2hex(integer in) {
string s = "0123456789abcdef";
string ret = "";
integer i;
in = in >> 8;
for (i = 0; i < 6; i++) {
ret = llGetSubString(s, in & 0xF, in & 0xF) + ret;
in = in >> 4;
}
return ret;
}
string pad_dash(string s) {
return
llGetSubString(s, 0, 7) + "-" +
llGetSubString(s, 8,11) + "-" +
llGetSubString(s,12,15) + "-" +
llGetSubString(s,16,19) + "-" +
llGetSubString(s,20,31);
}
key base64ToKey(string s) {
return (key) pad_dash(
integer2hex(llBase64ToInteger(llGetSubString(s,0,3))) +
integer2hex(llBase64ToInteger(llGetSubString(s,4,7))) +
integer2hex(llBase64ToInteger(llGetSubString(s,8,11))) +
integer2hex(llBase64ToInteger(llGetSubString(s,12,15))) +
integer2hex(llBase64ToInteger(llGetSubString(s,16,19))) +
integer2hex(llBase64ToInteger(llGetSubString(s,20,21)+"AA")));
}
Base 32768 optimized for size in Mono
// Copyright (C) 2009 Adam Wozniak and Doran Zemlja
// Copyright (C) 2015 Pedro Oval
// Released into the public domain.
// Free for anyone to use for any purpose they like.
//
// INTERNALLY, strings are represented as UTF-16, and internal memory
// is what we actually care about
//
// going for maximum compression, we should be able to get a 128 bit key
// down to 8 x 16 bit characters
//
// we'll do this by encoding integers as UTF-8 URL escaped characters,
// and calling llUnescapeURL to convert them to strings.
//
// unfortunately, UTF-16 has some unallowed codepoints. In particular,
// llEscapeURL/llUnescapeURL fails on the following code points:
//
// 0000, D800-DFFF, FDD0-FDEF, FFFE, FFFF
//
// Let's just make our lives easy and go with 15 bits per character.
// We'll encode 0000-7FFF as 0100-8100 to avoid null characters and leave
// all ASCII characters available as serialisation seperators.
// Also, let's go easy and just save up the 8 MSB as a final character at
// the end.
//
// this gives us a quick and easy 9 character key
// MOD: To make life even easier, use the range 0x800-0x8800 as they all
// start with the same UTF-8 range and there are no bits to test.
// (range is %E0-%EF)
string bhex(integer in)
{
return llGetSubString("0123456789abcdef", (in>>4) & 0xF, (in>>4) & 0xF)
+ llGetSubString("0123456789abcdef", in & 0xF, in & 0xF);
}
integer utf2i(string c)
{
integer ret = (integer)("0x" + (string)llParseString2List(llEscapeURL(c), (list)"%", []));
return ((ret & 0x0F0000) >> 4) + ((ret & 0x3F00) >> 2) + (ret & 0x3F) + (integer)-0x800;
}
string i2url(integer i)
{
i += 0x800;
return "%" + bhex(0xE0 | (i >> 12))
+ "%" + bhex(0x80 | ((i >> 6) & 0x3F))
+ "%" + bhex(0x80 | (i & 0x3F))
;
}
string compress_key(string k)
{
k = (string)llParseString2List(k, (list)"-", []);
string ret;
integer i = (integer)-9;
integer msbs;
integer word;
while (++i)
{
word = (integer) ("0x" + llGetSubString(k, 4*i, ~(4*~i)));
msbs = (msbs | (word & 0x8000)) >> 1;
ret += i2url(word & 0x7FFF);
}
return llUnescapeURL(i2url(msbs) + ret);
}
string uncompress_key(string s)
{
integer i = (integer)-9;
integer value;
integer msbs = utf2i(llGetSubString(s, value, value));
string ret;
while (++i)
{
value = utf2i(llGetSubString(s, i, i)) + ((msbs << (-i)) & 0x8000);
ret += bhex(value>>8) + bhex(value);
}
i = 24;
while ((i += (integer)-4) & (integer)-8)
ret = llInsertString(ret, i, "-");
return ret;
}
// Example usage: generate a key, compress, uncompress, and check if it matches.
default
{
state_entry()
{
string k = llGenerateKey();
string s = uncompress_key(compress_key(k));
llOwnerSay((string)(k==s)+"\n"+k + "\n" + s);
}
}