@@ -25,6 +25,7 @@ module Crypto.Secp256k1 (
2525 KeyPair ,
2626 Signature ,
2727 RecoverableSignature ,
28+ SchnorrSignature ,
2829 Tweak ,
2930
3031 -- * Parsing and Serialization
@@ -40,6 +41,8 @@ module Crypto.Secp256k1 (
4041 exportSignatureDer ,
4142 importRecoverableSignature ,
4243 exportRecoverableSignature ,
44+ importSchnorrSignature ,
45+ exportSchnorrSignature ,
4346 importTweak ,
4447
4548 -- * ECDSA Operations
@@ -283,6 +286,28 @@ instance NFData Signature where
283286 rnf Signature {.. } = seq signatureFPtr ()
284287
285288
289+ -- | Structure containing Schnorr Signature
290+ newtype SchnorrSignature = SchnorrSignature { schnorrSignatureFPtr :: ForeignPtr Prim. Sig64}
291+
292+
293+ instance Show SchnorrSignature where
294+ show sig = (B8. unpack . encodeBase16) (exportSchnorrSignature sig)
295+ instance Read SchnorrSignature where
296+ readsPrec i cs = case decodeBase16 $ B8. pack token of
297+ Left e -> []
298+ Right a -> maybeToList $ (,rest) <$> importSchnorrSignature a
299+ where
300+ trimmed = dropWhile isSpace cs
301+ (token, rest) = span isAlphaNum trimmed
302+ instance Eq SchnorrSignature where
303+ sig == sig' = unsafePerformIO . evalContT $ do
304+ sigp <- ContT $ withForeignPtr (schnorrSignatureFPtr sig)
305+ sigp' <- ContT $ withForeignPtr (schnorrSignatureFPtr sig')
306+ (EQ == ) <$> lift (memCompare (castPtr sigp) (castPtr sigp') 64 )
307+ instance NFData SchnorrSignature where
308+ rnf SchnorrSignature {.. } = seq schnorrSignatureFPtr ()
309+
310+
286311-- | Structure containing Signature AND recovery ID
287312newtype RecoverableSignature = RecoverableSignature { recoverableSignatureFPtr :: ForeignPtr Prim. RecSig65}
288313
@@ -493,6 +518,23 @@ exportRecoverableSignature RecoverableSignature{..} = unsafePerformIO . evalCont
493518 unsafePackByteString (outBuf, 65 )
494519
495520
521+ -- | Parses 'SchnorrSignature' from Schnorr (64 byte) representation
522+ importSchnorrSignature :: ByteString -> Maybe SchnorrSignature
523+ importSchnorrSignature bs
524+ | BS. length bs /= 64 = Nothing
525+ | otherwise = unsafePerformIO $ do
526+ outBuf <- mallocBytes 64
527+ unsafeUseByteString bs $ \ (ptr, _) -> do
528+ memcpy outBuf ptr 64
529+ Just . SchnorrSignature <$> newForeignPtr finalizerFree outBuf
530+
531+
532+ -- | Serializes 'SchnorrSignature' to Schnorr (64 byte) representation
533+ exportSchnorrSignature :: SchnorrSignature -> ByteString
534+ exportSchnorrSignature (SchnorrSignature fptr) = unsafePerformIO $
535+ withForeignPtr fptr $ \ ptr -> BS. packCStringLen (castPtr ptr, 64 )
536+
537+
496538-- | Parses 'Tweak' from 32 byte @ByteString@. If the @ByteString@ is an invalid 'SecKey' then this will yield @Nothing@
497539importTweak :: ByteString -> Maybe Tweak
498540importTweak = fmap (Tweak . castForeignPtr . secKeyFPtr) . importSecKey
@@ -702,7 +744,7 @@ keyPairPubKeyXOTweakAdd KeyPair{..} Tweak{..} = unsafePerformIO . evalContT $ do
702744
703745-- | Compute a schnorr signature using a 'KeyPair'. The @ByteString@ must be 32 bytes long to get a @Just@ out of this
704746-- function
705- schnorrSign :: KeyPair -> ByteString -> Maybe Signature
747+ schnorrSign :: KeyPair -> ByteString -> Maybe SchnorrSignature
706748schnorrSign KeyPair {.. } bs
707749 | BS. length bs /= 32 = Nothing
708750 | otherwise = unsafePerformIO . evalContT $ do
@@ -713,17 +755,17 @@ schnorrSign KeyPair{..} bs
713755 -- TODO: provide randomness here instead of supplying a null pointer
714756 ret <- Prim. schnorrsigSign ctx sigBuf msgHashPtr keyPairPtr nullPtr
715757 if isSuccess ret
716- then Just . Signature <$> newForeignPtr finalizerFree sigBuf
758+ then Just . SchnorrSignature <$> newForeignPtr finalizerFree sigBuf
717759 else free sigBuf $> Nothing
718760
719761
720762-- | Verify the authenticity of a schnorr signature. @True@ means the 'Signature' is correct.
721- schnorrVerify :: PubKeyXO -> ByteString -> Signature -> Bool
722- schnorrVerify PubKeyXO {.. } bs Signature {.. } = unsafePerformIO . evalContT $ do
763+ schnorrVerify :: PubKeyXO -> ByteString -> SchnorrSignature -> Bool
764+ schnorrVerify PubKeyXO {.. } bs SchnorrSignature {.. } = unsafePerformIO . evalContT $ do
723765 pubKeyPtr <- ContT (withForeignPtr pubKeyXOFPtr)
724- signaturePtr <- ContT (withForeignPtr signatureFPtr )
766+ schnorrSignaturePtr <- ContT (withForeignPtr schnorrSignatureFPtr )
725767 (msgPtr, msgLen) <- ContT (unsafeUseByteString bs)
726- lift $ isSuccess <$> Prim. schnorrsigSignVerify ctx signaturePtr msgPtr msgLen pubKeyPtr
768+ lift $ isSuccess <$> Prim. schnorrsigSignVerify ctx schnorrSignaturePtr msgPtr msgLen pubKeyPtr
727769
728770
729771-- | Generate a tagged sha256 digest as specified in BIP340
0 commit comments