Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bearer Did Impl #247

Merged
merged 7 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 36 additions & 15 deletions bound/kt/src/main/kotlin/web5/sdk/crypto/keys/InMemoryKeyManager.kt
Original file line number Diff line number Diff line change
@@ -1,33 +1,54 @@
package web5.sdk.crypto.keys

import web5.sdk.crypto.signers.OuterSigner
import web5.sdk.crypto.signers.Signer

import web5.sdk.rust.InMemoryKeyManager as RustCoreInMemoryKeyManager
import web5.sdk.rust.KeyManager as RustCoreKeyManager

/**
* A class for managing cryptographic keys in-memory.
*/
class InMemoryKeyManager {
private val rustCoreKeyManager = RustCoreInMemoryKeyManager()
class InMemoryKeyManager : KeyManager {
private val rustCoreInMemoryKeyManager = RustCoreInMemoryKeyManager()

/**
* Constructs an InMemoryKeyManager with the given private keys.
*
* @param privateJwks A list of private keys represented as JWKs (JSON Web Keys).
*/
constructor(privateJwks: List<Jwk>) {
privateJwks.forEach {
this.rustCoreInMemoryKeyManager.importPrivateJwk(it)
}
}

/**
* Returns the Signer for the given public key.
*
* @param publicJwk The public key represented as a JWK.
* @return Signer The signer for the given public key.
*/
override fun getSigner(publicJwk: Jwk): Signer {
val innerSigner = this.rustCoreInMemoryKeyManager.getSigner(publicJwk)
return OuterSigner(innerSigner)
}

/**
* Returns the Ed25519Signer for the given public key.
* Returns the RustCoreKeyManager.
*
* @param publicKey the public key represented as a Jwk.
* @return Ed25519Signer the signer for the given public key.
* @return RustCoreKeyManager The rust core key manager.
*/
fun getSigner(publicKey: Jwk): Signer {
return rustCoreKeyManager.getSigner(publicKey)
override fun getRustCoreKeyManager(): RustCoreKeyManager {
return this.rustCoreInMemoryKeyManager.getAsKeyManager()
}

/**
* For importing private keys which may be stored somewhere such as environment variables.
* Returns Jwk which is the public key for the given private key.
* Imports a private key which may be stored somewhere such as environment variables.
*
* @param privateKey the private key represented as a Jwk.
* @return Jwk the public key for the given private key.
* @param privateJwk The private key represented as a JWK.
* @return Jwk The public key represented as a JWK.
*/
fun importPrivateKey(privateKey: Jwk): Jwk {
return rustCoreKeyManager.importPrivateJwk(privateKey)
fun importPrivateJwk(privateJwk: Jwk): Jwk {
return this.rustCoreInMemoryKeyManager.importPrivateJwk(privateJwk)
}
}
}
17 changes: 5 additions & 12 deletions bound/kt/src/main/kotlin/web5/sdk/crypto/keys/KeyManager.kt
Original file line number Diff line number Diff line change
@@ -1,32 +1,25 @@
package web5.sdk.crypto.keys

import web5.sdk.crypto.signers.Signer
import web5.sdk.rust.KeyManager as RustCoreKeyManager

/**
* An interface representing a key manager for cryptographic operations.
*/
interface KeyManager {
/**
* Generates new key material and returns the public key represented as a Jwk.
*
* @return Jwk The generated public key.
*/
fun generateKeyMaterial(): Jwk

/**
* Returns the signer for the given public key.
*
* @param publicKey The public key represented as a Jwk.
* @return Signer The signer for the given public key.
*/
fun getSigner(publicKey: Jwk): Signer
fun getSigner(publicJwk: Jwk): Signer

/**
* Imports a key which may be stored somewhere such as environment variables.
* Returns the public key for the given private key.
* Returns the RustCoreKeyManager
*
* @param privateKey The private key represented as a Jwk.
* @return Jwk The public key for the given private key.
* @return RustCoreKeyManager The rust core key manager
*/
fun importKey(privateKey: Jwk): Jwk
fun getRustCoreKeyManager(): RustCoreKeyManager
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class Ed25519Signer : Signer {
* @return ByteArray the signature.
*/
@OptIn(ExperimentalUnsignedTypes::class)
override fun sign(payload: List<UByte>): ByteArray {
override fun sign(payload: ByteArray): ByteArray {
val uByteList = payload.toUByteArray().toList()
return rustCoreSigner.sign(uByteList)
}
Expand Down
19 changes: 17 additions & 2 deletions bound/kt/src/main/kotlin/web5/sdk/crypto/signers/Signer.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
package web5.sdk.crypto.signers

import web5.sdk.rust.SignerInterface as RustCoreSignerInterface
import web5.sdk.rust.Signer as RustCoreSigner

typealias Signer = RustCoreSignerInterface
interface Signer {
fun sign(payload: ByteArray): ByteArray
}

class OuterSigner: Signer {
private val rustCoreSigner: RustCoreSigner

constructor(rustCoreSigner: RustCoreSigner) {
this.rustCoreSigner = rustCoreSigner
}

@OptIn(ExperimentalUnsignedTypes::class)
override fun sign(payload: ByteArray): ByteArray {
return this.rustCoreSigner.sign(payload.toUByteArray().toList())
}
}
78 changes: 78 additions & 0 deletions bound/kt/src/main/kotlin/web5/sdk/dids/BearerDid.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package web5.sdk.dids

import web5.sdk.crypto.signers.Signer
import web5.sdk.crypto.keys.KeyManager
import web5.sdk.crypto.signers.OuterSigner

import web5.sdk.rust.BearerDid as RustCoreBearerDid

import web5.sdk.rust.didJwkResolve as rustCoreDidJwkResolve
import web5.sdk.rust.didWebResolve as rustCoreDidWebResolve
import web5.sdk.rust.didDhtResolve as rustCoreDidDhtResolve

/**
* Represents a Decentralized Identifier (DID) along with its DID document, key manager, metadata,
* and convenience functions.
*
* @property did The DID associated with this instance.
* @property document The DID document associated with this instance.
*/
class BearerDid {
val did: Did
val document: Document
val keyManager: KeyManager

private val rustCoreBearerDid: RustCoreBearerDid

/**
* Constructs a BearerDid instance using a DID URI and a key manager.
*
* @param uri The DID URI.
* @param keyManager The key manager to handle keys.
*/
constructor(uri: String, keyManager: KeyManager) {
this.rustCoreBearerDid = RustCoreBearerDid(uri, keyManager.getRustCoreKeyManager())

this.did = this.rustCoreBearerDid.getData().did
this.document = this.rustCoreBearerDid.getData().document
this.keyManager = keyManager
}

/**
* Returns a signer for the DID.
*
* @return Signer The signer for the DID.
*/
fun getSigner(): Signer {
val keyId = this.document.verificationMethod.first().id
val innerSigner = this.rustCoreBearerDid.getSigner(keyId)
return OuterSigner(innerSigner)
}

companion object {
/**
* Resolves a DID URI to a ResolutionResult.
*
* @param uri The DID URI to resolve.
* @return ResolutionResult The result of the DID resolution.
*/
@JvmStatic
suspend fun resolve(uri: String): ResolutionResult {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's your thinking with this function? This isn't in the APID, is it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right, I think got influenced by current impl in web5-kt.

That does beg the question though, how would we resovle a bearer did:

It would have to be like:

DidDht.resolve(bearerDid.did.uri)

But how would you know the type, (the bearer did could be JWK..)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bearer DID could be resolvable via the CONSTRUCTOR(uri: string, key_manager: KeyManager), because internal to that constructor would be three things:

  1. A call to ResolutionResult(uri) to resolve the Document
  2. A call to Did(uri) to parse the Did
  3. Assignment of the key_manager to the data member

I'm doing this in web5-r

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CLASS BearerDid
  PUBLIC DATA did: Did
  PUBLIC DATA document: Document
  CONSTRUCTOR(uri: string, key_manager: KeyManager)
  METHOD get_signer(): Signer

Right genius, its already resolved basically and we have document right there :duhh: I'll update it

// TODO: Add a concept of a universal resolver - https://github.com/TBD54566975/web5-rs/issues/246
val method = uri.substringAfter(":").substringBefore(":")
if(method == "jwk") {
return rustCoreDidJwkResolve(uri).getData()
}

if(method == "dht") {
return rustCoreDidDhtResolve(uri).getData()
}

if(method == "web") {
return rustCoreDidWebResolve(uri).getData()
}

throw IllegalArgumentException("Unknown method '$method'")
}
}
}
59 changes: 1 addition & 58 deletions bound/kt/src/main/kotlin/web5/sdk/dids/Did.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,62 +4,5 @@ import web5.sdk.rust.DidData as RustCoreDidData

/**
* Representation of a [DID Core Identifier](https://www.w3.org/TR/did-core/#identifiers).
*
* @property uri Represents the complete Decentralized Identifier (DID) URI.
* @property url Represents the DID URI + A network location identifier for a specific resource.
* @property method Specifies the DID method in the URI, indicating the underlying method-specific identifier scheme.
* @property id The method-specific identifier in the DID URI.
* @property params A map containing optional parameters present in the DID URI. These parameters are method-specific.
* @property path An optional path component in the DID URI.
* @property query An optional query component in the DID URI, used to express a request for a specific representation or resource related to the DID.
* @property fragment An optional fragment component in the DID URI, used to reference a specific part of a DID document.
*/
data class Did(
val uri: String,
val url: String,
val method: String,
val id: String,
val params: Map<String, String> = emptyMap(),
val path: String? = null,
val query: String? = null,
val fragment: String? = null
) {
/**
* Converts the Did instance to a RustCoreDidData binding.
*
* @return RustCoreDidData the corresponding RustCoreDidData object.
*/
fun toRustCore(): RustCoreDidData {
return RustCoreDidData(
uri = this.uri,
url = this.url,
method = this.method,
id = this.id,
params = this.params.ifEmpty { null },
path = this.path,
query = this.query,
fragment = this.fragment
)
}

companion object {
/**
* Creates a Did instance from a RustCoreDidData binding.
*
* @param didData the RustCoreDidData object.
* @return Did the corresponding Did instance.
*/
fun fromRustCore(didData: RustCoreDidData): Did {
return Did(
uri = didData.uri,
url = didData.url,
method = didData.method,
id = didData.id,
params = didData.params ?: emptyMap(),
path = didData.path,
query = didData.query,
fragment = didData.fragment
)
}
}
}
typealias Did = RustCoreDidData
4 changes: 2 additions & 2 deletions bound/kt/src/main/kotlin/web5/sdk/dids/methods/dht/DidDht.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class DidDht {
constructor(identityKey: Jwk) {
rustCoreDidDht = RustCoreDidDht.fromIdentityKey(identityKey)

this.did = Did.fromRustCore(rustCoreDidDht.getData().did)
this.did = rustCoreDidDht.getData().did
this.document = rustCoreDidDht.getData().document
}

Expand All @@ -42,7 +42,7 @@ class DidDht {
constructor(uri: String) {
rustCoreDidDht = RustCoreDidDht.fromUri(uri)

this.did = Did.fromRustCore(rustCoreDidDht.getData().did)
this.did = rustCoreDidDht.getData().did
this.document = rustCoreDidDht.getData().document
}

Expand Down
4 changes: 2 additions & 2 deletions bound/kt/src/main/kotlin/web5/sdk/dids/methods/jwk/DidJwk.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class DidJwk {
constructor(publicKey: Jwk) {
val rustCoreDidJwk = RustCoreDidJwk.fromPublicJwk(publicKey)

this.did = Did.fromRustCore(rustCoreDidJwk.getData().did)
this.did = rustCoreDidJwk.getData().did
this.document = rustCoreDidJwk.getData().document
}

Expand All @@ -38,7 +38,7 @@ class DidJwk {
constructor(uri: String) {
val rustCoreDidJwk = RustCoreDidJwk.fromUri(uri)

this.did = Did.fromRustCore(rustCoreDidJwk.getData().did)
this.did = rustCoreDidJwk.getData().did
this.document = rustCoreDidJwk.getData().document
}

Expand Down
Loading
Loading