3 stable releases
1.2.0 | Mar 10, 2025 |
---|---|
1.1.0 | Aug 7, 2024 |
1.0.1 | Jun 28, 2024 |
#605 in Magic Beans
5,662 downloads per month
Used in 12 crates
(5 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
update
call - the signature has to be retrieved in a
query
call
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
~2.5–9.5MB
~105K SLoC