From ca0166f447bab8f87f5c3c609842c92dde60dff4 Mon Sep 17 00:00:00 2001 From: erray Date: Tue, 21 Jan 2025 18:46:19 +0300 Subject: [PATCH] Refactor u4 and u32 (#201) * refactor u32 * refactor u4 and u32 * refactor u4_rot, fix bugs and clean up use's * fix typo --- bitvm/src/bigint/add.rs | 58 -- bitvm/src/bigint/mod.rs | 1 - bitvm/src/bigint/u32x8.rs | 270 ------ bitvm/src/hash/blake3_u4.rs | 6 +- bitvm/src/hash/sha256_u4.rs | 26 +- bitvm/src/hash/sha256_u4_stack.rs | 6 +- bitvm/src/lib.rs | 2 +- bitvm/src/u32/mod.rs | 2 - bitvm/src/u32/u32_add.rs | 100 ++- bitvm/src/u32/u32_and.rs | 41 +- bitvm/src/u32/u32_or.rs | 139 --- bitvm/src/u32/u32_rrot.rs | 77 +- bitvm/src/u32/u32_rshift.rs | 155 ---- bitvm/src/u32/u32_std.rs | 43 +- bitvm/src/u32/u32_xor.rs | 75 +- bitvm/src/u32/u32_zip.rs | 19 +- bitvm/src/u4/mod.rs | 1 - bitvm/src/u4/u4_add.rs | 536 +++--------- bitvm/src/u4/u4_add_stack.rs | 206 ++--- bitvm/src/u4/u4_logic.rs | 1318 ++++------------------------- bitvm/src/u4/u4_logic_stack.rs | 176 ++-- bitvm/src/u4/u4_rot.rs | 280 ++---- bitvm/src/u4/u4_rot_stack.rs | 154 ---- bitvm/src/u4/u4_shift.rs | 185 ++-- bitvm/src/u4/u4_shift_stack.rs | 170 +--- bitvm/src/u4/u4_std.rs | 31 +- 26 files changed, 850 insertions(+), 3227 deletions(-) delete mode 100644 bitvm/src/bigint/u32x8.rs delete mode 100644 bitvm/src/u32/u32_or.rs delete mode 100644 bitvm/src/u32/u32_rshift.rs delete mode 100644 bitvm/src/u4/u4_rot_stack.rs diff --git a/bitvm/src/bigint/add.rs b/bitvm/src/bigint/add.rs index 34d542d0..f3e389a6 100644 --- a/bitvm/src/bigint/add.rs +++ b/bitvm/src/bigint/add.rs @@ -63,31 +63,6 @@ impl BigIntImpl { } } - pub fn add1() -> Script { - script! { - 1 - { 1 << LIMB_SIZE } - - // A0 + 1 - limb_add_carry OP_TOALTSTACK - - // from A1 + carry_0 - // to A{N-2} + carry_{N-3} - for _ in 0..Self::N_LIMBS - 2 { - OP_SWAP - limb_add_carry OP_TOALTSTACK - } - - // A{N-1} + carry_{N-2} - OP_NIP - { limb_add_nocarry(Self::HEAD_OFFSET) } - - for _ in 0..Self::N_LIMBS - 1 { - OP_FROMALTSTACK - } - } - } - /// Double the BigInt on top of the stack /// /// # Note @@ -596,37 +571,4 @@ mod test { run(script); } } - - #[test] - fn test_1add() { - println!("U254.add1: {} bytes", U254::add1().len()); - let mut prng = ChaCha20Rng::seed_from_u64(0); - for _ in 0..100 { - let a: BigUint = prng.sample(RandomBits::new(254)); - let c: BigUint = (a.clone().add(BigUint::one())).rem(BigUint::one().shl(254)); - - let script = script! { - { U254::push_u32_le(&a.to_u32_digits()) } - { U254::add1() } - { U254::push_u32_le(&c.to_u32_digits()) } - { U254::equalverify(1, 0) } - OP_TRUE - }; - run(script); - } - - for _ in 0..100 { - let a: u64 = prng.gen(); - let c = a.wrapping_add(1u64); - - let script = script! { - { U64::push_u64_le(&[a]) } - { U64::add1() } - { U64::push_u64_le(&[c]) } - { U64::equalverify(1, 0) } - OP_TRUE - }; - run(script); - } - } } diff --git a/bitvm/src/bigint/mod.rs b/bitvm/src/bigint/mod.rs index 6679f65d..70f940d4 100644 --- a/bitvm/src/bigint/mod.rs +++ b/bitvm/src/bigint/mod.rs @@ -6,7 +6,6 @@ pub mod mul; pub mod std; pub mod sub; pub mod u29x9; -pub mod u32x8; pub struct BigIntImpl {} diff --git a/bitvm/src/bigint/u32x8.rs b/bitvm/src/bigint/u32x8.rs deleted file mode 100644 index a4397984..00000000 --- a/bitvm/src/bigint/u32x8.rs +++ /dev/null @@ -1,270 +0,0 @@ - -use crate::treepp::*; - -// x₀ → (x₀+1)%2³² -pub fn u32_1add_nocarry() -> Script { - script! { - // ⋯ x₀ - OP_SIZE OP_5 OP_EQUAL - // ⋯ x₀ x₀=2³¹ - OP_IF OP_DROP 0x7FFFFFFF OP_NEGATE - // ⋯ 1-2³¹ - OP_ELSE OP_1ADD OP_ENDIF - // ⋯ x₀+1 - } -} - -// x₀ → (x₀+1)%2³² x₀=-1 -pub fn u32_1add_carry() -> Script { - script! { - // ⋯ x₀ - OP_SIZE OP_5 OP_EQUAL - // ⋯ x₀ x₀=2³¹ - OP_IF OP_DROP 0x7FFFFFFF OP_NEGATE - // ⋯ 1-2³¹ - OP_ELSE OP_1ADD OP_ENDIF - // ⋯ x₀+1 - OP_DUP OP_0 OP_EQUAL - // ⋯ x₀+1 x₀=-1 - } -} - -// 2³¹-1 x₀ x₁ → 2³¹-1 (x₀+x₁)%2³² -pub fn u32_add_nocarry() -> Script { - script! { - // ⋯ 2³¹-1 x₀ x₁ - OP_SIZE OP_5 OP_EQUAL - // ⋯ 2³¹-1 x₀ x₁ x₁=2³¹ - OP_TUCK OP_IF - // ⋯ 2³¹-1 x₀ x₁=2³¹ x₁ - OP_DROP OP_0 - // ⋯ 2³¹-1 x₀ x₁=2³¹ 0 - OP_ELSE - // ⋯ 2³¹-1 x₀ x₁=2³¹ x₁ - OP_TUCK OP_GREATERTHAN - // ⋯ 2³¹-1 x₀ x₁≥2³¹ x₁ - OP_TUCK OP_IF OP_3 OP_PICK OP_ADD OP_1ADD OP_ENDIF - // ⋯ 2³¹-1 x₀ x₁≥2³¹ x₁[+2³¹] - OP_ENDIF - // ⋯ 2³¹-1 x₀ x₁≥2³¹ x₁[+2³¹] - OP_ROT OP_SIZE OP_5 OP_EQUAL - // ⋯ 2³¹-1 x₁≥2³¹ x₁[+2³¹] x₀ x₀=2³¹ - OP_TUCK OP_IF - // ⋯ 2³¹-1 x₁≥2³¹ x₁[+2³¹] x₀=2³¹ x₀ - OP_DROP OP_0 - // ⋯ 2³¹-1 x₁≥2³¹ x₁[+2³¹] x₀=2³¹ 0 - OP_ELSE - // ⋯ 2³¹-1 x₁≥2³¹ x₁[+2³¹] x₀=2³¹ x₀ - OP_TUCK OP_LESSTHAN - // ⋯ 2³¹-1 x₁≥2³¹ x₁[+2³¹] x₀ x₀<2³¹ - OP_TUCK OP_IF OP_4 OP_PICK OP_SUB OP_1SUB OP_ENDIF - // ⋯ 2³¹-1 x₁≥2³¹ x₁[+2³¹] x₀<2³¹ x₀[-2³¹] - OP_ENDIF - // ⋯ 2³¹-1 x₁≥2³¹ x₁[+2³¹] x₀≤2³¹ x₀[-2³¹] - OP_ROT OP_ADD - // ⋯ 2³¹-1 x₁≥2³¹ x₀≤2³¹ x₀+x₁[±2³¹] - OP_ROT OP_ROT OP_NUMNOTEQUAL - // ⋯ 2³¹-1 x₀+x₁[±2³¹] (x₀≤2³¹)≠(x₁≥2³¹) - OP_IF // x₀≤2³¹ ≠ x₁≥2³¹ - // ⋯ 2³¹-1 x₀+x₁[±2³¹] - OP_2DUP OP_0 OP_LESSTHANOREQUAL - // ⋯ 2³¹-1 x₀+x₁[±2³¹] x₀+x₁[±2³¹]≥2³¹ - OP_IF OP_ADD OP_1ADD OP_ELSE OP_SUB OP_1SUB OP_ENDIF - // ⋯ 2³¹-1 (x₀+x₁)%2³² - OP_ENDIF - // ⋯ 2³¹-1 (x₀+x₁)%2³² - } -} - -// 2³¹-1 x₀ x₁ → 2³¹-1 (x₀+x₁)%2³² x₀+x₁≥2³² -pub fn u32_add_carry() -> Script { - script! { - // ⋯ 2³¹-1 x₀ x₁ - OP_SIZE OP_5 OP_EQUAL - // ⋯ 2³¹-1 x₀ x₁ x₁=2³¹ - OP_TUCK OP_IF - // ⋯ 2³¹-1 x₀ x₁=2³¹ x₁ - OP_DROP OP_0 - // ⋯ 2³¹-1 x₀ x₁=2³¹ 0 - OP_ELSE - // ⋯ 2³¹-1 x₀ x₁=2³¹ x₁ - OP_TUCK OP_LESSTHAN - // ⋯ 2³¹-1 x₀ x₁≥2³¹ x₁ - OP_TUCK OP_IF OP_3 OP_PICK OP_SUB OP_1SUB OP_ENDIF - // ⋯ 2³¹-1 x₀ x₁≥2³¹ x₁[-2³¹] - OP_ENDIF - // ⋯ 2³¹-1 x₀ x₁≥2³¹ x₁[-2³¹] - OP_ROT OP_SIZE OP_5 OP_EQUAL - // ⋯ 2³¹-1 x₁≥2³¹ x₁[-2³¹] x₀ x₀=2³¹ - OP_TUCK OP_IF - // ⋯ 2³¹-1 x₁≥2³¹ x₁[-2³¹] x₀=2³¹ x₀ - OP_DROP OP_0 - // ⋯ 2³¹-1 x₁≥2³¹ x₁[-2³¹] x₀=2³¹ 0 - OP_ELSE - // ⋯ 2³¹-1 x₁≥2³¹ x₁[-2³¹] x₀=2³¹ x₀ - OP_TUCK OP_GREATERTHAN - // ⋯ 2³¹-1 x₁≥2³¹ x₁[-2³¹] x₀ x₀<2³¹ - OP_TUCK OP_IF OP_4 OP_PICK OP_ADD OP_1ADD OP_ENDIF - // ⋯ 2³¹-1 x₁≥2³¹ x₁[-2³¹] x₀<2³¹ x₀[+2³¹] - OP_ENDIF - // ⋯ 2³¹-1 x₁≥2³¹ x₁[-2³¹] x₀≤2³¹ x₀[+2³¹] - OP_ROT OP_DUP OP_0NOTEQUAL OP_TOALTSTACK OP_ADD - // ⋯ 2³¹-1 x₁≥2³¹ x₀≤2³¹ x₀+x₁[±2³¹] | x₁[-2³¹]≠0 - OP_DUP OP_2OVER OP_NUMNOTEQUAL OP_GREATERTHANOREQUAL - // ⋯ 2³¹-1 x₁≥2³¹ x₀≤2³¹ x₀+x₁[±2³¹] x₀+x₁[±2³¹]≥(x₀≤2³¹)≠(x₁≥2³¹) | x₁[-2³¹]≠0 - OP_2SWAP OP_TUCK OP_NUMNOTEQUAL - // ⋯ 2³¹-1 x₀+x₁[±2³¹] x₀+x₁[±2³¹]≥(x₀≤2³¹)≠(x₁≥2³¹) x₁≥2³¹ x₀≤2³¹ | x₁[-2³¹]≠0 - OP_FROMALTSTACK OP_SWAP - // ⋯ 2³¹-1 x₀+x₁[±2³¹] x₀+x₁[±2³¹]≥(x₀≤2³¹)≠(x₁≥2³¹) x₁≥2³¹ x₁[-2³¹]≠0 x₀≤2³¹ - OP_IF // x₀ ≤ 2³¹ - // ⋯ 2³¹-1 x₀+x₁[±2³¹] x₀+x₁[±2³¹]≥(x₀≤2³¹)≠(x₁≥2³¹) x₁≥2³¹ x₁[-2³¹]≠0 - OP_BOOLAND - // ⋯ 2³¹-1 x₀+x₁[±2³¹] x₀+x₁[±2³¹]≥(x₀≤2³¹)≠(x₁≥2³¹) x₁≥2³¹∧x₁[-2³¹]≠0 - OP_3 OP_PICK OP_2SWAP - // ⋯ 2³¹-1 x₁≥2³¹∧x₁[-2³¹]≠0 2³¹-1 x₀+x₁[±2³¹] x₀+x₁[±2³¹]≥(x₀≤2³¹)≠(x₁≥2³¹) - OP_IF // x₀+x₁[±2³¹] ≥ (x₀≤2³¹)≠(x₁≥2³¹) - // ⋯ 2³¹-1 x₁≥2³¹∧x₁[-2³¹]≠0 2³¹-1 x₀+x₁[±2³¹] - OP_1SUB OP_SWAP OP_SUB - // ⋯ 2³¹-1 x₁≥2³¹∧x₁[-2³¹]≠0 x₀+x₁[±2³¹]-2³¹ - OP_ELSE - // ⋯ 2³¹-1 x₁≥2³¹∧x₁[-2³¹]≠0 2³¹-1 x₀+x₁[±2³¹] - OP_1ADD OP_ADD - // ⋯ 2³¹-1 x₁≥2³¹∧x₁[-2³¹]≠0 x₀+x₁[±2³¹]+2³¹ - OP_ENDIF - // ⋯ 2³¹-1 x₀+x₁≥2³² (x₀+x₁)%2³² - OP_SWAP - // ⋯ 2³¹-1 (x₀+x₁)%2³² x₀+x₁≥2³² - OP_ELSE // x₁[-2³¹] = 0 - // ⋯ 2³¹-1 x₀+x₁[±2³¹] x₀+x₁[±2³¹]≥(x₀≤2³¹)≠(x₁≥2³¹) x₁≥2³¹ x₁[-2³¹]≠0 - OP_BOOLOR OP_BOOLAND - // ⋯ 2³¹-1 x₀+x₁[±2³¹] x₀+x₁[±2³¹]≥(x₀≤2³¹)≠(x₁≥2³¹)∨x₁≥2³¹∧x₁[-2³¹]≠0 - OP_ENDIF - // ⋯ 2³¹-1 (x₀+x₁)%2³² x₀+x₁≥2³² - } -} - -// 2³¹-1 x₀ x₁ → 2³¹-1 (x₀-x₁)%2³² -pub fn u32_sub_noborrow() -> Script { - script! { - // ⋯ 2³¹-1 x₀ x₁ - OP_SIZE OP_5 OP_EQUAL - // ⋯ 2³¹-1 x₀ x₁ x₁=2³¹ - OP_TUCK OP_IF - // ⋯ 2³¹-1 x₀ x₁=2³¹ x₁ - OP_DROP OP_0 - // ⋯ 2³¹-1 x₀ x₁=2³¹ 0 - OP_ELSE - // ⋯ 2³¹-1 x₀ x₁=2³¹ x₁ - OP_TUCK OP_GREATERTHAN - // ⋯ 2³¹-1 x₀ x₁≥2³¹ x₁ - OP_TUCK OP_IF OP_3 OP_PICK OP_ADD OP_1ADD OP_ENDIF - // ⋯ 2³¹-1 x₀ x₁≥2³¹ x₁[+2³¹] - OP_ENDIF - // ⋯ 2³¹-1 x₀ x₁≥2³¹ x₁[+2³¹] - OP_ROT OP_SIZE OP_5 OP_EQUAL - // ⋯ 2³¹-1 x₁≥2³¹ x₁[+2³¹] x₀ x₀=2³¹ - OP_TUCK OP_IF - // ⋯ 2³¹-1 x₁≥2³¹ x₁[+2³¹] x₀=2³¹ x₀ - OP_DROP OP_0 - // ⋯ 2³¹-1 x₁≥2³¹ x₁[+2³¹] x₀=2³¹ 0 - OP_ELSE - // ⋯ 2³¹-1 x₁≥2³¹ x₁[+2³¹] x₀=2³¹ x₀ - OP_TUCK OP_LESSTHAN - // ⋯ 2³¹-1 x₁≥2³¹ x₁[+2³¹] x₀ x₀<2³¹ - OP_TUCK OP_IF OP_4 OP_PICK OP_SUB OP_1SUB OP_ENDIF - // ⋯ 2³¹-1 x₁≥2³¹ x₁[+2³¹] x₀<2³¹ x₀[-2³¹] - OP_ENDIF - // ⋯ 2³¹-1 x₁≥2³¹ x₁[+2³¹] x₀≤2³¹ x₀[-2³¹] - OP_ROT OP_SUB - // ⋯ 2³¹-1 x₁≥2³¹ x₀≤2³¹ x₀+x₁[±2³¹] - OP_ROT OP_ROT OP_NUMNOTEQUAL - // ⋯ 2³¹-1 x₀+x₁[±2³¹] (x₀≤2³¹)≠(x₁≥2³¹) - OP_IF // x₀≤2³¹ ≠ x₁≥2³¹ - // ⋯ 2³¹-1 x₀+x₁[±2³¹] - OP_2DUP OP_0 OP_LESSTHANOREQUAL - // ⋯ 2³¹-1 x₀+x₁[±2³¹] x₀+x₁[±2³¹]≥2³¹ - OP_IF OP_ADD OP_1ADD OP_ELSE OP_SUB OP_1SUB OP_ENDIF - // ⋯ 2³¹-1 (x₀+x₁)%2³² - OP_ENDIF - // ⋯ 2³¹-1 (x₀+x₁)%2³² - } -} - -#[cfg(test)] -mod test { - use super::*; - #[test] - fn test_1add_nocarry() { - println!("u32_1add_nocarry: {} bytes", u32_1add_nocarry().len()); - run(script! { - 0 u32_1add_nocarry 1 OP_EQUALVERIFY // 0 + 1 ⩵ 1 mod 2³² - 0x7FFFFFFF u32_1add_nocarry 0x80000000 OP_EQUALVERIFY // 2³¹-1 + 1 ⩵ 1 mod 2³² - 0x80000000 u32_1add_nocarry 0x7FFFFFFF OP_NEGATE OP_EQUALVERIFY // 2³¹ + 1 ⩵ 2³¹+1 mod 2³² - 0x7FFFFFFF OP_NEGATE u32_1add_nocarry 0x7FFFFFFE OP_NEGATE OP_EQUALVERIFY // 2³¹+1 + 1 ⩵ 2³¹+2 mod 2³² - 1 OP_NEGATE u32_1add_nocarry 0 OP_EQUALVERIFY // 2³²-1 + 1 ⩵ 0 mod 2³² - OP_TRUE - }) - } - #[test] - fn test_1add_carry() { - println!("u32_1add_carry: {} bytes", u32_1add_carry().len()); - run(script! { - 0 u32_1add_carry 0 OP_EQUALVERIFY 1 OP_EQUALVERIFY // 0 + 1 ⩵ 1 mod 2³² - 0x7FFFFFFF u32_1add_carry 0 OP_EQUALVERIFY 0x80000000 OP_EQUALVERIFY // 2³¹-1 + 1 ⩵ 2³¹ mod 2³² - 0x7FFFFFFF OP_NEGATE u32_1add_carry 0 OP_EQUALVERIFY 0x7FFFFFFE OP_NEGATE OP_EQUALVERIFY - 1 OP_NEGATE u32_1add_carry 1 OP_EQUALVERIFY 0 OP_EQUALVERIFY // 2³²-1 + 1 ⩵ 0 mod 2³² - OP_TRUE - }) - } - #[test] - fn test_add_nocarry() { - println!("u32_add_nocarry: {} bytes", u32_add_nocarry().len()); - run(script! { 0x7FFFFFFF - 0 0 u32_add_nocarry 0 OP_EQUALVERIFY // 0 + 0 ⩵ 0 mod 2³² - 1 0 u32_add_nocarry 1 OP_EQUALVERIFY // 1 + 0 ⩵ 1 mod 2³² - 0 1 u32_add_nocarry 1 OP_EQUALVERIFY // 0 + 1 ⩵ 1 mod 2³² - 1 1 u32_add_nocarry 2 OP_EQUALVERIFY // 1 + 1 ⩵ 2 mod 2³² - 0x40000000 OP_DUP u32_add_nocarry 0x80000000 OP_EQUALVERIFY // 2³⁰ + 2³⁰ ⩵ 2³¹ mod 2³² - 0 0x80000000 u32_add_nocarry 0x80000000 OP_EQUALVERIFY // 0 + 2³¹ ⩵ 2³¹ mod 2³² - 0x80000000 0 u32_add_nocarry 0x80000000 OP_EQUALVERIFY // 2³¹ + 0 ⩵ 2³¹ mod 2³² - 0x80000000 OP_DUP u32_add_nocarry 0 OP_EQUALVERIFY // 2³¹ + 2³¹ ⩵ 0 mod 2³² - 1 OP_NEGATE 1 u32_add_nocarry 0 OP_EQUALVERIFY // 2³²-1 + 1 ⩵ 0 mod 2³² - 1 OP_NEGATE OP_DUP u32_add_nocarry 2 OP_NEGATE OP_EQUALVERIFY // 2³²-1 + 2³²-1 ⩵ 2³²-2 mod 2³² - 0x7FFFFFFF OP_NEGATE 0x80000000 u32_add_nocarry 1 OP_EQUALVERIFY // 2³¹+1 + 2³¹ = 1 mod 2³² - }) - } - #[test] - fn test_sub_noborrow() { - println!("u32_sub_noborrow: {} bytes", u32_sub_noborrow().len()); - run(script! { 0x7FFFFFFF - 0 0 u32_sub_noborrow 0 OP_EQUALVERIFY // 0 - 0 ⩵ 0 mod 2³² - 1 0 u32_sub_noborrow 1 OP_EQUALVERIFY // 1 - 0 ⩵ 1 mod 2³² - 0 1 u32_sub_noborrow 1 OP_NEGATE OP_EQUALVERIFY // 0 - 1 ⩵ 2³²-1 mod 2³² - 1 1 u32_sub_noborrow 0 OP_EQUALVERIFY // 1 - 1 ⩵ 0 mod 2³² - 0x40000000 OP_DUP u32_sub_noborrow 0 OP_EQUALVERIFY // 2³⁰ - 2³⁰ ⩵ 0 mod 2³² - 0 0x80000000 u32_sub_noborrow 0x80000000 OP_EQUALVERIFY // 0 - 2³¹ ⩵ 2³¹ mod 2³² - 0x80000000 0 u32_sub_noborrow 0x80000000 OP_EQUALVERIFY // 2³¹ - 0 ⩵ 2³¹ mod 2³² - 0x80000000 OP_DUP u32_sub_noborrow 0 OP_EQUALVERIFY // 2³¹ - 2³¹ ⩵ 0 mod 2³² - 1 OP_NEGATE 1 u32_sub_noborrow 2 OP_NEGATE OP_EQUALVERIFY // 2³²-1 - 1 ⩵ 2³²-2 mod 2³² - 1 OP_NEGATE OP_DUP u32_sub_noborrow 0 OP_EQUALVERIFY // 2³²-1 - 2³²-1 ⩵ 0 mod 2³² - 0x7FFFFFFF OP_NEGATE 0x80000000 u32_sub_noborrow 1 OP_EQUALVERIFY // 2³¹+1 - 2³¹ = 1 mod 2³² - }) - } - #[test] - fn test_add_carry() { - println!("u32_add_carry: {} bytes", u32_add_carry().len()); - run(script! { 0x7FFFFFFF - 0 0 u32_add_carry 0 OP_EQUALVERIFY 0 OP_EQUALVERIFY // 0 + 0 ⩵ 0 mod 2³² - 1 0 u32_add_carry 0 OP_EQUALVERIFY 1 OP_EQUALVERIFY // 1 + 0 ⩵ 1 mod 2³² - 0 1 u32_add_carry 0 OP_EQUALVERIFY 1 OP_EQUALVERIFY // 0 + 1 ⩵ 1 mod 2³² - 1 1 u32_add_carry 0 OP_EQUALVERIFY 2 OP_EQUALVERIFY // 1 + 1 ⩵ 2 mod 2³² - 0x40000000 OP_DUP u32_add_carry 0 OP_EQUALVERIFY 0x80000000 OP_EQUALVERIFY // 2³⁰ + 2³⁰ ⩵ 2³¹ mod 2³² - OP_0 0x80000000 u32_add_carry 0 OP_EQUALVERIFY 0x80000000 OP_EQUALVERIFY // 0 + 2³¹ ⩵ 2³¹ mod 2³² - 0x80000000 OP_0 u32_add_carry 0 OP_EQUALVERIFY 0x80000000 OP_EQUALVERIFY // 2³¹ + 0 ⩵ 2³¹ mod 2³² - 0x80000000 OP_DUP u32_add_carry 1 OP_EQUALVERIFY 0 OP_EQUALVERIFY // 2³¹ + 2³¹ ⩵ 0 mod 2³² - 1 OP_NEGATE 1 u32_add_carry 1 OP_EQUALVERIFY 0 OP_EQUALVERIFY // 2³²-1 + 1 ⩵ 0 mod 2³² - 1 OP_NEGATE OP_DUP u32_add_carry 1 OP_EQUALVERIFY 2 OP_NEGATE OP_EQUALVERIFY // 2³²-1 + 2³²-1 ⩵ 2³²-2 mod 2³² - 0x7FFFFFFF OP_NEGATE 0x80000000 u32_add_carry 1 OP_EQUALVERIFY 1 OP_EQUALVERIFY // 2³¹+1 + 2³¹ = 1 mod 2³² - }) - } -} diff --git a/bitvm/src/hash/blake3_u4.rs b/bitvm/src/hash/blake3_u4.rs index 2b72d88f..2158588c 100644 --- a/bitvm/src/hash/blake3_u4.rs +++ b/bitvm/src/hash/blake3_u4.rs @@ -25,8 +25,8 @@ pub struct TablesVars { impl TablesVars { pub fn new(stack: &mut StackTracker, use_full_tables: bool) -> Self { - let depth_lookup = if !use_full_tables { u4_push_from_depth_half_lookup(stack, -18) } else { u4_push_from_depth_lookup(stack, -17) }; - let xor_table = if !use_full_tables { u4_push_xor_table_stack(stack) } else { u4_push_xor_full_table_stack(stack) }; + let depth_lookup = if !use_full_tables { u4_push_from_depth_half_lookup(stack, -18) } else { u4_push_from_depth_full_lookup(stack, -17) }; + let xor_table = if !use_full_tables { u4_push_half_xor_table_stack(stack) } else { u4_push_full_xor_table_stack(stack) }; let shift_tables = u4_push_shift_for_blake(stack); let modulo = u4_push_modulo_for_blake(stack); let quotient = u4_push_quotient_for_blake(stack); @@ -659,9 +659,7 @@ pub fn blake3(stack: &mut StackTracker, mut msg_len: u32, final_rounds: u8) { #[cfg(test)] mod tests { - use std::collections::HashMap; - pub use bitcoin_script::script; //pub use bitcoin::ScriptBuf as Script; use bitcoin_script_stack::{debugger::debug_script, script_util::verify_n, stack::StackTracker, optimizer::optimize}; diff --git a/bitvm/src/hash/sha256_u4.rs b/bitvm/src/hash/sha256_u4.rs index fe3cf8c7..2efd5d36 100644 --- a/bitvm/src/hash/sha256_u4.rs +++ b/bitvm/src/hash/sha256_u4.rs @@ -189,15 +189,15 @@ pub fn ch_calculation(e: u32, f: u32, g: u32, offset_and: u32) -> Script { { g + 7 + 2} // e ~e g_nib_pos (account for e and ~e) OP_PICK // e ~e g - { u4_and_half_table(nib + offset_and + 3) } // e ( ~e & g ) + { u4_half_table_operation(nib + offset_and + 3) } // e ( ~e & g ) OP_SWAP // ( ~e & g ) e { f + 7 + 2} // ( ~e & g ) e f_nib_pos OP_PICK // ( ~e & g ) e f - { u4_and_half_table(nib + offset_and + 3) } // ( ~e & g ) (e & f) - { u4_xor_with_and_table(nib + offset_and + 2) } // ( ~e & g ) ^ (e & f) + { u4_half_table_operation(nib + offset_and + 3) } // ( ~e & g ) (e & f) + { u4_xor_with_half_and_table(nib + offset_and + 2) } // ( ~e & g ) ^ (e & f) //OP_TOALTSTACK } @@ -215,18 +215,18 @@ pub fn maj_calculation(a: u32, b: u32, c: u32, offset_and: u32) -> Script { OP_PICK // a b OP_2DUP // a b a b - { u4_xor_with_and_table(nib + offset_and + 4) } // a b (a^b) + { u4_xor_with_half_and_table(nib + offset_and + 4) } // a b (a^b) { c + 7 + 3 } // a b (a^b) c_nib_pos OP_PICK // a b (a^b) c - { u4_and_half_table(nib + offset_and + 4) } // a b ((a^b) & c) + { u4_half_table_operation(nib + offset_and + 4) } // a b ((a^b) & c) OP_ROT OP_ROT // ((a^b) & c) a b - { u4_and_half_table(nib + offset_and + 3) } // ((a^b) & c) (a & b) + { u4_half_table_operation(nib + offset_and + 3) } // ((a^b) & c) (a & b) - { u4_xor_with_and_table(nib + offset_and + 2) } // ((a^b) & c) ^ (a & b) + { u4_xor_with_half_and_table(nib + offset_and + 2) } // ((a^b) & c) ^ (a & b) } } @@ -278,7 +278,7 @@ pub fn sha256(num_bytes: u32) -> Script { let add_size = 130; let sched_size = 128; - let rrot_size = 96; + let rrot_size = 16 * 5; let half_logic_size = 136 + 16; let mut tables_size = rrot_size + half_logic_size; let use_add_table = chunks == 1; @@ -315,7 +315,7 @@ pub fn sha256(num_bytes: u32) -> Script { //TODO: if lookup table is pushed first and substracted // then we could avoid changing it ~(32 * chunk) { u4_drop_half_lookup() } - { u4_drop_half_and() } + { u4_drop_half_table() } { u4_push_half_xor_table() } { u4_push_half_lookup() } } @@ -336,7 +336,7 @@ pub fn sha256(num_bytes: u32) -> Script { //change xor with and table { u4_toaltstack(full_sched_size) } { u4_drop_half_lookup() } - { u4_drop_half_and() } + { u4_drop_half_table() } { u4_push_half_and_table() } { u4_push_half_lookup() } { u4_fromaltstack(full_sched_size) } @@ -452,7 +452,7 @@ pub fn sha256(num_bytes: u32) -> Script { } { u4_drop_half_lookup() } - { u4_drop_half_and() } + { u4_drop_half_table() } { u4_drop_rrot_tables() } if use_add_table { { u4_drop_add_tables() } @@ -512,10 +512,10 @@ mod tests { let script = script! { { u4_hex_to_nibbles(hex_in) } - { sha256(hex_in.len() as u32 /2)} + { sha256(hex_in.len() as u32 / 2)} - { u4_hex_to_nibbles(res.as_str())} + { u4_hex_to_nibbles(res.as_str()) } for _ in 0..64 { OP_TOALTSTACK } diff --git a/bitvm/src/hash/sha256_u4_stack.rs b/bitvm/src/hash/sha256_u4_stack.rs index 7045af24..f12d91dd 100644 --- a/bitvm/src/hash/sha256_u4_stack.rs +++ b/bitvm/src/hash/sha256_u4_stack.rs @@ -341,12 +341,12 @@ pub fn sha256_stack( let (lookup, xor_table) = if use_full_xor { ( u4_push_full_lookup_table_stack(stack), - u4_push_xor_full_table_stack(stack), + u4_push_full_xor_table_stack(stack), ) } else { ( - u4_push_lookup_table_stack(stack), - u4_push_xor_table_stack(stack), + u4_push_half_lookup_table_0_based_stack(stack), + u4_push_half_xor_table_stack(stack), ) }; diff --git a/bitvm/src/lib.rs b/bitvm/src/lib.rs index 1f5dbbb7..51001bac 100644 --- a/bitvm/src/lib.rs +++ b/bitvm/src/lib.rs @@ -240,7 +240,7 @@ pub fn run(script: treepp::Script) { exec_result.last_opcode, exec_result.final_stack ); } - println!("Max_stack_items = {}", exec_result.stats.max_nb_stack_items); + //println!("Max_stack_items = {}", exec_result.stats.max_nb_stack_items); assert!(exec_result.success); } diff --git a/bitvm/src/u32/mod.rs b/bitvm/src/u32/mod.rs index dbebf02a..e1ba7b6c 100644 --- a/bitvm/src/u32/mod.rs +++ b/bitvm/src/u32/mod.rs @@ -1,8 +1,6 @@ pub mod u32_add; pub mod u32_and; -pub mod u32_or; pub mod u32_rrot; -pub mod u32_rshift; pub mod u32_std; pub mod u32_xor; pub mod u32_zip; diff --git a/bitvm/src/u32/u32_add.rs b/bitvm/src/u32/u32_add.rs index bb8765c0..93ebc06c 100644 --- a/bitvm/src/u32/u32_add.rs +++ b/bitvm/src/u32/u32_add.rs @@ -1,39 +1,41 @@ -use crate::treepp::{script, Script}; +use crate::treepp::*; use crate::u32::u32_zip::{u32_copy_zip, u32_zip}; +/// Addition of two u8 elements at the top of the stack, pushing the carry after the sum pub fn u8_add_carry() -> Script { script! { OP_ADD - OP_DUP - 255 - OP_GREATERTHAN + 256 + OP_2DUP + OP_GREATERTHANOREQUAL OP_IF - 256 OP_SUB 1 OP_ELSE + OP_DROP 0 OP_ENDIF } } +/// Addition of two u8 elements at the top of the stack, without minding the carry pub fn u8_add() -> Script { script! { OP_ADD - OP_DUP - 255 - OP_GREATERTHAN + 256 + OP_2DUP + OP_GREATERTHANOREQUAL OP_IF - 256 OP_SUB + OP_0 OP_ENDIF + OP_DROP } } -/// Addition of two u32 values represented as u8 -/// Copies the first summand `a` and drops `b` +/// Modulo 2^32 addition of a-th and b-th u32 values, keeps the a-th element at stack pub fn u32_add(a: u32, b: u32) -> Script { - assert_ne!(a, b); + assert_ne!(a, b); script! { {u32_copy_zip(a, b)} @@ -66,8 +68,7 @@ pub fn u32_add(a: u32, b: u32) -> Script { } } -/// Addition of two u32 values represented as u8 -/// Drops both summands `a` and `b` +/// Modulo 2^32 addition of a-th and b-th u32 values pub fn u32_add_drop(a: u32, b: u32) -> Script { assert_ne!(a, b); script! { @@ -104,26 +105,63 @@ pub fn u32_add_drop(a: u32, b: u32) -> Script { #[cfg(test)] mod test { - use crate::run; - use crate::treepp::script; - use crate::u32::u32_add::*; - use crate::u32::u32_std::u32_push; + use super::*; + use crate::u32::u32_std::{u32_equal, u32_equalverify, u32_push}; + use rand::Rng; #[test] fn test_u32_add() { println!("u32_len: {}", u32_add_drop(1,0).len()); - let u32_value_a = 0xFFEEFFEEu32; - let u32_value_b = 0xEEFFEEFFu32; - - let script = script! { - { u32_push(u32_value_a) } - { u32_push(u32_value_b) } - { u32_add_drop(1, 0) } - 0xed OP_EQUALVERIFY - 0xee OP_EQUALVERIFY - 0xee OP_EQUALVERIFY - 0xee OP_EQUAL - }; - run(script); + let mut rng = rand::thread_rng(); + for _ in 0..1000 { + let x = rng.gen(); + let y = rng.gen_range(0..=u32::MAX - x); + let script_add_drop = script! { + { u32_push(x) } + { u32_push(y) } + { u32_add_drop(1, 0) } + { u32_push(x + y) } + { u32_equal() } + }; + let script_add = script! { + { u32_push(x) } + { u32_push(y) } + { u32_add(1, 0) } + { u32_push(x + y) } + { u32_equalverify() } + { u32_push(x) } + { u32_equal() } + }; + run(script_add_drop); + run(script_add); + } + } + #[test] + fn test_u8_adds_exhaustive() { + for a in 0..256 { + for b in 0..256 { + let script_without_carry = script! { + { a } + { b } + { u8_add() } + { (a + b) % 256 } + OP_EQUAL + }; + let script_with_carry = script! { + { a } + { b } + { u8_add_carry() } + { ((a + b) >= 256) as u32 } + OP_EQUAL + OP_TOALTSTACK + { (a + b) % 256 } + OP_EQUAL + OP_FROMALTSTACK + OP_BOOLAND + }; + run(script_without_carry); + run(script_with_carry); + } + } } } diff --git a/bitvm/src/u32/u32_and.rs b/bitvm/src/u32/u32_and.rs index 4bb47576..e489a8e3 100644 --- a/bitvm/src/u32/u32_and.rs +++ b/bitvm/src/u32/u32_and.rs @@ -1,10 +1,8 @@ -#![allow(dead_code)] - -use crate::treepp::{script, Script}; +use crate::treepp::*; use crate::u32::u32_zip::u32_copy_zip; -/// The bitwise AND of two u8 elements. -/// Expects the u8_xor_table to be on the stack +/// Bitwise AND of two u8 elements, i denoting how many values are there in the stack after the table (including the input numbers A and B) +/// Expects the u8_xor_table on the stack and uses it to process even and odd bits separately pub fn u8_and(i: u32) -> Script { script! { // f_A = f(A) @@ -67,9 +65,8 @@ pub fn u8_and(i: u32) -> Script { }.add_stack_hint(-(i as i32 + 256), -1) } -/// The bitwise AND of the u32 elements at address a and at address b. Drops a and b -/// -/// Expects the u8_xor_table to be on the stack +/// Bitwise AND of a-th and b-th u32 elements from the top, keeps a-th element in the stack +/// Expects u8_xor_table on the stack to use u8_and, and stack_size as a parameter to locate the table (which should be equal to 1 + number of the u32 elements in the stack after the table) pub fn u32_and(a: u32, b: u32, stack_size: u32) -> Script { assert_ne!(a, b); script! { @@ -97,16 +94,11 @@ pub fn u32_and(a: u32, b: u32, stack_size: u32) -> Script { #[cfg(test)] mod tests { - - use crate::run; - use crate::treepp::script; - use crate::u32::u32_and::*; + use super::*; use crate::u32::u32_std::*; use crate::u32::u32_xor::{u8_drop_xor_table, u8_push_xor_table}; use rand::Rng; - fn and(x: u32, y: u32) -> u32 { x & y } - #[test] fn test_and() { println!("u32 and: {} bytes", u32_and(0, 1, 3).len()); @@ -119,7 +111,7 @@ mod tests { {u32_push(x)} {u32_push(y)} {u32_and(0, 1, 3)} - {u32_push(and(x, y))} + {u32_push(x & y)} {u32_equal()} OP_TOALTSTACK {u32_drop()} // drop y @@ -129,4 +121,23 @@ mod tests { run(exec_script); } } + #[test] + fn test_u8_and_exhaustive() { + for a in 0..256 { + for b in 0..256 { + let script = script! { + { u8_push_xor_table() } + { a } + { b } + { u8_and(2) } + { a & b } + OP_EQUAL + OP_TOALTSTACK + { u8_drop_xor_table() } + OP_FROMALTSTACK + }; + run(script); + } + } + } } diff --git a/bitvm/src/u32/u32_or.rs b/bitvm/src/u32/u32_or.rs deleted file mode 100644 index d8678e39..00000000 --- a/bitvm/src/u32/u32_or.rs +++ /dev/null @@ -1,139 +0,0 @@ -#![allow(dead_code)] - -use crate::treepp::{script, Script}; -use crate::u32::u32_zip::u32_copy_zip; - -/// Bitwise OR of two u8 elements. -/// Expects the u8_xor_table to be on the stack. -/// -pub fn u8_or(i: u32) -> Script { - script! { - // f_A = f(A) - OP_DUP - {i} - OP_ADD - OP_PICK - - // A_even = f_A << 1 - OP_DUP - OP_DUP - OP_ADD - - // A_odd = A - A_even - OP_ROT - OP_SWAP - OP_SUB - - // f_B = f(B) - OP_ROT - OP_DUP - {i + 1} - OP_ADD - OP_PICK - - // B_even = f_B << 1 - OP_DUP - OP_DUP - OP_ADD - - // B_odd = B - B_even - OP_ROT - OP_SWAP - OP_SUB - - // A_andxor_B_even = f_A + f_B - OP_SWAP - 3 - OP_ROLL - OP_ADD - - // A_and_B_even = f(A_andxor_B_even) - OP_DUP - {i + 1} - OP_ADD - OP_PICK - OP_SUB - - // A_andxor_B_odd = A_odd + B_odd - OP_SWAP - OP_ROT - OP_ADD - - // A_and_B_odd = f(A_andxor_B_odd) - OP_DUP - {i} - OP_ADD - OP_PICK - OP_SUB - - // A_and_B = A_and_B_odd + (A_and_B_even << 1) - OP_OVER - OP_ADD - OP_ADD - }.add_stack_hint(-(i as i32 + 256), -1) -} - -/// Bitwise OR of two u32 elements. -/// Expects the u8_xor_table to be on the stack -pub fn u32_or(a: u32, b: u32, stack_size: u32) -> Script { - assert_ne!(a, b); - - script! { - {u32_copy_zip(a, b)} - - {u8_or(8 + (stack_size - 2) * 4)} - - OP_TOALTSTACK - - {u8_or(6 + (stack_size - 2) * 4)} - - OP_TOALTSTACK - - {u8_or(4 + (stack_size - 2) * 4)} - - OP_TOALTSTACK - - {u8_or(2 + (stack_size - 2) * 4)} - - - OP_FROMALTSTACK - OP_FROMALTSTACK - OP_FROMALTSTACK - } -} - -#[cfg(test)] -mod tests { - - use crate::run; - use crate::treepp::script; - use crate::u32::u32_or::*; - use crate::u32::u32_std::*; - use crate::u32::u32_xor::{u8_drop_xor_table, u8_push_xor_table}; - use rand::Rng; - - fn or(x: u32, y: u32) -> u32 { x | y } - - #[test] - fn test_or() { - println!("u32 or: {} bytes", u32_or(0, 1, 3).len()); - for _ in 0..100 { - let mut rng = rand::thread_rng(); - let x: u32 = rng.gen(); - let y: u32 = rng.gen(); - let exec_script = script! { - {u8_push_xor_table()} - {u32_push(x)} - {u32_push(y)} - {u32_or(0, 1, 3)} - {u32_push(or(x, y))} - {u32_equal()} - OP_TOALTSTACK - {u32_drop()} // drop y - {u8_drop_xor_table()} - OP_FROMALTSTACK - }; - run(exec_script); - } - } -} diff --git a/bitvm/src/u32/u32_rrot.rs b/bitvm/src/u32/u32_rrot.rs index eca45b2e..2c265cce 100644 --- a/bitvm/src/u32/u32_rrot.rs +++ b/bitvm/src/u32/u32_rrot.rs @@ -1,7 +1,4 @@ -#![allow(dead_code)] - -use crate::treepp::{script, Script}; -use core::panic; +use crate::treepp::*; /// Right rotation of an u32 element by 16 bits pub fn u32_rrot16() -> Script { @@ -18,7 +15,7 @@ pub fn u32_rrot8() -> Script { } } -/// Right rotation of an u8 element by 7 bits +/// Right rotation of the i-th u8 element by 7 bits pub fn u8_rrot7(i: u32) -> Script { let roll_script = match i { 0 => script! {}, @@ -86,6 +83,7 @@ pub fn u32_rrot7() -> Script { } } +/// Extracts (puts it at the top of the stack) the most significant bit of the u8 number and multiplies it by 2 modulo 256 pub fn u8_extract_1bit() -> Script { script! { OP_DUP @@ -103,31 +101,31 @@ pub fn u8_extract_1bit() -> Script { } } +/// Extracts (puts them at the top of the stack as the sum) the h most significant bits of the u8 number and multiplies it by 2^h modulo 256 pub fn u8_extract_hbit(hbit: usize) -> Script { - assert!(hbit < 8 && hbit != 0); + assert!((1..8).contains(&hbit)); if hbit == 1 { return u8_extract_1bit(); } - let base: usize = 2; - let x: usize = base.pow((hbit - 1).try_into().unwrap()); + let x: u32 = 1 << (hbit - 1); script! { 0 OP_TOALTSTACK for i in 0..hbit { - OP_DUP - 127 - OP_GREATERTHAN + 128 + OP_2DUP + OP_GREATERTHANOREQUAL OP_IF - 128 OP_SUB OP_FROMALTSTACK { x >> i } OP_ADD OP_TOALTSTACK + OP_DUP OP_ENDIF - + OP_DROP OP_DUP OP_ADD } @@ -135,43 +133,44 @@ pub fn u8_extract_hbit(hbit: usize) -> Script { OP_FROMALTSTACK } } -// 1 2 3 4 +/// Reorders (reverse and rotate) the bytes of an u32 number, assuming the starting order is 1 2 3 4 (4 being at the top): +/// if offset is 0, then reorder is 4 3 2 1 +/// if offset is 1, then reorder is 1 4 3 2 +/// if offset is 2, then reorder is 2 1 4 3 +/// if offset is 3, then reorder is 3 2 1 4 pub fn byte_reorder(offset: usize) -> Script { - assert!(offset < 4); + assert!((0..4).contains(&offset)); if offset == 0 { - // 4 3 2 1 script! { OP_SWAP OP_2SWAP OP_SWAP } } else if offset == 1 { - // 1 4 3 2 return script! { OP_SWAP OP_ROT }; } else if offset == 2 { - // 2 1 4 3 return script! { OP_SWAP OP_2SWAP OP_SWAP OP_2SWAP }; - } else if offset == 3 { + } else /* if offset == 3 */ { return script! { OP_SWAP OP_ROT OP_2SWAP }; - } else { - panic!("offset out of range") } } -pub fn specific_optimize(rot_num: usize) -> Option