Skip to content

Commit

Permalink
Merge branch 'main' into msrv-1.70.0
Browse files Browse the repository at this point in the history
* main:
  Use error for Verifier::verify(), Add ed25519 unit tests, Add Web5Error::Crypto (#300)
  Test Secp256k1Generator (#302)
  Generate X25519 keys (#301)
  Support X25519 in did:dht verification method (#299)
  add sign and verify test vectors (#292)
  Add feature complete Jwk (#294)
  • Loading branch information
Diane Huxley committed Aug 21, 2024
2 parents 22fd4a1 + 3c73267 commit a6aef12
Show file tree
Hide file tree
Showing 62 changed files with 2,341 additions and 416 deletions.
1 change: 1 addition & 0 deletions bindings/web5_uniffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use web5_uniffi_wrapper::{
Signer, Verifier,
},
in_memory_key_manager::InMemoryKeyManager,
jwk::Jwk,
key_manager::KeyManager,
},
dids::{
Expand Down
17 changes: 12 additions & 5 deletions bindings/web5_uniffi/src/web5.udl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ dictionary JwkData {
string? y;
};

interface Jwk {
constructor(JwkData data);
JwkData get_data();
[Throws=Web5Error]
string compute_thumbprint();
};

[Trait, WithForeign]
interface KeyManager {
[Throws=Web5Error]
Expand Down Expand Up @@ -50,7 +57,7 @@ interface Signer {
[Trait, WithForeign]
interface Verifier {
[Throws=Web5Error]
boolean verify(bytes message, bytes signature);
void verify(bytes message, bytes signature);
};

interface Ed25519Signer {
Expand All @@ -62,7 +69,7 @@ interface Ed25519Signer {
interface Ed25519Verifier {
constructor(JwkData public_jwk);
[Throws=Web5Error]
boolean verify(bytes message, bytes signature);
void verify(bytes message, bytes signature);
};

dictionary DidData {
Expand Down Expand Up @@ -112,8 +119,6 @@ dictionary ServiceData {
interface Document {
constructor(DocumentData data);
DocumentData get_data();
[Throws=Web5Error]
JwkData find_public_key_jwk(string key_id);
};

enum ResolutionMetadataError {
Expand Down Expand Up @@ -203,9 +208,11 @@ dictionary PortableDidData {
};

interface PortableDid {
[Throws=Web5Error]
[Name=from_json_string, Throws=Web5Error]
constructor([ByRef] string json);
PortableDidData get_data();
[Throws=Web5Error]
string to_json_string();
};

dictionary BearerDidData {
Expand Down
2 changes: 1 addition & 1 deletion bindings/web5_uniffi_wrapper/src/crypto/dsa/ed25519.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl Ed25519Verifier {
}

impl Verifier for Ed25519Verifier {
fn verify(&self, payload: Vec<u8>, signature: Vec<u8>) -> Result<bool> {
fn verify(&self, payload: Vec<u8>, signature: Vec<u8>) -> Result<()> {
Ok(self.0.verify(&payload, &signature)?)
}
}
9 changes: 4 additions & 5 deletions bindings/web5_uniffi_wrapper/src/crypto/dsa/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,20 @@ impl Signer for ToOuterSigner {
pub struct ToInnerSigner(pub Arc<dyn Signer>);

impl InnerSigner for ToInnerSigner {
fn sign(&self, payload: &[u8]) -> web5::crypto::dsa::Result<Vec<u8>> {
fn sign(&self, payload: &[u8]) -> web5::errors::Result<Vec<u8>> {
let signature = self.0.sign(Vec::from(payload))?;
Ok(signature)
}
}

pub trait Verifier: Send + Sync {
fn verify(&self, payload: Vec<u8>, signature: Vec<u8>) -> Result<bool>;
fn verify(&self, payload: Vec<u8>, signature: Vec<u8>) -> Result<()>;
}

pub struct ToInnerVerifier(pub Arc<dyn Verifier>);

impl InnerVerifier for ToInnerVerifier {
fn verify(&self, payload: &[u8], signature: &[u8]) -> web5::crypto::dsa::Result<bool> {
let verified = self.0.verify(Vec::from(payload), Vec::from(signature))?;
Ok(verified)
fn verify(&self, payload: &[u8], signature: &[u8]) -> web5::errors::Result<()> {
Ok(self.0.verify(Vec::from(payload), Vec::from(signature))?)
}
}
19 changes: 19 additions & 0 deletions bindings/web5_uniffi_wrapper/src/crypto/jwk.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use crate::errors::Result;
use web5::crypto::jwk::Jwk as InnerJwk;

pub struct Jwk(pub InnerJwk);

impl Jwk {
pub fn new(data: InnerJwk) -> Self {
Self(data)
}

pub fn get_data(&self) -> InnerJwk {
self.0.clone()
}

pub fn compute_thumbprint(&self) -> Result<String> {
let thumbprint = self.0.compute_thumbprint()?;
Ok(thumbprint)
}
}
1 change: 1 addition & 0 deletions bindings/web5_uniffi_wrapper/src/crypto/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod dsa;

pub mod in_memory_key_manager;
pub mod jwk;
pub mod key_manager;
7 changes: 1 addition & 6 deletions bindings/web5_uniffi_wrapper/src/dids/data_model/document.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::errors::Result;
use web5::{crypto::jwk::Jwk, dids::data_model::document::Document as InnerDocument};
use web5::dids::data_model::document::Document as InnerDocument;

pub struct Document(pub InnerDocument);

Expand All @@ -11,8 +10,4 @@ impl Document {
pub fn get_data(&self) -> InnerDocument {
self.0.clone()
}

pub fn find_public_key_jwk(&self, key_id: String) -> Result<Jwk> {
Ok(self.0.find_public_key_jwk(key_id)?)
}
}
15 changes: 11 additions & 4 deletions bindings/web5_uniffi_wrapper/src/dids/portable_did.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
use web5::dids::portable_did::PortableDid as InnerPortableDid;

use crate::errors::Result;
use web5::{
dids::portable_did::PortableDid as InnerPortableDid,
json::{FromJson, ToJson},
};

pub struct PortableDid(pub InnerPortableDid);

impl PortableDid {
pub fn new(json: &str) -> Result<Self> {
let inner_portable_did = InnerPortableDid::new(json)?;
pub fn from_json_string(json: &str) -> Result<Self> {
let inner_portable_did = InnerPortableDid::from_json_string(json)?;
Ok(Self(inner_portable_did))
}

pub fn get_data(&self) -> InnerPortableDid {
self.0.clone()
}

pub fn to_json_string(&self) -> Result<String> {
let json_string = self.0.to_json_string()?;
Ok(json_string)
}
}
71 changes: 16 additions & 55 deletions bindings/web5_uniffi_wrapper/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@ use std::{any::type_name, fmt::Debug};
use thiserror::Error;
use web5::credentials::presentation_definition::PexError;
use web5::credentials::CredentialError;
use web5::crypto::dsa::DsaError;
use web5::crypto::{jwk::JwkError, key_managers::KeyManagerError};
use web5::crypto::key_managers::KeyManagerError;
use web5::dids::bearer_did::BearerDidError;
use web5::dids::data_model::DataModelError as DidDataModelError;
use web5::dids::methods::MethodError;
use web5::dids::portable_did::PortableDidError;
use web5::errors::Web5Error as InnerWeb5Error;

#[derive(Debug, Error)]
Expand Down Expand Up @@ -79,30 +76,12 @@ where
variant_name.to_string()
}

impl From<JwkError> for Web5Error {
fn from(error: JwkError) -> Self {
Web5Error::new(error)
}
}

impl From<KeyManagerError> for Web5Error {
fn from(error: KeyManagerError) -> Self {
Web5Error::new(error)
}
}

impl From<DsaError> for Web5Error {
fn from(error: DsaError) -> Self {
Web5Error::new(error)
}
}

impl From<PortableDidError> for Web5Error {
fn from(error: PortableDidError) -> Self {
Web5Error::new(error)
}
}

impl From<MethodError> for Web5Error {
fn from(error: MethodError) -> Self {
Web5Error::new(error)
Expand All @@ -121,12 +100,6 @@ impl From<PexError> for Web5Error {
}
}

impl From<DidDataModelError> for Web5Error {
fn from(error: DidDataModelError) -> Self {
Web5Error::new(error)
}
}

impl From<BearerDidError> for Web5Error {
fn from(error: BearerDidError) -> Self {
Web5Error::new(error)
Expand All @@ -144,13 +117,7 @@ impl From<Web5Error> for KeyManagerError {
let variant = error.variant();
let msg = error.msg();

if variant
== variant_name(&KeyManagerError::JwkError(JwkError::ThumbprintFailed(
String::default(),
)))
{
return KeyManagerError::JwkError(JwkError::ThumbprintFailed(msg.to_string()));
} else if variant == variant_name(&KeyManagerError::KeyGenerationFailed) {
if variant == variant_name(&KeyManagerError::KeyGenerationFailed) {
return KeyManagerError::KeyGenerationFailed;
} else if variant
== variant_name(&KeyManagerError::InternalKeyStoreError(String::default()))
Expand All @@ -164,32 +131,26 @@ impl From<Web5Error> for KeyManagerError {
}
}

impl From<Web5Error> for DsaError {
impl From<Web5Error> for InnerWeb5Error {
fn from(error: Web5Error) -> Self {
let variant = error.variant();
let msg = error.msg();

if variant == variant_name(&DsaError::MissingPrivateKey) {
return DsaError::MissingPrivateKey;
} else if variant == variant_name(&DsaError::DecodeError(String::default())) {
return DsaError::DecodeError(msg);
} else if variant == variant_name(&DsaError::InvalidKeyLength(String::default())) {
return DsaError::InvalidKeyLength(msg);
} else if variant == variant_name(&DsaError::InvalidSignatureLength(String::default())) {
return DsaError::InvalidSignatureLength(msg);
} else if variant == variant_name(&DsaError::PublicKeyFailure(String::default())) {
return DsaError::PublicKeyFailure(msg);
} else if variant == variant_name(&DsaError::PrivateKeyFailure(String::default())) {
return DsaError::PrivateKeyFailure(msg);
} else if variant == variant_name(&DsaError::VerificationFailure(String::default())) {
return DsaError::VerificationFailure(msg);
} else if variant == variant_name(&DsaError::SignFailure(String::default())) {
return DsaError::SignFailure(msg);
} else if variant == variant_name(&DsaError::UnsupportedDsa) {
return DsaError::UnsupportedDsa;
if variant == variant_name(&InnerWeb5Error::Json(String::default())) {
return InnerWeb5Error::Json(msg);
} else if variant == variant_name(&InnerWeb5Error::Parameter(String::default())) {
return InnerWeb5Error::Parameter(msg);
} else if variant == variant_name(&InnerWeb5Error::DataMember(String::default())) {
return InnerWeb5Error::DataMember(msg);
} else if variant == variant_name(&InnerWeb5Error::NotFound(String::default())) {
return InnerWeb5Error::NotFound(msg);
} else if variant == variant_name(&InnerWeb5Error::Crypto(String::default())) {
return InnerWeb5Error::Crypto(msg);
} else if variant == variant_name(&InnerWeb5Error::Encoding(String::default())) {
return InnerWeb5Error::Encoding(msg);
}

DsaError::Unknown
InnerWeb5Error::Unknown(format!("unknown variant {} with msg {}", variant, msg))
}
}

Expand Down
21 changes: 21 additions & 0 deletions bound/kt/src/main/kotlin/web5/sdk/crypto/Ed25519Generator.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package web5.sdk.crypto

import web5.sdk.crypto.keys.Jwk
import web5.sdk.rust.ed25519GeneratorGenerate

/**
* Generates private key material for Ed25519.
*/
class Ed25519Generator {
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 {
val rustCoreJwkData = ed25519GeneratorGenerate()
return Jwk.fromRustCoreJwkData(rustCoreJwkData)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package web5.sdk.crypto.keys

import web5.sdk.crypto.signers.ToOuterSigner
import web5.sdk.crypto.signers.Signer
import web5.sdk.rust.InMemoryKeyManager as RustCoreInMemoryKeyManager

Expand All @@ -16,7 +17,7 @@ class InMemoryKeyManager : KeyManager {
*/
constructor(privateJwks: List<Jwk>) {
privateJwks.forEach {
this.rustCoreInMemoryKeyManager.importPrivateJwk(it)
this.rustCoreInMemoryKeyManager.importPrivateJwk(it.rustCoreJwkData)
}
}

Expand All @@ -27,7 +28,8 @@ class InMemoryKeyManager : KeyManager {
* @return Signer The signer for the given public key.
*/
override fun getSigner(publicJwk: Jwk): Signer {
return this.rustCoreInMemoryKeyManager.getSigner(publicJwk)
val rustCoreSigner = this.rustCoreInMemoryKeyManager.getSigner(publicJwk.rustCoreJwkData)
return ToOuterSigner(rustCoreSigner)
}

/**
Expand All @@ -37,6 +39,7 @@ class InMemoryKeyManager : KeyManager {
* @return Jwk The public key represented as a JWK.
*/
fun importPrivateJwk(privateJwk: Jwk): Jwk {
return this.rustCoreInMemoryKeyManager.importPrivateJwk(privateJwk)
val rustCoreJwkData = this.rustCoreInMemoryKeyManager.importPrivateJwk(privateJwk.rustCoreJwkData)
return Jwk.fromRustCoreJwkData(rustCoreJwkData)
}
}
36 changes: 35 additions & 1 deletion bound/kt/src/main/kotlin/web5/sdk/crypto/keys/Jwk.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,44 @@
package web5.sdk.crypto.keys

import web5.sdk.rust.Jwk as RustCoreJwk
import web5.sdk.rust.JwkData as RustCoreJwkData

/**
* Partial representation of a [JSON Web Key as per RFC7517](https://tools.ietf.org/html/rfc7517).
* Note that this is a subset of the spec.
*/
data class Jwk (
val alg: String? = null,
val kty: String,
val crv: String,
val x: String,
val y: String? = null,
val d: String? = null
) {
internal val rustCoreJwkData: RustCoreJwkData = RustCoreJwkData(
alg,
kty,
crv,
d,
x,
y
)

typealias Jwk = RustCoreJwkData
internal companion object {
fun fromRustCoreJwkData(rustCoreJwkData: RustCoreJwkData): Jwk {
return Jwk(
rustCoreJwkData.alg,
rustCoreJwkData.kty,
rustCoreJwkData.crv,
rustCoreJwkData.x,
rustCoreJwkData.y,
rustCoreJwkData.d,
)
}
}

fun computeThumbprint(): String {
val rustCoreJwk = RustCoreJwk(rustCoreJwkData)
return rustCoreJwk.computeThumbprint()
}
}
Loading

0 comments on commit a6aef12

Please sign in to comment.