@@ -25,28 +25,54 @@ describe("Schnorr256", () => {
2525 return ethers . solidityPacked ( [ "uint256" , "uint256" ] , [ p . x , p . y ] ) ;
2626 } ;
2727
28- const schnorrSign = function ( hashedMessage : string , privKey : bigint ) {
28+ const schnorrSign = function ( hashedMessage : string , privKey : bigint , pubKey : AffinePoint < bigint > ) {
2929 const randomness = schnorrKeyPair ( ) ;
3030 const k = randomness . privKey ;
3131 const R = randomness . pubKey ;
3232
3333 const c = BigInt (
3434 ethers . solidityPackedKeccak256 (
3535 [ "uint256" , "uint256" , "uint256" , "uint256" , "bytes32" ] ,
36- [ secp256k1 . CURVE . Gx , secp256k1 . CURVE . Gy , R . x , R . y , hashedMessage ] ,
36+ [ pubKey . x , pubKey . y , R . x , R . y , hashedMessage ] ,
3737 ) ,
3838 ) ;
3939 const e = ( k + c * privKey ) % secp256k1 . CURVE . n ;
4040
4141 return ethers . solidityPacked ( [ "uint256" , "uint256" , "uint256" ] , [ R . x , R . y , e ] ) ;
4242 } ;
4343
44+ const schnorrAdaptorSign = function (
45+ hashedMessage : string ,
46+ privKey : bigint ,
47+ pubKey : AffinePoint < bigint > ,
48+ T : AffinePoint < bigint > ,
49+ ) {
50+ const randomness = schnorrKeyPair ( ) ;
51+ const k = randomness . privKey ;
52+ const R = randomness . pubKey ;
53+
54+ const RT = secp256k1 . ProjectivePoint . fromAffine ( R ) . add ( secp256k1 . ProjectivePoint . fromAffine ( T ) ) . toAffine ( ) ;
55+
56+ const c = BigInt (
57+ ethers . solidityPackedKeccak256 (
58+ [ "uint256" , "uint256" , "uint256" , "uint256" , "bytes32" ] ,
59+ [ pubKey . x , pubKey . y , RT . x , RT . y , hashedMessage ] ,
60+ ) ,
61+ ) ;
62+
63+ const e = ( k + c * privKey ) % secp256k1 . CURVE . n ;
64+
65+ const signature = ethers . solidityPacked ( [ "uint256" , "uint256" , "uint256" ] , [ R . x , R . y , e ] ) ;
66+
67+ return { signature, RT , e } ;
68+ } ;
69+
4470 const prepareParameters = function ( message : string ) {
4571 const { privKey, pubKey } = schnorrKeyPair ( ) ;
4672
4773 const hashedMessage = ethers . keccak256 ( message ) ;
4874
49- const signature = schnorrSign ( hashedMessage , privKey ) ;
75+ const signature = schnorrSign ( hashedMessage , privKey , pubKey ) ;
5076
5177 return {
5278 hashedMessage,
@@ -108,4 +134,80 @@ describe("Schnorr256", () => {
108134 expect ( await schnorr . verifySECP256k1 ( hashedMessage , signature , wrongPubKey ) ) . to . be . false ;
109135 } ) ;
110136 } ) ;
137+
138+ describe ( "adaptorVerify" , ( ) => {
139+ it ( "should verify the adaptor signature" , async ( ) => {
140+ const { privKey, pubKey } = schnorrKeyPair ( ) ;
141+
142+ const hashedMessage = ethers . keccak256 ( "0x1337" ) ;
143+
144+ const t = bytesToNumberBE ( secp256k1 . utils . randomPrivateKey ( ) ) ;
145+ const T = secp256k1 . ProjectivePoint . BASE . multiply ( t ) . toAffine ( ) ;
146+
147+ const { signature } = schnorrAdaptorSign ( hashedMessage , privKey , pubKey , T ) ;
148+
149+ expect ( await schnorr . adaptorVerifySECP256k1 ( hashedMessage , signature , serializePoint ( pubKey ) , T ) ) . to . be . true ;
150+ } ) ;
151+
152+ it ( "should not verify if adaptor signature or public key or T is invalid" , async ( ) => {
153+ const { privKey, pubKey } = schnorrKeyPair ( ) ;
154+
155+ const hashedMessage = ethers . keccak256 ( "0x1337" ) ;
156+
157+ const t = bytesToNumberBE ( secp256k1 . utils . randomPrivateKey ( ) ) ;
158+ const t2 = bytesToNumberBE ( secp256k1 . utils . randomPrivateKey ( ) ) ;
159+
160+ const T = secp256k1 . ProjectivePoint . BASE . multiply ( t ) . toAffine ( ) ;
161+ const T2 = secp256k1 . ProjectivePoint . BASE . multiply ( t2 ) . toAffine ( ) ;
162+
163+ const { signature } = schnorrAdaptorSign ( hashedMessage , privKey , pubKey , T ) ;
164+
165+ expect ( await schnorr . adaptorVerifySECP256k1 ( ethers . keccak256 ( "0x1227" ) , signature , serializePoint ( pubKey ) , T ) ) . to
166+ . be . false ;
167+
168+ expect ( await schnorr . adaptorVerifySECP256k1 ( hashedMessage , signature , serializePoint ( pubKey ) , T2 ) ) . to . be . false ;
169+
170+ const wrongPubKey = "0x" + ethers . toBeHex ( 0 , 0x40 ) . slice ( 2 ) ;
171+ expect ( await schnorr . adaptorVerifySECP256k1 ( hashedMessage , signature , wrongPubKey , T ) ) . to . be . false ;
172+ } ) ;
173+ } ) ;
174+
175+ describe ( "extract" , ( ) => {
176+ it ( "should extract secret from two signatures correctly" , async ( ) => {
177+ const { privKey, pubKey } = schnorrKeyPair ( ) ;
178+
179+ const hashedMessage = ethers . keccak256 ( "0x1337" ) ;
180+
181+ const t = bytesToNumberBE ( secp256k1 . utils . randomPrivateKey ( ) ) ;
182+ const T = secp256k1 . ProjectivePoint . BASE . multiply ( t ) . toAffine ( ) ;
183+
184+ const { signature : adaptorSignature , RT , e } = schnorrAdaptorSign ( hashedMessage , privKey , pubKey , T ) ;
185+
186+ const signatureScalar = ( e + t ) % secp256k1 . CURVE . n ;
187+
188+ const signature = ethers . solidityPacked ( [ "uint256" , "uint256" , "uint256" ] , [ RT . x , RT . y , signatureScalar ] ) ;
189+
190+ expect ( await schnorr . extractSECP256k1 ( signature , adaptorSignature ) ) . to . be . eq ( t ) ;
191+ } ) ;
192+
193+ it ( "should revert if invalid signature or adaptor signature scalar is provided" , async ( ) => {
194+ const signature = ethers . solidityPacked ( [ "uint256" , "uint256" , "uint256" ] , [ 1n , 1n , 10n ] ) ;
195+ const adaptorSignature = ethers . solidityPacked ( [ "uint256" , "uint256" , "uint256" ] , [ 1n , 1n , 2n ] ) ;
196+
197+ const invalidSignature = ethers . solidityPacked ( [ "uint256" , "uint256" , "uint256" ] , [ 1n , 1n , secp256k1 . CURVE . n ] ) ;
198+ const invalidAdaptorSignature = ethers . solidityPacked (
199+ [ "uint256" , "uint256" , "uint256" ] ,
200+ [ 1n , 1n , secp256k1 . CURVE . n ] ,
201+ ) ;
202+
203+ await expect ( schnorr . extractSECP256k1 ( invalidSignature , adaptorSignature ) ) . to . be . revertedWithCustomError (
204+ schnorr ,
205+ "InvalidSignatureScalar" ,
206+ ) ;
207+ await expect ( schnorr . extractSECP256k1 ( signature , invalidAdaptorSignature ) ) . to . be . revertedWithCustomError (
208+ schnorr ,
209+ "InvalidSignatureScalar" ,
210+ ) ;
211+ } ) ;
212+ } ) ;
111213} ) ;
0 commit comments