Add sign_ecdsa_with_noncedata and sign_ecdsa_recoverable_with_noncedata
This commit is contained in:
parent
49905b0d44
commit
f93ca81348
|
@ -340,20 +340,44 @@ impl<C: Signing> Secp256k1<C> {
|
||||||
self.sign_ecdsa(msg, sk)
|
self.sign_ecdsa(msg, sk)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a signature for `msg` using the secret key `sk` and RFC6979 nonce
|
fn sign_ecdsa_with_noncedata_pointer(
|
||||||
/// Requires a signing-capable context.
|
&self,
|
||||||
pub fn sign_ecdsa(&self, msg: &Message, sk: &SecretKey) -> Signature {
|
msg: &Message,
|
||||||
|
sk: &SecretKey,
|
||||||
|
noncedata_ptr: *const ffi::types::c_void,
|
||||||
|
) -> Signature {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut ret = ffi::Signature::new();
|
let mut ret = ffi::Signature::new();
|
||||||
// We can assume the return value because it's not possible to construct
|
// We can assume the return value because it's not possible to construct
|
||||||
// an invalid signature from a valid `Message` and `SecretKey`
|
// an invalid signature from a valid `Message` and `SecretKey`
|
||||||
assert_eq!(ffi::secp256k1_ecdsa_sign(self.ctx, &mut ret, msg.as_c_ptr(),
|
assert_eq!(ffi::secp256k1_ecdsa_sign(self.ctx, &mut ret, msg.as_c_ptr(),
|
||||||
sk.as_c_ptr(), ffi::secp256k1_nonce_function_rfc6979,
|
sk.as_c_ptr(), ffi::secp256k1_nonce_function_rfc6979,
|
||||||
ptr::null()), 1);
|
noncedata_ptr), 1);
|
||||||
Signature::from(ret)
|
Signature::from(ret)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs a signature for `msg` using the secret key `sk` and RFC6979 nonce
|
||||||
|
/// Requires a signing-capable context.
|
||||||
|
pub fn sign_ecdsa(&self, msg: &Message, sk: &SecretKey) -> Signature {
|
||||||
|
self.sign_ecdsa_with_noncedata_pointer(msg, sk, ptr::null())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructs a signature for `msg` using the secret key `sk` and RFC6979 nonce
|
||||||
|
/// and includes 32 bytes of noncedata in the nonce generation via inclusion in
|
||||||
|
/// one of the hash operations during nonce generation. This is useful when multiple
|
||||||
|
/// signatures are needed for the same Message and SecretKey while still using RFC6979.
|
||||||
|
/// Requires a signing-capable context.
|
||||||
|
pub fn sign_ecdsa_with_noncedata(
|
||||||
|
&self,
|
||||||
|
msg: &Message,
|
||||||
|
sk: &SecretKey,
|
||||||
|
noncedata: &[u8; 32],
|
||||||
|
) -> Signature {
|
||||||
|
let noncedata_ptr = noncedata.as_ptr() as *const ffi::types::c_void;
|
||||||
|
self.sign_ecdsa_with_noncedata_pointer(msg, sk, noncedata_ptr)
|
||||||
|
}
|
||||||
|
|
||||||
fn sign_grind_with_check(
|
fn sign_grind_with_check(
|
||||||
&self, msg: &Message,
|
&self, msg: &Message,
|
||||||
sk: &SecretKey,
|
sk: &SecretKey,
|
||||||
|
|
|
@ -159,9 +159,12 @@ impl<C: Signing> Secp256k1<C> {
|
||||||
self.sign_ecdsa_recoverable(msg, sk)
|
self.sign_ecdsa_recoverable(msg, sk)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a signature for `msg` using the secret key `sk` and RFC6979 nonce
|
fn sign_ecdsa_recoverable_with_noncedata_pointer(
|
||||||
/// Requires a signing-capable context.
|
&self,
|
||||||
pub fn sign_ecdsa_recoverable(&self, msg: &Message, sk: &key::SecretKey) -> RecoverableSignature {
|
msg: &Message,
|
||||||
|
sk: &key::SecretKey,
|
||||||
|
noncedata_ptr: *const super_ffi::types::c_void,
|
||||||
|
) -> RecoverableSignature {
|
||||||
let mut ret = ffi::RecoverableSignature::new();
|
let mut ret = ffi::RecoverableSignature::new();
|
||||||
unsafe {
|
unsafe {
|
||||||
// We can assume the return value because it's not possible to construct
|
// We can assume the return value because it's not possible to construct
|
||||||
|
@ -173,7 +176,7 @@ impl<C: Signing> Secp256k1<C> {
|
||||||
msg.as_c_ptr(),
|
msg.as_c_ptr(),
|
||||||
sk.as_c_ptr(),
|
sk.as_c_ptr(),
|
||||||
super_ffi::secp256k1_nonce_function_rfc6979,
|
super_ffi::secp256k1_nonce_function_rfc6979,
|
||||||
ptr::null()
|
noncedata_ptr
|
||||||
),
|
),
|
||||||
1
|
1
|
||||||
);
|
);
|
||||||
|
@ -181,6 +184,27 @@ impl<C: Signing> Secp256k1<C> {
|
||||||
|
|
||||||
RecoverableSignature::from(ret)
|
RecoverableSignature::from(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs a signature for `msg` using the secret key `sk` and RFC6979 nonce
|
||||||
|
/// Requires a signing-capable context.
|
||||||
|
pub fn sign_ecdsa_recoverable(&self, msg: &Message, sk: &key::SecretKey) -> RecoverableSignature {
|
||||||
|
self.sign_ecdsa_recoverable_with_noncedata_pointer(msg, sk, ptr::null())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructs a signature for `msg` using the secret key `sk` and RFC6979 nonce
|
||||||
|
/// and includes 32 bytes of noncedata in the nonce generation via inclusion in
|
||||||
|
/// one of the hash operations during nonce generation. This is useful when multiple
|
||||||
|
/// signatures are needed for the same Message and SecretKey while still using RFC6979.
|
||||||
|
/// Requires a signing-capable context.
|
||||||
|
pub fn sign_ecdsa_recoverable_with_noncedata(
|
||||||
|
&self,
|
||||||
|
msg: &Message,
|
||||||
|
sk: &key::SecretKey,
|
||||||
|
noncedata: &[u8; 32],
|
||||||
|
) -> RecoverableSignature {
|
||||||
|
let noncedata_ptr = noncedata.as_ptr() as *const super_ffi::types::c_void;
|
||||||
|
self.sign_ecdsa_recoverable_with_noncedata_pointer(msg, sk, noncedata_ptr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: Verification> Secp256k1<C> {
|
impl<C: Verification> Secp256k1<C> {
|
||||||
|
@ -276,6 +300,32 @@ mod tests {
|
||||||
RecoveryId(1)))
|
RecoveryId(1)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(not(fuzzing))] // fixed sig vectors can't work with fuzz-sigs
|
||||||
|
#[cfg(all(feature="std", feature = "rand-std"))]
|
||||||
|
fn sign_with_noncedata() {
|
||||||
|
let mut s = Secp256k1::new();
|
||||||
|
s.randomize(&mut thread_rng());
|
||||||
|
let one: [u8; 32] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
|
||||||
|
|
||||||
|
let sk = SecretKey::from_slice(&one).unwrap();
|
||||||
|
let msg = Message::from_slice(&one).unwrap();
|
||||||
|
let noncedata = [42u8; 32];
|
||||||
|
|
||||||
|
let sig = s.sign_ecdsa_recoverable_with_noncedata(&msg, &sk, &noncedata);
|
||||||
|
assert_eq!(Ok(sig), RecoverableSignature::from_compact(&[
|
||||||
|
0xb5, 0x0b, 0xb6, 0x79, 0x5f, 0x31, 0x74, 0x8a,
|
||||||
|
0x4d, 0x37, 0xc3, 0xa9, 0x7e, 0xbd, 0x06, 0xa2,
|
||||||
|
0x2e, 0xa3, 0x37, 0x71, 0x04, 0x0f, 0x5c, 0x05,
|
||||||
|
0xd6, 0xe2, 0xbb, 0x2d, 0x38, 0xc6, 0x22, 0x7c,
|
||||||
|
0x34, 0x3b, 0x66, 0x59, 0xdb, 0x96, 0x99, 0x59,
|
||||||
|
0xd9, 0xfd, 0xdb, 0x44, 0xbd, 0x0d, 0xd9, 0xb9,
|
||||||
|
0xdd, 0x47, 0x66, 0x6a, 0xb5, 0x28, 0x71, 0x90,
|
||||||
|
0x1d, 0x17, 0x61, 0xeb, 0x82, 0xec, 0x87, 0x22],
|
||||||
|
RecoveryId(0)))
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(all(feature="std", feature = "rand-std"))]
|
#[cfg(all(feature="std", feature = "rand-std"))]
|
||||||
fn sign_and_verify_fail() {
|
fn sign_and_verify_fail() {
|
||||||
|
@ -317,6 +367,25 @@ mod tests {
|
||||||
assert_eq!(s.recover_ecdsa(&msg, &sig), Ok(pk));
|
assert_eq!(s.recover_ecdsa(&msg, &sig), Ok(pk));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(all(feature="std", feature = "rand-std"))]
|
||||||
|
fn sign_with_recovery_and_noncedata() {
|
||||||
|
let mut s = Secp256k1::new();
|
||||||
|
s.randomize(&mut thread_rng());
|
||||||
|
|
||||||
|
let mut msg = [0u8; 32];
|
||||||
|
thread_rng().fill_bytes(&mut msg);
|
||||||
|
let msg = Message::from_slice(&msg).unwrap();
|
||||||
|
|
||||||
|
let noncedata = [42u8; 32];
|
||||||
|
|
||||||
|
let (sk, pk) = s.generate_keypair(&mut thread_rng());
|
||||||
|
|
||||||
|
let sig = s.sign_ecdsa_recoverable_with_noncedata(&msg, &sk, &noncedata);
|
||||||
|
|
||||||
|
assert_eq!(s.recover_ecdsa(&msg, &sig), Ok(pk));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(all(feature="std", feature = "rand-std"))]
|
#[cfg(all(feature="std", feature = "rand-std"))]
|
||||||
fn bad_recovery() {
|
fn bad_recovery() {
|
||||||
|
|
20
src/lib.rs
20
src/lib.rs
|
@ -807,6 +807,7 @@ mod tests {
|
||||||
s.randomize(&mut thread_rng());
|
s.randomize(&mut thread_rng());
|
||||||
|
|
||||||
let mut msg = [0u8; 32];
|
let mut msg = [0u8; 32];
|
||||||
|
let noncedata = [42u8; 32];
|
||||||
for _ in 0..100 {
|
for _ in 0..100 {
|
||||||
thread_rng().fill_bytes(&mut msg);
|
thread_rng().fill_bytes(&mut msg);
|
||||||
let msg = Message::from_slice(&msg).unwrap();
|
let msg = Message::from_slice(&msg).unwrap();
|
||||||
|
@ -814,6 +815,8 @@ mod tests {
|
||||||
let (sk, pk) = s.generate_keypair(&mut thread_rng());
|
let (sk, pk) = s.generate_keypair(&mut thread_rng());
|
||||||
let sig = s.sign_ecdsa(&msg, &sk);
|
let sig = s.sign_ecdsa(&msg, &sk);
|
||||||
assert_eq!(s.verify_ecdsa(&msg, &sig, &pk), Ok(()));
|
assert_eq!(s.verify_ecdsa(&msg, &sig, &pk), Ok(()));
|
||||||
|
let noncedata_sig = s.sign_ecdsa_with_noncedata(&msg, &sk, &noncedata);
|
||||||
|
assert_eq!(s.verify_ecdsa(&msg, &noncedata_sig, &pk), Ok(()));
|
||||||
let low_r_sig = s.sign_ecdsa_low_r(&msg, &sk);
|
let low_r_sig = s.sign_ecdsa_low_r(&msg, &sk);
|
||||||
assert_eq!(s.verify_ecdsa(&msg, &low_r_sig, &pk), Ok(()));
|
assert_eq!(s.verify_ecdsa(&msg, &low_r_sig, &pk), Ok(()));
|
||||||
let grind_r_sig = s.sign_ecdsa_grind_r(&msg, &sk, 1);
|
let grind_r_sig = s.sign_ecdsa_grind_r(&msg, &sk, 1);
|
||||||
|
@ -927,6 +930,23 @@ mod tests {
|
||||||
assert!(from_hex("ag", &mut [0u8; 4]).is_err());
|
assert!(from_hex("ag", &mut [0u8; 4]).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(not(fuzzing))] // fuzz-sigs have fixed size/format
|
||||||
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||||
|
fn test_noncedata() {
|
||||||
|
let secp = Secp256k1::new();
|
||||||
|
let msg = hex!("887d04bb1cf1b1554f1b268dfe62d13064ca67ae45348d50d1392ce2d13418ac");
|
||||||
|
let msg = Message::from_slice(&msg).unwrap();
|
||||||
|
let noncedata = [42u8; 32];
|
||||||
|
let sk = SecretKey::from_str("57f0148f94d13095cfda539d0da0d1541304b678d8b36e243980aab4e1b7cead").unwrap();
|
||||||
|
let expected_sig = hex!("24861b3edd4e7da43319c635091405feced6efa4ec99c3c3c35f6c3ba0ed8816116772e84994084db85a6c20589f6a85af569d42275c2a5dd900da5776b99d5d");
|
||||||
|
let expected_sig = ecdsa::Signature::from_compact(&expected_sig).unwrap();
|
||||||
|
|
||||||
|
let sig = secp.sign_ecdsa_with_noncedata(&msg, &sk, &noncedata);
|
||||||
|
|
||||||
|
assert_eq!(expected_sig, sig);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(not(fuzzing))] // fixed sig vectors can't work with fuzz-sigs
|
#[cfg(not(fuzzing))] // fixed sig vectors can't work with fuzz-sigs
|
||||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||||
|
|
Loading…
Reference in New Issue