Newer
Older
use keys::{Signature, Public};
use crypto::{sha1, sha256, dhash160, dhash256, ripemd160};
script, Script, Num, VerificationFlags, Opcode, Error,
/// Helper function.
fn check_signature(
checker: &SignatureChecker,
public: Vec<u8>,
script_code: &Script,
version: SignatureVersion
) -> bool {
let public = match Public::from_slice(&public) {
Ok(public) => public,
_ => return false,
};
if script_sig.is_empty() {
return false;
let hash_type = script_sig.pop().unwrap() as u32;
let signature = script_sig.into();
checker.check_signature(&signature, &public, script_code, hash_type, version)
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
fn is_public_key(v: &[u8]) -> bool {
match v.len() {
33 if v[0] == 2 || v[0] == 3 => true,
65 if v[0] == 4 => true,
_ => false,
}
}
/// A canonical signature exists of: <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype>
/// Where R and S are not negative (their first byte has its highest bit not set), and not
/// excessively padded (do not start with a 0 byte, unless an otherwise negative number follows,
/// in which case a single 0 byte is necessary and even required).
///
/// See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623
///
/// This function is consensus-critical since BIP66.
fn is_valid_signature_encoding(sig: &[u8]) -> bool {
// Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] [sighash]
// * total-length: 1-byte length descriptor of everything that follows,
// excluding the sighash byte.
// * R-length: 1-byte length descriptor of the R value that follows.
// * R: arbitrary-length big-endian encoded R value. It must use the shortest
// possible encoding for a positive integers (which means no null bytes at
// the start, except a single one when the next byte has its highest bit set).
// * S-length: 1-byte length descriptor of the S value that follows.
// * S: arbitrary-length big-endian encoded S value. The same rules apply.
// * sighash: 1-byte value indicating what data is hashed (not part of the DER
// signature)
// Minimum and maximum size constraints
if sig.len() < 9 || sig.len() > 73 {
return false;
}
// A signature is of type 0x30 (compound)
if sig[0] != 0x30 {
return false;
}
// Make sure the length covers the entire signature.
if sig[1] as usize != sig.len() - 3 {
return false;
}
// Extract the length of the R element.
let len_r = sig[3] as usize;
// Make sure the length of the S element is still inside the signature.
if len_r + 5 >= sig.len() {
return false;
}
// Extract the length of the S element.
let len_s = sig[len_r + 5] as usize;
// Verify that the length of the signature matches the sum of the length
if len_r + len_s + 7 != sig.len() {
return false;
}
// Check whether the R element is an integer.
if sig[2] != 2 {
return false;
}
// Zero-length integers are not allowed for R.
if len_r == 0 {
return false;
}
// Negative numbers are not allowed for R.
if (sig[4] & 0x80) != 0 {
return false;
}
// Null bytes at the start of R are not allowed, unless R would
// otherwise be interpreted as a negative number.
if len_r > 1 && sig[4] == 0 && (!(sig[5] & 0x80)) != 0 {
return false;
}
// Check whether the S element is an integer.
if sig[len_r + 4] != 2 {
return false;
}
// Zero-length integers are not allowed for S.
if len_s == 0 {
return false;
}
// Negative numbers are not allowed for S.
if (sig[len_r + 6] & 0x80) != 0 {
return false;
}
// Null bytes at the start of S are not allowed, unless S would otherwise be
// interpreted as a negative number.
if len_s > 1 && (sig[len_r + 6] == 0) && (!(sig[len_r + 7] & 0x80)) != 0 {
return false;
}
true
}
fn is_low_der_signature(sig: &[u8]) -> Result<(), Error> {
if !is_valid_signature_encoding(sig) {
return Err(Error::SignatureDer);
}
let signature: Signature = sig.into();
if !signature.check_low_s() {
return Err(Error::SignatureHighS);
}
}
fn is_defined_hashtype_signature(sig: &[u8]) -> bool {
if sig.is_empty() {
return false;
}
Sighash::is_defined(sig[sig.len() -1] as u32)
fn check_signature_encoding(sig: &[u8], flags: &VerificationFlags) -> Result<(), Error> {
// Empty signature. Not strictly DER encoded, but allowed to provide a
// compact way to provide an invalid signature for use with CHECK(MULTI)SIG
if sig.is_empty() {
}
if (flags.verify_dersig || flags.verify_low_s || flags.verify_strictenc) && !is_valid_signature_encoding(sig) {
return Err(Error::SignatureDer);
}
if flags.verify_low_s {
try!(is_low_der_signature(sig));
}
if flags.verify_strictenc && !is_defined_hashtype_signature(sig) {
fn check_pubkey_encoding(v: &[u8], flags: &VerificationFlags) -> Result<(), Error> {
if flags.verify_strictenc && !is_public_key(v) {
return Err(Error::PubkeyType);
}
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
}
fn check_minimal_push(data: &[u8], opcode: Opcode) -> bool {
if data.is_empty() {
// Could have used OP_0.
opcode == Opcode::OP_0
} else if data.len() == 1 && data[0] >= 1 && data[0] <= 16 {
// Could have used OP_1 .. OP_16.
opcode as u8 == Opcode::OP_1 as u8 + (data[0] - 1)
} else if data.len() == 1 && data[0] == 0x81 {
// Could have used OP_1NEGATE
opcode == Opcode::OP_1NEGATE
} else if data.len() <= 75 {
// Could have used a direct push (opcode indicating number of bytes pushed + those bytes).
opcode as usize == data.len()
} else if data.len() <= 255 {
// Could have used OP_PUSHDATA.
opcode == Opcode::OP_PUSHDATA1
} else if data.len() <= 65535 {
// Could have used OP_PUSHDATA2.
opcode == Opcode::OP_PUSHDATA2
} else {
true
}
}
fn cast_to_bool(data: &[u8]) -> bool {
if data.is_empty() {
return false;
}
if data[..data.len() - 1].iter().any(|x| x != &0) {
return true;
}
let last = data[data.len() - 1];
!(last == 0 || last == 0x80)
pub fn verify_script(
script_sig: &Script,
script_pubkey: &Script,
flags: &VerificationFlags,
checker: &SignatureChecker
) -> Result<(), Error> {
if flags.verify_sigpushonly && !script_sig.is_push_only() {
return Err(Error::SignaturePushOnly);
}
let mut stack = Stack::new();
let mut stack_copy = Stack::new();
try!(eval_script(&mut stack, script_sig, flags, checker, SignatureVersion::Base));
if flags.verify_p2sh {
stack_copy = stack.clone();
}
let res = try!(eval_script(&mut stack, script_pubkey, flags, checker, SignatureVersion::Base));
if !res {
return Err(Error::EvalFalse);
}
// Additional validation for spend-to-script-hash transactions:
if flags.verify_p2sh && script_pubkey.is_pay_to_script_hash() {
if !script_sig.is_push_only() {
return Err(Error::SignaturePushOnly);
}
mem::swap(&mut stack, &mut stack_copy);
// stack cannot be empty here, because if it was the
// P2SH HASH <> EQUAL scriptPubKey would be evaluated with
// an empty stack and the EvalScript above would return false.
assert!(!stack.is_empty());
let res = try!(eval_script(&mut stack, &pubkey2, flags, checker, SignatureVersion::Base));
if !res {
return Err(Error::EvalFalse);
}
}
// The CLEANSTACK check is only performed after potential P2SH evaluation,
// as the non-P2SH evaluation of a P2SH script will obviously not result in
// a clean stack (the P2SH inputs remain). The same holds for witness evaluation.
if flags.verify_cleanstack {
// Disallow CLEANSTACK without P2SH, as otherwise a switch CLEANSTACK->P2SH+CLEANSTACK
// would be possible, which is not a softfork (and P2SH should be one).
assert!(flags.verify_p2sh);
assert!(flags.verify_witness);
if stack.len() != 1 {
return Err(Error::Cleanstack);
}
}
#[cfg_attr(feature="cargo-clippy", allow(match_same_arms))]
flags: &VerificationFlags,
if script.len() > script::MAX_SCRIPT_SIZE {
return Err(Error::ScriptSize);
}
let mut begincode = 0;
let mut exec_stack = Vec::<bool>::new();
let instruction = try!(script.get_instruction(pc));
let opcode = instruction.opcode;
if let Some(data) = instruction.data {
if data.len() > script::MAX_SCRIPT_ELEMENT_SIZE {
return Err(Error::PushSize);
}
if executing && flags.verify_minimaldata && !check_minimal_push(data, opcode) {
return Err(Error::Minimaldata);
}
}
if opcode.is_countable() {
op_count += 1;
if op_count > script::MAX_OPS_PER_SCRIPT {
return Err(Error::OpCount);
}
}
if opcode.is_disabled() {
return Err(Error::DisabledOpcode(opcode));
}
if !(executing || (Opcode::OP_IF <= opcode && opcode <= Opcode::OP_ENDIF)) {
match opcode {
Opcode::OP_PUSHDATA1 |
Opcode::OP_PUSHDATA2 |
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
Opcode::OP_0 |
Opcode::OP_PUSHBYTES_1 |
Opcode::OP_PUSHBYTES_2 |
Opcode::OP_PUSHBYTES_3 |
Opcode::OP_PUSHBYTES_4 |
Opcode::OP_PUSHBYTES_5 |
Opcode::OP_PUSHBYTES_6 |
Opcode::OP_PUSHBYTES_7 |
Opcode::OP_PUSHBYTES_8 |
Opcode::OP_PUSHBYTES_9 |
Opcode::OP_PUSHBYTES_10 |
Opcode::OP_PUSHBYTES_11 |
Opcode::OP_PUSHBYTES_12 |
Opcode::OP_PUSHBYTES_13 |
Opcode::OP_PUSHBYTES_14 |
Opcode::OP_PUSHBYTES_15 |
Opcode::OP_PUSHBYTES_16 |
Opcode::OP_PUSHBYTES_17 |
Opcode::OP_PUSHBYTES_18 |
Opcode::OP_PUSHBYTES_19 |
Opcode::OP_PUSHBYTES_20 |
Opcode::OP_PUSHBYTES_21 |
Opcode::OP_PUSHBYTES_22 |
Opcode::OP_PUSHBYTES_23 |
Opcode::OP_PUSHBYTES_24 |
Opcode::OP_PUSHBYTES_25 |
Opcode::OP_PUSHBYTES_26 |
Opcode::OP_PUSHBYTES_27 |
Opcode::OP_PUSHBYTES_28 |
Opcode::OP_PUSHBYTES_29 |
Opcode::OP_PUSHBYTES_30 |
Opcode::OP_PUSHBYTES_31 |
Opcode::OP_PUSHBYTES_32 |
Opcode::OP_PUSHBYTES_33 |
Opcode::OP_PUSHBYTES_34 |
Opcode::OP_PUSHBYTES_35 |
Opcode::OP_PUSHBYTES_36 |
Opcode::OP_PUSHBYTES_37 |
Opcode::OP_PUSHBYTES_38 |
Opcode::OP_PUSHBYTES_39 |
Opcode::OP_PUSHBYTES_40 |
Opcode::OP_PUSHBYTES_41 |
Opcode::OP_PUSHBYTES_42 |
Opcode::OP_PUSHBYTES_43 |
Opcode::OP_PUSHBYTES_44 |
Opcode::OP_PUSHBYTES_45 |
Opcode::OP_PUSHBYTES_46 |
Opcode::OP_PUSHBYTES_47 |
Opcode::OP_PUSHBYTES_48 |
Opcode::OP_PUSHBYTES_49 |
Opcode::OP_PUSHBYTES_50 |
Opcode::OP_PUSHBYTES_51 |
Opcode::OP_PUSHBYTES_52 |
Opcode::OP_PUSHBYTES_53 |
Opcode::OP_PUSHBYTES_54 |
Opcode::OP_PUSHBYTES_55 |
Opcode::OP_PUSHBYTES_56 |
Opcode::OP_PUSHBYTES_57 |
Opcode::OP_PUSHBYTES_58 |
Opcode::OP_PUSHBYTES_59 |
Opcode::OP_PUSHBYTES_60 |
Opcode::OP_PUSHBYTES_61 |
Opcode::OP_PUSHBYTES_62 |
Opcode::OP_PUSHBYTES_63 |
Opcode::OP_PUSHBYTES_64 |
Opcode::OP_PUSHBYTES_65 |
Opcode::OP_PUSHBYTES_66 |
Opcode::OP_PUSHBYTES_67 |
Opcode::OP_PUSHBYTES_68 |
Opcode::OP_PUSHBYTES_69 |
Opcode::OP_PUSHBYTES_70 |
Opcode::OP_PUSHBYTES_71 |
Opcode::OP_PUSHBYTES_72 |
Opcode::OP_PUSHBYTES_73 |
Opcode::OP_PUSHBYTES_74 |
Opcode::OP_PUSHBYTES_75 => {
Opcode::OP_1 |
Opcode::OP_2 |
Opcode::OP_3 |
Opcode::OP_4 |
Opcode::OP_5 |
Opcode::OP_6 |
Opcode::OP_7 |
Opcode::OP_8 |
Opcode::OP_9 |
Opcode::OP_10 |
Opcode::OP_11 |
Opcode::OP_12 |
Opcode::OP_13 |
Opcode::OP_14 |
Opcode::OP_15 |
Opcode::OP_16 => {
let value = opcode as u8 - (Opcode::OP_1 as u8 - 1);
Opcode::OP_CAT | Opcode::OP_SUBSTR | Opcode::OP_LEFT | Opcode::OP_RIGHT |
Opcode::OP_INVERT | Opcode::OP_AND | Opcode::OP_OR | Opcode::OP_XOR |
Opcode::OP_2MUL | Opcode::OP_2DIV | Opcode::OP_MUL | Opcode::OP_DIV |
Opcode::OP_MOD | Opcode::OP_LSHIFT | Opcode::OP_RSHIFT => {
return Err(Error::DisabledOpcode(opcode));
},
Opcode::OP_NOP => break,
Opcode::OP_CHECKLOCKTIMEVERIFY => {
if flags.verify_discourage_upgradable_nops {
return Err(Error::DiscourageUpgradableNops);
if flags.verify_clocktimeverify {
// Note that elsewhere numeric opcodes are limited to
// operands in the range -2**31+1 to 2**31-1, however it is
// legal for opcodes to produce results exceeding that
// range. This limitation is implemented by CScriptNum's
// default 4-byte limit.
//
// If we kept to that limit we'd have a year 2038 problem,
// even though the nLockTime field in transactions
// themselves is uint32 which only becomes meaningless
// after the year 2106.
//
// Thus as a special case we tell CScriptNum to accept up
// to 5-byte bignums, which are good until 2**39-1, well
// beyond the 2**32-1 limit of the nLockTime field itself.
let lock_time = try!(Num::from_slice(try!(stack.last()), flags.verify_minimaldata, 5));
// In the rare event that the argument may be < 0 due to
// some arithmetic being done first, you can always use
// 0 MAX CHECKLOCKTIMEVERIFY.
if lock_time.is_negative() {
return Err(Error::NegativeLocktime);
}
if !checker.check_lock_time(lock_time) {
return Err(Error::UnsatisfiedLocktime);
}
}
},
Opcode::OP_CHECKSEQUENCEVERIFY => {
if !flags.verify_chechsequenceverify && flags.verify_discourage_upgradable_nops {
return Err(Error::DiscourageUpgradableNops);
let sequence = try!(Num::from_slice(try!(stack.last()), flags.verify_minimaldata, 5));
if sequence.is_negative() {
return Err(Error::NegativeLocktime);
}
if (sequence & (SEQUENCE_LOCKTIME_DISABLE_FLAG as i64).into()).is_zero() && !checker.check_sequence(sequence) {
return Err(Error::UnsatisfiedLocktime);
Opcode::OP_NOP1 |
Opcode::OP_NOP4 |
Opcode::OP_NOP5 |
Opcode::OP_NOP6 |
Opcode::OP_NOP7 |
Opcode::OP_NOP8 |
Opcode::OP_NOP9 |
Opcode::OP_NOP10 => {
if flags.verify_discourage_upgradable_nops {
return Err(Error::DiscourageUpgradableNops);
}
},
Opcode::OP_IF | Opcode::OP_NOTIF => {
let mut exec_value = false;
exec_value = cast_to_bool(&try!(stack.pop().map_err(|_| Error::UnbalancedConditional)));
if opcode == Opcode::OP_NOTIF {
exec_value = !exec_value;
}
exec_stack.push(exec_value);
},
Opcode::OP_ELSE => {
if exec_stack.is_empty() {
return Err(Error::UnbalancedConditional);
}
let last_index = exec_stack.len() - 1;
let last = exec_stack[last_index];
exec_stack[last_index] = !last;
},
Opcode::OP_ENDIF => {
if exec_stack.is_empty() {
return Err(Error::UnbalancedConditional);
}
exec_stack.pop();
},
Opcode::OP_VERIFY => {
if !exec_value {
return Err(Error::Verify);
}
},
Opcode::OP_RETURN => {
return Err(Error::ReturnOpcode);
},
Opcode::OP_TOALTSTACK => {
stack.push(try!(altstack.pop().map_err(|_| Error::InvalidAltstackOperation)));
if cast_to_bool(try!(stack.last())) {
try!(stack.dup(1));
}
},
Opcode::OP_DEPTH => {
let depth = Num::from(stack.len());
let n: i64 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4)).into();
if n < 0 || n >= stack.len() as i64 {
return Err(Error::InvalidStackOperation);
}
let v = match opcode {
Opcode::OP_PICK => try!(stack.top(n as usize)).clone(),
_ => try!(stack.remove(n as usize)),
};
let v1 = try!(stack.pop());
let v2 = try!(stack.pop());
if v1 == v2 {
stack.push(vec![1].into());
} else {
stack.push(vec![0].into());
}
if !equal {
return Err(Error::EqualVerify);
}
},
Opcode::OP_1ADD => {
let n = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4)) + 1.into();
let n = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4)) - 1.into();
let n = -try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let n = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4)).abs();
let n = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4)).is_zero();
let n = !try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4)).is_zero();
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let v = Num::from(!v1.is_zero() && !v2.is_zero());
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let v = Num::from(!v1.is_zero() || !v2.is_zero());
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
if v1 != v2 {
return Err(Error::NumEqualVerify);
}
},
Opcode::OP_NUMNOTEQUAL => {
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
let v3 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
if v2 <= v3 && v3 <= v1 {
stack.push(vec![1].into());
} else {
stack.push(vec![0].into());
}
},
Opcode::OP_CODESEPARATOR => {
begincode = pc;
},
Opcode::OP_CHECKSIG | Opcode::OP_CHECKSIGVERIFY => {
let pubkey = try!(stack.pop());
let signature = try!(stack.pop());
let mut subscript = script.subscript(begincode);
if version == SignatureVersion::Base {
subscript = subscript.find_and_delete(&signature);
}
try!(check_signature_encoding(&signature, flags));
try!(check_pubkey_encoding(&pubkey, flags));
let success = check_signature(checker, signature.into(), pubkey.into(), &subscript, version);
if success {
stack.push(vec![1].into());
} else {
stack.push(vec![0].into());
}
},
Opcode::OP_CHECKSIGVERIFY if !success => {
return Err(Error::CheckSigVerify);
},
_ => {},
}
Opcode::OP_CHECKMULTISIG | Opcode::OP_CHECKMULTISIGVERIFY => {
let keys_count = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
if keys_count < 0.into() || keys_count > script::MAX_PUBKEYS_PER_MULTISIG.into() {
return Err(Error::PubkeyCount);
}
let keys: Vec<_> = try!((0..keys_count).into_iter().map(|_| stack.pop()).rev().collect());
let sigs_count = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
if sigs_count < 0.into() || sigs_count > keys_count.into() {
return Err(Error::SigCount);
}
let sigs_count: usize = sigs_count.into();
let sigs: Vec<_> = try!((0..sigs_count).into_iter().map(|_| stack.pop()).rev().collect());
let mut subscript = script.subscript(begincode);
if version == SignatureVersion::Base {
for signature in &sigs {
subscript = subscript.find_and_delete(signature);
}
}
let mut success = true;
let mut k = 0;
let mut s = 0;
while s < sigs.len() && success {
// TODO: remove redundant copying
let key = keys[k].clone();
let sig = sigs[s].clone();
try!(check_signature_encoding(&sig, flags));
try!(check_pubkey_encoding(&key, flags));
let ok = check_signature(checker, sig.into(), key.into(), &subscript, version);
if ok {
s += 1;
}
k += 1;
success = sigs.len() - s <= keys.len() - k;
}
if !try!(stack.pop()).is_empty() && flags.verify_nulldummy {
return Err(Error::SignatureNullDummy);
}
match opcode {
Opcode::OP_CHECKMULTISIG => {
if success {
stack.push(vec![1].into());
} else {
stack.push(vec![0].into());
}
},
Opcode::OP_CHECKMULTISIGVERIFY if !success => {
return Err(Error::CheckSigVerify);
},
_ => {},
}
},
Opcode::OP_RESERVED |
Opcode::OP_VER |
Opcode::OP_RESERVED1 |
Opcode::OP_RESERVED2 => {
if executing {
return Err(Error::DisabledOpcode(opcode));
}
},
Opcode::OP_VERNOTIF => {
return Err(Error::DisabledOpcode(opcode));
},
if stack.len() + altstack.len() > 1000 {
return Err(Error::StackSize);
}
if !exec_stack.is_empty() {
return Err(Error::UnbalancedConditional);
}
Opcode, Script, VerificationFlags, Builder, Error, Num, TransactionInputSigner,
NoopSignatureChecker, SignatureVersion, TransactionSignatureChecker, Stack
use super::{eval_script, verify_script, is_public_key};
#[test]
fn tests_is_public_key() {
assert!(!is_public_key(&[]));
assert!(!is_public_key(&[1]));
assert!(is_public_key(&Bytes::from("0495dfb90f202c7d016ef42c65bc010cd26bb8237b06253cc4d12175097bef767ed6b1fcb3caf1ed57c98d92e6cb70278721b952e29a335134857acd4c199b9d2f")));
assert!(is_public_key(&[2; 33]));
assert!(is_public_key(&[3; 33]));
assert!(!is_public_key(&[4; 33]));
}
// https://github.com/bitcoin/bitcoin/blob/d612837814020ae832499d18e6ee5eb919a87907/src/test/script_tests.cpp#L900
#[test]
fn test_push_data() {
let expected: Stack<Bytes> = vec![vec![0x5a].into()].into();
let flags = VerificationFlags::default()
.verify_p2sh(true);
let checker = NoopSignatureChecker;
let version = SignatureVersion::Base;
let direct: Script = vec![Opcode::OP_PUSHBYTES_1 as u8, 0x5a].into();
let pushdata1: Script = vec![Opcode::OP_PUSHDATA1 as u8, 0x1, 0x5a].into();
let pushdata2: Script = vec![Opcode::OP_PUSHDATA2 as u8, 0x1, 0, 0x5a].into();
let pushdata4: Script = vec![Opcode::OP_PUSHDATA4 as u8, 0x1, 0, 0, 0, 0x5a].into();
let mut direct_stack = Stack::new();
let mut pushdata1_stack = Stack::new();
let mut pushdata2_stack = Stack::new();
let mut pushdata4_stack = Stack::new();
assert!(eval_script(&mut direct_stack, &direct, &flags, &checker, version).unwrap());
assert!(eval_script(&mut pushdata1_stack, &pushdata1, &flags, &checker, version).unwrap());
assert!(eval_script(&mut pushdata2_stack, &pushdata2, &flags, &checker, version).unwrap());
assert!(eval_script(&mut pushdata4_stack, &pushdata4, &flags, &checker, version).unwrap());
assert_eq!(direct_stack, expected);
assert_eq!(pushdata1_stack, expected);
assert_eq!(pushdata2_stack, expected);
assert_eq!(pushdata4_stack, expected);
fn basic_test(script: &Script, expected: Result<bool, Error>, expected_stack: Stack<Bytes>) {
let flags = VerificationFlags::default()
.verify_p2sh(true);
let checker = NoopSignatureChecker;
let version = SignatureVersion::Base;
assert_eq!(eval_script(&mut stack, script, &flags, &checker, version), expected);
if expected.is_ok() {
}
}
#[test]
fn test_equal() {
let script = Builder::default()
.push_data(&[0x4])
.push_data(&[0x4])
.push_opcode(Opcode::OP_EQUAL)
.into_script();
let result = Ok(true);
basic_test(&script, result, stack);
}
#[test]
fn test_equal_false() {
let script = Builder::default()
.push_data(&[0x4])
.push_data(&[0x3])
.push_opcode(Opcode::OP_EQUAL)
.into_script();
let result = Ok(false);
basic_test(&script, result, stack);
}
#[test]
fn test_equal_invalid_stack() {
let script = Builder::default()
.push_data(&[0x4])
.push_opcode(Opcode::OP_EQUAL)
.into_script();
let result = Err(Error::InvalidStackOperation);
basic_test(&script, result, Stack::default());
}
#[test]
fn test_equal_verify() {
let script = Builder::default()
.push_data(&[0x4])
.push_data(&[0x4])
.push_opcode(Opcode::OP_EQUALVERIFY)
.into_script();
let result = Ok(false);
basic_test(&script, result, stack);
}
#[test]
fn test_equal_verify_failed() {
let script = Builder::default()
.push_data(&[0x4])
.push_data(&[0x3])
.push_opcode(Opcode::OP_EQUALVERIFY)
.into_script();
let result = Err(Error::EqualVerify);
basic_test(&script, result, Stack::default());