1
0
Fork 0
forked from fun/fun

Added RIPEMD-160 support to stdlib in lib/crypt/ripemd160.fun (BROKEN) and some more test scripts to examples/. (0.37.22)

This commit is contained in:
Johannes Findeisen 2025-12-28 00:54:55 +01:00
commit 21f437ebaf
10 changed files with 618 additions and 1 deletions

View file

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.10)
project(fun VERSION 0.37.21 LANGUAGES C)
project(fun VERSION 0.37.22 LANGUAGES C)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)

View file

@ -0,0 +1,154 @@
#!/usr/bin/env fun
/*
* This file is part of the Fun programming language.
* https://fun-lang.xyz/
*
* 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-12-27
*/
#include <crypt/ripemd160.fun>
fun to_hex_32(v)
d = ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"]
out = []
i = 0
while i < 4
b = band(shr(v, (3 - i) * 8), 0xFF)
push(out, d[shr(b, 4)])
push(out, d[band(b, 0xF)])
i = i + 1
return join(out, "")
rmd = RIPEMD160()
state = [1732584193, 4023233417, 2562383102, 271733878, 3285377520]
block = []
push(block, 128) // 0x80
i = 1
while i < 64
push(block, 0)
i = i + 1
print("Initial state:")
for v in state
print(" " + to_hex_32(v))
// Manual process_block logic with prints
M = []
i = 0
while i < 16
j = i * 4
push(M, rmd.word32_le(block[j], block[j+1], block[j+2], block[j+3]))
i = i + 1
al = state[0]
bl = state[1]
cl = state[2]
dl = state[3]
el = state[4]
ar = state[0]
br = state[1]
cr = state[2]
dr = state[3]
er = state[4]
j = 0
while j < 80
if j < 16
stage = 0
stage_r = 4
else if j < 32
stage = 1
stage_r = 3
else if j < 48
stage = 2
stage_r = 2
else if j < 64
stage = 3
stage_r = 1
else
stage = 4
stage_r = 0
f = rmd.F(stage, bl, cl, dl)
TL1 = rmd.add32(al, f)
TL2 = rmd.add32(M[rmd.RL[j]], rmd.KL[stage])
TL3 = rmd.add32(TL1, TL2)
TL4 = rmd.rol32(TL3, rmd.SL[j])
TL = rmd.add32(TL4, el)
if j < 2
print("j=" + to_string(j) + " L: al=" + to_hex_32(al) + " f=" + to_hex_32(f) + " TL3=" + to_hex_32(TL3) + " TL4=" + to_hex_32(TL4) + " TL=" + to_hex_32(TL))
al = el
el = dl
dl = rmd.rol32(cl, 10)
cl = bl
bl = TL
fr = rmd.F(stage_r, br, cr, dr)
TR1 = rmd.add32(ar, fr)
TR2 = rmd.add32(M[rmd.RR[j]], rmd.KR[stage])
TR3 = rmd.add32(TR1, TR2)
TR4 = rmd.rol32(TR3, rmd.SR[j])
TR = rmd.add32(TR4, er)
if j < 2
print("j=" + to_string(j) + " R: ar=" + to_hex_32(ar) + " fr=" + to_hex_32(fr) + " TR3=" + to_hex_32(TR3) + " TR4=" + to_hex_32(TR4) + " TR=" + to_hex_32(TR))
ar = er
er = dr
dr = rmd.rol32(cr, 10)
cr = br
br = TR
if j == 0
print("After j=0:")
print(" L: al=" + to_hex_32(al) + " bl=" + to_hex_32(bl) + " cl=" + to_hex_32(cl) + " dl=" + to_hex_32(dl) + " el=" + to_hex_32(el))
print(" R: ar=" + to_hex_32(ar) + " br=" + to_hex_32(br) + " cr=" + to_hex_32(cr) + " dr=" + to_hex_32(dr) + " er=" + to_hex_32(er))
j = j + 1
print("Registers after 80 steps:")
print(" L: A=" + to_hex_32(al) + " B=" + to_hex_32(bl) + " C=" + to_hex_32(cl) + " D=" + to_hex_32(dl) + " E=" + to_hex_32(el))
print(" R: Ar=" + to_hex_32(ar) + " Br=" + to_hex_32(br) + " Cr=" + to_hex_32(cr) + " Dr=" + to_hex_32(dr) + " Er=" + to_hex_32(er))
h0 = rmd.add32(state[1], rmd.add32(cl, dr))
h1 = rmd.add32(state[2], rmd.add32(dl, er))
h2 = rmd.add32(state[3], rmd.add32(el, ar))
h3 = rmd.add32(state[4], rmd.add32(al, br))
h4 = rmd.add32(state[0], rmd.add32(bl, cr))
state[0] = h0
state[1] = h1
state[2] = h2
state[3] = h3
state[4] = h4
print("Final state:")
for v in state
print(" " + to_hex_32(v))
/* Possible output:
Initial state:
67452301
efcdab89
98badcfe
10325476
c3d2e1f0
j=0 L: al=67452301 f=67452301 TL3=ce8a4682 TL4=52341674 TL=1606f864
j=0 R: ar=67452301 fr=10325476 TR3=c81a035d TR4=1a035dc8 TR=ddd63fb8
After j=0:
L: al=c3d2e1f0 bl=1606f864 cl=efcdab89 dl=eb73fa62 el=10325476
R: ar=c3d2e1f0 br=ddd63fb8 cr=efcdab89 dr=eb73fa62 er=10325476
j=1 L: al=c3d2e1f0 f=12b8a98f TL3=d68b8b7f TL4=e2dff5a2 TL=f3124a18
j=1 R: ar=c3d2e1f0 fr=221b9025 TR3=3690fdfb TR4=21fbf66d TR=322e4ae3
Registers after 80 steps:
L: A=594637a7 B=215d97b3 C=eba027eb D=b99cdc7a E=ec4dcdff
R: Ar=e7eb2e49 Br=85bff1f4 Cr=1d9bc99d Dr=a7ffa90b Er=ffcec761
Final state:
836d7c7f
522680d9
e46b50be
a2d90b8b
a63e8451
*/

