Skip to content

Commit a3dd9fe

Browse files
committed
miniscript/types: check that timelock values aren't too large
This changes the ZeroTime error into an InvalidTime error and checks that the disabling bit (most significant one) isn't set in the timelock value. We could also check the value is minimal, using the mask. Signed-off-by: Antoine Poinsot <[email protected]>
1 parent f550b9b commit a3dd9fe

File tree

2 files changed

+29
-21
lines changed

2 files changed

+29
-21
lines changed

src/miniscript/types/extra_props.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
//! Other miscellaneous type properties which are not related to
22
//! correctness or malleability.
33
4-
use miniscript::limits::{HEIGHT_TIME_THRESHOLD, SEQUENCE_LOCKTIME_TYPE_FLAG};
4+
use miniscript::limits::{
5+
HEIGHT_TIME_THRESHOLD, SEQUENCE_LOCKTIME_DISABLE_FLAG, SEQUENCE_LOCKTIME_TYPE_FLAG,
6+
};
57

68
use super::{Error, ErrorKind, Property, ScriptContext};
79
use script_num_size;
@@ -851,20 +853,22 @@ impl Property for ExtData {
851853
Ok(Self::from_multi(k, pks.len()))
852854
}
853855
Terminal::After(t) => {
854-
// FIXME check if t > 2^31 - 1
855-
if t == 0 {
856+
// Note that for CLTV this is a limitation not of Bitcoin but Miniscript. The
857+
// number on the stack would be a 5 bytes signed integer but Miniscript's B type
858+
// only consumes 4 bytes from the stack.
859+
if t == 0 || (t & SEQUENCE_LOCKTIME_DISABLE_FLAG) == 1 {
856860
return Err(Error {
857861
fragment: fragment.clone(),
858-
error: ErrorKind::ZeroTime,
862+
error: ErrorKind::InvalidTime,
859863
});
860864
}
861865
Ok(Self::from_after(t))
862866
}
863867
Terminal::Older(t) => {
864-
if t == 0 {
868+
if t == 0 || (t & SEQUENCE_LOCKTIME_DISABLE_FLAG) == 1 {
865869
return Err(Error {
866870
fragment: fragment.clone(),
867-
error: ErrorKind::ZeroTime,
871+
error: ErrorKind::InvalidTime,
868872
});
869873
}
870874
Ok(Self::from_older(t))

src/miniscript/types/mod.rs

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use std::{error, fmt};
2525
pub use self::correctness::{Base, Correctness, Input};
2626
pub use self::extra_props::ExtData;
2727
pub use self::malleability::{Dissat, Malleability};
28-
use super::ScriptContext;
28+
use super::{limits::SEQUENCE_LOCKTIME_DISABLE_FLAG, ScriptContext};
2929
use MiniscriptKey;
3030
use Terminal;
3131

@@ -38,8 +38,8 @@ fn return_none<T>(_: usize) -> Option<T> {
3838
/// Detailed type of a typechecker error
3939
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
4040
pub enum ErrorKind {
41-
/// Relative or absolute timelock had a time value of 0
42-
ZeroTime,
41+
/// Relative or absolute timelock had an invalid time value (either 0, or >=0x80000000)
42+
InvalidTime,
4343
/// Passed a `z` argument to a `d` wrapper when `z` was expected
4444
NonZeroDupIf,
4545
/// Multisignature or threshold policy had a `k` value of 0
@@ -117,9 +117,9 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> error::Error for Error<Pk, Ctx> {
117117
impl<Pk: MiniscriptKey, Ctx: ScriptContext> fmt::Display for Error<Pk, Ctx> {
118118
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
119119
match self.error {
120-
ErrorKind::ZeroTime => write!(
120+
ErrorKind::InvalidTime => write!(
121121
f,
122-
"fragment «{}» represents a 0-valued timelock (use `1` instead)",
122+
"fragment «{}» represents a timelock which value is invalid (time must be in [1; 0x80000000])",
123123
self.fragment,
124124
),
125125
ErrorKind::NonZeroDupIf => write!(
@@ -426,20 +426,22 @@ pub trait Property: Sized {
426426
Ok(Self::from_multi(k, pks.len()))
427427
}
428428
Terminal::After(t) => {
429-
if t == 0 {
429+
// Note that for CLTV this is a limitation not of Bitcoin but Miniscript. The
430+
// number on the stack would be a 5 bytes signed integer but Miniscript's B type
431+
// only consumes 4 bytes from the stack.
432+
if t == 0 || (t & SEQUENCE_LOCKTIME_DISABLE_FLAG) == 1 {
430433
return Err(Error {
431434
fragment: fragment.clone(),
432-
error: ErrorKind::ZeroTime,
435+
error: ErrorKind::InvalidTime,
433436
});
434437
}
435438
Ok(Self::from_after(t))
436439
}
437440
Terminal::Older(t) => {
438-
// FIXME check if t > 2^31 - 1
439-
if t == 0 {
441+
if t == 0 || (t & SEQUENCE_LOCKTIME_DISABLE_FLAG) == 1 {
440442
return Err(Error {
441443
fragment: fragment.clone(),
442-
error: ErrorKind::ZeroTime,
444+
error: ErrorKind::InvalidTime,
443445
});
444446
}
445447
Ok(Self::from_older(t))
@@ -803,20 +805,22 @@ impl Property for Type {
803805
Ok(Self::from_multi(k, pks.len()))
804806
}
805807
Terminal::After(t) => {
806-
// FIXME check if t > 2^31 - 1
807-
if t == 0 {
808+
// Note that for CLTV this is a limitation not of Bitcoin but Miniscript. The
809+
// number on the stack would be a 5 bytes signed integer but Miniscript's B type
810+
// only consumes 4 bytes from the stack.
811+
if t == 0 || (t & SEQUENCE_LOCKTIME_DISABLE_FLAG) == 1 {
808812
return Err(Error {
809813
fragment: fragment.clone(),
810-
error: ErrorKind::ZeroTime,
814+
error: ErrorKind::InvalidTime,
811815
});
812816
}
813817
Ok(Self::from_after(t))
814818
}
815819
Terminal::Older(t) => {
816-
if t == 0 {
820+
if t == 0 || (t & SEQUENCE_LOCKTIME_DISABLE_FLAG) == 1 {
817821
return Err(Error {
818822
fragment: fragment.clone(),
819-
error: ErrorKind::ZeroTime,
823+
error: ErrorKind::InvalidTime,
820824
});
821825
}
822826
Ok(Self::from_older(t))

0 commit comments

Comments
 (0)