1
0
Fork 0
forked from fun/fun

Added sha384.fun to std library and alot of fixes. (0.16.3)

This commit is contained in:
Johannes Findeisen 2025-10-01 19:08:08 +02:00
commit 17241b2401
18 changed files with 820 additions and 314 deletions

View file

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.16)
project(fun VERSION 0.16.2 LANGUAGES C)
project(fun VERSION 0.16.3 LANGUAGES C)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)

View file

@ -29,3 +29,26 @@ print(typeof(x)) // -> "String"
// Typed byte must remain numeric (uint8):
// b = "oops" // Uncomment to see a runtime type error
/* Expected output:
=== byte with hex literal and clamping ===
255
255
255
=== for-loop reassigning a byte variable (shows clamping near the top end) ===
250
251
252
253
254
255
255
255
255
255
=== dynamic vs typed ===
Number
String
*/

View file

@ -32,6 +32,16 @@ print(md5.md5_hex("6d65737361676520646967657374")) // -> f96b697d7cb7938d525a2f
print(md5.md5_hex("6162636465666768696a6b6c6d6e6f707172737475767778797a")) // -> c3fcd3d76192e4007dfb496cca67e13b
// "Have Fun!"
print(md5.md5_str("Have Fun!")) // ->
print(md5.md5_str("Have Fun!")) // -> 852438d026c018c4307b916406f98c62
print("=== Done ===")
/* Expected output:
=== MD5 demo (hex input) ===
900150983cd24fb0d6963f7d28e17f72
d41d8cd98f00b204e9800998ecf8427e
f96b697d7cb7938d525a2f31aaf161d0
c3fcd3d76192e4007dfb496cca67e13b
812f2c01287af0e7c0a0b3daa381a51a
=== Done ===
*/

View file

@ -31,3 +31,12 @@ print(sha.sha256_hex("6d65737361676520646967657374")) // -> f7846f55cf23e14eebea
print(sha.sha256_hex("6162636465666768696a6b6c6d6e6f707172737475767778797a")) // -> 71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73
print("=== Done ===")
/* Expected output:
=== SHA-256 demo (hex input) ===
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
3859a4ec00dcbed7c01d4a462d18c1f4097a690a1d4d459be4e5b6f5a594ee68
de8ff7370090823795e96e3b7fbee3cfad374492417da99d72ba55297f7e58ab
5d3ed26c5e75585f56e664c0ebc63aa185ec606109f6374fefa42c862670d257
=== Done ===
*/

View file

@ -35,3 +35,14 @@ print(sha.sha256_str("6162636465666768696a6b6c6d6e6f707172737475767778797a")) //
print("=== Note ===")
print("sha256_str(\"616263\") hashes the text 616263; sha256_hex(\"616263\") hashes bytes 0x61 0x62 0x63 (abc).")
/* Expected output:
=== SHA-256 demo (raw string input via sha256_str) ===
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
3859a4ec00dcbed7c01d4a462d18c1f4097a690a1d4d459be4e5b6f5a594ee68
faee5966a2c104cf2287085428a183fe58c18afdc5ff261571e8e9c4796ad635
57aad00934af3b05086a755a1787884f2af6554dce4fc9cab02e7008d31dab44
a863dce86b2577846b6fd399ae6c9830999b4525c50b74705998f3df852b6d25
=== Note ===
sha256_str("616263") hashes the text 616263; sha256_hex("616263") hashes bytes 0x61 0x62 0x63 (abc).
*/

29
examples/sha384_example.fun Executable file
View file

@ -0,0 +1,29 @@
#!/usr/bin/env fun
/*
* This file is part of the Fun programming language.
* https://hanez.org/project/fun/
*
* Copyright 2025 Johannes Findeisen <you@hanez.org>
* Licensed under the terms of the Apache-2.0 license.
* https://opensource.org/license/apache-2-0
*
* Added: 2025-10-01
*/
/*
* Example: Using SHA384 from lib/crypt/sha384.fun
*
* Expected output for "abc":
* cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7
*/
#include <crypt/sha384.fun>
s = SHA384()
// Hex input representing "abc"
print(s.sha384_hex("616263"))
// Raw string input
print(s.sha384_str("abc"))

View file

@ -33,3 +33,11 @@ print(sha.sha512_hex("6d65737361676520646967657374"))
// 3f36cc64dab6c0c5
print("=== Done ===")
/* Expected output:
=== SHA-512 demo (hex input) ===
cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f
107dbf389d9e9f71a3a95f6c055b9251bc5268c2be16d6c13492ea45b0199f3309e16455ab1e96118e8a905d5597b72038ddb372a89826046de66687bb420e7c
=== Done ===
*/

View file

