Security Utilities
Security utilities provide essential cryptographic functions for ensuring data integrity and authenticity within the Blocklet ecosystem. These functions handle common tasks such as signing and verifying data payloads, as well as managing complex multi-signature verification for blocklet metadata.
signResponse#
Signs a data payload using a provided wallet object and attaches the signature to the object. The function uses json-stable-stringify
to ensure a deterministic JSON string representation of the data before signing, which is crucial for verification.
Signature
function signResponse<T extends Record<string, any>>(data: T, wallet: WalletObject): T & { $signature: string }
Parameters
Name | Type | Description |
---|---|---|
|
| The JSON-serializable object to be signed. |
|
| An instance of a wallet from |
Returns
The original data
object with an added $signature
property containing the generated signature string.
Example
import { signResponse } from '@blocklet/meta';
import { fromRandom } from '@ocap/wallet';
const wallet = fromRandom();
const myData = {
user: 'did:abt:z123456789',
action: 'approve',
timestamp: Date.now(),
};
const signedData = signResponse(myData, wallet);
console.log(signedData);
// {
// user: 'did:abt:z123456789',
// action: 'approve',
// timestamp: 1678886400000,
// $signature: '...'
// }
verifyResponse#
Verifies a signature attached to a data object. It isolates the payload by removing the $signature
field, deterministically stringifies it, and then uses the provided wallet to verify the signature against the payload.
Signature
function verifyResponse<T extends Record<string, any>>(
signed: T & { $signature?: string },
wallet: WalletObject
): Promise<boolean>
Parameters
Name | Type | Description |
---|---|---|
|
| The object containing the data and the |
|
| The wallet corresponding to the public key of the original signer. |
Returns
A Promise<boolean>
that resolves to true
if the signature is valid, and false
otherwise.
Example
import { signResponse, verifyResponse } from '@blocklet/meta';
import { fromRandom } from '@ocap/wallet';
async function main() {
const wallet = fromRandom();
const myData = { user: 'did:abt:z123456789', action: 'approve' };
// Sign the data
const signedData = signResponse(myData, wallet);
console.log('Signed Data:', signedData);
// Verify the signature (should be true)
const isValid = await verifyResponse(signedData, wallet);
console.log('Verification successful:', isValid);
// Tamper with the data
const tamperedData = { ...signedData, action: 'reject' };
const isTamperedValid = await verifyResponse(tamperedData, wallet);
console.log('Verification of tampered data successful:', isTamperedValid);
}
main();
verifyMultiSig#
Verifies a chain of signatures on a blocklet.yml
metadata object. This is critical for ensuring the integrity and authenticity of blocklet metadata that may be signed by multiple parties (e.g., developer, publisher, registry). The verification process is sequential, and each signature covers the state of the metadata at the time of signing.
Signature
function verifyMultiSig(blockletMeta: TBlockletMeta): Promise<boolean>
Parameters
Name | Type | Description |
---|---|---|
|
| The full blocklet metadata object, including the |
Returns
A Promise<boolean>
that resolves to true
if all signatures in the chain are valid, and false
otherwise.
Verification Flow
The function iterates through signatures, validating each one against a reconstructed version of the metadata. This reconstruction accounts for fields that were excluded by the current signer or appended by previous signers.
Key Concepts
- Sequential Signing: Each signature signs the core metadata plus all subsequent signatures in the array. This creates a verifiable chain.
- Delegation: A signer can delegate signing authority to another key via a JWT.
verifyMultiSig
will first validate this delegation token before using the delegatee's key for verification. excludes
: A property in a signature object allowing a signer to exclude specific top-level metadata fields from their signed payload.appended
: A property where a signer declares fields they added. When verifying previous signatures, these fields are omitted from the payload to match its original state.
verifyVault#
Verifies a chronological, chained list of vault records. This mechanism establishes a secure, verifiable chain of DIDs, where each new entry must be approved by the preceding one. It is used to create a verifiable chain of trust or ownership transfer.
Signature
async function verifyVault(vaults: VaultRecord[], appPid: string, throwOnError = false): Promise<string>
Parameters
Name | Type | Description |
---|---|---|
|
| An array of vault records, sorted chronologically by the |
|
| A unique identifier for the application context (e.g., an app DID). |
|
| If |
Returns
A Promise<string>
that resolves to the DID of the last valid vault in the chain. If verification fails and throwOnError
is false
, it returns an empty string.
Verification Process
The function performs several checks in sequence:
- Ensures the vault list is not empty.
- Verifies that vaults are in ascending order by timestamp (
at
). - Checks for duplicate DIDs.
- For each vault, it verifies both an
approverSig
(from the previous vault owner or an initial approver) and asig
(the commit signature from the current vault owner).
These security utilities form the cryptographic foundation for trustworthy interactions in the Blocklet ecosystem. To understand how the wallets used in these functions are managed, see the DID & Wallet Utilities documentation.