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