@ -32,3 +32,12 @@ print(sha.sha512_str("616263")) // -> ee21095236a9c037f705f41ffa3cf60869891fcdb
print("=== Note ===")
print("sha512_str(\"616263\") hashes the text 616263; sha512_hex(\"616263\") hashes bytes 0x61 0x62 0x63 (abc).")
/* Expected output:
=== SHA-512 demo (raw string input via sha512_str) ===
cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f
ee21095236a9c037f705f41ffa3cf60869891fcdb461c5c8fe50e5b1711a27bfc02de2e387228651bdd034113cc59af777fdb9c915b70fdbed0eeacf7113296b
=== Note ===
sha512_str("616263") hashes the text 616263; sha512_hex("616263") hashes bytes 0x61 0x62 0x63 (abc).
*/

3
lib/README.md Normal file
View file

@ -0,0 +1,3 @@
# README
The Fun standard library.

3
lib/core/README.md Normal file
View file

@ -0,0 +1,3 @@
# README
In this directory every file should just contain one function if possible!

View file

@ -0,0 +1,62 @@
/*
* This file is part of the Fun programming language.
* https://hanez.org/project/fun/
*
* Copyright 2025 Johannes Findeisen <you@hanez.org>
* Licensed under the terms of the Apache-2.0 license.
* https://opensource.org/license/apache-2-0
*
* Added: 2025-10-01
*/
// ASCII string to bytes (printable ASCII 0x20..0x7E)
fun string_to_bytes_ascii(s)
str = to_string(s)
out = []
number i = 0
// ASCII printable ranges
P1 = " !\"#$%&'()*+,-./" // 32..47
P2 = "0123456789" // 48..57
P3 = ":;<=>?@" // 58..64
P4 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" // 65..90
P5 = "[\\]^_`" // 91..96
P6 = "abcdefghijklmnopqrstuvwxyz" // 97..122
P7 = "{|}~" // 123..126
while true
ch = substr(str, i, 1)
if (typeof(ch) != "String" || ch == "")
break
number code = -1
idx = find(P1, ch)
if (idx >= 0)
code = 32 + idx
else
idx = find(P2, ch)
if (idx >= 0)
code = 48 + idx
else
idx = find(P3, ch)
if (idx >= 0)
code = 58 + idx
else
idx = find(P4, ch)
if (idx >= 0)
code = 65 + idx
else
idx = find(P5, ch)
if (idx >= 0)
code = 91 + idx
else
idx = find(P6, ch)
if (idx >= 0)
code = 97 + idx
else
idx = find(P7, ch)
if (idx >= 0)
code = 123 + idx
else
// non-printable -> 0
code = 0
push(out, code)
i = i + 1
return out

View file

