forked from BitVM/BitVM
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathu32_add.rs
167 lines (149 loc) · 3.76 KB
/
u32_add.rs
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
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
256
OP_2DUP
OP_GREATERTHANOREQUAL
OP_IF
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
256
OP_2DUP
OP_GREATERTHANOREQUAL
OP_IF
OP_SUB
OP_0
OP_ENDIF
OP_DROP
}
}
/// 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);
script! {
{u32_copy_zip(a, b)}
// A0 + B0
u8_add_carry
OP_SWAP
OP_TOALTSTACK
// A1 + B1 + carry_0
OP_ADD
u8_add_carry
OP_SWAP
OP_TOALTSTACK
// A2 + B2 + carry_1
OP_ADD
u8_add_carry
OP_SWAP
OP_TOALTSTACK
// A3 + B3 + carry_2
OP_ADD
u8_add
OP_FROMALTSTACK
OP_FROMALTSTACK
OP_FROMALTSTACK
// Now there's the result C_3 C_2 C_1 C_0 on the stack
}
}
/// 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! {
{u32_zip(a, b)}
// A0 + B0
u8_add_carry
OP_SWAP
OP_TOALTSTACK
// A1 + B1 + carry_0
OP_ADD
u8_add_carry
OP_SWAP
OP_TOALTSTACK
// A2 + B2 + carry_1
OP_ADD
u8_add_carry
OP_SWAP
OP_TOALTSTACK
// A3 + B3 + carry_2
OP_ADD
u8_add
OP_FROMALTSTACK
OP_FROMALTSTACK
OP_FROMALTSTACK
// Now there's the result C_3 C_2 C_1 C_0 on the stack
}
}
#[cfg(test)]
mod test {
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 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);
}
}
}
}