4 stable releases
| 1.3.0 | May 15, 2025 |
|---|---|
| 1.2.0 | Mar 10, 2025 |
| 1.1.0 | Aug 7, 2024 |
| 1.0.1 | Jun 28, 2024 |
#23 in #canister
9,988 downloads per month
Used in 16 crates
(4 directly)
35KB
601 lines
IC Canister Signatures Creation
Crate for handling canister signatures public keys and creating canister signatures. Please refer to the ic-standalone-sig-verifier crate for canister signature verification.
Introduction
In order to create a canister signature, a canister needs to commit to a public key seed and a message_hash in its certified_data. This crate provides utilities to make this process as easy as possible.
For a more in-depth explanation of the concepts, see the official specification of canister signatures as well as the documentation of certified data.
Creating Signatures
Creating a signature is a two-step process:
- the signature has to be prepared in an
updatecall - the signature has to be retrieved in a
querycall
In order to bridge the two steps, the canister has to keep state about the prepared signatures:
use ic_canister_sig_creation::signature_map::SignatureMap;
thread_local! {
/// Prepared canister signatures, no need to keep them in stable memory as they are only kept for one minute
/// (to give clients time to do the query call).
static SIGNATURES : RefCell<SignatureMap> = RefCell::new(SignatureMap::default());
}
Preparing a Signature
To prepare a signature on a message, add it's hash to the signature map together with the seed used to generate the public key:
use ic_canister_sig_creation::hash_bytes;
/// The signature domain should be unique for the context in which the signature is used.
const SIG_DOMAIN: &[u8] = b"ic-example-canister-sig";
fn add_signature(seed: &[u8], message: &[u8]) {
let sig_inputs = CanisterSigInputs {
domain: SIG_DOMAIN,
seed,
message,
};
SIGNATURES.with_borrow_mut(|sigs| {
sigs.add_signature(&sig_inputs);
});
}
Then update the certified_data to the new root hash of the signature map:
use ic_canister_sig_creation::signature_map::LABEL_SIG;
use ic_cdk::api::set_certified_data;
fn update_root_hash() {
SIGNATURES.with_borrow(|sigs| {
set_certified_data(&labeled_hash(LABEL_SIG, &sigs.root_hash()));
})
}
Retrieving a Signature
To retrieve a prepared signature, use the get_signature_as_cbor on the SignatureMap instance:
/// The signature domain should be unique for the context in which the signature is used.
const SIG_DOMAIN: &[u8] = b"ic-example-canister-sig";
fn get_signature(seed: &[u8], message: &[u8]) -> Result<Vec<u8>, String> {
let sig_inputs = CanisterSigInputs {
domain: SIG_DOMAIN,
seed,
message,
};
SIGNATURES.with_borrow(|sigs| {
sigs.get_signature_as_cbor(&sig_inputs, None)
});
}
Dependencies
~3–12MB
~124K SLoC