1use blake2::Blake2bVar;
2use blake2::digest::{Update, VariableOutput};
3use hns_transaction::{Address, Coin, Transaction, Witness};
4use k256::ecdsa::signature::hazmat::PrehashVerifier;
5use k256::ecdsa::{Signature, VerifyingKey};
6use ripemd::Ripemd160;
7use sha1::Sha1;
8use sha2::{Digest, Sha256};
9use sha3::{Keccak256, Sha3_256};
10use thiserror::Error;
11
12use crate::{
13 is_valid_signature_hash_type, signature_hash, verify_locktime_predicate,
14 verify_sequence_predicate,
15};
16
17pub const MAX_SCRIPT_SIZE: usize = 10_000;
19pub const MAX_SCRIPT_PUSH: usize = 520;
21pub const MAX_SCRIPT_OPS: usize = 201;
23pub const MAX_SCRIPT_STACK: usize = 1_000;
25pub const MAX_MULTISIG_PUBKEYS: usize = 20;
27
28pub const OP_0: u8 = 0x00;
29pub const OP_PUSHDATA1: u8 = 0x4c;
30pub const OP_PUSHDATA2: u8 = 0x4d;
31pub const OP_PUSHDATA4: u8 = 0x4e;
32pub const OP_1NEGATE: u8 = 0x4f;
33pub const OP_RESERVED: u8 = 0x50;
34pub const OP_1: u8 = 0x51;
35pub const OP_2: u8 = 0x52;
36pub const OP_3: u8 = 0x53;
37pub const OP_4: u8 = 0x54;
38pub const OP_5: u8 = 0x55;
39pub const OP_6: u8 = 0x56;
40pub const OP_7: u8 = 0x57;
41pub const OP_8: u8 = 0x58;
42pub const OP_9: u8 = 0x59;
43pub const OP_10: u8 = 0x5a;
44pub const OP_11: u8 = 0x5b;
45pub const OP_12: u8 = 0x5c;
46pub const OP_13: u8 = 0x5d;
47pub const OP_14: u8 = 0x5e;
48pub const OP_15: u8 = 0x5f;
49pub const OP_16: u8 = 0x60;
50pub const OP_NOP: u8 = 0x61;
51pub const OP_VER: u8 = 0x62;
52pub const OP_IF: u8 = 0x63;
53pub const OP_NOTIF: u8 = 0x64;
54pub const OP_VERIF: u8 = 0x65;
55pub const OP_VERNOTIF: u8 = 0x66;
56pub const OP_ELSE: u8 = 0x67;
57pub const OP_ENDIF: u8 = 0x68;
58pub const OP_VERIFY: u8 = 0x69;
59pub const OP_RETURN: u8 = 0x6a;
60pub const OP_TOALTSTACK: u8 = 0x6b;
61pub const OP_FROMALTSTACK: u8 = 0x6c;
62pub const OP_2DROP: u8 = 0x6d;
63pub const OP_2DUP: u8 = 0x6e;
64pub const OP_3DUP: u8 = 0x6f;
65pub const OP_2OVER: u8 = 0x70;
66pub const OP_2ROT: u8 = 0x71;
67pub const OP_2SWAP: u8 = 0x72;
68pub const OP_IFDUP: u8 = 0x73;
69pub const OP_DEPTH: u8 = 0x74;
70pub const OP_DROP: u8 = 0x75;
71pub const OP_DUP: u8 = 0x76;
72pub const OP_NIP: u8 = 0x77;
73pub const OP_OVER: u8 = 0x78;
74pub const OP_PICK: u8 = 0x79;
75pub const OP_ROLL: u8 = 0x7a;
76pub const OP_ROT: u8 = 0x7b;
77pub const OP_SWAP: u8 = 0x7c;
78pub const OP_TUCK: u8 = 0x7d;
79pub const OP_CAT: u8 = 0x7e;
80pub const OP_SUBSTR: u8 = 0x7f;
81pub const OP_LEFT: u8 = 0x80;
82pub const OP_RIGHT: u8 = 0x81;
83pub const OP_SIZE: u8 = 0x82;
84pub const OP_INVERT: u8 = 0x83;
85pub const OP_AND: u8 = 0x84;
86pub const OP_OR: u8 = 0x85;
87pub const OP_XOR: u8 = 0x86;
88pub const OP_EQUAL: u8 = 0x87;
89pub const OP_EQUALVERIFY: u8 = 0x88;
90pub const OP_RESERVED1: u8 = 0x89;
91pub const OP_RESERVED2: u8 = 0x8a;
92pub const OP_1ADD: u8 = 0x8b;
93pub const OP_1SUB: u8 = 0x8c;
94pub const OP_2MUL: u8 = 0x8d;
95pub const OP_2DIV: u8 = 0x8e;
96pub const OP_NEGATE: u8 = 0x8f;
97pub const OP_ABS: u8 = 0x90;
98pub const OP_NOT: u8 = 0x91;
99pub const OP_0NOTEQUAL: u8 = 0x92;
100pub const OP_ADD: u8 = 0x93;
101pub const OP_SUB: u8 = 0x94;
102pub const OP_MUL: u8 = 0x95;
103pub const OP_DIV: u8 = 0x96;
104pub const OP_MOD: u8 = 0x97;
105pub const OP_LSHIFT: u8 = 0x98;
106pub const OP_RSHIFT: u8 = 0x99;
107pub const OP_BOOLAND: u8 = 0x9a;
108pub const OP_BOOLOR: u8 = 0x9b;
109pub const OP_NUMEQUAL: u8 = 0x9c;
110pub const OP_NUMEQUALVERIFY: u8 = 0x9d;
111pub const OP_NUMNOTEQUAL: u8 = 0x9e;
112pub const OP_LESSTHAN: u8 = 0x9f;
113pub const OP_GREATERTHAN: u8 = 0xa0;
114pub const OP_LESSTHANOREQUAL: u8 = 0xa1;
115pub const OP_GREATERTHANOREQUAL: u8 = 0xa2;
116pub const OP_MIN: u8 = 0xa3;
117pub const OP_MAX: u8 = 0xa4;
118pub const OP_WITHIN: u8 = 0xa5;
119pub const OP_RIPEMD160: u8 = 0xa6;
120pub const OP_SHA1: u8 = 0xa7;
121pub const OP_SHA256: u8 = 0xa8;
122pub const OP_HASH160: u8 = 0xa9;
123pub const OP_HASH256: u8 = 0xaa;
124pub const OP_CODESEPARATOR: u8 = 0xab;
125pub const OP_CHECKSIG: u8 = 0xac;
126pub const OP_CHECKSIGVERIFY: u8 = 0xad;
127pub const OP_CHECKMULTISIG: u8 = 0xae;
128pub const OP_CHECKMULTISIGVERIFY: u8 = 0xaf;
129pub const OP_NOP1: u8 = 0xb0;
130pub const OP_CHECKLOCKTIMEVERIFY: u8 = 0xb1;
131pub const OP_CHECKSEQUENCEVERIFY: u8 = 0xb2;
132pub const OP_NOP4: u8 = 0xb3;
133pub const OP_NOP5: u8 = 0xb4;
134pub const OP_NOP6: u8 = 0xb5;
135pub const OP_NOP7: u8 = 0xb6;
136pub const OP_NOP8: u8 = 0xb7;
137pub const OP_NOP9: u8 = 0xb8;
138pub const OP_NOP10: u8 = 0xb9;
139pub const OP_BLAKE160: u8 = 0xc0;
140pub const OP_BLAKE256: u8 = 0xc1;
141pub const OP_SHA3: u8 = 0xc2;
142pub const OP_KECCAK: u8 = 0xc3;
143pub const OP_TYPE: u8 = 0xd0;
144pub const OP_INVALIDOPCODE: u8 = 0xff;
145
146#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
147pub struct ScriptFlags(u32);
148
149impl ScriptFlags {
150 pub const NONE: Self = Self(0);
151 pub const VERIFY_MINIMAL_DATA: Self = Self(1 << 1);
152 pub const VERIFY_DISCOURAGE_UPGRADABLE_NOPS: Self = Self(1 << 2);
153 pub const VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM: Self = Self(1 << 3);
154 pub const VERIFY_MINIMAL_IF: Self = Self(1 << 4);
155 pub const VERIFY_NULLFAIL: Self = Self(1 << 5);
156 pub const MANDATORY: Self =
157 Self(Self::VERIFY_MINIMAL_DATA.0 | Self::VERIFY_MINIMAL_IF.0 | Self::VERIFY_NULLFAIL.0);
158 pub const STANDARD: Self = Self(
159 Self::MANDATORY.0
160 | Self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS.0
161 | Self::VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM.0,
162 );
163
164 pub const fn contains(self, other: Self) -> bool {
165 self.0 & other.0 == other.0
166 }
167
168 pub const fn from_bits(bits: u32) -> Self {
169 Self(bits)
170 }
171
172 pub const fn bits(self) -> u32 {
173 self.0
174 }
175
176 pub const fn union(self, other: Self) -> Self {
177 Self(self.0 | other.0)
178 }
179}
180
181#[derive(Clone, Debug, Eq, PartialEq)]
183pub struct Instruction {
184 pub opcode: u8,
185 pub data: Option<Vec<u8>>,
186 pub start: usize,
187 pub end: usize,
188}
189
190pub fn parse_script(script: &[u8]) -> Result<Vec<Instruction>, ScriptError> {
194 if script.len() > MAX_SCRIPT_SIZE {
195 return Err(ScriptError::ScriptSize);
196 }
197
198 let mut instructions = Vec::new();
199 let mut offset = 0usize;
200 while offset < script.len() {
201 let start = offset;
202 let opcode = script[offset];
203 offset += 1;
204 let data_len = match opcode {
205 0x01..=0x4b => Some(usize::from(opcode)),
206 OP_PUSHDATA1 => Some(usize::from(read_u8(script, &mut offset)?)),
207 OP_PUSHDATA2 => Some(usize::from(read_u16(script, &mut offset)?)),
208 OP_PUSHDATA4 => Some(
209 usize::try_from(read_u32(script, &mut offset)?)
210 .map_err(|_| ScriptError::BadOpcode(opcode))?,
211 ),
212 _ => None,
213 };
214 let data = if let Some(data_len) = data_len {
215 let end = offset
216 .checked_add(data_len)
217 .filter(|end| *end <= script.len())
218 .ok_or(ScriptError::BadOpcode(opcode))?;
219 let data = script[offset..end].to_vec();
220 offset = end;
221 Some(data)
222 } else {
223 None
224 };
225 instructions.push(Instruction {
226 opcode,
227 data,
228 start,
229 end: offset,
230 });
231 }
232 Ok(instructions)
233}
234
235pub fn count_script_sigops(script: &[u8]) -> u32 {
238 let mut total = 0u32;
239 let mut offset = 0usize;
240 let mut last_opcode = None;
241
242 while offset < script.len() {
243 let opcode = script[offset];
244 offset += 1;
245 let data_length = match opcode {
246 0x01..=0x4b => Some(usize::from(opcode)),
247 OP_PUSHDATA1 => {
248 let Some(length) = script.get(offset).copied() else {
249 break;
250 };
251 offset += 1;
252 Some(usize::from(length))
253 }
254 OP_PUSHDATA2 => {
255 let Some(bytes) = script.get(offset..offset.saturating_add(2)) else {
256 break;
257 };
258 let Ok(bytes) = <[u8; 2]>::try_from(bytes) else {
259 break;
260 };
261 offset += 2;
262 Some(usize::from(u16::from_le_bytes(bytes)))
263 }
264 OP_PUSHDATA4 => {
265 let Some(bytes) = script.get(offset..offset.saturating_add(4)) else {
266 break;
267 };
268 let Ok(bytes) = <[u8; 4]>::try_from(bytes) else {
269 break;
270 };
271 offset += 4;
272 let Ok(length) = usize::try_from(u32::from_le_bytes(bytes)) else {
273 break;
274 };
275 Some(length)
276 }
277 _ => None,
278 };
279 if let Some(data_length) = data_length {
280 let Some(end) = offset.checked_add(data_length) else {
281 break;
282 };
283 if end > script.len() {
284 break;
285 }
286 offset = end;
287 }
288
289 match opcode {
290 OP_CHECKSIG | OP_CHECKSIGVERIFY => total = total.saturating_add(1),
291 OP_CHECKMULTISIG | OP_CHECKMULTISIGVERIFY => {
292 let sigops = match last_opcode {
293 Some(opcode @ OP_1..=OP_16) => u32::from(opcode - 0x50),
294 _ => MAX_MULTISIG_PUBKEYS as u32,
295 };
296 total = total.saturating_add(sigops);
297 }
298 _ => {}
299 }
300 last_opcode = Some(opcode);
301 }
302 total
303}
304
305pub fn witness_program_sigops(address: &Address, witness: &Witness) -> u32 {
306 if address.version != 0 {
307 return 0;
308 }
309 match address.hash.len() {
310 20 => 1,
311 32 => witness
312 .items
313 .last()
314 .map_or(0, |script| count_script_sigops(script)),
315 _ => 0,
316 }
317}
318
319pub fn transaction_sigops(
320 transaction: &Transaction,
321 input_coins: &[Coin],
322) -> Result<u32, ScriptError> {
323 if transaction.is_coinbase() {
324 return Ok(0);
325 }
326 if transaction.inputs.len() != input_coins.len() {
327 return Err(ScriptError::InputCoinCount {
328 inputs: transaction.inputs.len(),
329 coins: input_coins.len(),
330 });
331 }
332
333 transaction
334 .inputs
335 .iter()
336 .zip(input_coins)
337 .try_fold(0u32, |total, (input, coin)| {
338 if input.previous_output != coin.outpoint {
339 return Err(ScriptError::InputCoinMismatch);
340 }
341 Ok(total.saturating_add(witness_program_sigops(&coin.address, &input.witness)))
342 })
343}
344
345pub trait SignatureVerifier: Send + Sync {
348 fn validate_compact_signature(&self, signature: &[u8; 64]) -> Result<(), ScriptError>;
349
350 fn verify(
351 &self,
352 message: &[u8; 32],
353 signature: &[u8; 64],
354 public_key: &[u8; 33],
355 ) -> Result<bool, ScriptError>;
356
357 fn is_consensus_complete(&self) -> bool {
358 false
359 }
360}
361
362#[derive(Clone, Copy, Debug, Default)]
365pub struct UnavailableSignatureVerifier;
366
367impl SignatureVerifier for UnavailableSignatureVerifier {
368 fn validate_compact_signature(&self, _signature: &[u8; 64]) -> Result<(), ScriptError> {
369 Err(ScriptError::SignatureBackendUnavailable)
370 }
371
372 fn verify(
373 &self,
374 _message: &[u8; 32],
375 _signature: &[u8; 64],
376 _public_key: &[u8; 33],
377 ) -> Result<bool, ScriptError> {
378 Err(ScriptError::SignatureBackendUnavailable)
379 }
380}
381
382#[derive(Clone, Copy, Debug, Default)]
384pub struct K256SignatureVerifier;
385
386impl SignatureVerifier for K256SignatureVerifier {
387 fn validate_compact_signature(&self, signature: &[u8; 64]) -> Result<(), ScriptError> {
388 let signature =
389 Signature::from_slice(signature).map_err(|_| ScriptError::SignatureEncoding)?;
390 if signature.normalize_s().is_some() {
391 return Err(ScriptError::SignatureEncoding);
392 }
393 Ok(())
394 }
395
396 fn verify(
397 &self,
398 message: &[u8; 32],
399 signature: &[u8; 64],
400 public_key: &[u8; 33],
401 ) -> Result<bool, ScriptError> {
402 let signature =
403 Signature::from_slice(signature).map_err(|_| ScriptError::SignatureEncoding)?;
404 let public_key = VerifyingKey::from_sec1_bytes(public_key)
405 .map_err(|_| ScriptError::PublicKeyEncoding)?;
406 Ok(public_key.verify_prehash(message, &signature).is_ok())
407 }
408
409 fn is_consensus_complete(&self) -> bool {
410 true
411 }
412}
413
414pub fn verify_witness_program(
415 transaction: &Transaction,
416 input_index: usize,
417 coin: &Coin,
418 flags: ScriptFlags,
419 signatures: &dyn SignatureVerifier,
420) -> Result<(), ScriptError> {
421 let input = transaction
422 .inputs
423 .get(input_index)
424 .ok_or(ScriptError::InputIndex {
425 requested: input_index,
426 inputs: transaction.inputs.len(),
427 })?;
428 if input.previous_output != coin.outpoint {
429 return Err(ScriptError::InputCoinMismatch);
430 }
431 let address = &coin.address;
432
433 if address.version == 31 {
434 return Err(ScriptError::OpReturn);
435 }
436 if input.witness.items.len() > MAX_SCRIPT_STACK {
437 return Err(ScriptError::StackSize);
438 }
439
440 let mut stack = input.witness.items.clone();
441 let redeem = if address.version == 0 {
442 match address.hash.len() {
443 32 => {
444 let witness_script = stack.pop().ok_or(ScriptError::WitnessProgramWitnessEmpty)?;
445 if witness_script.len() > MAX_SCRIPT_SIZE {
446 return Err(ScriptError::ScriptSize);
447 }
448 if sha3_256(&witness_script).as_slice() != address.hash.as_slice() {
449 return Err(ScriptError::WitnessProgramMismatch);
450 }
451 witness_script
452 }
453 20 => {
454 if stack.len() != 2 {
455 return Err(ScriptError::WitnessProgramMismatch);
456 }
457 pubkey_hash_script(&address.hash)
458 }
459 _ => return Err(ScriptError::WitnessProgramWrongLength),
460 }
461 } else {
462 if flags.contains(ScriptFlags::VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) {
463 return Err(ScriptError::DiscourageUpgradableWitnessProgram);
464 }
465 return Ok(());
466 };
467
468 execute_script(
469 &redeem,
470 &mut stack,
471 transaction,
472 input_index,
473 coin.value.get(),
474 flags,
475 signatures,
476 )?;
477
478 if stack.len() != 1 || !cast_to_bool(&stack[0]) {
479 return Err(ScriptError::EvalFalse);
480 }
481 Ok(())
482}
483
484fn pubkey_hash_script(hash: &[u8]) -> Vec<u8> {
485 let mut script = Vec::with_capacity(25);
486 script.extend_from_slice(&[OP_DUP, OP_BLAKE160, 20]);
487 script.extend_from_slice(hash);
488 script.extend_from_slice(&[OP_EQUALVERIFY, OP_CHECKSIG]);
489 script
490}
491
492#[allow(clippy::too_many_lines)]
496pub fn execute_script(
497 script: &[u8],
498 stack: &mut Vec<Vec<u8>>,
499 transaction: &Transaction,
500 input_index: usize,
501 previous_value: u64,
502 flags: ScriptFlags,
503 signatures: &dyn SignatureVerifier,
504) -> Result<(), ScriptError> {
505 if transaction.inputs.get(input_index).is_none() {
506 return Err(ScriptError::InputIndex {
507 requested: input_index,
508 inputs: transaction.inputs.len(),
509 });
510 }
511 if stack.len() > MAX_SCRIPT_STACK {
512 return Err(ScriptError::StackSize);
513 }
514 if stack.iter().any(|item| item.len() > MAX_SCRIPT_PUSH) {
515 return Err(ScriptError::PushSize);
516 }
517
518 let instructions = parse_script(script)?;
519 let mut alt_stack = Vec::<Vec<u8>>::new();
520 let mut conditions = Vec::<bool>::new();
521 let mut operation_count = 0usize;
522 let mut last_separator = 0usize;
523
524 for instruction in instructions {
525 if instruction
526 .data
527 .as_ref()
528 .is_some_and(|data| data.len() > MAX_SCRIPT_PUSH)
529 {
530 return Err(ScriptError::PushSize);
531 }
532 if instruction.opcode > OP_16 {
533 operation_count = operation_count
534 .checked_add(1)
535 .ok_or(ScriptError::OperationCount)?;
536 if operation_count > MAX_SCRIPT_OPS {
537 return Err(ScriptError::OperationCount);
538 }
539 }
540 if is_disabled_opcode(instruction.opcode) {
541 return Err(ScriptError::DisabledOpcode(instruction.opcode));
542 }
543
544 let executing = conditions.iter().all(|condition| *condition);
545 let is_branch = (OP_IF..=OP_ENDIF).contains(&instruction.opcode);
546 if !executing && !is_branch {
547 enforce_stack_limit(stack, &alt_stack)?;
548 continue;
549 }
550
551 if let Some(data) = instruction.data {
552 if flags.contains(ScriptFlags::VERIFY_MINIMAL_DATA)
553 && !is_minimal_push(instruction.opcode, &data)
554 {
555 return Err(ScriptError::MinimalData);
556 }
557 stack.push(data);
558 enforce_stack_limit(stack, &alt_stack)?;
559 continue;
560 }
561
562 match instruction.opcode {
563 OP_0 => stack.push(Vec::new()),
564 OP_1NEGATE => stack.push(encode_script_number(-1)),
565 OP_1..=OP_16 => {
566 stack.push(encode_script_number(i64::from(
567 instruction.opcode - OP_1 + 1,
568 )));
569 }
570 OP_NOP => {}
571 OP_TYPE => {
572 let covenant_type = transaction
573 .outputs
574 .get(input_index)
575 .map(|output| i64::from(output.covenant.kind.as_u8()))
576 .unwrap_or(0);
577 stack.push(encode_script_number(covenant_type));
578 }
579 OP_CHECKLOCKTIMEVERIFY => {
580 let value = decode_top_number(stack, flags, 5)?;
581 if value < 0 {
582 return Err(ScriptError::NegativeLocktime);
583 }
584 let predicate =
585 u32::try_from(value).map_err(|_| ScriptError::UnsatisfiedLocktime)?;
586 if !verify_locktime_predicate(transaction, input_index, predicate) {
587 return Err(ScriptError::UnsatisfiedLocktime);
588 }
589 }
590 OP_CHECKSEQUENCEVERIFY => {
591 let value = decode_top_number(stack, flags, 5)?;
592 if value < 0 {
593 return Err(ScriptError::NegativeLocktime);
594 }
595 let predicate =
596 u32::try_from(value).map_err(|_| ScriptError::UnsatisfiedLocktime)?;
597 if !verify_sequence_predicate(transaction, input_index, predicate) {
598 return Err(ScriptError::UnsatisfiedLocktime);
599 }
600 }
601 opcode if opcode == OP_NOP1 || (OP_NOP4..=OP_NOP10).contains(&opcode) => {
602 if flags.contains(ScriptFlags::VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
603 return Err(ScriptError::DiscourageUpgradableNops);
604 }
605 }
606 OP_IF | OP_NOTIF => {
607 let parent_executing = conditions.iter().all(|condition| *condition);
608 let mut value = false;
609 if parent_executing {
610 let item = stack.pop().ok_or(ScriptError::UnbalancedConditional)?;
611 if flags.contains(ScriptFlags::VERIFY_MINIMAL_IF)
612 && !(item.is_empty() || item.as_slice() == [1u8])
613 {
614 return Err(ScriptError::MinimalIf);
615 }
616 value = cast_to_bool(&item);
617 if instruction.opcode == OP_NOTIF {
618 value = !value;
619 }
620 }
621 conditions.push(value);
622 }
623 OP_ELSE => {
624 let Some(condition) = conditions.last_mut() else {
625 return Err(ScriptError::UnbalancedConditional);
626 };
627 *condition = !*condition;
628 }
629 OP_ENDIF => {
630 conditions.pop().ok_or(ScriptError::UnbalancedConditional)?;
631 }
632 OP_VERIFY => {
633 if !cast_to_bool(&pop(stack)?) {
634 return Err(ScriptError::Verify);
635 }
636 }
637 OP_RETURN => return Err(ScriptError::OpReturn),
638 OP_TOALTSTACK => alt_stack.push(pop(stack)?),
639 OP_FROMALTSTACK => {
640 let item = alt_stack
641 .pop()
642 .ok_or(ScriptError::InvalidAltStackOperation)?;
643 stack.push(item);
644 }
645 OP_2DROP => {
646 require_stack(stack, 2)?;
647 stack.truncate(stack.len() - 2);
648 }
649 OP_2DUP => duplicate_tail(stack, 2)?,
650 OP_3DUP => duplicate_tail(stack, 3)?,
651 OP_2OVER => {
652 require_stack(stack, 4)?;
653 let len = stack.len();
654 let values = stack[len - 4..len - 2].to_vec();
655 stack.extend(values);
656 }
657 OP_2ROT => {
658 require_stack(stack, 6)?;
659 let len = stack.len();
660 let first = stack.remove(len - 6);
661 let second = stack.remove(len - 6);
662 stack.push(first);
663 stack.push(second);
664 }
665 OP_2SWAP => {
666 require_stack(stack, 4)?;
667 let len = stack.len();
668 stack.swap(len - 4, len - 2);
669 stack.swap(len - 3, len - 1);
670 }
671 OP_IFDUP => {
672 let value = stack.last().ok_or(ScriptError::InvalidStackOperation)?;
673 if cast_to_bool(value) {
674 stack.push(value.clone());
675 }
676 }
677 OP_DEPTH => stack.push(encode_script_number(stack.len() as i64)),
678 OP_DROP => {
679 pop(stack)?;
680 }
681 OP_DUP => duplicate_tail(stack, 1)?,
682 OP_NIP => {
683 require_stack(stack, 2)?;
684 let len = stack.len();
685 stack.remove(len - 2);
686 }
687 OP_OVER => {
688 require_stack(stack, 2)?;
689 let len = stack.len();
690 stack.push(stack[len - 2].clone());
691 }
692 OP_PICK | OP_ROLL => {
693 let depth = decode_script_number(&pop(stack)?, minimal_numbers(flags), 4)?;
694 let depth =
695 usize::try_from(depth).map_err(|_| ScriptError::InvalidStackOperation)?;
696 if depth >= stack.len() {
697 return Err(ScriptError::InvalidStackOperation);
698 }
699 let index = stack.len() - 1 - depth;
700 let item = if instruction.opcode == OP_ROLL {
701 stack.remove(index)
702 } else {
703 stack[index].clone()
704 };
705 stack.push(item);
706 }
707 OP_ROT => {
708 require_stack(stack, 3)?;
709 let len = stack.len();
710 let item = stack.remove(len - 3);
711 stack.push(item);
712 }
713 OP_SWAP => {
714 require_stack(stack, 2)?;
715 let len = stack.len();
716 stack.swap(len - 2, len - 1);
717 }
718 OP_TUCK => {
719 require_stack(stack, 2)?;
720 let len = stack.len();
721 let item = stack[len - 1].clone();
722 stack.insert(len - 2, item);
723 }
724 OP_SIZE => {
725 let size = stack
726 .last()
727 .ok_or(ScriptError::InvalidStackOperation)?
728 .len();
729 stack.push(encode_script_number(size as i64));
730 }
731 OP_EQUAL | OP_EQUALVERIFY => {
732 require_stack(stack, 2)?;
733 let right = pop(stack)?;
734 let left = pop(stack)?;
735 let equal = left == right;
736 if instruction.opcode == OP_EQUALVERIFY {
737 if !equal {
738 return Err(ScriptError::EqualVerify);
739 }
740 } else {
741 push_bool(stack, equal);
742 }
743 }
744 OP_1ADD | OP_1SUB | OP_NEGATE | OP_ABS | OP_NOT | OP_0NOTEQUAL => {
745 let value = decode_script_number(&pop(stack)?, minimal_numbers(flags), 4)?;
746 let result = match instruction.opcode {
747 OP_1ADD => value.checked_add(1),
748 OP_1SUB => value.checked_sub(1),
749 OP_NEGATE => value.checked_neg(),
750 OP_ABS => value.checked_abs(),
751 OP_NOT => Some(i64::from(value == 0)),
752 OP_0NOTEQUAL => Some(i64::from(value != 0)),
753 _ => None,
754 }
755 .ok_or(ScriptError::NumericOverflow)?;
756 stack.push(encode_script_number(result));
757 }
758 OP_ADD
759 | OP_SUB
760 | OP_BOOLAND
761 | OP_BOOLOR
762 | OP_NUMEQUAL
763 | OP_NUMEQUALVERIFY
764 | OP_NUMNOTEQUAL
765 | OP_LESSTHAN
766 | OP_GREATERTHAN
767 | OP_LESSTHANOREQUAL
768 | OP_GREATERTHANOREQUAL
769 | OP_MIN
770 | OP_MAX => {
771 require_stack(stack, 2)?;
772 let right = decode_script_number(&pop(stack)?, minimal_numbers(flags), 4)?;
773 let left = decode_script_number(&pop(stack)?, minimal_numbers(flags), 4)?;
774 let result = match instruction.opcode {
775 OP_ADD => left
776 .checked_add(right)
777 .ok_or(ScriptError::NumericOverflow)?,
778 OP_SUB => left
779 .checked_sub(right)
780 .ok_or(ScriptError::NumericOverflow)?,
781 OP_BOOLAND => i64::from(left != 0 && right != 0),
782 OP_BOOLOR => i64::from(left != 0 || right != 0),
783 OP_NUMEQUAL | OP_NUMEQUALVERIFY => i64::from(left == right),
784 OP_NUMNOTEQUAL => i64::from(left != right),
785 OP_LESSTHAN => i64::from(left < right),
786 OP_GREATERTHAN => i64::from(left > right),
787 OP_LESSTHANOREQUAL => i64::from(left <= right),
788 OP_GREATERTHANOREQUAL => i64::from(left >= right),
789 OP_MIN => left.min(right),
790 OP_MAX => left.max(right),
791 _ => unreachable!(),
792 };
793 if instruction.opcode == OP_NUMEQUALVERIFY {
794 if result == 0 {
795 return Err(ScriptError::NumEqualVerify);
796 }
797 } else {
798 stack.push(encode_script_number(result));
799 }
800 }
801 OP_WITHIN => {
802 require_stack(stack, 3)?;
803 let maximum = decode_script_number(&pop(stack)?, minimal_numbers(flags), 4)?;
804 let minimum = decode_script_number(&pop(stack)?, minimal_numbers(flags), 4)?;
805 let value = decode_script_number(&pop(stack)?, minimal_numbers(flags), 4)?;
806 push_bool(stack, minimum <= value && value < maximum);
807 }
808 OP_BLAKE160 | OP_BLAKE256 | OP_SHA3 | OP_KECCAK => {
809 let item = pop(stack)?;
810 let digest = match instruction.opcode {
811 OP_BLAKE160 => blake2b_160(&item).to_vec(),
812 OP_BLAKE256 => blake2b_256(&item).to_vec(),
813 OP_SHA3 => sha3_256(&item).to_vec(),
814 OP_KECCAK => Keccak256::digest(&item).to_vec(),
815 _ => unreachable!(),
816 };
817 stack.push(digest);
818 }
819 OP_RIPEMD160 | OP_SHA1 | OP_SHA256 | OP_HASH160 | OP_HASH256 => {
820 let item = pop(stack)?;
821 let digest = match instruction.opcode {
822 OP_RIPEMD160 => Ripemd160::digest(&item).to_vec(),
823 OP_SHA1 => Sha1::digest(&item).to_vec(),
824 OP_SHA256 => Sha256::digest(&item).to_vec(),
825 OP_HASH160 => Ripemd160::digest(Sha256::digest(&item)).to_vec(),
826 OP_HASH256 => Sha256::digest(Sha256::digest(&item)).to_vec(),
827 _ => unreachable!(),
828 };
829 stack.push(digest);
830 }
831 OP_CODESEPARATOR => last_separator = instruction.end,
832 OP_CHECKSIG | OP_CHECKSIGVERIFY => {
833 require_stack(stack, 2)?;
834 let public_key = pop(stack)?;
835 let signature = pop(stack)?;
836 let valid = check_signature(
837 transaction,
838 input_index,
839 previous_value,
840 &script[last_separator..],
841 &signature,
842 &public_key,
843 signatures,
844 )?;
845 if !valid && flags.contains(ScriptFlags::VERIFY_NULLFAIL) && !signature.is_empty() {
846 return Err(ScriptError::NullFail);
847 }
848 if instruction.opcode == OP_CHECKSIGVERIFY {
849 if !valid {
850 return Err(ScriptError::CheckSigVerify);
851 }
852 } else {
853 push_bool(stack, valid);
854 }
855 }
856 OP_CHECKMULTISIG | OP_CHECKMULTISIGVERIFY => {
857 let valid = check_multisig(
858 stack,
859 transaction,
860 input_index,
861 previous_value,
862 &script[last_separator..],
863 flags,
864 signatures,
865 &mut operation_count,
866 )?;
867 if instruction.opcode == OP_CHECKMULTISIGVERIFY {
868 if !valid {
869 return Err(ScriptError::CheckMultiSigVerify);
870 }
871 } else {
872 push_bool(stack, valid);
873 }
874 }
875 OP_RESERVED | OP_VER | OP_VERIF | OP_VERNOTIF | OP_RESERVED1 | OP_RESERVED2
876 | OP_INVALIDOPCODE => return Err(ScriptError::BadOpcode(instruction.opcode)),
877 opcode => return Err(ScriptError::BadOpcode(opcode)),
878 }
879
880 enforce_stack_limit(stack, &alt_stack)?;
881 }
882
883 if !conditions.is_empty() {
884 return Err(ScriptError::UnbalancedConditional);
885 }
886 Ok(())
887}
888
889fn check_signature(
890 transaction: &Transaction,
891 input_index: usize,
892 previous_value: u64,
893 subscript: &[u8],
894 signature: &[u8],
895 public_key: &[u8],
896 signatures: &dyn SignatureVerifier,
897) -> Result<bool, ScriptError> {
898 let compact = if signature.is_empty() {
899 None
900 } else {
901 if signature.len() != 65 || !is_valid_signature_hash_type(signature[64]) {
902 return Err(ScriptError::SignatureEncoding);
903 }
904 let compact: &[u8; 64] = signature[..64]
905 .try_into()
906 .map_err(|_| ScriptError::SignatureEncoding)?;
907 signatures.validate_compact_signature(compact)?;
908 Some(compact)
909 };
910 let public_key: &[u8; 33] = public_key
911 .try_into()
912 .map_err(|_| ScriptError::PublicKeyEncoding)?;
913 if !matches!(public_key[0], 0x02 | 0x03) {
914 return Err(ScriptError::PublicKeyEncoding);
915 }
916 let Some(compact) = compact else {
917 return Ok(false);
918 };
919 let message = signature_hash(
920 transaction,
921 input_index,
922 subscript,
923 previous_value,
924 u32::from(signature[64]),
925 )?;
926 signatures.verify(&message, compact, public_key)
927}
928
929#[allow(clippy::too_many_arguments)]
930fn check_multisig(
931 stack: &mut Vec<Vec<u8>>,
932 transaction: &Transaction,
933 input_index: usize,
934 previous_value: u64,
935 subscript: &[u8],
936 flags: ScriptFlags,
937 signatures: &dyn SignatureVerifier,
938 operation_count: &mut usize,
939) -> Result<bool, ScriptError> {
940 let key_count = decode_script_number(&pop(stack)?, minimal_numbers(flags), 4)?;
941 let key_count = usize::try_from(key_count).map_err(|_| ScriptError::PublicKeyCount)?;
942 if key_count > MAX_MULTISIG_PUBKEYS {
943 return Err(ScriptError::PublicKeyCount);
944 }
945 *operation_count = (*operation_count)
946 .checked_add(key_count)
947 .ok_or(ScriptError::OperationCount)?;
948 if *operation_count > MAX_SCRIPT_OPS {
949 return Err(ScriptError::OperationCount);
950 }
951 require_stack(stack, key_count.saturating_add(1))?;
952 let keys_start = stack.len() - key_count;
953 let keys = stack.split_off(keys_start);
954 let signature_count = decode_script_number(&pop(stack)?, minimal_numbers(flags), 4)?;
955 let signature_count =
956 usize::try_from(signature_count).map_err(|_| ScriptError::SignatureCount)?;
957 if signature_count > key_count {
958 return Err(ScriptError::SignatureCount);
959 }
960 require_stack(stack, signature_count.saturating_add(1))?;
961 let signatures_start = stack.len() - signature_count;
962 let candidate_signatures = stack.split_off(signatures_start);
963 let dummy = pop(stack)?;
964
965 let mut remaining_signatures = candidate_signatures.len();
966 let mut remaining_keys = keys.len();
967 let mut valid = true;
968 while remaining_signatures > 0 {
969 if remaining_signatures > remaining_keys {
970 valid = false;
971 break;
972 }
973 let signature = &candidate_signatures[remaining_signatures - 1];
974 let key = &keys[remaining_keys - 1];
975 if check_signature(
976 transaction,
977 input_index,
978 previous_value,
979 subscript,
980 signature,
981 key,
982 signatures,
983 )? {
984 remaining_signatures -= 1;
985 }
986 remaining_keys -= 1;
987 }
988 valid &= remaining_signatures == 0;
989
990 if !valid
991 && flags.contains(ScriptFlags::VERIFY_NULLFAIL)
992 && candidate_signatures
993 .iter()
994 .any(|signature| !signature.is_empty())
995 {
996 return Err(ScriptError::NullFail);
997 }
998 if !dummy.is_empty() {
999 return Err(ScriptError::SignatureNullDummy);
1000 }
1001 Ok(valid)
1002}
1003
1004fn read_u8(script: &[u8], offset: &mut usize) -> Result<u8, ScriptError> {
1005 let value = *script
1006 .get(*offset)
1007 .ok_or(ScriptError::BadOpcode(OP_PUSHDATA1))?;
1008 *offset += 1;
1009 Ok(value)
1010}
1011
1012fn read_u16(script: &[u8], offset: &mut usize) -> Result<u16, ScriptError> {
1013 let end = offset
1014 .checked_add(2)
1015 .filter(|end| *end <= script.len())
1016 .ok_or(ScriptError::BadOpcode(OP_PUSHDATA2))?;
1017 let bytes: [u8; 2] = script[*offset..end]
1018 .try_into()
1019 .map_err(|_| ScriptError::BadOpcode(OP_PUSHDATA2))?;
1020 *offset = end;
1021 Ok(u16::from_le_bytes(bytes))
1022}
1023
1024fn read_u32(script: &[u8], offset: &mut usize) -> Result<u32, ScriptError> {
1025 let end = offset
1026 .checked_add(4)
1027 .filter(|end| *end <= script.len())
1028 .ok_or(ScriptError::BadOpcode(OP_PUSHDATA4))?;
1029 let bytes: [u8; 4] = script[*offset..end]
1030 .try_into()
1031 .map_err(|_| ScriptError::BadOpcode(OP_PUSHDATA4))?;
1032 *offset = end;
1033 Ok(u32::from_le_bytes(bytes))
1034}
1035
1036fn is_minimal_push(opcode: u8, data: &[u8]) -> bool {
1037 if data.is_empty() {
1038 return opcode == OP_0;
1039 }
1040 if data.len() == 1 && (1..=16).contains(&data[0]) {
1041 return opcode == OP_1 + data[0] - 1;
1042 }
1043 if data == [0x81] {
1044 return opcode == OP_1NEGATE;
1045 }
1046 match data.len() {
1047 1..=75 => opcode == data.len() as u8,
1048 76..=255 => opcode == OP_PUSHDATA1,
1049 256..=65_535 => opcode == OP_PUSHDATA2,
1050 _ => opcode == OP_PUSHDATA4,
1051 }
1052}
1053
1054fn is_disabled_opcode(opcode: u8) -> bool {
1055 matches!(
1056 opcode,
1057 OP_CAT
1058 | OP_SUBSTR
1059 | OP_LEFT
1060 | OP_RIGHT
1061 | OP_INVERT
1062 | OP_AND
1063 | OP_OR
1064 | OP_XOR
1065 | OP_2MUL
1066 | OP_2DIV
1067 | OP_MUL
1068 | OP_DIV
1069 | OP_MOD
1070 | OP_LSHIFT
1071 | OP_RSHIFT
1072 )
1073}
1074
1075fn minimal_numbers(flags: ScriptFlags) -> bool {
1076 flags.contains(ScriptFlags::VERIFY_MINIMAL_DATA)
1077}
1078
1079fn decode_top_number(
1080 stack: &[Vec<u8>],
1081 flags: ScriptFlags,
1082 maximum_size: usize,
1083) -> Result<i64, ScriptError> {
1084 let item = stack.last().ok_or(ScriptError::InvalidStackOperation)?;
1085 decode_script_number(item, minimal_numbers(flags), maximum_size)
1086}
1087
1088fn decode_script_number(
1089 bytes: &[u8],
1090 require_minimal: bool,
1091 maximum_size: usize,
1092) -> Result<i64, ScriptError> {
1093 if bytes.len() > maximum_size {
1094 return Err(ScriptError::NumericOverflow);
1095 }
1096 if require_minimal && !is_minimal_script_number(bytes) {
1097 return Err(ScriptError::NonMinimalNumber);
1098 }
1099 if bytes.is_empty() {
1100 return Ok(0);
1101 }
1102
1103 let mut magnitude = 0u64;
1104 for (index, byte) in bytes.iter().copied().enumerate() {
1105 magnitude |= u64::from(byte) << (8 * index);
1106 }
1107 let sign_bit = 1u64 << (bytes.len() * 8 - 1);
1108 let negative = magnitude & sign_bit != 0;
1109 magnitude &= !sign_bit;
1110 let magnitude = i64::try_from(magnitude).map_err(|_| ScriptError::NumericOverflow)?;
1111 Ok(if negative { -magnitude } else { magnitude })
1112}
1113
1114fn encode_script_number(value: i64) -> Vec<u8> {
1115 if value == 0 {
1116 return Vec::new();
1117 }
1118
1119 let negative = value < 0;
1120 let mut magnitude = value.unsigned_abs();
1121 let mut bytes = Vec::new();
1122 while magnitude != 0 {
1123 bytes.push(magnitude as u8);
1124 magnitude >>= 8;
1125 }
1126 if bytes.last().is_some_and(|byte| byte & 0x80 != 0) {
1127 bytes.push(if negative { 0x80 } else { 0x00 });
1128 } else if negative && let Some(last) = bytes.last_mut() {
1129 *last |= 0x80;
1130 }
1131 bytes
1132}
1133
1134fn is_minimal_script_number(bytes: &[u8]) -> bool {
1135 if bytes.is_empty() {
1136 return true;
1137 }
1138 if bytes.last().is_some_and(|byte| byte & 0x7f == 0) {
1139 if bytes.len() == 1 {
1140 return false;
1141 }
1142 if bytes[bytes.len() - 2] & 0x80 == 0 {
1143 return false;
1144 }
1145 }
1146 true
1147}
1148
1149fn cast_to_bool(bytes: &[u8]) -> bool {
1150 for (index, byte) in bytes.iter().copied().enumerate() {
1151 if byte == 0 {
1152 continue;
1153 }
1154 if index == bytes.len() - 1 && byte == 0x80 {
1155 return false;
1156 }
1157 return true;
1158 }
1159 false
1160}
1161
1162fn push_bool(stack: &mut Vec<Vec<u8>>, value: bool) {
1163 stack.push(if value { vec![1] } else { Vec::new() });
1164}
1165
1166fn pop(stack: &mut Vec<Vec<u8>>) -> Result<Vec<u8>, ScriptError> {
1167 stack.pop().ok_or(ScriptError::InvalidStackOperation)
1168}
1169
1170fn require_stack(stack: &[Vec<u8>], count: usize) -> Result<(), ScriptError> {
1171 if stack.len() < count {
1172 Err(ScriptError::InvalidStackOperation)
1173 } else {
1174 Ok(())
1175 }
1176}
1177
1178fn duplicate_tail(stack: &mut Vec<Vec<u8>>, count: usize) -> Result<(), ScriptError> {
1179 require_stack(stack, count)?;
1180 let start = stack.len() - count;
1181 let values = stack[start..].to_vec();
1182 stack.extend(values);
1183 Ok(())
1184}
1185
1186fn enforce_stack_limit(stack: &[Vec<u8>], alt_stack: &[Vec<u8>]) -> Result<(), ScriptError> {
1187 if stack.len().saturating_add(alt_stack.len()) > MAX_SCRIPT_STACK {
1188 Err(ScriptError::StackSize)
1189 } else {
1190 Ok(())
1191 }
1192}
1193
1194fn blake2b_160(input: &[u8]) -> [u8; 20] {
1195 let mut hasher = Blake2bVar::new(20).expect("valid BLAKE2b output length");
1196 hasher.update(input);
1197 let mut output = [0u8; 20];
1198 hasher
1199 .finalize_variable(&mut output)
1200 .expect("valid BLAKE2b output buffer");
1201 output
1202}
1203
1204fn blake2b_256(input: &[u8]) -> [u8; 32] {
1205 let mut hasher = Blake2bVar::new(32).expect("valid BLAKE2b output length");
1206 hasher.update(input);
1207 let mut output = [0u8; 32];
1208 hasher
1209 .finalize_variable(&mut output)
1210 .expect("valid BLAKE2b output buffer");
1211 output
1212}
1213
1214fn sha3_256(input: &[u8]) -> [u8; 32] {
1215 Sha3_256::digest(input).into()
1216}
1217
1218#[derive(Debug, Error)]
1219pub enum ScriptError {
1220 #[error("signature input {requested} is outside {inputs} inputs")]
1221 InputIndex { requested: usize, inputs: usize },
1222 #[error("invalid signature hash type 0x{0:08x}")]
1223 InvalidSignatureHashType(u32),
1224 #[error(transparent)]
1225 Transaction(#[from] hns_transaction::TransactionError),
1226 #[error("resolved input count {coins} does not match transaction input count {inputs}")]
1227 InputCoinCount { inputs: usize, coins: usize },
1228 #[error("resolved input coin does not match the transaction outpoint")]
1229 InputCoinMismatch,
1230 #[error("OP_RETURN")]
1231 OpReturn,
1232 #[error("script exceeds the consensus size limit")]
1233 ScriptSize,
1234 #[error("script stack exceeds the consensus item limit")]
1235 StackSize,
1236 #[error("script push exceeds the consensus item-size limit")]
1237 PushSize,
1238 #[error("witness program has an empty witness")]
1239 WitnessProgramWitnessEmpty,
1240 #[error("witness program does not match the committed hash or shape")]
1241 WitnessProgramMismatch,
1242 #[error("version-zero witness program has the wrong length")]
1243 WitnessProgramWrongLength,
1244 #[error("upgradable witness program is discouraged by policy")]
1245 DiscourageUpgradableWitnessProgram,
1246 #[error("upgradable NOP is discouraged by policy")]
1247 DiscourageUpgradableNops,
1248 #[error("script evaluated to false")]
1249 EvalFalse,
1250 #[error("script contains malformed or invalid opcode 0x{0:02x}")]
1251 BadOpcode(u8),
1252 #[error("script contains disabled opcode 0x{0:02x}")]
1253 DisabledOpcode(u8),
1254 #[error("script operation count exceeds the consensus limit")]
1255 OperationCount,
1256 #[error("script push is not minimally encoded")]
1257 MinimalData,
1258 #[error("script number is not minimally encoded")]
1259 NonMinimalNumber,
1260 #[error("conditional argument is not minimally encoded")]
1261 MinimalIf,
1262 #[error("script conditional is unbalanced")]
1263 UnbalancedConditional,
1264 #[error("invalid main-stack operation")]
1265 InvalidStackOperation,
1266 #[error("invalid alt-stack operation")]
1267 InvalidAltStackOperation,
1268 #[error("VERIFY failed")]
1269 Verify,
1270 #[error("EQUALVERIFY failed")]
1271 EqualVerify,
1272 #[error("NUMEQUALVERIFY failed")]
1273 NumEqualVerify,
1274 #[error("negative locktime")]
1275 NegativeLocktime,
1276 #[error("locktime predicate is not satisfied")]
1277 UnsatisfiedLocktime,
1278 #[error("script number overflow")]
1279 NumericOverflow,
1280 #[error("public key count is invalid")]
1281 PublicKeyCount,
1282 #[error("signature count is invalid")]
1283 SignatureCount,
1284 #[error("public key encoding is invalid")]
1285 PublicKeyEncoding,
1286 #[error("signature encoding is invalid")]
1287 SignatureEncoding,
1288 #[error("multisig dummy argument is not empty")]
1289 SignatureNullDummy,
1290 #[error("NULLFAIL")]
1291 NullFail,
1292 #[error("CHECKSIGVERIFY failed")]
1293 CheckSigVerify,
1294 #[error("CHECKMULTISIGVERIFY failed")]
1295 CheckMultiSigVerify,
1296 #[error("secp256k1 signature backend is unavailable")]
1297 SignatureBackendUnavailable,
1298}
1299
1300impl ScriptError {
1301 pub const fn hsd_code(&self) -> &'static str {
1303 match self {
1304 Self::InputIndex { .. }
1305 | Self::InvalidSignatureHashType(_)
1306 | Self::Transaction(_)
1307 | Self::InputCoinCount { .. }
1308 | Self::InputCoinMismatch
1309 | Self::NumericOverflow
1310 | Self::NonMinimalNumber
1311 | Self::SignatureBackendUnavailable => "UNKNOWN_ERROR",
1312 Self::OpReturn => "OP_RETURN",
1313 Self::ScriptSize => "SCRIPT_SIZE",
1314 Self::StackSize => "STACK_SIZE",
1315 Self::PushSize => "PUSH_SIZE",
1316 Self::WitnessProgramWitnessEmpty => "WITNESS_PROGRAM_WITNESS_EMPTY",
1317 Self::WitnessProgramMismatch => "WITNESS_PROGRAM_MISMATCH",
1318 Self::WitnessProgramWrongLength => "WITNESS_PROGRAM_WRONG_LENGTH",
1319 Self::DiscourageUpgradableWitnessProgram => "DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM",
1320 Self::DiscourageUpgradableNops => "DISCOURAGE_UPGRADABLE_NOPS",
1321 Self::EvalFalse => "EVAL_FALSE",
1322 Self::BadOpcode(_) => "BAD_OPCODE",
1323 Self::DisabledOpcode(_) => "DISABLED_OPCODE",
1324 Self::OperationCount => "OP_COUNT",
1325 Self::MinimalData => "MINIMALDATA",
1326 Self::MinimalIf => "MINIMALIF",
1327 Self::UnbalancedConditional => "UNBALANCED_CONDITIONAL",
1328 Self::InvalidStackOperation => "INVALID_STACK_OPERATION",
1329 Self::InvalidAltStackOperation => "INVALID_ALTSTACK_OPERATION",
1330 Self::Verify => "VERIFY",
1331 Self::EqualVerify => "EQUALVERIFY",
1332 Self::NumEqualVerify => "NUMEQUALVERIFY",
1333 Self::NegativeLocktime => "NEGATIVE_LOCKTIME",
1334 Self::UnsatisfiedLocktime => "UNSATISFIED_LOCKTIME",
1335 Self::PublicKeyCount => "PUBKEY_COUNT",
1336 Self::SignatureCount => "SIG_COUNT",
1337 Self::PublicKeyEncoding => "PUBKEY_ENCODING",
1338 Self::SignatureEncoding => "SIG_ENCODING",
1339 Self::SignatureNullDummy => "SIG_NULLDUMMY",
1340 Self::NullFail => "NULLFAIL",
1341 Self::CheckSigVerify => "CHECKSIGVERIFY",
1342 Self::CheckMultiSigVerify => "CHECKMULTISIGVERIFY",
1343 }
1344 }
1345}
1346
1347#[cfg(test)]
1348mod tests {
1349 use hns_covenants::CovenantKind;
1350 use hns_transaction::{Input, Outpoint, Output};
1351
1352 use super::*;
1353
1354 const HSD_SCRIPT_VECTORS: &str = include_str!("../fixtures/hsd/script-tests-v1.txt");
1355
1356 #[derive(Debug)]
1357 struct HsdScriptVector {
1358 index: usize,
1359 expected: String,
1360 flags: ScriptFlags,
1361 value: u64,
1362 locktime: u32,
1363 sequence: u32,
1364 script: Vec<u8>,
1365 witness: Vec<Vec<u8>>,
1366 }
1367
1368 fn parse_vector(line: &str) -> HsdScriptVector {
1369 let mut fields = line.split('|');
1370 let index = fields
1371 .next()
1372 .expect("index")
1373 .parse()
1374 .expect("numeric index");
1375 let expected = fields.next().expect("result").to_owned();
1376 let flags = ScriptFlags::from_bits(
1377 fields
1378 .next()
1379 .expect("flags")
1380 .parse()
1381 .expect("numeric flags"),
1382 );
1383 let value = fields
1384 .next()
1385 .expect("value")
1386 .parse()
1387 .expect("numeric value");
1388 let locktime = fields
1389 .next()
1390 .expect("locktime")
1391 .parse()
1392 .expect("numeric locktime");
1393 let sequence = fields
1394 .next()
1395 .expect("sequence")
1396 .parse()
1397 .expect("numeric sequence");
1398 let script = hex::decode(fields.next().expect("script")).expect("script hex");
1399 let witness_count = fields
1400 .next()
1401 .expect("witness count")
1402 .parse::<usize>()
1403 .expect("numeric witness count");
1404 let witness_field = fields.next().expect("witness");
1405 assert!(fields.next().is_none(), "unexpected vector field");
1406 let witness = if witness_count == 0 {
1407 assert!(witness_field.is_empty());
1408 Vec::new()
1409 } else {
1410 let items = witness_field
1411 .split(',')
1412 .map(|item| hex::decode(item).expect("witness hex"))
1413 .collect::<Vec<_>>();
1414 assert_eq!(items.len(), witness_count);
1415 items
1416 };
1417 HsdScriptVector {
1418 index,
1419 expected,
1420 flags,
1421 value,
1422 locktime,
1423 sequence,
1424 script,
1425 witness,
1426 }
1427 }
1428
1429 fn spending_fixture(vector: &HsdScriptVector) -> (Transaction, Coin) {
1430 let script_address =
1431 Address::new(0, sha3_256(&vector.script).to_vec()).expect("script address");
1432 let funding = Transaction {
1433 version: 1,
1434 inputs: vec![Input {
1435 previous_output: Outpoint::NULL,
1436 sequence: u32::MAX,
1437 witness: Witness {
1438 items: vec![vec![0], vec![0]],
1439 },
1440 }],
1441 outputs: vec![Output {
1442 value: vector.value.into(),
1443 address: script_address.clone(),
1444 covenant: Default::default(),
1445 }],
1446 locktime: 0,
1447 };
1448 let outpoint = Outpoint {
1449 transaction_hash: funding
1450 .transaction_hash()
1451 .expect("funding transaction hash"),
1452 index: 0,
1453 };
1454 let mut witness = vector.witness.clone();
1455 witness.push(vector.script.clone());
1456 let spending = Transaction {
1457 version: 1,
1458 inputs: vec![Input {
1459 previous_output: outpoint,
1460 sequence: vector.sequence,
1461 witness: Witness { items: witness },
1462 }],
1463 outputs: vec![Output {
1464 value: vector.value.into(),
1465 address: Address::new(0, vec![0; 20]).expect("null public-key hash"),
1466 covenant: Default::default(),
1467 }],
1468 locktime: vector.locktime,
1469 };
1470 let coin = Coin {
1471 outpoint,
1472 value: vector.value.into(),
1473 height: 1_u32.into(),
1474 coinbase: false,
1475 address: script_address,
1476 covenant: Default::default(),
1477 };
1478 (spending, coin)
1479 }
1480
1481 #[test]
1482 fn all_pinned_hsd_script_vectors_match_exact_results() {
1483 assert!(
1484 HSD_SCRIPT_VECTORS.contains("# hsd_revision=698e252ebc7b5c1dd0a9587e342fdd153d020ae4")
1485 );
1486 assert!(HSD_SCRIPT_VECTORS.contains(
1487 "# source_sha256=71548a587d1c7921cb899de192f59ed1833c85a6cd62d9dac8cd5b86b1225c86"
1488 ));
1489 let vectors = HSD_SCRIPT_VECTORS
1490 .lines()
1491 .filter(|line| !line.starts_with('#') && !line.is_empty())
1492 .map(parse_vector)
1493 .collect::<Vec<_>>();
1494 assert_eq!(vectors.len(), 876);
1495
1496 for vector in vectors {
1497 let (transaction, coin) = spending_fixture(&vector);
1498 let result = verify_witness_program(
1499 &transaction,
1500 0,
1501 &coin,
1502 vector.flags,
1503 &K256SignatureVerifier,
1504 );
1505 match (vector.expected.as_str(), result) {
1506 ("OK", Ok(())) => {}
1507 ("OK", Err(error)) => {
1508 panic!(
1509 "HSD script vector {} expected OK but returned {} ({})",
1510 vector.index,
1511 error.hsd_code(),
1512 error
1513 );
1514 }
1515 (expected, Err(error)) if error.hsd_code() == expected => {}
1516 (expected, Err(error)) => {
1517 panic!(
1518 "HSD script vector {} expected {} but returned {} ({})",
1519 vector.index,
1520 expected,
1521 error.hsd_code(),
1522 error
1523 );
1524 }
1525 (expected, Ok(())) => {
1526 panic!(
1527 "HSD script vector {} expected {} but succeeded",
1528 vector.index, expected
1529 );
1530 }
1531 }
1532 }
1533 }
1534
1535 #[test]
1536 fn op_type_and_coin_binding_are_consensus_visible() {
1537 let vector = HsdScriptVector {
1538 index: 0,
1539 expected: "OK".to_owned(),
1540 flags: ScriptFlags::MANDATORY,
1541 value: 1_000,
1542 locktime: 0,
1543 sequence: u32::MAX,
1544 script: vec![OP_TYPE, OP_7, OP_EQUAL],
1545 witness: Vec::new(),
1546 };
1547 let (mut transaction, coin) = spending_fixture(&vector);
1548 transaction
1549 .outputs
1550 .first_mut()
1551 .expect("fixture output")
1552 .covenant
1553 .kind = CovenantKind::Update;
1554 verify_witness_program(
1555 &transaction,
1556 0,
1557 &coin,
1558 ScriptFlags::MANDATORY,
1559 &K256SignatureVerifier,
1560 )
1561 .expect("OP_TYPE matches output covenant");
1562
1563 let mut wrong_coin = coin.clone();
1564 wrong_coin.outpoint.index = 1;
1565 assert!(matches!(
1566 verify_witness_program(
1567 &transaction,
1568 0,
1569 &wrong_coin,
1570 ScriptFlags::MANDATORY,
1571 &K256SignatureVerifier
1572 ),
1573 Err(ScriptError::InputCoinMismatch)
1574 ));
1575 }
1576}