I am writing a mechanism to generate a unique ID derived from sha256. I use:
require 'sha2'
function getUint64ID( callId )
local minimumValue = 100000000000000000
local maximumValue = 999999999999999999
outputHash = sha2.sha256hex(callId)
print(outputHash .. "\n")
local c1 = ""
for a, b in outputHash:gmatch"(%x)(%x)" do
hexTuple = tostring(a) .. tostring(b)
intVal = tonumber(hexTuple, 16)
c1 = c1 .. string.char(intVal)
end
uint64ID = ( minimumValue + ( tonumber(c1) % ( maximumValue - minimumValue + 1 ) ) )
print('uint64ID:')
print(string.format("%18.0f",uint64ID))
end
getUint64ID("test")
I get the following error in the above code:
stdin:17: attempt to perform arithmetic on a nil value
stack traceback:
stdin:17: in function 'getUint64ID'
stdin:1: in main chunk
[C]: ?
How to convert 32 bytes char buffer (c1) into a uint64 number in lua?
Related
Here is my code. two num plus > 0 but add a variable < 0 !!!
function addExp(actorExp, val)
local actorExp = actorExp -- actorExp = 800000000
local val = val -- val = 3000000000
if actorExp + val -- Here actorExp > 0 then
-- actorExp + val > 0 but
actorExp = actorExp + val -- Here actorExp = -2147483648 ???
else return end
updateInfo(actor)
end
how can i fix it
This is called an overflow error.
The way computers store data is using binary (1s and 0s), and depending on the size (number of digits) of the binary used to store each number (often 32 'bits') will determine the maximum value. When the maximum value is reached, it will "overflow" back to the start, which in this case is -2147483648 as it is a "signed" (can be negative) number.
vals = { i=1, j=2}
setmetatable(vals, {
__add = function (a, b)
return a*b
end,
})
sr = vals.i+vals.j
print(sr)
It prints sr as 3. The expected answer is 2 as 1*2 equals to 2. Why the addition operation (metamethod) is not getting into picture from the metatable of vars?
You misunderstood that a table with a metatable only fires at the table.
...not at a key/value it holds with same or different datatype.
They have not inherited the metatable.
Exception: Own implemention with __newindex
Where you can add/share the parent metatable to a new table (child then )
So look at this code and try it by yourself and understood...
vals = setmetatable({i = 1, j = 2}, {
__add = function (left, right)
return left.i * right -- Little change here
end,
})
vals + 15 -- __add will trigger this and returning: 15
vals + vals.j -- __add will trigger this and returning: 2
-- Lets change vals.i
vals.i = vals + vals.j
vals + 15 -- __add will trigger this and returning: 30
vals + vals.j -- __add will trigger this and returning: 4
"Numbers do not have metatables."
The datatype string has.
for key, value in pairs(getmetatable(_VERSION)) do
print(key, "=", value)
end
__div = function: 0x565e8f80
__pow = function: 0x565e8fa0
__sub = function: 0x565e9000
__mod = function: 0x565e8fc0
__idiv = function: 0x565e8f60
__add = function: 0x565e9020
__mul = function: 0x565e8fe0
__index = table: 0x5660d0b0
__unm = function: 0x565e8f40
And the __add is somewhat broken or not really useable...
_VERSION + 3
stdin:1: attempt to add a 'string' with a 'number'
stack traceback:
[C]: in metamethod 'add'
stdin:1: in main chunk
[C]: in ?
_VERSION + "3"
stdin:1: attempt to add a 'string' with a 'string'
stack traceback:
[C]: in metamethod 'add'
stdin:1: in main chunk
[C]: in ?
Imagine numbers have all math functions as methods...
> math.pi = debug.setmetatable(math.pi, {__index = math})
-- From now every number has math methods
> print(math.maxinteger:atan2() * 2)
3.1415926535898
-- Using method on return of before used method
-- Maybe it should be called "Chaining methods"?
> print(math.pi:deg():tointeger():type())
integer
-- type() returns a string. - Lets use upper() on this...
> print(math.pi:deg():tointeger():type():upper())
INTEGER
-- Typed in a Lua interactive console ( _VERSION = 5.4 )
-- PS: Also random() is not far away and can be
-- used directly with a number for a dice roller with
> print((1):random(6))
1
> print((1):random(6))
5
> print((1):random(6))
5
> print((1):random(6))
4
-- ;-)
Oups, how easy is this?
the first argument of the __add method is table type
local vals = {
i = 1,
j = 2
}
setmetatable(
vals,
{
__add = function(tbl, value)
return tbl.i + tbl.j + value
end
}
)
print(vals + 13)
I'm trying to reverse a decode function. This function takes a string and a key and encodes the string with that key. This is the code:
function decode(key, code)
return (code:gsub("..", function(h)
return string.char((tonumber(h, 16) + 256 - 13 - key + 255999744) % 256)
end))
end
If I input 7A as code and 9990 as key, it returns g
I tried reversing the operators and fed back the output of the decode function but I get an error becauase tonumber() returns nil. How can I reverse this function?
By using the answer to this Lua base coverter and flipping the operators of the decode function, I was able to convert back the input.
This is the whole code:
function encodes(key, code)
return (code:gsub("..", function(h)
return string.char((tonumber(h, 16) + 256 - 13 - key + 255999744) % 256)
end))
end
local floor,insert = math.floor, table.insert
function basen(n,b)
n = floor(n)
if not b or b == 10 then return tostring(n) end
local digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
local t = {}
local sign = ""
if n < 0 then
sign = "-"
n = -n
end
repeat
local d = (n % b) + 1
n = floor(n / b)
insert(t, 1, digits:sub(d,d))
until n == 0
return sign .. table.concat(t,"")
end
function decodes(key, code)
return (code:gsub(".", function(h)
out = (string.byte(h) - 256 + 13 + key - 255999744) % 256
return basen(out,16)
end))
end
a = encodes(9999, "7c7A")
print(a) --prints: `^
print("----------")
b = decodes(9999, a)
print(b) --prints: 7C7A
I am trying to write a PBKDF2 implementation in pure lua. I am writing it because I want to use it in a sandboxed lua environment that does not allow outside libraries. I had a look at the standard document from the IETF and had at it. Below is the code I have come up with:
do
package.preload["pbkdf2"] = function()
local hmac = require 'hmac'
local len = string.len
local gsub = string.gsub
local format = string.format
local byte = string.byte
local char = string.char
local concat = table.concat
local ceil = math.ceil
local function toBytes(str)
local tmp = {}
for i = 1, len(str) do
tmp[i] = byte(str, i)
end
return tmp
end
local function toString(bArray)
local tmp = {}
for i = 1, #bArray do
tmp[i] = char(bArray[i])
end
tmp = concat(tmp)
return tmp
end
-- transform a string of bytes in a string of hexadecimal digits
local function asHex(s)
local h = gsub(s, ".", function(c)
return format("%02x", byte(c))
end)
return h
end
local num2string = function(l, n)
local s = {}
for i = 1, n do
local idx = (n + 1) - i
s[idx] = char(l & 255)
l = l >> 8
end
s = concat(s)
return s
end
local buildBlock = function(hFun, password, salt, c, int)
local tmp
local tmp2
for i = 1, c do
if i == 1 then
print(int)
print(salt .. int)
-- PRF(password, salt || INT_32_BE(i)
-- return result of hash as a byte string
tmp = hmac.hash(hFun, password, salt .. num2string(int, 4), true)
else
-- returns result of hash as byte string
tmp2 = hmac.hash(hFun, password, tmp, true)
-- transform to byte arrays
tmp2 = toBytes(tmp2)
tmp = toBytes(tmp)
assert(#tmp == #tmp2)
-- apply XOR over bytes in both arrays
-- save results to final array
for j = 1, #tmp do
-- perform XOR operation on both elements in the respective arrays
tmp[j] = tmp[j] ~ tmp2[j]
end
-- transform back into byte string to pass to next hash
tmp = toString(tmp)
end
end
return tmp
end
local truncate = function(str, pos)
return string.sub(str, 1, pos)
end
local deriveKey = function(hFun, message, salt, c, dLen)
local hLen = hFun.outputSize
-- the derived key cannot be larger than (2^32 * hLen)
if dLen > (2^32) * hLen then error("The derived key cannot be larger than 2^32 times the output size of the hash function.") end
-- the block size is the desired key length divided by the output size of the underlying hash function, rounded up
local blockSize = ceil(dLen/hLen)
-- to store our blocks
local final = {}
for i = 1, blockSize do
-- lets make our blocks in here
final[i] = buildBlock(hFun, message, salt, c, i)
end
local result
if #final == 1 then
result = final[1] -- we only have one block
else
result = concat(final) -- turns final into a bytestring to be outputted
end
--if #result > dLen then truncate(final, dLen) end
assert(#result == dLen)
return asHex(result) -- outputs as a hex value
end
return {deriveKey = deriveKey}
end
end
This code is not getting the correct answers. Testing this code with test vectors provided here, assuming that the underlying PRF is HMAC-SHA256, the output is below:
key: "password"
salt: "salt"
c: 1
dkLen: 32
Got: 13463842ec330934dc124494b40d8baade465b72f3fcadad741f2d0e052fd2f5
Expected: 120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b
key: "password"
salt: "salt"
c: 2
dkLen: 32
Got: 8b82aed26f503effdbc6c14bc7f0338b2b90e387f14ac1f91f9ad74e618f9558
Expected: AE4D0C95AF6B46D32D0ADFF928F06DD02A303F8EF3C251DFD6E2D85A95474C43
I believe it may have something to do with the string to byte encoding, but I cannot pinpoint what exactly is causing the issue. When I was testing my HMAC code, I had to rely on online generators because I couldn't find vectors for HMAC-SHA224 and HMAC-SHA256. Some calculators would give me completely different output values for the same key, message combination. That could be because of how they are processing the inputs, but I am not sure. I would appreciate it if someone more experienced could help me out with this.
EDIT: This problem is solved. Seems that all that was needed was to pass int as a binary string of length 4. I updated the code with the fixes.
EDIT 2: I read the standard again to realize the solution was in my face the entire time (standard says to encode i as a 32-bit big endian integer).
The solution was to convert int to a binary string of length 4. Thanks to #EgorSkriptunoff for his insight.
I try to parse gpx files and to output encoded polylines (Google algorithm)
test.gpx
<trkseg>
<trkpt lon="-120.2" lat="38.5"/>
<trkpt lon="-120.95" lat="40.7"/>
<trkpt lon="-126.453" lat="43.252"/>
</trkseg>
I managed most of it, but have trouble with encoding the numbers
gpx2epl:
file = io.open(arg[1], "r")
io.input(file)
--
function round(number, precision)
return math.floor(number*math.pow(10,precision)+0.5) / math.pow(10,precision)
end
function encodeNumber(number)
return number
end
--
local Olatitude = 0
local Olongitude = 0
--
while true do
local line = io.read()
if line == nil
then
break
end
if string.match(line, "trkpt") then
local latitude
local longitude
local encnum
latitude = string.match(line, 'lat="(.-)"')
longitude = string.match(line, 'lon="(.-)"')
latitude = round(latitude,5)*100000
longitude = round(longitude,5)*100000
encnum = encodeNumber(latitude-Olatitude)
print(encnum)
encnum = encodeNumber(longitude-Olongitude)
print(encnum)
Olatitude = latitude
Olongitude = longitude
end
end
This script produces the expected output (see: Google Link), with the exception of encoded latitude and longitude.
3850000
-12020000
220000
-75000
255200
-550300
Mapquest provides an implementation in Javascript:
function encodeNumber(num) {
var num = num << 1;
if (num < 0) {
num = ~(num);
}
var encoded = '';
while (num >= 0x20) {
encoded += String.fromCharCode((0x20 | (num & 0x1f)) + 63);
num >>= 5;
}
encoded += String.fromCharCode(num + 63);
return encoded;
}
Can this be done in Lua? Can somebody please help me out. I have no idea how to implement this in Lua.
Edit:
Based on Doug's advice, I did:
function encodeNumber(number)
local num = number
num = num * 2
if num < 0
then
num = (num * -1) - 1
end
while num >= 32
do
local num2 = 32 + (num % 32) + 63
print(string.char(num2))
num = num / 32
end
print(string.char(num + 63) .. "\n-----")
end
encodeNumber(3850000) -- _p~iF
encodeNumber(-12020000) -- ~ps|U
encodeNumber(220000) -- _ulL
encodeNumber(-75000) -- nnqC
encodeNumber(255200) -- _mqN
encodeNumber(-550300) -- vxq`#
It's near expected output, but only near ... Any hint?
Taking encodeNumber piecemeal...
var num = num << 1;
This is just num = num * 2
num = ~(num);
This is num = (- num) - 1
0x20 | (num & 0x1f)
Is equivalent to 32 + (num % 32)
num >>= 5
Is equivalent to num = math.floor(num / 32)
ADDENDUM
To concatenate the characters, use a table to collect them:
function encodeNumber(number)
local num = number
num = num * 2
if num < 0
then
num = (num * -1) - 1
end
local t = {}
while num >= 32
do
local num2 = 32 + (num % 32) + 63
table.insert(t,string.char(num2))
num = math.floor(num / 32) -- use floor to keep integer portion only
end
table.insert(t,string.char(num + 63))
return table.concat(t)
end