Added sha384.fun to std library and alot of fixes. (0.16.3)
This commit is contained in:
parent
f0ed1d6761
commit
17241b2401
18 changed files with 820 additions and 314 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
cmake_minimum_required(VERSION 3.16)
|
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 11)
|
||||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
|
|
|
||||||
|
|
@ -29,3 +29,26 @@ print(typeof(x)) // -> "String"
|
||||||
|
|
||||||
// Typed byte must remain numeric (uint8):
|
// Typed byte must remain numeric (uint8):
|
||||||
// b = "oops" // Uncomment to see a runtime type error
|
// 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
|
||||||
|
*/
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,16 @@ print(md5.md5_hex("6d65737361676520646967657374")) // -> f96b697d7cb7938d525a2f
|
||||||
print(md5.md5_hex("6162636465666768696a6b6c6d6e6f707172737475767778797a")) // -> c3fcd3d76192e4007dfb496cca67e13b
|
print(md5.md5_hex("6162636465666768696a6b6c6d6e6f707172737475767778797a")) // -> c3fcd3d76192e4007dfb496cca67e13b
|
||||||
|
|
||||||
// "Have Fun!"
|
// "Have Fun!"
|
||||||
print(md5.md5_str("Have Fun!")) // ->
|
print(md5.md5_str("Have Fun!")) // -> 852438d026c018c4307b916406f98c62
|
||||||
|
|
||||||
print("=== Done ===")
|
print("=== Done ===")
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
=== MD5 demo (hex input) ===
|
||||||
|
900150983cd24fb0d6963f7d28e17f72
|
||||||
|
d41d8cd98f00b204e9800998ecf8427e
|
||||||
|
f96b697d7cb7938d525a2f31aaf161d0
|
||||||
|
c3fcd3d76192e4007dfb496cca67e13b
|
||||||
|
812f2c01287af0e7c0a0b3daa381a51a
|
||||||
|
=== Done ===
|
||||||
|
*/
|
||||||
|
|
|
||||||
|
|
@ -31,3 +31,12 @@ print(sha.sha256_hex("6d65737361676520646967657374")) // -> f7846f55cf23e14eebea
|
||||||
print(sha.sha256_hex("6162636465666768696a6b6c6d6e6f707172737475767778797a")) // -> 71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73
|
print(sha.sha256_hex("6162636465666768696a6b6c6d6e6f707172737475767778797a")) // -> 71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73
|
||||||
|
|
||||||
print("=== Done ===")
|
print("=== Done ===")
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
=== SHA-256 demo (hex input) ===
|
||||||
|
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
|
||||||
|
3859a4ec00dcbed7c01d4a462d18c1f4097a690a1d4d459be4e5b6f5a594ee68
|
||||||
|
de8ff7370090823795e96e3b7fbee3cfad374492417da99d72ba55297f7e58ab
|
||||||
|
5d3ed26c5e75585f56e664c0ebc63aa185ec606109f6374fefa42c862670d257
|
||||||
|
=== Done ===
|
||||||
|
*/
|
||||||
|
|
|
||||||
|
|
@ -35,3 +35,14 @@ print(sha.sha256_str("6162636465666768696a6b6c6d6e6f707172737475767778797a")) //
|
||||||
|
|
||||||
print("=== Note ===")
|
print("=== Note ===")
|
||||||
print("sha256_str(\"616263\") hashes the text 616263; sha256_hex(\"616263\") hashes bytes 0x61 0x62 0x63 (abc).")
|
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
29
examples/sha384_example.fun
Executable 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"))
|
||||||
|
|
@ -33,3 +33,11 @@ print(sha.sha512_hex("6d65737361676520646967657374"))
|
||||||
// 3f36cc64dab6c0c5
|
// 3f36cc64dab6c0c5
|
||||||
|
|
||||||
print("=== Done ===")
|
print("=== Done ===")
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
=== SHA-512 demo (hex input) ===
|
||||||
|
cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
|
||||||
|
ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f
|
||||||
|
107dbf389d9e9f71a3a95f6c055b9251bc5268c2be16d6c13492ea45b0199f3309e16455ab1e96118e8a905d5597b72038ddb372a89826046de66687bb420e7c
|
||||||
|
=== Done ===
|
||||||
|
*/
|
||||||
|
|
|
||||||
|
|
@ -32,3 +32,12 @@ print(sha.sha512_str("616263")) // -> ee21095236a9c037f705f41ffa3cf60869891fcdb
|
||||||
|
|
||||||
print("=== Note ===")
|
print("=== Note ===")
|
||||||
print("sha512_str(\"616263\") hashes the text 616263; sha512_hex(\"616263\") hashes bytes 0x61 0x62 0x63 (abc).")
|
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
3
lib/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# README
|
||||||
|
|
||||||
|
The Fun standard library.
|
||||||
3
lib/core/README.md
Normal file
3
lib/core/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# README
|
||||||
|
|
||||||
|
In this directory every file should just contain one function if possible!
|
||||||
62
lib/core/string_to_bytes_ascii.fun
Normal file
62
lib/core/string_to_bytes_ascii.fun
Normal 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
|
||||||
|
|
@ -18,265 +18,7 @@
|
||||||
// Example:
|
// Example:
|
||||||
// print(md5_hex("616263")) // "abc" => 900150983cd24fb0d6963f7d28e17f72
|
// 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
|
// Class wrapper to avoid global name collisions and show class usage
|
||||||
*/
|
|
||||||
|
|
||||||
#include <strings.fun>
|
#include <strings.fun>
|
||||||
|
|
||||||
|
|
|
||||||
272
lib/crypt/md5_legacy.fun
Normal file
272
lib/crypt/md5_legacy.fun
Normal 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
368
lib/crypt/sha384.fun
Normal 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)
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of the Fun programming language.
|
* This file is part of the Fun programming language.
|
||||||
* https://hanez.org/project/fun/
|
* https://hanez.org/project/fun/
|
||||||
*
|
*
|
||||||
|
|
@ -9,54 +9,7 @@
|
||||||
* Added: 2025-10-01
|
* Added: 2025-10-01
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// ASCII string to bytes (printable ASCII 0x20..0x7E)
|
// This file should not contain code! It should just include all string related
|
||||||
fun string_to_bytes_ascii(this, s)
|
// functions from core/*.fun.
|
||||||
str = to_string(s)
|
|
||||||
out = []
|
#include <core/string_to_bytes_ascii.fun>
|
||||||
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
|
|
||||||
|
|
|
||||||
4
play.fun
4
play.fun
|
|
@ -9,6 +9,8 @@
|
||||||
* https://opensource.org/license/apache-2-0
|
* https://opensource.org/license/apache-2-0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
include <strings.fun>
|
||||||
|
|
||||||
fun foo()
|
fun foo()
|
||||||
print("Have fun!")
|
print("Have fun!")
|
||||||
print("Having fun... forever.")
|
print("Having fun... forever.")
|
||||||
|
|
@ -17,6 +19,8 @@ print("Typeof foo(): " + typeof(foo))
|
||||||
|
|
||||||
print("Yay, the playground for having fun... ;)")
|
print("Yay, the playground for having fun... ;)")
|
||||||
|
|
||||||
|
print(string_to_bytes_ascii("Have Fun!"))
|
||||||
|
|
||||||
number n = 23
|
number n = 23
|
||||||
// Every type MUST be lowercase. Sint* must be sint*.
|
// Every type MUST be lowercase. Sint* must be sint*.
|
||||||
print(n)
|
print(n)
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@
|
||||||
* // Stack after: [5]
|
* // Stack after: [5]
|
||||||
*
|
*
|
||||||
* @author Johannes Findeisen
|
* @author Johannes Findeisen
|
||||||
* @date 2025-10-16
|
* @date 2025-09-16
|
||||||
*/
|
*/
|
||||||
|
|
||||||
case OP_LEN: {
|
case OP_LEN: {
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@
|
||||||
* // Stack after: []
|
* // Stack after: []
|
||||||
*
|
*
|
||||||
* @author Johannes Findeisen
|
* @author Johannes Findeisen
|
||||||
* @date 2025-10-16
|
* @date 2025-09-16
|
||||||
*/
|
*/
|
||||||
|
|
||||||
case OP_PRINT: {
|
case OP_PRINT: {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue