You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// High-S signatures require normalization since our verification implementation
59
+
// rejects them by default. If we had a verifier that does not restrict to
60
+
// low-S only, this step was not needed.
53
61
ifletSome(normalized) = signature.normalize_s(){
54
62
signature = normalized;
55
63
}
@@ -74,6 +82,22 @@ pub fn secp256k1_verify(
74
82
///
75
83
/// Returns the recovered pubkey in compressed form, which can be used
76
84
/// in secp256k1_verify directly.
85
+
///
86
+
/// This implementation accepts both high-S and low-S signatures. This is the
87
+
/// same behavior as Ethereum's `ecrecover`. The reason is that high-S signatures
88
+
/// may be perfectly valid if the application protocol does not disallow them.
89
+
/// Or as [EIP-2] put it "The ECDSA recover precompiled contract remains unchanged
90
+
/// and will keep accepting high s-values; this is useful e.g. if a contract
91
+
/// recovers old Bitcoin signatures.".
92
+
///
93
+
/// See also OpenZeppelin's [ECDSA.recover implementation](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.8.1/contracts/utils/cryptography/ECDSA.sol#L138-L149)
94
+
/// which adds further restrictions to avoid potential signature malleability.
95
+
/// Please note that restricting signatures to low-S does not make signatures unique
96
+
/// in the sense that for each (pubkey, message) there is only one signature. The
97
+
/// signer can generate an arbitrary amount of valid signatures.
"secp256k1_verify failed (test case {i} in {COSMOS_SECP256K1_TESTS_JSON})"
305
322
);
306
323
}
307
324
}
@@ -327,6 +344,7 @@ mod tests {
327
344
}
328
345
329
346
// Test data from https://github.com/randombit/botan/blob/2.9.0/src/tests/data/pubkey/ecdsa_key_recovery.vec
347
+
// This is a high-s value (`0x81F1A4457589F30D76AB9F89E748A68C8A94C30FE0BAC8FB5C0B54EA70BF6D2F > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0` is true)
330
348
{
331
349
let expected_x = "F3F8BB913AA68589A2C8C607A877AB05252ADBD963E1BE846DDEB8456942AEDC";
332
350
let expected_y = "A2ED51F08CA3EF3DAC0A7504613D54CD539FC1B3CBC92453CD704B6A2D012B2C";
@@ -349,6 +367,32 @@ mod tests {
349
367
let pubkey = secp256k1_recover_pubkey(&message_hash,&r_s, recovery_param).unwrap();
350
368
assert_eq!(pubkey, expected);
351
369
}
370
+
371
+
let file = File::open(COSMOS_SECP256K1_TESTS_JSON).unwrap();
372
+
let reader = BufReader::new(file);
373
+
let codes:Vec<Encoded> = serde_json::from_reader(reader).unwrap();
374
+
for(i, encoded)in(1..).zip(codes){
375
+
let message = hex::decode(&encoded.message).unwrap();
376
+
let signature = hex::decode(&encoded.signature).unwrap();
377
+
let public_key = hex::decode(&encoded.public_key).unwrap();
378
+
379
+
let hash = hex::decode(&encoded.message_hash).unwrap();
0 commit comments