2121using Neo . SmartContract ;
2222using Neo . SmartContract . Native ;
2323using Neo . VM ;
24+ using Neo . VM . Types ;
2425using Org . BouncyCastle . Utilities . Encoders ;
2526using System ;
2627using System . Collections . Generic ;
2728using System . Linq ;
29+ using System . Numerics ;
2830using System . Text ;
31+ using VMArray = Neo . VM . Types . Array ;
2932
3033namespace Neo . UnitTests . SmartContract . Native
3134{
@@ -265,30 +268,98 @@ public void TestBls12381Pairing()
265268 }
266269
267270 [ TestMethod ]
268- public void TestBls12AddAliases ( )
271+ public void TestBls12381MultiExpG1 ( )
269272 {
270- var expected = InvokeBlsAddMethod ( "bls12381Add" ) ;
271- foreach ( var alias in new [ ] { "bls12_g1add" , "bls12_g2add" } )
273+ var g1Point = G1Affine . FromCompressed ( g1 ) ;
274+ var pair1 = new VMArray ( new StackItem [ ]
272275 {
273- CollectionAssert . AreEqual ( expected , InvokeBlsAddMethod ( alias ) ) ;
274- }
276+ StackItem . FromInterface ( g1Point ) ,
277+ new ByteString ( CreateScalarBytes ( 1 ) )
278+ } ) ;
279+ var pair2 = new VMArray ( new StackItem [ ]
280+ {
281+ StackItem . FromInterface ( g1Point ) ,
282+ new ByteString ( CreateScalarBytes ( 2 ) )
283+ } ) ;
284+ var pairs = new VMArray ( new StackItem [ ] { pair1 , pair2 } ) ;
285+
286+ var result = CryptoLib . Bls12381MultiExp ( pairs ) ;
287+ var actual = result . GetInterface < G1Projective > ( ) ;
288+
289+ var expected = new G1Projective ( g1Point ) * CreateScalar ( 3 ) ;
290+ Assert . AreEqual ( new G1Affine ( expected ) . ToCompressed ( ) . ToHexString ( ) ,
291+ new G1Affine ( actual ) . ToCompressed ( ) . ToHexString ( ) ) ;
275292 }
276293
277294 [ TestMethod ]
278- public void TestBls12MulAliases ( )
295+ public void TestBls12381MultiExpG2 ( )
279296 {
280- var expected = InvokeBlsMulMethod ( "bls12381Mul" , false ) ;
281- foreach ( var alias in new [ ] { "bls12_g1mul" , "bls12_g2mul" } )
297+ var g2Point = G2Affine . FromCompressed ( g2 ) ;
298+ var pair = new VMArray ( new StackItem [ ]
282299 {
283- CollectionAssert . AreEqual ( expected , InvokeBlsMulMethod ( alias , false ) ) ;
284- }
300+ StackItem . FromInterface ( new G2Projective ( g2Point ) ) ,
301+ new ByteString ( CreateScalarBytes ( 5 ) )
302+ } ) ;
303+ var pairs = new VMArray ( new StackItem [ ] { pair } ) ;
304+
305+ var result = CryptoLib . Bls12381MultiExp ( pairs ) ;
306+ var actual = result . GetInterface < G2Projective > ( ) ;
307+
308+ var expected = new G2Projective ( g2Point ) * CreateScalar ( 5 ) ;
309+ Assert . AreEqual ( new G2Affine ( expected ) . ToCompressed ( ) . ToHexString ( ) ,
310+ new G2Affine ( actual ) . ToCompressed ( ) . ToHexString ( ) ) ;
285311 }
286312
287313 [ TestMethod ]
288- public void TestBls12PairingAlias ( )
314+ public void TestBls12381MultiExpReducesScalar ( )
289315 {
290- var expected = InvokeBlsPairingMethod ( "bls12381Pairing" ) ;
291- CollectionAssert . AreEqual ( expected , InvokeBlsPairingMethod ( "bls12_pairing" ) ) ;
316+ var g1Point = G1Affine . FromCompressed ( g1 ) ;
317+ var oversized = ( BigInteger . One << 260 ) + 5 ;
318+ var scalarBytes = CreateScalarBytes ( oversized ) ;
319+ var pair = new VMArray ( new StackItem [ ]
320+ {
321+ StackItem . FromInterface ( g1Point ) ,
322+ new ByteString ( scalarBytes )
323+ } ) ;
324+ var pairs = new VMArray ( new StackItem [ ] { pair } ) ;
325+
326+ var wide = new byte [ Scalar . Size * 2 ] ;
327+ System . Array . Copy ( scalarBytes , wide , scalarBytes . Length ) ;
328+ var reducedScalar = Scalar . FromBytesWide ( wide ) ;
329+
330+ var result = CryptoLib . Bls12381MultiExp ( pairs ) ;
331+ var actual = result . GetInterface < G1Projective > ( ) ;
332+
333+ var expected = new G1Projective ( g1Point ) * reducedScalar ;
334+ Assert . AreEqual ( new G1Affine ( expected ) . ToCompressed ( ) . ToHexString ( ) ,
335+ new G1Affine ( actual ) . ToCompressed ( ) . ToHexString ( ) ) ;
336+ }
337+
338+ [ TestMethod ]
339+ public void TestBls12381MultiExpMixedGroupFails ( )
340+ {
341+ var g1Point = G1Affine . FromCompressed ( g1 ) ;
342+ var g2Point = G2Affine . FromCompressed ( g2 ) ;
343+ var pair1 = new VMArray ( new StackItem [ ]
344+ {
345+ StackItem . FromInterface ( g1Point ) ,
346+ new ByteString ( CreateScalarBytes ( 1 ) )
347+ } ) ;
348+ var pair2 = new VMArray ( new StackItem [ ]
349+ {
350+ StackItem . FromInterface ( g2Point ) ,
351+ new ByteString ( CreateScalarBytes ( 1 ) )
352+ } ) ;
353+ var pairs = new VMArray ( new StackItem [ ] { pair1 , pair2 } ) ;
354+
355+ Assert . ThrowsExactly < ArgumentException > ( ( ) => CryptoLib . Bls12381MultiExp ( pairs ) ) ;
356+ }
357+
358+ [ TestMethod ]
359+ public void TestBls12381MultiExpEmptyFails ( )
360+ {
361+ var pairs = new VMArray ( ) ;
362+ Assert . ThrowsExactly < ArgumentException > ( ( ) => CryptoLib . Bls12381MultiExp ( pairs ) ) ;
292363 }
293364
294365 [ TestMethod ]
@@ -1153,7 +1224,7 @@ public void TestVerifyWithEd25519()
11531224 {
11541225 // byte[] privateKey = "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60".HexToBytes();
11551226 byte [ ] publicKey = "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a" . HexToBytes ( ) ;
1156- byte [ ] message = Array . Empty < byte > ( ) ;
1227+ byte [ ] message = System . Array . Empty < byte > ( ) ;
11571228 byte [ ] signature = ( "e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e06522490155" +
11581229 "5fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b" ) . HexToBytes ( ) ;
11591230
@@ -1169,13 +1240,13 @@ public void TestVerifyWithEd25519()
11691240
11701241 // Test with an invalid signature
11711242 byte [ ] invalidSignature = new byte [ signature . Length ] ;
1172- Array . Copy ( signature , invalidSignature , signature . Length ) ;
1243+ System . Array . Copy ( signature , invalidSignature , signature . Length ) ;
11731244 invalidSignature [ 0 ] ^= 0x01 ; // Flip one bit
11741245 Assert . IsFalse ( CallVerifyWithEd25519 ( message , publicKey , invalidSignature ) ) ;
11751246
11761247 // Test with an invalid public key
11771248 byte [ ] invalidPublicKey = new byte [ publicKey . Length ] ;
1178- Array . Copy ( publicKey , invalidPublicKey , publicKey . Length ) ;
1249+ System . Array . Copy ( publicKey , invalidPublicKey , publicKey . Length ) ;
11791250 invalidPublicKey [ 0 ] ^= 0x01 ; // Flip one bit
11801251 Assert . IsFalse ( CallVerifyWithEd25519 ( message , invalidPublicKey , signature ) ) ;
11811252 }
@@ -1203,61 +1274,22 @@ private bool CallVerifyWithEd25519(byte[] message, byte[] publicKey, byte[] sign
12031274 }
12041275 }
12051276
1206- private byte [ ] InvokeBlsAddMethod ( string methodName )
1277+ private static byte [ ] CreateScalarBytes ( BigInteger value )
12071278 {
1208- var snapshotCache = TestBlockchain . GetTestSnapshotCache ( ) ;
1209- using ScriptBuilder script = new ( ) ;
1210- script . EmitDynamicCall ( NativeContract . CryptoLib . Hash , "bls12381Deserialize" , gt ) ;
1211- script . EmitDynamicCall ( NativeContract . CryptoLib . Hash , "bls12381Deserialize" , gt ) ;
1212- script . EmitPush ( 2 ) ;
1213- script . Emit ( OpCode . PACK ) ;
1214- script . EmitPush ( CallFlags . All ) ;
1215- script . EmitPush ( methodName ) ;
1216- script . EmitPush ( NativeContract . CryptoLib . Hash ) ;
1217- script . EmitSysCall ( ApplicationEngine . System_Contract_Call ) ;
1218- return ExecuteBlsScript ( script , snapshotCache ) ;
1279+ if ( value < 0 )
1280+ throw new ArgumentOutOfRangeException ( nameof ( value ) ) ;
1281+
1282+ var bytes = new byte [ Scalar . Size ] ;
1283+ var mask = ( BigInteger . One << ( Scalar . Size * 8 ) ) - BigInteger . One ;
1284+ var truncated = value & mask ;
1285+ if ( ! truncated . TryWriteBytes ( bytes , out _ , isBigEndian : false ) )
1286+ throw new InvalidOperationException ( "Unable to encode scalar value." ) ;
1287+ return bytes ;
12191288 }
12201289
1221- private byte [ ] InvokeBlsMulMethod ( string methodName , bool neg )
1222- {
1223- var snapshotCache = TestBlockchain . GetTestSnapshotCache ( ) ;
1224- using ScriptBuilder script = new ( ) ;
1225- byte [ ] data = new byte [ 32 ] ;
1226- data [ 0 ] = 0x03 ;
1227- script . EmitPush ( neg ) ;
1228- script . EmitPush ( data ) ;
1229- script . EmitDynamicCall ( NativeContract . CryptoLib . Hash , "bls12381Deserialize" , gt ) ;
1230- script . EmitPush ( 3 ) ;
1231- script . Emit ( OpCode . PACK ) ;
1232- script . EmitPush ( CallFlags . All ) ;
1233- script . EmitPush ( methodName ) ;
1234- script . EmitPush ( NativeContract . CryptoLib . Hash ) ;
1235- script . EmitSysCall ( ApplicationEngine . System_Contract_Call ) ;
1236- return ExecuteBlsScript ( script , snapshotCache ) ;
1237- }
1290+ private static byte [ ] CreateScalarBytes ( uint value ) => CreateScalarBytes ( new BigInteger ( value ) ) ;
12381291
1239- private byte [ ] InvokeBlsPairingMethod ( string methodName )
1240- {
1241- var snapshotCache = TestBlockchain . GetTestSnapshotCache ( ) ;
1242- using ScriptBuilder script = new ( ) ;
1243- script . EmitDynamicCall ( NativeContract . CryptoLib . Hash , "bls12381Deserialize" , g2 ) ;
1244- script . EmitDynamicCall ( NativeContract . CryptoLib . Hash , "bls12381Deserialize" , g1 ) ;
1245- script . EmitPush ( 2 ) ;
1246- script . Emit ( OpCode . PACK ) ;
1247- script . EmitPush ( CallFlags . All ) ;
1248- script . EmitPush ( methodName ) ;
1249- script . EmitPush ( NativeContract . CryptoLib . Hash ) ;
1250- script . EmitSysCall ( ApplicationEngine . System_Contract_Call ) ;
1251- return ExecuteBlsScript ( script , snapshotCache ) ;
1252- }
1292+ private static Scalar CreateScalar ( uint value ) => Scalar . FromBytes ( CreateScalarBytes ( value ) ) ;
12531293
1254- private byte [ ] ExecuteBlsScript ( ScriptBuilder script , StoreCache snapshotCache )
1255- {
1256- using var engine = ApplicationEngine . Create ( TriggerType . Application , null , snapshotCache ,
1257- settings : TestProtocolSettings . Default ) ;
1258- engine . LoadScript ( script . ToArray ( ) ) ;
1259- Assert . AreEqual ( VMState . HALT , engine . Execute ( ) ) ;
1260- return engine . ResultStack . Pop ( ) . GetInterface < Gt > ( ) . ToArray ( ) ;
1261- }
12621294 }
12631295}
0 commit comments