308 lines
7.8 KiB
Plaintext
308 lines
7.8 KiB
Plaintext
func panic[msg: String] : I64
|
|
printf("PANIC: %s\n", msg)
|
|
exit(1)
|
|
|
|
func print[x: String] : I64
|
|
printf("%s\n", x)
|
|
|
|
func print_i64[x: I64] : I64
|
|
printf("%ld\n", x)
|
|
|
|
func String.is_whitespace[c: U8] : Bool
|
|
return c == ' ' || c == 10 || c == 13 || c == 9
|
|
|
|
func String.concat[a: String, b: String] : String
|
|
let c: String = malloc(strlen(a) + strlen(b) + 1)
|
|
strcpy(c, a)
|
|
strcat(c, b)
|
|
return c
|
|
|
|
func String.find[s: String, needle: U8] : I64
|
|
let s_len: I64 = strlen(s)
|
|
for i in 0..s_len
|
|
if String.nth(s, i) == needle
|
|
return i
|
|
return -1
|
|
|
|
func String.substr[s: String, start: I64, length: I64] : String
|
|
if start < 0 || length < 0 || start + length > strlen(s)
|
|
panic("String.substr out of bounds")
|
|
|
|
let out: String = malloc(length + 1)
|
|
strncpy(out, s + start, length)
|
|
String.set(out, length, 0)
|
|
return out
|
|
|
|
func String.trim[s: String] : String
|
|
let start: I64 = 0
|
|
let end: I64 = strlen(s) - 1
|
|
|
|
while start <= end && String.is_whitespace(String.nth(s, start))
|
|
start = start + 1
|
|
|
|
while end >= start && String.is_whitespace(String.nth(s, end))
|
|
end = end - 1
|
|
|
|
return String.substr(s, start, end - start + 1)
|
|
|
|
func String.rev[s: String] : String
|
|
let len: I64 = strlen(s)
|
|
let out: String = malloc(len + 1)
|
|
|
|
for i in 0..len
|
|
String.set(out, i, String.nth(s, len - i - 1))
|
|
String.set(out, len, 0)
|
|
return out
|
|
|
|
func IO.read_line[]: String
|
|
let buffer: String = malloc(1024)
|
|
fgets(buffer, 1024, IO.stdin())
|
|
return buffer
|
|
|
|
func IO.read_file[path: String]: String
|
|
let file: Ptr = fopen(path, "rb")
|
|
if !file
|
|
panic("failed to open file")
|
|
|
|
fseek(file, 0, 2)
|
|
let size: I64 = ftell(file)
|
|
rewind(file)
|
|
|
|
let buffer: String = malloc(size + 1)
|
|
|
|
let n: I64 = fread(buffer, 1, size, file)
|
|
String.set(buffer, n, 0)
|
|
fclose(file)
|
|
return buffer
|
|
|
|
func IO.write_file[path: String, content: String] : I64
|
|
let file: Ptr = fopen(path, "wb")
|
|
if !file
|
|
panic("failed to open file")
|
|
|
|
fwrite(content, 1, strlen(content), file)
|
|
fclose(file)
|
|
|
|
func U8.parse_i64[c: U8]: I64
|
|
return c - '0'
|
|
|
|
func I64.to_string[n: I64] : String
|
|
let x: String = malloc(21)
|
|
sprintf(x, "%ld", n)
|
|
return x
|
|
|
|
func I64.parse[s: String] : I64
|
|
return strtol(s, 0, 0)
|
|
|
|
func Math.gcd[a: I64, b: I64] : I64
|
|
while b != 0
|
|
let tmp: I64 = b
|
|
b = a % b
|
|
a = tmp
|
|
return a
|
|
|
|
func Math.min[a: I64, b: I64] : I64
|
|
if a < b
|
|
return a
|
|
return b
|
|
|
|
func Math.max[a: I64, b: I64] : I64
|
|
if a > b
|
|
return a
|
|
return b
|
|
|
|
func Math.abs[n: I64] : I64
|
|
if n < 0
|
|
return -n
|
|
return n
|
|
|
|
func Math.pow[b: I64, e: I64] : I64
|
|
let out: I64 = 1
|
|
for i in 0..e
|
|
out = out * b
|
|
return out
|
|
|
|
func Math.lcm[a: I64, b: I64] : I64
|
|
return (a * b) / Math.gcd(a, b)
|
|
|
|
func Math.isqrt[n: I64] : I64
|
|
if n < 0
|
|
return -1
|
|
if n == 0 || n == 1
|
|
return n
|
|
|
|
let guess: I64 = n
|
|
let next_guess: I64 = (guess + n / guess) / 2
|
|
|
|
while next_guess < guess
|
|
guess = next_guess
|
|
next_guess = (guess + n / guess) / 2
|
|
|
|
return guess
|
|
|
|
func Math.is_prime[n: I64]: Bool
|
|
if n <= 1
|
|
return false
|
|
if n == 2 || n == 3
|
|
return true
|
|
if n % 2 == 0 || n % 3 == 0
|
|
return false
|
|
|
|
let i: I64 = 5
|
|
while i * i <= n
|
|
if n % i == 0 || n % (i + 2) == 0
|
|
return false
|
|
i = i + 6
|
|
return true
|
|
|
|
func Math.urandom[]: I64
|
|
let buffer: Ptr = malloc(8)
|
|
let file: Ptr = fopen("/dev/urandom", "rb")
|
|
fread(buffer, 8, 1, file)
|
|
fclose(file)
|
|
let n: I64 = deref(buffer)
|
|
free(buffer)
|
|
return n
|
|
|
|
func Array.new[] : Array
|
|
return calloc(1, 24)
|
|
|
|
func Crypto.hex_encode[s: String] : String
|
|
let hex_chars: String = "0123456789abcdef"
|
|
let s_len: I64 = strlen(s)
|
|
let j: I64 = 0
|
|
let out: String = malloc(s_len*2+1)
|
|
|
|
for i in 0..s_len
|
|
let high: U8 = Bit.rshift(String.nth(s, i), 4) && 15
|
|
let low: U8 = String.nth(s, i) && 15
|
|
String.set(out, j, String.nth(hex_chars, high))
|
|
String.set(out, j+1, String.nth(hex_chars, low))
|
|
j = j + 2
|
|
|
|
String.set(out, j, 0)
|
|
return out
|
|
|
|
func Crypto.from_hex_digit[d: U8] : I64
|
|
if d >= 'a' && d <= 'f'
|
|
return d - 'a' + 10
|
|
if d >= 'A' && d <= 'F'
|
|
return d - 'A' + 10
|
|
return U8.parse_i64(d)
|
|
|
|
func Crypto.hex_decode[s: String] : String
|
|
let s_len: I64 = strlen(s)
|
|
let i: I64 = 0
|
|
let j: I64 = 0
|
|
let out: String = malloc(s_len/2+1)
|
|
|
|
while i < s_len
|
|
String.set(out, j, Crypto.from_hex_digit(String.nth(s, i)) * 16 + Crypto.from_hex_digit(String.nth(s, i+1)))
|
|
i = i + 2
|
|
j = j + 1
|
|
|
|
String.set(out, j, 0)
|
|
return out
|
|
|
|
func Crypto.rc4[key: String, plaintext: String]: String
|
|
let S: String = malloc(256)
|
|
for i in 0..256
|
|
String.set(S, i, i)
|
|
|
|
let j: I64 = 0
|
|
let key_len: I64 = strlen(key)
|
|
for i in 0..256
|
|
j = (j + String.nth(S, i) + String.nth(key, i % key_len)) % 256
|
|
let tmp: U8 = String.nth(S, i)
|
|
String.set(S, i, String.nth(S, j))
|
|
String.set(S, j, tmp)
|
|
|
|
let i: I64 = 0
|
|
j = 0
|
|
let plaintext_len: I64 = strlen(plaintext)
|
|
let ciphertext: String = malloc(plaintext_len+1)
|
|
for n in 0..plaintext_len
|
|
i = (i + 1) % 256
|
|
j = (j + String.nth(S, i)) % 256
|
|
|
|
let tmp: U8 = String.nth(S, i)
|
|
String.set(S, i, String.nth(S, j))
|
|
String.set(S, j, tmp)
|
|
|
|
let r: I64 = String.nth(S, (String.nth(S, i) + String.nth(S, j)) % 256)
|
|
String.set(ciphertext, n, r ^ String.nth(plaintext, n))
|
|
|
|
String.set(ciphertext, plaintext_len, 0)
|
|
free(S)
|
|
return ciphertext
|
|
|
|
func Crypto.base64_encode[s: String] : String
|
|
let chars: String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
|
let s_len: I64 = strlen(s)
|
|
let out: String = malloc(s_len*2)
|
|
let i: I64 = 0
|
|
let j: I64 = 0
|
|
|
|
while i < s_len
|
|
let b1: U8 = String.nth(s, i)
|
|
let b2: U8 = 0
|
|
if i + 1 < s_len
|
|
b2 = String.nth(s, i+1)
|
|
let b3: U8 = 0
|
|
if i + 2 < s_len
|
|
b3 = String.nth(s, i+2)
|
|
i = i + 3
|
|
|
|
let triple: I64 = Bit.lshift(b1, 16) || Bit.lshift(b2, 8) || b3
|
|
String.set(out, j, String.nth(chars, Bit.rshift(triple, 18) && 63))
|
|
String.set(out, j+1, String.nth(chars, Bit.rshift(triple, 12) && 63))
|
|
String.set(out, j+2, String.nth(chars, Bit.rshift(triple, 6) && 63))
|
|
String.set(out, j+3, String.nth(chars, triple && 63))
|
|
j = j + 4
|
|
|
|
let padding: I64 = s_len % 3
|
|
if padding == 1
|
|
String.set(out, j-2, '=')
|
|
String.set(out, j-1, '=')
|
|
else if padding == 2
|
|
String.set(out, j-1, '=')
|
|
|
|
String.set(out, j, 0)
|
|
return out
|
|
|
|
func Crypto.base64_decode[s: String] : String
|
|
let chars: String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
|
let s_len: I64 = strlen(s)
|
|
let out: String = malloc(s_len)
|
|
let i: I64 = 0
|
|
let j: I64 = 0
|
|
|
|
while String.nth(s, s_len-1) == '='
|
|
s_len = s_len - 1
|
|
|
|
while i < s_len
|
|
let s1: U8 = String.find(chars, String.nth(s, i))
|
|
let s2: U8 = 0
|
|
if i + 1 < s_len
|
|
s2 = String.find(chars, String.nth(s, i+1))
|
|
let s3: U8 = 0
|
|
if i + 2 < s_len
|
|
s3 = String.find(chars, String.nth(s, i+2))
|
|
let s4: U8 = 0
|
|
if i + 3 < s_len
|
|
s4 = String.find(chars, String.nth(s, i+3))
|
|
i = i + 4
|
|
|
|
let triple: U8 = Bit.lshift(s1, 18) || Bit.lshift(s2, 12) || Bit.lshift(s3, 6) || s4
|
|
|
|
String.set(out, j, Bit.rshift(triple, 16) && 255)
|
|
j = j + 1
|
|
if s3 != 64
|
|
String.set(out, j, Bit.rshift(triple, 8) && 255)
|
|
j = j + 1
|
|
if s4 != 64
|
|
String.set(out, j, triple && 255)
|
|
j = j + 1
|
|
|
|
String.set(out, j, 0)
|
|
return out |