Skip to content

Commit c4051f6

Browse files
partial verify tested ok
1 parent 389658b commit c4051f6

File tree

3 files changed

+119
-51
lines changed

3 files changed

+119
-51
lines changed

src/libMPC/SCL_Musig2.mjs

Lines changed: 66 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,42 @@ Mulmod(a,b){
336336
return (a*b)%this.order;
337337
}
338338

339+
//operations are not constant time, not required as aggregation is a public function
340+
Partial_sig_agg(psigs, session_ctx){
341+
let sessionV=this.Get_session_values(session_ctx);//(Q, gacc, tacc, b, R, e)
342+
343+
344+
let Q=sessionV[0];//aggnonce
345+
let tacc=sessionV[2];
346+
347+
let e=sessionV[5];
348+
349+
let s = BigInt(0);
350+
let u = psigs.length;
351+
for(let i=0;i<u;i++){
352+
let s_i = int_from_bytes(psigs[i])
353+
if(s_i> this.order){
354+
return false;
355+
}
356+
s = (s + s_i) % this.order;
357+
}
358+
let g=BigInt(1);
359+
if(this.curve.Has_even_y(Q)==false)
360+
g= this.order - g;//n-1
361+
362+
363+
s = (s + e * g * tacc) % this.order;
364+
s=int_to_bytes(s,32);
365+
366+
let R=this.curve.GetX(sessionV[4]);
367+
console.log("R=",R);
368+
console.log("from ",sessionV[4]);
369+
console.log("s=",s, s.length);
370+
371+
return Buffer.concat([R,s]);
372+
373+
}
374+
339375
//partial signature
340376
//secnonce: 2 nonces + kpub
341377
//sk: 32 bytes
@@ -369,20 +405,22 @@ Psign(secnonce, sk, session_ctx){
369405
let secnonce_pk=secnonce.slice(64, 64+this.RawBytesSize);//pk is part of secnonce, 32 or 33 bytes
370406
let Q3=this.curve.PointDecompress(secnonce_pk);
371407

408+
372409
//todo test x equality
373410
if(this.curve.EqualsX(P,Q3)==false){
374411
return false;//wrong public key
375412
}
376413

377414
let a=this.Get_session_key_agg_coeff(session_ctx[1], secnonce.slice(64, 64+this.RawBytesSize));
378-
415+
416+
379417
let g=BigInt('0x1') ;
380418
if(this.curve.Has_even_y(Q)==false){//this line ensures the compatibility with requirement that aggregated key is even in verification
381419
g=this.order-g;//n-1
382420

383421
}
384422
let d = this.Mulmod(g , gacc );//d = (g * gacc * d_) % n
385-
d= this.Mulmod(d, d_);
423+
d= this.Mulmod(d, d_);//g*gacc*d
386424
let s = (k1 + this.Mulmod(b , k2) ) % this.order;//
387425
s= (s+ this.Mulmod(this.Mulmod(e , a) , d))% this.order;
388426

@@ -393,70 +431,51 @@ Psign(secnonce, sk, session_ctx){
393431
}
394432

395433

396-
//operations are not constant time, not required as aggregation is a public function
397-
Partial_sig_agg(psigs, session_ctx){
398-
let sessionV=this.Get_session_values(session_ctx);//(Q, gacc, tacc, b, R, e)
399-
400-
401-
let Q=sessionV[0];//aggnonce
402-
let tacc=sessionV[2];
403-
404-
let e=sessionV[5];
405-
406-
let s = BigInt(0);
407-
let u = psigs.length;
408-
for(let i=0;i<u;i++){
409-
let s_i = int_from_bytes(psigs[i])
410-
if(s_i> this.order){
411-
return false;
412-
}
413-
s = (s + s_i) % this.order;
414-
}
415-
let g=BigInt(1);
416-
if(this.curve.Has_even_y(Q)==false)
417-
g= this.order - g;//n-1
418-
419-
420-
s = (s + e * g * tacc) % this.order;
421-
s=int_to_bytes(s,32);
422-
423-
let R=this.curve.GetX(sessionV[4]);
424-
console.log("R=",R);
425-
console.log("from ",sessionV[4]);
426-
console.log("s=",s, s.length);
427-
428-
return Buffer.concat([R,s]);
429-
430-
}
431-
432434
/********************************************************************************************/
433435
/* VERIFICATIONS*/
434436
/********************************************************************************************/
435437

436438
//verify one of the partial signature provided by a participant
437439
Psig_verify(psig, pubnonce, pk, session_ctx){
438-
let sessionV=this.Get_session_values(session_ctx);//(Q, gacc, tacc, b, R, e)
440+
let sessionV=this.Get_session_values(session_ctx);//(Q, gacc, _, b, R, e)
439441
let s = int_from_bytes(psig);
442+
console.log("psig:", psig);
443+
let Q=sessionV[0];
444+
let gacc=sessionV[1];
445+
let b=sessionV[3];
446+
let R=sessionV[4];
447+
let e=sessionV[5];
448+
449+
440450
let R_s1 = this.curve.PointDecompress(pubnonce.slice(0,this.RawBytesSize));
441451
let R_s2 = this.curve.PointDecompress(pubnonce.slice(this.RawBytesSize,2*this.RawBytesSize));
442-
452+
443453
let Re_s_ =R_s1.add(R_s2.multiply(b));
454+
455+
let Re_s=Re_s_;
456+
457+
if(this.curve.Has_even_y(R)==false)
458+
{
459+
Re_s=Re_s.negate();//forced to even point
460+
}
461+
let P=this.curve.PointDecompress(pk);//partial input public key
444462

445-
let Re_s=this.curve.PointCompressXonly(Re_s_);//forced to even point
463+
let a=this.Get_session_key_agg_coeff(session_ctx[1], pk);//session_ctx[1]=pubkeys
446464

447465

448-
a=key_agg_coeff(session_ctx[1], pk);
449466
let g=BigInt(1);
450-
if(has_even_y(Q)==false)
451-
g=secp256k1.CURVE.n - g;//n-1
452-
let P=ProjectivePoint.fromHex(pk);//partial input public key
467+
if(this.curve.Has_even_y(Q)==false){
468+
g=this.order - g;//n-1
469+
}
453470

454471
g=(g*gacc) % this.order;
455472

456-
let G= secp256k1.ProjectivePoint.BASE;
473+
let G= this.curve.GetBase();
457474
let P1 = (G.multiply(s));
458-
let P2=Re_s.add(P.multiply((e*a*g)%this.order));
459475

476+
let tmp=this.Mulmod(e,a);
477+
tmp=this.Mulmod(tmp,g);//e*a*g % n
478+
let P2=(Re_s.add(P.multiply(tmp)));
460479

461480
return (P1.equals(P2));
462481
}

src/libMPC/SCL_ecc.mjs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ export class SCL_ecc
102102
}
103103
}
104104

