Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
1a443fe
Add Ethereum-compatible aliases for BLS12-381
Jim8y Sep 22, 2025
67b0fbb
Format codebase
Jim8y Sep 22, 2025
7f3fe50
Merge branch 'dev' into feature/bls12-eth-aliases
ajara87 Sep 25, 2025
dc9b374
Merge branch 'dev' into feature/bls12-eth-aliases
Jim8y Oct 14, 2025
1f82a9b
Implement BLS12-381 multi exponentiation
Jim8y Oct 17, 2025
be21a84
Merge branch 'dev' into feature/bls12-eth-aliases
shargon Oct 18, 2025
3f69ba9
Merge branch 'dev' into feature/bls12-eth-aliases
shargon Oct 20, 2025
9607bd7
Update src/Neo/SmartContract/Native/CryptoLib.BLS12_381.cs
shargon Oct 20, 2025
b6fb04b
Merge branch 'dev' into feature/bls12-eth-aliases
Jim8y Oct 23, 2025
5f4dbe5
Harden BLS12-381 multi exponentiation
Jim8y Oct 23, 2025
2e8378c
Merge branch 'dev' into feature/bls12-eth-aliases
cschuchardt88 Oct 23, 2025
434c62e
Merge branch 'dev' into feature/bls12-eth-aliases
shargon Oct 23, 2025
dc23a56
Add subgroup validation tests for BLS multi exp
Jim8y Nov 4, 2025
bcabd4e
Merge origin/dev into feature/bls12-eth-aliases
Jim8y Nov 4, 2025
5b40385
Fix BLS12-381 multiexp endianness and add Ethereum tests
Jim8y Nov 6, 2025
15cb14b
Document bls12381MultiExp scalar encoding
Jim8y Nov 6, 2025
a39ed8e
Revert "Document bls12381MultiExp scalar encoding"
Jim8y Nov 6, 2025
7fa60b7
Validate pairing inputs for BLS12-381
Jim8y Nov 6, 2025
a49a6b7
Merge branch 'dev' into feature/bls12-eth-aliases
Jim8y Nov 8, 2025
7d468ce
Add EVM-compatible BLS12 alias entrypoints
Jim8y Nov 10, 2025
df66f45
Add EIP-2537 serialize helpers and boundary tests
Jim8y Nov 20, 2025
93713e8
Add edge-case coverage for eth BLS serialize/deserialize
Jim8y Nov 20, 2025
8dedeed
Tweak assertion message
Jim8y Nov 20, 2025
f2c75e6
Update tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs
shargon Nov 27, 2025
421bc93
Update tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs
shargon Nov 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/Neo/SmartContract/Native/CryptoLib.BLS12_381.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,14 @@ public static InteropInterface Bls12381Add(InteropInterface x, InteropInterface
};
}

[ContractMethod(Hardfork.HF_Gorgon, CpuFee = 1 << 19, Name = "bls12_g1add")]
public static InteropInterface Bls12G1Add(InteropInterface x, InteropInterface y)
=> Bls12381Add(x, y);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adds Ethereum-compatible aliases

CryptoLib calls won't be compatible with Ethereum anyway, so I don't think this PR can be accepted. It adds an ambiguity to the CryptoLib interface.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, the same thing (if we really care about specific names which is questionable to me since it's about N3 contracts, they're different from EVM/Solidity contracts anyway) can be provided by devpack without contract modifications (and code/manifest bloat).


[ContractMethod(Hardfork.HF_Gorgon, CpuFee = 1 << 19, Name = "bls12_g2add")]
public static InteropInterface Bls12G2Add(InteropInterface x, InteropInterface y)
=> Bls12381Add(x, y);

/// <summary>
/// Mul operation of gt point and multiplier
/// </summary>
Expand All @@ -119,6 +127,14 @@ public static InteropInterface Bls12381Mul(InteropInterface x, byte[] mul, bool
};
}

[ContractMethod(Hardfork.HF_Gorgon, CpuFee = 1 << 21, Name = "bls12_g1mul")]
public static InteropInterface Bls12G1Mul(InteropInterface x, byte[] mul, bool neg)
=> Bls12381Mul(x, mul, neg);

[ContractMethod(Hardfork.HF_Gorgon, CpuFee = 1 << 21, Name = "bls12_g2mul")]
public static InteropInterface Bls12G2Mul(InteropInterface x, byte[] mul, bool neg)
=> Bls12381Mul(x, mul, neg);

/// <summary>
/// Pairing operation of g1 and g2
/// </summary>
Expand All @@ -142,5 +158,9 @@ public static InteropInterface Bls12381Pairing(InteropInterface g1, InteropInter
};
return new(Bls12.Pairing(in g1a, in g2a));
}

