1use super::stack::{PushValue, StackOp};
10
11const FIELD_P_MINUS_2_LOW32: u32 = 0xFFFF_FC2D;
17
18const THREE_CURVE_N_SCRIPT_NUM: [u8; 33] = [
21 0xc3, 0xc3, 0xa2, 0x70, 0xa6, 0x1b, 0x77, 0x3f, 0xb3, 0xe0, 0xd9, 0x0d,
22 0xb4, 0x96, 0x0c, 0x30, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
23 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02,
24];
25
26const GEN_X_BYTES: [u8; 32] = [
28 0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55, 0xa0, 0x62, 0x95,
29 0xce, 0x87, 0x0b, 0x07, 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9,
30 0x59, 0xf2, 0x81, 0x5b, 0x16, 0xf8, 0x17, 0x98,
31];
32
33const GEN_Y_BYTES: [u8; 32] = [
35 0x48, 0x3a, 0xda, 0x77, 0x26, 0xa3, 0xc4, 0x65, 0x5d, 0xa4, 0xfb, 0xfc,
36 0x0e, 0x11, 0x08, 0xa8, 0xfd, 0x17, 0xb4, 0x48, 0xa6, 0x85, 0x54, 0x19,
37 0x9c, 0x47, 0xd0, 0x8f, 0xfb, 0x10, 0xd4, 0xb8,
38];
39
40fn collect_ops(f: impl FnOnce(&mut dyn FnMut(StackOp))) -> Vec<StackOp> {
42 let mut ops = Vec::new();
43 f(&mut |op| ops.push(op));
44 ops
45}
46
47struct ECTracker<'a> {
52 nm: Vec<String>,
53 e: &'a mut dyn FnMut(StackOp),
54}
55
56#[allow(dead_code)]
57impl<'a> ECTracker<'a> {
58 fn new(init: &[&str], emit: &'a mut dyn FnMut(StackOp)) -> Self {
59 ECTracker {
60 nm: init.iter().map(|s| s.to_string()).collect(),
61 e: emit,
62 }
63 }
64
65 fn depth(&self) -> usize {
66 self.nm.len()
67 }
68
69 fn find_depth(&self, name: &str) -> usize {
70 for i in (0..self.nm.len()).rev() {
71 if self.nm[i] == name {
72 return self.nm.len() - 1 - i;
73 }
74 }
75 panic!("ECTracker: '{}' not on stack {:?}", name, self.nm);
76 }
77
78 fn push_bytes(&mut self, n: &str, v: Vec<u8>) {
79 (self.e)(StackOp::Push(PushValue::Bytes(v)));
80 self.nm.push(n.to_string());
81 }
82
83 fn push_int(&mut self, n: &str, v: i128) {
84 (self.e)(StackOp::Push(PushValue::Int(v)));
85 self.nm.push(n.to_string());
86 }
87
88 fn dup(&mut self, n: &str) {
89 (self.e)(StackOp::Dup);
90 self.nm.push(n.to_string());
91 }
92
93 fn drop(&mut self) {
94 (self.e)(StackOp::Drop);
95 if !self.nm.is_empty() {
96 self.nm.pop();
97 }
98 }
99
100 fn nip(&mut self) {
101 (self.e)(StackOp::Nip);
102 let len = self.nm.len();
103 if len >= 2 {
104 self.nm.remove(len - 2);
105 }
106 }
107
108 fn over(&mut self, n: &str) {
109 (self.e)(StackOp::Over);
110 self.nm.push(n.to_string());
111 }
112
113 fn swap(&mut self) {
114 (self.e)(StackOp::Swap);
115 let len = self.nm.len();
116 if len >= 2 {
117 self.nm.swap(len - 1, len - 2);
118 }
119 }
120
121 fn rot(&mut self) {
122 (self.e)(StackOp::Rot);
123 let len = self.nm.len();
124 if len >= 3 {
125 let r = self.nm.remove(len - 3);
126 self.nm.push(r);
127 }
128 }
129
130 fn op(&mut self, code: &str) {
131 (self.e)(StackOp::Opcode(code.into()));
132 }
133
134 fn roll(&mut self, d: usize) {
135 if d == 0 {
136 return;
137 }
138 if d == 1 {
139 self.swap();
140 return;
141 }
142 if d == 2 {
143 self.rot();
144 return;
145 }
146 (self.e)(StackOp::Push(PushValue::Int(d as i128)));
147 self.nm.push(String::new());
148 (self.e)(StackOp::Opcode("OP_ROLL".into()));
149 self.nm.pop(); let idx = self.nm.len() - 1 - d;
151 let r = self.nm.remove(idx);
152 self.nm.push(r);
153 }
154
155 fn pick(&mut self, d: usize, n: &str) {
156 if d == 0 {
157 self.dup(n);
158 return;
159 }
160 if d == 1 {
161 self.over(n);
162 return;
163 }
164 (self.e)(StackOp::Push(PushValue::Int(d as i128)));
165 self.nm.push(String::new());
166 (self.e)(StackOp::Opcode("OP_PICK".into()));
167 self.nm.pop(); self.nm.push(n.to_string());
169 }
170
171 fn to_top(&mut self, name: &str) {
172 let d = self.find_depth(name);
173 self.roll(d);
174 }
175
176 fn copy_to_top(&mut self, name: &str, n: &str) {
177 let d = self.find_depth(name);
178 self.pick(d, n);
179 }
180
181 fn to_alt(&mut self) {
182 self.op("OP_TOALTSTACK");
183 if !self.nm.is_empty() {
184 self.nm.pop();
185 }
186 }
187
188 fn from_alt(&mut self, n: &str) {
189 self.op("OP_FROMALTSTACK");
190 self.nm.push(n.to_string());
191 }
192
193 fn rename(&mut self, n: &str) {
194 if let Some(last) = self.nm.last_mut() {
195 *last = n.to_string();
196 }
197 }
198
199 fn raw_block(
201 &mut self,
202 consume: &[&str],
203 produce: Option<&str>,
204 f: impl FnOnce(&mut dyn FnMut(StackOp)),
205 ) {
206 for _ in consume {
207 if !self.nm.is_empty() {
208 self.nm.pop();
209 }
210 }
211 f(self.e);
212 if let Some(p) = produce {
213 self.nm.push(p.to_string());
214 }
215 }
216
217 fn emit_if(
219 &mut self,
220 cond_name: &str,
221 then_fn: impl FnOnce(&mut dyn FnMut(StackOp)),
222 else_fn: impl FnOnce(&mut dyn FnMut(StackOp)),
223 result_name: Option<&str>,
224 ) {
225 self.to_top(cond_name);
226 self.nm.pop(); let then_ops = collect_ops(then_fn);
228 let else_ops = collect_ops(else_fn);
229 (self.e)(StackOp::If {
230 then_ops,
231 else_ops,
232 });
233 if let Some(rn) = result_name {
234 self.nm.push(rn.to_string());
235 }
236 }
237}
238
239const FIELD_P_SCRIPT_NUM: [u8; 33] = [
251 0x2f, 0xfc, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
252 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
253 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
254];
255
256fn push_field_p(t: &mut ECTracker, name: &str) {
258 t.push_bytes(name, FIELD_P_SCRIPT_NUM.to_vec());
261}
262
263fn field_mod(t: &mut ECTracker, a_name: &str, result_name: &str) {
266 t.to_top(a_name);
267 push_field_p(t, "_fmod_p");
268 t.raw_block(&[a_name, "_fmod_p"], Some(result_name), |e| {
270 e(StackOp::Opcode("OP_2DUP".into())); e(StackOp::Opcode("OP_MOD".into())); e(StackOp::Rot); e(StackOp::Drop); e(StackOp::Over); e(StackOp::Opcode("OP_ADD".into())); e(StackOp::Swap); e(StackOp::Opcode("OP_MOD".into())); });
279}
280
281fn field_add(t: &mut ECTracker, a_name: &str, b_name: &str, result_name: &str) {
283 t.to_top(a_name);
284 t.to_top(b_name);
285 t.raw_block(&[a_name, b_name], Some("_fadd_sum"), |e| {
286 e(StackOp::Opcode("OP_ADD".into()));
287 });
288 field_mod(t, "_fadd_sum", result_name);
289}
290
291fn field_sub(t: &mut ECTracker, a_name: &str, b_name: &str, result_name: &str) {
293 t.to_top(a_name);
294 t.to_top(b_name);
295 t.raw_block(&[a_name, b_name], Some("_fsub_diff"), |e| {
296 e(StackOp::Opcode("OP_SUB".into()));
297 });
298 field_mod(t, "_fsub_diff", result_name);
299}
300
301fn field_mul(t: &mut ECTracker, a_name: &str, b_name: &str, result_name: &str) {
303 t.to_top(a_name);
304 t.to_top(b_name);
305 t.raw_block(&[a_name, b_name], Some("_fmul_prod"), |e| {
306 e(StackOp::Opcode("OP_MUL".into()));
307 });
308 field_mod(t, "_fmul_prod", result_name);
309}
310
311fn field_sqr(t: &mut ECTracker, a_name: &str, result_name: &str) {
313 t.copy_to_top(a_name, "_fsqr_copy");
314 field_mul(t, a_name, "_fsqr_copy", result_name);
315}
316
317fn field_inv(t: &mut ECTracker, a_name: &str, result_name: &str) {
320 t.copy_to_top(a_name, "_inv_r");
326 for _i in 0..222 {
328 field_sqr(t, "_inv_r", "_inv_r2");
329 t.rename("_inv_r");
330 t.copy_to_top(a_name, "_inv_a");
331 field_mul(t, "_inv_r", "_inv_a", "_inv_m");
332 t.rename("_inv_r");
333 }
334 field_sqr(t, "_inv_r", "_inv_r2");
336 t.rename("_inv_r");
337 let low_bits = FIELD_P_MINUS_2_LOW32;
339 for i in (0..=31).rev() {
340 field_sqr(t, "_inv_r", "_inv_r2");
341 t.rename("_inv_r");
342 if (low_bits >> i) & 1 != 0 {
343 t.copy_to_top(a_name, "_inv_a");
344 field_mul(t, "_inv_r", "_inv_a", "_inv_m");
345 t.rename("_inv_r");
346 }
347 }
348 t.to_top(a_name);
350 t.drop();
351 t.to_top("_inv_r");
352 t.rename(result_name);
353}
354
355fn decompose_point(t: &mut ECTracker, point_name: &str, x_name: &str, y_name: &str) {
362 t.to_top(point_name);
363 t.raw_block(&[point_name], None, |e| {
365 e(StackOp::Push(PushValue::Int(32)));
366 e(StackOp::Opcode("OP_SPLIT".into()));
367 });
368 t.nm.push("_dp_xb".to_string());
370 t.nm.push("_dp_yb".to_string());
371
372 t.raw_block(&["_dp_yb"], Some(y_name), |e| {
375 emit_reverse_32(e);
376 e(StackOp::Push(PushValue::Bytes(vec![0x00])));
377 e(StackOp::Opcode("OP_CAT".into()));
378 e(StackOp::Opcode("OP_BIN2NUM".into()));
379 });
380
381 t.to_top("_dp_xb");
383 t.raw_block(&["_dp_xb"], Some(x_name), |e| {
384 emit_reverse_32(e);
385 e(StackOp::Push(PushValue::Bytes(vec![0x00])));
386 e(StackOp::Opcode("OP_CAT".into()));
387 e(StackOp::Opcode("OP_BIN2NUM".into()));
388 });
389
390 t.swap();
392}
393
394fn compose_point(t: &mut ECTracker, x_name: &str, y_name: &str, result_name: &str) {
397 t.to_top(x_name);
400 t.raw_block(&[x_name], Some("_cp_xb"), |e| {
401 e(StackOp::Push(PushValue::Int(33)));
402 e(StackOp::Opcode("OP_NUM2BIN".into()));
403 e(StackOp::Push(PushValue::Int(32)));
405 e(StackOp::Opcode("OP_SPLIT".into()));
406 e(StackOp::Drop);
407 emit_reverse_32(e);
408 });
409
410 t.to_top(y_name);
412 t.raw_block(&[y_name], Some("_cp_yb"), |e| {
413 e(StackOp::Push(PushValue::Int(33)));
414 e(StackOp::Opcode("OP_NUM2BIN".into()));
415 e(StackOp::Push(PushValue::Int(32)));
416 e(StackOp::Opcode("OP_SPLIT".into()));
417 e(StackOp::Drop);
418 emit_reverse_32(e);
419 });
420
421 t.to_top("_cp_xb");
423 t.to_top("_cp_yb");
424 t.raw_block(&["_cp_xb", "_cp_yb"], Some(result_name), |e| {
425 e(StackOp::Opcode("OP_CAT".into()));
426 });
427}
428
429fn emit_reverse_32(e: &mut dyn FnMut(StackOp)) {
432 e(StackOp::Opcode("OP_0".into()));
434 e(StackOp::Swap);
435 for _i in 0..32 {
437 e(StackOp::Push(PushValue::Int(1)));
439 e(StackOp::Opcode("OP_SPLIT".into()));
440 e(StackOp::Rot);
442 e(StackOp::Rot);
444 e(StackOp::Swap);
446 e(StackOp::Opcode("OP_CAT".into()));
448 e(StackOp::Swap);
450 }
452 e(StackOp::Drop);
454}
455
456fn affine_add(t: &mut ECTracker) {
463 t.copy_to_top("qy", "_qy1");
465 t.copy_to_top("py", "_py1");
466 field_sub(t, "_qy1", "_py1", "_s_num");
467
468 t.copy_to_top("qx", "_qx1");
470 t.copy_to_top("px", "_px1");
471 field_sub(t, "_qx1", "_px1", "_s_den");
472
473 field_inv(t, "_s_den", "_s_den_inv");
475 field_mul(t, "_s_num", "_s_den_inv", "_s");
476
477 t.copy_to_top("_s", "_s_keep");
479 field_sqr(t, "_s", "_s2");
480 t.copy_to_top("px", "_px2");
481 field_sub(t, "_s2", "_px2", "_rx1");
482 t.copy_to_top("qx", "_qx2");
483 field_sub(t, "_rx1", "_qx2", "rx");
484
485 t.copy_to_top("px", "_px3");
487 t.copy_to_top("rx", "_rx2");
488 field_sub(t, "_px3", "_rx2", "_px_rx");
489 field_mul(t, "_s_keep", "_px_rx", "_s_px_rx");
490 t.copy_to_top("py", "_py2");
491 field_sub(t, "_s_px_rx", "_py2", "ry");
492
493 t.to_top("px"); t.drop();
495 t.to_top("py"); t.drop();
496 t.to_top("qx"); t.drop();
497 t.to_top("qy"); t.drop();
498}
499
500fn jacobian_double(t: &mut ECTracker) {
507 t.copy_to_top("jy", "_jy_save");
509 t.copy_to_top("jx", "_jx_save");
510 t.copy_to_top("jz", "_jz_save");
511
512 field_sqr(t, "jy", "_A");
514
515 t.copy_to_top("_A", "_A_save");
517 field_mul(t, "jx", "_A", "_xA");
518 t.push_int("_four", 4);
519 field_mul(t, "_xA", "_four", "_B");
520
521 field_sqr(t, "_A_save", "_A2");
523 t.push_int("_eight", 8);
524 field_mul(t, "_A2", "_eight", "_C");
525
526 field_sqr(t, "_jx_save", "_x2");
528 t.push_int("_three", 3);
529 field_mul(t, "_x2", "_three", "_D");
530
531 t.copy_to_top("_D", "_D_save");
533 t.copy_to_top("_B", "_B_save");
534 field_sqr(t, "_D", "_D2");
535 t.copy_to_top("_B", "_B1");
536 t.push_int("_two1", 2);
537 field_mul(t, "_B1", "_two1", "_2B");
538 field_sub(t, "_D2", "_2B", "_nx");
539
540 t.copy_to_top("_nx", "_nx_copy");
542 field_sub(t, "_B_save", "_nx_copy", "_B_nx");
543 field_mul(t, "_D_save", "_B_nx", "_D_B_nx");
544 field_sub(t, "_D_B_nx", "_C", "_ny");
545
546 field_mul(t, "_jy_save", "_jz_save", "_yz");
548 t.push_int("_two2", 2);
549 field_mul(t, "_yz", "_two2", "_nz");
550
551 t.to_top("_B"); t.drop();
553 t.to_top("jz"); t.drop();
554 t.to_top("_nx"); t.rename("jx");
555 t.to_top("_ny"); t.rename("jy");
556 t.to_top("_nz"); t.rename("jz");
557}
558
559fn jacobian_to_affine(t: &mut ECTracker, rx_name: &str, ry_name: &str) {
562 field_inv(t, "jz", "_zinv");
563 t.copy_to_top("_zinv", "_zinv_keep");
564 field_sqr(t, "_zinv", "_zinv2");
565 t.copy_to_top("_zinv2", "_zinv2_keep");
566 field_mul(t, "_zinv_keep", "_zinv2", "_zinv3");
567 field_mul(t, "jx", "_zinv2_keep", rx_name);
568 field_mul(t, "jy", "_zinv3", ry_name);
569}
570
571fn build_jacobian_add_affine_inline(e: &mut dyn FnMut(StackOp), t: &ECTracker) {
581 let cloned_nm: Vec<String> = t.nm.clone();
583 let init_strs: Vec<&str> = cloned_nm.iter().map(|s| s.as_str()).collect();
584 let mut it = ECTracker::new(&init_strs, e);
585
586 it.copy_to_top("jz", "_jz_for_z1cu"); it.copy_to_top("jz", "_jz_for_z3"); it.copy_to_top("jy", "_jy_for_y3"); it.copy_to_top("jx", "_jx_for_u1h2"); field_sqr(&mut it, "jz", "_Z1sq");
594
595 it.copy_to_top("_Z1sq", "_Z1sq_for_u2");
597 field_mul(&mut it, "_jz_for_z1cu", "_Z1sq", "_Z1cu");
598
599 it.copy_to_top("ax", "_ax_c");
601 field_mul(&mut it, "_ax_c", "_Z1sq_for_u2", "_U2");
602
603 it.copy_to_top("ay", "_ay_c");
605 field_mul(&mut it, "_ay_c", "_Z1cu", "_S2");
606
607 field_sub(&mut it, "_U2", "jx", "_H");
609
610 field_sub(&mut it, "_S2", "jy", "_R");
612
613 it.copy_to_top("_H", "_H_for_h3");
615 it.copy_to_top("_H", "_H_for_z3");
616
617 field_sqr(&mut it, "_H", "_H2");
619
620 it.copy_to_top("_H2", "_H2_for_u1h2");
622
623 field_mul(&mut it, "_H_for_h3", "_H2", "_H3");
625
626 field_mul(&mut it, "_jx_for_u1h2", "_H2_for_u1h2", "_U1H2");
628
629 it.copy_to_top("_R", "_R_for_y3");
631 it.copy_to_top("_U1H2", "_U1H2_for_y3");
632 it.copy_to_top("_H3", "_H3_for_y3");
633
634 field_sqr(&mut it, "_R", "_R2");
636 field_sub(&mut it, "_R2", "_H3", "_x3_tmp");
637 it.push_int("_two", 2);
638 field_mul(&mut it, "_U1H2", "_two", "_2U1H2");
639 field_sub(&mut it, "_x3_tmp", "_2U1H2", "_X3");
640
641 it.copy_to_top("_X3", "_X3_c");
643 field_sub(&mut it, "_U1H2_for_y3", "_X3_c", "_u_minus_x");
644 field_mul(&mut it, "_R_for_y3", "_u_minus_x", "_r_tmp");
645 field_mul(&mut it, "_jy_for_y3", "_H3_for_y3", "_jy_h3");
646 field_sub(&mut it, "_r_tmp", "_jy_h3", "_Y3");
647
648 field_mul(&mut it, "_jz_for_z3", "_H_for_z3", "_Z3");
650
651 it.to_top("_X3"); it.rename("jx");
653 it.to_top("_Y3"); it.rename("jy");
654 it.to_top("_Z3"); it.rename("jz");
655}
656
657pub fn emit_ec_add(emit: &mut dyn FnMut(StackOp)) {
665 let mut t = ECTracker::new(&["_pa", "_pb"], emit);
666 decompose_point(&mut t, "_pa", "px", "py");
667 decompose_point(&mut t, "_pb", "qx", "qy");
668 affine_add(&mut t);
669 compose_point(&mut t, "rx", "ry", "_result");
670}
671
672pub fn emit_ec_mul(emit: &mut dyn FnMut(StackOp)) {
678 let mut t = ECTracker::new(&["_pt", "_k"], emit);
679 decompose_point(&mut t, "_pt", "ax", "ay");
681
682 t.to_top("_k");
687 t.push_bytes("_3n", THREE_CURVE_N_SCRIPT_NUM.to_vec());
688 t.raw_block(&["_k", "_3n"], Some("_k3n"), |e| {
689 e(StackOp::Opcode("OP_ADD".into()));
690 });
691 t.rename("_k");
692
693 t.copy_to_top("ax", "jx");
695 t.copy_to_top("ay", "jy");
696 t.push_int("jz", 1);
697
698 for bit in (0..=256).rev() {
700 jacobian_double(&mut t);
702
703 t.copy_to_top("_k", "_k_copy");
705 if bit > 0 {
706 if bit <= 126 {
709 t.push_int("_div", 1i128 << bit);
710 } else {
711 let divisor_bytes = script_number_pow2(bit);
712 t.push_bytes("_div", divisor_bytes);
713 }
714 t.raw_block(&["_k_copy", "_div"], Some("_shifted"), |e| {
715 e(StackOp::Opcode("OP_DIV".into()));
716 });
717 } else {
718 t.rename("_shifted");
719 }
720 t.push_int("_two", 2);
721 t.raw_block(&["_shifted", "_two"], Some("_bit"), |e| {
722 e(StackOp::Opcode("OP_MOD".into()));
723 });
724
725 t.to_top("_bit");
728 t.nm.pop(); let add_ops = collect_ops(|add_emit| {
730 build_jacobian_add_affine_inline(add_emit, &t);
731 });
732 (t.e)(StackOp::If {
733 then_ops: add_ops,
734 else_ops: vec![],
735 });
736 }
737
738 jacobian_to_affine(&mut t, "_rx", "_ry");
740
741 t.to_top("ax"); t.drop();
743 t.to_top("ay"); t.drop();
744 t.to_top("_k"); t.drop();
745
746 compose_point(&mut t, "_rx", "_ry", "_result");
748}
749
750pub fn emit_ec_mul_gen(emit: &mut dyn FnMut(StackOp)) {
754 let mut g_point = Vec::with_capacity(64);
756 g_point.extend_from_slice(&GEN_X_BYTES);
757 g_point.extend_from_slice(&GEN_Y_BYTES);
758 emit(StackOp::Push(PushValue::Bytes(g_point)));
759 emit(StackOp::Swap); emit_ec_mul(emit);
761}
762
763pub fn emit_ec_negate(emit: &mut dyn FnMut(StackOp)) {
767 let mut t = ECTracker::new(&["_pt"], emit);
768 decompose_point(&mut t, "_pt", "_nx", "_ny");
769 push_field_p(&mut t, "_fp");
770 field_sub(&mut t, "_fp", "_ny", "_neg_y");
771 compose_point(&mut t, "_nx", "_neg_y", "_result");
772}
773
774pub fn emit_ec_on_curve(emit: &mut dyn FnMut(StackOp)) {
778 let mut t = ECTracker::new(&["_pt"], emit);
779 decompose_point(&mut t, "_pt", "_x", "_y");
780
781 field_sqr(&mut t, "_y", "_y2");
783
784 t.copy_to_top("_x", "_x_copy");
786 field_sqr(&mut t, "_x", "_x2");
787 field_mul(&mut t, "_x2", "_x_copy", "_x3");
788 t.push_int("_seven", 7);
789 field_add(&mut t, "_x3", "_seven", "_rhs");
790
791 t.to_top("_y2");
793 t.to_top("_rhs");
794 t.raw_block(&["_y2", "_rhs"], Some("_result"), |e| {
795 e(StackOp::Opcode("OP_EQUAL".into()));
796 });
797}
798
799pub fn emit_ec_mod_reduce(emit: &mut dyn FnMut(StackOp)) {
803 emit(StackOp::Opcode("OP_2DUP".into()));
804 emit(StackOp::Opcode("OP_MOD".into()));
805 emit(StackOp::Rot);
806 emit(StackOp::Drop);
807 emit(StackOp::Over);
808 emit(StackOp::Opcode("OP_ADD".into()));
809 emit(StackOp::Swap);
810 emit(StackOp::Opcode("OP_MOD".into()));
811}
812
813pub fn emit_ec_encode_compressed(emit: &mut dyn FnMut(StackOp)) {
817 emit(StackOp::Push(PushValue::Int(32)));
819 emit(StackOp::Opcode("OP_SPLIT".into()));
820 emit(StackOp::Opcode("OP_SIZE".into()));
822 emit(StackOp::Push(PushValue::Int(1)));
823 emit(StackOp::Opcode("OP_SUB".into()));
824 emit(StackOp::Opcode("OP_SPLIT".into()));
825 emit(StackOp::Opcode("OP_BIN2NUM".into()));
827 emit(StackOp::Push(PushValue::Int(2)));
828 emit(StackOp::Opcode("OP_MOD".into()));
829 emit(StackOp::Swap);
831 emit(StackOp::Drop); emit(StackOp::If {
834 then_ops: vec![StackOp::Push(PushValue::Bytes(vec![0x03]))],
835 else_ops: vec![StackOp::Push(PushValue::Bytes(vec![0x02]))],
836 });
837 emit(StackOp::Swap);
839 emit(StackOp::Opcode("OP_CAT".into()));
840}
841
842pub fn emit_ec_make_point(emit: &mut dyn FnMut(StackOp)) {
846 emit(StackOp::Push(PushValue::Int(33)));
848 emit(StackOp::Opcode("OP_NUM2BIN".into()));
849 emit(StackOp::Push(PushValue::Int(32)));
850 emit(StackOp::Opcode("OP_SPLIT".into()));
851 emit(StackOp::Drop);
852 emit_reverse_32(emit);
853 emit(StackOp::Swap);
855 emit(StackOp::Push(PushValue::Int(33)));
857 emit(StackOp::Opcode("OP_NUM2BIN".into()));
858 emit(StackOp::Push(PushValue::Int(32)));
859 emit(StackOp::Opcode("OP_SPLIT".into()));
860 emit(StackOp::Drop);
861 emit_reverse_32(emit);
862 emit(StackOp::Swap);
864 emit(StackOp::Opcode("OP_CAT".into()));
866}
867
868pub fn emit_ec_point_x(emit: &mut dyn FnMut(StackOp)) {
872 emit(StackOp::Push(PushValue::Int(32)));
873 emit(StackOp::Opcode("OP_SPLIT".into()));
874 emit(StackOp::Drop);
875 emit_reverse_32(emit);
876 emit(StackOp::Push(PushValue::Bytes(vec![0x00])));
878 emit(StackOp::Opcode("OP_CAT".into()));
879 emit(StackOp::Opcode("OP_BIN2NUM".into()));
880}
881
882pub fn emit_ec_point_y(emit: &mut dyn FnMut(StackOp)) {
886 emit(StackOp::Push(PushValue::Int(32)));
887 emit(StackOp::Opcode("OP_SPLIT".into()));
888 emit(StackOp::Swap);
889 emit(StackOp::Drop);
890 emit_reverse_32(emit);
891 emit(StackOp::Push(PushValue::Bytes(vec![0x00])));
893 emit(StackOp::Opcode("OP_CAT".into()));
894 emit(StackOp::Opcode("OP_BIN2NUM".into()));
895}
896
897fn script_number_pow2(n: usize) -> Vec<u8> {
906 let byte_idx = n / 8;
913 let bit_pos = n % 8;
914 let min_len = byte_idx + 1;
915 let needs_sign_byte = bit_pos == 7;
916 let total_len = if needs_sign_byte { min_len + 1 } else { min_len };
917
918 let mut bytes = vec![0u8; total_len];
919 bytes[byte_idx] = 1 << bit_pos;
920 bytes
923}