Generating custom principals/uuids in Rust

Hey, I’ve looked through quite a few different places, and I’m not quite sure on the best way to generate custom principals or uuids with Rust.

How would I go about doing this? Is it possible to create custom principals? I think it would just be nice to be able to generate uuids that have the same format as IC principals.

Custom or random? Random ones can be generated from a random private/public key pair.

Principals follow a pattern and don’t make sense as a random blob; canister IDs are created by the system and cannot sign messages, only derived Principal IDs (derived from a private key) can sign messages.

So the only “custom” prinicpals I could see would be canister IDs, which you can use the text format to encode some. But the goal of Principals was always as an opaque blob that doesn’t make sense as a random value.

Thank you.

I want to be able to create UUIDs from within a canister. What is the best way to go about that? I think it would be nice for the UUID generated to have the same format as a principal, even if it doesn’t have the special features of a principal. All of this in Rust

You can use a PRNG, and you could seed it with the random beacon if you really want random stuff (otherwise timestamp would be enough?). The beacon API is here: The Internet Computer Interface Specification :: Internet Computer (it’s raw_rand : () -> (blob)).

Creating principals from a UUID wouldn’t make much sense IMO.

Just to back up a little, what is the problem you’re trying to solve by getting Principals in this manner? How are the principals going to be used?

1 Like

I’m just trying to generate UUIDs for database entries is all, and I would prefer to have UUIDs instead of incremental integers

2 Likes

How do I access raw_rand from a Rust canister? I don’t see it in the ic-cdk packages as far as I can tell. Am I supposed to treat the management canister as a canister and call it that way? Could you provide an example?

Yes. It’s a bit low level currently but it should work as any inter canister calls.

let (bytes,): (Vec<u8>,) = ic_cdk::api::call(Principal.management_canister(), "raw_rand", ()).await?;
3 Likes

Thank you! Are inter-canister calls documented for Rust at all? There doesn’t seem to be very much Rust documentation at all, unless I am not looking in the right places.

The CDK is a bit low level for the time being, just mapping on top of the System API exports with a bit of functionality for making calls async. Sorry about that, it’s still early in the development :slight_smile: We will get better over time.

1 Like

Very cool, I was looking for something similar for UUID’s, I ended up going with a global index.

I did too for now. I was wondering about the cost of using raw_rand for this?

I was able to get this working from a canister by creating a sha256 hash of the random bytes, which is awesome!

I am running into an issue with the IC’s async/await implementation though, I think. I’m using async-graphql, and from within an async mutation resolver, I’m getting some crazy errors about threading. I’m sure I’ll learn a lot more about this in the coming days and weeks, but can you give some insight into the async/await implementation that the IC has chosen? Here’s the issue I’ve opened in the async-graphql repo: Having trouble using std::rc::Rc values within a Mutation object. · Issue #110 · async-graphql/async-graphql · GitHub

I’m fearing that the IC’s async/await implementation might not be compatible with async-graphql, perhaps because the IC’s async/await has made an assumption that it will only operate in a single-threaded environment.

Also, would it be possible to make the raw_rand function synchronous? For example, getting the current time is a simple synchronous call to ic_cdk::api::time, so nice and simple. ic_cdk::api::raw_rand would be really nice.

2 Likes

The random value returned is guaranteed to be truly random (using a physical random beacon), so it cannot be synchronous. If you don’t need that kind of security, I recommend to use a PRNG seeded with either the beacon or time.

3 Likes

@hansl Sounds good on the sync, thank you. My bigger problem from a couple comments back remains…and I’m afraid it’s going to become a very large problem once I need to do inter-canister calls

@rckprtr how does what you’re doing compare with what I wrote here?

Hey,

So we are probably going to use this method

We have not had a chance to upgrade to !thread_local yet as we use the old paradigm 200+ times in our repo and figure it would be better to do a complete refactor instead of a quick fix.

Rick

1 Like

Can you give me example about using PRNG?
is it like

let id = rand::prng().gen(0..16)

?
Because: when i tried rand::prng it cannot find function prngin craterand [E0425]

I think you’d need to do something like this:

2 Likes