From 055d15efb585c279c2b94c7803decffd0ca2651e Mon Sep 17 00:00:00 2001 From: hh Date: Mon, 25 Nov 2024 18:17:29 +0800 Subject: [PATCH] optimze u30xu30 --- .asm/asm.json | 4 +- src/contracts/opmul.ts | 14 +- src/contracts/umath.ts | 306 +++++++++++++---------------------- tests/contracts/testOpMul.ts | 16 +- tests/specs/opmul.test.ts | 87 ++++++---- 5 files changed, 202 insertions(+), 225 deletions(-) diff --git a/.asm/asm.json b/.asm/asm.json index fdd1649..96866c8 100644 --- a/.asm/asm.json +++ b/.asm/asm.json @@ -1,5 +1,7 @@ { "OpMul": { - "mul": "OP_DUP OP_0 OP_GREATERTHANOREQUAL OP_VERIFY OP_1 OP_PICK OP_0 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_DUP 00000040 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 00000040 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 00000020 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 00000020 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 00000010 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 00000010 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 00000008 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 00000008 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 00000004 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 00000004 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 00000002 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 00000002 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 00000001 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 00000001 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 00008000 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 00008000 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 000040 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 000040 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 000020 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 000020 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 000010 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 000010 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 000008 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 000008 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 000004 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 000004 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 000002 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 000002 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 000001 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 000001 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 008000 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 008000 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 0040 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 0040 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 0020 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 0020 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 0010 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 0010 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 0008 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 0008 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 0004 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 0004 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 0002 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 0002 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 0001 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 0001 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 8000 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 8000 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 40 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 40 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 20 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 20 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP OP_16 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE OP_16 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP OP_8 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE OP_8 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP OP_4 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE OP_4 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP OP_2 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE OP_2 OP_SUB OP_1 OP_SWAP OP_ENDIF 1f OP_PICK OP_SWAP OP_IF OP_DUP OP_ELSE OP_0 OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SIZE OP_5 OP_EQUAL OP_NOT OP_VERIFY OP_NIP" + "mul": "OP_DUP OP_0 OP_GREATERTHANOREQUAL OP_VERIFY OP_1 OP_PICK OP_0 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_DUP 00000040 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 00000040 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 00000020 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 00000020 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 00000010 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 00000010 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 00000008 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 00000008 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 00000004 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 00000004 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 00000002 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 00000002 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 00000001 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 00000001 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 00008000 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 00008000 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 000040 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 000040 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 000020 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 000020 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 000010 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 000010 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 000008 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 000008 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 000004 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 000004 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 000002 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 000002 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 000001 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 000001 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 008000 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 008000 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 0040 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 0040 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 0020 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 0020 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 0010 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 0010 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 0008 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 0008 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 0004 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 0004 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 0002 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 0002 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 0001 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 0001 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 8000 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 8000 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 40 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 40 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 20 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 20 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP OP_16 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE OP_16 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP OP_8 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE OP_8 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP OP_4 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE OP_4 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP OP_2 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE OP_2 OP_SUB OP_1 OP_SWAP OP_ENDIF 1f OP_PICK OP_SWAP OP_IF OP_DUP OP_ELSE OP_0 OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_SIZE OP_5 OP_EQUAL OP_IF OP_DROP OP_0 OP_ENDIF OP_ROT OP_IF OP_DUP OP_VERIFY OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SIZE OP_5 OP_EQUAL OP_NOT OP_VERIFY OP_NIP", + "u15Mul": "OP_DUP ff7f OP_LESSTHANOREQUAL OP_VERIFY OP_DUP OP_0 OP_GREATERTHANOREQUAL OP_VERIFY OP_1 OP_PICK ff7f OP_LESSTHANOREQUAL OP_VERIFY OP_1 OP_PICK OP_0 OP_GREATERTHANOREQUAL OP_VERIFY OP_DUP 0040 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 0040 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 0020 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 0020 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 0010 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 0010 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 0008 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 0008 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 0004 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 0004 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 0002 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 0002 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 0001 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 0001 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 8000 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 8000 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 40 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 40 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 20 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 20 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP OP_16 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE OP_16 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP OP_8 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE OP_8 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP OP_4 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE OP_4 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP OP_2 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE OP_2 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_15 OP_PICK OP_SWAP OP_IF OP_DUP OP_ELSE OP_0 OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_NIP", + "sliceU30": "OP_DUP ffffff3f OP_LESSTHANOREQUAL OP_VERIFY OP_DUP OP_0 OP_GREATERTHANOREQUAL OP_VERIFY OP_DUP 00000020 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 00000020 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 00000010 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 00000010 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 00000008 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 00000008 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 00000004 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 00000004 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 00000002 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 00000002 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 00000001 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 00000001 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 00008000 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 00008000 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 000040 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 000040 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 000020 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 000020 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 000010 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 000010 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 000008 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 000008 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 000004 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 000004 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 000002 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 000002 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 000001 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 000001 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_DUP 008000 OP_LESSTHAN OP_IF OP_0 OP_SWAP OP_ELSE 008000 OP_SUB OP_1 OP_SWAP OP_ENDIF OP_TOALTSTACK OP_1 OP_SWAP OP_IF OP_DUP OP_ELSE OP_0 OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_SWAP OP_DUP OP_ADD OP_ROT OP_IF OP_DUP OP_ROT OP_ADD OP_ELSE OP_SWAP OP_ENDIF OP_NIP OP_FROMALTSTACK" } } diff --git a/src/contracts/opmul.ts b/src/contracts/opmul.ts index ebd42ac..1f93811 100644 --- a/src/contracts/opmul.ts +++ b/src/contracts/opmul.ts @@ -1,4 +1,4 @@ -import { method, SmartContractLib } from 'scrypt-ts' +import { FixedArray, method, SmartContractLib } from 'scrypt-ts' export class OpMul extends SmartContractLib { constructor() { @@ -9,4 +9,16 @@ export class OpMul extends SmartContractLib { static mul(a: bigint, b: bigint): bigint { return a * b } + + @method() + static u15Mul(a: bigint, b: bigint): bigint { + return a * b + } + + @method() + static sliceU30(a: bigint): FixedArray { + const hi = a / 32768n + const lo = a % 32768n + return [hi, lo] + } } diff --git a/src/contracts/umath.ts b/src/contracts/umath.ts index d07e972..c5a18f1 100644 --- a/src/contracts/umath.ts +++ b/src/contracts/umath.ts @@ -1,4 +1,5 @@ import { FixedArray, SmartContractLib, assert, method, prop } from 'scrypt-ts' +import { OpMul } from './opmul' export type U15 = bigint @@ -17,6 +18,16 @@ export type U31 = { lo: U30 } +export type U45 = { + hi: U15 + lo: U30 +} + +export type U46 = { + hi: boolean + lo: U45 +} + export type U60 = { hi: U30 lo: U30 @@ -36,54 +47,61 @@ export class UMath extends SmartContractLib { @prop() static readonly LIM_U30: bigint = 1073741824n // 2^30 - @prop() - static readonly NULL_U16: U16 = { - hi: false, - lo: 0n, + @method() + static null_U16(): U16 { + return { + hi: false, + lo: 0n, + } } - @prop() - static readonly NULL_U30: U30 = { - hi: 0n, - lo: 0n, + @method() + static null_U30(): U30 { + return { + hi: 0n, + lo: 0n, + } } - @prop() - static readonly NULL_U31: U31 = { - hi: false, - lo: UMath.NULL_U30, + @method() + static null_U31(): U31 { + return { + hi: false, + lo: UMath.null_U30(), + } } - @prop() - static readonly NULL_U60: U60 = { - hi: UMath.NULL_U30, - lo: UMath.NULL_U30, + @method() + static null_U45(): U45 { + return { + hi: 0n, + lo: UMath.null_U30(), + } } - @prop() - static readonly NULL_U61: U61 = { - hi: false, - lo: UMath.NULL_U60, + @method() + static null_U46(): U46 { + return { + hi: false, + lo: UMath.null_U45(), + } } - @prop() - static readonly NULL_U15_BITS: U15Bits = [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - ] + @method() + static null_U60(): U60 { + return { + hi: UMath.null_U30(), + lo: UMath.null_U30(), + } + } + + @method() + static null_U61(): U61 { + return { + hi: false, + lo: UMath.null_U60(), + } + } /** * Checks limb value is within specified bounds [0, 2^15). @@ -100,14 +118,28 @@ export class UMath extends SmartContractLib { return UMath.checkU15(a.hi) && UMath.checkU15(a.lo) } + @method() + static checkU45(a: U45): boolean { + return UMath.checkU15(a.hi) && UMath.checkU30(a.lo) + } + @method() static checkU60(a: U60): boolean { return UMath.checkU30(a.hi) && UMath.checkU30(a.lo) } + @method() + static toU30(a: bigint): U30 { + const res = OpMul.sliceU30(a) + return { + hi: res[0], + lo: res[1], + } + } + @method() static addU15Carry(a: U15, b: U15): U16 { - const res = UMath.NULL_U16 + const res = UMath.null_U16() const sum = a + b if (sum >= UMath.LIM_U15) { @@ -122,7 +154,7 @@ export class UMath extends SmartContractLib { @method() static addU30Carry(a: U30, b: U30): U31 { - const res = UMath.NULL_U31 + const res = UMath.null_U31() const sum0 = a.lo + b.lo let carry0 = 0n @@ -146,7 +178,7 @@ export class UMath extends SmartContractLib { @method() static subU15Borrow(a: U15, b: U15): U30 { - const res = UMath.NULL_U30 + const res = UMath.null_U30() const diff = a - b if (a >= b) { @@ -161,7 +193,7 @@ export class UMath extends SmartContractLib { @method() static subU30Borrow(a: U30, b: U30): U60 { - const res = UMath.NULL_U60 + const res = UMath.null_U60() const diff0 = a.lo - b.lo let borrow0 = 0n @@ -188,7 +220,7 @@ export class UMath extends SmartContractLib { @method() static addU60Carry(a: U60, b: U60): U61 { - const res = UMath.NULL_U61 + const res = UMath.null_U61() const sum0 = a.lo.lo + b.lo.lo let carry0 = 0n @@ -230,7 +262,7 @@ export class UMath extends SmartContractLib { @method() static subU60Borrow(a: U60, b: U60): U61 { - const res = UMath.NULL_U61 + const res = UMath.null_U61() const diff0 = a.lo.lo - b.lo.lo let borrow0 = 0n @@ -275,7 +307,7 @@ export class UMath extends SmartContractLib { @method() static addU60(a: U60, b: U60): U60 { - const res = UMath.NULL_U60 + const res = UMath.null_U60() const sum0 = a.lo.lo + b.lo.lo let carry0 = 0n @@ -314,7 +346,7 @@ export class UMath extends SmartContractLib { @method() static subU60(a: U60, b: U60): U60 { - const res = UMath.NULL_U60 + const res = UMath.null_U60() const diff0 = a.lo.lo - b.lo.lo let borrow0 = 0n @@ -361,6 +393,21 @@ export class UMath extends SmartContractLib { return a.hi == b.hi && b.lo == b.lo } + @method() + static eqU31(a: U31, b: U31): boolean { + return a.hi == b.hi && UMath.eqU30(a.lo, b.lo) + } + + @method() + static eqU45(a: U45, b: U45): boolean { + return a.hi == b.hi && UMath.eqU30(a.lo, b.lo) + } + + @method() + static eqU6(a: U46, b: U46): boolean { + return a.hi == b.hi && UMath.eqU45(a.lo, b.lo) + } + @method() static eqU60(a: U60, b: U60): boolean { return UMath.eqU30(a.hi, b.hi) && UMath.eqU30(a.lo, b.lo) @@ -447,153 +494,10 @@ export class UMath extends SmartContractLib { return res } - @method() - static num2BitsU15(a: U15): U15Bits { - const res = UMath.NULL_U15_BITS - if (a >= 16384n) { - a -= 16384n - res[0] = true - } - if (a >= 8192n) { - a -= 8192n - res[1] = true - } - if (a >= 4096n) { - a -= 4096n - res[2] = true - } - if (a >= 2048n) { - a -= 2048n - res[3] = true - } - if (a >= 1024n) { - a -= 1024n - res[4] = true - } - if (a >= 512n) { - a -= 512n - res[5] = true - } - if (a >= 256n) { - a -= 256n - res[6] = true - } - if (a >= 128n) { - a -= 128n - res[7] = true - } - if (a >= 64n) { - a -= 64n - res[8] = true - } - if (a >= 32n) { - a -= 32n - res[9] = true - } - if (a >= 16n) { - a -= 16n - res[10] = true - } - if (a >= 8n) { - a -= 8n - res[11] = true - } - if (a >= 4n) { - a -= 4n - res[12] = true - } - if (a >= 2n) { - a -= 2n - res[13] = true - } - if (a >= 1n) { - res[14] = true - } - - return res - } - @method() static mulU15(a: U15, b: U15): U30 { - // Split b into a bit array. - const bBits = UMath.num2BitsU15(b) - - // Perform multiplication. Res up to 30 bits long. - let res = 0n - for (let i = 0; i < 15; i++) { - if (bBits[14 - i]) { - res += a - } - a += a - } - - // Split res to two 15 bit limbs. - let x = 0n - if (res >= 536870912n) { - x += 16384n - res -= 536870912n - } - if (res >= 268435456n) { - x += 8192n - res -= 268435456n - } - if (res >= 134217728n) { - x += 4096n - res -= 134217728n - } - if (res >= 67108864n) { - x += 2048n - res -= 67108864n - } - if (res >= 33554432n) { - x += 1024n - res -= 33554432n - } - if (res >= 16777216n) { - x += 512n - res -= 16777216n - } - if (res >= 8388608n) { - x += 256n - res -= 8388608n - } - if (res >= 4194304n) { - x += 128n - res -= 4194304n - } - if (res >= 2097152n) { - x += 64n - res -= 2097152n - } - if (res >= 1048576n) { - x += 32n - res -= 1048576n - } - if (res >= 524288n) { - x += 16n - res -= 524288n - } - if (res >= 262144n) { - x += 8n - res -= 262144n - } - if (res >= 131072n) { - x += 4n - res -= 131072n - } - if (res >= 65536n) { - x += 2n - res -= 65536n - } - if (res >= 32768n) { - x += 1n - res -= 32768n - } - - return { - hi: x, - lo: res, - } + const res = OpMul.u15Mul(a, b) + return UMath.toU30(res) } @method() @@ -626,4 +530,24 @@ export class UMath extends SmartContractLib { return { hi: hi30bit, lo: lo30bit } } + + @method() + static mulU45(a: U45, b: U15): U60 { + const bU30: U30 = { + hi: 0n, + lo: b, + } + + const lobit = UMath.mulU30(a.lo, bU30) + + const hibit: U60 = { + hi: UMath.mulU15(a.hi, b), + lo: { + hi: 0n, + lo: 0n, + }, + } + + return UMath.addU60(hibit, lobit) + } } diff --git a/tests/contracts/testOpMul.ts b/tests/contracts/testOpMul.ts index c6ab26c..e95012e 100644 --- a/tests/contracts/testOpMul.ts +++ b/tests/contracts/testOpMul.ts @@ -1,23 +1,29 @@ -import { method, assert, SmartContract } from 'scrypt-ts' -import { OpMul, UMath, U30, U60, U15 } from '../opmul' +import { method, assert, SmartContract, equals } from 'scrypt-ts' +import { OpMul, UMath, U30, U60, U15, U45 } from '../opmul' export class TestOpMul extends SmartContract { @method() public unlock(a: bigint, b: bigint, c: bigint) { const c_ = OpMul.mul(a, b) assert(c_ == c, 'result not equal a*b') - assert(c_ <= 2147483647, 'result overflow') + assert(c_ <= 2147483647n, 'result overflow') } @method() public unlockU15(a: U15, b: U15, c: U30) { const c_ = UMath.mulU15(a, b) - assert(c_ == c, 'result not equal a*b') + assert(equals(c_, c), 'result not equal a*b') } @method() public unlockU30(a: U30, b: U30, c: U60) { const c_ = UMath.mulU30(a, b) - assert(c_ == c, 'result not equal a*b') + assert(equals(c_, c), 'result not equal a*b') + } + + @method() + public unlockU45(a: U45, b: U15, c: U60) { + const c_ = UMath.mulU45(a, b) + assert(equals(c_, c), 'result not equal a*b') } } diff --git a/tests/specs/opmul.test.ts b/tests/specs/opmul.test.ts index 77fbf60..cf4c647 100644 --- a/tests/specs/opmul.test.ts +++ b/tests/specs/opmul.test.ts @@ -13,7 +13,7 @@ import { unlockTaprootContractInput, } from '../utils/utils' import { MethodCallOptions } from 'scrypt-ts' -import { UMath, U15, U30, U60 } from '../opmul' +import { UMath, U15, U30, U60, U45 } from '../opmul' use(chaiAsPromised) @@ -30,7 +30,7 @@ describe('Test SmartContract `Opmul`', () => { async function unlock( a: bigint, b: bigint, - method: 'unlock' | 'unlockU15' | 'unlockU30' = 'unlock' + method: 'unlock' | 'unlockU15' | 'unlockU30' | 'unlockU45' = 'unlock' ) { const taprootContract = createTaprootContract(instance) @@ -50,38 +50,64 @@ describe('Test SmartContract `Opmul`', () => { const c = a * b - const args: Array = [] + const args: Array = [] - if (method === 'unlockU30') { + if (method === 'unlockU45') { + const aHi = a / UMath.LIM_U30 + const aLow = a % UMath.LIM_U30 + args.push({ + hi: aHi, + lo: { + lo: aLow % UMath.LIM_U15, + hi: aLow / UMath.LIM_U15, + }, + }) + + args.push(b) + + const cHi = c / UMath.LIM_U30 + const clo = c % UMath.LIM_U30 + + args.push({ + hi: { + hi: cHi / UMath.LIM_U15, + lo: cHi % UMath.LIM_U15, + }, + lo: { + hi: clo / UMath.LIM_U15, + lo: clo % UMath.LIM_U15, + }, + }) + } else if (method === 'unlockU30') { args.push({ - lo: a % UMath.LIM_U15, hi: a / UMath.LIM_U15, + lo: a % UMath.LIM_U15, }) args.push({ - lo: b % UMath.LIM_U15, hi: b / UMath.LIM_U15, + lo: b % UMath.LIM_U15, }) const cHi = c / UMath.LIM_U30 const clo = c % UMath.LIM_U30 args.push({ - lo: { - lo: clo % UMath.LIM_U15, - hi: clo / UMath.LIM_U15, - }, hi: { - lo: cHi % UMath.LIM_U15, hi: cHi / UMath.LIM_U15, + lo: cHi % UMath.LIM_U15, + }, + lo: { + hi: clo / UMath.LIM_U15, + lo: clo % UMath.LIM_U15, }, }) } else if (method === 'unlockU15') { args.push(a) args.push(b) args.push({ - lo: c % UMath.LIM_U15, hi: c / UMath.LIM_U15, + lo: c % UMath.LIM_U15, }) } else if (method === 'unlock') { args.push(a) @@ -92,7 +118,7 @@ describe('Test SmartContract `Opmul`', () => { const call = await instance.methods[method](...args, { fromUTXO: getDummyUTXO(), verify: false, - exec: false, + exec: true, } as MethodCallOptions) const revealTx = new btc.Transaction() @@ -117,17 +143,17 @@ describe('Test SmartContract `Opmul`', () => { function testUnlock( a: bigint, b: bigint, - method: 'unlock' | 'unlockU15' | 'unlockU30' = 'unlock', + method: 'unlock' | 'unlockU15' | 'unlockU30' | 'unlockU45' = 'unlock', errstr: string = '' ) { it(`when a = ${a}, b = ${b}, call [${method}] should ${ errstr ? 'fail' : 'pass' }`, async () => { - const res = await unlock(a, b, method) - if (errstr) { - expect(res).to.eq(errstr) + await expect(unlock(a, b, method)).rejectedWith(errstr) } else { + const res = await unlock(a, b, method) + expect(res).to.true } }) @@ -141,24 +167,20 @@ describe('Test SmartContract `Opmul`', () => { testUnlock(int32max, 0n) testUnlock(0n, int32max) - - const N = BigInt(Math.max(100, Math.floor(Math.random() * 1000))) + const FAIL_ERR_STR = 'Execution failed, result overflow' + const N = BigInt(Math.max(1000, Math.floor(Math.random() * 10000))) console.log('N:', N) for (let i = 1n; i < 2n ** 15n; ) { testUnlock(i, int32max / i) - testUnlock(-1n * i, int32max / i) testUnlock(int32max / i, i) - testUnlock((-1n * int32max) / i, i) i += N } // fail if b < 0 - const FAIL_ERR_STR = 'SCRIPT_ERR_VERIFY' - for (let i = 1n; i < 2n ** 15n; ) { - testUnlock(int32max / i, -1n * i, 'unlock', FAIL_ERR_STR) + testUnlock(int32max / i, i + 1n, 'unlock', FAIL_ERR_STR) i += N } @@ -175,14 +197,19 @@ describe('Test SmartContract `Opmul`', () => { i += N } - for (let i = 0; i < 100n; i++) { + for (let i = 0; i < 10n; i++) { const a = BigInt(Math.floor(Math.random() * 2 ** 16) + 2 ** 16) testUnlock(a, int32max / a + 1n, 'unlock', FAIL_ERR_STR) } const u30max = 2n ** 30n - 1n const u15max = 2n ** 15n - 1n + const u45max = 2n ** 45n - 1n + testUnlock(u45max, u15max, 'unlockU45') + testUnlock(u45max, 1n, 'unlockU45') + testUnlock(1n, u15max, 'unlockU45') + testUnlock(1n, 1n, 'unlockU45') testUnlock(1n, 1n, 'unlockU30') testUnlock(1n, u30max, 'unlockU30') testUnlock(u30max, 1n, 'unlockU30') @@ -192,13 +219,19 @@ describe('Test SmartContract `Opmul`', () => { testUnlock(u15max, 1n, 'unlockU15') testUnlock(u15max, u15max, 'unlockU15') - for (let i = 0; i < 100n; i++) { + for (let i = 0; i < 10n; i++) { + const a = BigInt(Math.floor(Math.random() * Number(u45max))) + const b = BigInt(Math.floor(Math.random() * Number(u15max))) + testUnlock(a, b, 'unlockU45') + } + + for (let i = 0; i < 10n; i++) { const a = BigInt(Math.floor(Math.random() * Number(u30max))) const b = BigInt(Math.floor(Math.random() * Number(u30max))) testUnlock(a, b, 'unlockU30') } - for (let i = 0; i < 100n; i++) { + for (let i = 0; i < 10n; i++) { const a = BigInt(Math.floor(Math.random() * Number(u15max))) const b = BigInt(Math.floor(Math.random() * Number(u15max))) testUnlock(a, b, 'unlockU15')