Skip to content
This repository was archived by the owner on Oct 19, 2024. It is now read-only.

Commit

Permalink
fix(core): normalize signature S (#2679)
Browse files Browse the repository at this point in the history
* fix(core): normalize signature S

* chore: clippy
  • Loading branch information
DaniPopes authored Nov 20, 2023
1 parent dc6022e commit 4e09be8
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 6 deletions.
2 changes: 1 addition & 1 deletion ethers-contract/tests/it/contract_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ fn _contract_call_into_future_is_send() {
future
}

is_send(contract.cache().into_future());
drop(is_send(contract.cache().into_future()));
}
22 changes: 20 additions & 2 deletions ethers-core/src/types/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ impl Signature {

/// Retrieves the recovery signature.
fn as_signature(&self) -> Result<(RecoverableSignature, RecoveryId), SignatureError> {
let recovery_id = self.recovery_id()?;
let signature = {
let mut recovery_id = self.recovery_id()?;
let mut signature = {
let mut r_bytes = [0u8; 32];
let mut s_bytes = [0u8; 32];
self.r.to_big_endian(&mut r_bytes);
Expand All @@ -138,6 +138,14 @@ impl Signature {
K256Signature::from_scalars(*gar, *gas)?
};

// Normalize into "low S" form. See:
// - https://github.com/RustCrypto/elliptic-curves/issues/988
// - https://github.com/bluealloy/revm/pull/870
if let Some(normalized) = signature.normalize_s() {
signature = normalized;
recovery_id = RecoveryId::from_byte(recovery_id.to_byte() ^ 1).unwrap();
}

Ok((signature, recovery_id))
}

Expand Down Expand Up @@ -324,6 +332,16 @@ mod tests {
assert_eq!(tx.recover_from().unwrap(), expected);
}

#[test]
fn can_recover_tx_sender_not_normalized() {
let sig = Signature::from_str("48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c8041b").unwrap();
let hash =
H256::from_str("5eb4f5a33c621f32a8622d5f943b6b102994dfe4e5aebbefe69bb1b2aa0fc93e")
.unwrap();
let expected = Address::from_str("0f65fe9276bc9a24ae7083ae28e2660ef72df99e").unwrap();
assert_eq!(sig.recover(hash).unwrap(), expected);
}

#[test]
fn recover_web3_signature() {
// test vector taken from:
Expand Down
6 changes: 3 additions & 3 deletions ethers-core/src/types/transaction/eip2718.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,9 +417,9 @@ impl TypedTransaction {
impl Decodable for TypedTransaction {
fn decode(rlp: &rlp::Rlp) -> Result<Self, rlp::DecoderError> {
let tx_type: Option<U64> = match rlp.is_data() {
true => Ok(Some(rlp.data()?.into())),
false => Ok(None),
}?;
true => Some(rlp.data()?.into()),
false => None,
};
let rest = rlp::Rlp::new(
rlp.as_raw().get(1..).ok_or(rlp::DecoderError::Custom("no transaction payload"))?,
);
Expand Down

0 comments on commit 4e09be8

Please sign in to comment.