Skip to content

Commit

Permalink
Merge pull request #271 from DSRCorporation/anoncreds-wc3
Browse files Browse the repository at this point in the history
AnonCreds Credentials using the W3C Standard - implementation
  • Loading branch information
swcurran authored Dec 7, 2023
2 parents c6ea2fd + 59a8a8c commit fd44f1b
Show file tree
Hide file tree
Showing 41 changed files with 6,224 additions and 1,773 deletions.
8 changes: 7 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ path = "src/lib.rs"
crate-type = ["staticlib", "rlib", "cdylib"]

[features]
default = ["ffi", "logger", "zeroize"]
default = ["ffi", "logger", "zeroize", "w3c"]
ffi = ["dep:ffi-support"]
zeroize = ["dep:zeroize"]
logger = ["dep:env_logger"]
vendored = ["anoncreds-clsignatures/openssl_vendored"]
w3c = ["base64", "chrono"]

[dependencies]
anoncreds-clsignatures = "0.2.4"
Expand All @@ -40,6 +41,11 @@ serde_json = { version = "1.0.94", features = ["raw_value"] }
sha2 = "0.10.6"
thiserror = "1.0.39"
zeroize = { version = "1.5.7", optional = true, features = ["zeroize_derive"] }
base64 = { version = "0.21.5", optional = true }
chrono = { version = "0.4.31", optional = true, features = ["serde"] }

[dev-dependencies]
rstest = "0.18.2"

[profile.release]
lto = true
Expand Down
117 changes: 115 additions & 2 deletions src/data_types/credential.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use serde_json::Value;
use std::collections::HashMap;

#[cfg(feature = "zeroize")]
use zeroize::Zeroize;

use crate::cl::{CredentialSignature, RevocationRegistry, SignatureCorrectnessProof, Witness};
use crate::error::{ConversionError, ValidationError};
use crate::types::MakeCredentialValues;
use crate::utils::validation::Validatable;
use crate::Error;

use super::rev_reg_def::RevocationRegistryDefinitionId;
use super::{cred_def::CredentialDefinitionId, schema::SchemaId};
Expand Down Expand Up @@ -73,14 +77,71 @@ impl Validatable for Credential {
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct CredentialInfo {
pub referent: String,
pub attrs: ShortCredentialValues,
pub attrs: RawCredentialValues,
pub schema_id: SchemaId,
pub cred_def_id: CredentialDefinitionId,
pub rev_reg_id: Option<RevocationRegistryDefinitionId>,
pub cred_rev_id: Option<String>,
}

pub type ShortCredentialValues = HashMap<String, String>;
#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
pub struct RawCredentialValues(pub HashMap<String, String>);

#[cfg(feature = "zeroize")]
impl Drop for RawCredentialValues {
fn drop(&mut self) {
self.zeroize();
}
}

#[cfg(feature = "zeroize")]
impl Zeroize for RawCredentialValues {
fn zeroize(&mut self) {
for attr in self.0.values_mut() {
attr.zeroize();
}
}
}

impl Validatable for RawCredentialValues {
fn validate(&self) -> Result<(), ValidationError> {
if self.0.is_empty() {
return Err("RawCredentialValues validation failed: empty list has been passed".into());
}

Ok(())
}
}

impl From<&CredentialValues> for RawCredentialValues {
fn from(values: &CredentialValues) -> Self {
RawCredentialValues(
values
.0
.iter()
.map(|(attribute, values)| (attribute.to_owned(), values.raw.to_owned()))
.collect(),
)
}
}

impl RawCredentialValues {
pub fn encode(&self, encoding: &CredentialValuesEncoding) -> Result<CredentialValues, Error> {
match encoding {
CredentialValuesEncoding::Auto => {
let mut cred_values = MakeCredentialValues::default();
for (attribute, raw_value) in self.0.iter() {
cred_values.add_raw(attribute, raw_value)?;
}
Ok(cred_values.into())
}
encoding => Err(err_msg!(
"Credential values encoding {:?} is not supported",
encoding
)),
}
}
}

#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
pub struct CredentialValues(pub HashMap<String, AttributeValues>);
Expand Down Expand Up @@ -117,3 +178,55 @@ pub struct AttributeValues {
pub raw: String,
pub encoded: String,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CredentialValuesEncoding {
Auto,
Other(String),
}

impl ToString for CredentialValuesEncoding {
fn to_string(&self) -> String {
match self {
CredentialValuesEncoding::Auto => "auto".to_string(),
CredentialValuesEncoding::Other(other) => other.to_string(),
}
}
}

impl From<&str> for CredentialValuesEncoding {
fn from(value: &str) -> Self {
match value {
"auto" => CredentialValuesEncoding::Auto,
other => CredentialValuesEncoding::Other(other.to_string()),
}
}
}

impl Serialize for CredentialValuesEncoding {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
Value::String(self.to_string()).serialize(serializer)
}
}

impl<'de> Deserialize<'de> for CredentialValuesEncoding {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Value::deserialize(deserializer)
.map_err(de::Error::custom)?
.as_str()
.map(CredentialValuesEncoding::from)
.ok_or_else(|| de::Error::custom("Cannot parse credential value encoding"))
}
}

impl Default for CredentialValuesEncoding {
fn default() -> Self {
CredentialValuesEncoding::Auto
}
}
4 changes: 4 additions & 0 deletions src/data_types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,7 @@ pub mod macros;

/// Identifier wrapper for the issuer
pub mod issuer_id;

#[cfg(feature = "w3c")]
/// W3C Credential standard definitions
pub mod w3c;
36 changes: 36 additions & 0 deletions src/data_types/w3c/constants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use once_cell::sync::Lazy;
use std::collections::HashSet;

use crate::data_types::w3c::credential::{Contexts, Types};
use crate::data_types::w3c::uri::URI;

// Contexts
pub const W3C_CONTEXT: &str = "https://www.w3.org/2018/credentials/v1";
pub const W3C_ANONCREDS_CONTEXT: &str = "https://raw.githubusercontent.com/hyperledger/anoncreds-spec/main/data/anoncreds-w3c-context.json";

// Types
pub const W3C_CREDENTIAL_TYPE: &str = "VerifiableCredential";
pub const W3C_PRESENTATION_TYPE: &str = "VerifiablePresentation";
pub const W3C_ANONCREDS_CREDENTIAL_TYPE: &str = "AnonCredsCredential";
pub const W3C_ANONCREDS_PRESENTATION_TYPE: &str = "AnonCredsPresentation";

pub(crate) static ANONCREDS_CONTEXTS: Lazy<Contexts> = Lazy::new(|| {
Contexts(HashSet::from([
URI::from(W3C_CONTEXT),
URI::from(W3C_ANONCREDS_CONTEXT),
]))
});

pub(crate) static ANONCREDS_CREDENTIAL_TYPES: Lazy<Types> = Lazy::new(|| {
Types(HashSet::from([
String::from(W3C_CREDENTIAL_TYPE),
String::from(W3C_ANONCREDS_CREDENTIAL_TYPE),
]))
});

pub(crate) static ANONCREDS_PRESENTATION_TYPES: Lazy<Types> = Lazy::new(|| {
Types(HashSet::from([
String::from(W3C_PRESENTATION_TYPE),
String::from(W3C_ANONCREDS_PRESENTATION_TYPE),
]))
});
Loading

0 comments on commit fd44f1b

Please sign in to comment.