View file

@ -0,0 +1,58 @@
#!/usr/bin/env fun
/*
* This file is part of the Fun programming language.
* https://fun-lang.xyz/
*
* 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-12-27
*/
// THIS IS BROKEN ACTUALLY! IT DOES NOT CALCULATE THE EXPECTED HASHES!
// Example usage of the RIPEMD-160 hash algorithm.
#include <crypt/ripemd160.fun>
rmd = RIPEMD160()
// Test case 1: Empty string
s1 = ""
h1 = rmd.ripemd160_str(s1)
print("RIPEMD-160(\"" + s1 + "\") = " + h1)
// Expected: 9c1185a5c5e9fc54612808977ee8f548b2258d31
// Test case 2: "abc"
s2 = "abc"
h2 = rmd.ripemd160_str(s2)
print("RIPEMD-160(\"" + s2 + "\") = " + h2)
// Expected: 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc
// Test case 3: "message digest"
s3 = "message digest"
h3 = rmd.ripemd160_str(s3)
print("RIPEMD-160(\"" + s3 + "\") = " + h3)
// Expected: 5d0689ef49d2fae572b881b123a85ffa21595f36
// Example of hashing from hex string
hex_input = "616263" // "abc" in hex
h4 = rmd.ripemd160_hex(hex_input)
print("RIPEMD-160(hex: " + hex_input + ") = " + h4)
// Expected: 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc
/* Expected output:
RIPEMD-160("") = 9c1185a5c5e9fc54612808977ee8f548b2258d31
RIPEMD-160("abc") = 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc
RIPEMD-160("message digest") = 5d0689ef49d2fae572b881b123a85ffa21595f36
RIPEMD-160(hex: 616263) = 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc
*/
/* Actual output:
RIPEMD-160("") = d90cc72ef4ad5a2c51f89dc938de0b989c4c4b46
RIPEMD-160("abc") = 7f339b642aaa074a849c6c1cd860cb049cc792b3
RIPEMD-160("message digest") = a4f9cd0270a341d05a713df4bf49a3ce8aabde64
RIPEMD-160(hex: 616263) = 7f339b642aaa074a849c6c1cd860cb049cc792b3
*/

