Merge pull request #640 from mir-protocol/ripeMD

RipeMD
This commit is contained in:
Dima V 2022-10-03 15:49:04 -07:00 committed by GitHub
commit dd6c5a0d1a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 1100 additions and 31 deletions

View File

@ -22,6 +22,7 @@ pest = "2.1.3"
pest_derive = "2.1.0"
rand = "0.8.5"
rand_chacha = "0.3.1"
ripemd = "0.1.3"
rlp = "0.5.1"
serde = { version = "1.0.144", features = ["derive"] }
sha2 = "0.10.2"

View File

@ -48,6 +48,13 @@ pub(crate) fn combined_kernel() -> Kernel {
include_str!("asm/mpt/storage_write.asm"),
include_str!("asm/mpt/util.asm"),
include_str!("asm/mpt/write.asm"),
include_str!("asm/ripemd/box.asm"),
include_str!("asm/ripemd/compression.asm"),
include_str!("asm/ripemd/constants.asm"),
include_str!("asm/ripemd/functions.asm"),
include_str!("asm/ripemd/main.asm"),
include_str!("asm/ripemd/memory.asm"),
include_str!("asm/ripemd/update.asm"),
include_str!("asm/rlp/encode.asm"),
include_str!("asm/rlp/decode.asm"),
include_str!("asm/rlp/num_bytes.asm"),

View File

@ -55,8 +55,7 @@
// stack: (empty)
%endmacro
// Load a big-endian u32, consisting of 4 bytes (c_3, c_2, c_1, c_0),
// from the kernel.
// Load from the kernel a big-endian u32, consisting of 4 bytes (c_3, c_2, c_1, c_0)
%macro mload_kernel_u32(segment)
// stack: offset
DUP1
@ -85,6 +84,32 @@
// stack: (((((c_3 << 8) | c_2) << 8) | c_1) << 8) | c_0
%endmacro
// Load from the kernel a little-endian u32, consisting of 4 bytes (c_0, c_1, c_2, c_3)
%macro mload_kernel_u32_LE(segment)
// stack: offset
DUP1
%mload_kernel($segment)
// stack: c0 , offset
DUP2
%add_const(1)
%mload_kernel($segment)
%shl_const(8)
OR
// stack: c0 | (c1 << 8) , offset
DUP2
%add_const(2)
%mload_kernel($segment)
%shl_const(16)
OR
// stack: c0 | (c1 << 8) | (c2 << 16), offset
SWAP1
%add_const(3)
%mload_kernel($segment)
%shl_const(24)
OR
// stack: c0 | (c1 << 8) | (c2 << 16) | (c3 << 24)
%endmacro
// Load a u256 (big-endian) from the kernel.
%macro mload_kernel_u256(segment)
// stack: offset
@ -204,11 +229,13 @@
// stack: value
%endmacro
// Load a single byte from kernel general memory.
%macro mload_kernel_general
// stack: offset
%mload_kernel(@SEGMENT_KERNEL_GENERAL)
// stack: value
%macro mload_kernel_code(label)
// stack: shift
PUSH $label
ADD
// stack: label + shift
%mload_kernel_code
// stack: byte
%endmacro
// Load a big-endian u32, consisting of 4 bytes (c_3, c_2, c_1, c_0),
@ -219,6 +246,24 @@
// stack: value
%endmacro
%macro mload_kernel_code_u32(label)
// stack: u32_shift
%mul_const(4)
// stack: byte_shift
PUSH $label
ADD
// stack: offset
%mload_kernel_u32(@SEGMENT_CODE)
// stack: value
%endmacro
// Load a single byte from kernel general memory.
%macro mload_kernel_general
// stack: offset
%mload_kernel(@SEGMENT_KERNEL_GENERAL)
// stack: value
%endmacro
// Load a big-endian u32, consisting of 4 bytes (c_3, c_2, c_1, c_0),
// from kernel general memory.
%macro mload_kernel_general_u32
@ -227,6 +272,14 @@
// stack: value
%endmacro
// Load a little-endian u32, consisting of 4 bytes (c_3, c_2, c_1, c_0),
// from kernel general memory.
%macro mload_kernel_general_u32_LE
// stack: offset
%mload_kernel_u32_LE(@SEGMENT_KERNEL_GENERAL)
// stack: value
%endmacro
// Load a u256 (big-endian) from kernel code.
%macro mload_kernel_code_u256
// stack: offset
@ -248,13 +301,6 @@
// stack: (empty)
%endmacro
// Store a single byte to kernel general memory.
%macro mstore_kernel_general
// stack: offset, value
%mstore_kernel(@SEGMENT_KERNEL_GENERAL)
// stack: (empty)
%endmacro
// Store a big-endian u32, consisting of 4 bytes (c_3, c_2, c_1, c_0),
// to kernel code.
%macro mstore_kernel_code_u32
@ -262,6 +308,27 @@
%mstore_kernel_u32(@SEGMENT_CODE)
%endmacro
// Store a single byte to @SEGMENT_RLP_RAW.
%macro mstore_rlp
// stack: offset, value
%mstore_kernel(@SEGMENT_RLP_RAW)
// stack: (empty)
%endmacro
%macro mstore_kernel_general
// stack: offset, value
%mstore_kernel(@SEGMENT_KERNEL_GENERAL)
// stack:
%endmacro
%macro mstore_kernel_general(offset)
// stack: value
PUSH $offset
// stack: offset, value
%mstore_kernel_general
// stack:
%endmacro
// Store a big-endian u32, consisting of 4 bytes (c_3, c_2, c_1, c_0),
// to kernel general memory.
%macro mstore_kernel_general_u32
@ -269,9 +336,12 @@
%mstore_kernel_u32(@SEGMENT_KERNEL_GENERAL)
%endmacro
// Store a single byte to @SEGMENT_RLP_RAW.
%macro mstore_rlp
// stack: offset, value
%mstore_kernel(@SEGMENT_RLP_RAW)
// stack: (empty)
// set offset i to offset j in kernel general
%macro mupdate_kernel_general
// stack: j, i
%mload_kernel_general
// stack: x, i
SWAP1
%mstore_kernel_general
// stack:
%endmacro

View File

@ -0,0 +1,96 @@
/// Note that we unpack STATE: 5 to a, b, c, d, e
/// All additions are u32
///
/// def box(a, b, c, d, e, F, K):
///
/// box = get_box(sides, rounds, boxes)
/// a += F(b, c, d)
/// r = load(r)(box)
/// x = load_offset(r)
/// a += x + K
/// s = load(s)(box)
/// a = rol(s, a)
/// a += e
/// c = rol(10, c)
///
/// return e, a, b, c, d, F, K
global box:
// stack: a, b, c, d, e, F, K, boxes, rounds, sides, virt
PUSH pre_rol
DUP5
DUP5
DUP5
DUP10
// stack: F, b, c, d, pre_rol, a, b, c, d, e, F, K, boxes, rounds, sides, virt
JUMP
pre_rol:
// stack: F(b, c, d), a, b, c, d, e, F, K, boxes, rounds, sides, virt
ADD
// stack: a, b, c, d, e, F, K, boxes, rounds, sides, virt
%get_box
// stack: box, a, b, c, d, e, F, K, boxes, rounds, sides, virt
DUP12
DUP2
%mload_kernel_code(r_data)
ADD
// stack: virt + r, box, a, b, c, d, e, F, K, boxes, rounds, sides, virt
%mload_kernel_general_u32_LE
// stack: x, box, a, b, c, d, e, F, K, boxes, rounds, sides, virt
SWAP1
SWAP2
// stack: a, x, box, b, c, d, e, F, K, boxes, rounds, sides, virt
ADD
DUP8
ADD
%as_u32
// stack: a, box, b, c, d, e, F, K, boxes, rounds, sides, virt
PUSH mid_rol
SWAP2
// stack: box, a, mid_rol, b, c, d, e, F, K, boxes, rounds, sides, virt
%mload_kernel_code(s_data)
// stack: s, a, mid_rol, b, c, d, e, F, K, boxes, rounds, sides, virt
%jump(rol)
mid_rol:
// stack: a, b, c, d, e, F, K, boxes, rounds, sides, virt
DUP5
// stack: e, a, b, c, d, e, F, K, boxes, rounds, sides, virt
ADD
%as_u32
// stack: a, b, c, d, e, F, K, boxes, rounds, sides, virt
%stack (a, b, c) -> (10, c, post_rol, a, b)
// stack: 10, c, post_rol, a, b, d, e, F, K, boxes, rounds, sides, virt
%jump(rol)
post_rol:
// stack: c, a, b, d, e, F, K, boxes , rounds, sides, virt
%stack (c, a, b, d, e, F, K, boxes) -> (boxes, 1, a, b, c, d, F, K, e)
// stack: boxes, 1, a, b, c, d, F, K, e, rounds, sides, virt
SUB
SWAP7
// stack: e, a, b, c, d, F, K, boxes-1, rounds, sides, virt
%jump(round)
%macro get_round
// stack: sides, rounds
%mul_const(5)
PUSH 10
SUB
SUB
// stack: 10 - 5*sides - rounds
%endmacro
%macro get_box
// stack: ARGS: 7, boxes, rounds, sides
DUP10
%mul_const(80)
DUP10
%mul_const(16)
DUP10
// stack: boxes , 16*rounds , 80*sides, ARGS: 7, boxes, rounds, sides
PUSH 176
SUB
SUB
SUB
// stack: 176 - boxes - 16*rounds - 80*sides, ARGS: 7, boxes, rounds, sides
%endmacro

View File

@ -0,0 +1,160 @@
/// _block is stored in memory: its address virt stays on the stack
/// def compress(STATE: 5, _block):
///
/// STATEL = STATE
/// STATEL = loop(STATEL)
///
/// STATER = state
/// STATER = loop(STATER)
///
/// return mix(STATER, STATEL, STATE)
///
///
/// def mix(STATER, STATEL, STATE):
/// return
/// u32(s1 + l2 + r3),
/// u32(s2 + l3 + r4),
/// u32(s3 + l4 + r0),
/// u32(s4 + l0 + r1),
/// u32(s0 + l1 + r2)
///
/// where si, li, ri, oi, VR, RD respectively denote
/// STATE[i], STATEL[i], STATER[i], OUTPUT[i], virt, retdest
global compress:
// stack: STATE, virt, retdest
PUSH switch
DUP7
%stack () -> (0, 0, 16, 5, 1)
// stack: 0, 0, 16, 5, 1, virt, switch, STATE, virt, retdest
DUP12
DUP12
DUP12
DUP12
DUP12
// stack: STATE, 0, 0, 16, 5, 1, virt, switch, STATE, virt, retdest
%jump(loop)
switch:
// stack: STATEL, STATE, virt, retdest
PUSH mix
DUP12
%stack () -> (16, 5, 0)
// stack: 16, 5, 0, virt, mix, STATEL, STATE, virt, retdest
DUP15
DUP15
DUP15
DUP15
DUP15
// stack: STATE, 16, 5, 0, virt, mix, STATEL, STATE, virt, retdest
%stack (STATE: 5) -> (STATE, 0, 0)
// stack: STATE, 0, 0, 16, 5, 0, virt, mix, STATEL, STATE, virt, retdest
%jump(loop)
mix:
// stack: r0, r1, r2, r3, r4, l0, l1, l2, l3, l4, s0, s1, s2, s3, s4, VR, RD
SWAP10
// stack: s0, r1, r2, r3, r4, l0, l1, l2, l3, l4, r0, s1, s2, s3, s4, VR, RD
SWAP1
// stack: r1, s0, r2, r3, r4, l0, l1, l2, l3, l4, r0, s1, s2, s3, s4, VR, RD
SWAP6
// stack: l1, s0, r2, r3, r4, l0, r1, l2, l3, l4, r0, s1, s2, s3, s4, VR, RD
%add3_u32
// stack: o4, r3, r4, l0, r1, l2, l3, l4, r0, s1, s2, s3, s4, VR, RD
SWAP14
// stack: RD, r3, r4, l0, r1, l2, l3, l4, r0, s1, s2, s3, s4, VR, o4
SWAP11
// stack: s3, r3, r4, l0, r1, l2, l3, l4, r0, s1, s2, RD, s4, VR, o4
SWAP10
// stack: s2, r3, r4, l0, r1, l2, l3, l4, r0, s1, s3, RD, s4, VR, o4
SWAP1
// stack: r3, s2, r4, l0, r1, l2, l3, l4, r0, s1, s3, RD, s4, VR, o4
SWAP6
// stack: l3, s2, r4, l0, r1, l2, r3, l4, r0, s1, s3, RD, s4, VR, o4
%add3_u32
// stack: o1, l0, r1, l2, r3, l4, r0, s1, s3, RD, s4, VR, o4
SWAP9
// stack: RD, l0, r1, l2, r3, l4, r0, s1, s3, o1, s4, VR, o4
SWAP10
// stack: s4, l0, r1, l2, r3, l4, r0, s1, s3, o1, RD, VR, o4
%add3_u32
// stack: o3, l2, r3, l4, r0, s1, s3, o1, RD, VR, o4
SWAP9
// stack: VR, l2, r3, l4, r0, s1, s3, o1, RD, o3, o4
SWAP5
// stack: s1, l2, r3, l4, r0, VR, s3, o1, RD, o3, o4
%add3_u32
// stack: o0, l4, r0, VR, s3, o1, RD, o3, o4
SWAP4
// stack: s3, l4, r0, VR, o0, o1, RD, o3, o4
%add3_u32
// stack: o2, VR, o0, o1, RD, o3, o4
SWAP4
// stack: RD, VR, o0, o1, o2, o3, o4
SWAP1
// stack: VR, RD, o0, o1, o2, o3, o4
POP
// stack: RD, o0, o1, o2, o3, o4
JUMP
/// def loop(STATE: 5):
/// while rounds:
/// update_round_vars()
/// round(STATE: 5, F, K, rounds, sides)
///
/// def update_round_vars():
/// F = load(F)(sides, rounds)
/// K = load(K)(sides, rounds)
///
/// def round(STATE, rounds, sides):
/// while boxes:
/// box(STATE, F, K)
/// boxes -= 1
/// boxes = 16
/// rounds -= 1
loop:
// stack: STATE, F, K, 16, rounds, sides, virt, retdest
DUP9
// stack: round, STATE, F, K, 16, rounds, sides, virt, retdest
%jumpi(update_round_vars)
// stack: STATE, F, K, 16, 0, sides, virt, retdest
%stack (STATE: 5, F, K, boxes, rounds, sides, virt, retdest) -> (retdest, STATE)
// stack: retdest, STATE
JUMP
update_round_vars:
// stack: STATE, F , K , 16, rounds, sides, virt, retdest
DUP9
DUP11
%get_round
DUP1
// stack: rnd, rnd, STATE, F , K , 16, rounds, sides, virt, retdest
SWAP7
POP
%push_f
SWAP7
// stack: rnd, rnd, STATE, F', K , 16, rounds, sides, virt, retdest
SWAP8
POP
%mload_kernel_code_u32(k_data)
SWAP7
POP
// stack: STATE, F', K', 16, rounds, sides, virt, retdest
%jump(round)
global round:
// stack: STATE, F, K, boxes, rounds , sides, virt, retdest
DUP8
// stack: boxes, STATE, F, K, boxes, rounds , sides, virt, retdest
%jumpi(box)
// stack: STATE, F, K, 0, rounds , sides, virt, retdest
SWAP7
POP
PUSH 16
SWAP7
// stack: STATE, F, K, 16, rounds , sides, virt, retdest
PUSH 1
DUP10
SUB
SWAP9
POP
// stack: STATE, F, K, 16, rounds-1, sides, virt, retdest
%jump(loop)

View File

@ -0,0 +1,117 @@
global k_data:
// Left
BYTES 0x00, 0x00, 0x00, 0x00
BYTES 0x5A, 0x82, 0x79, 0x99
BYTES 0x6E, 0xD9, 0xEB, 0xA1
BYTES 0x8F, 0x1B, 0xBC, 0xDC
BYTES 0xA9, 0x53, 0xFD, 0x4E
// Right
BYTES 0x50, 0xA2, 0x8B, 0xE6
BYTES 0x5C, 0x4D, 0xD1, 0x24
BYTES 0x6D, 0x70, 0x3E, 0xF3
BYTES 0x7A, 0x6D, 0x76, 0xE9
BYTES 0x00, 0x00, 0x00, 0x00
global s_data:
// Left Round 0
BYTES 11, 14, 15, 12
BYTES 05, 08, 07, 09
BYTES 11, 13, 14, 15
BYTES 06, 07, 09, 08
// Left Round 1
BYTES 07, 06, 08, 13
BYTES 11, 09, 07, 15
BYTES 07, 12, 15, 09
BYTES 11, 07, 13, 12
// Left Round 2
BYTES 11, 13, 06, 07
BYTES 14, 09, 13, 15
BYTES 14, 08, 13, 06
BYTES 05, 12, 07, 05
// Left Round 3
BYTES 11, 12, 14, 15
BYTES 14, 15, 09, 08
BYTES 09, 14, 05, 06
BYTES 08, 06, 05, 12
// Left Round 4
BYTES 09, 15, 05, 11
BYTES 06, 08, 13, 12
BYTES 05, 12, 13, 14
BYTES 11, 08, 05, 06
// Right Round 0
BYTES 08, 09, 09, 11
BYTES 13, 15, 15, 05
BYTES 07, 07, 08, 11
BYTES 14, 14, 12, 06
// Right Round 1
BYTES 09, 13, 15, 07
BYTES 12, 08, 09, 11
BYTES 07, 07, 12, 07
BYTES 06, 15, 13, 11
// Right Round 2
BYTES 09, 07, 15, 11
BYTES 08, 06, 06, 14
BYTES 12, 13, 05, 14
BYTES 13, 13, 07, 05
// Right Round 3
BYTES 15, 05, 08, 11
BYTES 14, 14, 06, 14
BYTES 06, 09, 12, 09
BYTES 12, 05, 15, 08
// Right Round 4
BYTES 08, 05, 12, 09
BYTES 12, 05, 14, 06
BYTES 08, 13, 06, 05
BYTES 15, 13, 11, 11
global r_data:
// Left Round 0
BYTES 00, 04, 08, 12
BYTES 16, 20, 24, 28
BYTES 32, 36, 40, 44
BYTES 48, 52, 56, 60
// Left Round 1
BYTES 28, 16, 52, 04
BYTES 40, 24, 60, 12
BYTES 48, 00, 36, 20
BYTES 08, 56, 44, 32
// Left Round 2
BYTES 12, 40, 56, 16
BYTES 36, 60, 32, 04
BYTES 08, 28, 00, 24
BYTES 52, 44, 20, 48
// Left Round 3
BYTES 04, 36, 44, 40
BYTES 00, 32, 48, 16
BYTES 52, 12, 28, 60
BYTES 56, 20, 24, 08
// Left Round 4
BYTES 16, 00, 20, 36
BYTES 28, 48, 08, 40
BYTES 56, 04, 12, 32
BYTES 44, 24, 60, 52
// Right Round 0
BYTES 20, 56, 28, 00
BYTES 36, 08, 44, 16
BYTES 52, 24, 60, 32
BYTES 04, 40, 12, 48
// Right Round 1
BYTES 24, 44, 12, 28
BYTES 00, 52, 20, 40
BYTES 56, 60, 32, 48
BYTES 16, 36, 04, 08
// Right Round 2
BYTES 60, 20, 04, 12
BYTES 28, 56, 24, 36
BYTES 44, 32, 48, 08
BYTES 40, 00, 16, 52
// Right Round 3
BYTES 32, 24, 16, 04
BYTES 12, 44, 60, 00
BYTES 20, 48, 08, 52
BYTES 36, 28, 40, 56
// Right Round 4
BYTES 48, 60, 40, 16
BYTES 04, 20, 32, 28
BYTES 24, 08, 52, 56
BYTES 00, 12, 36, 44

View File

@ -0,0 +1,150 @@
/// def rol(n, x):
/// return (u32(x << n)) | (x >> (32 - n))
global rol:
// stack: n, x, retdest
SWAP1
DUP1
DUP3
// stack: n, x, x, n, retdest
PUSH 32
SUB
// stack: 32-n, x, x, n, retdest
SHR
// stack: x >> (32-n), x, n, retdest
SWAP2
// stack: n, x, x >> (32-n), retdest
SHL
// stack: x << n, x >> (32-n), retdest
%as_u32
// stack: u32(x << n), x >> (32-n), retdest
OR
// stack: u32(x << n) | (x >> (32-n)), retdest
SWAP1
JUMP
// def push_f(rnd):
// Fs = [F0, F1, F2, F3, F4, F4, F3, F2, F1, F0]
// acc = 0
// for i, F in enumerate(Fs):
// acc += (i==rnd)*F
// return acc, rnd
//
// %this_f(i,F) enacts
// acc += (i==rnd)*F
%macro push_f
// stack: rnd
PUSH 0
%this_f(0,F0)
%this_f(1,F1)
%this_f(2,F2)
%this_f(3,F3)
%this_f(4,F4)
%this_f(5,F4)
%this_f(6,F3)
%this_f(7,F2)
%this_f(8,F1)
%this_f(9,F0)
// stack: F, rnd
%endmacro
%macro this_f(i, F)
// stack: acc, rnd
DUP2
// stack: rnd , acc, rnd
%eq_const($i)
// stack: rnd==i , acc, rnd
%mul_const($F)
// stack: (rnd==i)*F , acc, rnd
ADD
// stack: (rnd==j)*F + acc, rnd
%endmacro
/// def F0(x, y, z):
/// return x ^ y ^ z
global F0:
// stack: x , y , z, retdest
XOR
// stack: x ^ y , z, retdest
XOR
// stack: x ^ y ^ z, retdest
SWAP1
JUMP
/// def F1(x, y, z):
/// return (x & y) | (u32(~x) & z)
global F1:
// stack: x, y, z, retdest
DUP1
// stack: x, x, y, z, retdest
SWAP2
// stack: y, x, x, z, retdest
AND
// stack: y & x, x, z, retdest
SWAP2
// stack: z, x, y & x , retdest
SWAP1
// stack: x, z, y & x , retdest
%not_u32
// stack: ~x, z, y & x , retdest
AND
// stack: ~x & z , y & x , retdest
OR
// stack: (~x & z) | (y & x), retdest
SWAP1
JUMP
/// def F2(x, y, z):
/// return (x | u32(~y)) ^ z
global F2:
// stack: x , y, z, retdest
SWAP1
// stack: y , x, z, retdest
%not_u32
// stack: ~y , x , z, retdest
OR
// stack: ~y | x , z, retdest
XOR
// stack: (~y | x) ^ z, retdest
SWAP1
JUMP
/// def F3(x, y, z):
/// return (x & z) | (u32(~z) & y)
global F3:
// stack: x, y , z , retdest
DUP3
// stack: z , x, y , z , retdest
AND
// stack: z & x, y , z , retdest
SWAP2
// stack: z, y, z & x , retdest
%not_u32
// stack: ~z , y, z & x , retdest
AND
// stack: ~z & y, z & x , retdest
OR
// stack: (~z & y) | (z & x), retdest
SWAP1
JUMP
/// def F4(x, y, z):
/// return x ^ (y | u32(~z))
global F4:
// stack: x, y, z, retdest
SWAP2
// stack: z, y, x, retdest
%not_u32
// stack: ~z, y, x, retdest
OR
// stack: ~z | y, x, retdest
XOR
// stack: (~z | y) ^ x, retdest
SWAP1
JUMP

View File

@ -0,0 +1,107 @@
/// Variables beginning with _ are in memory
///
/// def ripemd160(_input):
/// STATE, count, _buffer = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0], 0, [0]*64
/// STATE, count, _buffer = ripemd_update(STATE, count, _buffer, len(input) , bytes = _input )
/// STATE, count, _buffer = ripemd_update(STATE, count, _buffer, padlength(len(input)), bytes = [0x80]+[0]*63)
/// STATE, count, _buffer = ripemd_update(STATE, count, _buffer, 8, bytes = size(len(_input)))
/// return process(STATE)
///
/// ripemd is called on a stack with ADDR and length
/// ripemd_stack is called on a stack with length, followed by the input bytes
///
/// ripemd_update receives and return the stack in the form:
/// stack: STATE, count, length, virt
/// where virt is the virtual address of the bytes argument
global ripemd_stack:
// stack: length, INPUT
%stack (length) -> (64, length, 0x80, 63, length, length)
// stack: 64, length, 0x80, 63, length, length, INPUT
%jump(ripemd_storage) // stores the following into memory
// init _buffer at virt 0 [consumes 64]
// store _size at virt 64 [consumes length]
// store _padding at virt 72 [consumes 0x80, 63]
// store _input at virt 136 [consumes length]
global ripemd:
// stack: ADDR, length
%stack (ADDR: 3, length) -> (64, length, 0x80, 63, length, ADDR, length)
// stack: 64, length, 0x80, 63, length, ADDR, length
%jump(ripemd_storage) // stores the following into memory
// init _buffer at virt 0 [consumes 64]
// store _size at virt 64 [consumes length]
// store _padding at virt 72 [consumes 0x80, 63]
// store _input at virt 136 [consumes ADDR, length]
global ripemd_init:
// stack: length
%stack (length) -> ( 0, length, 136, ripemd_1, ripemd_2, process)
// stack: count = 0, length, virt = 136, ripemd_1, ripemd_2, process
%stack () -> (0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0)
// stack: 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0, count, length, virt, LABELS
%jump(ripemd_update)
ripemd_1:
// stack: STATE, count, length , virt , LABELS
DUP7
// stack: length, STATE, count, length , virt , LABELS
%padlength
// stack: padlength, STATE, count, length , virt , LABELS
SWAP7
POP
// stack: STATE, count, length = padlength, virt , LABELS
%stack (STATE: 5, count, length, virt) -> (STATE, count, length, 72)
// STATE, count, length , virt = 72, LABELS
%jump(ripemd_update)
ripemd_2:
// stack: STATE, count, length , virt , LABELS
%stack (STATE: 5, count, length, virt) -> (STATE, count, 8, 64)
// stack: STATE, count, length = 8, virt = 64, LABELS
%jump(ripemd_update)
global process:
// stack: a , b, c, d, e, count, length, virt
%reverse_bytes_u32
%shl_const(128)
// stack: a', b, c, d, e, VARS
SWAP1
%reverse_bytes_u32
%shl_const(96)
OR
// stack: b' a', c, d, e, VARS
SWAP1
%reverse_bytes_u32
%shl_const(64)
OR
// stack: c' b' a', d, e, VARS
SWAP1
%reverse_bytes_u32
%shl_const(32)
OR
// stack: d' c' b' a', e, VARS
SWAP1
%reverse_bytes_u32
OR
// stack: e' d' c' b' a', VARS
%stack (result, VARS: 3, retdest) -> (retdest, result)
// stack: 0xdeadbeef, result
JUMP
/// def padlength(length):
/// t = length % 64
/// return 56 + 64*(t > 47) - t
%macro padlength
// stack: count
%mod_const(64)
// stack: t = count % 64
PUSH 47
DUP2
// stack: t , 47 , t
GT
// stack: t > 47 , t
%mul_const(64)
%add_const(56)
// stack: 56 + 64*(t > 47), t
SUB
%endmacro

View File

@ -0,0 +1,137 @@
global ripemd_storage: // starts by initializing buffer
// stack: i [init: 64]
%store_zeros(64, ripemd_storage)
// stack:
%jump(store_size)
store_size:
// stack: length
%shl_const(3)
// stack: abcdefgh
%extract_and_store_byte(64)
// stack: abcdefg
%extract_and_store_byte(65)
// stack: abcdef
%extract_and_store_byte(66)
// stack: abcde
%extract_and_store_byte(67)
// stack: abcd
%extract_and_store_byte(68)
// stack: abc
%extract_and_store_byte(69)
// stack: ab
%extract_and_store_byte(70)
// stack: a
%mstore_kernel_general(71)
// stack: 0x80 // padding has 0x80 in first position and zeros elsewhere
%mstore_kernel_general(72) // store first padding term here so as to avoid extra label
%jump(store_padding)
store_padding:
// stack: i [init 63], length
%store_zeros(136, store_padding)
// stack: length
DUP1
%jumpi(store_input_stack)
POP
%jump(ripemd_init)
store_input_stack:
// stack: rem, length, REM_INP
%stack (rem, length, head) -> (length, rem, 136, head, rem, length)
SUB
ADD
// stack: offset, byte, rem, length, REM_INP
%mstore_kernel_general
// stack: rem, length, REM_INP
%sub_const(1)
DUP1
// stack: rem - 1, rem - 1, length, REM_INP
%jumpi(store_input_stack)
// stack: 0, length
POP
%jump(ripemd_init)
store_input:
// stack: rem , ADDR , length
DUP4
DUP4
DUP4
MLOAD_GENERAL
// stack: byte, rem , ADDR , length
DUP2
DUP7
SUB
%add_const(136)
// stack: offset, byte, rem , ADDR , length
%mstore_kernel_general
// stack: rem , ADDR , length
%sub_const(1)
// stack: rem-1, ADDR , length
SWAP3
%add_const(1)
SWAP3
// stack: rem-1, ADDR+1, length
DUP1
%jumpi(store_input)
// stack: 0 , ADDR , length
%pop4
// stack: length
%jump(ripemd_init)
/// def buffer_update(get, set, times):
/// for i in range(times):
/// buffer[set+i] = bytestring[get+i]
global buffer_update:
// stack: get , set , times , retdest
DUP2
DUP2
// stack: get, set, get , set , times , retdest
%mupdate_kernel_general
// stack: get , set , times , retdest
%add_const(1)
SWAP1
%add_const(1)
SWAP1
SWAP2
%sub_const(1)
SWAP2
// stack: get+1, set+1, times-1, retdest
DUP3
%jumpi(buffer_update)
// stack: get , set , 0 , retdest
%pop3
JUMP
%macro store_zeros(N, label)
// stack: i
%stack (i) -> ($N, i, 0, i)
SUB
// stack: offset = N-i, 0, i
%mstore_kernel_general
// stack: i
%sub_const(1)
DUP1
// stack: i-1, i-1
%jumpi($label)
// stack: 0
POP
%endmacro
%macro extract_and_store_byte(offset)
// stack: xsy
PUSH 0x100
DUP2
MOD
// stack: y, xsy
%stack (y, xsy) -> (xsy, y, 0x100, y)
// stack: xsy, y, 0x100, y
SUB
DIV
SWAP1
// stack: y, xs
%mstore_kernel_general($offset)
// stack: xs
%endmacro

View File

@ -0,0 +1,108 @@
/// ripemd_update will receive and return the stack in the form:
/// stack: STATE, count, length, virt
///
/// def ripemd_update(state, count, buffer, length, bytestring):
/// have = (count // 8) % 64
/// need = 64 - have
/// shift = 0
/// P = length >= need and have
/// Q = length >= need
/// if P:
/// update_1()
/// if Q:
/// update_2()
/// R = length > shift
/// if R:
/// buffer_update(virt + shift, have, length - shift)
///
/// return state, count + 8*length, buffer
global ripemd_update:
// stack: STATE, count, length, virt, retdest
%stack (STATE: 5, count, length, virt) -> (count, 8, 64, STATE, count, length, virt)
DIV
MOD
// stack: have, STATE, count, length, virt, retdest
DUP1
PUSH 64
SUB
PUSH 0
// stack: shift, need, have, STATE, count, length, virt, retdest
%stack (shift, need, have, STATE: 5, count, length) -> (length, need, STATE, shift, need, have, count, length)
// stack: length, need, STATE, shift, need, have, count, length, virt, retdest
LT
ISZERO
// stack: Q, STATE, shift, need, have, count, length, virt, retdest
%stack (Q, STATE: 5, shift, need, have) -> (have, Q, Q, STATE, shift, need, have)
%gt_const(0)
AND
// stack: P, Q, STATE, shift, need, have, count, length, virt, retdest
%jumpi(update_1)
// stack: Q, STATE, shift, need, have, count, length, virt, retdest
%jumpi(update_2)
final_update:
// stack: STATE, shift, need, have, count, length, virt, retdest
%stack (STATE: 5, shift, need, have, count, length) -> (length, shift, return_step, STATE, shift, need, have, count, length)
SUB
// stack: ARGS: 2, STATE, shift, need, have, count, length, virt, retdest
%stack (ARGS: 2, STATE: 5, shift, need, have, count, length, virt) -> (shift, virt, have, ARGS, STATE, shift, need, have, count, length, virt)
ADD
// stack: ARGS: 4, STATE, shift, need, have, count, length, virt, retdest
%stack (ARGS: 4, STATE: 5, shift, need, have, count, length) -> (length, shift, ARGS, STATE, shift, need, have, count, length)
GT
// stack: R, ARGS: 4, STATE, shift, need, have, count, length, virt, retdest
%jumpi(buffer_update)
// stack: ARGS: 4, STATE, shift, need, have, count, length, virt, retdest
%pop3
JUMP
return_step:
// stack: STATE, shift, need, have, count, length, virt, retdest
SWAP8
DUP10
%mul_const(8)
ADD
SWAP8
// stack: STATE, shift, need, have, count, length, virt, retdest
%stack (STATE: 5, shift, need, have, count, length, virt, retdest) -> (retdest, STATE, count, length, virt)
JUMP
/// def update_1():
/// buffer_update(virt, have, need)
/// shift = need
/// have = 0
/// state = compress(state, buffer)
update_1:
// stack: Q, STATE, shift, need, have, count, length, virt, retdest
%stack (Q, STATE: 5, shift, need, have, count, length, virt) -> (virt, have, need, update_1a, STATE, shift, need, have, count, length, virt)
%jump(buffer_update)
update_1a:
// stack: STATE, shift, need, have, count, length, virt, retdest
%stack (STATE: 5, shift, need, have) -> (STATE, 0, update_2, need, need, 0)
// stack: STATE, 0, update_2, shift = need, need, have = 0, count, length, virt, retdest
%jump(compress)
/// def update_2():
/// while length >= shift + 64:
/// shift += 64
/// state = compress(state, bytestring[shift-64:])
update_2:
// stack: STATE, shift, need, have, count, length, virt, retdest
%stack (STATE: 5, shift, need, have, count, length) -> (64, shift, length, STATE, shift, need, have, count, length)
ADD
GT
// stack: cond, STATE, shift, need, have, count, length, virt, retdest
%jumpi(final_update)
SWAP5
%add_const(64)
SWAP5
%stack (STATE: 5, shift) -> (shift, 64, STATE, shift)
DUP13
ADD
SUB
// stack: offset, STATE, shift, need, have, count, length, virt, retdest
%stack (offset, STATE: 5) -> (STATE, offset, update_2)
// stack: STATE, offset, update_2, shift, need, have, count, length, virt, retdest
%jump(compress)

View File

@ -230,6 +230,36 @@
// stack: max
%endmacro
%macro as_u32
%and_const(0xffffffff)
%endmacro
%macro not_u32
// stack: x
PUSH 0xffffffff
// stack: 0xffffffff, x
SUB
// stack: 0xffffffff - x
%endmacro
// u32 addition (discarding 2^32 bit)
%macro add_u32
// stack: x, y
ADD
// stack: x + y
%as_u32
// stack: (x + y) & u32::MAX
%endmacro
%macro add3_u32
// stack: x , y , z
ADD
// stack: x + y , z
ADD
// stack: x + y + z
%as_u32
%endmacro
%macro increment
%add_const(1)
%endmacro
@ -247,15 +277,30 @@
ISZERO
%endmacro
%macro as_u32
%and_const(0xFFFFFFFF)
%endmacro
// u32 addition (discarding 2^32 bit)
%macro add_u32
// stack: x, y
ADD
// stack: x + y
%as_u32
// stack: (x + y) & u32::MAX
// given u32 bytestring abcd return dcba
%macro reverse_bytes_u32
// stack: abcd
DUP1
PUSH 28
BYTE
// stack: a, abcd
DUP2
PUSH 29
BYTE
%shl_const(8)
// stack: b0, a, abcd
DUP3
PUSH 30
BYTE
%shl_const(16)
// stack: c00, b0, a, abcd
SWAP3
PUSH 31
BYTE
%shl_const(24)
// stack: d000, b0, a, c00
OR
OR
OR
// stack: dcba
%endmacro

View File

@ -3,7 +3,8 @@ use std::str::FromStr;
use anyhow::Result;
use ethereum_types::U256;
use rand::{thread_rng, Rng};
use sha2::{Digest, Sha256};
use ripemd::{Digest, Ripemd160};
use sha2::Sha256;
use crate::cpu::kernel::aggregator::combined_kernel;
use crate::cpu::kernel::interpreter::run_with_kernel;
@ -15,6 +16,13 @@ fn sha2(input: Vec<u8>) -> U256 {
U256::from(&hasher.finalize()[..])
}
/// Standard RipeMD implementation.
fn ripemd(input: Vec<u8>) -> U256 {
let mut hasher = Ripemd160::new();
hasher.update(input);
U256::from(&hasher.finalize()[..])
}
fn test_hash(hash_fn_label: &str, standard_implementation: &dyn Fn(Vec<u8>) -> U256) -> Result<()> {
let kernel = combined_kernel();
let mut rng = thread_rng();
@ -48,3 +56,8 @@ fn test_hash(hash_fn_label: &str, standard_implementation: &dyn Fn(Vec<u8>) -> U
fn test_sha2() -> Result<()> {
test_hash("sha2", &sha2)
}
#[test]
fn test_ripemd() -> Result<()> {
test_hash("ripemd_stack", &ripemd)
}

View File

@ -5,6 +5,7 @@ mod exp;
mod hash;
mod mpt;
mod packing;
mod ripemd;
mod rlp;
mod transaction_parsing;

View File

@ -0,0 +1,57 @@
use anyhow::Result;
use ethereum_types::U256;
use itertools::Itertools;
use crate::cpu::kernel::aggregator::combined_kernel;
use crate::cpu::kernel::interpreter::run_with_kernel;
fn make_input(word: &str) -> Vec<u32> {
let mut input: Vec<u32> = vec![word.len().try_into().unwrap()];
input.append(&mut word.as_bytes().iter().map(|&x| x as u32).collect_vec());
input.push(u32::from_str_radix("deadbeef", 16).unwrap());
input
}
#[test]
fn test_ripemd_reference() -> Result<()> {
let reference = vec![
("", "0x9c1185a5c5e9fc54612808977ee8f548b2258d31"),
("a", "0x0bdc9d2d256b3ee9daae347be6f4dc835a467ffe"),
("abc", "0x8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"),
(
"message digest",
"0x5d0689ef49d2fae572b881b123a85ffa21595f36",
),
(
"abcdefghijklmnopqrstuvwxyz",
"0xf71c27109c692c1b56bbdceb5b9d2865b3708dbc",
),
(
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
"0x12a053384a9c0c88e405a06c27dcf49ada62eb2b",
),
(
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
"0xb0e20b6e3116640286ed3a87a5713079b21f5189",
),
(
"12345678901234567890123456789012345678901234567890123456789012345678901234567890",
"0x9b752e45573d4b39f4dbd3323cab82bf63326bfb",
),
];
for (x, y) in reference {
let input: Vec<u32> = make_input(x);
let expected = U256::from(y);
let kernel = combined_kernel();
let initial_offset = kernel.global_labels["ripemd_stack"];
let initial_stack: Vec<U256> = input.iter().map(|&x| U256::from(x as u32)).rev().collect();
let final_stack: Vec<U256> = run_with_kernel(&kernel, initial_offset, initial_stack)?
.stack()
.to_vec();
let actual = final_stack[0];
assert_eq!(actual, expected);
}
Ok(())
}