diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:47:55 +0000 |
commit | 2aadc03ef15cb5ca5cc2af8a7c08e070742f0ac4 (patch) | |
tree | 033cc839730fda84ff08db877037977be94e5e3a /vendor/openssl/src/dsa.rs | |
parent | Initial commit. (diff) | |
download | cargo-upstream.tar.xz cargo-upstream.zip |
Adding upstream version 0.70.1+ds1.upstream/0.70.1+ds1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/openssl/src/dsa.rs')
-rw-r--r-- | vendor/openssl/src/dsa.rs | 697 |
1 files changed, 697 insertions, 0 deletions
diff --git a/vendor/openssl/src/dsa.rs b/vendor/openssl/src/dsa.rs new file mode 100644 index 0000000..1a63e8a --- /dev/null +++ b/vendor/openssl/src/dsa.rs @@ -0,0 +1,697 @@ +//! Digital Signatures +//! +//! DSA ensures a message originated from a known sender, and was not modified. +//! DSA uses asymmetrical keys and an algorithm to output a signature of the message +//! using the private key that can be validated with the public key but not be generated +//! without the private key. + +use cfg_if::cfg_if; +use foreign_types::{ForeignType, ForeignTypeRef}; +#[cfg(not(boringssl))] +use libc::c_int; +use std::fmt; +use std::mem; +use std::ptr; + +use crate::bn::{BigNum, BigNumRef}; +use crate::error::ErrorStack; +use crate::pkey::{HasParams, HasPrivate, HasPublic, Params, Private, Public}; +use crate::util::ForeignTypeRefExt; +use crate::{cvt, cvt_p}; +use openssl_macros::corresponds; + +generic_foreign_type_and_impl_send_sync! { + type CType = ffi::DSA; + fn drop = ffi::DSA_free; + + /// Object representing DSA keys. + /// + /// A DSA object contains the parameters p, q, and g. There is a private + /// and public key. The values p, g, and q are: + /// + /// * `p`: DSA prime parameter + /// * `q`: DSA sub-prime parameter + /// * `g`: DSA base parameter + /// + /// These values are used to calculate a pair of asymmetrical keys used for + /// signing. + /// + /// OpenSSL documentation at [`DSA_new`] + /// + /// [`DSA_new`]: https://www.openssl.org/docs/manmaster/crypto/DSA_new.html + /// + /// # Examples + /// + /// ``` + /// use openssl::dsa::Dsa; + /// use openssl::error::ErrorStack; + /// use openssl::pkey::Private; + /// + /// fn create_dsa() -> Result<Dsa<Private>, ErrorStack> { + /// let sign = Dsa::generate(2048)?; + /// Ok(sign) + /// } + /// # fn main() { + /// # create_dsa(); + /// # } + /// ``` + pub struct Dsa<T>; + /// Reference to [`Dsa`]. + /// + /// [`Dsa`]: struct.Dsa.html + pub struct DsaRef<T>; +} + +impl<T> Clone for Dsa<T> { + fn clone(&self) -> Dsa<T> { + (**self).to_owned() + } +} + +impl<T> ToOwned for DsaRef<T> { + type Owned = Dsa<T>; + + fn to_owned(&self) -> Dsa<T> { + unsafe { + ffi::DSA_up_ref(self.as_ptr()); + Dsa::from_ptr(self.as_ptr()) + } + } +} + +impl<T> DsaRef<T> +where + T: HasPublic, +{ + to_pem! { + /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure. + /// + /// The output will have a header of `-----BEGIN PUBLIC KEY-----`. + #[corresponds(PEM_write_bio_DSA_PUBKEY)] + public_key_to_pem, + ffi::PEM_write_bio_DSA_PUBKEY + } + + to_der! { + /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure. + #[corresponds(i2d_DSA_PUBKEY)] + public_key_to_der, + ffi::i2d_DSA_PUBKEY + } + + /// Returns a reference to the public key component of `self`. + #[corresponds(DSA_get0_key)] + pub fn pub_key(&self) -> &BigNumRef { + unsafe { + let mut pub_key = ptr::null(); + DSA_get0_key(self.as_ptr(), &mut pub_key, ptr::null_mut()); + BigNumRef::from_const_ptr(pub_key) + } + } +} + +impl<T> DsaRef<T> +where + T: HasPrivate, +{ + private_key_to_pem! { + /// Serializes the private key to a PEM-encoded DSAPrivateKey structure. + /// + /// The output will have a header of `-----BEGIN DSA PRIVATE KEY-----`. + #[corresponds(PEM_write_bio_DSAPrivateKey)] + private_key_to_pem, + /// Serializes the private key to a PEM-encoded encrypted DSAPrivateKey structure. + /// + /// The output will have a header of `-----BEGIN DSA PRIVATE KEY-----`. + #[corresponds(PEM_write_bio_DSAPrivateKey)] + private_key_to_pem_passphrase, + ffi::PEM_write_bio_DSAPrivateKey + } + + to_der! { + /// Serializes the private_key to a DER-encoded `DSAPrivateKey` structure. + #[corresponds(i2d_DSAPrivateKey)] + private_key_to_der, + ffi::i2d_DSAPrivateKey + } + + /// Returns a reference to the private key component of `self`. + #[corresponds(DSA_get0_key)] + pub fn priv_key(&self) -> &BigNumRef { + unsafe { + let mut priv_key = ptr::null(); + DSA_get0_key(self.as_ptr(), ptr::null_mut(), &mut priv_key); + BigNumRef::from_const_ptr(priv_key) + } + } +} + +impl<T> DsaRef<T> +where + T: HasParams, +{ + /// Returns the maximum size of the signature output by `self` in bytes. + #[corresponds(DSA_size)] + pub fn size(&self) -> u32 { + unsafe { ffi::DSA_size(self.as_ptr()) as u32 } + } + + /// Returns the DSA prime parameter of `self`. + #[corresponds(DSA_get0_pqg)] + pub fn p(&self) -> &BigNumRef { + unsafe { + let mut p = ptr::null(); + DSA_get0_pqg(self.as_ptr(), &mut p, ptr::null_mut(), ptr::null_mut()); + BigNumRef::from_const_ptr(p) + } + } + + /// Returns the DSA sub-prime parameter of `self`. + #[corresponds(DSA_get0_pqg)] + pub fn q(&self) -> &BigNumRef { + unsafe { + let mut q = ptr::null(); + DSA_get0_pqg(self.as_ptr(), ptr::null_mut(), &mut q, ptr::null_mut()); + BigNumRef::from_const_ptr(q) + } + } + + /// Returns the DSA base parameter of `self`. + #[corresponds(DSA_get0_pqg)] + pub fn g(&self) -> &BigNumRef { + unsafe { + let mut g = ptr::null(); + DSA_get0_pqg(self.as_ptr(), ptr::null_mut(), ptr::null_mut(), &mut g); + BigNumRef::from_const_ptr(g) + } + } +} +#[cfg(boringssl)] +type BitType = libc::c_uint; +#[cfg(not(boringssl))] +type BitType = c_int; + +impl Dsa<Params> { + /// Creates a DSA params based upon the given parameters. + #[corresponds(DSA_set0_pqg)] + pub fn from_pqg(p: BigNum, q: BigNum, g: BigNum) -> Result<Dsa<Params>, ErrorStack> { + unsafe { + let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?); + cvt(DSA_set0_pqg(dsa.0, p.as_ptr(), q.as_ptr(), g.as_ptr()))?; + mem::forget((p, q, g)); + Ok(dsa) + } + } + + /// Generates DSA params based on the given number of bits. + #[corresponds(DSA_generate_parameters_ex)] + pub fn generate_params(bits: u32) -> Result<Dsa<Params>, ErrorStack> { + ffi::init(); + unsafe { + let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?); + cvt(ffi::DSA_generate_parameters_ex( + dsa.0, + bits as BitType, + ptr::null(), + 0, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ))?; + Ok(dsa) + } + } + + /// Generates a private key based on the DSA params. + #[corresponds(DSA_generate_key)] + pub fn generate_key(self) -> Result<Dsa<Private>, ErrorStack> { + unsafe { + let dsa_ptr = self.0; + cvt(ffi::DSA_generate_key(dsa_ptr))?; + mem::forget(self); + Ok(Dsa::from_ptr(dsa_ptr)) + } + } +} + +impl Dsa<Private> { + /// Generate a DSA key pair. + /// + /// The `bits` parameter corresponds to the length of the prime `p`. + pub fn generate(bits: u32) -> Result<Dsa<Private>, ErrorStack> { + let params = Dsa::generate_params(bits)?; + params.generate_key() + } + + /// Create a DSA key pair with the given parameters + /// + /// `p`, `q` and `g` are the common parameters. + /// `priv_key` is the private component of the key pair. + /// `pub_key` is the public component of the key. Can be computed via `g^(priv_key) mod p` + pub fn from_private_components( + p: BigNum, + q: BigNum, + g: BigNum, + priv_key: BigNum, + pub_key: BigNum, + ) -> Result<Dsa<Private>, ErrorStack> { + ffi::init(); + unsafe { + let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?); + cvt(DSA_set0_pqg(dsa.0, p.as_ptr(), q.as_ptr(), g.as_ptr()))?; + mem::forget((p, q, g)); + cvt(DSA_set0_key(dsa.0, pub_key.as_ptr(), priv_key.as_ptr()))?; + mem::forget((pub_key, priv_key)); + Ok(dsa) + } + } +} + +impl Dsa<Public> { + from_pem! { + /// Decodes a PEM-encoded SubjectPublicKeyInfo structure containing a DSA key. + /// + /// The input should have a header of `-----BEGIN PUBLIC KEY-----`. + #[corresponds(PEM_read_bio_DSA_PUBKEY)] + public_key_from_pem, + Dsa<Public>, + ffi::PEM_read_bio_DSA_PUBKEY + } + + from_der! { + /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing a DSA key. + #[corresponds(d2i_DSA_PUBKEY)] + public_key_from_der, + Dsa<Public>, + ffi::d2i_DSA_PUBKEY + } + + /// Create a new DSA key with only public components. + /// + /// `p`, `q` and `g` are the common parameters. + /// `pub_key` is the public component of the key. + pub fn from_public_components( + p: BigNum, + q: BigNum, + g: BigNum, + pub_key: BigNum, + ) -> Result<Dsa<Public>, ErrorStack> { + ffi::init(); + unsafe { + let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?); + cvt(DSA_set0_pqg(dsa.0, p.as_ptr(), q.as_ptr(), g.as_ptr()))?; + mem::forget((p, q, g)); + cvt(DSA_set0_key(dsa.0, pub_key.as_ptr(), ptr::null_mut()))?; + mem::forget(pub_key); + Ok(dsa) + } + } +} + +impl<T> fmt::Debug for Dsa<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "DSA") + } +} + +cfg_if! { + if #[cfg(any(ossl110, libressl273, boringssl))] { + use ffi::{DSA_get0_key, DSA_get0_pqg, DSA_set0_key, DSA_set0_pqg}; + } else { + #[allow(bad_style)] + unsafe fn DSA_get0_pqg( + d: *mut ffi::DSA, + p: *mut *const ffi::BIGNUM, + q: *mut *const ffi::BIGNUM, + g: *mut *const ffi::BIGNUM) + { + if !p.is_null() { + *p = (*d).p; + } + if !q.is_null() { + *q = (*d).q; + } + if !g.is_null() { + *g = (*d).g; + } + } + + #[allow(bad_style)] + unsafe fn DSA_get0_key( + d: *mut ffi::DSA, + pub_key: *mut *const ffi::BIGNUM, + priv_key: *mut *const ffi::BIGNUM) + { + if !pub_key.is_null() { + *pub_key = (*d).pub_key; + } + if !priv_key.is_null() { + *priv_key = (*d).priv_key; + } + } + + #[allow(bad_style)] + unsafe fn DSA_set0_key( + d: *mut ffi::DSA, + pub_key: *mut ffi::BIGNUM, + priv_key: *mut ffi::BIGNUM) -> c_int + { + (*d).pub_key = pub_key; + (*d).priv_key = priv_key; + 1 + } + + #[allow(bad_style)] + unsafe fn DSA_set0_pqg( + d: *mut ffi::DSA, + p: *mut ffi::BIGNUM, + q: *mut ffi::BIGNUM, + g: *mut ffi::BIGNUM) -> c_int + { + (*d).p = p; + (*d).q = q; + (*d).g = g; + 1 + } + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::DSA_SIG; + fn drop = ffi::DSA_SIG_free; + + /// Object representing DSA signature. + /// + /// DSA signatures consist of two components: `r` and `s`. + /// + /// # Examples + /// + /// ``` + /// use std::convert::TryInto; + /// + /// use openssl::bn::BigNum; + /// use openssl::dsa::{Dsa, DsaSig}; + /// use openssl::hash::MessageDigest; + /// use openssl::pkey::PKey; + /// use openssl::sign::{Signer, Verifier}; + /// + /// const TEST_DATA: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + /// let dsa_ref = Dsa::generate(1024).unwrap(); + /// + /// let pub_key: PKey<_> = dsa_ref.clone().try_into().unwrap(); + /// let priv_key: PKey<_> = dsa_ref.try_into().unwrap(); + /// + /// let mut signer = if let Ok(signer) = Signer::new(MessageDigest::sha256(), &priv_key) { + /// signer + /// } else { + /// // DSA signing is not supported (eg. BoringSSL) + /// return; + /// }; + /// + /// signer.update(TEST_DATA).unwrap(); + /// + /// let signature = signer.sign_to_vec().unwrap(); + /// // Parse DER-encoded DSA signature + /// let signature = DsaSig::from_der(&signature).unwrap(); + /// + /// // Extract components `r` and `s` + /// let r = BigNum::from_slice(&signature.r().to_vec()).unwrap(); + /// let s = BigNum::from_slice(&signature.s().to_vec()).unwrap(); + /// + /// // Construct new DSA signature from components + /// let signature = DsaSig::from_private_components(r, s).unwrap(); + /// + /// // Serialize DSA signature to DER + /// let signature = signature.to_der().unwrap(); + /// + /// let mut verifier = Verifier::new(MessageDigest::sha256(), &pub_key).unwrap(); + /// verifier.update(TEST_DATA).unwrap(); + /// assert!(verifier.verify(&signature[..]).unwrap()); + /// ``` + pub struct DsaSig; + + /// Reference to a [`DsaSig`]. + pub struct DsaSigRef; +} + +impl DsaSig { + /// Returns a new `DsaSig` by setting the `r` and `s` values associated with an DSA signature. + #[corresponds(DSA_SIG_set0)] + pub fn from_private_components(r: BigNum, s: BigNum) -> Result<Self, ErrorStack> { + unsafe { + let sig = cvt_p(ffi::DSA_SIG_new())?; + DSA_SIG_set0(sig, r.as_ptr(), s.as_ptr()); + mem::forget((r, s)); + Ok(DsaSig::from_ptr(sig)) + } + } + + from_der! { + /// Decodes a DER-encoded DSA signature. + #[corresponds(d2i_DSA_SIG)] + from_der, + DsaSig, + ffi::d2i_DSA_SIG + } +} + +impl fmt::Debug for DsaSig { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("DsaSig") + .field("r", self.r()) + .field("s", self.s()) + .finish() + } +} + +impl DsaSigRef { + to_der! { + /// Serializes the DSA signature into a DER-encoded `DSASignature` structure. + #[corresponds(i2d_DSA_SIG)] + to_der, + ffi::i2d_DSA_SIG + } + + /// Returns internal component `r` of an `DsaSig`. + #[corresponds(DSA_SIG_get0)] + pub fn r(&self) -> &BigNumRef { + unsafe { + let mut r = ptr::null(); + DSA_SIG_get0(self.as_ptr(), &mut r, ptr::null_mut()); + BigNumRef::from_const_ptr(r) + } + } + + /// Returns internal component `s` of an `DsaSig`. + #[corresponds(DSA_SIG_get0)] + pub fn s(&self) -> &BigNumRef { + unsafe { + let mut s = ptr::null(); + DSA_SIG_get0(self.as_ptr(), ptr::null_mut(), &mut s); + BigNumRef::from_const_ptr(s) + } + } +} + +cfg_if! { + if #[cfg(any(ossl110, libressl273, boringssl))] { + use ffi::{DSA_SIG_set0, DSA_SIG_get0}; + } else { + #[allow(bad_style)] + unsafe fn DSA_SIG_set0( + sig: *mut ffi::DSA_SIG, + r: *mut ffi::BIGNUM, + s: *mut ffi::BIGNUM, + ) -> c_int { + if r.is_null() || s.is_null() { + return 0; + } + ffi::BN_clear_free((*sig).r); + ffi::BN_clear_free((*sig).s); + (*sig).r = r; + (*sig).s = s; + 1 + } + + #[allow(bad_style)] + unsafe fn DSA_SIG_get0( + sig: *const ffi::DSA_SIG, + pr: *mut *const ffi::BIGNUM, + ps: *mut *const ffi::BIGNUM) + { + if !pr.is_null() { + (*pr) = (*sig).r; + } + if !ps.is_null() { + (*ps) = (*sig).s; + } + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::bn::BigNumContext; + #[cfg(not(boringssl))] + use crate::hash::MessageDigest; + #[cfg(not(boringssl))] + use crate::pkey::PKey; + #[cfg(not(boringssl))] + use crate::sign::{Signer, Verifier}; + + #[test] + pub fn test_generate() { + Dsa::generate(1024).unwrap(); + } + + #[test] + fn test_pubkey_generation() { + let dsa = Dsa::generate(1024).unwrap(); + let p = dsa.p(); + let g = dsa.g(); + let priv_key = dsa.priv_key(); + let pub_key = dsa.pub_key(); + let mut ctx = BigNumContext::new().unwrap(); + let mut calc = BigNum::new().unwrap(); + calc.mod_exp(g, priv_key, p, &mut ctx).unwrap(); + assert_eq!(&calc, pub_key) + } + + #[test] + fn test_priv_key_from_parts() { + let p = BigNum::from_u32(283).unwrap(); + let q = BigNum::from_u32(47).unwrap(); + let g = BigNum::from_u32(60).unwrap(); + let priv_key = BigNum::from_u32(15).unwrap(); + let pub_key = BigNum::from_u32(207).unwrap(); + + let dsa = Dsa::from_private_components(p, q, g, priv_key, pub_key).unwrap(); + assert_eq!(dsa.pub_key(), &BigNum::from_u32(207).unwrap()); + assert_eq!(dsa.priv_key(), &BigNum::from_u32(15).unwrap()); + assert_eq!(dsa.p(), &BigNum::from_u32(283).unwrap()); + assert_eq!(dsa.q(), &BigNum::from_u32(47).unwrap()); + assert_eq!(dsa.g(), &BigNum::from_u32(60).unwrap()); + } + + #[test] + fn test_pub_key_from_parts() { + let p = BigNum::from_u32(283).unwrap(); + let q = BigNum::from_u32(47).unwrap(); + let g = BigNum::from_u32(60).unwrap(); + let pub_key = BigNum::from_u32(207).unwrap(); + + let dsa = Dsa::from_public_components(p, q, g, pub_key).unwrap(); + assert_eq!(dsa.pub_key(), &BigNum::from_u32(207).unwrap()); + assert_eq!(dsa.p(), &BigNum::from_u32(283).unwrap()); + assert_eq!(dsa.q(), &BigNum::from_u32(47).unwrap()); + assert_eq!(dsa.g(), &BigNum::from_u32(60).unwrap()); + } + + #[test] + fn test_params() { + let params = Dsa::generate_params(1024).unwrap(); + let p = params.p().to_owned().unwrap(); + let q = params.q().to_owned().unwrap(); + let g = params.g().to_owned().unwrap(); + let key = params.generate_key().unwrap(); + let params2 = Dsa::from_pqg( + key.p().to_owned().unwrap(), + key.q().to_owned().unwrap(), + key.g().to_owned().unwrap(), + ) + .unwrap(); + assert_eq!(p, *params2.p()); + assert_eq!(q, *params2.q()); + assert_eq!(g, *params2.g()); + } + + #[test] + #[cfg(not(boringssl))] + fn test_signature() { + const TEST_DATA: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + let dsa_ref = Dsa::generate(1024).unwrap(); + + let p = dsa_ref.p(); + let q = dsa_ref.q(); + let g = dsa_ref.g(); + + let pub_key = dsa_ref.pub_key(); + let priv_key = dsa_ref.priv_key(); + + let priv_key = Dsa::from_private_components( + BigNumRef::to_owned(p).unwrap(), + BigNumRef::to_owned(q).unwrap(), + BigNumRef::to_owned(g).unwrap(), + BigNumRef::to_owned(priv_key).unwrap(), + BigNumRef::to_owned(pub_key).unwrap(), + ) + .unwrap(); + let priv_key = PKey::from_dsa(priv_key).unwrap(); + + let pub_key = Dsa::from_public_components( + BigNumRef::to_owned(p).unwrap(), + BigNumRef::to_owned(q).unwrap(), + BigNumRef::to_owned(g).unwrap(), + BigNumRef::to_owned(pub_key).unwrap(), + ) + .unwrap(); + let pub_key = PKey::from_dsa(pub_key).unwrap(); + + let mut signer = Signer::new(MessageDigest::sha256(), &priv_key).unwrap(); + signer.update(TEST_DATA).unwrap(); + + let signature = signer.sign_to_vec().unwrap(); + let mut verifier = Verifier::new(MessageDigest::sha256(), &pub_key).unwrap(); + verifier.update(TEST_DATA).unwrap(); + assert!(verifier.verify(&signature[..]).unwrap()); + } + + #[test] + #[cfg(not(boringssl))] + fn test_signature_der() { + use std::convert::TryInto; + + const TEST_DATA: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + let dsa_ref = Dsa::generate(1024).unwrap(); + + let pub_key: PKey<_> = dsa_ref.clone().try_into().unwrap(); + let priv_key: PKey<_> = dsa_ref.try_into().unwrap(); + + let mut signer = Signer::new(MessageDigest::sha256(), &priv_key).unwrap(); + signer.update(TEST_DATA).unwrap(); + + let signature = signer.sign_to_vec().unwrap(); + eprintln!("{:?}", signature); + let signature = DsaSig::from_der(&signature).unwrap(); + + let r = BigNum::from_slice(&signature.r().to_vec()).unwrap(); + let s = BigNum::from_slice(&signature.s().to_vec()).unwrap(); + + let signature = DsaSig::from_private_components(r, s).unwrap(); + let signature = signature.to_der().unwrap(); + + let mut verifier = Verifier::new(MessageDigest::sha256(), &pub_key).unwrap(); + verifier.update(TEST_DATA).unwrap(); + assert!(verifier.verify(&signature[..]).unwrap()); + } + + #[test] + #[allow(clippy::redundant_clone)] + fn clone() { + let key = Dsa::generate(2048).unwrap(); + drop(key.clone()); + } + + #[test] + fn dsa_sig_debug() { + let sig = DsaSig::from_der(&[ + 48, 46, 2, 21, 0, 135, 169, 24, 58, 153, 37, 175, 248, 200, 45, 251, 112, 238, 238, 89, + 172, 177, 182, 166, 237, 2, 21, 0, 159, 146, 151, 237, 187, 8, 82, 115, 14, 183, 103, + 12, 203, 46, 161, 208, 251, 167, 123, 131, + ]) + .unwrap(); + let s = format!("{:?}", sig); + assert_eq!(s, "DsaSig { r: 774484690634577222213819810519929266740561094381, s: 910998676210681457251421818099943952372231273347 }"); + } +} |