[ContractMethod(Hardfork.HF_Gorgon, CpuFee = 1 << 23, Name = "bls12_pairing")]
public static InteropInterface Bls12Pairing(InteropInterface g1, InteropInterface g2)
=> Bls12381Pairing(g1, g2);
}
}
85 changes: 85 additions & 0 deletions tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
using Neo.Ledger;
using Neo.Network.P2P;
using Neo.Network.P2P.Payloads;
using Neo.Persistence;
using Neo.SmartContract;
using Neo.SmartContract.Native;
using Neo.VM;
Expand Down Expand Up @@ -263,6 +264,33 @@ public void TestBls12381Pairing()
Assert.AreEqual(expected.ToLower(), result.GetInterface<Gt>().ToArray().ToHexString());
}

[TestMethod]
public void TestBls12AddAliases()
{
var expected = InvokeBlsAddMethod("bls12381Add");
foreach (var alias in new[] { "bls12_g1add", "bls12_g2add" })
{
CollectionAssert.AreEqual(expected, InvokeBlsAddMethod(alias));
}
}

[TestMethod]
public void TestBls12MulAliases()
{
var expected = InvokeBlsMulMethod("bls12381Mul", false);
foreach (var alias in new[] { "bls12_g1mul", "bls12_g2mul" })
{
CollectionAssert.AreEqual(expected, InvokeBlsMulMethod(alias, false));
}
}

[TestMethod]
public void TestBls12PairingAlias()
{
var expected = InvokeBlsPairingMethod("bls12381Pairing");
CollectionAssert.AreEqual(expected, InvokeBlsPairingMethod("bls12_pairing"));
}

[TestMethod]
public void Bls12381Equal()
{
Expand Down Expand Up @@ -1174,5 +1202,62 @@ private bool CallVerifyWithEd25519(byte[] message, byte[] publicKey, byte[] sign
return engine.ResultStack.Pop().GetBoolean();
}
}

private byte[] InvokeBlsAddMethod(string methodName)
{
var snapshotCache = TestBlockchain.GetTestSnapshotCache();
using ScriptBuilder script = new();
script.EmitDynamicCall(NativeContract.CryptoLib.Hash, "bls12381Deserialize", gt);
script.EmitDynamicCall(NativeContract.CryptoLib.Hash, "bls12381Deserialize", gt);
script.EmitPush(2);
script.Emit(OpCode.PACK);
script.EmitPush(CallFlags.All);
script.EmitPush(methodName);
script.EmitPush(NativeContract.CryptoLib.Hash);
script.EmitSysCall(ApplicationEngine.System_Contract_Call);
return ExecuteBlsScript(script, snapshotCache);
}

private byte[] InvokeBlsMulMethod(string methodName, bool neg)
{
var snapshotCache = TestBlockchain.GetTestSnapshotCache();
using ScriptBuilder script = new();
byte[] data = new byte[32];
data[0] = 0x03;
script.EmitPush(neg);
script.EmitPush(data);
script.EmitDynamicCall(NativeContract.CryptoLib.Hash, "bls12381Deserialize", gt);
script.EmitPush(3);
script.Emit(OpCode.PACK);
script.EmitPush(CallFlags.All);
script.EmitPush(methodName);
script.EmitPush(NativeContract.CryptoLib.Hash);
script.EmitSysCall(ApplicationEngine.System_Contract_Call);
return ExecuteBlsScript(script, snapshotCache);
}

private byte[] InvokeBlsPairingMethod(string methodName)
{
var snapshotCache = TestBlockchain.GetTestSnapshotCache();
using ScriptBuilder script = new();
script.EmitDynamicCall(NativeContract.CryptoLib.Hash, "bls12381Deserialize", g2);
script.EmitDynamicCall(NativeContract.CryptoLib.Hash, "bls12381Deserialize", g1);
script.EmitPush(2);
script.Emit(OpCode.PACK);
script.EmitPush(CallFlags.All);
script.EmitPush(methodName);
script.EmitPush(NativeContract.CryptoLib.Hash);
script.EmitSysCall(ApplicationEngine.System_Contract_Call);
return ExecuteBlsScript(script, snapshotCache);
}

private byte[] ExecuteBlsScript(ScriptBuilder script, StoreCache snapshotCache)
{
using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache,
settings: TestProtocolSettings.Default);
engine.LoadScript(script.ToArray());
Assert.AreEqual(VMState.HALT, engine.Execute());
return engine.ResultStack.Pop().GetInterface<Gt>().ToArray();
}
}
}
Loading
Loading