Skip to content

Commit

Permalink
Merge branch 'main' into test-of-test-of-test
Browse files Browse the repository at this point in the history
* main:
  Add secp256k1 signer & verifier, fix serde deserialize optional timestamp bug, add vc verify test vector (#350)
  implementation of create_presentation_from_credentials (#347)
  • Loading branch information
diehuxx committed Sep 10, 2024
2 parents 1eab034 + bb75678 commit 7fc0252
Show file tree
Hide file tree
Showing 32 changed files with 2,606 additions and 200 deletions.
9 changes: 6 additions & 3 deletions bindings/web5_uniffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@ use web5_uniffi_wrapper::{
VerifiableCredentialCreateOptions as VerifiableCredentialCreateOptionsData,
VerifiableCredentialData,
},
verifiable_presentation_1_1::VerifiablePresentation,
verifiable_presentation_1_1::{
VerifiablePresentation,
VerifiablePresentationCreateOptions as VerifiablePresentationCreateOptionsData,
VerifiablePresentationData,
},
},
crypto::{
dsa::{
ed25519::{ed25519_generator_generate, Ed25519Signer, Ed25519Verifier},
secp256k1::{secp256k1_generator_generate, Secp256k1Signer, Secp256k1Verifier},
Signer, Verifier,
},
in_memory_key_manager::InMemoryKeyManager,
Expand All @@ -37,8 +42,6 @@ use web5_uniffi_wrapper::{
use web5::{
credentials::{
CredentialSchema as CredentialSchemaData, CredentialStatus as CredentialStatusData,
VerifiablePresentation as VerifiablePresentationData,
VerifiablePresentationCreateOptions as VerifiablePresentationCreateOptionsData,
},
crypto::{dsa::Dsa, jwk::Jwk as JwkData},
dids::{
Expand Down
21 changes: 17 additions & 4 deletions bindings/web5_uniffi/src/web5.udl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace web5 {
JwkData ed25519_generator_generate();
JwkData secp256k1_generator_generate();

[Throws=Web5Error]
BearerDid did_jwk_create(DidJwkCreateOptions? options);
Expand Down Expand Up @@ -91,6 +92,18 @@ interface Ed25519Verifier {
void verify(bytes message, bytes signature);
};

interface Secp256k1Signer {
constructor(JwkData private_key);
[Throws=Web5Error]
bytes sign(bytes payload);
};

interface Secp256k1Verifier {
constructor(JwkData public_jwk);
[Throws=Web5Error]
void verify(bytes message, bytes signature);
};

dictionary DidData {
string uri;
string url;
Expand Down Expand Up @@ -245,12 +258,10 @@ interface PresentationDefinition {
string get_json_serialized_presentation_definition();
[Throws=Web5Error]
sequence<string> select_credentials([ByRef] sequence<string> vc_jwts);
[Throws=Web5Error]
string create_presentation_from_credentials([ByRef] sequence<string> vc_jwts);
};





dictionary VerifiableCredentialCreateOptionsData {
string? id;
sequence<string>? context;
Expand Down Expand Up @@ -323,6 +334,7 @@ dictionary VerifiablePresentationCreateOptionsData {
sequence<string>? type;
timestamp? issuance_date;
timestamp? expiration_date;
string? json_serialized_additional_data;
};

interface VerifiablePresentation {
Expand Down Expand Up @@ -351,4 +363,5 @@ dictionary VerifiablePresentationData {
timestamp issuance_date;
timestamp? expiration_date;
sequence<string> verifiable_credential;
string? json_serialized_additional_data;
};
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ impl PresentationDefinition {
Ok(self.0.select_credentials(vc_jwts)?)
}

pub fn create_presentation_from_credentials(&self, vc_jwts: &Vec<String>) -> Result<String> {
let presentation_result = self.0.create_presentation_from_credentials(vc_jwts)?;
let json_serialized_presentation_result = serde_json::to_string(&presentation_result)?;

Ok(json_serialized_presentation_result)
}

pub fn get_json_serialized_presentation_definition(&self) -> Result<String> {
let json_serialized_presentation_definition = serde_json::to_string(&self.0)?;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
use crate::{dids::bearer_did::BearerDid, errors::Result};
use serde_json::Value;
use std::collections::HashMap;
use std::sync::Arc;
use std::time::SystemTime;
use web5::credentials::VerifiablePresentation as InnerVerifiablePresentation;
use web5::credentials::VerifiablePresentationCreateOptions;
use web5::credentials::VerifiablePresentationCreateOptions as InnerVerifiablePresentationCreateOptions;

#[derive(Default)]
pub struct VerifiablePresentationCreateOptions {
pub id: Option<String>,
pub context: Option<Vec<String>>,
pub r#type: Option<Vec<String>>,
pub issuance_date: Option<SystemTime>,
pub expiration_date: Option<SystemTime>,
pub json_serialized_additional_data: Option<String>,
}

pub struct VerifiablePresentation {
pub inner_vp: InnerVerifiablePresentation,
Expand All @@ -13,20 +26,44 @@ impl VerifiablePresentation {
vc_jwts: Vec<String>,
options: Option<VerifiablePresentationCreateOptions>,
) -> Result<Self> {
let inner_vp = InnerVerifiablePresentation::create(holder, vc_jwts, options)?;
let options = options.unwrap_or_default();

let additional_data = match options.json_serialized_additional_data {
Some(additional_data) => Some(serde_json::from_str::<HashMap<String, Value>>(
&additional_data,
)?),
None => None,
};

let inner_options = InnerVerifiablePresentationCreateOptions {
id: options.id,
context: options.context,
r#type: options.r#type,
issuance_date: options.issuance_date,
expiration_date: options.expiration_date,
additional_data,
};

let inner_vp = InnerVerifiablePresentation::create(holder, vc_jwts, Some(inner_options))?;

Ok(Self { inner_vp })
}

pub fn get_data(&self) -> Result<InnerVerifiablePresentation> {
Ok(InnerVerifiablePresentation {
pub fn get_data(&self) -> Result<VerifiablePresentationData> {
let json_serialized_additional_data = match &self.inner_vp.additional_data {
Some(e) => Some(serde_json::to_string(e)?),
None => None,
};

Ok(VerifiablePresentationData {
context: self.inner_vp.context.clone(),
id: self.inner_vp.id.clone(),
r#type: self.inner_vp.r#type.clone(),
holder: self.inner_vp.holder.clone(),
verifiable_credential: self.inner_vp.verifiable_credential.clone(),
issuance_date: self.inner_vp.issuance_date,
expiration_date: self.inner_vp.expiration_date,
json_serialized_additional_data,
})
}

Expand All @@ -45,3 +82,15 @@ impl VerifiablePresentation {
Ok(vp_jwt)
}
}

#[derive(Clone)]
pub struct VerifiablePresentationData {
pub context: Vec<String>,
pub id: String,
pub r#type: Vec<String>,
pub holder: String,
pub issuance_date: SystemTime,
pub expiration_date: Option<SystemTime>,
pub verifiable_credential: Vec<String>,
pub json_serialized_additional_data: Option<String>,
}
1 change: 1 addition & 0 deletions bindings/web5_uniffi_wrapper/src/crypto/dsa/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod ed25519;
pub mod secp256k1;

use crate::errors::Result;
use std::sync::Arc;
Expand Down
44 changes: 44 additions & 0 deletions bindings/web5_uniffi_wrapper/src/crypto/dsa/secp256k1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use super::{Signer, Verifier};
use crate::errors::Result;
use web5::crypto::{
dsa::{
secp256k1::{
Secp256k1Generator as InnerSecp256k1Generator, Secp256k1Signer as InnerSecp256k1Signer,
Secp256k1Verifier as InnerSecp256k1Verifier,
},
Signer as InnerSigner, Verifier as InnerVerifier,
},
jwk::Jwk,
};

pub fn secp256k1_generator_generate() -> Jwk {
InnerSecp256k1Generator::generate()
}

pub struct Secp256k1Signer(pub InnerSecp256k1Signer);

impl Secp256k1Signer {
pub fn new(private_jwk: Jwk) -> Self {
Self(InnerSecp256k1Signer::new(private_jwk))
}
}

impl Signer for Secp256k1Signer {
fn sign(&self, payload: Vec<u8>) -> Result<Vec<u8>> {
Ok(self.0.sign(&payload)?)
}
}

pub struct Secp256k1Verifier(pub InnerSecp256k1Verifier);

impl Secp256k1Verifier {
pub fn new(public_jwk: Jwk) -> Self {
Self(InnerSecp256k1Verifier::new(public_jwk))
}
}

impl Verifier for Secp256k1Verifier {
fn verify(&self, payload: Vec<u8>, signature: Vec<u8>) -> Result<()> {
Ok(self.0.verify(&payload, &signature)?)
}
}
27 changes: 27 additions & 0 deletions bound/kt/src/main/kotlin/web5/sdk/crypto/Secp256k1Generator.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package web5.sdk.crypto

import web5.sdk.Web5Exception
import web5.sdk.crypto.keys.Jwk
import web5.sdk.rust.secp256k1GeneratorGenerate
import web5.sdk.rust.Web5Exception.Exception as RustCoreException

/**
* Generates private key material for secp256k1.
*/
class Secp256k1Generator {
companion object {
/**
* Generate the private key material; return Jwk includes private key material.
*
* @return Jwk the JWK with private key material included.
*/
fun generate(): Jwk {
try {
val rustCoreJwkData = secp256k1GeneratorGenerate()
return Jwk.fromRustCoreJwkData(rustCoreJwkData)
} catch (e: RustCoreException) {
throw Web5Exception.fromRustCore(e)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package web5.sdk.crypto.signers

import web5.sdk.Web5Exception
import web5.sdk.crypto.keys.Jwk
import web5.sdk.rust.Secp256k1Signer as RustCoreSecp256k1Signer
import web5.sdk.rust.Web5Exception.Exception as RustCoreException

/**
* Implementation of Signer for secp256k1.
*/
class Secp256k1Signer(privateJwk: Jwk) : Signer {
private val rustCoreSigner = RustCoreSecp256k1Signer(privateJwk.rustCoreJwkData)

/**
* Implementation of Signer's sign instance method for secp256k1.
*
* @param payload the data to be signed.
* @return ByteArray the signature.
*/
override fun sign(payload: ByteArray): ByteArray {
try {
return rustCoreSigner.sign(payload)
} catch (e: RustCoreException) {
throw Web5Exception.fromRustCore(e)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package web5.sdk.crypto.verifiers

import web5.sdk.Web5Exception
import web5.sdk.crypto.keys.Jwk
import web5.sdk.rust.Secp256k1Verifier as RustCoreSecp256k1Verifier
import web5.sdk.rust.Web5Exception.Exception as RustCoreException

/**
* Implementation of Verifier for secp256k1.
*/
class Secp256k1Verifier(publicJwk: Jwk) : Verifier {
private val rustCoreVerifier = RustCoreSecp256k1Verifier(publicJwk.rustCoreJwkData)

/**
* Implementation of Signer's verify instance method for secp256k1.
*
* @param message the data to be verified.
* @param signature the signature to be verified.
* @throws Web5Exception in the case of a failed verification
*/
override fun verify(message: ByteArray, signature: ByteArray) {
try {
rustCoreVerifier.verify(message, signature)
} catch (e: RustCoreException) {
throw Web5Exception.fromRustCore(e)
}
}
}
Loading

0 comments on commit 7fc0252

Please sign in to comment.