105+
Force_Even(Point){//if a point has odd parity coordinates, negates it
106+
let Pc=this.PointCompressXonly(Point);
107+
return this.PointDecompressEven(Pc);
108+
}
109+
105110
EqualsX(Point1, Point2){
106111

107112
return true;

src/libMPC/test_Musig2.mjs

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ function test_nonceagg(){
182182

183183

184184
//valid test case 3, https://github.com/bitcoin/bips/blob/master/bip-0327/vectors/sig_agg_vectors.json
185-
function test_partialsig_withtweak_1(){
185+
function test_partialsig_agg_withtweak_1(){
186186
const curve = 'secp256k1';
187187
const signer = new SCL_Musig2(curve);
188188

@@ -355,6 +355,8 @@ function random_fullsession(Curve){
355355
let nonce1= signer.Nonce_gen(seckeys[0], pubkeys[0], x_aggpk, msg, extra_in);
356356
let nonce2= signer.Nonce_gen(seckeys[1], pubkeys[1], x_aggpk, msg, extra_in);
357357

358+
359+
358360
//aggregation of public nonces
359361
let aggnonce = signer.Nonce_agg([nonce1[1].toString('hex'), nonce2[1].toString('hex')]);
360362
console.log("aggnonce=", aggnonce);
@@ -364,10 +366,14 @@ function random_fullsession(Curve){
364366
console.log(" -Partial signatures");
365367

366368
let p1=signer.Psign(nonce1[0], seckeys[0], session_ctx);
369+
367370
console.log("p1=",p1);
371+
console.log("partial verify:",signer.Psig_verify(p1, nonce1[1], pubK1, session_ctx));
368372

369373
let p2=signer.Psign(nonce2[0], seckeys[1], session_ctx);
370374
console.log("p2=",p2);
375+
console.log("partial verify:",signer.Psig_verify(p2, nonce2[1], pubK2, session_ctx));
376+
371377

372378
let psigs=[p1,p2];
373379

@@ -382,7 +388,44 @@ function random_fullsession(Curve){
382388
console.log("check=", check);
383389
}
384390

391+
//extracted from 'sign_verify_vectors.json'
392+
function test_partialsig_notweak(){
393+
const curve = 'secp256k1';
394+
const signer = new SCL_Musig2(curve);
395+
396+
397+
console.log("/*************************** ");
398+
console.log("Partial sig no tweak:");
399+
400+
const pubkeys= [
401+
Buffer.from("03935F972DA013F80AE011890FA89B67A27B7BE6CCB24D3274D18B2D4067F261A9", 'hex'),
402+
Buffer.from("02F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9", 'hex'),
403+
Buffer.from("02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA661", 'hex')
404+
];
405+
406+
const secnonce=Buffer.from(
407+
"508B81A611F100A6B2B6B29656590898AF488BCF2E1F55CF22E5CFB84421FE61FA27FD49B1D50085B481285E1CA205D55C82CC1B31FF5CD54A489829355901F703935F972DA013F80AE011890FA89B67A27B7BE6CCB24D3274D18B2D4067F261A9"
408+
, 'hex');
385409

410+
const sk=Buffer.from("7FB9E0E687ADA1EEBF7ECFE2F21E73EBDB51A7D450948DFE8D76D7F2D1007671", 'hex');
411+
const aggnonce=Buffer.from("028465FCF0BBDBCF443AABCCE533D42B4B5A10966AC09A49655E8C42DAAB8FCD61037496A3CC86926D452CAFCFD55D25972CA1675D549310DE296BFF42F72EEEA8C9",'hex');
412+
const msg=Buffer.from("F95466D086770E689964664219266FE5ED215C92AE20BAB5C9D79ADDDDF3C0CF",'hex');
413+
414+
//'aggnonce','pubkeys', 'tweaks', 'is_xonly','msg';
415+
const session_ctx=[aggnonce, pubkeys, [], [], msg];
416+
const expected=Buffer.from("012ABBCB52B3016AC03AD82395A1A415C48B93DEF78718E62A7A90052FE224FB", 'hex');
417+
const pubnonce=Buffer.from("0337c87821afd50a8644d820a8f3e02e499c931865c2360fb43d0a0d20dafe07ea0287bf891d2a6deaebadc909352aa9405d1428c15f4b75f04dae642a95c2548480",'hex');
418+
let res= signer.Psign(secnonce, sk, session_ctx);
419+
420+
console.log("res=", res);
421+
422+
let verif=signer.Psig_verify(res,pubnonce, pubkeys[0],session_ctx);
423+
console.log("Partial verify:", verif);
424+
console.log("expected=", expected);
425+
426+
console.log( res.equals(expected));
427+
428+
}
386429

387430
(async () => {
388431

@@ -391,15 +434,16 @@ function random_fullsession(Curve){
391434
test_keyaggcoeff();//key aggregation is ok
392435
test_noncegen();
393436
test_nonceagg();
394-
test_partialsig_withtweak_1();
437+
test_partialsig_notweak();
438+
test_partialsig_agg_withtweak_1
395439
test_schnorrverify();
396440
unitary_fullsession_K1();
397441
test_schnorrverify2();
398442

399443
/* test full session */
400444
random_fullsession('secp256k1');
401-
402445
random_fullsession('ed25519');
403-
446+
447+
404448

405449
})();

0 commit comments

Comments
 (0)