Repository: nervosnetwork/ckb-system-scripts (language: rust)

Issue:
secp256k1_blake160_sighash_all can exit early if witness data is too large
https://github.com/nervosnetwork/ckb-system-scripts/blob/d2ae4cd4d627cd026f1f3777d5486d6abdcb8d6c/c/secp256k1_blake160_sighash_all.c#L126


Discussion / hints:

Fix patch:
diff --git a/build.rs b/build.rs
index fc1cefd..c168317 100644
--- a/build.rs
+++ b/build.rs
@@ -14,7 +14,7 @@ const CKB_HASH_PERSONALIZATION: &[u8] = b"ckb-default-hash";
 
 const BINARIES: &[(&str, &str)] = &[(
     "secp256k1_blake160_sighash_all",
-    "94334bdda40b69bae067d84937aa6bbccf8acd0df6626d4b9ac70d4612a11933",
+    "1435f069749e0b09a194b1d902a5e0c5f69554de9083d311addc7b3490b8ecd1",
 )];
 
 fn main() {
diff --git a/c/secp256k1_blake160_sighash_all.c b/c/secp256k1_blake160_sighash_all.c
index be6c3e8..cb3f5ef 100644
--- a/c/secp256k1_blake160_sighash_all.c
+++ b/c/secp256k1_blake160_sighash_all.c
@@ -16,6 +16,7 @@
 #define ERROR_SECP_SERIALIZE_PUBKEY -9
 #define ERROR_BUFFER_NOT_ENOUGH -10
 #define ERROR_ENCODING -11
+#define ERROR_WITNESS_TOO_LONG -12
 
 #define BLAKE2B_BLOCK_SIZE 32
 #define BLAKE160_SIZE 20
@@ -127,6 +128,9 @@ int main(int argc, char* argv[])
     if (ret != CKB_SUCCESS) {
       return ERROR_SYSCALL;
     }
+    if (len > WITNESS_SIZE) {
+      return ERROR_WITNESS_TOO_LONG;
+    }
 
     if (!(witness_table = ns(Witness_as_root(witness)))) {
       return ERROR_ENCODING;


Test patch:
diff --git a/tests/secp256k1_blake160_sighash_all.rs b/tests/secp256k1_blake160_sighash_all.rs
index f83de81..10e50b2 100644
--- a/tests/secp256k1_blake160_sighash_all.rs
+++ b/tests/secp256k1_blake160_sighash_all.rs
@@ -220,3 +220,42 @@ fn test_signing_wrong_tx_hash() {
         .verify(MAX_CYCLES);
     assert_eq!(verify_result, Err(ScriptError::ValidationFailure(-3)));
 }
+
+#[test]
+fn test_super_long_witness() {
+    let mut data_loader = DummyDataLoader::new();
+    let key_gen = Generator::new();
+    let privkey = key_gen.random_privkey();
+    let pubkey = privkey.pubkey().expect("pubkey");
+    // compute pubkey hash
+    let pubkey_hash = {
+        let ser_pk = pubkey.serialize();
+        hash::blake2b_256(ser_pk)[..20].to_vec()
+    };
+    let tx = gen_tx(
+        &mut data_loader,
+        SIGHASH_ALL_BIN.clone(),
+        vec![pubkey_hash.into()],
+    );
+
+    let mut buffer: Vec<u8> = vec![];
+    buffer.resize(40000, 1);
+    let super_long_message = Bytes::from(&buffer[..]);
+
+    let mut blake2b = hash::new_blake2b();
+    let mut message = [0u8; 32];
+    blake2b.update(&tx.hash()[..]);
+    blake2b.update(&super_long_message[..]);
+    blake2b.finalize(&mut message);
+    let message = H256::from(message);
+    let sig = privkey.sign_recoverable(&message).expect("sign");
+    let tx = TransactionBuilder::from_transaction(tx)
+        .witness(vec![Bytes::from(sig.serialize()), super_long_message])
+        .build();
+
+    let resolved_tx = build_resolved_tx(&tx, SIGHASH_ALL_BIN.len());
+    let script_config = ScriptConfig::default();
+    let verify_result = TransactionScriptsVerifier::new(&resolved_tx, &data_loader, &script_config)
+        .verify(MAX_CYCLES);
+    assert_eq!(verify_result, Err(ScriptError::ValidationFailure(-12)));
+}