View file

@ -0,0 +1,19 @@
#!/usr/bin/env fun
/*
* This file is part of the Fun programming language.
* https://fun-lang.xyz/
*
* 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-12-27
*/
#include <crypt/ripemd160.fun>
print("Include OK")
/* Expected output:
Include OK
*/

26
examples/test_bits.fun Normal file
View file

@ -0,0 +1,26 @@
#!/usr/bin/env fun
/*
* This file is part of the Fun programming language.
* https://fun-lang.xyz/
*
* 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-12-27
*/
print(bxor(0x80000000, 0x00000001))
print(bor(0x80000000, 0x00000001))
print(band(0x80000000, 0x80000000))
print(bnot(0x80000000))
print(bnot(0x7FFFFFFF))
/* Expected output:
2147483649
2147483649
2147483648
2147483647
2147483648
*/

22
examples/test_rol.fun Normal file
View file

@ -0,0 +1,22 @@
#!/usr/bin/env fun
/*
* This file is part of the Fun programming language.
* https://fun-lang.xyz/
*
* 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-12-27
*/
print(rol(0x12345678, 4)) // Should be 0x23456781
print(rol(0x80000000, 1)) // Should be 0x00000001
print(rol(0x00000001, 31)) // Should be 0x80000000
/* Expected output:
591751041
1
2147483648
*/

20
examples/test_shl.fun Normal file
View file

@ -0,0 +1,20 @@
#!/usr/bin/env fun
/*
* This file is part of the Fun programming language.
* https://fun-lang.xyz/
*
* 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-12-27
*/
print(shl(0x80, 24))
print(128 * 16777216)
/* Expected output:
2147483648
2147483648
*/

24
examples/test_types.fun Normal file
View file

@ -0,0 +1,24 @@
#!/usr/bin/env fun
/*
* This file is part of the Fun programming language.
* https://fun-lang.xyz/
*
* 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-12-27
*/
print(typeof(128 * 16777216))
print(128 * 16777216)
print(typeof(0x80000000))
print(0x80000000)
/* Expected output:
Number
2147483648
Number
2147483648
*/

22
examples/test_xor.fun Normal file
View file

@ -0,0 +1,22 @@
#!/usr/bin/env fun
/*
* This file is part of the Fun programming language.
* https://fun-lang.xyz/
*
* 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-12-27
*/
print(bxor(0xefcdab89, 0x98badcfe))
print(bxor(0x77767677, 0x10325476))
print(bxor(bxor(0xefcdab89, 0x98badcfe), 0x10325476))
/* Expected output:
2004318071
1732518401
1732584193
*/

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

