Skip to content

Commit

Permalink
refactor: only issuer id for legacy->w3c
Browse files Browse the repository at this point in the history
Signed-off-by: Timo Glastra <[email protected]>
  • Loading branch information
TimoGlastra committed Feb 5, 2024
1 parent 3c027a9 commit 8eae789
Show file tree
Hide file tree
Showing 15 changed files with 94 additions and 137 deletions.
73 changes: 37 additions & 36 deletions docs/design/w3c/w3c-representation.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
## Design for W3C representation of AnonCreds credentials and presentation

This design document describes how W3C formatted Verifiable Credentials and Presentations are supported in `anoncreds-rs` library.
This design document describes how W3C formatted Verifiable Credentials and Presentations are supported in `anoncreds-rs` library.

### Goals and ideas

* Use legacy styled credentials to generate W3C AnonCreds credentials and presentations
* Credentials conversion:
* Convert legacy styled AnonCreds credentials into W3C form
* Convert W3C styled AnonCreds credentials into legacy form
* Presentation conversion (Optional):
* Convert legacy styled AnonCreds presentation into W3C form
* Convert W3C styled AnonCreds presentation into legacy form
* Issue AnonCreds credentials in W3C form
* Create W3C presentations using W3C AnonCreds credentials
* Verify W3C presentations containing AnonCreds proof
* Extend W3C credentials:
* Ability to set Data Integrity proof signatures for generated W3C credential objects:
* W3C credentials may contain multiple signatures
* AnonCreds-Rs only generates/handle AnonCreds signatures
* Ability to add additional credential metadata
- Use legacy styled credentials to generate W3C AnonCreds credentials and presentations
- Credentials conversion:
- Convert legacy styled AnonCreds credentials into W3C form
- Convert W3C styled AnonCreds credentials into legacy form
- Presentation conversion (Optional):
- Convert legacy styled AnonCreds presentation into W3C form
- Convert W3C styled AnonCreds presentation into legacy form
- Issue AnonCreds credentials in W3C form
- Create W3C presentations using W3C AnonCreds credentials
- Verify W3C presentations containing AnonCreds proof
- Extend W3C credentials:
- Ability to set Data Integrity proof signatures for generated W3C credential objects:
- W3C credentials may contain multiple signatures
- AnonCreds-Rs only generates/handle AnonCreds signatures
- Ability to add additional credential metadata

#### Out of scope

* Credentials: Verify validity of non-AnonCreds Data Integrity proof signatures
* Presentations: Create presentations using non-AnonCreds Data Integrity proof signature
* Presentations: Verify validity of presentations including non-AnonCreds Data Integrity proof signatures
* Presentations: Support different formats (for example DIF) of Presentation Request
- Credentials: Verify validity of non-AnonCreds Data Integrity proof signatures
- Presentations: Create presentations using non-AnonCreds Data Integrity proof signature
- Presentations: Verify validity of presentations including non-AnonCreds Data Integrity proof signatures
- Presentations: Support different formats (for example DIF) of Presentation Request

### Public API

Expand All @@ -40,15 +40,16 @@ is require application uses conversion methods to get required format.
These methods allow to solve both cases:

Methods purpose - have to forms of credentials (probably even duplicate in wallet) to cover both cases: legacy and W3C
* `anoncreds_credential_to_w3c` - create W3C Presentation using a credential previously issued in legacy form
* `anoncreds_credential_from_w3c` - create a legacy styled presentation (for legacy Verifier) using a credential issued in W3C form

- `anoncreds_credential_to_w3c` - create W3C Presentation using a credential previously issued in legacy form
- `anoncreds_credential_from_w3c` - create a legacy styled presentation (for legacy Verifier) using a credential issued in W3C form

