summaryrefslogtreecommitdiff
path: root/ext/crypto/lib.rs
diff options
context:
space:
mode:
authorSatya Rohith <me@satyarohith.com>2024-07-12 10:50:32 +0530
committerGitHub <noreply@github.com>2024-07-12 10:50:32 +0530
commitfee4d3a7627634e0ac352c832d821da9127b9b97 (patch)
treec29cd9ae6c4ab96c9dd27b642001c3058c49cdf8 /ext/crypto/lib.rs
parent01c074d1958bef0cb8076f911d46907d290c5ee8 (diff)
perf(ext/crypto): make randomUUID() 5x faster (#24510)
Diffstat (limited to 'ext/crypto/lib.rs')
-rw-r--r--ext/crypto/lib.rs75
1 files changed, 70 insertions, 5 deletions
diff --git a/ext/crypto/lib.rs b/ext/crypto/lib.rs
index 8a526bb40..7aa3462c7 100644
--- a/ext/crypto/lib.rs
+++ b/ext/crypto/lib.rs
@@ -615,14 +615,15 @@ pub fn op_crypto_random_uuid(state: &mut OpState) -> Result<String, AnyError> {
let uuid = if let Some(seeded_rng) = maybe_seeded_rng {
let mut bytes = [0u8; 16];
seeded_rng.fill(&mut bytes);
- uuid::Builder::from_bytes(bytes)
- .with_version(uuid::Version::Random)
- .into_uuid()
+ fast_uuid_v4(&mut bytes)
} else {
- uuid::Uuid::new_v4()
+ let mut rng = thread_rng();
+ let mut bytes = [0u8; 16];
+ rng.fill(&mut bytes);
+ fast_uuid_v4(&mut bytes)
};
- Ok(uuid.to_string())
+ Ok(uuid)
}
#[op2(async)]
@@ -713,3 +714,67 @@ pub fn op_crypto_unwrap_key(
pub fn get_declaration() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("lib.deno_crypto.d.ts")
}
+
+const HEX_CHARS: &[u8; 16] = b"0123456789abcdef";
+
+fn fast_uuid_v4(bytes: &mut [u8; 16]) -> String {
+ // Set UUID version to 4 and variant to 1.
+ bytes[6] = (bytes[6] & 0x0f) | 0x40;
+ bytes[8] = (bytes[8] & 0x3f) | 0x80;
+
+ let buf = [
+ HEX_CHARS[(bytes[0] >> 4) as usize],
+ HEX_CHARS[(bytes[0] & 0x0f) as usize],
+ HEX_CHARS[(bytes[1] >> 4) as usize],
+ HEX_CHARS[(bytes[1] & 0x0f) as usize],
+ HEX_CHARS[(bytes[2] >> 4) as usize],
+ HEX_CHARS[(bytes[2] & 0x0f) as usize],
+ HEX_CHARS[(bytes[3] >> 4) as usize],
+ HEX_CHARS[(bytes[3] & 0x0f) as usize],
+ b'-',
+ HEX_CHARS[(bytes[4] >> 4) as usize],
+ HEX_CHARS[(bytes[4] & 0x0f) as usize],
+ HEX_CHARS[(bytes[5] >> 4) as usize],
+ HEX_CHARS[(bytes[5] & 0x0f) as usize],
+ b'-',
+ HEX_CHARS[(bytes[6] >> 4) as usize],
+ HEX_CHARS[(bytes[6] & 0x0f) as usize],
+ HEX_CHARS[(bytes[7] >> 4) as usize],
+ HEX_CHARS[(bytes[7] & 0x0f) as usize],
+ b'-',
+ HEX_CHARS[(bytes[8] >> 4) as usize],
+ HEX_CHARS[(bytes[8] & 0x0f) as usize],
+ HEX_CHARS[(bytes[9] >> 4) as usize],
+ HEX_CHARS[(bytes[9] & 0x0f) as usize],
+ b'-',
+ HEX_CHARS[(bytes[10] >> 4) as usize],
+ HEX_CHARS[(bytes[10] & 0x0f) as usize],
+ HEX_CHARS[(bytes[11] >> 4) as usize],
+ HEX_CHARS[(bytes[11] & 0x0f) as usize],
+ HEX_CHARS[(bytes[12] >> 4) as usize],
+ HEX_CHARS[(bytes[12] & 0x0f) as usize],
+ HEX_CHARS[(bytes[13] >> 4) as usize],
+ HEX_CHARS[(bytes[13] & 0x0f) as usize],
+ HEX_CHARS[(bytes[14] >> 4) as usize],
+ HEX_CHARS[(bytes[14] & 0x0f) as usize],
+ HEX_CHARS[(bytes[15] >> 4) as usize],
+ HEX_CHARS[(bytes[15] & 0x0f) as usize],
+ ];
+
+ // Safety: the buffer is all valid UTF-8.
+ unsafe { String::from_utf8_unchecked(buf.to_vec()) }
+}
+
+#[test]
+fn test_fast_uuid_v4_correctness() {
+ let mut rng = thread_rng();
+ let mut bytes = [0u8; 16];
+ rng.fill(&mut bytes);
+ let uuid = fast_uuid_v4(&mut bytes.clone());
+ let uuid_lib = uuid::Builder::from_bytes(bytes)
+ .set_variant(uuid::Variant::RFC4122)
+ .set_version(uuid::Version::Random)
+ .as_uuid()
+ .to_string();
+ assert_eq!(uuid, uuid_lib);
+}