diff --git a/compiler_base/3rdparty/rustc_span/Cargo.toml b/compiler_base/3rdparty/rustc_span/Cargo.toml index e7aabaad8..f4108550f 100644 --- a/compiler_base/3rdparty/rustc_span/Cargo.toml +++ b/compiler_base/3rdparty/rustc_span/Cargo.toml @@ -22,4 +22,5 @@ cfg-if = "0.1.2" tracing = "0.1" sha1 = { package = "sha-1", version = "0.10.0" } sha2 = "0.10.1" -md5 = { package = "md-5", version = "0.10.0" } \ No newline at end of file +md5 = { package = "md-5", version = "0.10.0" } +blake3 = "1.5.4" \ No newline at end of file diff --git a/compiler_base/3rdparty/rustc_span/src/lib.rs b/compiler_base/3rdparty/rustc_span/src/lib.rs index 548bafb36..e3ee8193a 100644 --- a/compiler_base/3rdparty/rustc_span/src/lib.rs +++ b/compiler_base/3rdparty/rustc_span/src/lib.rs @@ -36,6 +36,7 @@ use std::rc::Rc; use std::str::FromStr; use md5::Digest; +use blake3::Hash as Blake3; use md5::Md5; use sha1::Sha1; use sha2::Sha256; @@ -602,6 +603,7 @@ pub enum SourceFileHashAlgorithm { Md5, Sha1, Sha256, + Blake3, } impl FromStr for SourceFileHashAlgorithm { @@ -612,6 +614,7 @@ impl FromStr for SourceFileHashAlgorithm { "md5" => Ok(SourceFileHashAlgorithm::Md5), "sha1" => Ok(SourceFileHashAlgorithm::Sha1), "sha256" => Ok(SourceFileHashAlgorithm::Sha256), + "blake3" => Ok(SourceFileHashAlgorithm::Blake3), _ => Err(()), } } @@ -643,6 +646,12 @@ impl SourceFileHash { SourceFileHashAlgorithm::Sha256 => { value.copy_from_slice(&Sha256::digest(data)); } + SourceFileHashAlgorithm::Blake3 => { + let mut hasher = Blake3::new(); + hasher.update(data); + let result = hasher.finalize(); + value.copy_from_slice(result.as_bytes()); + } } hash } @@ -663,6 +672,7 @@ impl SourceFileHash { SourceFileHashAlgorithm::Md5 => 16, SourceFileHashAlgorithm::Sha1 => 20, SourceFileHashAlgorithm::Sha256 => 32, + SourceFileHashAlgorithm::Blake3 => 32, } } } diff --git a/kclvm/Cargo.lock b/kclvm/Cargo.lock index 581f2a5c3..14242249e 100644 --- a/kclvm/Cargo.lock +++ b/kclvm/Cargo.lock @@ -135,6 +135,12 @@ dependencies = [ "backtrace", ] +[[package]] +name = "arrayref" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" + [[package]] name = "arrayvec" version = "0.7.4" @@ -238,6 +244,19 @@ dependencies = [ "typenum", ] +[[package]] +name = "blake3" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if 1.0.0", + "constant_time_eq", +] + [[package]] name = "block-buffer" version = "0.7.3" @@ -320,9 +339,12 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.1.6" +version = "1.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" +checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -473,6 +495,12 @@ version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "373e9fafaa20882876db20562275ff58d50e0caa2590077fe7ce7bef90211d0d" +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + [[package]] name = "core-foundation-sys" version = "0.8.6" @@ -1980,6 +2008,7 @@ dependencies = [ "ahash", "anyhow", "base64 0.13.1", + "blake3", "bstr", "chrono", "fancy-regex", @@ -3693,6 +3722,12 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.2" diff --git a/kclvm/runtime/Cargo.toml b/kclvm/runtime/Cargo.toml index e5c8d7e36..6c7ee47c5 100644 --- a/kclvm/runtime/Cargo.toml +++ b/kclvm/runtime/Cargo.toml @@ -21,6 +21,7 @@ regex = "1.5.5" md5 = "0.7.0" sha2 = "0.9.8" sha1 = "0.6.0" +blake3 = "1.5.4" chrono = "0.4.19" ahash = "0.7.2" indexmap = "1.0" diff --git a/kclvm/runtime/src/_kclvm.h b/kclvm/runtime/src/_kclvm.h index 9a4b2f0fd..8b2caff69 100644 --- a/kclvm/runtime/src/_kclvm.h +++ b/kclvm/runtime/src/_kclvm.h @@ -239,6 +239,8 @@ kclvm_value_ref_t* kclvm_crypto_sha384(kclvm_context_t* ctx, kclvm_value_ref_t* kclvm_value_ref_t* kclvm_crypto_sha512(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +kclvm_value_ref_t* kclvm_crypto_blake3(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); + kclvm_value_ref_t* kclvm_crypto_uuid(kclvm_context_t* ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); kclvm_value_ref_t* kclvm_datetime_date(kclvm_context_t* ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); diff --git a/kclvm/runtime/src/_kclvm.rs b/kclvm/runtime/src/_kclvm.rs index cdf5373c7..cc9cdd721 100644 --- a/kclvm/runtime/src/_kclvm.rs +++ b/kclvm/runtime/src/_kclvm.rs @@ -112,6 +112,7 @@ pub enum ApiFunc { kclvm_crypto_sha256, kclvm_crypto_sha384, kclvm_crypto_sha512, + kclvm_crypto_blake3, kclvm_crypto_uuid, kclvm_datetime_date, kclvm_datetime_now, diff --git a/kclvm/runtime/src/_kclvm_addr.rs b/kclvm/runtime/src/_kclvm_addr.rs index ec6aec4f0..81794a939 100644 --- a/kclvm/runtime/src/_kclvm_addr.rs +++ b/kclvm/runtime/src/_kclvm_addr.rs @@ -113,6 +113,7 @@ pub fn _kclvm_get_fn_ptr_by_name(name: &str) -> u64 { "kclvm_crypto_sha256" => crate::kclvm_crypto_sha256 as *const () as u64, "kclvm_crypto_sha384" => crate::kclvm_crypto_sha384 as *const () as u64, "kclvm_crypto_sha512" => crate::kclvm_crypto_sha512 as *const () as u64, + "kclvm_crypto_blake3" => crate::kclvm_crypto_blake3 as *const () as u64, "kclvm_crypto_uuid" => crate::kclvm_crypto_uuid as *const () as u64, "kclvm_datetime_date" => crate::kclvm_datetime_date as *const () as u64, "kclvm_datetime_now" => crate::kclvm_datetime_now as *const () as u64, diff --git a/kclvm/runtime/src/_kclvm_api_spec.rs b/kclvm/runtime/src/_kclvm_api_spec.rs index a0d97b5f7..53c63f753 100644 --- a/kclvm/runtime/src/_kclvm_api_spec.rs +++ b/kclvm/runtime/src/_kclvm_api_spec.rs @@ -794,6 +794,10 @@ // api-spec(c): kclvm_value_ref_t* kclvm_crypto_sha512(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); // api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_crypto_sha512(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); +/// api-spec: kclvm_crypto_blake3 +/// api-spec(c): kclvm_value_ref_t* kclvm_crypto_blake3(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs); +/// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_crypto_blake3(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %args, %kclvm_value_ref_t* %_kwargs); + // api-spec: kclvm_crypto_uuid // api-spec(c): kclvm_value_ref_t* kclvm_crypto_uuid(kclvm_context_t* ctx, kclvm_value_ref_t* _args, kclvm_value_ref_t* _kwargs); // api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_crypto_uuid(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %_args, %kclvm_value_ref_t* %_kwargs); diff --git a/kclvm/runtime/src/crypto/mod.rs b/kclvm/runtime/src/crypto/mod.rs index 53ad9d8bc..8e84d3c8a 100644 --- a/kclvm/runtime/src/crypto/mod.rs +++ b/kclvm/runtime/src/crypto/mod.rs @@ -1,5 +1,6 @@ //! Copyright The KCL Authors. All rights reserved. +extern crate blake3; extern crate md5; extern crate sha1; extern crate sha2; @@ -167,6 +168,34 @@ pub extern "C" fn kclvm_crypto_sha512( panic!("sha512() missing 1 required positional argument: 'value'"); } +// blake3(value: str, encoding: str = "utf-8") -> str + +#[no_mangle] +#[runtime_fn] +pub extern "C" fn kclvm_crypto_blake3( + ctx: *mut kclvm_context_t, + args: *const kclvm_value_ref_t, + _kwargs: *const kclvm_value_ref_t, +) -> *const kclvm_value_ref_t { + let args = ptr_as_ref(args); + let ctx = mut_ptr_as_ref(ctx); + if let Some(s) = args.arg_i_str(0, None) { + let mut hasher = blake3::Hasher::new(); + hasher.update(s.as_bytes()); + let result = hasher.finalize(); + + let mut hex = String::with_capacity(2 * Sha256::output_size()); + use std::fmt::Write; + + for byte in result.as_bytes() { + let _ = write!(&mut hex, "{byte:02x}"); + } + + return ValueRef::str(hex.as_ref()).into_raw(ctx); + } + panic!("blake3() missing 1 required positional argument: 'value'"); +} + #[no_mangle] #[runtime_fn] pub extern "C" fn kclvm_crypto_uuid( diff --git a/kclvm/sema/src/builtin/system_module.rs b/kclvm/sema/src/builtin/system_module.rs index 8f3562327..26de42b45 100644 --- a/kclvm/sema/src/builtin/system_module.rs +++ b/kclvm/sema/src/builtin/system_module.rs @@ -1386,6 +1386,27 @@ register_crypto_member! { false, None, ) + blake3 => Type::function( + None, + Type::str_ref(), + &[ + Parameter { + name: "value".to_string(), + ty: Type::str_ref(), + has_default: false, + range: dummy_range(), + }, + Parameter { + name: "encoding".to_string(), + ty: Type::str_ref(), + has_default: true, + range: dummy_range(), + }, + ], + r#"Encrypt the string `value` using `BLAKE3` and the codec registered for encoding."#, + false, + None, + ) uuid => Type::function( None, Type::str_ref(), diff --git a/kclvm/tests/test_units/runtime/crypto/test_crypto.py b/kclvm/tests/test_units/runtime/crypto/test_crypto.py index 46721e45d..8224964f9 100644 --- a/kclvm/tests/test_units/runtime/crypto/test_crypto.py +++ b/kclvm/tests/test_units/runtime/crypto/test_crypto.py @@ -38,6 +38,9 @@ def sha384(self, value: str) -> str: def sha512(self, value: str) -> str: return self.dylib.Invoke(f"crypto.sha512", value) + def blake3(self, value: str) -> str: + return self.dylib.Invoke(f"crypto.blake3", value) + def test_md5(self): self.assertEqual( self.md5("The quick brown fox jumps over the lazy dog"), @@ -77,6 +80,12 @@ def test_sha512(self): self.sha512(""), "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", ) + + def test_blake3(self): + self.assertEqual( + self.blake3(""), + "af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262", + ) if __name__ == "__main__": diff --git a/test/grammar/builtins/crypto/blake/blake3/main.k b/test/grammar/builtins/crypto/blake/blake3/main.k new file mode 100644 index 000000000..e8397fe26 --- /dev/null +++ b/test/grammar/builtins/crypto/blake/blake3/main.k @@ -0,0 +1,3 @@ +import crypto + +blake3 = crypto.blake3("ABCDEF") diff --git a/test/grammar/builtins/crypto/blake/blake3/stdout.golden b/test/grammar/builtins/crypto/blake/blake3/stdout.golden new file mode 100644 index 000000000..59ce547c5 --- /dev/null +++ b/test/grammar/builtins/crypto/blake/blake3/stdout.golden @@ -0,0 +1 @@ +blake3: 61c8c05f3e588c663cd9fbb1d7ad93604ed08cf335497095a020222cc9976cf1 \ No newline at end of file