```rust
/// Convert credential in legacy form into W3C AnonCreds credential form
///
/// # Params
/// cred: object handle pointing to credential in legacy form to convert
/// cred_def: object handle pointing to the credential definition
/// issuer_id: issuer_id of the credential. Can be extracted from the cred_def and will be used as the `issuer` field in the w3c credential
/// w3c_version: version of w3c verifiable credential specification (1.1 or 2.0) to use
/// cred_p: reference that will contain converted credential (in W3C form) instance pointer
///
Expand All @@ -57,7 +58,7 @@ Methods purpose - have to forms of credentials (probably even duplicate in walle
#[no_mangle]
pub extern "C" fn anoncreds_credential_to_w3c(
cred: ObjectHandle,
cred_def: ObjectHandle,
issuer_id: FfiStr,
w3c_version: FfiStr,
cred_p: *mut ObjectHandle,
) -> ErrorCode {}
Expand Down Expand Up @@ -90,18 +91,18 @@ So the credentials and presentations themselves are generated using new flow met
The reasons for adding duplication methods:

- avoid breaking changes in the existing API
- for example if we want Credential Offer pointing to the form of a credential to be issued
- for example if we want Credential Offer pointing to the form of a credential to be issued
- clear separation between flows
- if a flow targeting issuing of W3C Credential the specific set of function to be used
- if a flow targeting issuing of W3C Credential the specific set of function to be used
- avoid the situation when function result value may be in different forms
- example:
- issuer creates offer in legacy form but with resulting credential format indication (legacy or w3c )
- as the flow execution result, create credential function returns credential either in w3c or legacy form
depending on offer
- if application analyze credential somehow it cause difficulties
- example:
- issuer creates offer in legacy form but with resulting credential format indication (legacy or w3c )
- as the flow execution result, create credential function returns credential either in w3c or legacy form
depending on offer
- if application analyze credential somehow it cause difficulties
- easier deprecation of legacy styled credentials and APIs
- presentation conversion methods are not needed anymore in this case
- only credential conversion method to do migration for previously issued credentials
- only credential conversion method to do migration for previously issued credentials

```rust
/// Create Credential in W3C form according to the specification.
Expand Down Expand Up @@ -172,7 +173,7 @@ pub extern "C" fn anoncreds_w3c_credential_get_integrity_proof_details(
) -> ErrorCode {}

