From a57f39eafeb020e1144cd367956a96c3a6d77513 Mon Sep 17 00:00:00 2001 From: gldeng Date: Wed, 4 Sep 2024 18:12:51 +0800 Subject: [PATCH] feat(zkp): Add methods required for supporting zkp verification over Bn254 --- .../Validators/Method/ArrayValidator.cs | 3 +- .../AElf.Sdk.CSharp.Internal.csproj | 10 ++- .../InternalBuiltIns.cs | 36 +++++++++++ src/AElf.Sdk.CSharp.Spec/IBuiltIns.cs | 4 ++ .../CSharpSmartContractContext.cs | 55 ++++++++++++----- src/AElf.Types/Types/BigIntValue.cs | 61 ++++++++++++++++++- 6 files changed, 150 insertions(+), 19 deletions(-) diff --git a/src/AElf.CSharp.CodeOps/Validators/Method/ArrayValidator.cs b/src/AElf.CSharp.CodeOps/Validators/Method/ArrayValidator.cs index 5a58387f14..08fced5f36 100644 --- a/src/AElf.CSharp.CodeOps/Validators/Method/ArrayValidator.cs +++ b/src/AElf.CSharp.CodeOps/Validators/Method/ArrayValidator.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading; using AElf.CSharp.Core; +using AElf.Types; using Mono.Cecil; using Mono.Cecil.Cil; using Volo.Abp.DependencyInjection; @@ -24,7 +25,7 @@ public class ArrayValidator : IValidator, ITransientDependency .LimitByTotalSize(typeof(decimal), sizeof(decimal)) .LimitByTotalSize(typeof(char), sizeof(char)) .LimitByTotalSize(typeof(String), 128) // Need to limit the size of strings by disallowing String.Concat - + .LimitByTotalSize(typeof(BigIntValue), 128) // It isn't possible to estimate runtime sizes for below, so limit by count .LimitByCount(typeof(Type), 5) .LimitByCount(typeof(Object), 5) // Support object in Linq queries diff --git a/src/AElf.Sdk.CSharp.Internal/AElf.Sdk.CSharp.Internal.csproj b/src/AElf.Sdk.CSharp.Internal/AElf.Sdk.CSharp.Internal.csproj index 7557797899..7f5bd490af 100644 --- a/src/AElf.Sdk.CSharp.Internal/AElf.Sdk.CSharp.Internal.csproj +++ b/src/AElf.Sdk.CSharp.Internal/AElf.Sdk.CSharp.Internal.csproj @@ -10,13 +10,19 @@ - + + all + + + all + + all - + diff --git a/src/AElf.Sdk.CSharp.Internal/InternalBuiltIns.cs b/src/AElf.Sdk.CSharp.Internal/InternalBuiltIns.cs index 990e0f49ce..0d61e255b8 100644 --- a/src/AElf.Sdk.CSharp.Internal/InternalBuiltIns.cs +++ b/src/AElf.Sdk.CSharp.Internal/InternalBuiltIns.cs @@ -1,5 +1,7 @@ using System; using AElf.Sdk.CSharp.Spec; +using Bn254.Net; +using Nethereum.Util; namespace AElf.Sdk.CSharp.Internal; @@ -9,6 +11,7 @@ public static void Initialize() { // call this method to ensure this assembly is loaded in the runtime. } + public bool Ed25519Verify(byte[] signature, byte[] message, byte[] publicKey) { try @@ -22,4 +25,37 @@ public bool Ed25519Verify(byte[] signature, byte[] message, byte[] publicKey) return false; } } + + public byte[] Keccak256(byte[] message) + { + return Sha3Keccack.Current.CalculateHash(message); + } + + public (byte[] x, byte[] y) Bn254G1Mul(byte[] x1, byte[] y1, byte[] s) + { + var (xUInt256, yUInt256) = Bn254.Net.Bn254.Mul(UInt256.FromBigEndianBytes(x1), UInt256.FromBigEndianBytes(y1), + UInt256.FromBigEndianBytes(s)); + return (xUInt256.ToBigEndianBytes(), yUInt256.ToBigEndianBytes()); + } + + public (byte[] x3, byte[] y3) Bn254G1Add(byte[] x1, byte[] y1, byte[] x2, byte[] y2) + { + var (x3UInt256, y3UInt256) = Bn254.Net.Bn254.Add(UInt256.FromBigEndianBytes(x1), UInt256.FromBigEndianBytes(y1), + UInt256.FromBigEndianBytes(x2), UInt256.FromBigEndianBytes(y2)); + return (x3UInt256.ToBigEndianBytes(), y3UInt256.ToBigEndianBytes()); + } + + public bool Bn254Pairing((byte[], byte[], byte[], byte[], byte[], byte[])[] input) + { + var elements = new (UInt256, UInt256, UInt256, UInt256, UInt256, UInt256)[input.Length]; + for (var i = 0; i < input.Length; i++) + { + var (x1, y1, x2, y2, x3, y3) = input[i]; + elements[i] = (UInt256.FromBigEndianBytes(x1), UInt256.FromBigEndianBytes(y1), + UInt256.FromBigEndianBytes(x2), UInt256.FromBigEndianBytes(y2), + UInt256.FromBigEndianBytes(x3), UInt256.FromBigEndianBytes(y3)); + } + + return Bn254.Net.Bn254.Pairing(elements); + } } \ No newline at end of file diff --git a/src/AElf.Sdk.CSharp.Spec/IBuiltIns.cs b/src/AElf.Sdk.CSharp.Spec/IBuiltIns.cs index bb4a5a7de2..f19de71ebe 100644 --- a/src/AElf.Sdk.CSharp.Spec/IBuiltIns.cs +++ b/src/AElf.Sdk.CSharp.Spec/IBuiltIns.cs @@ -3,4 +3,8 @@ public interface IBuiltIns { bool Ed25519Verify(byte[] signature, byte[] message, byte[] publicKey); + byte[] Keccak256(byte[] message); + (byte[] x, byte[] y) Bn254G1Mul(byte[] x1, byte[] y1, byte[] s); + (byte[] x3, byte[] y3) Bn254G1Add(byte[] x1, byte[] y1, byte[] x2, byte[] y2); + bool Bn254Pairing((byte[], byte[], byte[], byte[], byte[], byte[])[] input); } \ No newline at end of file diff --git a/src/AElf.Sdk.CSharp/CSharpSmartContractContext.cs b/src/AElf.Sdk.CSharp/CSharpSmartContractContext.cs index 96eeae7eac..146c0ba31c 100644 --- a/src/AElf.Sdk.CSharp/CSharpSmartContractContext.cs +++ b/src/AElf.Sdk.CSharp/CSharpSmartContractContext.cs @@ -17,7 +17,7 @@ namespace AElf.Sdk.CSharp; public class CSharpSmartContractContext : ISmartContractBridgeContext, IBuiltIns { private IBuiltIns BuiltInsImplementation { get; } - + public CSharpSmartContractContext(ISmartContractBridgeContext smartContractBridgeContextImplementation) { SmartContractBridgeContextImplementation = smartContractBridgeContextImplementation; @@ -90,7 +90,7 @@ public void FireLogEvent(LogEvent logEvent) /// The height of the block that contains the transaction before charging. /// public Transaction Transaction => SmartContractBridgeContextImplementation.Transaction; - + /// /// The time included in the current blocks header. /// @@ -153,7 +153,7 @@ public void DeployContract(Address address, SmartContractRegistration registrati { SmartContractBridgeContextImplementation.DeployContract(address, registration, name); } - + /// /// Update a smart contract (only the genesis contract can call it). /// @@ -164,17 +164,21 @@ public void UpdateContract(Address address, SmartContractRegistration registrati { SmartContractBridgeContextImplementation.UpdateContract(address, registration, name); } - + public ContractInfoDto DeploySmartContract(Address address, SmartContractRegistration registration, Hash name) { - return SmartContractBridgeContextImplementation.DeploySmartContract(address,registration,name); + return SmartContractBridgeContextImplementation.DeploySmartContract(address, registration, name); } - public ContractInfoDto UpdateSmartContract(Address address, SmartContractRegistration registration, Hash name,string previousContractVersion) + + public ContractInfoDto UpdateSmartContract(Address address, SmartContractRegistration registration, Hash name, + string previousContractVersion) { - return SmartContractBridgeContextImplementation.UpdateSmartContract(address,registration,name,previousContractVersion); + return SmartContractBridgeContextImplementation.UpdateSmartContract(address, registration, name, + previousContractVersion); } - public ContractVersionCheckDto CheckContractVersion(string previousContractVersion, SmartContractRegistration registration) + public ContractVersionCheckDto CheckContractVersion(string previousContractVersion, + SmartContractRegistration registration) { return SmartContractBridgeContextImplementation.CheckContractVersion(previousContractVersion, registration); } @@ -226,13 +230,14 @@ public void SendVirtualInline(Hash fromVirtualAddress, Address toAddress, string SmartContractBridgeContextImplementation.SendVirtualInline(fromVirtualAddress, toAddress, methodName, args); } - - public void SendVirtualInline(Hash fromVirtualAddress, Address toAddress, string methodName, ByteString args,bool logTransaction) + + public void SendVirtualInline(Hash fromVirtualAddress, Address toAddress, string methodName, ByteString args, + bool logTransaction) { SmartContractBridgeContextImplementation.SendVirtualInline(fromVirtualAddress, toAddress, methodName, - args,logTransaction); + args, logTransaction); } - + /// /// Sends a virtual inline transaction to another contract. This method is only available to system smart contract. @@ -250,7 +255,7 @@ public void SendVirtualInlineBySystemContract(Hash fromVirtualAddress, Address t SmartContractBridgeContextImplementation.SendVirtualInlineBySystemContract(fromVirtualAddress, toAddress, methodName, args); } - + public void SendVirtualInlineBySystemContract(Hash fromVirtualAddress, Address toAddress, string methodName, ByteString args, bool logTransaction) { @@ -391,14 +396,34 @@ public Address ConvertVirtualAddressToContractAddressWithContractHashName(Hash v return SmartContractBridgeContextImplementation.ConvertVirtualAddressToContractAddressWithContractHashName( virtualAddress); } - + public bool ECVrfVerify(byte[] pubKey, byte[] alpha, byte[] pi, out byte[] beta) { return SmartContractBridgeContextImplementation.ECVrfVerify(pubKey, alpha, pi, out beta); } - + public bool Ed25519Verify(byte[] signature, byte[] message, byte[] publicKey) { return BuiltInsImplementation.Ed25519Verify(signature, message, publicKey); } + + public byte[] Keccak256(byte[] message) + { + return BuiltInsImplementation.Keccak256(message); + } + + public (byte[] x, byte[] y) Bn254G1Mul(byte[] x1, byte[] y1, byte[] s) + { + return BuiltInsImplementation.Bn254G1Mul(x1, y1, s); + } + + public (byte[] x3, byte[] y3) Bn254G1Add(byte[] x1, byte[] y1, byte[] x2, byte[] y2) + { + return BuiltInsImplementation.Bn254G1Add(x1, y1, x2, y2); + } + + public bool Bn254Pairing((byte[], byte[], byte[], byte[], byte[], byte[])[] input) + { + return BuiltInsImplementation.Bn254Pairing(input); + } } \ No newline at end of file diff --git a/src/AElf.Types/Types/BigIntValue.cs b/src/AElf.Types/Types/BigIntValue.cs index 38ddc94df6..f65c8897a3 100644 --- a/src/AElf.Types/Types/BigIntValue.cs +++ b/src/AElf.Types/Types/BigIntValue.cs @@ -5,9 +5,30 @@ namespace AElf.Types { - public partial class BigIntValue : IComparable, IComparable { + #region Frequent Values + + public static BigIntValue Zero => new BigIntValue { Value = "0" }; + public static BigIntValue One => new BigIntValue { Value = "1" }; + + #endregion + + public static BigIntValue FromBigEndianBytes(byte[] bigEndianBytes) + { + var bigInteger = new BigInteger(bigEndianBytes, true, true); + return new BigIntValue + { + Value = bigInteger.ToString() + }; + } + + public byte[] ToBigEndianBytes() + { + var bigInteger = ConvertStringToBigInteger(Value); + return bigInteger.ToByteArray(true, true); + } + public int CompareTo(object obj) { if (!(obj is BigIntValue bigInt)) throw new InvalidOperationException(); @@ -126,6 +147,43 @@ private static bool LessThan(in BigIntValue a, in BigIntValue b) return aBigInt < bBigInt; } + #region Operators + + public static BigIntValue operator %(BigIntValue a, BigIntValue b) + { + return BigInteger.Remainder(ConvertStringToBigInteger(a.Value), ConvertStringToBigInteger(b.Value)) + .ToString(); + } + + public static BigIntValue operator +(BigIntValue a, BigIntValue b) + { + return BigInteger.Add(ConvertStringToBigInteger(a.Value), ConvertStringToBigInteger(b.Value)).ToString(); + } + + public static BigIntValue operator -(BigIntValue a, BigIntValue b) + { + return BigInteger.Subtract(ConvertStringToBigInteger(a.Value), ConvertStringToBigInteger(b.Value)) + .ToString(); + } + + public static BigIntValue operator *(BigIntValue a, BigIntValue b) + { + return BigInteger.Multiply(ConvertStringToBigInteger(a.Value), ConvertStringToBigInteger(b.Value)) + .ToString(); + } + + public static bool operator ==(BigIntValue a, BigIntValue b) + { + return ConvertStringToBigInteger(a?.Value ?? "0") == ConvertStringToBigInteger(b?.Value ?? "0"); + } + + public static bool operator !=(BigIntValue a, BigIntValue b) + { + return !(a == b); + } + + #endregion + #region < <= > >= public static bool operator <(in BigIntValue a, in BigIntValue b) @@ -149,5 +207,6 @@ private static bool LessThan(in BigIntValue a, in BigIntValue b) } #endregion + } } \ No newline at end of file