diff --git a/docs/native-contracts-api.md b/docs/native-contracts-api.md
index d89d261bf3..38e7fc436e 100644
--- a/docs/native-contracts-api.md
+++ b/docs/native-contracts-api.md
@@ -78,6 +78,7 @@ When calling a native contract method by transaction script, there are several t
 | bls12381Equal | Determines whether the specified points are equal. | InteropInterface(*x*), InteropInterface(*y*) | Boolean | 1<<5 | 0 | -- | -- |
 | bls12381Add | Add operation of two points. | InteropInterface(*x*), InteropInterface(*y*) | InteropInterface | 1<<19 | 0 | -- | -- |
 | bls12381Mul | Mul operation of gt point and multiplier | InteropInterface(*x*), Byte[](*mul*), Boolean(*neg*) | InteropInterface | 1<<21 | 0 | -- | -- |
+| bls12381MultiExp | Multi exponentiation operation for bls12381 points. | Array(*pairs*) | InteropInterface | 1<<23 | 0 | -- | HF_Faun |
 | bls12381Pairing | Pairing operation of g1 and g2 | InteropInterface(*g1*), InteropInterface(*g2*) | InteropInterface | 1<<23 | 0 | -- | -- |
 | recoverSecp256K1 | Recovers the public key from a secp256k1 signature in a single byte array format. | Byte[](*messageHash*), Byte[](*signature*) | Byte[] | 1<<15 | 0 | -- | HF_Echidna |
 | ripemd160 | Computes the hash value for the specified byte array using the ripemd160 algorithm. | Byte[](*data*) | Byte[] | 1<<15 | 0 | -- | -- |
diff --git a/src/Neo/SmartContract/Native/CryptoLib.BLS12_381.cs b/src/Neo/SmartContract/Native/CryptoLib.BLS12_381.cs
index 51ef7f6b90..299a4dd3a6 100644
--- a/src/Neo/SmartContract/Native/CryptoLib.BLS12_381.cs
+++ b/src/Neo/SmartContract/Native/CryptoLib.BLS12_381.cs
@@ -12,11 +12,15 @@
 using Neo.Cryptography.BLS12_381;
 using Neo.VM.Types;
 using System;
+using Array = Neo.VM.Types.Array;
+using VMBuffer = Neo.VM.Types.Buffer;
 
 namespace Neo.SmartContract.Native
 {
     partial class CryptoLib
     {
+        private const int Bls12381MultiExpMaxPairs = 128;
+
         /// 
         /// Serialize a bls12381 point.
         /// 
@@ -119,6 +123,83 @@ public static InteropInterface Bls12381Mul(InteropInterface x, byte[] mul, bool
             };
         }
 
+        /// 
+        /// Multi exponentiation operation for bls12381 points.
+        /// 
+        /// Array of [point, scalar] pairs.
+        /// The accumulated point.
+        [ContractMethod(Hardfork.HF_Faun, CpuFee = 1 << 23)]
+        public static InteropInterface Bls12381MultiExp(Array pairs)
+        {
+            if (pairs is null || pairs.Count == 0)
+                throw new ArgumentException("BLS12-381 multi exponent requires at least one pair");
+            if (pairs.Count > Bls12381MultiExpMaxPairs)
+                throw new ArgumentOutOfRangeException(nameof(pairs), $"BLS12-381 multi exponent supports at most {Bls12381MultiExpMaxPairs} pairs");
+
+            bool? useG2 = null;
+            G1Projective g1Accumulator = G1Projective.Identity;
+            G2Projective g2Accumulator = G2Projective.Identity;
+
+            foreach (StackItem item in pairs)
+            {
+                if (item is not Array pair || pair.Count != 2)
+                    throw new ArgumentException("BLS12-381 multi exponent pair must contain point and scalar");
+
+                if (pair[0] is not InteropInterface pointInterface)
+                    throw new ArgumentException("BLS12-381 multi exponent requires interop points");
+
+                var point = pointInterface.GetInterface