Replace libsecp256k1 with secp256k1 (#10798)

* Replace libsecp256k1 with secp256k1

* Wipe ecdsa secret key from memory on drop

* Some comments for a known issue

* Safer core crypto primitives `from_slice` constructor

Previous version panics if slice lenght is not the expected one.

* Unit test fix

* Enable use of global secp256k1 context

* Better comments for ecdsa `Pair` drop

* Replace `libsecp256k1` with `seco256k1` in `beefy-mmr`

Used to convert ecdsa public key to ETH address

* Replace `libsecp256k1` with `secp256k1` in FRAME `contracts`benchmarks

* Temporary rollback of `beefy-mmr` to libsecp256k1

Check for detected build issues

* Cargo fmt

* Rollback of FRAME `contracts` benchmarks to `libsecp256k1`

* Rollback for unrelated changes

* Typo fix

* Add comments for deprecated `ecdsa_verify` and `secp256k1_ecdsa_recover`
This commit is contained in:
Davide Galassi
2022-02-26 22:00:00 +01:00
committed by GitHub
parent b77d3f917d
commit 4aab84cc42
10 changed files with 184 additions and 152 deletions
+21 -1
View File
@@ -8382,7 +8382,6 @@ version = "0.10.0-dev"
dependencies = [
"hex-literal",
"lazy_static",
"libsecp256k1",
"lru 0.6.6",
"parity-scale-codec",
"parking_lot 0.12.0",
@@ -9170,6 +9169,25 @@ dependencies = [
"zeroize",
]
[[package]]
name = "secp256k1"
version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab7883017d5b21f011ef8040ea9c6c7ac90834c0df26a69e4c0b06276151f125"
dependencies = [
"rand 0.6.5",
"secp256k1-sys",
]
[[package]]
name = "secp256k1-sys"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "957da2573cde917463ece3570eab4a0b3f19de6f1646cde62e6fd3868f566036"
dependencies = [
"cc",
]
[[package]]
name = "secrecy"
version = "0.8.0"
@@ -9817,6 +9835,7 @@ dependencies = [
"regex",
"scale-info",
"schnorrkel",
"secp256k1",
"secrecy",
"serde",
"serde_json",
@@ -9927,6 +9946,7 @@ dependencies = [
"log 0.4.14",
"parity-scale-codec",
"parking_lot 0.12.0",
"secp256k1",
"sp-core",
"sp-externalities",
"sp-keystore",
+1
View File
@@ -265,6 +265,7 @@ percent-encoding = { opt-level = 3 }
primitive-types = { opt-level = 3 }
ring = { opt-level = 3 }
rustls = { opt-level = 3 }
secp256k1 = { opt-level = 3 }
sha2 = { opt-level = 3 }
sha3 = { opt-level = 3 }
smallvec = { opt-level = 3 }
@@ -105,7 +105,7 @@ fn cryptos_are_compatible() {
let sp_core_signature = sp_core_secret.sign(message); // no error expected...
assert!(sp_core::ed25519::Pair::verify(
&sp_core::ed25519::Signature::from_slice(&libp2p_signature),
&sp_core::ed25519::Signature::from_slice(&libp2p_signature).unwrap(),
message,
&sp_core_public
));
-1
View File
@@ -31,7 +31,6 @@ sc-executor-common = { version = "0.10.0-dev", path = "common" }
sc-executor-wasmi = { version = "0.10.0-dev", path = "wasmi" }
sc-executor-wasmtime = { version = "0.10.0-dev", path = "wasmtime", optional = true }
parking_lot = "0.12.0"
libsecp256k1 = "0.7"
sp-core-hashing-proc-macro = { version = "4.0.0-dev", path = "../../primitives/core/hashing/proc-macro" }
lru = "0.6.6"
tracing = "0.1.29"
+4 -1
View File
@@ -54,8 +54,9 @@ schnorrkel = { version = "0.9.1", features = [
"u64_backend",
], default-features = false, optional = true }
hex = { version = "0.4", default-features = false, optional = true }
libsecp256k1 = { version = "0.7", default-features = false, features = ["hmac", "static-context"], optional = true }
libsecp256k1 = { version = "0.7", default-features = false, features = ["static-context"], optional = true }
merlin = { version = "2.0", default-features = false, optional = true }
secp256k1 = { version = "0.21.2", default-features = false, features = ["recovery", "global-context"], optional = true }
ss58-registry = { version = "1.11.0", default-features = false }
sp-core-hashing = { version = "4.0.0", path = "./hashing", default-features = false, optional = true }
sp-runtime-interface = { version = "5.0.0", default-features = false, path = "../runtime-interface" }
@@ -106,6 +107,7 @@ std = [
"schnorrkel/std",
"regex",
"num-traits/std",
"secp256k1/std",
"sp-core-hashing/std",
"sp-debug-derive/std",
"sp-externalities",
@@ -129,6 +131,7 @@ full_crypto = [
"schnorrkel",
"hex",
"libsecp256k1",
"secp256k1",
"sp-core-hashing",
"sp-runtime-interface/disable_target_static_assertions",
"merlin",
+105 -115
View File
@@ -15,9 +15,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// tag::description[]
//! Simple ECDSA API.
// end::description[]
//! Simple ECDSA secp256k1 API.
use codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
@@ -37,9 +35,12 @@ use crate::{
#[cfg(feature = "std")]
use bip39::{Language, Mnemonic, MnemonicType};
#[cfg(feature = "full_crypto")]
use core::convert::{TryFrom, TryInto};
use core::convert::TryFrom;
#[cfg(feature = "full_crypto")]
use libsecp256k1::{PublicKey, SecretKey};
use secp256k1::{
ecdsa::{RecoverableSignature, RecoveryId},
Message, PublicKey, SecretKey, SECP256K1,
};
#[cfg(feature = "std")]
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
#[cfg(feature = "full_crypto")]
@@ -57,7 +58,17 @@ type Seed = [u8; 32];
/// The ECDSA compressed public key.
#[cfg_attr(feature = "full_crypto", derive(Hash))]
#[derive(
Clone, Encode, Decode, PassByInner, MaxEncodedLen, TypeInfo, Eq, PartialEq, PartialOrd, Ord,
Clone,
Copy,
Encode,
Decode,
PassByInner,
MaxEncodedLen,
TypeInfo,
Eq,
PartialEq,
PartialOrd,
Ord,
)]
pub struct Public(pub [u8; 33]);
@@ -75,10 +86,16 @@ impl Public {
/// This will convert the full public key into the compressed format.
#[cfg(feature = "std")]
pub fn from_full(full: &[u8]) -> Result<Self, ()> {
libsecp256k1::PublicKey::parse_slice(full, None)
.map(|k| k.serialize_compressed())
.map(Self)
.map_err(|_| ())
let pubkey = if full.len() == 64 {
// Tag it as uncompressed public key.
let mut tagged_full = [0u8; 65];
tagged_full[0] = 0x04;
tagged_full[1..].copy_from_slice(full);
secp256k1::PublicKey::from_slice(&tagged_full)
} else {
secp256k1::PublicKey::from_slice(full)
};
pubkey.map(|k| Self(k.serialize())).map_err(|_| ())
}
}
@@ -296,55 +313,46 @@ impl Signature {
///
/// NOTE: No checking goes on to ensure this is a real signature. Only use it if
/// you are certain that the array actually is a signature. GIGO!
pub fn from_slice(data: &[u8]) -> Self {
pub fn from_slice(data: &[u8]) -> Option<Self> {
if data.len() != 65 {
return None
}
let mut r = [0u8; 65];
r.copy_from_slice(data);
Signature(r)
Some(Signature(r))
}
/// Recover the public key from this signature and a message.
#[cfg(feature = "full_crypto")]
pub fn recover<M: AsRef<[u8]>>(&self, message: M) -> Option<Public> {
let message = libsecp256k1::Message::parse(&blake2_256(message.as_ref()));
let sig: (_, _) = self.try_into().ok()?;
libsecp256k1::recover(&message, &sig.0, &sig.1)
.ok()
.map(|recovered| Public(recovered.serialize_compressed()))
self.recover_prehashed(&blake2_256(message.as_ref()))
}
/// Recover the public key from this signature and a pre-hashed message.
#[cfg(feature = "full_crypto")]
pub fn recover_prehashed(&self, message: &[u8; 32]) -> Option<Public> {
let message = libsecp256k1::Message::parse(message);
let sig: (_, _) = self.try_into().ok()?;
libsecp256k1::recover(&message, &sig.0, &sig.1)
let rid = RecoveryId::from_i32(self.0[64] as i32).ok()?;
let sig = RecoverableSignature::from_compact(&self.0[..64], rid).ok()?;
let message = Message::from_slice(message).expect("Message is 32 bytes; qed");
SECP256K1
.recover_ecdsa(&message, &sig)
.ok()
.map(|key| Public(key.serialize_compressed()))
.map(|pubkey| Public(pubkey.serialize()))
}
}
#[cfg(feature = "full_crypto")]
impl From<(libsecp256k1::Signature, libsecp256k1::RecoveryId)> for Signature {
fn from(x: (libsecp256k1::Signature, libsecp256k1::RecoveryId)) -> Signature {
impl From<RecoverableSignature> for Signature {
fn from(recsig: RecoverableSignature) -> Signature {
let mut r = Self::default();
r.0[0..64].copy_from_slice(&x.0.serialize()[..]);
r.0[64] = x.1.serialize();
let (recid, sig) = recsig.serialize_compact();
r.0[..64].copy_from_slice(&sig);
// This is safe due to the limited range of possible valid ids.
r.0[64] = recid.to_i32() as u8;
r
}
}
#[cfg(feature = "full_crypto")]
impl<'a> TryFrom<&'a Signature> for (libsecp256k1::Signature, libsecp256k1::RecoveryId) {
type Error = ();
fn try_from(
x: &'a Signature,
) -> Result<(libsecp256k1::Signature, libsecp256k1::RecoveryId), Self::Error> {
parse_signature_standard(&x.0).map_err(|_| ())
}
}
/// Derive a single hard junction.
#[cfg(feature = "full_crypto")]
fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed {
@@ -362,7 +370,7 @@ pub enum DeriveError {
#[cfg(feature = "full_crypto")]
#[derive(Clone)]
pub struct Pair {
public: PublicKey,
public: Public,
secret: SecretKey,
}
@@ -416,8 +424,9 @@ impl TraitPair for Pair {
/// You should never need to use this; generate(), generate_with_phrase
fn from_seed_slice(seed_slice: &[u8]) -> Result<Pair, SecretStringError> {
let secret =
SecretKey::parse_slice(seed_slice).map_err(|_| SecretStringError::InvalidSeedLength)?;
let public = PublicKey::from_secret_key(&secret);
SecretKey::from_slice(seed_slice).map_err(|_| SecretStringError::InvalidSeedLength)?;
let public = PublicKey::from_secret_key(SECP256K1, &secret);
let public = Public(public.serialize());
Ok(Pair { public, secret })
}
@@ -427,7 +436,7 @@ impl TraitPair for Pair {
path: Iter,
_seed: Option<Seed>,
) -> Result<(Pair, Option<Seed>), DeriveError> {
let mut acc = self.secret.serialize();
let mut acc = self.seed();
for j in path {
match j {
DeriveJunction::Soft(_cc) => return Err(DeriveError::SoftKeyInPath),
@@ -439,25 +448,19 @@ impl TraitPair for Pair {
/// Get the public key.
fn public(&self) -> Public {
Public(self.public.serialize_compressed())
self.public
}
/// Sign a message.
fn sign(&self, message: &[u8]) -> Signature {
let message = libsecp256k1::Message::parse(&blake2_256(message));
libsecp256k1::sign(&message, &self.secret).into()
self.sign_prehashed(&blake2_256(message))
}
/// Verify a signature on a message. Returns true if the signature is good.
fn verify<M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool {
let message = libsecp256k1::Message::parse(&blake2_256(message.as_ref()));
let sig: (_, _) = match sig.try_into() {
Ok(x) => x,
_ => return false,
};
match libsecp256k1::recover(&message, &sig.0, &sig.1) {
Ok(actual) => pubkey.0[..] == actual.serialize_compressed()[..],
_ => false,
match sig.recover(message) {
Some(actual) => actual == *pubkey,
None => false,
}
}
@@ -466,17 +469,9 @@ impl TraitPair for Pair {
/// This doesn't use the type system to ensure that `sig` and `pubkey` are the correct
/// size. Use it only if you're coming from byte buffers and need the speed.
fn verify_weak<P: AsRef<[u8]>, M: AsRef<[u8]>>(sig: &[u8], message: M, pubkey: P) -> bool {
let message = libsecp256k1::Message::parse(&blake2_256(message.as_ref()));
if sig.len() != 65 {
return false
}
let (sig, ri) = match parse_signature_standard(&sig) {
Ok(sigri) => sigri,
_ => return false,
};
match libsecp256k1::recover(&message, &sig, &ri) {
Ok(actual) => pubkey.as_ref() == &actual.serialize()[1..],
_ => false,
match Signature::from_slice(sig).and_then(|sig| sig.recover(message)) {
Some(actual) => actual.as_ref() == pubkey.as_ref(),
None => false,
}
}
@@ -490,7 +485,7 @@ impl TraitPair for Pair {
impl Pair {
/// Get the seed for this key.
pub fn seed(&self) -> Seed {
self.secret.serialize()
self.secret.serialize_secret()
}
/// Exactly as `from_string` except that if no matches are found then, the the first 32
@@ -507,57 +502,57 @@ impl Pair {
/// Sign a pre-hashed message
pub fn sign_prehashed(&self, message: &[u8; 32]) -> Signature {
let message = libsecp256k1::Message::parse(message);
libsecp256k1::sign(&message, &self.secret).into()
let message = Message::from_slice(message).expect("Message is 32 bytes; qed");
SECP256K1.sign_ecdsa_recoverable(&message, &self.secret).into()
}
/// Verify a signature on a pre-hashed message. Return `true` if the signature is valid
/// and thus matches the given `public` key.
pub fn verify_prehashed(sig: &Signature, message: &[u8; 32], public: &Public) -> bool {
let message = libsecp256k1::Message::parse(message);
let sig: (_, _) = match sig.try_into() {
Ok(x) => x,
_ => return false,
};
match libsecp256k1::recover(&message, &sig.0, &sig.1) {
Ok(actual) => public.0[..] == actual.serialize_compressed()[..],
_ => false,
match sig.recover_prehashed(message) {
Some(actual) => actual == *public,
None => false,
}
}
/// Verify a signature on a message. Returns true if the signature is good.
/// Parses Signature using parse_overflowing_slice
/// Parses Signature using parse_overflowing_slice.
#[deprecated(note = "please use `verify` instead")]
pub fn verify_deprecated<M: AsRef<[u8]>>(sig: &Signature, message: M, pubkey: &Public) -> bool {
let message = libsecp256k1::Message::parse(&blake2_256(message.as_ref()));
let (sig, ri) = match parse_signature_overflowing(&sig.0) {
Ok(sigri) => sigri,
let parse_signature_overflowing = |x: [u8; 65]| {
let sig = libsecp256k1::Signature::parse_overflowing_slice(&x[..64]).ok()?;
let rid = libsecp256k1::RecoveryId::parse(x[64]).ok()?;
Some((sig, rid))
};
let (sig, rid) = match parse_signature_overflowing(sig.0) {
Some(sigri) => sigri,
_ => return false,
};
match libsecp256k1::recover(&message, &sig, &ri) {
Ok(actual) => pubkey.0[..] == actual.serialize_compressed()[..],
match libsecp256k1::recover(&message, &sig, &rid) {
Ok(actual) => pubkey.0 == actual.serialize_compressed(),
_ => false,
}
}
}
// The `secp256k1` backend doesn't implement cleanup for their private keys.
// Currently we should take care of wiping the secret from memory.
// NOTE: this solution is not effective when `Pair` is moved around memory.
// The very same problem affects other cryptographic backends that are just using
// `zeroize`for their secrets.
#[cfg(feature = "full_crypto")]
fn parse_signature_standard(
x: &[u8],
) -> Result<(libsecp256k1::Signature, libsecp256k1::RecoveryId), libsecp256k1::Error> {
let sig = libsecp256k1::Signature::parse_standard_slice(&x[..64])?;
let ri = libsecp256k1::RecoveryId::parse(x[64])?;
Ok((sig, ri))
}
#[cfg(feature = "full_crypto")]
fn parse_signature_overflowing(
x: &[u8],
) -> Result<(libsecp256k1::Signature, libsecp256k1::RecoveryId), libsecp256k1::Error> {
let sig = libsecp256k1::Signature::parse_overflowing_slice(&x[..64])?;
let ri = libsecp256k1::RecoveryId::parse(x[64])?;
Ok((sig, ri))
impl Drop for Pair {
fn drop(&mut self) {
let ptr = self.secret.as_mut_ptr();
for off in 0..self.secret.len() {
unsafe {
core::ptr::write_volatile(ptr.add(off), 0);
}
}
}
}
impl CryptoType for Public {
@@ -578,12 +573,9 @@ impl CryptoType for Pair {
#[cfg(test)]
mod test {
use super::*;
use crate::{
crypto::{
set_default_ss58_version, PublicError, Ss58AddressFormat, Ss58AddressFormatRegistry,
DEV_PHRASE,
},
keccak_256,
use crate::crypto::{
set_default_ss58_version, PublicError, Ss58AddressFormat, Ss58AddressFormatRegistry,
DEV_PHRASE,
};
use hex_literal::hex;
use serde_json;
@@ -802,22 +794,20 @@ mod test {
// `msg` shouldn't be mangled
let msg = [0u8; 32];
let sig1 = pair.sign_prehashed(&msg);
let sig2: Signature =
libsecp256k1::sign(&libsecp256k1::Message::parse(&msg), &pair.secret).into();
let sig2: Signature = {
let message = Message::from_slice(&msg).unwrap();
SECP256K1.sign_ecdsa_recoverable(&message, &pair.secret).into()
};
assert_eq!(sig1, sig2);
// signature is actually different
let sig2 = pair.sign(&msg);
assert_ne!(sig1, sig2);
// using pre-hashed `msg` works
let msg = keccak_256(b"this should be hashed");
let sig1 = pair.sign_prehashed(&msg);
let sig2: Signature =
libsecp256k1::sign(&libsecp256k1::Message::parse(&msg), &pair.secret).into();
let msg = b"this should be hashed";
let sig1 = pair.sign_prehashed(&blake2_256(msg));
let sig2 = pair.sign(msg);
assert_eq!(sig1, sig2);
}
@@ -826,12 +816,12 @@ mod test {
let (pair, _, _) = Pair::generate_with_phrase(Some("password"));
// `msg` and `sig` match
let msg = keccak_256(b"this should be hashed");
let msg = blake2_256(b"this should be hashed");
let sig = pair.sign_prehashed(&msg);
assert!(Pair::verify_prehashed(&sig, &msg, &pair.public()));
// `msg` and `sig` don't match
let msg = keccak_256(b"this is a different message");
let msg = blake2_256(b"this is a different message");
assert!(!Pair::verify_prehashed(&sig, &msg, &pair.public()));
}
@@ -840,7 +830,7 @@ mod test {
let (pair, _, _) = Pair::generate_with_phrase(Some("password"));
// recovered key matches signing key
let msg = keccak_256(b"this should be hashed");
let msg = blake2_256(b"this should be hashed");
let sig = pair.sign_prehashed(&msg);
let key = sig.recover_prehashed(&msg).unwrap();
assert_eq!(pair.public(), key);
@@ -849,7 +839,7 @@ mod test {
assert!(Pair::verify_prehashed(&sig, &msg, &key));
// recovered key and signing key don't match
let msg = keccak_256(b"this is a different message");
let msg = blake2_256(b"this is a different message");
let key = sig.recover_prehashed(&msg).unwrap();
assert_ne!(pair.public(), key);
}
+5 -2
View File
@@ -321,10 +321,13 @@ impl Signature {
///
/// NOTE: No checking goes on to ensure this is a real signature. Only use it if
/// you are certain that the array actually is a signature. GIGO!
pub fn from_slice(data: &[u8]) -> Self {
pub fn from_slice(data: &[u8]) -> Option<Self> {
if data.len() != 64 {
return None
}
let mut r = [0u8; 64];
r.copy_from_slice(data);
Signature(r)
Some(Signature(r))
}
/// A new instance from an H512.
+5 -2
View File
@@ -341,10 +341,13 @@ impl Signature {
///
/// NOTE: No checking goes on to ensure this is a real signature. Only use it if
/// you are certain that the array actually is a signature. GIGO!
pub fn from_slice(data: &[u8]) -> Self {
pub fn from_slice(data: &[u8]) -> Option<Self> {
if data.len() != 64 {
return None
}
let mut r = [0u8; 64];
r.copy_from_slice(data);
Signature(r)
Some(Signature(r))
}
/// A new instance from an H512.
+2
View File
@@ -30,6 +30,7 @@ sp-tracing = { version = "4.0.0", default-features = false, path = "../tracing"
log = { version = "0.4.8", optional = true }
futures = { version = "0.3.1", features = ["thread-pool"], optional = true }
parking_lot = { version = "0.12.0", optional = true }
secp256k1 = { version = "0.21.2", features = ["recovery", "global-context"], optional = true }
tracing = { version = "0.1.29", default-features = false }
tracing-core = { version = "0.1.17", default-features = false}
@@ -44,6 +45,7 @@ std = [
"sp-trie",
"sp-state-machine",
"libsecp256k1",
"secp256k1",
"sp-runtime-interface/std",
"sp-externalities",
"sp-wasm-interface/std",
+40 -29
View File
@@ -66,6 +66,12 @@ use sp_runtime_interface::{
use codec::{Decode, Encode};
#[cfg(feature = "std")]
use secp256k1::{
ecdsa::{RecoverableSignature, RecoveryId},
Message, SECP256K1,
};
#[cfg(feature = "std")]
use sp_externalities::{Externalities, ExternalitiesExt};
@@ -647,7 +653,7 @@ pub trait Crypto {
SyncCryptoStore::sign_with(keystore, id, &pub_key.into(), msg)
.ok()
.flatten()
.map(|sig| ed25519::Signature::from_slice(sig.as_slice()))
.and_then(|sig| ed25519::Signature::from_slice(&sig))
}
/// Verify `ed25519` signature.
@@ -771,7 +777,7 @@ pub trait Crypto {
SyncCryptoStore::sign_with(keystore, id, &pub_key.into(), msg)
.ok()
.flatten()
.map(|sig| sr25519::Signature::from_slice(sig.as_slice()))
.and_then(|sig| sr25519::Signature::from_slice(&sig))
}
/// Verify an `sr25519` signature.
@@ -820,7 +826,7 @@ pub trait Crypto {
SyncCryptoStore::sign_with(keystore, id, &pub_key.into(), msg)
.ok()
.flatten()
.map(|sig| ecdsa::Signature::from_slice(sig.as_slice()))
.and_then(|sig| ecdsa::Signature::from_slice(&sig))
}
/// Sign the given a pre-hashed `msg` with the `ecdsa` key that corresponds to the given public
@@ -842,7 +848,9 @@ pub trait Crypto {
/// Verify `ecdsa` signature.
///
/// Returns `true` when the verification was successful.
/// This version is able to handle, non-standard, overflowing signatures.
fn ecdsa_verify(sig: &ecdsa::Signature, msg: &[u8], pub_key: &ecdsa::Public) -> bool {
#[allow(deprecated)]
ecdsa::Pair::verify_deprecated(sig, msg, pub_key)
}
@@ -891,18 +899,20 @@ pub trait Crypto {
///
/// Returns `Err` if the signature is bad, otherwise the 64-byte pubkey
/// (doesn't include the 0x04 prefix).
/// This version is able to handle, non-standard, overflowing signatures.
fn secp256k1_ecdsa_recover(
sig: &[u8; 65],
msg: &[u8; 32],
) -> Result<[u8; 64], EcdsaVerifyError> {
let rs = libsecp256k1::Signature::parse_overflowing_slice(&sig[0..64])
.map_err(|_| EcdsaVerifyError::BadRS)?;
let v = libsecp256k1::RecoveryId::parse(
if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8
let rid = libsecp256k1::RecoveryId::parse(
if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8,
)
.map_err(|_| EcdsaVerifyError::BadV)?;
let pubkey = libsecp256k1::recover(&libsecp256k1::Message::parse(msg), &rs, &v)
.map_err(|_| EcdsaVerifyError::BadSignature)?;
let sig = libsecp256k1::Signature::parse_overflowing_slice(&sig[..64])
.map_err(|_| EcdsaVerifyError::BadRS)?;
let msg = libsecp256k1::Message::parse(msg);
let pubkey =
libsecp256k1::recover(&msg, &sig, &rid).map_err(|_| EcdsaVerifyError::BadSignature)?;
let mut res = [0u8; 64];
res.copy_from_slice(&pubkey.serialize()[1..65]);
Ok(res)
@@ -920,16 +930,16 @@ pub trait Crypto {
sig: &[u8; 65],
msg: &[u8; 32],
) -> Result<[u8; 64], EcdsaVerifyError> {
let rs = libsecp256k1::Signature::parse_standard_slice(&sig[0..64])
let rid = RecoveryId::from_i32(if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as i32)
.map_err(|_| EcdsaVerifyError::BadV)?;
let sig = RecoverableSignature::from_compact(&sig[..64], rid)
.map_err(|_| EcdsaVerifyError::BadRS)?;
let v = libsecp256k1::RecoveryId::parse(
if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8
)
.map_err(|_| EcdsaVerifyError::BadV)?;
let pubkey = libsecp256k1::recover(&libsecp256k1::Message::parse(msg), &rs, &v)
let msg = Message::from_slice(msg).expect("Message is 32 bytes; qed");
let pubkey = SECP256K1
.recover_ecdsa(&msg, &sig)
.map_err(|_| EcdsaVerifyError::BadSignature)?;
let mut res = [0u8; 64];
res.copy_from_slice(&pubkey.serialize()[1..65]);
res.copy_from_slice(&pubkey.serialize_uncompressed()[1..]);
Ok(res)
}
@@ -943,14 +953,15 @@ pub trait Crypto {
sig: &[u8; 65],
msg: &[u8; 32],
) -> Result<[u8; 33], EcdsaVerifyError> {
let rs = libsecp256k1::Signature::parse_overflowing_slice(&sig[0..64])
.map_err(|_| EcdsaVerifyError::BadRS)?;
let v = libsecp256k1::RecoveryId::parse(
if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8
let rid = libsecp256k1::RecoveryId::parse(
if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8,
)
.map_err(|_| EcdsaVerifyError::BadV)?;
let pubkey = libsecp256k1::recover(&libsecp256k1::Message::parse(msg), &rs, &v)
.map_err(|_| EcdsaVerifyError::BadSignature)?;
let sig = libsecp256k1::Signature::parse_overflowing_slice(&sig[0..64])
.map_err(|_| EcdsaVerifyError::BadRS)?;
let msg = libsecp256k1::Message::parse(msg);
let pubkey =
libsecp256k1::recover(&msg, &sig, &rid).map_err(|_| EcdsaVerifyError::BadSignature)?;
Ok(pubkey.serialize_compressed())
}
@@ -965,15 +976,15 @@ pub trait Crypto {
sig: &[u8; 65],
msg: &[u8; 32],
) -> Result<[u8; 33], EcdsaVerifyError> {
let rs = libsecp256k1::Signature::parse_standard_slice(&sig[0..64])
let rid = RecoveryId::from_i32(if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as i32)
.map_err(|_| EcdsaVerifyError::BadV)?;
let sig = RecoverableSignature::from_compact(&sig[..64], rid)
.map_err(|_| EcdsaVerifyError::BadRS)?;
let v = libsecp256k1::RecoveryId::parse(
if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8
)
.map_err(|_| EcdsaVerifyError::BadV)?;
let pubkey = libsecp256k1::recover(&libsecp256k1::Message::parse(msg), &rs, &v)
let msg = Message::from_slice(msg).expect("Message is 32 bytes; qed");
let pubkey = SECP256K1
.recover_ecdsa(&msg, &sig)
.map_err(|_| EcdsaVerifyError::BadSignature)?;
Ok(pubkey.serialize_compressed())
Ok(pubkey.serialize())
}
}