Skip to main content

rings_core/ecc/
mod.rs

1//! ECDSA, EdDSA, and ElGamal
2use std::convert::TryFrom;
3use std::str::FromStr;
4
5use ethereum_types::H160;
6use hex;
7use k256::ecdsa::RecoveryId;
8use k256::ecdsa::Signature as K256Signature;
9use k256::ecdsa::SigningKey as K256SigningKey;
10use k256::ecdsa::VerifyingKey as K256VerifyingKey;
11use k256::AffinePoint as K256AffinePoint;
12use k256::PublicKey as K256PublicKey;
13use k256::Scalar as K256Scalar;
14use k256::SecretKey as K256SecretKey;
15use rand::SeedableRng;
16use rand_hc::Hc128Rng;
17use serde::Deserialize;
18use serde::Serialize;
19use sha1::Digest;
20use sha1::Sha1;
21use subtle::CtOption;
22
23use crate::error::Error;
24use crate::error::Result;
25pub mod elgamal;
26pub mod group;
27pub mod keys;
28/// Signature schemes used by DID identity and provider login.
29pub mod signers;
30mod types;
31use elliptic_curve::generic_array::typenum::U32;
32use elliptic_curve::generic_array::GenericArray;
33use elliptic_curve::point::AffineCoordinates;
34use elliptic_curve::point::DecompressPoint;
35use elliptic_curve::sec1::ToEncodedPoint;
36use elliptic_curve::FieldBytes;
37use elliptic_curve::PrimeField as _;
38pub use group::*;
39pub use keys::*;
40use p256::NistP256;
41use subtle::Choice;
42pub use types::PublicKey;
43
44/// ref <https://docs.rs/web3/0.18.0/src/web3/signing.rs.html#69>
45///
46/// length r: 32, length s: 32, length v(recovery_id): 1
47pub type SigBytes = [u8; 65];
48/// Alias PublicKey.
49pub type CurveEle<const SIZE: usize> = PublicKey<SIZE>;
50/// PublicKeyAddress is H160.
51pub type PublicKeyAddress = H160;
52
53/// Secp256k1 secret key bytes.
54///
55/// The bytes are validated at construction time and stay in the canonical
56/// external format used by existing configs and DIDs.
57#[derive(PartialEq, Eq, Clone, Copy)]
58pub struct SecretKey([u8; 32]);
59
60impl std::fmt::Debug for SecretKey {
61    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62        f.debug_tuple("SecretKey").field(&"<redacted>").finish()
63    }
64}
65
66/// Wrap String into HashStr.
67#[derive(Deserialize, Serialize, Debug, Clone, Eq, PartialEq)]
68pub struct HashStr(String);
69
70/// Compute the Keccak-256 hash of input bytes.
71pub fn keccak256(bytes: &[u8]) -> [u8; 32] {
72    use tiny_keccak::Hasher;
73    use tiny_keccak::Keccak;
74    let mut output = [0u8; 32];
75    let mut hasher = Keccak::v256();
76    hasher.update(bytes);
77    hasher.finalize(&mut output);
78    output
79}
80
81impl HashStr {
82    /// Create a hash string wrapper from an existing string value.
83    pub fn new<T: Into<String>>(s: T) -> Self {
84        HashStr(s.into())
85    }
86
87    /// Compute the SHA-1 digest of raw bytes and encode it as lowercase hex.
88    pub fn from_bytes(bytes: &[u8]) -> Self {
89        let mut hasher = Sha1::new();
90        hasher.update(bytes);
91        HashStr(hex::encode(hasher.finalize()))
92    }
93
94    /// Return the wrapped hash string.
95    pub fn inner(&self) -> String {
96        self.0.clone()
97    }
98}
99
100impl TryFrom<PublicKey<33>> for K256PublicKey {
101    type Error = Error;
102    fn try_from(key: PublicKey<33>) -> Result<Self> {
103        Self::from_sec1_bytes(&key.0).map_err(|_| Error::ECDSAPublicKeyBadFormat)
104    }
105}
106
107impl TryFrom<PublicKey<33>> for ed25519_dalek::VerifyingKey {
108    type Error = Error;
109    fn try_from(key: PublicKey<33>) -> Result<Self> {
110        // pubkey[0] == 0
111        let [_, bytes @ ..] = key.0;
112        Self::from_bytes(&bytes).map_err(|_| Error::EdDSAPublicKeyBadFormat)
113    }
114}
115
116impl AffineCoordinates for PublicKey<33> {
117    type FieldRepr = GenericArray<u8, U32>;
118
119    fn x(&self) -> Self::FieldRepr {
120        let [_, x @ ..] = self.0;
121        GenericArray::<u8, U32>::from(x)
122    }
123
124    fn y_is_odd(&self) -> subtle::Choice {
125        let [prefix, ..] = self.0;
126        match prefix {
127            2u8 => Choice::from(1),
128            3u8 => Choice::from(0),
129            _ => Choice::from(0),
130        }
131    }
132}
133
134impl PublicKey<33> {
135    /// Map a PublicKey into secp256r1 affine point,
136    /// This function is an constant-time cryptographic implementations
137    pub fn ct_into_secp256r1_affine(self) -> CtOption<primeorder::AffinePoint<NistP256>> {
138        primeorder::AffinePoint::<NistP256>::decompress(&self.x(), self.y_is_odd())
139    }
140
141    /// Map a PublicKey into secp256r1 public key,
142    /// This function is an constant-time cryptographic implementations
143    pub fn ct_try_into_secp256r1_pubkey(self) -> CtOption<Result<ecdsa::VerifyingKey<NistP256>>> {
144        let opt_affine: CtOption<primeorder::AffinePoint<NistP256>> =
145            self.ct_into_secp256r1_affine();
146        opt_affine.and_then(|affine| {
147            let ret =
148                ecdsa::VerifyingKey::<NistP256>::from_affine(affine).map_err(Error::ECDSAError);
149            match ret {
150                Ok(_r) => CtOption::new(ret, Choice::from(1)),
151                Err(_) => CtOption::new(ret, Choice::from(0)),
152            }
153        })
154    }
155}
156
157impl From<SecretKey> for FieldBytes<NistP256> {
158    fn from(val: SecretKey) -> Self {
159        GenericArray::<u8, U32>::from(val.ser())
160    }
161}
162
163impl From<ed25519_dalek::VerifyingKey> for PublicKey<33> {
164    fn from(key: ed25519_dalek::VerifyingKey) -> Self {
165        // [u8;32] here
166        // ref: https://docs.rs/ed25519-dalek/latest/ed25519_dalek/struct.VerifyingKey.html
167        let mut data = [0u8; 33];
168        let key_bytes = key.to_bytes();
169        if let Some(suffix) = data.get_mut(1..) {
170            suffix.copy_from_slice(&key_bytes);
171        }
172        Self(data)
173    }
174}
175
176impl TryFrom<PublicKey<33>> for K256AffinePoint {
177    type Error = Error;
178    fn try_from(key: PublicKey<33>) -> Result<Self> {
179        Ok(TryInto::<K256PublicKey>::try_into(key)?
180            .to_projective()
181            .to_affine())
182    }
183}
184
185impl TryFrom<K256AffinePoint> for PublicKey<33> {
186    type Error = Error;
187    fn try_from(a: K256AffinePoint) -> Result<Self> {
188        let encoded = a.to_encoded_point(true);
189        let data: [u8; 33] = encoded
190            .as_bytes()
191            .try_into()
192            .map_err(|_| Error::InvalidPublicKey)?;
193        Ok(Self(data))
194    }
195}
196
197impl From<K256PublicKey> for PublicKey<33> {
198    fn from(key: K256PublicKey) -> Self {
199        let encoded = key.to_encoded_point(true);
200        let mut data = [0u8; 33];
201        if encoded.as_bytes().len() == data.len() {
202            data.copy_from_slice(encoded.as_bytes());
203        }
204        Self(data)
205    }
206}
207
208impl From<K256VerifyingKey> for PublicKey<33> {
209    fn from(key: K256VerifyingKey) -> Self {
210        let encoded = key.to_encoded_point(true);
211        let mut data = [0u8; 33];
212        if encoded.as_bytes().len() == data.len() {
213            data.copy_from_slice(encoded.as_bytes());
214        }
215        Self(data)
216    }
217}
218
219impl From<SecretKey> for PublicKey<33> {
220    fn from(secret_key: SecretKey) -> Self {
221        secret_key.pubkey()
222    }
223}
224
225impl<T> From<T> for HashStr
226where T: Into<String>
227{
228    fn from(s: T) -> Self {
229        let inputs = s.into();
230        HashStr::from_bytes(inputs.as_bytes())
231    }
232}
233
234impl TryFrom<&str> for SecretKey {
235    type Error = Error;
236    fn try_from(s: &str) -> Result<Self> {
237        let key = hex::decode(s)?;
238        let key_arr: [u8; 32] = key.as_slice().try_into()?;
239        Self::from_bytes(key_arr)
240    }
241}
242
243impl std::str::FromStr for SecretKey {
244    type Err = Error;
245
246    fn from_str(s: &str) -> Result<Self> {
247        Self::try_from(s)
248    }
249}
250
251#[allow(clippy::to_string_trait_impl)]
252impl ToString for SecretKey {
253    fn to_string(&self) -> String {
254        hex::encode(self.0)
255    }
256}
257
258struct SecretKeyVisitor;
259
260impl<'de> serde::de::Visitor<'de> for SecretKeyVisitor {
261    type Value = SecretKey;
262
263    fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
264        formatter.write_str("SecretKey deserializer")
265    }
266    fn visit_str<E>(self, value: &str) -> std::result::Result<Self::Value, E>
267    where E: serde::de::Error {
268        SecretKey::from_str(value).map_err(|e| serde::de::Error::custom(e))
269    }
270}
271
272impl<'de> Deserialize<'de> for SecretKey {
273    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
274    where D: serde::Deserializer<'de> {
275        deserializer.deserialize_str(SecretKeyVisitor)
276    }
277}
278
279impl Serialize for SecretKey {
280    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
281    where S: serde::Serializer {
282        serializer.serialize_str(self.to_string().as_str())
283    }
284}
285
286fn public_key_address(pubkey: &PublicKey<33>) -> PublicKeyAddress {
287    let hash = match TryInto::<K256PublicKey>::try_into(*pubkey) {
288        // if pubkey is ecdsa key
289        Ok(pk) => {
290            let data = pk.to_encoded_point(false);
291            let data = data.as_bytes();
292            debug_assert_eq!(data.first(), Some(&0x04));
293            keccak256(data.get(1..).unwrap_or_default())
294        }
295        // if pubkey is eddsa key
296        Err(_) => keccak256(pubkey.0.get(1..).unwrap_or_default()),
297    };
298    PublicKeyAddress::from_slice(&hash[12..])
299}
300
301fn secret_key_address(secret_key: &SecretKey) -> PublicKeyAddress {
302    secret_key.pubkey().address()
303}
304
305impl SecretKey {
306    pub(crate) fn from_bytes(bytes: [u8; 32]) -> Result<Self> {
307        K256SecretKey::from_slice(&bytes).map_err(|_| Error::PrivateKeyBadFormat)?;
308        Ok(Self(bytes))
309    }
310
311    pub(crate) fn secp256k1_scalar(&self) -> K256Scalar {
312        Option::<K256Scalar>::from(K256Scalar::from_repr(self.0.into())).unwrap_or(K256Scalar::ONE)
313    }
314
315    /// Generate a random secp256k1 secret key.
316    pub fn random() -> Self {
317        let mut rng = Hc128Rng::from_entropy();
318        let bytes = K256SecretKey::random(&mut rng).to_bytes();
319        Self(bytes.into())
320    }
321
322    /// Derive the Ethereum-style address for this secret key.
323    pub fn address(&self) -> PublicKeyAddress {
324        secret_key_address(self)
325    }
326
327    /// Sign a UTF-8 message after hashing it with Keccak-256.
328    pub fn sign(&self, message: &str) -> SigBytes {
329        self.sign_raw(message.as_bytes())
330    }
331
332    /// Sign raw message bytes after hashing them with Keccak-256.
333    pub fn sign_raw(&self, message: &[u8]) -> SigBytes {
334        let message_hash = keccak256(message);
335        self.sign_hash(&message_hash)
336    }
337
338    /// Sign an already computed 32-byte message hash.
339    pub fn sign_hash(&self, message_hash: &[u8; 32]) -> SigBytes {
340        let signing_key = match K256SigningKey::from_slice(&self.0) {
341            Ok(signing_key) => signing_key,
342            Err(_) => return [0u8; 65],
343        };
344        let (signature, recover_id) = match signing_key.sign_prehash_recoverable(message_hash) {
345            Ok(signature) => signature,
346            Err(_) => return [0u8; 65],
347        };
348        let mut sig_bytes: SigBytes = [0u8; 65];
349        sig_bytes[0..64].copy_from_slice(signature.to_bytes().as_slice());
350        sig_bytes[64] = recover_id.to_byte();
351        sig_bytes
352    }
353
354    /// Derive the compressed public key for this secret key.
355    pub fn pubkey(&self) -> PublicKey<33> {
356        match K256SecretKey::from_slice(&self.0) {
357            Ok(secret_key) => secret_key.public_key().into(),
358            Err(_) => PublicKey([0u8; 33]),
359        }
360    }
361
362    /// Serialize this secret key into its 32-byte representation.
363    pub fn ser(&self) -> [u8; 32] {
364        self.0
365    }
366}
367
368impl PublicKey<33> {
369    /// Derive the Ethereum-style address for this public key.
370    pub fn address(&self) -> PublicKeyAddress {
371        public_key_address(self)
372    }
373}
374
375/// Recover PublicKey from RawMessage using signature.
376pub fn recover<S>(message: &[u8], signature: S) -> Result<PublicKey<33>>
377where S: AsRef<[u8]> {
378    let sig_bytes: SigBytes = signature.as_ref().try_into()?;
379    let message_hash: [u8; 32] = keccak256(message);
380    recover_hash(&message_hash, &sig_bytes)
381}
382
383/// Recover PublicKey from HashMessage using signature.
384pub fn recover_hash(message_hash: &[u8; 32], sig: &[u8; 65]) -> Result<PublicKey<33>> {
385    let r_s_signature: [u8; 64] = sig[..64].try_into()?;
386    let recovery_id: u8 = sig[64];
387    let signature = K256Signature::try_from(r_s_signature.as_slice()).map_err(Error::ECDSAError)?;
388    let recovery_id =
389        RecoveryId::from_byte(recovery_id).ok_or(Error::InvalidRecoverId(recovery_id))?;
390    Ok(
391        K256VerifyingKey::recover_from_prehash(message_hash, &signature, recovery_id)
392            .map_err(Error::ECDSAError)?
393            .into(),
394    )
395}
396
397#[cfg(test)]
398pub(crate) mod tests {
399    use hex::FromHex;
400
401    use super::*;
402
403    #[test]
404    fn test_parse_to_string_with_sha10x00() {
405        let s = "65860affb4b570dba06db294aa7c676f68e04a5bf2721243ad3cbc05a79c68c0";
406        let t: HashStr = s.into();
407        assert_eq!(t.0.len(), 40);
408    }
409
410    #[test]
411    fn test_parse_to_string_with_sha10x01() {
412        let s = "hello";
413        let t: HashStr = s.into();
414        assert_eq!(t.0.len(), 40);
415    }
416
417    #[test]
418    fn test_metamask_sign_for_debug() {
419        let key = &SecretKey::try_from(
420            "65860affb4b570dba06db294aa7c676f68e04a5bf2721243ad3cbc05a79c68c0",
421        )
422        .unwrap();
423        let sig_hash =
424            Vec::from_hex("4a5c5d454721bbbb25540c3317521e71c373ae36458f960d2ad46ef088110e95")
425                .unwrap();
426        let msg = "test";
427        // https://docs.rs/web3/latest/src/web3/signing.rs.html#221
428        let prefix_msg_ret = "\x19Ethereum Signed Message:\n4test"
429            .to_string()
430            .into_bytes();
431        let mut prefix_msg = format!("\x19Ethereum Signed Message:\n{}", msg.len()).into_bytes();
432        prefix_msg.extend_from_slice(msg.as_bytes());
433        assert_eq!(
434            prefix_msg,
435            prefix_msg_ret,
436            "{}",
437            String::from_utf8(prefix_msg.clone()).unwrap()
438        );
439        //        let hash = hash_message(msg.as_bytes()).0;
440        assert_eq!(keccak256(prefix_msg_ret.as_slice()), sig_hash.as_slice());
441        // window.ethereum.request({method: "personal_sign", params: ["test", "0x11E807fcc88dD319270493fB2e822e388Fe36ab0"]})
442        let metamask_sig = Vec::from_hex("724fc31d9272b34d8406e2e3a12a182e72510b008de6cc44684577e31e20d9626fb760d6a0badd79a6cf4cd56b2fc0fbd60c438b809aa7d29bfb598c13e7b50e1b").unwrap();
443        assert_eq!(metamask_sig.len(), 65);
444        let h: [u8; 32] = sig_hash.as_slice().try_into().unwrap();
445        let recover_id = key.sign_hash(&h)[64];
446        assert_eq!(recover_id, 0);
447        let mut sig = key.sign_raw(&prefix_msg);
448        sig[64] = 27;
449        assert_eq!(sig, metamask_sig.as_slice());
450    }
451
452    #[test]
453    fn test_recover() {
454        let key = SecretKey::random();
455        let pubkey1 = key.pubkey();
456        let pubkey2 = recover("hello".as_bytes(), key.sign("hello")).unwrap();
457        assert_eq!(pubkey1, pubkey2);
458    }
459
460    pub(crate) fn gen_ordered_keys(n: usize) -> Vec<SecretKey> {
461        let mut keys = Vec::from_iter(std::iter::repeat_with(SecretKey::random).take(n));
462        keys.sort_by(|a, b| {
463            if a.address() < b.address() {
464                std::cmp::Ordering::Less
465            } else {
466                std::cmp::Ordering::Greater
467            }
468        });
469        keys
470    }
471}