11import 'dart:typed_data' ;
2+ import 'package:coinlib/src/crypto/random.dart' ;
23import 'heap.dart' ;
34
45class Secp256k1Exception implements Exception {
@@ -14,15 +15,15 @@ class SigWithRecId {
1415 SigWithRecId (this .signature, this .recid);
1516}
1617
17- class MuSigCacheGeneric < MuSigAggCachePtr > {
18- final Heap <MuSigAggCachePtr > _cache ;
19- MuSigCacheGeneric (this ._cache );
18+ class OpaqueGeneric < Ptr > {
19+ final Heap <Ptr > _heap ;
20+ OpaqueGeneric (this ._heap );
2021}
2122
2223abstract class Secp256k1Base <
2324 CtxPtr , UCharPtr , PubKeyPtr , SizeTPtr , SignaturePtr ,
2425 RecoverableSignaturePtr , KeyPairPtr , XPubKeyPtr , IntPtr , MuSigAggCachePtr ,
25- PubKeyPtrPtr , NullPtr
26+ PubKeyPtrPtr , MuSigSecNoncePtr , MuSigPubNoncePtr , NullPtr
2627> {
2728
2829 static const contextNone = 1 ;
@@ -36,6 +37,7 @@ abstract class Secp256k1Base<
3637 static const uncompressedPubkeySize = 65 ;
3738 static const sigSize = 64 ;
3839 static const derSigSize = 72 ;
40+ static const muSigPubNonceSize = 66 ;
3941 static const recSigSize = 65 ;
4042 static const keyPairSize = 96 ;
4143 static const xonlySize = 32 ;
@@ -107,6 +109,13 @@ abstract class Secp256k1Base<
107109 late int Function (
108110 CtxPtr , PubKeyPtr , MuSigAggCachePtr , UCharPtr ,
109111 ) extMuSigPubkeyXOnlyTweakAdd;
112+ late int Function (
113+ CtxPtr , MuSigSecNoncePtr , MuSigPubNoncePtr , UCharPtr , NullPtr , PubKeyPtr ,
114+ NullPtr , NullPtr , NullPtr ,
115+ ) extMuSigNonceGen;
116+ late int Function (
117+ CtxPtr , UCharPtr , MuSigPubNoncePtr ,
118+ ) extMuSigPubNonceSerialize;
110119
111120 // Heap arrays
112121
@@ -119,6 +128,7 @@ abstract class Secp256k1Base<
119128 late HeapBytes <UCharPtr > entropyArray;
120129 late HeapBytes <UCharPtr > serializedSigArray;
121130 late HeapBytes <UCharPtr > derSigArray;
131+ late HeapBytes <UCharPtr > muSigPubNonceArray;
122132
123133 // Other pre-allocated heap objects
124134 late Heap <PubKeyPtr > pubKey;
@@ -128,6 +138,7 @@ abstract class Secp256k1Base<
128138 late Heap <KeyPairPtr > keyPair;
129139 late Heap <XPubKeyPtr > xPubKey;
130140 late HeapInt <IntPtr > recId;
141+ late Heap <MuSigPubNoncePtr > muSigPubNonce;
131142
132143 // Context pointer is allocated by underlying library
133144 late CtxPtr ctxPtr;
@@ -473,6 +484,7 @@ abstract class Secp256k1Base<
473484
474485 _parsePrivKeyIntoKeyPairPtr (privKey);
475486 hashArray.load (hash);
487+ if (extraEntropy != null ) entropyArray.load (extraEntropy);
476488
477489 if (
478490 extSchnorrSign32 (
@@ -528,7 +540,7 @@ abstract class Secp256k1Base<
528540 ///
529541 /// Returns the aggregated public key bytes and an opaque object for the MuSig
530542 /// aggregation cache used for signing.
531- (Uint8List , MuSigCacheGeneric <MuSigAggCachePtr >) muSigAgggregate (
543+ (Uint8List , OpaqueGeneric <MuSigAggCachePtr >) muSigAgggregate (
532544 List <Uint8List > pubKeysBytes,
533545 ) {
534546 _requireLoad ();
@@ -556,23 +568,23 @@ abstract class Secp256k1Base<
556568 throw Secp256k1Exception ("Couldn't aggregate public keys for MuSig2" );
557569 }
558570
559- return (_serializeXPubKeyFromPtr (), MuSigCacheGeneric (musigCache));
571+ return (_serializeXPubKeyFromPtr (), OpaqueGeneric (musigCache));
560572
561573 }
562574
563575 /// Tweaks the aggregate MuSig key returning the new aggregate key and cache.
564576 /// The new cache is a new object. The previous cache is not valid for the
565577 /// tweaked key
566- (Uint8List , MuSigCacheGeneric <MuSigAggCachePtr >) muSigTweakXOnly (
567- MuSigCacheGeneric <MuSigAggCachePtr > cache,
578+ (Uint8List , OpaqueGeneric <MuSigAggCachePtr >) muSigTweakXOnly (
579+ OpaqueGeneric <MuSigAggCachePtr > cache,
568580 Uint8List scalar,
569581 ) {
570582 _requireLoad ();
571583
572584 scalarArray.load (scalar);
573585
574586 // Copy cache to avoid side-effects
575- final newCache = copyMuSigCache (cache._cache .ptr);
587+ final newCache = copyMuSigCache (cache._heap .ptr);
576588
577589 if (
578590 extMuSigPubkeyXOnlyTweakAdd (
@@ -582,7 +594,45 @@ abstract class Secp256k1Base<
582594 throw Secp256k1Exception ("Couldn't apply tweak to MuSig key" );
583595 }
584596
585- return (_serializePubKeyFromPtr (true ), MuSigCacheGeneric (newCache));
597+ return (_serializePubKeyFromPtr (true ), OpaqueGeneric (newCache));
598+
599+ }
600+
601+ /// Generates and returns an opaque secret and serialised public nonce for
602+ /// a MuSig signing session. This produces a unique nonce each time.
603+ ///
604+ /// The nonce must only be used once for a single signing session and
605+ /// discarded after the signing session succeeds or fails for any reason.
606+ ///
607+ /// The [pubKeyBytes] must be the compressed or uncompressed public key used
608+ /// by the signer.
609+ (OpaqueGeneric <MuSigSecNoncePtr >, Uint8List ) muSigGenerateNonce (
610+ Uint8List pubKeyBytes,
611+ ) {
612+ _requireLoad ();
613+
614+ _parsePubkeyIntoPtr (pubKeyBytes);
615+ entropyArray.load (generateRandomBytes (32 ));
616+
617+ final secNonce = allocMuSigSecNonce ();
618+
619+ if (
620+ extMuSigNonceGen (
621+ ctxPtr, secNonce.ptr, muSigPubNonce.ptr, entropyArray.ptr, nullPtr,
622+ pubKey.ptr, nullPtr, nullPtr, nullPtr,
623+ ) != 1
624+ ) {
625+ throw Secp256k1Exception ("Couldn't generate MuSig nonce for key" );
626+ }
627+
628+ extMuSigPubNonceSerialize (
629+ ctxPtr, muSigPubNonceArray.ptr, muSigPubNonce.ptr,
630+ );
631+
632+ return (
633+ OpaqueGeneric (secNonce),
634+ Uint8List .fromList (muSigPubNonceArray.list),
635+ );
586636
587637 }
588638
@@ -600,4 +650,8 @@ abstract class Secp256k1Base<
600650 /// struct into it.
601651 Heap <MuSigAggCachePtr > copyMuSigCache (MuSigAggCachePtr copyFrom);
602652
653+ /// Specialised sub-classes should override to allocate an
654+ /// secp256k1_musig_secnonce on the heap.
655+ Heap <MuSigSecNoncePtr > allocMuSigSecNonce ();
656+
603657}
0 commit comments