Custom Integration
Custom integration provides greater flexibility by allowing the appchain to directly communicate with Fairyring's x/keyshare
module over IBC.
This method requires the appchain to handle the logic for initiating IBC transactions to Fairyring and processing the corresponding responses. While it provides full control over encryption workflows, it demands more effort compared to direct x/pep
integration.
Overview
In the custom integration path:
- The appchain establishes direct IBC communication with Fairyring's
keyshare
module. - The appchain must manage when to send IBC requests and how to handle IBC acknowledgments and responses.
- Responsibility for queueing, timeout handling, retries, and state management lies with the appchain.
This approach is suitable for advanced chains that want to implement their own confidential workflows or layer additional logic on top of Fairyring's capabilities.
Available IBC Endpoints
Fairyring's x/keyshare
module provides several IBC packet types that the appchain can interact with. Below is a summary of each available packet and its purpose.
RequestDecryptionKeyPacketData
Used by the appchain to request an identity from Fairyring.
This initiates the process of generating an encrypted identity and eventually obtaining its corresponding decryption key.
GetDecryptionKeyPacketData
Used by the appchain to request a decryption key for an already existing identity from Fairyring.
This packet is useful when the identity has already been requested previously, and only the key material is now needed.
DecryptionKeyDataPacketData
Sent by Fairyring to the appchain when a decryption key has been generated.
The appchain must be able to handle and consume this packet appropriately, such as by unlocking transactions encrypted under that identity.
RequestPrivateDecryptionKeyPacketData
Used by the appchain to request the generation of a private identity on Fairyring.
Private identities enable use cases where fine-grained access control is desired, such as user-specific confidential data.
GetPrivateDecryptionKeyPacketData
Used by the appchain to request a list of encrypted keyshares for an existing private identity from Fairyring.
This is part of enabling the private decryption workflow, where key material must be assembled in a privacy-preserving manner.
PrivateDecryptionKeyDataPacketData
Sent by Fairyring to the appchain containing the list of encrypted keyshares corresponding to a private identity.
The appchain must process this packet to reconstruct the private key securely when appropriate.
CurrentKeysPacketData
Used by the appchain to fetch the latest active and queued Master Public Keys (MPKs) from Fairyring.
This is critical to ensure that encryption operations on the appchain are always performed using the correct public key material.
General Integration Approach
Custom integration requires the appchain to:
- Establish an IBC connection with the Fairyring chain targeting the
keyshare
module. - Build and send IBC packets according to the desired workflow (e.g., requesting an identity, fetching decryption keys).
- Handle incoming packets (e.g., decryption keys, keyshares) in the IBC packet handler logic.
- Maintain local state, retries, timeouts, and re-request logic as necessary.
This is an advanced integration mode and assumes familiarity with Cosmos SDK's IBC application development.
Example Code Snippets
Sending a RequestDecryptionKeyPacket
import keysharetypes "github.com/Fairblock/fairyring/x/keyshare/types"
packet := keysharetypes.KeysharePacketData{
Packet: &keysharetypes.KeysharePacketData_RequestDecryptionKeyPacket{
RequestDecryptionKeyPacket: &keysharetypes.RequestDecryptionKeyPacketData{
Requester: requesterAddress.String(),
Identity: identity,
EstimatedDelay: durationpb.New(time.Minute * 5),
},
},
}
// Send the packet over IBC
err := app.KeyshareKeeper.TransmitKeysharePacket(
ctx,
packet,
sourcePort,
sourceChannel,
timeoutHeight,
timeoutTimestamp,
)
if err != nil {
return sdkerrors.Wrap(err, "failed to send RequestDecryptionKeyPacketData")
}
Handling a DecryptionKeyDataPacket
func (am AppModule) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data keysharetypes.KeysharePacketData) exported.Acknowledgement {
switch pkt := data.Packet.(type) {
case *keysharetypes.KeysharePacketData_DecryptionKeyDataPacket:
return handleDecryptionKeyData(ctx, pkt.DecryptionKeyDataPacket)
// handle other packet types
default:
return channeltypes.NewErrorAcknowledgement(fmt.Sprintf("unrecognized keyshare packet type"))
}
}
func handleDecryptionKeyData(ctx sdk.Context, packet *keysharetypes.DecryptionKeyDataPacketData) exported.Acknowledgement {
// Example: store decryption key locally
k.SetDecryptionKey(ctx, packet.Identity, packet.DecryptionKey)
return channeltypes.NewResultAcknowledgement([]byte("decryption key stored"))
}
Important Considerations
- IBC setup: Ensure a stable IBC connection exists with the Fairyring chain before sending any packets.
- Timeouts: Handle packet timeouts properly to avoid dangling requests.
- Retries: Implement retry logic where necessary, especially for long-lived decryption key generation processes.
- State management: Track pending identities and decryption keys cleanly in your appchain's state.
Conclusion
Custom integration offers full flexibility and enables building highly specialized confidential workflows using Fairyring's infrastructure. However, it demands careful IBC management, packet handling, and appchain-side orchestration.