local function crypto() local function a()local b,c=table.insert,table.concat;local function d(e,f,g,h,i)local j,k,l,m=e[f],e[g],e[h],e[i]local n;j=(j+k)%0x100000000;n=bit32.bxor(m,j)m=bit32.band(bit32.bor(bit32.lshift(n,16),bit32.rshift(n,16)),0xffffffff)l=(l+m)%0x100000000;n=bit32.bxor(k,l)k=bit32.band(bit32.bor(bit32.lshift(n,12),bit32.rshift(n,20)),0xffffffff)j=(j+k)%0x100000000;n=bit32.bxor(m,j)m=bit32.band(bit32.bor(bit32.lshift(n,8),bit32.rshift(n,24)),0xffffffff)l=(l+m)%0x100000000;n=bit32.bxor(k,l)k=bit32.band(bit32.bor(bit32.lshift(n,7),bit32.rshift(n,25)),0xffffffff)e[f],e[g],e[h],e[i]=j,k,l,m;return e end;local o={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}local p={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}local q=function(r,s,t)local e=o;local u=p;e[1],e[2],e[3],e[4]=0x61707865,0x3320646e,0x79622d32,0x6b206574;for v=1,8 do e[v+4]=r[v]end;e[13]=s;for v=1,3 do e[v+13]=t[v]end;for v=1,16 do u[v]=e[v]end;for w=1,10 do d(u,1,5,9,13)d(u,2,6,10,14)d(u,3,7,11,15)d(u,4,8,12,16)d(u,1,6,11,16)d(u,2,7,12,13)d(u,3,8,9,14)d(u,4,5,10,15)end;for v=1,16 do e[v]=bit32.band(e[v]+u[v],0xffffffff)end;return e end;local x="=64)local D=table.pack(string.unpack(x,z,A))local E=q(r,s,t)for v=1,16 do D[v]=bit32.bxor(D[v],E[v])end;local F=string.pack(x,table.unpack(D))if B<64 then F=string.sub(F,1,B)end;return F end;local G=function(r,s,t,z)assert(s+math.floor(#z/64)+1<0xffffffff,"block counter must fit an uint32")assert(#r==32,"#key must be 32")assert(#t==12,"#nonce must be 12")local H=table.pack(string.unpack("=16 do a6=a6+bit32.band(Q('=16 then T(e,U)end;if e.bytes==0 then else local ah=string.sub(U,e.midx)..'\x01'..string.rep('\0',16-e.bytes-1)assert(#ah==16)e.final=true;T(e,ah)end;return e end;local function ai(e)local l,aj;local ak;local a6=e.h[1]local a7=e.h[2]local a8=e.h[3]local a9=e.h[4]local aa=e.h[5]l=bit32.rshift(a7,26)a7=bit32.band(a7,0x3ffffff)a8=a8+l;l=bit32.rshift(a8,26)a8=bit32.band(a8,0x3ffffff)a9=a9+l;l=bit32.rshift(a9,26)a9=bit32.band(a9,0x3ffffff)aa=aa+l;l=bit32.rshift(aa,26)aa=bit32.band(aa,0x3ffffff)a6=a6+l*5;l=bit32.rshift(a6,26)a6=bit32.band(a6,0x3ffffff)a7=a7+l;local al=a6+5;l=bit32.rshift(al,26)al=bit32.band(al,0x3ffffff)local am=a7+l;l=bit32.rshift(am,26)am=bit32.band(am,0x3ffffff)local an=a8+l;l=bit32.rshift(an,26)an=bit32.band(an,0x3ffffff)local ao=a9+l;l=bit32.rshift(ao,26)ao=bit32.band(ao,0x3ffffff)local ap=bit32.band(aa+l-0x4000000,0xffffffff)aj=bit32.band(bit32.rshift(ap,31)-1,0xffffffff)al=bit32.band(al,aj)am=bit32.band(am,aj)an=bit32.band(an,aj)ao=bit32.band(ao,aj)ap=bit32.band(ap,aj)aj=bit32.band(bit32.bnot(aj),0xffffffff)a6=bit32.bor(bit32.band(a6,aj),al)a7=bit32.bor(bit32.band(a7,aj),am)a8=bit32.bor(bit32.band(a8,aj),an)a9=bit32.bor(bit32.band(a9,aj),ao)aa=bit32.bor(bit32.band(aa,aj),ap)a6=bit32.band(bit32.bor(a6,bit32.lshift(a7,26)),0xffffffff)a7=bit32.band(bit32.bor(bit32.rshift(a7,6),bit32.lshift(a8,20)),0xffffffff)a8=bit32.band(bit32.bor(bit32.rshift(a8,12),bit32.lshift(a9,14)),0xffffffff)a9=bit32.band(bit32.bor(bit32.rshift(a9,18),bit32.lshift(aa,8)),0xffffffff)ak=a6+e.pad[1]a6=bit32.band(ak,0xffffffff)ak=a7+e.pad[2]+bit32.rshift(ak,32)a7=bit32.band(ak,0xffffffff)ak=a8+e.pad[3]+bit32.rshift(ak,32)a8=bit32.band(ak,0xffffffff)ak=a9+e.pad[4]+bit32.rshift(ak,32)a9=bit32.band(ak,0xffffffff)local aq=string.pack('b0 then r=sha256(r):gsub('..',function(b1)return string.char(tonumber(b1,16))end)end;if#r0 then bl.K=aZ(bl.K,bl.V.."\1"..bn)bl.V=aZ(bl.K,bl.V)end end;local function bo(bp)bl.K=string.rep("\0",32)bl.V=string.rep("\1",32)bm(bp)bl.inited=true end;local function bq(aT)if not bl.inited then error("DRBG not seeded. Call seed_entropy() once.")end;local aU={}while#table.concat(aU)0 then bu[#bu+1]=bt end;local bp=sha256(table.concat(bu)):gsub('..',function(b1)return string.char(tonumber(b1,16))end)bo(bp)local ak=fs.open(bk,"wb")ak.write(bq(48))ak.close()end end;local bx="\1"local by="\1"local bz="SiSS RA rev1|chacha20poly1305"local function bA(aT)return string.char(bit32.band(bit32.rshift(aT,24),255),bit32.band(bit32.rshift(aT,16),255),bit32.band(bit32.rshift(aT,8),255),bit32.band(aT,255))end;local function bB(aT)return string.char(bit32.band(bit32.rshift(aT,8),255),bit32.band(aT,255))end;local function bC(bD)return bA(bD)..bB(32)end;local function bE(aA)local bF,bG,bH,bI,ac,ad=aA:byte(1,6)local bJ=bit32.bor(bit32.lshift(bF,24),bit32.lshift(bG,16),bit32.lshift(bH,8),bI)local bK=bit32.bor(bit32.lshift(ac,8),ad)return bJ,bK end;local function bL(aT)return bq(aT)end;local function bM(O)assert(#O==12,"nonce must be 12 bytes")local aD=O:sub(1,6)local aE=O:sub(7,12)return aD,aE end;local function bN(b7,bO)local b8=bL(16)local bJ=1000;local r=b6(b7,b8,bJ,32)local O=bL(12)local aD,aE=bM(O)local bP,aK=aN.encrypt(bz,r,aD,aE,bO)local bQ=bC(bJ)local bR=table.concat{bx,by,bQ,b8,O,bP,aK}return aR(bR)end;local function bS(b7,bR)local aS=aW(bR)if#aS<1+1+6+16+12+16 then return nil,"ciphertext too short"end;local bT=1;local bU=aS:sub(bT,bT)bT=bT+1;if bU~=bx then return nil,"version mismatch"end;local bV=aS:sub(bT,bT)bT=bT+1;if bV~=by then return nil,"kdf mismatch"end;local bQ=aS:sub(bT,bT+5)bT=bT+6;local bJ,bK=bE(bQ)if bK~=32 then return nil,"bad dkLen"end;local b8=aS:sub(bT,bT+15)bT=bT+16;local O=aS:sub(bT,bT+11)bT=bT+12;local aD,aE=bM(O)local bW=16;local aK=aS:sub(#aS-bW+1)local bP=aS:sub(bT,#aS-bW)local r=b6(b7,b8,bJ,32)local z,bX=aN.decrypt(bz,r,aD,aE,bP,aK)if not z then return nil,bX or"auth failed"end;return z end;return{decrypt_with_password=bS,encrypt_with_password=bN,seed_entropy=bs} end local hmac = crypto() ---@type string local password ---@type number local port ---@type ccTweaked.peripheral.Modem local modem local function init(modemI, portI, passwordI) port = portI password = passwordI modem = modemI hmac.seed_entropy() modem.open(port) end ---@param itemName string ---@param count number|nil local function withdraw(itemName, count) if not port or not modem or not password then error("tiny_ra_library: init was never ran") end local data = { itemName = itemName } if count then data["count"] = count end modem.transmit(port, port, hmac.encrypt_with_password(password, textutils.serialiseJSON({ ["type"] = "withdraw", ["data"] = data }))) end ---@param slots number[] ---@param count number|nil local function depositBySlots(slots, count) if not port or not modem or not password then error("tiny_ra_library: init was never ran") end local data = { slots = slots } if count then data["count"] = count end modem.transmit(port, port, hmac.encrypt_with_password(password, textutils.serialiseJSON({ ["type"] = "deposit", ["data"] = data }))) end ---@param itemName string ---@param count number|nil local function depositByItemName(itemName, count) if not port or not modem or not password then error("tiny_ra_library: init was never ran") end local data = { itemName = itemName } if count then data["count"] = count end modem.transmit(port, port, hmac.encrypt_with_password(password, textutils.serialiseJSON({ ["type"] = "deposit", ["data"] = data }))) end return { init = init, withdraw = withdraw, depositByItemName = depositByItemName, depositBySlots = depositBySlots }