@ -18,265 +18,7 @@
// Example:
// print(md5_hex("616263")) // "abc" => 900150983cd24fb0d6963f7d28e17f72
/* Legacy global API and helpers are commented out below.
Please use the MD5 class (see at the end of this file).
fun u32(x)
// bring x into [0 .. 2^32-1] by modular reduction
m = 4294967296
while x < 0
x = x + m
while x >= m
x = x - m
return x
fun shl32(x, s)
return shl(u32(x), s)
fun shr32(x, s)
return shr(u32(x), s)
fun rol32(x, s)
return rol(u32(x), s)
fun and32(a, b)
return band(u32(a), u32(b))
fun or32(a, b)
return bor(u32(a), u32(b))
fun xor32(a, b)
return bxor(u32(a), u32(b))
fun not32(x)
return bnot(u32(x))
fun add32(a, b)
return u32(a + b)
fun add32_4(a, b, c, d)
return u32(u32(u32(a + b) + c) + d)
fun hex_val(ch)
if (ch == "0")
return 0
else if (ch == "1")
return 1
else if (ch == "2")
return 2
else if (ch == "3")
return 3
else if (ch == "4")
return 4
else if (ch == "5")
return 5
else if (ch == "6")
return 6
else if (ch == "7")
return 7
else if (ch == "8")
return 8
else if (ch == "9")
return 9
else if (ch == "a" || ch == "A")
return 10
else if (ch == "b" || ch == "B")
return 11
else if (ch == "c" || ch == "C")
return 12
else if (ch == "d" || ch == "D")
return 13
else if (ch == "e" || ch == "E")
return 14
else if (ch == "f" || ch == "F")
return 15
else
return 0
fun byte_from_hex_pair(hh)
// hh is 2-char string
hi = hex_val(substr(hh, 0, 1))
lo = hex_val(substr(hh, 1, 1))
return hi * 16 + lo
fun from_hex(hex)
// parse even-length hex string to array of bytes (numbers 0..255)
arr = []
i = 0
n = len(hex)
while i + 1 < n
b = byte_from_hex_pair(substr(hex, i, 2))
push(arr, b)
i = i + 2
return arr
fun two_hex(n)
n = n % 256
d = ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"]
hi = n / 16
lo = n % 16
// build with join
parts = [d[hi], d[lo]]
return join(parts, "")
fun bytes_to_hex(arr)
i = 0
out = []
while i < len(arr)
push(out, two_hex(arr[i]))
i = i + 1
return join(out, "")
// MD5 auxiliary functions
fun F(x, y, z)
return or32(and32(x, y), and32(not32(x), z))
fun G(x, y, z)
return or32(and32(x, z), and32(y, not32(z)))
fun H(x, y, z)
return xor32(xor32(x, y), z)
fun I(x, y, z)
return xor32(y, or32(x, not32(z)))
// T constants (K) = floor(abs(sin(i+1)) * 2^32), i=0..63
K = [
3614090360, 3905402710, 606105819, 3250441966, 4118548399, 1200080426, 2821735955, 4249261313,
1770035416, 2336552879, 4294925233, 2304563134, 1804603682, 4254626195, 2792965006, 1236535329,
4129170786, 3225465664, 643717713, 3921069994, 3593408605, 38016083, 3634488961, 3889429448,
568446438, 3275163606, 4107603335, 1163531501, 2850285829, 4243563512, 1735328473, 2368359562,
4294588738, 2272392833, 1839030562, 4259657740, 2763975236, 1272893353, 4139469664, 3200236656,
681279174, 3936430074, 3572445317, 76029189, 3654602809, 3873151461, 530742520, 3299628645,
4096336452, 1126891415, 2878612391, 4237533241, 1700485571, 2399980690, 4293915773, 2240044497,
1873313359, 4264355552, 2734768916, 1309151649, 4149444226, 3174756917, 718787259, 3951481745
]
// per-round rotation amounts
S = [
7,12,17,22, 7,12,17,22, 7,12,17,22, 7,12,17,22,
5, 9,14,20, 5, 9,14,20, 5, 9,14,20, 5, 9,14,20,
4,11,16,23, 4,11,16,23, 4,11,16,23, 4,11,16,23,
6,10,15,21, 6,10,15,21, 6,10,15,21, 6,10,15,21
]
fun pad_bytes(bytes)
// returns a new array with MD5 padding
L = len(bytes)
out = []
// copy original bytes
i = 0
while i < L
push(out, bytes[i])
i = i + 1
// append 0x80
push(out, 128)
// pad zeros until length % 64 == 56
while (len(out) % 64) != 56
push(out, 0)
// append length (bits) as 64-bit little-endian
len_bits = L * 8
j = 0
while j < 8
b = (len_bits / pow(2, 8 * j)) % 256
push(out, b)
j = j + 1
return out
fun word32_le(b0, b1, b2, b3)
return u32(b0 + b1 * 256 + b2 * 65536 + b3 * 16777216)
fun process_block(state, block)
// state: [a0,b0,c0,d0], block: 64 bytes array
a0 = state[0]
b0 = state[1]
c0 = state[2]
d0 = state[3]
// M[16] little-endian words
M = []
i = 0
while i < 16
j = i * 4
w = word32_le(block[j], block[j+1], block[j+2], block[j+3])
push(M, w)
i = i + 1
A = a0
B = b0
C = c0
D = d0
k = 0
while k < 64
if (k < 16)
f = F(B, C, D)
g = k
else if (k < 32)
f = G(B, C, D)
g = (5 * k + 1) % 16
else if (k < 48)
f = H(B, C, D)
g = (3 * k + 5) % 16
else
f = I(B, C, D)
g = (7 * k) % 16
tmp = D
sum = add32_4(A, f, K[k], M[g])
D = C
C = B
B = add32(B, rol32(sum, S[k]))
A = tmp
k = k + 1
state[0] = add32(state[0], A)
state[1] = add32(state[1], B)
state[2] = add32(state[2], C)
state[3] = add32(state[3], D)
return state
fun md5_bytes(bytes)
// returns array of 16 bytes of digest
data = pad_bytes(bytes)
// initial state
a0 = 1732584193 // 0x67452301
b0 = 4023233417 // 0xEFCDAB89
c0 = 2562383102 // 0x98BADCFE
d0 = 271733878 // 0x10325476
state = [a0, b0, c0, d0]
off = 0
N = len(data)
while off < N
block = []
i = 0
while i < 64
push(block, data[off + i])
i = i + 1
state = process_block(state, block)
off = off + 64
// output digest as little-endian bytes of A,B,C,D
out = []
j = 0
while j < 4
v = state[j]
// 4 bytes little-endian
push(out, (v ) % 256)
push(out, (v / 256) % 256)
push(out, (v / 65536) % 256)
push(out, (v / 16777216) % 256)
j = j + 1
return out
fun md5_hex(hexStr)
bytes = from_hex(hexStr)
digest = md5_bytes(bytes)
return bytes_to_hex(digest)
// Class wrapper to avoid global name collisions and show class usage
*/
#include <strings.fun>

272
lib/crypt/md5_legacy.fun Normal file
View file

