implement hopper backend via beta config

This commit is contained in:
Soph :3 2026-01-30 23:07:09 +02:00
parent d86ab173e1
commit d367bf0f8d
10 changed files with 3198 additions and 537 deletions

View file

@ -1,97 +0,0 @@
-- Copyright (c) 2015 Phil Leblanc -- see LICENSE file
------------------------------------------------------------
--[[
aead_chacha_poly
Authenticated Encryption with Associated Data (AEAD) [1], based
on Chacha20 stream encryption and Poly1305 MAC, as defined
in RFC 7539 [2].
[1] https://en.wikipedia.org/wiki/Authenticated_encryption
[2] http://www.rfc-editor.org/rfc/rfc7539.txt
This file uses chacha20.lua and poly1305 for the encryption
and MAC primitives.
]]
local chacha20 = require "lib.plc.chacha20"
local poly1305 = require "lib.plc.poly1305"
------------------------------------------------------------
-- poly1305 key generation
local poly_keygen = function(key, nonce)
local counter = 0
local m = string.rep('\0', 64)
local e = chacha20.encrypt(key, counter, nonce, m)
-- keep only first the 256 bits (32 bytes)
return e:sub(1, 32)
end
local pad16 = function(s)
-- return null bytes to add to s so that #s is a multiple of 16
return (#s % 16 == 0) and "" or ('\0'):rep(16 - (#s % 16))
end
local app = table.insert
local encrypt = function(aad, key, iv, constant, plain)
-- aad: additional authenticated data - arbitrary length
-- key: 32-byte string
-- iv, constant: concatenated to form the nonce (12 bytes)
-- (why not one 12-byte param? --maybe because IPsec uses
-- an 8-byte nonce)
-- implementation: RFC 7539 sect 2.8.1
-- (memory inefficient - encr text is copied in mac_data)
local mt = {} -- mac_data table
local nonce = constant .. iv
local otk = poly_keygen(key, nonce)
local encr = chacha20.encrypt(key, 1, nonce, plain)
app(mt, aad)
app(mt, pad16(aad))
app(mt, encr)
app(mt, pad16(encr))
-- aad and encrypted text length must be encoded as
-- little endian _u64_ (and not u32) -- see errata at
-- https://www.rfc-editor.org/errata_search.php?rfc=7539
app(mt, string.pack('<I8', #aad))
app(mt, string.pack('<I8', #encr))
local mac_data = table.concat(mt)
--~ p16('mac', mac_data)
local tag = poly1305.auth(mac_data, otk)
return encr, tag
end --chacha20_aead_encrypt()
local function decrypt(aad, key, iv, constant, encr, tag)
-- (memory inefficient - encr text is copied in mac_data)
-- (structure similar to aead_encrypt => what could be factored?)
local mt = {} -- mac_data table
local nonce = constant .. iv
local otk = poly_keygen(key, nonce)
app(mt, aad)
app(mt, pad16(aad))
app(mt, encr)
app(mt, pad16(encr))
app(mt, string.pack('<I8', #aad))
app(mt, string.pack('<I8', #encr))
local mac_data = table.concat(mt)
local mac = poly1305.auth(mac_data, otk)
if mac == tag then
local plain = chacha20.encrypt(key, 1, nonce, encr)
return plain
else
return nil, "auth failed"
end
end --chacha20_aead_decrypt()
------------------------------------------------------------
-- return aead_chacha_poly module
return {
poly_keygen = poly_keygen,
encrypt = encrypt,
decrypt = decrypt,
}

View file

@ -1,225 +0,0 @@
local g = string.gsub
sha256 = loadstring(g(
g(
g(
g(
g(
g(
g(
g(
'Sa=XbandSb=XbxWSc=XlshiftSd=unpackSe=2^32SYf(g,h)Si=g/2^hSj=i%1Ui-j+j*eVSYk(l,m)Sn=l/2^mUn-n%1VSo={0x6a09e667Tbb67ae85T3c6ef372Ta54ff53aT510e527fT9b05688cT1f83d9abT5be0cd19}Sp={0x428a2f98T71374491Tb5c0fbcfTe9b5dba5T3956c25bT59f111f1T923f82a4Tab1c5ed5Td807aa98T12835b01T243185beT550c7dc3T72be5d74T80deb1feT9bdc06a7Tc19bf174Te49b69c1Tefbe4786T0fc19dc6T240ca1ccT2de92c6fT4a7484aaT5cb0a9dcT76f988daT983e5152Ta831c66dTb00327c8Tbf597fc7Tc6e00bf3Td5a79147T06ca6351T14292967T27b70a85T2e1b2138T4d2c6dfcT53380d13T650a7354T766a0abbT81c2c92eT92722c85Ta2bfe8a1Ta81a664bTc24b8b70Tc76c51a3Td192e819Td6990624Tf40e3585T106aa070T19a4c116T1e376c08T2748774cT34b0bcb5T391c0cb3T4ed8aa4aT5b9cca4fT682e6ff3T748f82eeT78a5636fT84c87814T8cc70208T90befffaTa4506cebTbef9a3f7Tc67178f2}SYq(r,q)if e-1-r[1]<q then r[2]=r[2]+1;r[1]=q-(e-1-r[1])-1 else r[1]=r[1]+qVUrVSYs(t)Su=#t;t[#t+1]=0x80;while#t%64~=56Zt[#t+1]=0VSv=q({0,0},u*8)fWw=2,1,-1Zt[#t+1]=a(k(a(v[w]TFF000000),24)TFF)t[#t+1]=a(k(a(v[w]TFF0000),16)TFF)t[#t+1]=a(k(a(v[w]TFF00),8)TFF)t[#t+1]=a(v[w]TFF)VUtVSYx(y,w)Uc(y[w]W0,24)+c(y[w+1]W0,16)+c(y[w+2]W0,8)+(y[w+3]W0)VSYz(t,w,A)SB={}fWC=1,16ZB[C]=x(t,w+(C-1)*4)VfWC=17,64ZSD=B[C-15]SE=b(b(f(B[C-15],7),f(B[C-15],18)),k(B[C-15],3))SF=b(b(f(B[C-2],17),f(B[C-2],19)),k(B[C-2],10))B[C]=(B[C-16]+E+B[C-7]+F)%eVSG,h,H,I,J,j,K,L=d(A)fWC=1,64ZSM=b(b(f(J,6),f(J,11)),f(J,25))SN=b(a(J,j),a(Xbnot(J),K))SO=(L+M+N+p[C]+B[C])%eSP=b(b(f(G,2),f(G,13)),f(G,22))SQ=b(b(a(G,h),a(G,H)),a(h,H))SR=(P+Q)%e;L,K,j,J,I,H,h,G=K,j,J,(I+O)%e,H,h,G,(O+R)%eVA[1]=(A[1]+G)%e;A[2]=(A[2]+h)%e;A[3]=(A[3]+H)%e;A[4]=(A[4]+I)%e;A[5]=(A[5]+J)%e;A[6]=(A[6]+j)%e;A[7]=(A[7]+K)%e;A[8]=(A[8]+L)%eUAVUY(t)t=t W""t=type(t)=="string"and{t:byte(1,-1)}Wt;t=s(t)SA={d(o)}fWw=1,#t,64ZA=z(t,w,A)VU("%08x"):rep(8):format(d(A))V',
"S", " local "), "T", ",0x"), "U", " return "), "V", " end "), "W", "or "), "X", "bit32."), "Y",
"function "), "Z",
" do "))()
local aead = require("lib.plc.aead_chacha_poly")
local function tobytes(s) return { s:byte(1, #s) } end
local function frombytes(t) return string.char(table.unpack(t)) end
local b64abc = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'
local function b64u_encode(bin)
local t, n, out = tobytes(bin), #bin, {}
local i = 1
while i <= n do
local a = t[i] or 0; local b = t[i + 1] or 0; local c = t[i + 2] or 0
local triple = a * 65536 + b * 256 + c
out[#out + 1] = b64abc:sub(bit32.band(bit32.rshift(triple, 18), 63) + 1, bit32.band(bit32.rshift(triple, 18), 63) + 1)
out[#out + 1] = b64abc:sub(bit32.band(bit32.rshift(triple, 12), 63) + 1, bit32.band(bit32.rshift(triple, 12), 63) + 1)
out[#out + 1] = i + 1 <= n and
b64abc:sub(bit32.band(bit32.rshift(triple, 6), 63) + 1, bit32.band(bit32.rshift(triple, 6), 63) + 1) or ''
out[#out + 1] = i + 2 <= n and
b64abc:sub(bit32.band(bit32.rshift(triple, 0), 63) + 1, bit32.band(bit32.rshift(triple, 0), 63) + 1) or ''
i = i + 3
end
return table.concat(out)
end
local function b64u_decode(txt)
local map = {}
for i = 1, #b64abc do map[b64abc:sub(i, i)] = i - 1 end
local out = {}
local i = 1
while i <= #txt do
local a = map[txt:sub(i, i)]; i = i + 1
local b = map[txt:sub(i, i)]; i = i + 1
local c = map[txt:sub(i, i)]; i = i + 1
local d = map[txt:sub(i, i)]; i = i + 1
if a == nil or b == nil then break end
local triple = bit32.bor(bit32.lshift(a, 18), bit32.lshift(b, 12), bit32.lshift(c or 0, 6), (d or 0))
out[#out + 1] = string.char(bit32.band(bit32.rshift(triple, 16), 255))
if c ~= nil then out[#out + 1] = string.char(bit32.band(bit32.rshift(triple, 8), 255)) end
if d ~= nil then out[#out + 1] = string.char(bit32.band(triple, 255)) end
end
return table.concat(out)
end
local function hmac_sha256(key, msg)
local block = 64
if #key > block then key = (sha256(key):gsub('..', function(h) return string.char(tonumber(h, 16)) end)) end
if #key < block then key = key .. string.rep("\0", block - #key) end
local o_key_pad = key:gsub('.', function(c) return string.char(bit32.bxor(string.byte(c), 0x5c)) end)
local i_key_pad = key:gsub('.', function(c) return string.char(bit32.bxor(string.byte(c), 0x36)) end)
local inner = sha256(i_key_pad .. msg)
inner = inner:gsub('..', function(h) return string.char(tonumber(h, 16)) end)
local mac = sha256(o_key_pad .. inner)
return mac:gsub('..', function(h) return string.char(tonumber(h, 16)) end)
end
local function int_be(n) -- 32-bit BE
return string.char(bit32.band(bit32.rshift(n, 24), 255), bit32.band(bit32.rshift(n, 16), 255),
bit32.band(bit32.rshift(n, 8), 255), bit32.band(n, 255))
end
local function pbkdf2_sha256(password, salt, iterations, dkLen)
local hLen = 32
local l = math.ceil(dkLen / hLen)
local r = dkLen - (l - 1) * hLen
local dk = {}
for i = 1, l do
local U = hmac_sha256(password, salt .. int_be(i))
local T = { U:byte(1, hLen) }
for itr = 2, iterations do
U = hmac_sha256(password, U)
local Ub = { U:byte(1, hLen) }
for j = 1, hLen do T[j] = bit32.bxor(T[j], Ub[j]) end
if itr % 500 == 0 then sleep(0) end
end
if i < l then
dk[#dk + 1] = string.char(table.unpack(T))
else
dk[#dk + 1] = string.char(table.unpack(T, 1, r))
end
end
return table.concat(dk)
end
-- HMAC-DRBG
local SEED_PATH = "siss_drg_seed.bin"
local DRBG = { K = string.rep("\0", 32), V = string.rep("\1", 32), inited = false }
local function drbg_update(provided_data)
DRBG.K = hmac_sha256(DRBG.K, DRBG.V .. "\0" .. (provided_data or ""))
DRBG.V = hmac_sha256(DRBG.K, DRBG.V)
if provided_data and #provided_data > 0 then
DRBG.K = hmac_sha256(DRBG.K, DRBG.V .. "\1" .. provided_data)
DRBG.V = hmac_sha256(DRBG.K, DRBG.V)
end
end
local function drbg_init(seed)
DRBG.K = string.rep("\0", 32)
DRBG.V = string.rep("\1", 32)
drbg_update(seed)
DRBG.inited = true
end
local function drbg_bytes(n)
if not DRBG.inited then error("DRBG not seeded. Call seed_entropy() once.") end
local out = {}
while #table.concat(out) < n do
DRBG.V = hmac_sha256(DRBG.K, DRBG.V)
out[#out + 1] = DRBG.V
end
drbg_update("")
local buf = table.concat(out)
return buf:sub(1, n)
end
local function seed_entropy(extra_bytes)
local accum = {}
if fs.exists(SEED_PATH) then
local f = fs.open(SEED_PATH, "rb"); accum[#accum + 1] = f.readAll(); f.close()
local seed = sha256(table.concat(accum)):gsub('..', function(h) return string.char(tonumber(h, 16)) end)
drbg_init(seed)
else
term.write("Move around / mash keys then press Enter 4 times to seed…\n")
for i = 1, 4 do
local t1 = os.clock(); read(); local t2 = os.clock()
accum[#accum + 1] = int_be(math.floor((t2 - t1) * 1e9)) .. tostring({}):sub(8)
end
if extra_bytes and #extra_bytes > 0 then accum[#accum + 1] = extra_bytes end
local seed = sha256(table.concat(accum)):gsub('..', function(h) return string.char(tonumber(h, 16)) end)
drbg_init(seed)
local f = fs.open(SEED_PATH, "wb")
f.write(drbg_bytes(48))
f.close()
end
end
local VERSION = "\1"
local KDF_ID = "\1"
local AAD = "SiSS RA rev1|chacha20poly1305"
local function u32be(n)
return string.char(bit32.band(bit32.rshift(n, 24), 255), bit32.band(bit32.rshift(n, 16), 255),
bit32.band(bit32.rshift(n, 8), 255), bit32.band(n, 255))
end
local function u16be(n) return string.char(bit32.band(bit32.rshift(n, 8), 255), bit32.band(n, 255)) end
local function pack_params(iter)
return u32be(iter) .. u16be(32)
end
local function unpack_params(s)
local i1, i2, i3, i4, d1, d2 = s:byte(1, 6)
local iters = (bit32.bor(bit32.lshift(i1, 24), bit32.lshift(i2, 16), bit32.lshift(i3, 8), i4))
local dklen = (bit32.bor(bit32.lshift(d1, 8), d2))
return iters, dklen
end
local function random_bytes(n) return drbg_bytes(n) end
local function split_nonce12(nonce12)
assert(#nonce12 == 12, "nonce must be 12 bytes")
local iv = nonce12:sub(1, 6)
local constant = nonce12:sub(7, 12)
return iv, constant
end
local function encrypt_with_password(password, plaintext)
local salt = random_bytes(16)
local iters = 1000
local key = pbkdf2_sha256(password, salt, iters, 32)
local nonce12 = random_bytes(12)
local iv, constant = split_nonce12(nonce12)
local ciphertext, tag = aead.encrypt(AAD, key, iv, constant, plaintext)
local params = pack_params(iters)
local blob = table.concat { VERSION, KDF_ID, params, salt, nonce12, ciphertext, tag }
return b64u_encode(blob)
end
local function decrypt_with_password(password, blob)
local bin = b64u_decode(blob)
if #bin < 1 + 1 + 6 + 16 + 12 + 16 then return nil, "ciphertext too short" end
local pos = 1
local ver = bin:sub(pos, pos); pos = pos + 1
if ver ~= VERSION then return nil, "version mismatch" end
local kdfid = bin:sub(pos, pos); pos = pos + 1
if kdfid ~= KDF_ID then return nil, "kdf mismatch" end
local params = bin:sub(pos, pos + 5); pos = pos + 6
local iters, dklen = unpack_params(params); if dklen ~= 32 then return nil, "bad dkLen" end
local salt = bin:sub(pos, pos + 15); pos = pos + 16
-- read the same 12-byte nonce and split the same way
local nonce12 = bin:sub(pos, pos + 11); pos = pos + 12
local iv, constant = split_nonce12(nonce12)
local tag_len = 16
local tag = bin:sub(#bin - tag_len + 1)
local ciphertext = bin:sub(pos, #bin - tag_len)
local key = pbkdf2_sha256(password, salt, iters, 32)
local pt, err = aead.decrypt(AAD, key, iv, constant, ciphertext, tag)
if not pt then return nil, err or "auth failed" end
return pt
end
return {
decrypt_with_password = decrypt_with_password,
encrypt_with_password = encrypt_with_password,
seed_entropy = seed_entropy
}

View file

@ -1,204 +0,0 @@
-- Copyright (c) 2015 Phil Leblanc -- see LICENSE file
------------------------------------------------------------
--[[
Poly1305 message authentication (MAC) created by Dan Bernstein
...
]]
-----------------------------------------------------------
-- poly1305
local sunp = string.unpack
local bit32 = bit32 -- alias
local function poly_init(k)
-- k: 32-byte key as a string
-- initialize internal state
local st = {
r = {
bit32.band(sunp('<I4', k, 1), 0x3ffffff), -- r0
bit32.band(bit32.rshift(sunp('<I4', k, 4), 2), 0x3ffff03), -- r1
bit32.band(bit32.rshift(sunp('<I4', k, 7), 4), 0x3ffc0ff), -- r2
bit32.band(bit32.rshift(sunp('<I4', k, 10), 6), 0x3f03fff), -- r3
bit32.band(bit32.rshift(sunp('<I4', k, 13), 8), 0x00fffff), -- r4
},
h = { 0, 0, 0, 0, 0 },
pad = { sunp('<I4', k, 17), -- 's' in rfc
sunp('<I4', k, 21),
sunp('<I4', k, 25),
sunp('<I4', k, 29),
},
buffer = "", --
leftover = 0,
final = false,
} --st
return st
end --poly_init()
local function poly_blocks(st, m)
-- st: internal state
-- m: message:string
local bytes = #m
local midx = 1
local hibit = st.final and 0 or 0x01000000 -- 1 << 24
local r0 = st.r[1]
local r1 = st.r[2]
local r2 = st.r[3]
local r3 = st.r[4]
local r4 = st.r[5]
local s1 = r1 * 5
local s2 = r2 * 5
local s3 = r3 * 5
local s4 = r4 * 5
local h0 = st.h[1]
local h1 = st.h[2]
local h2 = st.h[3]
local h3 = st.h[4]
local h4 = st.h[5]
local d0, d1, d2, d3, d4, c
--
while bytes >= 16 do -- 16 = poly1305_block_size
-- h += m[i] (in rfc: a += n with 0x01 byte)
h0 = h0 + bit32.band(sunp('<I4', m, midx), 0x3ffffff)
h1 = h1 + bit32.band(bit32.rshift(sunp('<I4', m, midx + 3), 2), 0x3ffffff)
h2 = h2 + bit32.band(bit32.rshift(sunp('<I4', m, midx + 6), 4), 0x3ffffff)
h3 = h3 + bit32.band(bit32.rshift(sunp('<I4', m, midx + 9), 6), 0x3ffffff)
h4 = h4 + bit32.bor(bit32.rshift(sunp('<I4', m, midx + 12), 8), hibit) -- 0x01 byte
--
-- h *= r % p (partial)
d0 = h0 * r0 + h1 * s4 + h2 * s3 + h3 * s2 + h4 * s1
d1 = h0 * r1 + h1 * r0 + h2 * s4 + h3 * s3 + h4 * s2
d2 = h0 * r2 + h1 * r1 + h2 * r0 + h3 * s4 + h4 * s3
d3 = h0 * r3 + h1 * r2 + h2 * r1 + h3 * r0 + h4 * s4
d4 = h0 * r4 + h1 * r3 + h2 * r2 + h3 * r1 + h4 * r0
--
c = bit32.band(bit32.rshift(d0, 26), 0xffffffff); h0 = bit32.band(d0, 0x3ffffff)
d1 = d1 + c; c = bit32.band(bit32.rshift(d1, 26), 0xffffffff); h1 = bit32.band(d1, 0x3ffffff)
d2 = d2 + c; c = bit32.band(bit32.rshift(d2, 26), 0xffffffff); h2 = bit32.band(d2, 0x3ffffff)
d3 = d3 + c; c = bit32.band(bit32.rshift(d3, 26), 0xffffffff); h3 = bit32.band(d3, 0x3ffffff)
d4 = d4 + c; c = bit32.band(bit32.rshift(d4, 26), 0xffffffff); h4 = bit32.band(d4, 0x3ffffff)
h0 = h0 + (c * 5); c = bit32.rshift(h0, 26); h0 = bit32.band(h0, 0x3ffffff)
h1 = h1 + c
--
midx = midx + 16 -- 16 = poly1305_block_size
bytes = bytes - 16
end --while
st.h[1] = h0
st.h[2] = h1
st.h[3] = h2
st.h[4] = h3
st.h[5] = h4
st.bytes = bytes -- remaining bytes. must be < 16 here
st.midx = midx -- index of first remaining bytes
return st
end --poly_blocks()
local function poly_update(st, m)
-- st: internal state
-- m: message:string
st.bytes, st.midx = #m, 1
-- process full blocks if any
if st.bytes >= 16 then
poly_blocks(st, m)
end
--handle remaining bytes
if st.bytes == 0 then -- no bytes left
-- nothing to do? no add 0x01? - apparently not.
else
local buffer = string.sub(m, st.midx)
.. '\x01' .. string.rep('\0', 16 - st.bytes - 1)
assert(#buffer == 16)
st.final = true -- this is the last block
--~ p16(buffer)
poly_blocks(st, buffer)
end
--
return st
end --poly_update
local function poly_finish(st)
--
local c, mask --u32
local f --u64
-- fully carry h
local h0 = st.h[1]
local h1 = st.h[2]
local h2 = st.h[3]
local h3 = st.h[4]
local h4 = st.h[5]
--
c = bit32.rshift(h1, 26); h1 = bit32.band(h1, 0x3ffffff)
h2 = h2 + c; c = bit32.rshift(h2, 26); h2 = bit32.band(h2, 0x3ffffff)
h3 = h3 + c; c = bit32.rshift(h3, 26); h3 = bit32.band(h3, 0x3ffffff)
h4 = h4 + c; c = bit32.rshift(h4, 26); h4 = bit32.band(h4, 0x3ffffff)
h0 = h0 + (c * 5); c = bit32.rshift(h0, 26); h0 = bit32.band(h0, 0x3ffffff)
h1 = h1 + c
--
--compute h + -p
local g0 = (h0 + 5); c = bit32.rshift(g0, 26); g0 = bit32.band(g0, 0x3ffffff)
local g1 = (h1 + c); c = bit32.rshift(g1, 26); g1 = bit32.band(g1, 0x3ffffff)
local g2 = (h2 + c); c = bit32.rshift(g2, 26); g2 = bit32.band(g2, 0x3ffffff)
local g3 = (h3 + c); c = bit32.rshift(g3, 26); g3 = bit32.band(g3, 0x3ffffff)
local g4 = bit32.band(h4 + c - 0x4000000, 0xffffffff) -- (1 << 26)
--
-- select h if h < p, or h + -p if h >= p
mask = bit32.band(bit32.rshift(g4, 31) - 1, 0xffffffff)
--
g0 = bit32.band(g0, mask)
g1 = bit32.band(g1, mask)
g2 = bit32.band(g2, mask)
g3 = bit32.band(g3, mask)
g4 = bit32.band(g4, mask)
--
mask = bit32.band(bit32.bnot(mask), 0xffffffff)
h0 = bit32.bor(bit32.band(h0, mask), g0)
h1 = bit32.bor(bit32.band(h1, mask), g1)
h2 = bit32.bor(bit32.band(h2, mask), g2)
h3 = bit32.bor(bit32.band(h3, mask), g3)
h4 = bit32.bor(bit32.band(h4, mask), g4)
--
--h = h % (2^128)
h0 = bit32.band(bit32.bor((h0), bit32.lshift(h1, 26)), 0xffffffff)
h1 = bit32.band(bit32.bor(bit32.rshift(h1, 6), bit32.lshift(h2, 20)), 0xffffffff)
h2 = bit32.band(bit32.bor(bit32.rshift(h2, 12), bit32.lshift(h3, 14)), 0xffffffff)
h3 = bit32.band(bit32.bor(bit32.rshift(h3, 18), bit32.lshift(h4, 8)), 0xffffffff)
--
-- mac = (h + pad) % (2^128)
f = h0 + st.pad[1]; h0 = bit32.band(f, 0xffffffff)
f = h1 + st.pad[2] + bit32.rshift(f, 32); h1 = bit32.band(f, 0xffffffff)
f = h2 + st.pad[3] + bit32.rshift(f, 32); h2 = bit32.band(f, 0xffffffff)
f = h3 + st.pad[4] + bit32.rshift(f, 32); h3 = bit32.band(f, 0xffffffff)
--
local mac = string.pack('<I4I4I4I4', h0, h1, h2, h3)
-- (should zero out the state?)
--
return mac
end --poly_finish()
local function poly_auth(m, k)
-- m: msg string
-- k: key string (must be 32 bytes)
-- return mac 16-byte string
assert(#k == 32)
local st = poly_init(k)
poly_update(st, m)
local mac = poly_finish(st)
return mac
end --poly_auth()
local function poly_verify(m, k, mac)
local macm = poly_auth(m, k)
return macm == mac
end --poly_verify()
------------------------------------------------------------
-- return poly1305 module
return {
init = poly_init,
update = poly_update,
finish = poly_finish,
auth = poly_auth,
verify = poly_verify,
}

2983
src/lib/hopper.lua Normal file

File diff suppressed because it is too large Load diff

View file

@ -409,12 +409,12 @@ function PrimeUI.selectionBox(win, x, y, width, height, entries, action, selectC
end
-- Redraw screen.
drawEntries()
elseif key == keys.enter then
elseif key ~= keys.up and key ~= keys.down then
-- Select the entry: send the action.
if type(action) == "string" then
PrimeUI.resolve("selectionBox", action, entries()[selection])
PrimeUI.resolve("selectionBox", action, entries()[selection], key)
else
action(entries()[selection])
action(entries()[selection], key)
end
end
elseif event == "mouse_click" and key == 1 then
@ -503,6 +503,48 @@ function PrimeUI.selectionBox(win, x, y, width, height, entries, action, selectC
return drawEntries
end
--- Draws a thin border around a screen region.
---@param win window The window to draw on
---@param x number The X coordinate of the inside of the box
---@param y number The Y coordinate of the inside of the box
---@param width number The width of the inner box
---@param height number The height of the inner box
---@param fgColor color|nil The color of the border (defaults to white)
---@param bgColor color|nil The color of the background (defaults to black)
function PrimeUI.borderBox(win, x, y, width, height, fgColor, bgColor)
expect(1, win, "table")
expect(2, x, "number")
expect(3, y, "number")
expect(4, width, "number")
expect(5, height, "number")
fgColor = expect(6, fgColor, "number", "nil") or colors.white
bgColor = expect(7, bgColor, "number", "nil") or colors.black
-- Draw the top-left corner & top border.
win.setBackgroundColor(bgColor)
win.setTextColor(fgColor)
win.setCursorPos(x - 1, y - 1)
win.write("\x9C" .. ("\x8C"):rep(width))
-- Draw the top-right corner.
win.setBackgroundColor(fgColor)
win.setTextColor(bgColor)
win.write("\x93")
-- Draw the right border.
for i = 1, height do
win.setCursorPos(win.getCursorPos() - 1, y + i - 1)
win.write("\x95")
end
-- Draw the left border.
win.setBackgroundColor(bgColor)
win.setTextColor(fgColor)
for i = 1, height do
win.setCursorPos(x - 1, y + i - 1)
win.write("\x95")
end
-- Draw the bottom border and corners.
win.setCursorPos(x - 1, y + height)
win.write("\x8D" .. ("\x8C"):rep(width) .. "\x8E")
end
return {
PrimeUI = PrimeUI
}

View file

@ -160,7 +160,7 @@ function run()
amount = tonumber(args[3], 10)
end
local moved = inv.sendItemAwayMultiple(slots, peripInventory, peripInventory, amount)
local moved = inv.sendItemAwayMultiple(slots, peripInventory, config.chatbox.players[user], amount)
chatbox.tell(user, "Moved `" .. tostring(moved) .. "` items.", BOT_NAME)
elseif args[1] == "withdraw" then
@ -196,7 +196,7 @@ function run()
amount = tonumber(args[3], 10)
end
local moved = inv.sendItemToSelf(itemName, peripInventory, amount)
local moved = inv.sendItemToSelf(itemName, peripInventory, amount, config.chatbox.players[user])
chatbox.tell(user, "Moved `" .. tostring(moved) .. "` items.", BOT_NAME)
end

View file

@ -1,6 +1,10 @@
local config = require("../../config") ---@type Config
if config.inventories == nil and config.remote.connection then
return require("modules.inventory_layers.inv_ra")
else
if config.beta and config.beta.hopper ~= nil then
return require("modules.inventory_layers.inv_hopper")
end
return require("modules.inventory_layers.inv_ail")
end

View file

@ -32,7 +32,8 @@ end
---@param itemName string
---@param perip ccTweaked.peripheral.Inventory|string|nil
---@param maxAmount number|nil
local function sendItemToSelf(itemName, perip, maxAmount)
---@param id string|nil
local function sendItemToSelf(itemName, perip, maxAmount, id)
if perip == nil then
perip = turtleId
end

View file

@ -0,0 +1,142 @@
local previousInventory = {}
local turtleMoveAllowed = true
local config = require("../../config") ---@type Config
local hopper = require("lib.hopper")
local hopperInventories = table.concat(config.inventories, "|");
local function sync()
hopper("-storage store " .. hopperInventories)
print("Synced.");
end
---@param itemName string
---@param perip ccTweaked.peripheral.Inventory|string|nil
---@param maxAmount number|nil
---@param id string|nil
local function sendItemToSelf(itemName, perip, maxAmount, id)
if perip == nil then
perip = "self"
end
local rid = ""
if id == nil then
if type(perip) ~= "string" then
return
else
rid = perip
end
else
rid = id;
end
turtleMoveAllowed = false
local moved = hopper("store " .. rid .. " " .. itemName .. " -transfer-limit " .. tostring(maxAmount or 64))
turtleMoveAllowed = true
return moved
end
---@param slots ccTweaked.turtle.turtleSlot[]
---@param perip ccTweaked.peripheral.Inventory|nil
---@param id string|nil
---@param maxAmount number|nil
local function sendItemAwayMultiple(slots, perip, id, maxAmount)
if perip == nil then
perip = turtle
end
local srcId = id or "self"
if srcId == nil then return end
local hopslots = ""
for _, slot in pairs(slots) do
hopslots = hopslots .. " -from-slot " .. tostring(slot)
end
return hopper(srcId .. " store -from-limit-max " .. (maxAmount or 64) .. hopslots .. " -per-slot")
end
local function getTurtleInventory()
local inventory = {}
for slot = 1, 16 do
local item = turtle.getItemDetail(slot, false)
inventory[slot] = item
end
return inventory
end
local function detectPlayerInsert()
if turtle then
previousInventory = getTurtleInventory()
while true do
os.pullEvent("turtle_inventory")
local currentInventory = getTurtleInventory()
if turtleMoveAllowed then
local newlyAddedSlots = {}
for slot = 1, 16 do
local prev = previousInventory[slot]
local curr = currentInventory[slot]
if not prev and curr then
table.insert(newlyAddedSlots, slot)
end
end
if #newlyAddedSlots > 0 then
sendItemAwayMultiple(newlyAddedSlots)
end
end
previousInventory = currentInventory
end
end
end
local function run()
return function()
-- this needs to do something
print("inv.run ran")
while true do
sleep(1)
end
end
end
local function listItemAmounts()
return hopper.list("store")
end
local function listNames()
local aa = listItemAmounts()
local names = {}
for name, _ in pairs(aa) do
table.insert(names, name)
end
return names
end
local function getItem(z)
return {} -- can't implement this well enough sadly, just expect every item exists
end
return {
detectPlayerInsert = detectPlayerInsert,
sendItemAwayMultiple = sendItemAwayMultiple,
sendItemToSelf = sendItemToSelf,
getTurtleInventory = getTurtleInventory,
listItemAmounts = listItemAmounts,
listNames = listNames,
getItem = getItem,
sync = sync,
run = run
}

View file

@ -48,12 +48,16 @@ local function run()
function()
return com
end,
function(option)
function(option, key)
if not option then return end
if key == keys.enter then
local z = option:match("^(%S+)")
if inv.getItem(z) then
inv.sendItemToSelf(z)
end
end
end
)
PrimeUI.inputBox(win, 2, 2, w - 2, function(data)
@ -79,6 +83,17 @@ local function run()
end
end)
PrimeUI.addTask(function()
while true do
local _, osTimer = os.pullEvent("timer")
if osTimer == timer then
com = getFiltered()
updateEntries()
timer = os.startTimer(1)
end
end
end)
PrimeUI.run()
end