/// Create W3C Presentation according to the specification.
///
///
/// # Params
/// pres_req: object handle pointing to presentation request
/// credentials: credentials (in W3C form) to use for presentation preparation
Expand Down Expand Up @@ -248,7 +249,7 @@ legacy_credential = Holder.anoncreds_process_credential(legacy_credential,...)
/// Convert legacy styled credential to W3C credential form
w3c_credential = Holder.anoncreds_credential_to_w3c(legacy_credential)
/// Do wallets need to store both credential forms to handle legacy and DIF presentations requests?
/// Do wallets need to store both credential forms to handle legacy and DIF presentations requests?
Wallet.store_legacy_credential(legacy_credential)
Wallet.store_w3c_credential(w3c_credential)
Expand All @@ -270,7 +271,7 @@ w3c_credential = Holder.anoncreds_w3c_process_credential(w3c_credential,...)
/// Convert W3C credential to legacy form
legacy_credential = Holder.anoncreds_credential_from_w3c(w3c_credential)
/// Do wallets need to store both credential forms to handle legacy and DIF presentations requests?
/// Do wallets need to store both credential forms to handle legacy and DIF presentations requests?
Wallet.store_legacy_credential(legacy_credential)
Wallet.store_w3c_credential(w3c_credential)
Expand All @@ -289,7 +290,7 @@ w3c_credential_request = Holder.anoncreds_w3c_create_credential_request(w3c_cred
w3c_credential = Issuer.anoncreds_w3c_create_credential(w3c_credential_request,...)
w3c_credential = Holder.anoncreds_w3c_process_credential(w3c_credential,...)
/// Do wallets need to store both credential forms to handle legacy and DIF presentations requests?
/// Do wallets need to store both credential forms to handle legacy and DIF presentations requests?
Wallet.store_w3c_credential(w3c_credential)
/// Verifiy W3C presenttion using W3C crdential form
Expand Down
9 changes: 5 additions & 4 deletions src/ffi/w3c/credential.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::data_types::issuer_id::IssuerId;
use crate::data_types::w3c::VerifiableCredentialSpecVersion;
use ffi_support::{rust_string_to_c, FfiStr};
use std::ffi::c_char;
Expand Down Expand Up @@ -125,7 +126,7 @@ pub extern "C" fn anoncreds_process_w3c_credential(
///
/// # Params
/// cred: object handle pointing to credential in legacy form to convert
/// cred_def: object handle pointing to the credential definition
/// issuer_id: issuer_id of the credential. Can be extracted from the cred_def and will be used as the `issuer` field in the w3c credential
/// w3c_version: version of w3c verifiable credential specification (1.1 or 2.0) to use
/// cred_p: reference that will contain converted credential (in W3C form) instance pointer
///
Expand All @@ -134,7 +135,7 @@ pub extern "C" fn anoncreds_process_w3c_credential(
#[no_mangle]
pub extern "C" fn anoncreds_credential_to_w3c(
cred: ObjectHandle,
cred_def: ObjectHandle,
issuer_id: FfiStr,
w3c_version: FfiStr,
cred_p: *mut ObjectHandle,
) -> ErrorCode {
Expand All @@ -148,8 +149,8 @@ pub extern "C" fn anoncreds_credential_to_w3c(
None => None,
};

let w3c_credential =
credential_to_w3c(credential, cred_def.load()?.cast_ref()?, w3c_version)?;
let issuer_id = IssuerId::new(issuer_id).expect("Invalid issuer ID");
let w3c_credential = credential_to_w3c(credential, issuer_id, w3c_version)?;
let w3c_cred = ObjectHandle::create(w3c_credential)?;

unsafe { *cred_p = w3c_cred };
Expand Down
28 changes: 17 additions & 11 deletions src/services/w3c/credential_conversion.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::data_types::cred_def::CredentialDefinition;
use crate::data_types::issuer_id::IssuerId;
use crate::data_types::w3c::credential::W3CCredential;
use crate::data_types::w3c::credential_attributes::CredentialSubject;
use crate::data_types::w3c::proof::{CredentialSignatureProofValue, DataIntegrityProof};
Expand Down Expand Up @@ -87,19 +87,19 @@ use crate::Error;
/// ```
pub fn credential_to_w3c(
credential: &Credential,
cred_def: &CredentialDefinition,
issuer_id: IssuerId,
version: Option<VerifiableCredentialSpecVersion>,
) -> Result<W3CCredential, Error> {
trace!(
"credential_to_w3c >>> credential: {:?}, cred_def: {:?}",
"credential_to_w3c >>> credential: {:?}, issuer_id: {:?}",
credential,
cred_def
issuer_id
);

credential.validate()?;

let credential = credential.try_clone()?;
let issuer = cred_def.issuer_id.clone();
let issuer = issuer_id.clone();
let attributes = CredentialSubject::from(&credential.values);
let signature = CredentialSignatureProofValue {
schema_id: credential.schema_id,
Expand Down Expand Up @@ -323,9 +323,12 @@ pub(crate) mod tests {
#[test]
fn test_convert_credential_to_and_from_w3c() {
let original_legacy_credential = legacy_credential();
let w3c_credential =
credential_to_w3c(&original_legacy_credential, &credential_definition(), None)
.expect("unable to convert credential to w3c form");
let w3c_credential = credential_to_w3c(
&original_legacy_credential,
credential_definition().issuer_id,
None,
)
.expect("unable to convert credential to w3c form");
let legacy_credential = credential_from_w3c(&w3c_credential)
.expect("unable to convert credential to legacy form");
assert_eq!(json!(original_legacy_credential), json!(legacy_credential),)
Expand All @@ -339,9 +342,12 @@ pub(crate) mod tests {
#[case] expected_context: Contexts,
) {
let legacy_credential = legacy_credential();
let w3c_credential =
credential_to_w3c(&legacy_credential, &credential_definition(), Some(version))
.expect("unable to convert credential to w3c form");
let w3c_credential = credential_to_w3c(
&legacy_credential,
credential_definition().issuer_id,
Some(version),
)
.expect("unable to convert credential to w3c form");

assert_eq!(w3c_credential.context, expected_context.clone());
assert_eq!(w3c_credential.type_, ANONCREDS_CREDENTIAL_TYPES.clone());
Expand Down
2 changes: 1 addition & 1 deletion tests/utils/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -964,7 +964,7 @@ impl<'a> ProverWallet<'a> {
match credential {
Credentials::Legacy(legacy_cred) => {
// Convert legacy credential into W3C form
let w3c_cred = credential_to_w3c(&legacy_cred, cred_def, None)
let w3c_cred = credential_to_w3c(&legacy_cred, cred_def.issuer_id, None)
.expect("Error converting legacy credential into W3C form");

// Store w3c credential in wallet
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -656,16 +656,12 @@ export class NodeJSAnoncreds implements Anoncreds {
return Boolean(handleReturnPointer<number>(ret))
}

public credentialToW3c(options: {
objectHandle: ObjectHandle
credentialDefinition: ObjectHandle
w3cVersion?: string
}): ObjectHandle {
const { objectHandle, credentialDefinition, w3cVersion } = serializeArguments(options)
public credentialToW3c(options: { objectHandle: ObjectHandle; issuerId: string; w3cVersion?: string }): ObjectHandle {
const { objectHandle, issuerId, w3cVersion } = serializeArguments(options)

const ret = allocatePointer()

this.nativeAnoncreds.anoncreds_credential_to_w3c(objectHandle, credentialDefinition, w3cVersion, ret)
this.nativeAnoncreds.anoncreds_credential_to_w3c(objectHandle, issuerId, w3cVersion, ret)
this.handleError()

return new ObjectHandle(handleReturnPointer<number>(ret))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,10 +241,7 @@ export const nativeBindings = {
FFI_INT8_PTR
]
],
anoncreds_credential_to_w3c: [
FFI_ERRORCODE,
[FFI_OBJECT_HANDLE, FFI_OBJECT_HANDLE, FFI_STRING, FFI_OBJECT_HANDLE_PTR]
],
anoncreds_credential_to_w3c: [FFI_ERRORCODE, [FFI_OBJECT_HANDLE, FFI_STRING, FFI_STRING, FFI_OBJECT_HANDLE_PTR]],
anoncreds_credential_from_w3c: [FFI_ERRORCODE, [FFI_OBJECT_HANDLE, FFI_OBJECT_HANDLE_PTR]],
anoncreds_w3c_credential_get_integrity_proof_details: [FFI_ERRORCODE, [FFI_OBJECT_HANDLE, FFI_OBJECT_HANDLE_PTR]],
anoncreds_w3c_credential_proof_get_attribute: [FFI_ERRORCODE, [FFI_OBJECT_HANDLE, FFI_STRING, FFI_STRING_PTR]],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -870,15 +870,15 @@ jsi::Value processW3cCredential(jsi::Runtime &rt, jsi::Object options) {

jsi::Value credentialToW3c(jsi::Runtime &rt, jsi::Object options) {
auto credential = jsiToValue<ObjectHandle>(rt, options, "objectHandle");
auto credentialDefinition =
jsiToValue<ObjectHandle>(rt, options, "credentialDefinition");
auto issuerId =
jsiToValue<std::string>(rt, options, "issuerId");
auto w3cVersion =
jsiToValue<std::string>(rt, options, "w3cVersion", true);

ObjectHandle out;

ErrorCode code = anoncreds_credential_to_w3c(
credential, credentialDefinition,
credential, issuerId.c_str(),
w3cVersion.length() ? w3cVersion.c_str() : nullptr, &out);

return createReturnValue(rt, code, &out);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,11 +214,7 @@ export type NativeBindings = {

w3cCredentialProofGetAttribute(options: { objectHandle: number; name: string }): ReturnObject<string>

credentialToW3c(options: {
objectHandle: number
credentialDefinition: number
w3cVersion?: string
}): ReturnObject<Handle>
credentialToW3c(options: { objectHandle: number; issuerId: string; w3cVersion?: string }): ReturnObject<Handle>

credentialFromW3c(options: { objectHandle: number }): ReturnObject<Handle>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -507,11 +507,7 @@ export class ReactNativeAnoncreds implements Anoncreds {
return new ObjectHandle(handle)
}

public credentialToW3c(options: {
objectHandle: ObjectHandle
credentialDefinition: ObjectHandle
w3cVersion?: string
}): ObjectHandle {
public credentialToW3c(options: { objectHandle: ObjectHandle; issuerId: string; w3cVersion?: string }): ObjectHandle {
const handle = this.handleError(this.anoncreds.credentialToW3c(serializeArguments(options)))
return new ObjectHandle(handle)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,11 +250,7 @@ export type Anoncreds = {

w3cCredentialFromJson(options: { json: string }): ObjectHandle

credentialToW3c(options: {
objectHandle: ObjectHandle
credentialDefinition: ObjectHandle
w3cVersion?: string
}): ObjectHandle
credentialToW3c(options: { objectHandle: ObjectHandle; issuerId: string; w3cVersion?: string }): ObjectHandle

credentialFromW3c(options: { objectHandle: ObjectHandle }): ObjectHandle

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export type ProcessCredentialOptions = {
}

export type CredentialToW3cOptions = {
credentialDefinition: CredentialDefinition | JsonObject
issuerId: string
w3cVersion?: string
}

Expand Down Expand Up @@ -151,28 +151,13 @@ export class Credential extends AnoncredsObject {
}

public toW3c(options: CredentialToW3cOptions): W3cCredential {
let credential
// Objects created within this method must be freed up
const objectHandles: ObjectHandle[] = []
try {
const credentialDefinition =
options.credentialDefinition instanceof CredentialDefinition
? options.credentialDefinition.handle
: pushToArray(CredentialDefinition.fromJson(options.credentialDefinition).handle, objectHandles)

credential = new W3cCredential(
anoncreds.credentialToW3c({
objectHandle: this.handle,
credentialDefinition,
w3cVersion: options.w3cVersion
}).handle
)
} finally {
objectHandles.forEach((handle) => {
handle.clear()
})
}
return credential
return new W3cCredential(
anoncreds.credentialToW3c({
objectHandle: this.handle,
issuerId: options.issuerId,
w3cVersion: options.w3cVersion
}).handle
)
}

public static fromW3c(options: CredentialFromW3cOptions) {
Expand Down
Loading

0 comments on commit 8eae789

Please sign in to comment.