Files
Odin/core/encoding/uuid/generation.odin
T
2024-06-22 18:21:31 -04:00

161 lines
3.6 KiB
Odin

package uuid
import "core:crypto/legacy/md5"
import "core:crypto/legacy/sha1"
import "core:math/rand"
import "core:mem"
/*
Generate a version 3 UUID.
This UUID is generated from a name within a namespace.
MD5 is used to hash the name with the namespace to produce the UUID.
Inputs:
- namespace: Another `Identifier` that is used to represent the underlying namespace.
This can be any one of the `Namespace_*` values provided in this package.
- name: The byte slice used to generate the name on top of the namespace.
Returns:
- result: The generated UUID.
*/
generate_v3_bytes :: proc(
namespace: Identifier,
name: []byte,
) -> (
result: Identifier,
) {
namespace := namespace
ctx: md5.Context
md5.init(&ctx)
md5.update(&ctx, namespace[:])
md5.update(&ctx, name)
md5.final(&ctx, result[:])
result[VERSION_BYTE_INDEX] &= 0x0F
result[VERSION_BYTE_INDEX] |= 0x30
result[VARIANT_BYTE_INDEX] &= 0x3F
result[VARIANT_BYTE_INDEX] |= 0x80
return
}
/*
Generate a version 3 UUID.
This UUID is generated from a name within a namespace.
MD5 is used to hash the name with the namespace to produce the UUID.
Inputs:
- namespace: Another `Identifier` that is used to represent the underlying namespace.
This can be any one of the `Namespace_*` values provided in this package.
- name: The string used to generate the name on top of the namespace.
Returns:
- result: The generated UUID.
*/
generate_v3_string :: proc(
namespace: Identifier,
name: string,
) -> (
result: Identifier,
) {
return generate_v3_bytes(namespace, transmute([]byte)name)
}
generate_v3 :: proc {
generate_v3_bytes,
generate_v3_string,
}
/*
Generate a version 4 UUID.
This UUID will be pseudorandom, save for 6 pre-determined version and variant bits.
Returns:
- result: The generated UUID.
*/
generate_v4 :: proc() -> (result: Identifier) {
bytes_generated := rand.read(result[:])
assert(bytes_generated == 16, "RNG failed to generate 16 bytes for UUID v4.")
result[VERSION_BYTE_INDEX] &= 0x0F
result[VERSION_BYTE_INDEX] |= 0x40
result[VARIANT_BYTE_INDEX] &= 0x3F
result[VARIANT_BYTE_INDEX] |= 0x80
return
}
/*
Generate a version 5 UUID.
This UUID is generated from a name within a namespace.
SHA1 is used to hash the name with the namespace to produce the UUID.
Inputs:
- namespace: Another `Identifier` that is used to represent the underlying namespace.
This can be any one of the `Namespace_*` values provided in this package.
- name: The byte slice used to generate the name on top of the namespace.
Returns:
- result: The generated UUID.
*/
generate_v5_bytes :: proc(
namespace: Identifier,
name: []byte,
) -> (
result: Identifier,
) {
namespace := namespace
digest: [sha1.DIGEST_SIZE]byte
ctx: sha1.Context
sha1.init(&ctx)
sha1.update(&ctx, namespace[:])
sha1.update(&ctx, name)
sha1.final(&ctx, digest[:])
mem.copy_non_overlapping(&result, &digest, 16)
result[VERSION_BYTE_INDEX] &= 0x0F
result[VERSION_BYTE_INDEX] |= 0x50
result[VARIANT_BYTE_INDEX] &= 0x3F
result[VARIANT_BYTE_INDEX] |= 0x80
return
}
/*
Generate a version 5 UUID.
This UUID is generated from a name within a namespace.
SHA1 is used to hash the name with the namespace to produce the UUID.
Inputs:
- namespace: Another `Identifier` that is used to represent the underlying namespace.
This can be any one of the `Namespace_*` values provided in this package.
- name: The string used to generate the name on top of the namespace.
Returns:
- result: The generated UUID.
*/
generate_v5_string :: proc(
namespace: Identifier,
name: string,
) -> (
result: Identifier,
) {
return generate_v5_bytes(namespace, transmute([]byte)name)
}
generate_v5 :: proc {
generate_v5_bytes,
generate_v5_string,
}