diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index cfb3b68..278b1ce 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -1,4 +1,4 @@ -name: SSI Build +name: Lint, Build & Test on: pull_request: @@ -22,6 +22,16 @@ jobs: - uses: bufbuild/buf-setup-action@v1 + - name: Installing Rust Tools + run: |- + rustup component add rustfmt + rustup component add clippy + + - name: Linting + run: |- + cargo fmt --check --all + cargo clippy --all-targets --all-features -- -D warnings + - name: Build run: |- cargo build diff --git a/.github/workflows/linting.yaml b/.github/workflows/linting.yaml deleted file mode 100644 index 3fb1b7a..0000000 --- a/.github/workflows/linting.yaml +++ /dev/null @@ -1,23 +0,0 @@ -name: SSI Linting - -on: - pull_request: - branches: - - main -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - - name: Setup | Rust - uses: ATiltedTree/setup-rust@v1 - with: - rust-version: 1.62 - - - name: Installing - run: rustup component add rustfmt - - - name: Linting - run: |- - cargo fmt --check --all diff --git a/core/src/credential.rs b/core/src/credential.rs index ec36000..821417f 100644 --- a/core/src/credential.rs +++ b/core/src/credential.rs @@ -1,12 +1,5 @@ -use std::time::SystemTime; - -use crate::HashMap; -use serde::{Deserialize, Serialize}; -use serde_json::Value; - -mod formatter_context; -mod formatter_credential_date; -mod formatter_credential_type; +// This module attempts to provide a relatively simple & high level way of interacting with Credentials, Verifiable Credentials, Presentations and Verifiable Presentations +// Adheres to the https://www.w3.org/TR/vc-data-model/ spec. // cred_subject is a generic that implements trait X // trait X allows us to encode that object into JSON-LD @@ -15,104 +8,92 @@ mod formatter_credential_type; // --- // Default context and Cred types are defaulted but can be redefined -type VerificationContext = [&'static str; 2]; +pub type VerificationContext = Vec; -pub const CONTEXT_CREDENTIALS: VerificationContext = [ - "https://www.w3.org/2018/credentials/v1", - "https://www.w3.org/2018/credentials/examples/v1", -]; +pub const BASE_CREDENDIAL_CONTEXT: &str = "https://www.w3.org/2018/credentials/v1"; +pub const EXAMPLE_CREDENTIAL_CONTEXT: &str = "https://www.w3.org/2018/credentials/examples/v1"; -pub const CRED_TYPE_PERMANENT_RESIDENT_CARD: &'static str = "PermanentResidentCard"; -pub const CRED_TYPE_BANK_CARD: &'static str = "BankCard"; +#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)] +pub enum CredentialType { + #[serde(rename = "VerifiableCredential")] + Common, + PermanentResidentCard, + BankCard, +} -#[derive(Serialize, Deserialize, Clone, Debug)] +#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)] pub struct CredentialSubject { - id: String, + pub id: String, #[serde(flatten)] - pub property_set: HashMap, + pub property_set: std::collections::HashMap, } -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)] pub struct VerifiableCredential { #[serde(flatten)] - credential: Credential, + pub credential: Credential, pub proof: crate::proof::DataIntegrityProof, } -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)] pub struct Credential { #[serde(rename = "@context")] - #[serde(with = "formatter_context")] - context: Vec, + pub context: Vec, #[serde(rename = "@id")] - id: String, + pub id: String, #[serde(rename = "type")] - cred_type: Vec, + pub cred_type: Vec, #[serde(rename = "issuanceDate")] - #[serde(with = "formatter_credential_date")] - issuance_date: SystemTime, + pub issuance_date: String, #[serde(rename = "credentialSubject")] - subject: CredentialSubject, + pub subject: CredentialSubject, + #[serde(flatten)] - pub property_set: HashMap, + pub property_set: std::collections::HashMap, } impl Credential { - pub fn new( - context: VerificationContext, - cred_type: Vec, - cred_subject: HashMap, - property_set: HashMap, - id: &str, - ) -> Credential { - let vc = Credential { - context: context.into_iter().map(|s| s.to_string()).collect(), - id: id.to_string(), - cred_type: cred_type, - issuance_date: SystemTime::now(), - subject: CredentialSubject { - id: id.to_string(), - property_set: cred_subject, - }, - property_set: property_set, - }; - vc - } - - pub fn serialize(&self) -> Value { - return serde_json::to_value(&self).unwrap(); - } - - pub fn deserialize(contents: String) -> Result { - serde_json::from_str(&contents) + pub fn try_into_verifiable_credential( + self, + issuer_signer: &impl signature::suite::DIDSigner, + relation: signature::suite::VerificationRelation, + ) -> Result> { + let serialized_credential = serde_json::to_value(&self)?; + let proof = crate::proof::create_data_integrity_proof( + issuer_signer, + serialized_credential, + relation, + )?; + + Ok(VerifiableCredential { + credential: self, + proof, + }) } - pub fn create_verifiable_credentials( + pub fn into_verifiable_credential( self, integrity_proof: crate::proof::DataIntegrityProof, ) -> VerifiableCredential { - let vc = VerifiableCredential { + VerifiableCredential { credential: self, proof: integrity_proof, - }; - return vc; + } } } -#[derive(Debug, Serialize, Deserialize, Clone)] -#[serde(bound(deserialize = "'de: 'static"))] +#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)] pub struct VerifiablePresentation { #[serde(flatten)] - presentation: Presentation, - proof: crate::proof::DataIntegrityProof, + pub presentation: Presentation, + pub proof: crate::proof::DataIntegrityProof, } -#[derive(Debug, Serialize, Deserialize, Clone)] -#[serde(bound(deserialize = "'de: 'static"))] +#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)] pub struct Presentation { #[serde(rename = "@context")] pub context: VerificationContext, @@ -120,60 +101,47 @@ pub struct Presentation { pub verifiable_credential: Vec, } -impl Presentation { - pub fn new( - context: VerificationContext, - verifiable_credential: Vec, - ) -> Presentation { - Presentation { - context, - verifiable_credential, - } - } - - pub fn serialize(&self) -> Value { - return serde_json::to_value(&self).unwrap(); - } -} - #[cfg(test)] mod tests { - use crate::Credential; + use super::*; use assert_json_diff::assert_json_eq; use serde_json::json; #[test] fn test_create_credential_from_string() -> Result<(), String> { let expect = json!({ - "@context":["https://www.w3.org/2018/credentials/v1","https://www.w3.org/2018/credentials/examples/v1"],"@id":"https://issuer.oidp.uscis.gov/credentials/83627465","type":["VerifiableCredential", "PermanentResidentCard"],"issuer": "did:example:28394728934792387", + "@context":["https://www.w3.org/2018/credentials/v1","https://www.w3.org/2018/credentials/examples/v1"], + "@id":"https://issuer.oidp.uscis.gov/credentials/83627465", + "type":["VerifiableCredential", "PermanentResidentCard"], + "issuer": "did:example:28394728934792387", "identifier": "83627465", "name": "Permanent Resident Card", "description": "Government of Example Permanent Resident Card.", "issuanceDate": "2019-12-03T12:19:52Z", "expirationDate": "2029-12-03T12:19:52Z", "credentialSubject": { - "id": "did:example:b34ca6cd37bbf23", - "type": ["PermanentResident", "Person"], - "givenName": "JOHN", - "familyName": "SMITH", - "gender": "Male", - "image": "data:image/png;base64,iVBORw0KGgo...kJggg==", - "residentSince": "2015-01-01", - "lprCategory": "C09", - "lprNumber": "999-999-999", - "commuterClassification": "C1", - "birthCountry": "Bahamas", - "birthDate": "1958-07-17" + "id": "did:example:b34ca6cd37bbf23", + "type": ["PermanentResident", "Person"], + "givenName": "JOHN", + "familyName": "SMITH", + "gender": "Male", + "image": "data:image/png;base64,iVBORw0KGgo...kJggg==", + "residentSince": "2015-01-01", + "lprCategory": "C09", + "lprNumber": "999-999-999", + "commuterClassification": "C1", + "birthCountry": "Bahamas", + "birthDate": "1958-07-17" }, }); - let ds = Credential::deserialize(expect.to_string()); - if ds.is_ok() { - let vc = ds.unwrap().serialize(); + let res = serde_json::from_str::(&expect.to_string()); + assert!(res.is_ok()); + if let Ok(vc) = res { + let vc = serde_json::to_value(vc).unwrap(); assert_json_eq!(expect, vc); - } else { - assert!(false); } + Ok(()) } } diff --git a/core/src/credential/formatter_context.rs b/core/src/credential/formatter_context.rs deleted file mode 100644 index 38f3777..0000000 --- a/core/src/credential/formatter_context.rs +++ /dev/null @@ -1,24 +0,0 @@ -use serde::{self, Deserialize, Deserializer, Serializer}; -use std::string::String; - -pub fn serialize(ctx: &Vec, serializer: S) -> Result -where - S: Serializer, -{ - let ctx_vec = crate::CONTEXT_CREDENTIALS - .into_iter() - .map(|s| s.to_string()); - serializer.collect_seq(ctx_vec) -} - -pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - let s = Vec::::deserialize(deserializer)?; - let s = crate::CONTEXT_CREDENTIALS - .into_iter() - .map(|s| s.to_string()) - .collect(); - Ok(s) -} diff --git a/core/src/credential/formatter_credential_date.rs b/core/src/credential/formatter_credential_date.rs deleted file mode 100644 index 5b4e5ea..0000000 --- a/core/src/credential/formatter_credential_date.rs +++ /dev/null @@ -1,25 +0,0 @@ -use chrono::{DateTime, Utc}; -use serde::{self, Deserialize, Deserializer, Serializer}; -use std::string::String; -use std::time::SystemTime; - -const FORMAT: &'static str = "%Y-%m-%dT%H:%M:%SZ"; - -pub fn serialize(date: &SystemTime, serializer: S) -> Result -where - S: Serializer, -{ - let utc = DateTime::::from(*date).format(FORMAT); - serializer.serialize_str(&format!("{utc}")) -} - -pub fn deserialize<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - use serde::de::Error; - - String::deserialize(deserializer) // -> Result - .and_then(|s: String| DateTime::parse_from_rfc3339(&s).map_err(Error::custom)) - .map(SystemTime::from) -} diff --git a/core/src/credential/formatter_credential_type.rs b/core/src/credential/formatter_credential_type.rs deleted file mode 100644 index 74d9561..0000000 --- a/core/src/credential/formatter_credential_type.rs +++ /dev/null @@ -1,16 +0,0 @@ -use serde::{self, Deserialize, Deserializer, Serializer}; - -pub fn serialize(cr_type: &String, serializer: S) -> Result -where - S: Serializer, -{ - serializer.collect_seq(cr_type.split(",")) -} - -pub fn deserialize<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - let s = Vec::::deserialize(deserializer)?.join(","); - Ok(s) -} diff --git a/core/src/identity.rs b/core/src/identity.rs index 41c036b..6f1870c 100644 --- a/core/src/identity.rs +++ b/core/src/identity.rs @@ -31,7 +31,7 @@ fn create_did_document(verifier: impl signature::suite::DIDVerifier) -> Di where S: signature::suite::Signature, { - let did_doc = DidDocument { + DidDocument { context: vec![ "https://www.w3.org/ns/did/v1".to_string(), "https://w3id.org/security/suites/ed25519-2020/v1".to_string(), @@ -98,9 +98,7 @@ where signature::suite::VerificationRelation::AssertionMethod, ), }], - }; - - return did_doc; + } } #[derive(serde::Serialize, serde::Deserialize, Clone, Debug)] @@ -181,7 +179,7 @@ mod tests { #[rstest::rstest] #[case::restored_successfully(get_did(), get_json_restore_mock_ok(), true)] fn test_restore_identity( - #[case] did: String, + #[case] _did: String, #[case] restore_response: Result, #[case] expect_ok: bool, ) -> Result<(), String> { @@ -189,7 +187,7 @@ mod tests { resolver_mock .expect_read() .with(mockall::predicate::function(|did_doc: &String| -> bool { - did_doc.clone().len() > 0 + !did_doc.clone().is_empty() })) .return_once(|_| (restore_response)); @@ -232,8 +230,8 @@ mod tests { fn test_create_identity( #[case] mock_create_response: Result<(), crate::error::ResolverError>, - #[case] did_doc: String, - #[case] did_document_input_mock: serde_json::Value, + #[case] _did_doc: String, + #[case] _did_document_input_mock: serde_json::Value, #[case] expect_ok: bool, ) -> Result<(), String> { let mut resolver_mock = MockDIDResolver::default(); diff --git a/core/src/lib.rs b/core/src/lib.rs index 3f367cb..0a9d5e5 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -3,10 +3,6 @@ pub mod error; pub mod identity; pub mod proof; -use credential::*; -use serde_json::{self, Value}; -use std::collections::HashMap; - /// Verification of Data Integrity Proofs requires the resolution of the `verificationMethod` specified in the proof. /// The `verificationMethod` refers to a cryptographic key stored in some external source. /// The DIDResolver is responsible for resolving the `verificationMethod` to a key that can be used to verify the proof. @@ -33,24 +29,36 @@ pub trait DIDResolver: Send + Sync + 'static { } pub trait DocumentBuilder { + fn get_contexts() -> credential::VerificationContext { + vec![ + credential::BASE_CREDENDIAL_CONTEXT.to_string(), + credential::EXAMPLE_CREDENTIAL_CONTEXT.to_string(), + ] + } + /// Given the credential type and the credential subject information, create a unissued JSON-LD credential. /// In order to become a Verifiable Credential, a data integrity proof must be created for the credential and appended to the JSON-LD document. /// this is the default implementation of the `create` method. The `create` method can be overridden to create a custom credential. fn create_credential( &self, - cred_type: Vec, - cred_subject: HashMap, - property_set: HashMap, + cred_type: credential::CredentialType, + cred_subject: std::collections::HashMap, + property_set: std::collections::HashMap, id: &str, - ) -> Result> { - let vc = Credential::new( - CONTEXT_CREDENTIALS, - cred_type, - cred_subject, + ) -> Result> { + let context = Self::get_contexts(); + + Ok(credential::Credential { + context, + id: id.to_string(), + cred_type: vec![credential::CredentialType::Common, cred_type], + issuance_date: chrono::Utc::now().to_rfc3339(), + subject: credential::CredentialSubject { + id: id.to_string(), + property_set: cred_subject, + }, property_set, - id, - ); - Ok(vc) + }) } /// Given the set of credentials, create a unsigned JSON-LD Presentation of those credentials. @@ -58,9 +66,13 @@ pub trait DocumentBuilder { /// presentation and appended to the JSON-LD document. fn create_presentation( &self, - credentials: Vec, - ) -> Result> { - Ok(Presentation::new(CONTEXT_CREDENTIALS, credentials)) + credentials: Vec, + ) -> Result> { + let context = Self::get_contexts(); + Ok(credential::Presentation { + context, + verifiable_credential: credentials, + }) } } @@ -87,10 +99,9 @@ pub fn verify_presentation( #[cfg(test)] mod tests { - use crate::proof::create_data_integrity_proof; - use crate::serde_json::json; - use crate::DocumentBuilder; + use super::*; use assert_json_diff::assert_json_eq; + use serde_json::json; use std::{collections::HashMap, vec}; use serde_json::Value; @@ -106,12 +117,11 @@ mod tests { fn get_body_subject() -> (HashMap, HashMap) { let mut kv_body: HashMap = HashMap::new(); - let mut kv_subject: HashMap = HashMap::new(); let type_rs = json!(["VerifiableCredential", "PermanentResidentCard"]); kv_body.entry("type".to_string()).or_insert(type_rs); - let expect = json!({ + let _expect = json!({ "@context": [ "https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1" @@ -160,7 +170,7 @@ mod tests { json!(["VerifiableCredential", "PermanentResidentCard"]), ); - kv_subject = HashMap::from([ + let mut kv_subject: HashMap = HashMap::from([ ("id", "did:example:b34ca6cd37bbf23"), ("givenName", "JOHN"), ("familyName", "SMITH"), @@ -179,7 +189,7 @@ mod tests { kv_subject.insert("type".to_string(), json!(["PermanentResident", "Person"])); - return (kv_body, kv_subject); + (kv_body, kv_subject) } #[test] @@ -216,7 +226,7 @@ mod tests { let (kv_body, kv_subject) = get_body_subject(); let vc = to.create_credential( - vec![crate::CRED_TYPE_PERMANENT_RESIDENT_CARD.to_string()], + credential::CredentialType::PermanentResidentCard, kv_subject, kv_body, "https://issuer.oidp.uscis.gov/credentials/83627465", @@ -224,7 +234,7 @@ mod tests { assert!(vc.is_ok()); let credential = vc.unwrap(); - assert_json_eq!(expect_credential, credential.serialize()); + assert_json_eq!(expect_credential, serde_json::to_value(credential).unwrap()); Ok(()) } @@ -263,7 +273,7 @@ mod tests { let (kv_body, kv_subject) = get_body_subject(); let vc = to.create_credential( - vec![crate::CRED_TYPE_PERMANENT_RESIDENT_CARD.to_string()], + credential::CredentialType::PermanentResidentCard, kv_subject, kv_body, "https://issuer.oidp.uscis.gov/credentials/83627465", @@ -271,15 +281,15 @@ mod tests { assert!(vc.is_ok()); let credential = vc.unwrap(); - let proof = create_data_integrity_proof( + let proof = proof::create_data_integrity_proof( &signer, - credential.serialize(), + serde_json::to_value(credential.clone()).unwrap(), signature::suite::VerificationRelation::AssertionMethod, ); assert!(proof.is_ok()); - let verifiable_credential = credential.create_verifiable_credentials(proof.unwrap()); + let verifiable_credential = credential.into_verifiable_credential(proof.unwrap()); let credentials = vec![verifiable_credential]; let interim_presentation = to .create_presentation(credentials) @@ -289,7 +299,7 @@ mod tests { let interim_proof = serde_json::to_value(interim_proof).unwrap(); expect_presentation["verifiableCredential"][0]["proof"] = interim_proof; - let presentation_json = interim_presentation.serialize(); + let presentation_json = serde_json::to_value(interim_presentation).unwrap(); assert_json_eq!(expect_presentation, presentation_json); Ok(()) diff --git a/core/src/proof/normalization.rs b/core/src/proof/normalization.rs index e6b7996..f1e4d3c 100644 --- a/core/src/proof/normalization.rs +++ b/core/src/proof/normalization.rs @@ -1,5 +1,4 @@ pub fn normalize(doc: serde_json::Value) -> impl AsRef<[u8]> { let encoded = doc.to_string(); - let result = encoded.into_bytes(); - result + encoded.into_bytes() } diff --git a/registry_resolver/build.rs b/registry_resolver/build.rs index e2783bd..4bee9cb 100644 --- a/registry_resolver/build.rs +++ b/registry_resolver/build.rs @@ -1,8 +1,13 @@ fn main() -> Result<(), Box> { let package_path = "buf.build/knox-networks/registry-mgmt"; - std::process::Command::new("buf") + let std::process::Output { status, stderr, .. } = std::process::Command::new("buf") .arg("generate") .arg(package_path) - .spawn()?; + .output()?; + + if !status.success() { + return Err(String::from_utf8_lossy(&stderr).into()); + } + Ok(()) } diff --git a/registry_resolver/src/lib.rs b/registry_resolver/src/lib.rs index 28035ec..efbc90a 100644 --- a/registry_resolver/src/lib.rs +++ b/registry_resolver/src/lib.rs @@ -1,5 +1,5 @@ mod registry_client; -const DID_METHOD: &'static str = "knox"; +const DID_METHOD: &str = "knox"; #[derive(Clone, Debug)] pub struct RegistryResolver @@ -16,7 +16,7 @@ const fn get_method_helper() -> &'static str { impl RegistryResolver { pub async fn new(url: impl Into) -> Self { let client = registry_client::GrpcClient::new(url.into()).await; - RegistryResolver { client: client } + RegistryResolver { client } } } #[async_trait::async_trait] @@ -51,13 +51,12 @@ where .await .map_err(|e| ssi_core::error::ResolverError::NetworkFailure(e.to_string()))?; - let document = - res.into_inner() - .document - .ok_or(ssi_core::error::ResolverError::DocumentNotFound(format!( - "No document found associated with {}", - did - )))?; + let document = res.into_inner().document.ok_or_else(|| { + ssi_core::error::ResolverError::DocumentNotFound(format!( + "No document found associated with {}", + did + )) + })?; Ok(serde_json::to_value(document) .map_err(|e| ssi_core::error::ResolverError::InvalidData(e.to_string()))?) @@ -82,7 +81,7 @@ mod tests { } fn create_did_doc(did: String) -> serde_json::Value { - return serde_json::json!({ + serde_json::json!({ "@context":["https://www.w3.org/ns/did/v1","https://w3id.org/security/suites/ed25519-2020/v1"], "id":did, "authentication":[ @@ -98,15 +97,15 @@ mod tests { {"id":format!("did:knox:{}#{}", did, did),"type":"Ed25519VerificationKey2020","controller":"did:knox:z6MkfFmsob7fC3MmqU1JVfdBnMbnAw7xm1mrEtPvAoojLcRh","publicKeyMultibase":"z6MkfFmsob7fC3MmqU1JVfdBnMbnAw7xm1mrEtPvAoojLcRh" }] } - ); + ) } fn create_did_struct(doc: serde_json::Value) -> pbjson_types::Struct { - return serde_json::from_value(doc).unwrap(); + serde_json::from_value(doc).unwrap() } fn create_did() -> String { - return String::from("did:knox:z6MkfFmsob7fC3MmqU1JVfdBnMbnAw7xm1mrEtPvAoojLcRh"); + String::from("did:knox:z6MkfFmsob7fC3MmqU1JVfdBnMbnAw7xm1mrEtPvAoojLcRh") } #[rstest::rstest] @@ -140,14 +139,14 @@ mod tests { #[case] expect_ok: bool, ) { let mut mock_client = MockRegistryClient::default(); - if mock_create_response.is_some() { + if let Some(res) = mock_create_response { mock_client .expect_create() .with( mockall::predicate::eq(did.clone()), mockall::predicate::eq(Some(create_did_struct(doc.clone()))), ) - .return_once(|_, _| (mock_create_response.unwrap())); + .return_once(|_, _| (res)); } let resolver = RegistryResolver { @@ -197,11 +196,11 @@ mod tests { #[case] expect_ok: bool, ) { let mut mock_client = MockRegistryClient::default(); - if mock_read_response.is_some() { + if let Some(res) = mock_read_response { mock_client .expect_read() .with(mockall::predicate::eq(did.clone())) - .return_once(|_| (mock_read_response.unwrap())); + .return_once(|_| res); } let resolver = RegistryResolver { diff --git a/signature/src/suite/ed25519_2020.rs b/signature/src/suite/ed25519_2020.rs index af8ba50..133bcbe 100644 --- a/signature/src/suite/ed25519_2020.rs +++ b/signature/src/suite/ed25519_2020.rs @@ -7,7 +7,7 @@ const ED25519_SIGNATURE_2020: &str = "Ed25519Signature2020"; const ED25519_VERIFICATION_KEY_2020: &str = "Ed25519VerificationKey2020"; /// Ed25519 Multicodec constant -pub const MULTICODEC_ED25519_PUB: &'static [u8] = &[0xed, 0x01]; +pub const MULTICODEC_ED25519_PUB: &[u8] = &[0xed, 0x01]; pub mod error; @@ -93,7 +93,7 @@ impl super::Signature for Ed25519Signature { impl super::PrivateKey for ed25519_zebra::SigningKey {} impl super::PublicKey for ed25519_zebra::VerificationKey { fn get_encoded_public_key(&self) -> String { - multibase::encode(multibase::Base::Base58Btc, get_prefixed_public_key(&self)) + multibase::encode(multibase::Base::Base58Btc, get_prefixed_public_key(self)) } } @@ -195,7 +195,7 @@ impl Ed25519KeyPair { } pub fn generate_mnemonic(language: MnemonicLanguage) -> Mnemonic { - let mnemonic = bip39::Mnemonic::new(bip39::MnemonicType::Words24, language.clone().into()); + let mnemonic = bip39::Mnemonic::new(bip39::MnemonicType::Words24, language.into()); return Mnemonic { language,