@ -0,0 +1,272 @@
/*
* This file is part of the Fun programming language.
* https://hanez.org/project/fun/
*
* Copyright 2025 Johannes Findeisen <you@hanez.org>
* Licensed under the terms of the Apache-2.0 license.
* https://opensource.org/license/apache-2-0
*
* Added: 2025-10-01
*/
#include <strings.fun>
// Legacy global API and helpers. Please use the MD5 class (see lib/crypt/md5.fun).
fun u32(x)
// bring x into [0 .. 2^32-1] by modular reduction
m = 4294967296
while x < 0
x = x + m
while x >= m
x = x - m
return x
fun shl32(x, s)
return shl(u32(x), s)
fun shr32(x, s)
return shr(u32(x), s)
fun rol32(x, s)
return rol(u32(x), s)
fun and32(a, b)
return band(u32(a), u32(b))
fun or32(a, b)
return bor(u32(a), u32(b))
fun xor32(a, b)
return bxor(u32(a), u32(b))
fun not32(x)
return bnot(u32(x))
fun add32(a, b)
return u32(a + b)
fun add32_4(a, b, c, d)
return u32(u32(u32(a + b) + c) + d)
fun hex_val(ch)
if (ch == "0")
return 0
else if (ch == "1")
return 1
else if (ch == "2")
return 2
else if (ch == "3")
return 3
else if (ch == "4")
return 4
else if (ch == "5")
return 5
else if (ch == "6")
return 6
else if (ch == "7")
return 7
else if (ch == "8")
return 8
else if (ch == "9")
return 9
else if (ch == "a" || ch == "A")
return 10
else if (ch == "b" || ch == "B")
return 11
else if (ch == "c" || ch == "C")
return 12
else if (ch == "d" || ch == "D")
return 13
else if (ch == "e" || ch == "E")
return 14
else if (ch == "f" || ch == "F")
return 15
else
return 0
fun byte_from_hex_pair(hh)
// hh is 2-char string
hi = hex_val(substr(hh, 0, 1))
lo = hex_val(substr(hh, 1, 1))
return hi * 16 + lo
fun from_hex(hex)
// parse even-length hex string to array of bytes (numbers 0..255)
arr = []
i = 0
n = len(hex)
while i + 1 < n
b = byte_from_hex_pair(substr(hex, i, 2))
push(arr, b)
i = i + 2
return arr
fun two_hex(n)
n = n % 256
d = ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"]
hi = n / 16
lo = n % 16
// build with join
parts = [d[hi], d[lo]]
return join(parts, "")
fun bytes_to_hex(arr)
i = 0
out = []
while i < len(arr)
push(out, two_hex(arr[i]))
i = i + 1
return join(out, "")
// MD5 auxiliary functions
fun F(x, y, z)
return or32(and32(x, y), and32(not32(x), z))
fun G(x, y, z)
return or32(and32(x, z), and32(y, not32(z)))
fun H(x, y, z)
return xor32(xor32(x, y), z)
fun I(x, y, z)
return xor32(y, or32(x, not32(z)))
// T constants (K) = floor(abs(sin(i+1)) * 2^32), i=0..63
K = [
3614090360, 3905402710, 606105819, 3250441966, 4118548399, 1200080426, 2821735955, 4249261313,
1770035416, 2336552879, 4294925233, 2304563134, 1804603682, 4254626195, 2792965006, 1236535329,
4129170786, 3225465664, 643717713, 3921069994, 3593408605, 38016083, 3634488961, 3889429448,
568446438, 3275163606, 4107603335, 1163531501, 2850285829, 4243563512, 1735328473, 2368359562,
4294588738, 2272392833, 1839030562, 4259657740, 2763975236, 1272893353, 4139469664, 3200236656,
681279174, 3936430074, 3572445317, 76029189, 3654602809, 3873151461, 530742520, 3299628645,
4096336452, 1126891415, 2878612391, 4237533241, 1700485571, 2399980690, 4293915773, 2240044497,
1873313359, 4264355552, 2734768916, 1309151649, 4149444226, 3174756917, 718787259, 3951481745
]
// per-round rotation amounts
S = [
7,12,17,22, 7,12,17,22, 7,12,17,22, 7,12,17,22,
5, 9,14,20, 5, 9,14,20, 5, 9,14,20, 5, 9,14,20,
4,11,16,23, 4,11,16,23, 4,11,16,23, 4,11,16,23,
6,10,15,21, 6,10,15,21, 6,10,15,21, 6,10,15,21
]
fun pad_bytes(bytes)
// returns a new array with MD5 padding
L = len(bytes)
out = []
// copy original bytes
i = 0
while i < L
push(out, bytes[i])
i = i + 1
// append 0x80
push(out, 128)
// pad zeros until length % 64 == 56
while (len(out) % 64) != 56
push(out, 0)
// append length (bits) as 64-bit little-endian
len_bits = L * 8
j = 0
while j < 8
b = (len_bits / pow(2, 8 * j)) % 256
push(out, b)
j = j + 1
return out
fun word32_le(b0, b1, b2, b3)
return u32(b0 + b1 * 256 + b2 * 65536 + b3 * 16777216)
fun process_block(state, block)
// state: [a0,b0,c0,d0], block: 64 bytes array
a0 = state[0]
b0 = state[1]
c0 = state[2]
d0 = state[3]
// M[16] little-endian words
M = []
i = 0
while i < 16
j = i * 4
w = word32_le(block[j], block[j+1], block[j+2], block[j+3])
push(M, w)
i = i + 1
A = a0
B = b0
C = c0
D = d0
k = 0
while k < 64
if (k < 16)
f = F(B, C, D)
g = k
else if (k < 32)
f = G(B, C, D)
g = (5 * k + 1) % 16
else if (k < 48)
f = H(B, C, D)
g = (3 * k + 5) % 16
else
f = I(B, C, D)
g = (7 * k) % 16
tmp = D
sum = add32_4(A, f, K[k], M[g])
D = C
C = B
B = add32(B, rol32(sum, S[k]))
A = tmp
k = k + 1
state[0] = add32(state[0], A)
state[1] = add32(state[1], B)
state[2] = add32(state[2], C)
state[3] = add32(state[3], D)
return state
fun md5_bytes(bytes)
// returns array of 16 bytes of digest
data = pad_bytes(bytes)
// initial state
a0 = 1732584193 // 0x67452301
b0 = 4023233417 // 0xEFCDAB89
c0 = 2562383102 // 0x98BADCFE
d0 = 271733878 // 0x10325476
state = [a0, b0, c0, d0]
off = 0
N = len(data)
while off < N
block = []
i = 0
while i < 64
push(block, data[off + i])
i = i + 1
state = process_block(state, block)
off = off + 64
// output digest as little-endian bytes of A,B,C,D
out = []
j = 0
while j < 4
v = state[j]
// 4 bytes little-endian
push(out, (v) % 256)
push(out, (v / 256) % 256)
push(out, (v / 65536) % 256)
push(out, (v / 16777216) % 256)
j = j + 1
return out
fun md5_hex(hexStr)
bytes = from_hex(hexStr)
digest = md5_bytes(bytes)
return bytes_to_hex(digest)
fun md5_str(this, str)
bytes = string_to_bytes_ascii(str)
digest = this.md5_bytes(bytes)
return this.bytes_to_hex(digest)

