use super::{ErrorKind, Property};
use crate::ScriptContext;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub enum Dissat {
None,
Unique,
Unknown,
}
impl Dissat {
fn is_subtype(&self, other: Self) -> bool {
match (*self, other) {
(x, y) if x == y => true,
(_, Dissat::Unknown) => true,
_ => false,
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Malleability {
pub dissat: Dissat,
pub safe: bool,
pub non_malleable: bool,
}
impl Malleability {
pub fn is_subtype(&self, other: Self) -> bool {
self.dissat.is_subtype(other.dissat)
&& self.safe >= other.safe
&& self.non_malleable >= other.non_malleable
}
}
impl Property for Malleability {
fn from_true() -> Self {
Malleability {
dissat: Dissat::None,
safe: false,
non_malleable: true,
}
}
fn from_false() -> Self {
Malleability {
dissat: Dissat::Unique,
safe: true,
non_malleable: true,
}
}
fn from_pk_k<Ctx: ScriptContext>() -> Self {
Malleability {
dissat: Dissat::Unique,
safe: true,
non_malleable: true,
}
}
fn from_pk_h<Ctx: ScriptContext>() -> Self {
Malleability {
dissat: Dissat::Unique,
safe: true,
non_malleable: true,
}
}
fn from_multi(_: usize, _: usize) -> Self {
Malleability {
dissat: Dissat::Unique,
safe: true,
non_malleable: true,
}
}
fn from_multi_a(_: usize, _: usize) -> Self {
Malleability {
dissat: Dissat::Unique,
safe: true,
non_malleable: true,
}
}
fn from_hash() -> Self {
Malleability {
dissat: Dissat::Unknown,
safe: false,
non_malleable: true,
}
}
fn from_time(_: u32) -> Self {
Malleability {
dissat: Dissat::None,
safe: false,
non_malleable: true,
}
}
fn cast_alt(self) -> Result<Self, ErrorKind> {
Ok(self)
}
fn cast_swap(self) -> Result<Self, ErrorKind> {
Ok(self)
}
fn cast_check(self) -> Result<Self, ErrorKind> {
Ok(self)
}
fn cast_dupif(self) -> Result<Self, ErrorKind> {
Ok(Malleability {
dissat: if self.dissat == Dissat::None {
Dissat::Unique
} else {
Dissat::Unknown
},
safe: self.safe,
non_malleable: self.non_malleable,
})
}
fn cast_verify(self) -> Result<Self, ErrorKind> {
Ok(Malleability {
dissat: Dissat::None,
safe: self.safe,
non_malleable: self.non_malleable,
})
}
fn cast_nonzero(self) -> Result<Self, ErrorKind> {
Ok(Malleability {
dissat: if self.dissat == Dissat::None {
Dissat::Unique
} else {
Dissat::Unknown
},
safe: self.safe,
non_malleable: self.non_malleable,
})
}
fn cast_zeronotequal(self) -> Result<Self, ErrorKind> {
Ok(self)
}
fn cast_true(self) -> Result<Self, ErrorKind> {
Ok(Malleability {
dissat: Dissat::None,
safe: self.safe,
non_malleable: self.non_malleable,
})
}
fn cast_or_i_false(self) -> Result<Self, ErrorKind> {
Ok(Malleability {
dissat: if self.dissat == Dissat::None {
Dissat::Unique
} else {
Dissat::Unknown
},
safe: self.safe,
non_malleable: self.non_malleable,
})
}
fn and_b(left: Self, right: Self) -> Result<Self, ErrorKind> {
Ok(Malleability {
dissat: match (left.dissat, right.dissat) {
(Dissat::None, Dissat::None) => Dissat::None,
(Dissat::None, _) if left.safe => Dissat::None,
(_, Dissat::None) if right.safe => Dissat::None,
(Dissat::Unique, Dissat::Unique) => {
if left.safe && right.safe {
Dissat::Unique
} else {
Dissat::Unknown
}
}
_ => Dissat::Unknown,
},
safe: left.safe || right.safe,
non_malleable: left.non_malleable && right.non_malleable,
})
}
fn and_v(left: Self, right: Self) -> Result<Self, ErrorKind> {
Ok(Malleability {
dissat: match (left.safe, right.dissat) {
(_, Dissat::None) => Dissat::None, (true, _) => Dissat::None, _ => Dissat::Unknown,
},
safe: left.safe || right.safe,
non_malleable: left.non_malleable && right.non_malleable,
})
}
fn or_b(left: Self, right: Self) -> Result<Self, ErrorKind> {
Ok(Malleability {
dissat: Dissat::Unique,
safe: left.safe && right.safe,
non_malleable: left.non_malleable
&& left.dissat == Dissat::Unique
&& right.non_malleable
&& right.dissat == Dissat::Unique
&& (left.safe || right.safe),
})
}
fn or_d(left: Self, right: Self) -> Result<Self, ErrorKind> {
Ok(Malleability {
dissat: right.dissat,
safe: left.safe && right.safe,
non_malleable: left.non_malleable
&& left.dissat == Dissat::Unique
&& right.non_malleable
&& (left.safe || right.safe),
})
}
fn or_c(left: Self, right: Self) -> Result<Self, ErrorKind> {
Ok(Malleability {
dissat: Dissat::None,
safe: left.safe && right.safe,
non_malleable: left.non_malleable
&& left.dissat == Dissat::Unique
&& right.non_malleable
&& (left.safe || right.safe),
})
}
fn or_i(left: Self, right: Self) -> Result<Self, ErrorKind> {
Ok(Malleability {
dissat: match (left.dissat, right.dissat) {
(Dissat::None, Dissat::None) => Dissat::None,
(Dissat::Unique, Dissat::None) => Dissat::Unique,
(Dissat::None, Dissat::Unique) => Dissat::Unique,
_ => Dissat::Unknown,
},
safe: left.safe && right.safe,
non_malleable: left.non_malleable && right.non_malleable && (left.safe || right.safe),
})
}
fn and_or(a: Self, b: Self, c: Self) -> Result<Self, ErrorKind> {
Ok(Malleability {
dissat: match (a.safe, b.dissat, c.dissat) {
(_, Dissat::None, Dissat::Unique) => Dissat::Unique, (true, _, Dissat::Unique) => Dissat::Unique, (_, Dissat::None, Dissat::None) => Dissat::None, (true, _, Dissat::None) => Dissat::None, _ => Dissat::Unknown,
},
safe: (a.safe || b.safe) && c.safe,
non_malleable: a.non_malleable
&& c.non_malleable
&& a.dissat == Dissat::Unique
&& b.non_malleable
&& (a.safe || b.safe || c.safe),
})
}
fn threshold<S>(k: usize, n: usize, mut sub_ck: S) -> Result<Self, ErrorKind>
where
S: FnMut(usize) -> Result<Self, ErrorKind>,
{
let mut safe_count = 0;
let mut all_are_dissat_unique = true;
let mut all_are_non_malleable = true;
for i in 0..n {
let subtype = sub_ck(i)?;
safe_count += if subtype.safe { 1 } else { 0 };
all_are_dissat_unique &= subtype.dissat == Dissat::Unique;
all_are_non_malleable &= subtype.non_malleable;
}
Ok(Malleability {
dissat: if all_are_dissat_unique && safe_count == n {
Dissat::Unique
} else {
Dissat::Unknown
},
safe: safe_count > n - k,
non_malleable: all_are_non_malleable && safe_count >= n - k && all_are_dissat_unique,
})
}
}