@ -0,0 +1,272 @@
/*
* This file is part of the Fun programming language.
* https://fun-lang.xyz/
*
* 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-12-27
*/
// THIS IS BROKEN ACTUALLY! IT DOES NOT CALCULATE THE EXPECTED HASHES!
#include <strings.fun>
class RIPEMD160()
KL = [0, 1518500249, 1859775393, 2400959708, 2840853838]
KR = [1352829926, 1548603684, 1836062451, 2054012649, 0]
RL = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
]
RR = [
5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
]
SL = [
11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
]
SR = [
8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
]
fun u32(this, x)
m = 4294967296
while x < 0
x = x + m
while x >= m
x = x - m
return x
fun rol32(this, x, s)
return rol(this.u32(x), s)
fun add32(this, a, b)
return this.u32(a + b)
fun F(this, stage, x, y, z)
if stage == 0
return bxor(bxor(x, y), z)
else if stage == 1
return bor(band(x, y), band(bnot(x), z))
else if stage == 2
return bxor(bor(x, bnot(y)), z)
else if stage == 3
return bor(band(x, z), band(y, bnot(z)))
else
return bxor(x, bor(y, bnot(z)))
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)
hi = this.hex_val(substr(hh, 0, 1))
lo = this.hex_val(substr(hh, 1, 1))
return hi * 16 + lo
fun from_hex(this, hex)
arr = []
i = 0
n = len(hex)
while i + 1 < n
push(arr, this.byte_from_hex_pair(substr(hex, i, 2)))
i = i + 2
return arr
fun two_hex(this, n)
n = band(n, 0xFF)
d = ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"]
return join([d[shr(n, 4)], d[band(n, 0xF)]], "")
fun bytes_to_hex(this, arr)
i = 0
out = []
while i < len(arr)
push(out, this.two_hex(arr[i]))
i = i + 1
return join(out, "")
fun pad_bytes(this, bytes)
L = len(bytes)
out = []
i = 0
while i < L
push(out, bytes[i])
i = i + 1
push(out, 128)
while (len(out) % 64) != 56
push(out, 0)
len_bits = L * 8
j = 0
while j < 8
push(out, band(shr(len_bits, 8 * j), 0xFF))
j = j + 1
return out
fun word32_le(this, b0, b1, b2, b3)
return bor(bor(bor(b0, shl(b1, 8)), shl(b2, 16)), shl(b3, 24))
fun process_block(this, state, block)
M = []
i = 0
while i < 16
j = i * 4
push(M, this.word32_le(block[j], block[j+1], block[j+2], block[j+3]))
i = i + 1
A = state[0]
B = state[1]
C = state[2]
D = state[3]
E = state[4]
Ar = state[0]
Br = state[1]
Cr = state[2]
Dr = state[3]
Er = state[4]
j = 0
while j < 80
if j < 16
stage = 0
stage_r = 4
else if j < 32
stage = 1
stage_r = 3
else if j < 48
stage = 2
stage_r = 2
else if j < 64
stage = 3
stage_r = 1
else
stage = 4
stage_r = 0
// Left side step
T = this.add32(this.rol32(this.add32(this.add32(A, this.F(stage, B, C, D)), this.add32(M[this.RL[j]], this.KL[stage])), this.SL[j]), E)
A = E
E = D
D = this.rol32(C, 10)
C = B
B = T
// Right side step
Tr = this.add32(this.rol32(this.add32(this.add32(Ar, this.F(stage_r, Br, Cr, Dr)), this.add32(M[this.RR[j]], this.KR[stage])), this.SR[j]), Er)
Ar = Er
Er = Dr
Dr = this.rol32(Cr, 10)
Cr = Br
Br = Tr
j = j + 1
al = A
bl = B
cl = C
dl = D
el = E
ar = Ar
br = Br
cr = Cr
dr = Dr
er = Er
h0 = state[0]
h1 = state[1]
h2 = state[2]
h3 = state[3]
h4 = state[4]
state[0] = this.add32(h1, this.add32(B, Cr))
state[1] = this.add32(h2, this.add32(C, Dr))
state[2] = this.add32(h3, this.add32(D, Er))
state[3] = this.add32(h4, this.add32(E, Ar))
state[4] = this.add32(h0, this.add32(A, Br))
return state
fun ripemd160_bytes(this, bytes)
state = [1732584193, 4023233417, 2562383102, 271733878, 3285377520]
data = this.pad_bytes(bytes)
N = len(data)
off = 0
while off < N
block = []
i = 0
while i < 64
push(block, data[off + i])
i = i + 1
state = this.process_block(state, block)
off = off + 64
out = []
j = 0
while j < 5
v = state[j]
push(out, band(v, 0xFF))
push(out, band(shr(v, 8), 0xFF))
push(out, band(shr(v, 16), 0xFF))
push(out, band(shr(v, 24), 0xFF))
j = j + 1
return out
fun ripemd160_hex(this, hexStr)
bytes = this.from_hex(hexStr)
digest = this.ripemd160_bytes(bytes)
return this.bytes_to_hex(digest)
fun ripemd160_str(this, str)
bytes = string_to_bytes_ascii(str)
digest = this.ripemd160_bytes(bytes)
return this.bytes_to_hex(digest)