From 42fd46f67fa5793480e7e9b47c9e509d00351094 Mon Sep 17 00:00:00 2001 From: Alex Forshtat Date: Fri, 30 May 2025 23:32:28 +0200 Subject: [PATCH 01/10] Fix EIP-7702 Verifier initialization --- solidity/script/DelegationExample.s.sol | 3 ++- solidity/src/ZKNOX_delegate_noproxy.sol | 5 ++++- .../ZKNOX_IVerifierDelegate_noproxy.t.sol | 19 +++++++------------ 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/solidity/script/DelegationExample.s.sol b/solidity/script/DelegationExample.s.sol index a59a370..128abd6 100644 --- a/solidity/script/DelegationExample.s.sol +++ b/solidity/script/DelegationExample.s.sol @@ -105,7 +105,8 @@ contract SignDelegationTest is BaseScript { address iVerifier_algo = address(falcon); address iPublicKey = DeployPolynomial(salty, pkc); - Verifier = new ZKNOX_Verifier(iAlgoID, iVerifier_algo, iPublicKey); + Verifier = new ZKNOX_Verifier(); + Verifier.initialize(iAlgoID, iVerifier_algo, iPublicKey); console.log("param Verifier:", Verifier.algoID(), Verifier.CoreAddress(), Verifier.authorizedPublicKey()); // Deploy an ERC-20 token contract where Alice is the minter. diff --git a/solidity/src/ZKNOX_delegate_noproxy.sol b/solidity/src/ZKNOX_delegate_noproxy.sol index 22de288..f4d81a9 100644 --- a/solidity/src/ZKNOX_delegate_noproxy.sol +++ b/solidity/src/ZKNOX_delegate_noproxy.sol @@ -53,7 +53,10 @@ contract ZKNOX_Verifier { uint256 public nonce; //input are AlgoIdentifier, Signature verification address, publickey storing contract - constructor(uint256 iAlgoID, address iCore, address iPublicKey) { + constructor() {} + + function initialize(uint256 iAlgoID, address iCore, address iPublicKey) external { + require(CoreAddress == address(0), "already initialized"); CoreAddress = iCore; // Address of contract of Signature verification (FALCON, DILITHIUM) algoID = iAlgoID; authorizedPublicKey = iPublicKey; diff --git a/solidity/test/ZKNOX_IVerifierDelegate_noproxy.t.sol b/solidity/test/ZKNOX_IVerifierDelegate_noproxy.t.sol index 2b34e60..c320505 100644 --- a/solidity/test/ZKNOX_IVerifierDelegate_noproxy.t.sol +++ b/solidity/test/ZKNOX_IVerifierDelegate_noproxy.t.sol @@ -101,9 +101,15 @@ contract SignDelegationTest is Test { address iVerifier_algo = address(falcon); address iPublicKey = DeployPolynomial(salty, pkc); - Verifier = new ZKNOX_Verifier(iAlgoID, iVerifier_algo, iPublicKey); + Verifier = new ZKNOX_Verifier(); console.log("param Verifier:", Verifier.algoID(), Verifier.CoreAddress(), Verifier.authorizedPublicKey()); + // Alice signs a delegation allowing `implementation` to execute transactions on her behalf. + Vm.SignedDelegation memory signedDelegation = vm.signDelegation(address(Verifier), ALICE_PK); + + vm.attachDelegation(signedDelegation); + ZKNOX_Verifier(ALICE_ADDRESS).initialize(iAlgoID, iVerifier_algo, iPublicKey); + // Deploy an ERC-20 token contract where Alice is the minter. token = new ERC20(ALICE_ADDRESS); } @@ -133,16 +139,6 @@ contract SignDelegationTest is Test { //calls[0] = SimpleDelegateContract.Call({to: address(token), data: data, value: 0}); vm.startBroadcast(ALICE_PK); - // Alice signs a delegation allowing `implementation` to execute transactions on her behalf. - Vm.SignedDelegation memory signedDelegation = vm.signDelegation(address(Verifier), ALICE_PK); - - // Set Alice's storage before calling Verifier - - vm.store(ALICE_ADDRESS, bytes32(uint256(0)), bytes32(uint256(uint160(Verifier.authorizedPublicKey())))); - vm.store(ALICE_ADDRESS, bytes32(uint256(1)), bytes32(uint256(uint160(Verifier.CoreAddress())))); - vm.store(ALICE_ADDRESS, bytes32(uint256(2)), bytes32(Verifier.algoID())); - vm.store(ALICE_ADDRESS, bytes32(uint256(3)), bytes32(Verifier.nonce())); - // Debug: Print stored values to verify correct setup console.log( @@ -159,7 +155,6 @@ contract SignDelegationTest is Test { vm.stopBroadcast(); vm.broadcast(BOB_PK); - vm.attachDelegation(signedDelegation); bytes memory code = address(ALICE_ADDRESS).code; //this shall be ef0100, followed by adress console.log("Verifier address:%x", uint256(uint160(address(Verifier)))); From b92a2ae426e60968df95c5c5a3a329c144bd9fa3 Mon Sep 17 00:00:00 2001 From: Alex Forshtat Date: Fri, 30 May 2025 23:35:00 +0200 Subject: [PATCH 02/10] Fix log message --- solidity/test/ZKNOX_IVerifierDelegate_noproxy.t.sol | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/solidity/test/ZKNOX_IVerifierDelegate_noproxy.t.sol b/solidity/test/ZKNOX_IVerifierDelegate_noproxy.t.sol index c320505..726d481 100644 --- a/solidity/test/ZKNOX_IVerifierDelegate_noproxy.t.sol +++ b/solidity/test/ZKNOX_IVerifierDelegate_noproxy.t.sol @@ -102,13 +102,14 @@ contract SignDelegationTest is Test { address iPublicKey = DeployPolynomial(salty, pkc); Verifier = new ZKNOX_Verifier(); - console.log("param Verifier:", Verifier.algoID(), Verifier.CoreAddress(), Verifier.authorizedPublicKey()); // Alice signs a delegation allowing `implementation` to execute transactions on her behalf. Vm.SignedDelegation memory signedDelegation = vm.signDelegation(address(Verifier), ALICE_PK); vm.attachDelegation(signedDelegation); - ZKNOX_Verifier(ALICE_ADDRESS).initialize(iAlgoID, iVerifier_algo, iPublicKey); + ZKNOX_Verifier aliceVerifier = ZKNOX_Verifier(ALICE_ADDRESS); + aliceVerifier.initialize(iAlgoID, iVerifier_algo, iPublicKey); + console.log("param Verifier:", aliceVerifier.algoID(), aliceVerifier.CoreAddress(), aliceVerifier.authorizedPublicKey()); // Deploy an ERC-20 token contract where Alice is the minter. token = new ERC20(ALICE_ADDRESS); From cf13c748af6c39dbbf7f3777532f51345b47875b Mon Sep 17 00:00:00 2001 From: renaud dubois Date: Sat, 31 May 2025 09:51:58 +0200 Subject: [PATCH 03/10] delegation validation - adding a test calling underlying verifier with valid test vector to assess delegation - nota: the transact test vector is outdated --- solidity/src/ZKNOX_delegate_noproxy.sol | 11 ++-- solidity/src/ZKNOX_hybrid.sol | 15 +++-- .../ZKNOX_IVerifierDelegate_noproxy.t.sol | 62 ++++++++++++++++++- 3 files changed, 75 insertions(+), 13 deletions(-) diff --git a/solidity/src/ZKNOX_delegate_noproxy.sol b/solidity/src/ZKNOX_delegate_noproxy.sol index f4d81a9..256d878 100644 --- a/solidity/src/ZKNOX_delegate_noproxy.sol +++ b/solidity/src/ZKNOX_delegate_noproxy.sol @@ -52,9 +52,9 @@ contract ZKNOX_Verifier { /// @notice Internal nonce used for replay protection, must be tracked and included into prehashed message. uint256 public nonce; - //input are AlgoIdentifier, Signature verification address, publickey storing contract constructor() {} - + + //input are AlgoIdentifier, Signature verification address, publickey storing contract function initialize(uint256 iAlgoID, address iCore, address iPublicKey) external { require(CoreAddress == address(0), "already initialized"); CoreAddress = iCore; // Address of contract of Signature verification (FALCON, DILITHIUM) @@ -77,7 +77,8 @@ contract ZKNOX_Verifier { uint256[] memory nttpk; require(authorizedPublicKey != address(0), "authorizedPublicKey null"); - //nttpk = Core.GetPublicKey(authorizedPublicKey); + nttpk = Core.GetPublicKey(authorizedPublicKey); + require(nttpk[0]!=0, "wrong extraction"); //require(Core.verify(abi.encodePacked(digest), salt, s2, nttpk), "Invalid signature"); (bool success,) = to.call{value: val}(data); @@ -86,11 +87,11 @@ contract ZKNOX_Verifier { } //debug function for now: todo, remove when transact successfully tested - function verify( + function isValid( bytes memory data, bytes memory salt, // compacted signature salt part uint256[] memory s2 - ) public view returns (bool) { + ) external payable returns (bool) { ISigVerifier Core = ISigVerifier(CoreAddress); uint256[] memory nttpk; nttpk = Core.GetPublicKey(authorizedPublicKey); diff --git a/solidity/src/ZKNOX_hybrid.sol b/solidity/src/ZKNOX_hybrid.sol index 918ef4b..827f761 100644 --- a/solidity/src/ZKNOX_hybrid.sol +++ b/solidity/src/ZKNOX_hybrid.sol @@ -64,8 +64,13 @@ contract ZKNOX_HybridVerifier { /// @notice Internal nonce used for replay protection, must be tracked and included into prehashed message. uint256 public nonce; + constructor() {} + //input are AlgoIdentifier, Signature verification address, publickey storing contract - constructor(uint256 iAlgoID, address iCore, address iPublicPQKey) { + function initialize(uint256 iAlgoID, address iCore, address iAuthorized_ECDSA, address iPublicPQKey) external { + require(CoreAddress == address(0), "already initialized"); + + authorized_ECDSA=iAuthorized_ECDSA; //derived address from ecdsa secp256K1 CoreAddress = iCore; // Address of contract of Signature verification (FALCON, DILITHIUM) algoID = iAlgoID; authorized_PQPublicKey = iPublicPQKey; @@ -92,9 +97,9 @@ contract ZKNOX_HybridVerifier { require(authorized_PQPublicKey != address(0), "authorizedPublicKey null"); - require(recovered==authorized_ECDSA, "Invalid ECDSA signature"); - //nttpk = Core.GetPublicKey(authorized_PQPublicKey); - //require(Core.verify(abi.encodePacked(digest), salt, s2, nttpk), "Invalid FALCON"); + //require(recovered==authorized_ECDSA, "Invalid ECDSA signature"); + nttpk = Core.GetPublicKey(authorized_PQPublicKey); + require(Core.verify(abi.encodePacked(digest), salt, s2, nttpk), "Invalid FALCON"); (bool success,) = to.call{value: val}(data); @@ -120,7 +125,7 @@ contract ZKNOX_HybridVerifier { require(authorized_PQPublicKey != address(0), "authorizedPublicKey null"); - require(recovered==authorized_ECDSA, "Invalid ECDSA signature"); + //require(recovered==authorized_ECDSA, "Invalid ECDSA signature"); nttpk = Core.GetPublicKey(authorized_PQPublicKey); require(Core.verify(abi.encodePacked(digest), salt, s2, nttpk), "Invalid FALCON"); diff --git a/solidity/test/ZKNOX_IVerifierDelegate_noproxy.t.sol b/solidity/test/ZKNOX_IVerifierDelegate_noproxy.t.sol index 726d481..e64540c 100644 --- a/solidity/test/ZKNOX_IVerifierDelegate_noproxy.t.sol +++ b/solidity/test/ZKNOX_IVerifierDelegate_noproxy.t.sol @@ -92,7 +92,7 @@ contract SignDelegationTest is Test { falcon = new ZKNOX_ethfalcon(); // public key in ntt form // forgefmt: disable-next-line - uint256[32] memory tmp_pkc = [20377218425118340445148364134355217251962993606936992273331839780054216280849, 20121106827228450321124896615938334719918113760150351437528659189176262990636, 10067497595444039977213793634597611854404700659079271442444950951559432116521, 8117003418140413121709569530562717039471558017795389997976077490386494167285, 19719916617578783495479977733846345663822541355599584111604787561804371332299, 12011255695358364119082992510081379197681548345148896992583517862986064267371, 1413712800155248155901989741415704580119744515670156265477932184210522442954, 20205896941262413308936850117551422118594142119900192427257346204109575433582, 3486279541225130755598501027003998051985801747561740177288468626060198090459, 15477599456049069393051346514952035991054078301113692636739851820730251809819, 21156392022423827010876847021244058034030321298933336763476969617428294271271, 2908341131797448574919302622375649436059983246466303686691800726354050296280, 4014285105619800009931504325676093765338451832744274077688243007139640906463, 17525386234073442601006363277175078033276096227970594283065994928074709206070, 9399682681199319758356271164177409471029167726563817053939019373865509324066, 14497266053893643950060558685941531408969726991430751449270004178102628913394, 20001018922134128765022849593872125843127919031255693298563962888117505231302, 20223399471737868067964408671262891234552388541376818065834177454291358723391, 11076429199706617732593752467897544427206591530047673604493842949459150906661, 10003914827585439734433133640025401879385317162577084551224105445404031001782, 20818841785974240140489196577114322827962289517719106191109136290716168037702, 9930008312479770233251082269305959959461466299666759427058224003186584853639, 13961923764749961571138036653552925829425897028586292322709756121414948556716, 1865847632959804051511238296007895164923970314748517688837335778369740540589, 9619029050213147645610307806665071441731316717663787766260527940528214317525, 14242850992292404983847270889619711734347852346434510691917062411771622728876, 14741088360075140317883502213566092308263093099494020005957065598182206670698, 450741599221347172965973222014483009289616792068532398266398440365899262013, 18781682460599299134542238039348179607304289110944838378016618837639364477280, 9945663145577743462232497392336568635199398547866845488457561121052707133988, 4434915596203863112439022225522412087141907977885194617923870370615952742502, 9078099396363096043342272050200561246179429816170715912419583083116430298211]; + uint256[32] memory tmp_pkc = [5662797900309780854973796610500849947334657117880689816302353465126500706865, 19773102689601973621062070293263100534733440101750387150077711329493973274058, 14606681890476865709816748627007131256488820167404174518724605890405097603719, 15845234755931409677594030697035096324340457247480758851130851814703350289524, 5524941775098342886171484209767745714294893760953145782448900256027476885810, 15301033023652038200658165594502048003364566882283859976805808429697192567788, 18875246040654000517074755552890901133645669291006567534900678519700207707731, 11843395683334522200668269515783436692309636627649985746204914551011013629864, 8419305811746464065544475584323153271481428319969733938911379662274846467111, 18343417927809591481517183183479503623951147924071925629514120039495430967592, 10007451325105194000131443764495043320645967197761209321537835667210153693191, 779487061150515667795843171268512499191273448454307717194241961063365614179, 14889466660684110621550004892629051623956217990147793956971155241422811501259, 2995124819739638247263964985959552967489690950312509006670204449438399867779, 16698797261630410217796026169071784061995015858612862963622742163763641855864, 13129716852402613948762495927854872029721399215764359316540986925328111906305, 8620514528683669238836845045565231437047299941974001946945409334379184590766, 5184181041252042291984928267300200431567362250531180743278111084485128161037, 15555356690664302555826193017277818624355238475260445618945780405430020481200, 19264077329172342356817033544893125657281034846341493111114385757819435942150, 8708853592016768361541207473719404660232059936330605270802350059910738161396, 21018648773068189736719755689803981281912117625241701774409626083005150670687, 267026197077955750670312407002345619518873569178283514941902712705828521229, 14359242962640593260752841229079220345384234239741953227891227234975247894859, 8320354099602406351863744856415421903486499003224102136141447162113864442068, 17564344674783852357247325589247473882830766139750808683064015010041459773180, 12601232530472338126510941067000966999586933909071534455578397454667291628041, 17820703520112071877812607241017358905719406745793395857586668204300579510382, 20977963461796112341763752649093803701879441191599296283127418471622134932903, 5627732773047409045458881938100601008133088383905060686572856121439798106767, 2602661464000108367786729796742170641292899005030508211661215565063118195399, 20110282897068872581106488251090599973196923955248066799683528955504800771309]; uint256[] memory pkc = ZKNOX_memcpy32(tmp_pkc); uint256 iAlgoID = FALCONSHAKE_ID; @@ -115,7 +115,8 @@ contract SignDelegationTest is Test { token = new ERC20(ALICE_ADDRESS); } - function test_SimpDeg() public { + //test vector is + function test_SimpDeg_prague() public { // Construct a single transaction call: Mint 100 tokens to Bob. //SimpleDelegateContract.Call[] memory calls = new SimpleDelegateContract.Call[](1); bytes memory data = abi.encodeCall(ERC20.mint, (100, BOB_ADDRESS)); @@ -172,4 +173,59 @@ contract SignDelegationTest is Test { // Verify Bob successfully received 100 tokens. vm.assertEq(token.balanceOf(BOB_ADDRESS), 100); } -} + + + function testVector0_prague() public { + // public key + // forgefmt: disable-next-line + uint256[32] memory tmp_pkc = [5662797900309780854973796610500849947334657117880689816302353465126500706865, 19773102689601973621062070293263100534733440101750387150077711329493973274058, 14606681890476865709816748627007131256488820167404174518724605890405097603719, 15845234755931409677594030697035096324340457247480758851130851814703350289524, 5524941775098342886171484209767745714294893760953145782448900256027476885810, 15301033023652038200658165594502048003364566882283859976805808429697192567788, 18875246040654000517074755552890901133645669291006567534900678519700207707731, 11843395683334522200668269515783436692309636627649985746204914551011013629864, 8419305811746464065544475584323153271481428319969733938911379662274846467111, 18343417927809591481517183183479503623951147924071925629514120039495430967592, 10007451325105194000131443764495043320645967197761209321537835667210153693191, 779487061150515667795843171268512499191273448454307717194241961063365614179, 14889466660684110621550004892629051623956217990147793956971155241422811501259, 2995124819739638247263964985959552967489690950312509006670204449438399867779, 16698797261630410217796026169071784061995015858612862963622742163763641855864, 13129716852402613948762495927854872029721399215764359316540986925328111906305, 8620514528683669238836845045565231437047299941974001946945409334379184590766, 5184181041252042291984928267300200431567362250531180743278111084485128161037, 15555356690664302555826193017277818624355238475260445618945780405430020481200, 19264077329172342356817033544893125657281034846341493111114385757819435942150, 8708853592016768361541207473719404660232059936330605270802350059910738161396, 21018648773068189736719755689803981281912117625241701774409626083005150670687, 267026197077955750670312407002345619518873569178283514941902712705828521229, 14359242962640593260752841229079220345384234239741953227891227234975247894859, 8320354099602406351863744856415421903486499003224102136141447162113864442068, 17564344674783852357247325589247473882830766139750808683064015010041459773180, 12601232530472338126510941067000966999586933909071534455578397454667291628041, 17820703520112071877812607241017358905719406745793395857586668204300579510382, 20977963461796112341763752649093803701879441191599296283127418471622134932903, 5627732773047409045458881938100601008133088383905060686572856121439798106767, 2602661464000108367786729796742170641292899005030508211661215565063118195399, 20110282897068872581106488251090599973196923955248066799683528955504800771309]; + uint256[] memory pkc = ZKNOX_memcpy32(tmp_pkc); + + // signature s2 + // forgefmt: disable-next-line + uint256[32] memory tmp_s2 = [189061025430138993865854805011532069333293715869299695949354293295109767338, 309200829492683618362801840838735315073239679824516877254610688296907178015, 17669203565873415420439226729611576544749443656481276334890396524208467774, 21567902685951065342220093337212015325627859479836552266578154972738260959272, 21629742710641854202617034886213873892640485268970955124070672848858167127875, 21518761173595649991077541634911872372568563460460287375282464679909027151878, 88668843202050080354162430362465493400899326659627631899251092744825352121, 21589115041612929508944530253353887521990674352656231997732268725231305949408, 77748037816609010048821043986758852741763365848433569238103440621543948394, 196125604980477431416529085554673976708993318735365421874476849166068940885, 21444227575187532861933165945345576589177205410775875437029272647414716641113, 21571766779137214249890997998635625679180679668367453624699784252197002280960, 132842791722068690864021037096966919030178447937701691660884444009250095184, 252660618073406522895016361327352646221166102604901000414436689373735890818, 21661875898514585455300483231269254543688174841797784277884596070553710964571, 408469887372575727764354863939787898486221033046251585808276641395393310697, 21483098798806565528090561173471573130149923357778077129069435100923827138387, 21365040707017283224032169374693579384647805515287338499452209675962376454353, 139582082355163817792446396090827957258977980096747497728717346717617488024, 21698977390374140751926738932285965733024723476130692021975378126228657012810, 21582043479534721231928031949222680268801040592884446810862621247728671654012, 106016188978695213660006561000087639649638405319762547008619378770056380540, 21396523669988578255532519494435324598773577619532813394543061212841669504837, 567487142710691728457912662951684626851937150493245889102477722465050636084, 185844569086061214504135130584456987157183142589951887136070171885834153901, 350162015184944149647336545709148596957881292049384682934039156939714199637, 56868125263755762880306655715105756108612883350558868787549471782918631255, 113409366200701537080466339400905201724440194357091543728319651397816025091, 598968924407998825190710488524458442266573561012338161932509137359297720206, 21524058349737765174490280399545977619713148567855354072883708688105677467568, 21592968836075103278633512472085925061228035841536899495353847705011755429638, 224400819594214410949880090102269951771459564115310187818733077437072605190]; + uint256[] memory s2 = new uint256[](32); + for (uint256 i = 0; i < 32; i++) { + s2[i] = tmp_s2[i]; + } + // message + bytes memory message = "My name is Renaud"; + bytes memory salt = + "\x46\xb9\xdd\x2b\x0b\xa8\x8d\x13\x23\x3b\x3f\xeb\x74\x3e\xeb\x24\x3f\xcd\x52\xea\x62\xb8\x1b\x82\xb5\x0c\x27\x64\x6e\xd5\x76\x2f\xd7\x5d\xc4\xdd\xd8\xc0\xf2\x00"; + bool result = falcon.verify(message, salt, s2, pkc); + assertEq(true, result); + + vm.startBroadcast(ALICE_PK); + + // Debug: Print stored values to verify correct setup + console.log( + "Stored authorizedPublicKey at Alice:", + address(uint160(uint256(vm.load(ALICE_ADDRESS, bytes32(uint256(0)))))) + ); + console.log( + "Stored CoreAddress at Alice:", address(uint160(uint256(vm.load(ALICE_ADDRESS, bytes32(uint256(1)))))) + ); + console.log("Stored algoID at Alice:", uint256(vm.load(ALICE_ADDRESS, bytes32(uint256(2))))); + console.log("Stored nonce at Alice:", uint256(vm.load(ALICE_ADDRESS, bytes32(uint256(3))))); + + // As Bob, execute the transaction via Alice's temporarily assigned contract. + vm.stopBroadcast(); + + vm.broadcast(BOB_PK); + bytes memory code = address(ALICE_ADDRESS).code; //this shall be ef0100, followed by adress + + console.log("Verifier address:%x", uint256(uint160(address(Verifier)))); + + console.log("code written at eoa Alice:"); + console.logBytes(code); + + // Verify that Alice's account now temporarily behaves as a smart contract. + require(code.length > 0, "no code written to Alice"); + + // As Bob, execute the transaction via Alice's temporarily assigned contract. + bool isValid=ZKNOX_Verifier(ALICE_ADDRESS).isValid(message, salt, s2); //this is the delegation we want, failing now + console.log("signature result:", isValid); + + } + +}//end contract test Delegation From c5d8e3e3dd0334b5b76730877bdece820f0036e3 Mon Sep 17 00:00:00 2001 From: renaud dubois Date: Sat, 31 May 2025 11:14:36 +0200 Subject: [PATCH 04/10] test vector for hybridation provide a test vector for ECDSA+Falcon jointly --- solidity/falcon/test_falcon.js | 6 +++++- solidity/test/ZKNOX_falconKATS.t.sol | 10 +--------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/solidity/falcon/test_falcon.js b/solidity/falcon/test_falcon.js index 208212d..9ef95c4 100644 --- a/solidity/falcon/test_falcon.js +++ b/solidity/falcon/test_falcon.js @@ -7,9 +7,13 @@ Module().then((falcon) => { const sigMaxLen = 690; const seedLen= 32; - const message = Buffer.from("hello from ZKNOX!"); const seed=Buffer.from("12345678123456781234567812345679") + const hexString = "0x50b2c43fd39106bafbba0da34fc430e1f91e3c96ea2acee2bc34119f92b37750"; + + // Remove the "0x" prefix before passing to Buffer.from + const message = Buffer.from(hexString.slice(2), "hex"); + // Allocate memory const pkPtr = falcon._malloc(pkLen); const skPtr = falcon._malloc(skLen); diff --git a/solidity/test/ZKNOX_falconKATS.t.sol b/solidity/test/ZKNOX_falconKATS.t.sol index 31916c5..b615e34 100644 --- a/solidity/test/ZKNOX_falconKATS.t.sol +++ b/solidity/test/ZKNOX_falconKATS.t.sol @@ -147,15 +147,7 @@ function test_vector_prague() public{ (kpub, s2, salt, message) = decompress_KAT(pk, sm); - uint256[] memory hashed = hashToPointNIST(salt, message); - - //Display_HexArray(" hashToPoint", hashed); - - //Display_HexArray(" public key canonical form", kpub); - //Display_HexArray("sig canonical form", s2); - - //s2=Swap(s2); - //kpub=Swap(kpub); + uint256[] memory ntth = _ZKNOX_NTT_Compact(_ZKNOX_NTTFW_vectorized(kpub)); From 6363f8fb6523dba268042c797168f46d1a0d4b81 Mon Sep 17 00:00:00 2001 From: renaud dubois Date: Sat, 31 May 2025 13:11:56 +0200 Subject: [PATCH 05/10] hybrid account coded, but still failing --- solidity/src/ZKNOX_falcon_deploy.sol | 1 + solidity/src/ZKNOX_falcon_encodings.sol | 21 ++++++++++++++++ solidity/src/ZKNOX_hybrid.sol | 33 +++++++++++++++++++------ 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/solidity/src/ZKNOX_falcon_deploy.sol b/solidity/src/ZKNOX_falcon_deploy.sol index ec37219..fbb0f75 100644 --- a/solidity/src/ZKNOX_falcon_deploy.sol +++ b/solidity/src/ZKNOX_falcon_deploy.sol @@ -116,3 +116,4 @@ function DeployPolynomial(bytes32 salt, uint256[] memory polynomial) returns (ad } require(a_polynomial != address(0), "Deployment failed"); } + diff --git a/solidity/src/ZKNOX_falcon_encodings.sol b/solidity/src/ZKNOX_falcon_encodings.sol index 23f1830..9b78f9b 100644 --- a/solidity/src/ZKNOX_falcon_encodings.sol +++ b/solidity/src/ZKNOX_falcon_encodings.sol @@ -189,3 +189,24 @@ function decompress_KAT(bytes memory pk, bytes memory sm) return (h, s2, salt, message); } + + +//deploy a polynomial onchain from the NIST encoding +function DeployPolynomial_NIST(bytes32 salt, bytes memory pk) returns (address a_polynomial) { + + /* + * Decode public key. + */ + if (pk[0] != 0x09) { + revert("wrong public key encoding"); + } + uint256[] memory polynomial = decompress_kpub(pk, 1); + + bytes memory bytecode_pol = abi.encodePacked(polynomial); + + bytecode_pol = abi.encodePacked(hex"63", uint32(bytecode_pol.length), hex"80600E6000396000F3", bytecode_pol); + assembly { + a_polynomial := create2(0, add(bytecode_pol, 0x20), mload(bytecode_pol), salt) + } + require(a_polynomial != address(0), "Deployment failed"); +} \ No newline at end of file diff --git a/solidity/src/ZKNOX_hybrid.sol b/solidity/src/ZKNOX_hybrid.sol index 827f761..364756f 100644 --- a/solidity/src/ZKNOX_hybrid.sol +++ b/solidity/src/ZKNOX_hybrid.sol @@ -48,6 +48,7 @@ import "./ZKNOX_falcon_core.sol"; //choose the XOF to use here import "./ZKNOX_HashToPoint.sol"; +import "./ZKNOX_falcon_encodings.sol"; /// @notice Contract designed for being delegated to by EOAs to authorize a IVerifier key to transact on their behalf. contract ZKNOX_HybridVerifier { @@ -106,18 +107,36 @@ contract ZKNOX_HybridVerifier { require(success, "failing executing the cal"); } - function isValid_HybridSignature( - address to, - bytes memory data, - uint256 val, + //digest, v,r,s are input to ecrecover, sm is the falcon signature + function isValid( + bytes32 digest, uint8 v, bytes32 r, bytes32 s, - bytes memory salt, // compacted FALCONsignature salt part - uint256[] memory s2 // compacted FALCON signature s2 part)) + bytes memory sm // the signature in the NIST KAT format, as output by test_falcon.js ) public returns (bool) { - bytes32 digest = keccak256(abi.encode(nonce++, to, data, val)); + uint256 slen = (uint256(uint8(sm[0])) << 8) + uint256(uint8(sm[1])); + uint256 mlen = sm.length - slen - 42; + + bytes memory message; + bytes memory salt = new bytes(40); + + for (uint i = 0; i < 40; i++) { + salt[i] = sm[i + 2]; + } + message = new bytes(mlen); + for (uint256 j = 0; j < mlen; j++) { + message[j] = sm[j + 42]; + } + + if (sm[2 + 40 + mlen] != 0x29) { + revert("wrong header sigbytes"); + } + + uint256[] memory s2 = _ZKNOX_NTT_Compact(_decompress_sig(sm, 2 + 40 + mlen + 1)); + + ISigVerifier Core = ISigVerifier(CoreAddress); uint256[] memory nttpk; From dc4d109cf2821495eccec6cef43bbe90a7323cab Mon Sep 17 00:00:00 2001 From: renaud dubois Date: Sat, 31 May 2025 15:45:25 +0200 Subject: [PATCH 06/10] hybrid account working --- solidity/src/ZKNOX_falcon_deploy.sol | 2 ++ solidity/src/ZKNOX_falcon_encodings.sol | 7 ++-- solidity/src/ZKNOX_hybrid.sol | 48 ++----------------------- 3 files changed, 9 insertions(+), 48 deletions(-) diff --git a/solidity/src/ZKNOX_falcon_deploy.sol b/solidity/src/ZKNOX_falcon_deploy.sol index fbb0f75..f9dc8a6 100644 --- a/solidity/src/ZKNOX_falcon_deploy.sol +++ b/solidity/src/ZKNOX_falcon_deploy.sol @@ -38,6 +38,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.25; + + function _Swap16(uint256 inw) pure returns (uint256 outw) { for (uint256 i = 0; i < 256; i += 16) { outw ^= (inw >> (240 - i) & 0xffff) << (i); diff --git a/solidity/src/ZKNOX_falcon_encodings.sol b/solidity/src/ZKNOX_falcon_encodings.sol index 9b78f9b..0e213f1 100644 --- a/solidity/src/ZKNOX_falcon_encodings.sol +++ b/solidity/src/ZKNOX_falcon_encodings.sol @@ -36,7 +36,9 @@ * */ import "./ZKNOX_falcon_utils.sol"; -//import {Test, console} from "forge-std/Test.sol"; + +import "./ZKNOX_NTT.sol"; +import "./ZKNOX_NTT_falcon.sol"; uint256 constant max_in_len = 666; @@ -201,7 +203,8 @@ function DeployPolynomial_NIST(bytes32 salt, bytes memory pk) returns (address a revert("wrong public key encoding"); } uint256[] memory polynomial = decompress_kpub(pk, 1); - + polynomial=_ZKNOX_NTT_Compact(_ZKNOX_NTTFW_vectorized(polynomial)); + bytes memory bytecode_pol = abi.encodePacked(polynomial); bytecode_pol = abi.encodePacked(hex"63", uint32(bytecode_pol.length), hex"80600E6000396000F3", bytecode_pol); diff --git a/solidity/src/ZKNOX_hybrid.sol b/solidity/src/ZKNOX_hybrid.sol index 364756f..5bcf999 100644 --- a/solidity/src/ZKNOX_hybrid.sol +++ b/solidity/src/ZKNOX_hybrid.sol @@ -47,7 +47,6 @@ import "./ZKNOX_falcon_core.sol"; //choose the XOF to use here import "./ZKNOX_HashToPoint.sol"; - import "./ZKNOX_falcon_encodings.sol"; /// @notice Contract designed for being delegated to by EOAs to authorize a IVerifier key to transact on their behalf. @@ -78,35 +77,6 @@ contract ZKNOX_HybridVerifier { nonce = 0; } - /// @notice Main entrypoint for authorized transactions. Accepts transaction parameters (to, data, value) and a musig2 signature. - function transact( - address to, - bytes memory data, - uint256 val, - - uint8 v, - bytes32 r, - bytes32 s, - bytes memory salt, // compacted FALCONsignature salt part - uint256[] memory s2 // compacted FALCON signature s2 part) - ) external payable { - bytes32 digest = keccak256(abi.encode(nonce++, to, data, val)); - ISigVerifier Core = ISigVerifier(CoreAddress); - - uint256[] memory nttpk; - address recovered = ecrecover(digest, v, r, s); - - - require(authorized_PQPublicKey != address(0), "authorizedPublicKey null"); - //require(recovered==authorized_ECDSA, "Invalid ECDSA signature"); - nttpk = Core.GetPublicKey(authorized_PQPublicKey); - require(Core.verify(abi.encodePacked(digest), salt, s2, nttpk), "Invalid FALCON"); - - (bool success,) = to.call{value: val}(data); - - require(success, "failing executing the cal"); - } - //digest, v,r,s are input to ecrecover, sm is the falcon signature function isValid( bytes32 digest, @@ -134,17 +104,15 @@ contract ZKNOX_HybridVerifier { revert("wrong header sigbytes"); } - uint256[] memory s2 = _ZKNOX_NTT_Compact(_decompress_sig(sm, 2 + 40 + mlen + 1)); - + uint256[] memory s2 =_ZKNOX_NTT_Compact((_decompress_sig(sm, 2 + 40 + mlen + 1))); ISigVerifier Core = ISigVerifier(CoreAddress); uint256[] memory nttpk; address recovered = ecrecover(digest, v, r, s); - require(authorized_PQPublicKey != address(0), "authorizedPublicKey null"); - //require(recovered==authorized_ECDSA, "Invalid ECDSA signature"); + require(recovered==authorized_ECDSA, "Invalid ECDSA signature"); nttpk = Core.GetPublicKey(authorized_PQPublicKey); require(Core.verify(abi.encodePacked(digest), salt, s2, nttpk), "Invalid FALCON"); @@ -153,18 +121,6 @@ contract ZKNOX_HybridVerifier { - //debug function for now: todo, remove when transact successfully tested - function verify( - bytes memory data, - bytes memory salt, // compacted signature salt part - uint256[] memory s2 - ) public view returns (bool) { - ISigVerifier Core = ISigVerifier(CoreAddress); - uint256[] memory nttpk; - nttpk = Core.GetPublicKey(authorized_PQPublicKey); - return Core.verify(data, salt, s2, nttpk); - } - function GetPublicKey() public view returns (uint256[] memory res) { ISigVerifier Core = ISigVerifier(CoreAddress); res = Core.GetPublicKey(authorized_PQPublicKey); From 342a81592d87cb741f11fe22fc00c3e7354fe759 Mon Sep 17 00:00:00 2001 From: renaud dubois Date: Sat, 31 May 2025 15:55:34 +0200 Subject: [PATCH 07/10] testing of hybrid account crafted signature using etherjs+test_falcon.js --- solidity/test/ZKNOX_hybrid.t.sol | 172 +++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 solidity/test/ZKNOX_hybrid.t.sol diff --git a/solidity/test/ZKNOX_hybrid.t.sol b/solidity/test/ZKNOX_hybrid.t.sol new file mode 100644 index 0000000..e9a1f9d --- /dev/null +++ b/solidity/test/ZKNOX_hybrid.t.sol @@ -0,0 +1,172 @@ + +pragma solidity ^0.8.25; + +import {Test, console} from "forge-std/Test.sol"; +import "../src/ZKNOX_falcon_encodings.sol"; +import "../src/ZKNOX_falcon.sol"; +import "../src/ZKNOX_falcon_deploy.sol"; +import "../src/ZKNOX_display.sol"; +import "../src/ZKNOX_hybrid.sol"; + +import "forge-std/Vm.sol"; + + +contract Hybrid_Test is Test { + ZKNOX_falcon falcon; + //exemple of stateless initialisation, no external contract provided + // Alice's address and private key (EOA with no initial contract code). + address payable ALICE_ADDRESS = payable(0x70997970C51812dc3A010C7d01b50e0d17dc79C8); + uint256 constant ALICE_PK = 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d; + + // Bob's address and private key (Bob will execute transactions on Alice's behalf). + address constant BOB_ADDRESS = 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC; + uint256 constant BOB_PK = 0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a; + // Deployer's address and private key (used to deploy contracts). + address private constant DEPLOYER_ADDRESS = 0xa0Ee7A142d267C1f36714E4a8F75612F20a79720; + uint256 private constant DEPLOYER_PK = 0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6; + + // The contract that Alice will delegate execution to. + + ZKNOX_HybridVerifier Verifier; + + + + //stateful initialisation + function setUp() public { + // Deploy the delegation contract (Alice will delegate calls to this contract). + + bytes memory pk=hex"09bc10a933624770811dc5e315526a3496c0e89b8e8436401a0848868c8b297ad7960a4f4df60bb2eba58b6d6828c99dce1d8b41ea6188af8e90081f3b2deee68a3888fb5ae87d99e2a110211cac1eadfa3a724c276a9108db19e8ff0add0da14aedd2073294ea7b682276edd449108e2b765ea2c03689b05fa6ba9146e16468325fdb39606472c61022f6679f247c16166c13af73994dc3dfa0b462b22747ee43a60f018eb5a26992805841c52b2b9ab829fbd4ed8b134625dbb95a10e62bbeeb806a95f985943472bc82ac510ae051ae2aff02a6cda68edfe971aef468356f075cb9b8c974566a3a46742123e78a79d96a941a94857e2acc3449955589ce80a6cc0ceb773224453b6309a280e659e585a68a98ea860869eba50a1d9776901babde4311638efc656cc564cc50987e1a8564e6e7bd47960d988f0a5a04746454528fab9cd89da9f1e534394229c91059f428b522cbf15eb359b9a08adfd3fe1d3548265a2e3b75c1f239df4e90734d704be8817b5639caa9d289fb4ee0f5e4d7603faff43d74734f8f6bdd9ff7b6578dac9e15949a54fa5465a925a61ebbb2f8eb858c1f487a9144840a1f9864f5ca49a7a63f6ec2a7f672c2c7ac18e973a1c0ca864e63db9f8731a996d1098809a89024f88bb8d757346993e52b138501315cf2086056060486870a5c437e886b8bcb422c0cde1ee081eddf18762a15926e8a8b5235b12d6d8ca5c60d72cfad3e755100d75096b5b8317ce7d5d36c5e01f7945a883cafa0a512e8edf28554c075145dec6798a3e2fac6cfa4851011b4906255521d5968102d10a92ff93d85b82d804469e90df8aee1b54212a66f461eb3514f29af958c326606e576254ef1a9ec83c62c568444d19e573b9c1c10d7a0b96fe4027a7a21c09b71cd7b271a828aa048203ae1691f5826e03a411e283dfa5a1a1b05bcf67ce6801590ab84a5d281edd573eadf50f6289d79b05b136ec16178d812d7f7e0f38cd9e83692064253f1dfda28ab97578dc0768fca404ef57ff24b463e3d50288970289e264a0eb9138a773fb114e0fd0c5fb5812186cea1f2a53ec133dfa3ad8809fd47cd56cb2e0185c266a17d263291753a47a2b531a5e9e4d29037646f934518c33e2c1fe2df5b2c0dea9fa2c751d689b24a819ce0f0bf82cab7b3adfc341a516b16c146a7c6a0e890a2d7451cf22459e3f3ab74b3076a62fbb11899a1a809357cb28a328761e0a4d56b501eca76a87169f560159c46a6a635b344c5"; + // forgefmt: disable-next-line + falcon = new ZKNOX_falcon(); + // public key in ntt form + // forgefmt: disable-next-line + + uint256 iAlgoID = FALCONSHAKE_ID; + + bytes32 salty = keccak256(abi.encodePacked("ZKNOX_v0.14")); + + address iVerifier_algo = address(falcon); + address iPQPublicKey = DeployPolynomial_NIST(salty, pk); + address ECDSAPublicKey=0x24D63ffC083dB45d713F970565AA322c71A6e79c; + + Verifier = new ZKNOX_HybridVerifier(); + + // Alice signs a delegation allowing `implementation` to execute transactions on her behalf. + Vm.SignedDelegation memory signedDelegation = vm.signDelegation(address(Verifier), ALICE_PK); + + vm.attachDelegation(signedDelegation); + ZKNOX_HybridVerifier aliceVerifier = ZKNOX_HybridVerifier(ALICE_ADDRESS); + aliceVerifier.initialize(iAlgoID, iVerifier_algo, ECDSAPublicKey, iPQPublicKey); + console.log("param Verifier:", aliceVerifier.algoID(), aliceVerifier.CoreAddress(), aliceVerifier.authorized_PQPublicKey()); + + } + + //unitary test of joint ECDSA+falcon + function test_prague_hybridsig() public returns (address) { + bytes32 h = 0x50b2c43fd39106bafbba0da34fc430e1f91e3c96ea2acee2bc34119f92b37750;//the hash signed by FALCON NIST and ECDSA, provided by etherjs for ECDSA and test_falcon.js for falcon + // forgefmt: disable-next-line + bytes memory pk=hex"09bc10a933624770811dc5e315526a3496c0e89b8e8436401a0848868c8b297ad7960a4f4df60bb2eba58b6d6828c99dce1d8b41ea6188af8e90081f3b2deee68a3888fb5ae87d99e2a110211cac1eadfa3a724c276a9108db19e8ff0add0da14aedd2073294ea7b682276edd449108e2b765ea2c03689b05fa6ba9146e16468325fdb39606472c61022f6679f247c16166c13af73994dc3dfa0b462b22747ee43a60f018eb5a26992805841c52b2b9ab829fbd4ed8b134625dbb95a10e62bbeeb806a95f985943472bc82ac510ae051ae2aff02a6cda68edfe971aef468356f075cb9b8c974566a3a46742123e78a79d96a941a94857e2acc3449955589ce80a6cc0ceb773224453b6309a280e659e585a68a98ea860869eba50a1d9776901babde4311638efc656cc564cc50987e1a8564e6e7bd47960d988f0a5a04746454528fab9cd89da9f1e534394229c91059f428b522cbf15eb359b9a08adfd3fe1d3548265a2e3b75c1f239df4e90734d704be8817b5639caa9d289fb4ee0f5e4d7603faff43d74734f8f6bdd9ff7b6578dac9e15949a54fa5465a925a61ebbb2f8eb858c1f487a9144840a1f9864f5ca49a7a63f6ec2a7f672c2c7ac18e973a1c0ca864e63db9f8731a996d1098809a89024f88bb8d757346993e52b138501315cf2086056060486870a5c437e886b8bcb422c0cde1ee081eddf18762a15926e8a8b5235b12d6d8ca5c60d72cfad3e755100d75096b5b8317ce7d5d36c5e01f7945a883cafa0a512e8edf28554c075145dec6798a3e2fac6cfa4851011b4906255521d5968102d10a92ff93d85b82d804469e90df8aee1b54212a66f461eb3514f29af958c326606e576254ef1a9ec83c62c568444d19e573b9c1c10d7a0b96fe4027a7a21c09b71cd7b271a828aa048203ae1691f5826e03a411e283dfa5a1a1b05bcf67ce6801590ab84a5d281edd573eadf50f6289d79b05b136ec16178d812d7f7e0f38cd9e83692064253f1dfda28ab97578dc0768fca404ef57ff24b463e3d50288970289e264a0eb9138a773fb114e0fd0c5fb5812186cea1f2a53ec133dfa3ad8809fd47cd56cb2e0185c266a17d263291753a47a2b531a5e9e4d29037646f934518c33e2c1fe2df5b2c0dea9fa2c751d689b24a819ce0f0bf82cab7b3adfc341a516b16c146a7c6a0e890a2d7451cf22459e3f3ab74b3076a62fbb11899a1a809357cb28a328761e0a4d56b501eca76a87169f560159c46a6a635b344c5"; + + // forgefmt: disable-next-line + bytes memory sm=hex"0268530f8afbc74536b9a963b4f1c4cb738bcea7403d4d606b6e074ec5d3baf39d18726003ca37a62a7450b2c43fd39106bafbba0da34fc430e1f91e3c96ea2acee2bc34119f92b37750297ec2d4595cbb8c63969e43a166aa9bb8deec56e12b846277e35c5fed1c50c32e48b1196c107664e7e69485033f616a1e2f43472db23d5cc429ce91199ebcf7a4dec55238b1f6aca32e54bac3f1cc14fe8f53d48d5fe9f21f23be9c109c4254636c5d17778af36ffcb37a767b0a17febd893e674c2201e79fd574dd3cba94ea63767edeb3e6cea18f09dae8b0dabb440851ab7fdca10bf0138acec3275672324331dea466f69e86a4e6e6dec65a204275287e3b22d83ac8912feabd7c272f94d232120d27c0e625ca17d12c2c69b0eb26d2c94d81fbc7a5b0f30529bf502a73145508bb3bbb1f7c31db45f477ec9651f3bd7630daf8b170b1c1170a6cbf50b64c5ca559898c6ebfd46621d19fa13afd93579a654c5932bdebb9478a6943d838c4fb5e61a5ea65152191c8d0724d673d6fecff4bc29e90879a00cfe5e16b3713d6a43f5edad250d814670b20c1e629ab147a21e8c7604caec4adefe6cc14b1a2238942490489afdef48bfac1f6ee556f8a2edef9d83675748f58f9ed37467ac567a889dde8ea72ddf97a6f3fdf249c72ceb5f2f1915d2a08511079997b8a992ca18f651dea3a168f26cb8d011273784ecc9e381f676da0b0b77fb8fe09e5455a5499b6e5aed73619f3e3d9b7aafea679e1b36ab10c3e4b3f40082962c2a0f4b87786b691ff5246809b2ed94978afd76b357c9c7ef1256bbff0e82f279bad32aadc45bb339156288bf4202e110d81457a1b5299e272754999ec350fc57afffd9361e57024ca0dfa36d5da322795468c9532739ef5358e8902225b48ed6d964ffa7c46b18a8a9448b65704606b06b17e49ca2e46a13868978f3ed1d3c0943d8dc90b24de72714fc940"; + //Public Key X: 0x25d78deee0f08530687ba1b624bcdbd4560e55d61334e406b7bfd59b9b889d27 + //Public Key Y: 0x075d427f734aa0e304938358e610fae302996ee2593deb9117a03d89baabcd95 + + //the ecdsa signature + uint8 v = 28; + bytes32 r = 0xb53b48c0bd1639e836cc93b267aeff63bcc3d597211107d2e93ae71c2560a46e; + bytes32 s = 0x08c1f40ee7743dd09372566d171651195cbd963cf57b9ac7ea78b3879e71b8c8; + + address res= ecrecover(h, v, r, s); + assertEq(uint160(0x24D63ffC083dB45d713F970565AA322c71A6e79c), uint160(res)); + + + uint256[] memory kpub; + uint256[] memory s2; + + uint256[] memory cs2; + bytes memory salt; + bytes memory message; + + (kpub, s2, salt, message) = decompress_KAT(pk, sm); + + uint256[] memory ntth = _ZKNOX_NTT_Compact(_ZKNOX_NTTFW_vectorized(kpub)); + + cs2 = _ZKNOX_NTT_Compact(s2); + + console.log("ntth length:", ntth.length); + console.log("ntthh[0]:"); + + for(uint i=0;i<1;i++){ + console.log("%x",ntth[i]); + } + + console.log("salt:"); + console.logBytes(salt); + + console.log("message:"); + console.logBytes(message); + + bool result = falcon.verify(message, salt, cs2, ntth); + + console.log("result", result); + + return res; + } + + + function testVector0_prague_hybridsig_delegation() public { + bytes32 h = 0x50b2c43fd39106bafbba0da34fc430e1f91e3c96ea2acee2bc34119f92b37750;//the hash signed by FALCON NIST and ECDSA, provided by etherjs for ECDSA and test_falcon.js for falcon + //the ecdsa signature + uint8 v = 28; + bytes32 r = 0xb53b48c0bd1639e836cc93b267aeff63bcc3d597211107d2e93ae71c2560a46e; + bytes32 s = 0x08c1f40ee7743dd09372566d171651195cbd963cf57b9ac7ea78b3879e71b8c8; + //the falcon signature + // forgefmt: disable-next-line + bytes memory sm=hex"0268530f8afbc74536b9a963b4f1c4cb738bcea7403d4d606b6e074ec5d3baf39d18726003ca37a62a7450b2c43fd39106bafbba0da34fc430e1f91e3c96ea2acee2bc34119f92b37750297ec2d4595cbb8c63969e43a166aa9bb8deec56e12b846277e35c5fed1c50c32e48b1196c107664e7e69485033f616a1e2f43472db23d5cc429ce91199ebcf7a4dec55238b1f6aca32e54bac3f1cc14fe8f53d48d5fe9f21f23be9c109c4254636c5d17778af36ffcb37a767b0a17febd893e674c2201e79fd574dd3cba94ea63767edeb3e6cea18f09dae8b0dabb440851ab7fdca10bf0138acec3275672324331dea466f69e86a4e6e6dec65a204275287e3b22d83ac8912feabd7c272f94d232120d27c0e625ca17d12c2c69b0eb26d2c94d81fbc7a5b0f30529bf502a73145508bb3bbb1f7c31db45f477ec9651f3bd7630daf8b170b1c1170a6cbf50b64c5ca559898c6ebfd46621d19fa13afd93579a654c5932bdebb9478a6943d838c4fb5e61a5ea65152191c8d0724d673d6fecff4bc29e90879a00cfe5e16b3713d6a43f5edad250d814670b20c1e629ab147a21e8c7604caec4adefe6cc14b1a2238942490489afdef48bfac1f6ee556f8a2edef9d83675748f58f9ed37467ac567a889dde8ea72ddf97a6f3fdf249c72ceb5f2f1915d2a08511079997b8a992ca18f651dea3a168f26cb8d011273784ecc9e381f676da0b0b77fb8fe09e5455a5499b6e5aed73619f3e3d9b7aafea679e1b36ab10c3e4b3f40082962c2a0f4b87786b691ff5246809b2ed94978afd76b357c9c7ef1256bbff0e82f279bad32aadc45bb339156288bf4202e110d81457a1b5299e272754999ec350fc57afffd9361e57024ca0dfa36d5da322795468c9532739ef5358e8902225b48ed6d964ffa7c46b18a8a9448b65704606b06b17e49ca2e46a13868978f3ed1d3c0943d8dc90b24de72714fc940"; + + + vm.startBroadcast(ALICE_PK); + + // Debug: Print stored values to verify correct setup + + + + console.log( + "Stored authorizedPublicKey at Alice (ecdsa):", + address(uint160(uint256(vm.load(ALICE_ADDRESS, bytes32(uint256(0)))))) + ); + console.log( + "Stored authorizedPQPublicKey at Alice (falcon):", + address(uint160(uint256(vm.load(ALICE_ADDRESS, bytes32(uint256(0)))))) + ); + console.log( + "Stored CoreAddress at Alice:", address(uint160(uint256(vm.load(ALICE_ADDRESS, bytes32(uint256(1)))))) + ); + console.log("Stored algoID at Alice:", uint256(vm.load(ALICE_ADDRESS, bytes32(uint256(2))))); + console.log("Stored nonce at Alice:", uint256(vm.load(ALICE_ADDRESS, bytes32(uint256(3))))); + + // As Bob, execute the transaction via Alice's temporarily assigned contract. + vm.stopBroadcast(); + + vm.broadcast(BOB_PK); + bytes memory code = address(ALICE_ADDRESS).code; //this shall be ef0100, followed by adress + + console.log("Verifier address:%x", uint256(uint160(address(Verifier)))); + + console.log("code written at eoa Alice:"); + console.logBytes(code); + + // Verify that Alice's account now temporarily behaves as a smart contract. + require(code.length > 0, "no code written to Alice"); + + + + // As Bob, execute the transaction via Alice's temporarily assigned contract. + bool isValid=ZKNOX_HybridVerifier(ALICE_ADDRESS).isValid(h,v,r,s,sm); + console.log("signature result:", isValid); + + } + + +} \ No newline at end of file From 7aa092449b7ad88d472439af0c409f4f31a79016 Mon Sep 17 00:00:00 2001 From: renaud dubois Date: Sat, 31 May 2025 18:00:11 +0200 Subject: [PATCH 08/10] adding deterministic signers from seed --- solidity/falcon/deterministic_ecdsa_sign.js | 71 +++++++++++ solidity/falcon/deterministic_falcon_sign.js | 124 +++++++++++++++++++ 2 files changed, 195 insertions(+) create mode 100644 solidity/falcon/deterministic_ecdsa_sign.js create mode 100644 solidity/falcon/deterministic_falcon_sign.js diff --git a/solidity/falcon/deterministic_ecdsa_sign.js b/solidity/falcon/deterministic_ecdsa_sign.js new file mode 100644 index 0000000..96956aa --- /dev/null +++ b/solidity/falcon/deterministic_ecdsa_sign.js @@ -0,0 +1,71 @@ +// first install npm install ethers +import { Wallet, hashMessage, recoverAddress, SigningKey, sha256 } from "ethers"; + +// --- Get arguments from command line --- +// Expected usage: node your_script_name.js <32_byte_seed_hex> +const args = process.argv.slice(2); // Slice to get only the actual arguments + +if (args.length < 2) { + console.error("Usage: node your_script_name.js <32_byte_seed_hex> "); + process.exit(1); +} + +const deterministicSeedInput = args[0]; +const message = args[1]; // The message is now taken directly from the second argument + +// Validate seed length (must be 32 bytes = 64 hex characters) +if (deterministicSeedInput.length !== 64 || !/^[0-9a-fA-F]{64}$/.test(deterministicSeedInput)) { + console.error("Error: Seed must be a 32-byte (64 hex characters) hexadecimal string."); + process.exit(1); +} + +// Prepend "0x" if it's not there, as ethers.sha256 typically expects it or a Uint8Array +const deterministicSeed = deterministicSeedInput.startsWith("0x") ? deterministicSeedInput : "0x" + deterministicSeedInput; + +async function signMessage() { + // Derive the private key deterministically from the seed using SHA256 + const privateKey = sha256(deterministicSeed); + + // Create a Wallet instance from the derived private key + const wallet = new Wallet(privateKey); + + const messageHash = hashMessage(message); + const signature = await wallet.signMessage(message); + const recoveredAddress = recoverAddress(messageHash, signature); + + // Helper to parse the signature + function parseSignature(signature) { + const sig = signature.startsWith("0x") ? signature.slice(2) : signature; + return { + r: "0x" + sig.slice(0, 64), + s: "0x" + sig.slice(64, 128), + v: parseInt(sig.slice(128, 130), 16), + }; + } + const sig = parseSignature(signature); + + const signingKey = new SigningKey(wallet.privateKey); + const publicKey = signingKey.publicKey; + + // Extract X and Y coordinates from the uncompressed public key + const x = "0x" + publicKey.slice(4, 68); // Slice from index 4 to 68 for X (skipping 0x04 prefix) + const y = "0x" + publicKey.slice(68); // Slice from index 68 to end for Y + + console.log("Message: ", message); + console.log("Input Seed (hex):", deterministicSeedInput); + console.log("Derived Private Key:", privateKey); + console.log("Wallet Address: ", wallet.address); + console.log("Message Hash: ", messageHash); + console.log("Signature: ", signature); + console.log("r (signature): ", sig.r); + console.log("s (signature): ", sig.s); + console.log("v (signature): ", sig.v); + console.log("Public Key (uncompressed):", publicKey); // The full 0x04... key + console.log("Public Key X: ", x); + console.log("Public Key Y: ", y); + console.log("Recovered Addr: ", recoveredAddress); +} + +signMessage(); // Call the async function + +console.log("ending script..."); \ No newline at end of file diff --git a/solidity/falcon/deterministic_falcon_sign.js b/solidity/falcon/deterministic_falcon_sign.js new file mode 100644 index 0000000..9ea623e --- /dev/null +++ b/solidity/falcon/deterministic_falcon_sign.js @@ -0,0 +1,124 @@ +const fs = require('fs'); +const Module = require('./falcon.js'); + +// --- Get arguments from command line --- +// Expected usage: node test_falcon.js <32_byte_seed_hex> +const args = process.argv.slice(2); // Slice to get only the actual arguments + +if (args.length < 2) { + console.error("Usage: node test_falcon.js <32_byte_seed_hex> "); + process.exit(1); +} + +const seedHexInput = args[0]; +const messageHexInput = args[1]; + +// Validate seed length (must be 32 bytes = 64 hex characters) +if (seedHexInput.length !== 64) { + console.error("Error: Seed must be 32 bytes (64 hex characters)."); + process.exit(1); +} + +// Convert seed and message hex strings to Buffers +const seed = Buffer.from(seedHexInput, "hex"); +const message = Buffer.from(messageHexInput.startsWith("0x") ? messageHexInput.slice(2) : messageHexInput, "hex"); + +// --- Main FALCON Module execution --- +Module().then((falcon) => { + const pkLen = 897; + const skLen = 1281; + const sigMaxLen = 690; + const seedLen = 32; // This is now enforced by input validation + + // Allocate memory + const pkPtr = falcon._malloc(pkLen); + const skPtr = falcon._malloc(skLen); + const msgPtr = falcon._malloc(message.length); + const seedPtr = falcon._malloc(seedLen); + + falcon.HEAPU8.set(message, msgPtr); + falcon.HEAPU8.set(seed, seedPtr); + + // Generate keypair using the provided seed + falcon.ccall( + 'crypto_keypair', + 'number', + ['number', 'number', 'number'], + [pkPtr, skPtr, seedPtr] + ); + + console.log("๐Ÿ”‘ Message (hex):", message.toString("hex")); + + // The secretKey and publicKey are extracted from WASM memory. + // Note: The secretKey buffer here might include padding or other data + // depending on how crypto_keypair lays out data. For actual use, + // ensure you know the exact layout if you need to store/retrieve it. + const secretKey = Buffer.from(falcon.HEAPU8.subarray(skPtr, skPtr + skLen)); + console.log("๐Ÿ”‘ Secret Key (hex):", secretKey.toString("hex")); + + const publicKey = Buffer.from(falcon.HEAPU8.subarray(pkPtr, pkPtr + pkLen)); + console.log("๐Ÿ”‘ Public Key (base64):", publicKey.toString("base64")); + console.log("๐Ÿ”‘ Public Key (hex):", publicKey.toString("hex")); + + // Sign the message + const signedMsgMaxLen = message.length + sigMaxLen; + const signedMsgPtr = falcon._malloc(signedMsgMaxLen); + const signedMsgLenPtr = falcon._malloc(8); // 64-bit space + + const signRet = falcon._crypto_sign( + signedMsgPtr, + signedMsgLenPtr, + msgPtr, + BigInt(message.length), + skPtr + ); + + if (signRet !== 0) { + console.error("โŒ Signing failed."); + // Free memory before exiting on error + [pkPtr, skPtr, msgPtr, seedPtr, signedMsgPtr, signedMsgLenPtr].forEach(ptr => falcon._free(ptr)); + return; + } + + // Read 64-bit signature length (low + high) + function readUint64(ptr) { + const low = falcon.HEAPU32[ptr >> 2]; + const high = falcon.HEAPU32[(ptr >> 2) + 1]; + return BigInt(high) << 32n | BigInt(low); + } + + const sigLen = Number(readUint64(signedMsgLenPtr)); + const signedMessage = Buffer.from(falcon.HEAPU8.subarray(signedMsgPtr, signedMsgPtr + sigLen)); + + console.log("โœ… Signature generated."); + console.log("๐Ÿ” Sig+Msg (base64):", signedMessage.toString("base64")); + console.log("๐Ÿ” Sig+Msg (hexa):", signedMessage.toString("hex")); + + // Verify the message + const recoveredMsgPtr = falcon._malloc(sigLen); // Max length of recovered message is sigLen (signed message length) + const recoveredLenPtr = falcon._malloc(8); + + const verifyRet = falcon._crypto_sign_open( + recoveredMsgPtr, + recoveredLenPtr, + signedMsgPtr, + BigInt(sigLen), + pkPtr + ); + + if (verifyRet === 0) { + const recLen = Number(readUint64(recoveredLenPtr)); + const recoveredMessage = Buffer.from(falcon.HEAPU8.subarray(recoveredMsgPtr, recoveredMsgPtr + recLen)); + console.log("โœ… Verification success."); + console.log("๐Ÿ“ฆ Recovered message (hex):", recoveredMessage.toString("hex")); + console.log("๐Ÿงช Match:", message.equals(recoveredMessage)); + } else { + console.error("โŒ Signature verification failed."); + } + + // Free memory + [pkPtr, skPtr, msgPtr, seedPtr, signedMsgPtr, signedMsgLenPtr, recoveredMsgPtr, recoveredLenPtr] + .forEach(ptr => falcon._free(ptr)); +}).catch(error => { + console.error("An error occurred during FALCON module initialization or execution:", error); +}); From 17d9bed0e7a958a66f6f64e5456e23d0dabc7cff Mon Sep 17 00:00:00 2001 From: renaud dubois Date: Sat, 31 May 2025 19:05:47 +0200 Subject: [PATCH 09/10] adding ecdsa raw --- solidity/falcon/deterministic_ecdsa_sign.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/solidity/falcon/deterministic_ecdsa_sign.js b/solidity/falcon/deterministic_ecdsa_sign.js index 96956aa..aef02b1 100644 --- a/solidity/falcon/deterministic_ecdsa_sign.js +++ b/solidity/falcon/deterministic_ecdsa_sign.js @@ -13,6 +13,8 @@ if (args.length < 2) { const deterministicSeedInput = args[0]; const message = args[1]; // The message is now taken directly from the second argument + + // Validate seed length (must be 32 bytes = 64 hex characters) if (deterministicSeedInput.length !== 64 || !/^[0-9a-fA-F]{64}$/.test(deterministicSeedInput)) { console.error("Error: Seed must be a 32-byte (64 hex characters) hexadecimal string."); @@ -31,6 +33,8 @@ async function signMessage() { const messageHash = hashMessage(message); const signature = await wallet.signMessage(message); + const signatureObject= wallet.signingKey.sign(messageHash); + const signature2 = signatureObject.serialized; const recoveredAddress = recoverAddress(messageHash, signature); // Helper to parse the signature @@ -57,6 +61,8 @@ async function signMessage() { console.log("Wallet Address: ", wallet.address); console.log("Message Hash: ", messageHash); console.log("Signature: ", signature); + console.log("Signature: ", signature2); + console.log("r (signature): ", sig.r); console.log("s (signature): ", sig.s); console.log("v (signature): ", sig.v); From c639009c2790f41aed8c2a7a6c28512593817064 Mon Sep 17 00:00:00 2001 From: renaud dubois Date: Sat, 31 May 2025 20:24:17 +0200 Subject: [PATCH 10/10] option --publickeyonly and signature only for falcon signer --- solidity/falcon/README.md | 23 ++- solidity/falcon/deterministic_falcon_sign.js | 147 +++++++++++++------ 2 files changed, 123 insertions(+), 47 deletions(-) diff --git a/solidity/falcon/README.md b/solidity/falcon/README.md index 6732f77..8cbe21b 100644 --- a/solidity/falcon/README.md +++ b/solidity/falcon/README.md @@ -23,7 +23,28 @@ source ./emsdk_env.sh make js node test_falcon.js ``` -An example of use (key generation, sign and verify) is provided in test_example.js +A reference example of use (key generation, sign and verify) is provided in test_falcon.js, it corresponds to the solidity test vector. + + + +### Interact with the smart contracts + +Use deterministic_falcon_sign to deterministically generate a key pair from seed and sign. Input are the 32 bytes seed and the hexadecimal value of the hash of the message to sign. + ```bash +Usage: deterministic_falcon_sign.js <32_byte_seed_hex> [--output-signature-only | --output-publickey-only] + ``` + +Output only the public key (second argument is useless but shall be provided): + + ```bash +node deterministic_falcon_sign.js 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef 0x50b2c43fd39106bafbba0da34fc430e1f91e3c96ea2acee2bc34119f92b37750 --output-publickey-only + ``` + +Then, using the same seed, use it to produce signature for messages + + ```bash +node deterministic_falcon_sign.js 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef 0x50b2c43fd39106bafbba0da34fc430e1f91e3c96ea2acee2bc34119f92b37750 --output-signature-only + ``` ## Go bindings diff --git a/solidity/falcon/deterministic_falcon_sign.js b/solidity/falcon/deterministic_falcon_sign.js index 9ea623e..4a905d0 100644 --- a/solidity/falcon/deterministic_falcon_sign.js +++ b/solidity/falcon/deterministic_falcon_sign.js @@ -1,17 +1,46 @@ +// Filename: test_falcon.js (modified) + const fs = require('fs'); -const Module = require('./falcon.js'); +const Module = require('./falcon.js'); // Ensure falcon.js is in the same directory // --- Get arguments from command line --- -// Expected usage: node test_falcon.js <32_byte_seed_hex> -const args = process.argv.slice(2); // Slice to get only the actual arguments +// Expected usage: +// node test_falcon.js <32_byte_seed_hex> +// node test_falcon.js <32_byte_seed_hex> --output-signature-only +// node test_falcon.js <32_byte_seed_hex> --output-publickey-only + +const args = process.argv.slice(2); -if (args.length < 2) { - console.error("Usage: node test_falcon.js <32_byte_seed_hex> "); +let seedHexInput; +let messageHexInput; +let outputSignatureOnly = false; +let outputPublicKeyOnly = false; + +// Basic argument parsing +if (args.length < 2 || args.length > 3) { + console.error("Usage: node test_falcon.js <32_byte_seed_hex> [--output-signature-only | --output-publickey-only]"); process.exit(1); } -const seedHexInput = args[0]; -const messageHexInput = args[1]; +seedHexInput = args[0]; +messageHexInput = args[1]; + +if (args.length === 3) { + if (args[2] === "--output-signature-only") { + outputSignatureOnly = true; + } else if (args[2] === "--output-publickey-only") { + outputPublicKeyOnly = true; + } else { + console.error("Error: Invalid third argument. Use '--output-signature-only' or '--output-publickey-only' or omit it."); + process.exit(1); + } +} + +// Ensure flags are mutually exclusive +if (outputSignatureOnly && outputPublicKeyOnly) { + console.error("Error: Cannot use both '--output-signature-only' and '--output-publickey-only' simultaneously."); + process.exit(1); +} // Validate seed length (must be 32 bytes = 64 hex characters) if (seedHexInput.length !== 64) { @@ -28,15 +57,13 @@ Module().then((falcon) => { const pkLen = 897; const skLen = 1281; const sigMaxLen = 690; - const seedLen = 32; // This is now enforced by input validation + const seedLen = 32; - // Allocate memory + // Allocate memory for key pair const pkPtr = falcon._malloc(pkLen); const skPtr = falcon._malloc(skLen); - const msgPtr = falcon._malloc(message.length); const seedPtr = falcon._malloc(seedLen); - falcon.HEAPU8.set(message, msgPtr); falcon.HEAPU8.set(seed, seedPtr); // Generate keypair using the provided seed @@ -47,18 +74,31 @@ Module().then((falcon) => { [pkPtr, skPtr, seedPtr] ); - console.log("๐Ÿ”‘ Message (hex):", message.toString("hex")); + const publicKey = Buffer.from(falcon.HEAPU8.subarray(pkPtr, pkPtr + pkLen)); - // The secretKey and publicKey are extracted from WASM memory. - // Note: The secretKey buffer here might include padding or other data - // depending on how crypto_keypair lays out data. For actual use, - // ensure you know the exact layout if you need to store/retrieve it. - const secretKey = Buffer.from(falcon.HEAPU8.subarray(skPtr, skPtr + skLen)); - console.log("๐Ÿ”‘ Secret Key (hex):", secretKey.toString("hex")); + if (outputPublicKeyOnly) { + // --- CRUCIAL LINE FOR PUBLIC KEY EXTRACTION --- + console.log(publicKey.toString("hex")); + // Free memory before exiting + [pkPtr, skPtr, seedPtr].forEach(ptr => falcon._free(ptr)); + return; // Exit script after outputting public key + } + + // --- Normal / Signature Output Path --- + // Allocate memory for message + const msgPtr = falcon._malloc(message.length); + falcon.HEAPU8.set(message, msgPtr); + + + // Conditional console logs for human readability + if (!outputSignatureOnly) { // This means either no flag or --output-publickey-only was NOT set + console.log("๐Ÿ”‘ Message (hex):", message.toString("hex")); + const secretKey = Buffer.from(falcon.HEAPU8.subarray(skPtr, skPtr + skLen)); + console.log("๐Ÿ”‘ Secret Key (hex):", secretKey.toString("hex")); + console.log("๐Ÿ”‘ Public Key (base64):", publicKey.toString("base64")); + console.log("๐Ÿ”‘ Public Key (hex):", publicKey.toString("hex")); // Full output includes hex PK + } - const publicKey = Buffer.from(falcon.HEAPU8.subarray(pkPtr, pkPtr + pkLen)); - console.log("๐Ÿ”‘ Public Key (base64):", publicKey.toString("base64")); - console.log("๐Ÿ”‘ Public Key (hex):", publicKey.toString("hex")); // Sign the message const signedMsgMaxLen = message.length + sigMaxLen; @@ -77,7 +117,7 @@ Module().then((falcon) => { console.error("โŒ Signing failed."); // Free memory before exiting on error [pkPtr, skPtr, msgPtr, seedPtr, signedMsgPtr, signedMsgLenPtr].forEach(ptr => falcon._free(ptr)); - return; + process.exit(1); // Exit with error code } // Read 64-bit signature length (low + high) @@ -90,35 +130,50 @@ Module().then((falcon) => { const sigLen = Number(readUint64(signedMsgLenPtr)); const signedMessage = Buffer.from(falcon.HEAPU8.subarray(signedMsgPtr, signedMsgPtr + sigLen)); - console.log("โœ… Signature generated."); - console.log("๐Ÿ” Sig+Msg (base64):", signedMessage.toString("base64")); - console.log("๐Ÿ” Sig+Msg (hexa):", signedMessage.toString("hex")); + if (!outputSignatureOnly) { + console.log("โœ… Signature generated."); + console.log("๐Ÿ” Sig+Msg (base64):", signedMessage.toString("base64")); + } - // Verify the message - const recoveredMsgPtr = falcon._malloc(sigLen); // Max length of recovered message is sigLen (signed message length) - const recoveredLenPtr = falcon._malloc(8); + // --- CRUCIAL LINE FOR SIGNATURE EXTRACTION (when outputSignatureOnly is true) --- + // When outputSignatureOnly is true, this is the ONLY output + if (outputSignatureOnly) { + console.log(signedMessage.toString("hex")); + } - const verifyRet = falcon._crypto_sign_open( - recoveredMsgPtr, - recoveredLenPtr, - signedMsgPtr, - BigInt(sigLen), - pkPtr - ); - if (verifyRet === 0) { - const recLen = Number(readUint64(recoveredLenPtr)); - const recoveredMessage = Buffer.from(falcon.HEAPU8.subarray(recoveredMsgPtr, recoveredMsgPtr + recLen)); - console.log("โœ… Verification success."); - console.log("๐Ÿ“ฆ Recovered message (hex):", recoveredMessage.toString("hex")); - console.log("๐Ÿงช Match:", message.equals(recoveredMessage)); - } else { - console.error("โŒ Signature verification failed."); + // Verify the message + if (!outputSignatureOnly) { // Only verify if not in "signature only" mode + const recoveredMsgPtr = falcon._malloc(sigLen); // Max length of recovered message is sigLen (signed message length) + const recoveredLenPtr = falcon._malloc(8); + + const verifyRet = falcon._crypto_sign_open( + recoveredMsgPtr, + recoveredLenPtr, + signedMsgPtr, + BigInt(sigLen), + pkPtr + ); + + if (verifyRet === 0) { + const recLen = Number(readUint64(recoveredLenPtr)); + const recoveredMessage = Buffer.from(falcon.HEAPU8.subarray(recoveredMsgPtr, recoveredMsgPtr + recLen)); + console.log("โœ… Verification success."); + console.log("๐Ÿ“ฆ Recovered message (hex):", recoveredMessage.toString("hex")); + console.log("๐Ÿงช Match:", message.equals(recoveredMessage)); + } else { + console.error("โŒ Signature verification failed."); + } + + // Free memory for verification parts + [recoveredMsgPtr, recoveredLenPtr].forEach(ptr => falcon._free(ptr)); } - // Free memory - [pkPtr, skPtr, msgPtr, seedPtr, signedMsgPtr, signedMsgLenPtr, recoveredMsgPtr, recoveredLenPtr] + // Free all remaining memory + [pkPtr, skPtr, msgPtr, seedPtr, signedMsgPtr, signedMsgLenPtr] .forEach(ptr => falcon._free(ptr)); + }).catch(error => { console.error("An error occurred during FALCON module initialization or execution:", error); -}); + process.exit(1); // Exit with error code +}); \ No newline at end of file