|
@@ -247,7 +247,7 @@ impl TryFrom<Secret> for P2PKConditions {
|
|
|
.secret_data
|
|
|
.tags
|
|
|
.into_iter()
|
|
|
- .flat_map(Tag::try_from)
|
|
|
+ .map(|t| Tag::try_from(t).unwrap())
|
|
|
.map(|t| (t.kind(), t))
|
|
|
.collect();
|
|
|
|
|
@@ -344,12 +344,15 @@ impl Proof {
|
|
|
return Ok(());
|
|
|
}
|
|
|
|
|
|
+ println!("{:?}", spending_conditions.refund_keys);
|
|
|
+
|
|
|
if let Some(locktime) = spending_conditions.locktime {
|
|
|
// If lock time has passed check if refund witness signature is valid
|
|
|
if locktime.lt(&unix_time()) && !spending_conditions.refund_keys.is_empty() {
|
|
|
for s in &self.witness.signatures {
|
|
|
for v in &spending_conditions.refund_keys {
|
|
|
- let sig = Signature::try_from(s.as_bytes())
|
|
|
+ println!("{}", v);
|
|
|
+ let sig = Signature::try_from(hex::decode(s)?.as_slice())
|
|
|
.map_err(|_| Error::InvalidSignature)?;
|
|
|
|
|
|
// As long as there is one valid refund signature it can be spent
|
|
@@ -488,43 +491,34 @@ where
|
|
|
type Error = Error;
|
|
|
|
|
|
fn try_from(tag: Vec<S>) -> Result<Self, Self::Error> {
|
|
|
- let tag_len = tag.len();
|
|
|
let tag_kind: TagKind = match tag.first() {
|
|
|
Some(kind) => TagKind::from(kind),
|
|
|
None => return Err(Error::KindNotFound),
|
|
|
};
|
|
|
|
|
|
- if tag_len.eq(&2) {
|
|
|
- match tag_kind {
|
|
|
- TagKind::SigFlag => Ok(Tag::SigFlag(SigFlag::from(tag[1].as_ref()))),
|
|
|
- TagKind::NSigs => Ok(Tag::NSigs(tag[1].as_ref().parse()?)),
|
|
|
- TagKind::Locktime => Ok(Tag::LockTime(tag[1].as_ref().parse()?)),
|
|
|
- _ => Err(Error::UnknownTag),
|
|
|
+ match tag_kind {
|
|
|
+ TagKind::SigFlag => Ok(Tag::SigFlag(SigFlag::from(tag[1].as_ref()))),
|
|
|
+ TagKind::NSigs => Ok(Tag::NSigs(tag[1].as_ref().parse()?)),
|
|
|
+ TagKind::Locktime => Ok(Tag::LockTime(tag[1].as_ref().parse()?)),
|
|
|
+ TagKind::Refund => {
|
|
|
+ let pubkeys = tag
|
|
|
+ .iter()
|
|
|
+ .skip(1)
|
|
|
+ .flat_map(|p| VerifyingKey::from_str(p.as_ref()))
|
|
|
+ .collect();
|
|
|
+
|
|
|
+ Ok(Self::Refund(pubkeys))
|
|
|
}
|
|
|
- } else if tag_len.gt(&1) {
|
|
|
- match tag_kind {
|
|
|
- TagKind::Refund => {
|
|
|
- let pubkeys = tag
|
|
|
- .iter()
|
|
|
- .skip(1)
|
|
|
- .flat_map(|p| VerifyingKey::from_str(p.as_ref()))
|
|
|
- .collect();
|
|
|
-
|
|
|
- Ok(Self::Refund(pubkeys))
|
|
|
- }
|
|
|
- TagKind::Pubkeys => {
|
|
|
- let pubkeys = tag
|
|
|
- .iter()
|
|
|
- .skip(1)
|
|
|
- .flat_map(|p| VerifyingKey::from_str(p.as_ref()))
|
|
|
- .collect();
|
|
|
-
|
|
|
- Ok(Self::PubKeys(pubkeys))
|
|
|
- }
|
|
|
- _ => Err(Error::UnknownTag),
|
|
|
+ TagKind::Pubkeys => {
|
|
|
+ let pubkeys = tag
|
|
|
+ .iter()
|
|
|
+ .skip(1)
|
|
|
+ .flat_map(|p| VerifyingKey::from_str(p.as_ref()))
|
|
|
+ .collect();
|
|
|
+
|
|
|
+ Ok(Self::PubKeys(pubkeys))
|
|
|
}
|
|
|
- } else {
|
|
|
- Err(Error::UnknownTag)
|
|
|
+ _ => Err(Error::UnknownTag),
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -775,13 +769,24 @@ mod tests {
|
|
|
)
|
|
|
.unwrap();
|
|
|
|
|
|
+ let signing_key_two = SigningKey::from_str(
|
|
|
+ "0000000000000000000000000000000000000000000000000000000000000001",
|
|
|
+ )
|
|
|
+ .unwrap();
|
|
|
+
|
|
|
+ let signing_key_three = SigningKey::from_str(
|
|
|
+ "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
|
|
|
+ )
|
|
|
+ .unwrap();
|
|
|
let v_key: VerifyingKey = secret_key.verifying_key();
|
|
|
+ let v_key_two: VerifyingKey = signing_key_two.verifying_key();
|
|
|
+ let v_key_three: VerifyingKey = signing_key_three.verifying_key();
|
|
|
|
|
|
let conditions = P2PKConditions {
|
|
|
- locktime: None,
|
|
|
- pubkeys: vec![v_key],
|
|
|
- refund_keys: vec![],
|
|
|
- num_sigs: None,
|
|
|
+ locktime: Some(21),
|
|
|
+ pubkeys: vec![v_key.clone(), v_key_two, v_key_three],
|
|
|
+ refund_keys: vec![v_key],
|
|
|
+ num_sigs: Some(2),
|
|
|
sig_flag: SigFlag::SigInputs,
|
|
|
};
|
|
|
|
|
@@ -802,4 +807,53 @@ mod tests {
|
|
|
|
|
|
assert!(proof.verify_p2pk().is_ok());
|
|
|
}
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn test_verify() {
|
|
|
+ // Proof with a valid signature
|
|
|
+ let valid_proof = r#"{"amount":1,"secret":"[\"P2PK\",{\"nonce\":\"859d4935c4907062a6297cf4e663e2835d90d97ecdd510745d32f6816323a41f\",\"data\":\"0249098aa8b9d2fbec49ff8598feb17b592b986e62319a4fa488a3dc36387157a7\",\"tags\":[[\"sigflag\",\"SIG_INPUTS\"]]}]","C":"02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904","id":"009a1f293253e41e","witness":"{\"signatures\":[\"60f3c9b766770b46caac1d27e1ae6b77c8866ebaeba0b9489fe6a15a837eaa6fcd6eaa825499c72ac342983983fd3ba3a8a41f56677cc99ffd73da68b59e1383\"]}"}"#;
|
|
|
+
|
|
|
+ let valid_proof: Proof = serde_json::from_str(valid_proof).unwrap();
|
|
|
+
|
|
|
+ assert!(valid_proof.verify_p2pk().is_ok());
|
|
|
+
|
|
|
+ // Proof with a signature that is in a different secret
|
|
|
+ let invalid_proof = r#"{"amount":1,"secret":"[\"P2PK\",{\"nonce\":\"859d4935c4907062a6297cf4e663e2835d90d97ecdd510745d32f6816323a41f\",\"data\":\"0249098aa8b9d2fbec49ff8598feb17b592b986e62319a4fa488a3dc36387157a7\",\"tags\":[[\"sigflag\",\"SIG_INPUTS\"]]}]","C":"02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904","id":"009a1f293253e41e","witness":"{\"signatures\":[\"3426df9730d365a9d18d79bed2f3e78e9172d7107c55306ac5ddd1b2d065893366cfa24ff3c874ebf1fc22360ba5888ddf6ff5dbcb9e5f2f5a1368f7afc64f15\"]}"}"#;
|
|
|
+
|
|
|
+ let invalid_proof: Proof = serde_json::from_str(invalid_proof).unwrap();
|
|
|
+
|
|
|
+ assert!(invalid_proof.verify_p2pk().is_err());
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn verify_multi_sig() {
|
|
|
+ // Proof with 2 valid signatures to satifiy the condition
|
|
|
+ let valid_proof = r#"{"amount":0,"secret":"[\"P2PK\",{\"nonce\":\"0ed3fcb22c649dd7bbbdcca36e0c52d4f0187dd3b6a19efcc2bfbebb5f85b2a1\",\"data\":\"0249098aa8b9d2fbec49ff8598feb17b592b986e62319a4fa488a3dc36387157a7\",\"tags\":[[\"pubkeys\",\"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798\",\"02142715675faf8da1ecc4d51e0b9e539fa0d52fdd96ed60dbe99adb15d6b05ad9\"],[\"n_sigs\",\"2\"],[\"sigflag\",\"SIG_INPUTS\"]]}]","C":"02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904","id":"009a1f293253e41e","witness":"{\"signatures\":[\"83564aca48c668f50d022a426ce0ed19d3a9bdcffeeaee0dc1e7ea7e98e9eff1840fcc821724f623468c94f72a8b0a7280fa9ef5a54a1b130ef3055217f467b3\",\"9a72ca2d4d5075be5b511ee48dbc5e45f259bcf4a4e8bf18587f433098a9cd61ff9737dc6e8022de57c76560214c4568377792d4c2c6432886cc7050487a1f22\"]}"}"#;
|
|
|
+
|
|
|
+ let valid_proof: Proof = serde_json::from_str(valid_proof).unwrap();
|
|
|
+
|
|
|
+ assert!(valid_proof.verify_p2pk().is_ok());
|
|
|
+
|
|
|
+ // Proof with onlt one of the required signatures
|
|
|
+ let invalid_proof = r#"{"amount":0,"secret":"[\"P2PK\",{\"nonce\":\"0ed3fcb22c649dd7bbbdcca36e0c52d4f0187dd3b6a19efcc2bfbebb5f85b2a1\",\"data\":\"0249098aa8b9d2fbec49ff8598feb17b592b986e62319a4fa488a3dc36387157a7\",\"tags\":[[\"pubkeys\",\"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798\",\"02142715675faf8da1ecc4d51e0b9e539fa0d52fdd96ed60dbe99adb15d6b05ad9\"],[\"n_sigs\",\"2\"],[\"sigflag\",\"SIG_INPUTS\"]]}]","C":"02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904","id":"009a1f293253e41e","witness":"{\"signatures\":[\"83564aca48c668f50d022a426ce0ed19d3a9bdcffeeaee0dc1e7ea7e98e9eff1840fcc821724f623468c94f72a8b0a7280fa9ef5a54a1b130ef3055217f467b3\"]}"}"#;
|
|
|
+
|
|
|
+ let invalid_proof: Proof = serde_json::from_str(invalid_proof).unwrap();
|
|
|
+
|
|
|
+ // Verification should fail without the requires signatures
|
|
|
+ assert!(invalid_proof.verify_p2pk().is_err());
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn verify_refund() {
|
|
|
+ let valid_proof = r#"{"amount":0,"secret":"[\"P2PK\",{\"nonce\":\"3eff971bb1ca70b16be3446a4d3feedf2f37f054c5c8621d832744df71b028f0\",\"data\":\"0249098aa8b9d2fbec49ff8598feb17b592b986e62319a4fa488a3dc36387157a7\",\"tags\":[[\"pubkeys\",\"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798\",\"02142715675faf8da1ecc4d51e0b9e539fa0d52fdd96ed60dbe99adb15d6b05ad9\"],[\"locktime\",\"21\"],[\"n_sigs\",\"2\"],[\"refund\",\"49098aa8b9d2fbec49ff8598feb17b592b986e62319a4fa488a3dc36387157a7\"],[\"sigflag\",\"SIG_INPUTS\"]]}]","C":"02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904","id":"009a1f293253e41e","witness":"{\"signatures\":[\"94c6355461ca88e5d22c4e65e920b2e8253ccb4dd084675453a7bba7044e580246bd05e2520691afeccb2a88784cc56064353aec8b6a61e172727ba9cb3054a1\"]}"}"#;
|
|
|
+
|
|
|
+ let valid_proof: Proof = serde_json::from_str(valid_proof).unwrap();
|
|
|
+ assert!(valid_proof.verify_p2pk().is_ok());
|
|
|
+
|
|
|
+ let invalid_proof = r#"{"amount":0,"secret":"[\"P2PK\",{\"nonce\":\"d14cf9be9d9438d548b6b9d29bf800611136d053421b0f48c38d1447a7a92fc8\",\"data\":\"0249098aa8b9d2fbec49ff8598feb17b592b986e62319a4fa488a3dc36387157a7\",\"tags\":[[\"pubkeys\",\"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798\",\"02142715675faf8da1ecc4d51e0b9e539fa0d52fdd96ed60dbe99adb15d6b05ad9\"],[\"locktime\",\"2100000000000\"],[\"n_sigs\",\"2\"],[\"refund\",\"49098aa8b9d2fbec49ff8598feb17b592b986e62319a4fa488a3dc36387157a7\"],[\"sigflag\",\"SIG_INPUTS\"]]}]","C":"02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904","id":"009a1f293253e41e","witness":"{\"signatures\":[\"c3079dccf828e9d38bbbb17edf19c7915ee11920cf271c36b8780fdeb88b16fbfbe0328c7dcbe80e56cdc8f85c5831c79df77b27e81e5630a4dd392601fab9eb\"]}"}"#;
|
|
|
+
|
|
|
+ let invalid_proof: Proof = serde_json::from_str(invalid_proof).unwrap();
|
|
|
+
|
|
|
+ assert!(invalid_proof.verify_p2pk().is_err());
|
|
|
+ }
|
|
|
}
|