368
lib/crypt/sha384.fun Normal file
View file

@ -0,0 +1,368 @@
/*
* This file is part of the Fun programming language.
* https://hanez.org/project/fun/
*
* Copyright 2025 Johannes Findeisen <you@hanez.org>
* Licensed under the terms of the Apache-2.0 license.
* https://opensource.org/license/apache-2-0
*
* Added: 2025-10-01
*/
// lib/crypt/sha384.fun
// Pure Fun SHA-384 implementation operating on hex-string input.
// 64-bit words are represented as [hi, lo] (two uint32 parts).
//
// Public API (class):
// s = SHA384()
// s.sha384_hex(hexStr) -> digest hex string (lowercase, 96 hex chars)
// s.sha384_str(str) -> digest hex string (lowercase, 96 hex chars)
//
// Known test vector ("abc"):
// SHA-384("abc") =
// cb00753f45a35e8bb5a03d699ac65007272c32ab0eded163
// 1a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7
#include <strings.fun>
class SHA384()
// -------- hex helpers --------
fun hex_val(this, ch)
if (ch == "0")
return 0
else if (ch == "1")
return 1
else if (ch == "2")
return 2
else if (ch == "3")
return 3
else if (ch == "4")
return 4
else if (ch == "5")
return 5
else if (ch == "6")
return 6
else if (ch == "7")
return 7
else if (ch == "8")
return 8
else if (ch == "9")
return 9
else if (ch == "a" || ch == "A")
return 10
else if (ch == "b" || ch == "B")
return 11
else if (ch == "c" || ch == "C")
return 12
else if (ch == "d" || ch == "D")
return 13
else if (ch == "e" || ch == "E")
return 14
else if (ch == "f" || ch == "F")
return 15
else
return 0
fun byte_from_hex_pair(this, hh)
number hi = this.hex_val(substr(hh, 0, 1))
number lo = this.hex_val(substr(hh, 1, 1))
return hi * 16 + lo
fun from_hex(this, hex)
hex = to_string(hex)
arr = []
number i = 0
number n = len(hex)
while i + 1 < n
number b = this.byte_from_hex_pair(substr(hex, i, 2))
push(arr, b)
i = i + 2
return arr
fun two_hex(this, n)
n = n % 256
hexd = "0123456789abcdef"
number hi = (n / 16) % 16
number lo = n % 16
c1 = substr(hexd, hi, 1)
c2 = substr(hexd, lo, 1)
return join([c1, c2], "")
fun bytes_to_hex(this, arr)
out = []
number i = 0
number L = len(arr)
while i < L
push(out, this.two_hex(arr[i]))
i = i + 1
return join(out, "")
// -------- 32/64 helpers --------
fun u32(this, x)
m = 4294967296
while x < 0
x = x + m
while x >= m
x = x - m
return x
// 64-bit as [hi, lo] (each uint32)
fun pack64_be(this, b0,b1,b2,b3,b4,b5,b6,b7)
number hi = this.u32(b0 * 16777216 + b1 * 65536 + b2 * 256 + b3)
number lo = this.u32(b4 * 16777216 + b5 * 65536 + b6 * 256 + b7)
return [hi, lo]
fun add64(this, a, b)
number alo = this.u32(a[1])
number ahi = this.u32(a[0])
number blo = this.u32(b[1])
number bhi = this.u32(b[0])
number sum_lo = alo + blo
number carry = sum_lo / 4294967296
sum_lo = sum_lo % 4294967296
number sum_hi = (ahi + bhi + carry) % 4294967296
return [sum_hi, sum_lo]
fun add64_5(this, a, b, c, d, e)
return this.add64(this.add64(this.add64(this.add64(a, b), c), d), e)
fun xor64(this, a, b)
return [ bxor(a[0], b[0]), bxor(a[1], b[1]) ]
fun and64(this, a, b)
return [ band(a[0], b[0]), band(a[1], b[1]) ]
fun or64(this, a, b)
return [ bor(a[0], b[0]), bor(a[1], b[1]) ]
fun not64(this, a)
return [ bnot(a[0]), bnot(a[1]) ]
// logical right shift by n (0..63)
fun shr64(this, a, n)
number s = n % 64
number hi = a[0]
number lo = a[1]
if (s == 0)
return [hi, lo]
else if (s < 32)
number new_lo = bor( shr(lo, s), shl(hi, 32 - s) )
number new_hi = shr(hi, s)
return [ new_hi, new_lo ]
else
number k = s - 32
number new_lo2 = shr(hi, k)
return [ 0, new_lo2 ]
// rotate right by n (0..63)
fun rotr64(this, a, n)
number s = n % 64
number hi = a[0]
number lo = a[1]
if (s == 0)
return [hi, lo]
else if (s < 32)
number new_lo = bor( shr(lo, s), shl(hi, 32 - s) )
number new_hi = bor( shr(hi, s), shl(lo, 32 - s) )
return [ new_hi, new_lo ]
else
number k = s - 32
// swap roles
number new_lo2 = bor( shr(hi, k), shl(lo, 32 - k) )
number new_hi2 = bor( shr(lo, k), shl(hi, 32 - k) )
return [ new_hi2, new_lo2 ]
// SHA-512 logical functions (used by SHA-384 rounds)
fun Ch(this, x, y, z)
// (x & y) ^ (~x & z)
return this.xor64(this.and64(x, y), this.and64(this.not64(x), z))
fun Maj(this, x, y, z)
// (x & y) ^ (x & z) ^ (y & z)
return this.xor64(this.xor64(this.and64(x, y), this.and64(x, z)), this.and64(y, z))
fun Sigma0(this, x)
return this.xor64(this.xor64(this.rotr64(x, 28), this.rotr64(x, 34)), this.rotr64(x, 39))
fun Sigma1(this, x)
return this.xor64(this.xor64(this.rotr64(x, 14), this.rotr64(x, 18)), this.rotr64(x, 41))
fun sigma0(this, x)
return this.xor64(this.xor64(this.rotr64(x, 1), this.rotr64(x, 8)), this.shr64(x, 7))
fun sigma1(this, x)
return this.xor64(this.xor64(this.rotr64(x, 19), this.rotr64(x, 61)), this.shr64(x, 6))
// -------- constants --------
// SHA-384 uses the same K constants as SHA-512
K = [
[0x428a2f98,0xd728ae22],[0x71374491,0x23ef65cd],[0xb5c0fbcf,0xec4d3b2f],[0xe9b5dba5,0x8189dbbc],
[0x3956c25b,0xf348b538],[0x59f111f1,0xb605d019],[0x923f82a4,0xaf194f9b],[0xab1c5ed5,0xda6d8118],
[0xd807aa98,0xa3030242],[0x12835b01,0x45706fbe],[0x243185be,0x4ee4b28c],[0x550c7dc3,0xd5ffb4e2],
[0x72be5d74,0xf27b896f],[0x80deb1fe,0x3b1696b1],[0x9bdc06a7,0x25c71235],[0xc19bf174,0xcf692694],
[0xe49b69c1,0x9ef14ad2],[0xefbe4786,0x384f25e3],[0x0fc19dc6,0x8b8cd5b5],[0x240ca1cc,0x77ac9c65],
[0x2de92c6f,0x592b0275],[0x4a7484aa,0x6ea6e483],[0x5cb0a9dc,0xbd41fbd4],[0x76f988da,0x831153b5],
[0x983e5152,0xee66dfab],[0xa831c66d,0x2db43210],[0xb00327c8,0x98fb213f],[0xbf597fc7,0xbeef0ee4],
[0xc6e00bf3,0x3da88fc2],[0xd5a79147,0x930aa725],[0x06ca6351,0xe003826f],[0x14292967,0x0a0e6e70],
[0x27b70a85,0x46d22ffc],[0x2e1b2138,0x5c26c926],[0x4d2c6dfc,0x5ac42aed],[0x53380d13,0x9d95b3df],
[0x650a7354,0x8baf63de],[0x766a0abb,0x3c77b2a8],[0x81c2c92e,0x47edaee6],[0x92722c85,0x1482353b],
[0xa2bfe8a1,0x4cf10364],[0xa81a664b,0xbc423001],[0xc24b8b70,0xd0f89791],[0xc76c51a3,0x0654be30],
[0xd192e819,0xd6ef5218],[0xd6990624,0x5565a910],[0xf40e3585,0x5771202a],[0x106aa070,0x32bbd1b8],
[0x19a4c116,0xb8d2d0c8],[0x1e376c08,0x5141ab53],[0x2748774c,0xdf8eeb99],[0x34b0bcb5,0xe19b48a8],
[0x391c0cb3,0xc5c95a63],[0x4ed8aa4a,0xe3418acb],[0x5b9cca4f,0x7763e373],[0x682e6ff3,0xd6b2b8a3],
[0x748f82ee,0x5defb2fc],[0x78a5636f,0x43172f60],[0x84c87814,0xa1f0ab72],[0x8cc70208,0x1a6439ec],
[0x90befffa,0x23631e28],[0xa4506ceb,0xde82bde9],[0xbef9a3f7,0xb2c67915],[0xc67178f2,0xe372532b],
[0xca273ece,0xea26619c],[0xd186b8c7,0x21c0c207],[0xeada7dd6,0xcde0eb1e],[0xf57d4f7f,0xee6ed178],
[0x06f067aa,0x72176fba],[0x0a637dc5,0xa2c898a6],[0x113f9804,0xbef90dae],[0x1b710b35,0x131c471b],
[0x28db77f5,0x23047d84],[0x32caab7b,0x40c72493],[0x3c9ebe0a,0x15c9bebc],[0x431d67c4,0x9c100d4c],
[0x4cc5d4be,0xcb3e42b6],[0x597f299c,0xfc657e2a],[0x5fcb6fab,0x3ad6faec],[0x6c44198c,0x4a475817]
]
// SHA-384 initial hash value (IV), 64-bit words split into [hi, lo]
IV = [
[0xcbbb9d5d, 0xc1059ed8], [0x629a292a, 0x367cd507], [0x9159015a, 0x3070dd17], [0x152fecd8, 0xf70e5939],
[0x67332667, 0xffc00b31], [0x8eb44a87, 0x68581511], [0xdb0c2e0d, 0x64f98fa7], [0x47b5481d, 0xbefa4fa4]
]
// -------- padding --------
fun pad_bytes(this, bytes)
number L = len(bytes)
out = []
// copy bytes
number i = 0
while i < L
push(out, bytes[i])
i = i + 1
// append 0x80
push(out, 128)
// pad zeros until length % 128 == 112 (i.e., 896 bits)
while (len(out) % 128) != 112
push(out, 0)
// append 128-bit length (we use upper 64 bits zero, lower 64 = L*8)
number j = 0
while j < 8
push(out, 0)
j = j + 1
// lower 8 bytes big-endian
number bits = L * 8
number t = 7
while t >= 0
number b = (bits / pow(2, 8 * t)) % 256
push(out, b)
t = t - 1
return out
// -------- core --------
fun process_block(this, H, block)
// W ring buffer of 16 words ([hi, lo])
W = []
number i = 0
while i < 16
number j = i * 8
push(W, this.pack64_be(block[j],block[j+1],block[j+2],block[j+3],
block[j+4],block[j+5],block[j+6],block[j+7]))
i = i + 1
a = H[0]
b = H[1]
c = H[2]
d = H[3]
e = H[4]
f = H[5]
g = H[6]
h = H[7]
number t = 0
while t < 80
number idx = t % 16
if (t >= 16)
w2 = W[(t - 2) % 16]
w7 = W[(t - 7) % 16]
w15 = W[(t - 15) % 16]
w16 = W[(t - 16) % 16]
s1 = this.sigma1(w2)
s0 = this.sigma0(w15)
tmp = this.add64(w16, s0)
tmp = this.add64(tmp, w7)
W[idx] = this.add64(tmp, s1)
Wt = W[idx]
// Precompute hot terms once per round
Se1 = this.Sigma1(e)
ch = this.Ch(e, f, g)
// T1 = h + Se1 + ch + K[t] + Wt
tmp1 = this.add64(h, Se1)
tmp1 = this.add64(tmp1, ch)
tmp1 = this.add64(tmp1, this.K[t])
T1 = this.add64(tmp1, Wt)
// T2 = Sigma0(a) + Maj(a, b, c)
T2 = this.add64(this.Sigma0(a), this.Maj(a, b, c))
// State update
h = g
g = f
f = e
e = this.add64(d, T1)
d = c
c = b
b = a
a = this.add64(T1, T2)
t = t + 1
H[0] = this.add64(H[0], a)
H[1] = this.add64(H[1], b)
H[2] = this.add64(H[2], c)
H[3] = this.add64(H[3], d)
H[4] = this.add64(H[4], e)
H[5] = this.add64(H[5], f)
H[6] = this.add64(H[6], g)
H[7] = this.add64(H[7], h)
return H
fun sha384_bytes(this, bytes)
data = this.pad_bytes(bytes)
// init H (deep copy IV)
H = [ this.IV[0], this.IV[1], this.IV[2], this.IV[3], this.IV[4], this.IV[5], this.IV[6], this.IV[7] ]
number off = 0
number N = len(data)
while off < N
block = []
number i = 0
while i < 128
push(block, data[off + i])
i = i + 1
H = this.process_block(H, block)
off = off + 128
// output 48 bytes big-endian from H[0..5]
out = []
number j = 0
while j < 6
word = H[j]
number hi = word[0]
number lo = word[1]
// hi
push(out, (hi / 16777216) % 256)
push(out, (hi / 65536) % 256)
push(out, (hi / 256) % 256)
push(out, hi % 256)
// lo
push(out, (lo / 16777216) % 256)
push(out, (lo / 65536) % 256)
push(out, (lo / 256) % 256)
push(out, lo % 256)
j = j + 1
return out
fun sha384_hex(this, hexStr)
bytes = this.from_hex(hexStr)
digest = this.sha384_bytes(bytes)
return this.bytes_to_hex(digest)
// Hash raw string bytes (printable ASCII)
fun sha384_str(this, str)
bytes = string_to_bytes_ascii(str)
digest = this.sha384_bytes(bytes)
return this.bytes_to_hex(digest)

