forked from BitVM/BitVM
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathu32_and.rs
More file actions
143 lines (122 loc) · 3.3 KB
/
u32_and.rs
File metadata and controls
143 lines (122 loc) · 3.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
use crate::treepp::*;
use crate::u32::u32_zip::u32_copy_zip;
/// 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)
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)
{i}
OP_ADD
OP_PICK
// A_andxor_B_odd = A_odd + B_odd
OP_SWAP
OP_ROT
OP_ADD
// A_and_B_odd = f(A_andxor_B_odd)
{i - 1}
OP_ADD
OP_PICK
// A_and_B = A_and_B_odd + (A_and_B_even << 1)
OP_OVER
OP_ADD
OP_ADD
}
}
/// 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! {
{u32_copy_zip(a, b)}
{u8_and(8 + (stack_size - 2) * 4)}
OP_TOALTSTACK
{u8_and(6 + (stack_size - 2) * 4)}
OP_TOALTSTACK
{u8_and(4 + (stack_size - 2) * 4)}
OP_TOALTSTACK
{u8_and(2 + (stack_size - 2) * 4)}
OP_FROMALTSTACK
OP_FROMALTSTACK
OP_FROMALTSTACK
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::u32::u32_std::*;
use crate::u32::u32_xor::{u8_drop_xor_table, u8_push_xor_table};
use rand::Rng;
#[test]
fn test_and() {
println!("u32 and: {} bytes", u32_and(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_and(0, 1, 3)}
{u32_push(x & y)}
{u32_equal()}
OP_TOALTSTACK
{u32_drop()} // drop y
{u8_drop_xor_table()}
OP_FROMALTSTACK
};
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);
}
}
}
}