Skip to main content

User Secret Share Encryption

A dWallet consists of a User Secret Share, and a Network Secret Share.

The core primitive that governs control over a dWallet on the dWallet Network is the dWallet’s User Secret Share. Possession of the user secret share grants the ability to authorize and sign transactions using that specific dWallet.

To facilitate ownership transfer or grant access to a dWallet, the User Secret Share must be encrypted and bound to a designated address on the network. This is achieved by encrypting the User Secret Share using the recipient account’s EncryptionKey. Each account on the dWallet Network generates its own EncryptionKey object, which is stored in a mapping that links addresses to their respective encryption keys called EncryptionKeysTable.

By leveraging this system, we can securely encrypt data to a specific account using its EncryptionKey, especially transferring dWallets between accounts, ensuring privacy during data exchange.

By enabling the encryption process directly on-chain, users no longer need to rely on off-chain processes or manually manage encryption, which streamlines activities such as sharing access, transferring ownership, and automating DeFi operations via smart contracts. This feature also enhances smart contract functionality, allowing them to securely manage actions like setting trading limits, enforcing policies, or transferring collateral without requiring user intervention. The encryption feature integrates seamlessly with Zero Trust Protocols (ZTPs) by minimizing off-chain reliance, simplifying key management, and upholding security protocols.

For example, in a DeFi loan scenario, users can lock BTC in a dWallet and manage the loan conditions through smart contracts, all while keeping the User Secret Share encrypted and secure on-chain.

Transferring a dWallet's User Secret Share

When we create a dWallet, we provide an EncryptionKey and receive an encryptedSecretShareObjID. Using this object ID, we can access the encrypted secret share object. The owner of the dWallet is the sole entity that can decrypt the User Secret Share which is essential for signing messages using this dWallet.

Encrypting the User Secret Share

Please read about Encryption Keys before you proceed. We assume that you already created a dwallet using: createDWallet(). If not, please create one as explained here.

On the sender side, we need the public key of the target account.

This is how we perform the transfer.

import {serialized_pubkeys_from_decentralized_dkg_output} from '@dwallet-network/signature-mpc-wasm';
import {
getEncryptedUserShareByObjectID,
sendUserShareToSuiPubKey,
} from '@dwallet-network/dwallet.js/signature-mpc';

// Get your encrypted user secret share.
const encryptedSecretShare = await getEncryptedUserShareByObjectID(
client,
createdDwallet?.encryptedSecretShareObjID!,
);

// Verify you signed the dkg output public keys before using it to send the user share.
let signedDWalletPubKeys = new Uint8Array(encryptedSecretShare?.signedDWalletPubKeys!);
console.log("signedDWalletPubKeys ", signedDWalletPubKeys);

const res = await keypair
.getPublicKey()
.verify(
serialized_pubkeys_from_decentralized_dkg_output(
new Uint8Array(createdDwallet?.decentralizedDKGOutput!),
),
signedDWalletPubKeys,
);
console.assert(res, "Failed to verify the signed dkg output public keys");

// This is sent to you off-chain by the receiver.
// It is placed here only to make the example work.
const otherKeypair = new Ed25519Keypair();


// Send the user secret share to a target address
const objRef = await sendUserShareToSuiPubKey(
client,
keypair,
createdDwallet!,
otherKeypair.getPublicKey(),
activeEncryptionKeysTableID,
signedDWalletPubKeys,
);

Now, you transfer off-chain the objectId of the objRef to the receiver. Also, the receiver needs the address of the sender.

import {createDWallet} from "@dwallet-network/dwallet.js/signature-mpc";

let encryptedUserShareObjID = objRef?.objectId;
let senderAddress = keypair.toSuiAddress();
let dwalletID = createdDwallet?.dwalletID!;

// This is not a real function, you have to implement it yourself.
SendToReceiverOffChain(encryptedUserShareObjID, senderAddress, dwalletID);

On the receiver’s side, you must accept the Encrypted User Share. It’s important to note that the client and keypair parameters in this context refer to the receiver, and they differ from those used by the sender.

import {getEncryptedUserShareByObjID} from "@dwallet-network/dwallet.js/signature-mpc";

// Get the parameters from the sender.
const {
encryptedUserShareObjID,
senderAddress,
dwalletID,
// This is not a real function, you have to implement it yourself.
} = ReceiveParametersOffChain();

// Get the new Encrypted User Share object ID.
let encryptedUserShare = await getEncryptedUserShareByObjID(
client,
encryptedUserShareObjID!,
);

// Approve acceptance of the User Secret Share.
const result = await acceptUserShare(
encryptedUserShare!,
senderAddress,
receiverEncryptionKeyObj,
dwalletID,
activeEncryptionKeysTableID,
client,
keypair,
);

console.assert(result, 'Failed to accept user share: Result is not truthy.');