View file

@ -1,4 +1,4 @@
/*
/*
* This file is part of the Fun programming language.
* https://hanez.org/project/fun/
*
@ -9,54 +9,7 @@
* Added: 2025-10-01
*/
// ASCII string to bytes (printable ASCII 0x20..0x7E)
fun string_to_bytes_ascii(this, s)
str = to_string(s)
out = []
number i = 0
// ASCII printable ranges
P1 = " !\"#$%&'()*+,-./" // 32..47
P2 = "0123456789" // 48..57
P3 = ":;<=>?@" // 58..64
P4 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" // 65..90
P5 = "[\\]^_`" // 91..96
P6 = "abcdefghijklmnopqrstuvwxyz" // 97..122
P7 = "{|}~" // 123..126
while true
ch = substr(str, i, 1)
if (typeof(ch) != "String" || ch == "")
break
number code = -1
idx = find(P1, ch)
if (idx >= 0)
code = 32 + idx
else
idx = find(P2, ch)
if (idx >= 0)
code = 48 + idx
else
idx = find(P3, ch)
if (idx >= 0)
code = 58 + idx
else
idx = find(P4, ch)
if (idx >= 0)
code = 65 + idx
else
idx = find(P5, ch)
if (idx >= 0)
code = 91 + idx
else
idx = find(P6, ch)
if (idx >= 0)
code = 97 + idx
else
idx = find(P7, ch)
if (idx >= 0)
code = 123 + idx
else
// non-printable -> 0
code = 0
push(out, code)
i = i + 1
return out
// This file should not contain code! It should just include all string related
// functions from core/*.fun.
#include <core/string_to_bytes_ascii.fun>

View file

@ -9,6 +9,8 @@
* https://opensource.org/license/apache-2-0
*/
include <strings.fun>
fun foo()
print("Have fun!")
print("Having fun... forever.")
@ -17,6 +19,8 @@ print("Typeof foo(): " + typeof(foo))
print("Yay, the playground for having fun... ;)")
print(string_to_bytes_ascii("Have Fun!"))
number n = 23
// Every type MUST be lowercase. Sint* must be sint*.
print(n)

View file

@ -28,7 +28,7 @@
* // Stack after: [5]
*
* @author Johannes Findeisen
* @date 2025-10-16
* @date 2025-09-16
*/
case OP_LEN: {

View file

@ -24,7 +24,7 @@
* // Stack after: []
*
* @author Johannes Findeisen
* @date 2025-10-16
* @date 2025-09-16
*/
case OP_PRINT: {