secp256k1_sys/
recovery.rs
1use crate::{Context, Signature, NonceFn, PublicKey, CPtr, impl_array_newtype, secp256k1_context_no_precomp};
6use crate::types::*;
7use core::fmt;
8
9#[repr(C)]
11#[derive(Copy, Clone)]
12#[cfg_attr(secp256k1_fuzz, derive(PartialEq, Eq, PartialOrd, Ord, Hash))]
13pub struct RecoverableSignature([c_uchar; 65]);
14impl_array_newtype!(RecoverableSignature, c_uchar, 65);
15
16impl RecoverableSignature {
17 pub fn new() -> RecoverableSignature { RecoverableSignature([0; 65]) }
19
20 fn serialize(&self) -> [u8; 65] {
22 let mut buf = [0u8; 65];
23 let mut recid = 0;
24 unsafe {
25 let ret = secp256k1_ecdsa_recoverable_signature_serialize_compact(
26 secp256k1_context_no_precomp,
27 buf.as_mut_c_ptr(),
28 &mut recid,
29 self,
30 );
31 debug_assert!(ret == 1);
32 }
33 buf[64] = (recid & 0xFF) as u8;
34 buf
35 }
36}
37
38impl Default for RecoverableSignature {
39 fn default() -> Self {
40 RecoverableSignature::new()
41 }
42}
43
44impl fmt::Debug for RecoverableSignature {
45 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
46 let mut ret = [0u8; 64];
47 let mut recid = 0i32;
48
49 unsafe {
50 let err = secp256k1_ecdsa_recoverable_signature_serialize_compact(
51 super::secp256k1_context_no_precomp,
52 ret.as_mut_c_ptr(),
53 &mut recid,
54 self,
55 );
56 assert!(err == 1);
57 }
58
59 for byte in ret.iter() {
60 write!(f, "{:02x}", byte)?;
61 }
62 write!(f, "{:02x}", recid as u8)?;
63
64 Ok(())
65 }
66}
67
68#[cfg(not(secp256k1_fuzz))]
69impl PartialOrd for RecoverableSignature {
70 fn partial_cmp(&self, other: &RecoverableSignature) -> Option<core::cmp::Ordering> {
71 Some(self.cmp(other))
72 }
73}
74
75#[cfg(not(secp256k1_fuzz))]
76impl Ord for RecoverableSignature {
77 fn cmp(&self, other: &RecoverableSignature) -> core::cmp::Ordering {
78 let this = self.serialize();
79 let that = other.serialize();
80 this.cmp(&that)
81 }
82}
83
84#[cfg(not(secp256k1_fuzz))]
85impl PartialEq for RecoverableSignature {
86 fn eq(&self, other: &Self) -> bool {
87 self.cmp(other) == core::cmp::Ordering::Equal
88 }
89}
90
91#[cfg(not(secp256k1_fuzz))]
92impl Eq for RecoverableSignature {}
93
94#[cfg(not(secp256k1_fuzz))]
95impl core::hash::Hash for RecoverableSignature {
96 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
97 let ser = self.serialize();
98 ser.hash(state);
99 }
100}
101
102extern "C" {
103 #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_10_0_ecdsa_recoverable_signature_parse_compact")]
104 pub fn secp256k1_ecdsa_recoverable_signature_parse_compact(cx: *const Context, sig: *mut RecoverableSignature,
105 input64: *const c_uchar, recid: c_int)
106 -> c_int;
107
108 #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_10_0_ecdsa_recoverable_signature_serialize_compact")]
109 pub fn secp256k1_ecdsa_recoverable_signature_serialize_compact(cx: *const Context, output64: *mut c_uchar,
110 recid: *mut c_int, sig: *const RecoverableSignature)
111 -> c_int;
112
113 #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_10_0_ecdsa_recoverable_signature_convert")]
114 pub fn secp256k1_ecdsa_recoverable_signature_convert(cx: *const Context, sig: *mut Signature,
115 input: *const RecoverableSignature)
116 -> c_int;
117}
118
119#[cfg(not(secp256k1_fuzz))]
120extern "C" {
121 #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_10_0_ecdsa_sign_recoverable")]
122 pub fn secp256k1_ecdsa_sign_recoverable(cx: *const Context,
123 sig: *mut RecoverableSignature,
124 msg32: *const c_uchar,
125 sk: *const c_uchar,
126 noncefn: NonceFn,
127 noncedata: *const c_void)
128 -> c_int;
129
130 #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_10_0_ecdsa_recover")]
131 pub fn secp256k1_ecdsa_recover(cx: *const Context,
132 pk: *mut PublicKey,
133 sig: *const RecoverableSignature,
134 msg32: *const c_uchar)
135 -> c_int;
136}
137
138
139#[cfg(secp256k1_fuzz)]
140mod fuzz_dummy {
141 use core::slice;
142
143 use crate::{secp256k1_ec_pubkey_create, secp256k1_ec_pubkey_parse, secp256k1_ec_pubkey_serialize, SECP256K1_SER_COMPRESSED};
144 use super::*;
145
146 pub unsafe fn secp256k1_ecdsa_sign_recoverable(
148 cx: *const Context,
149 sig: *mut RecoverableSignature,
150 msg32: *const c_uchar,
151 sk: *const c_uchar,
152 _noncefn: NonceFn,
153 _noncedata: *const c_void,
154 ) -> c_int {
155 let mut new_pk = PublicKey::new();
157 if secp256k1_ec_pubkey_create(cx, &mut new_pk, sk) != 1 {
158 return 0;
159 }
160 let sig_sl = slice::from_raw_parts_mut(sig as *mut u8, 65);
162 let msg_sl = slice::from_raw_parts(msg32 as *const u8, 32);
163 sig_sl[..32].copy_from_slice(msg_sl);
164 let mut out_len: size_t = 33;
165 secp256k1_ec_pubkey_serialize(cx, sig_sl[32..].as_mut_ptr(), &mut out_len, &new_pk, SECP256K1_SER_COMPRESSED);
166 sig_sl.swap(32, 64);
170 sig_sl[64] -= 2;
171 1
172 }
173
174 pub unsafe fn secp256k1_ecdsa_recover(
175 cx: *const Context,
176 pk: *mut PublicKey,
177 sig: *const RecoverableSignature,
178 msg32: *const c_uchar
179 ) -> c_int {
180 let sig_sl = slice::from_raw_parts(sig as *const u8, 65);
181 let msg_sl = slice::from_raw_parts(msg32 as *const u8, 32);
182
183 if sig_sl[64] >= 4 {
184 return 0;
185 }
186 let mut pk_ser = [0u8; 33];
188 pk_ser.copy_from_slice(&sig_sl[32..]);
189 pk_ser.swap(0, 32);
190 pk_ser[0] += 2;
191 if secp256k1_ec_pubkey_parse(cx, pk, pk_ser.as_ptr(), 33) == 0 {
194 return 0;
195 }
196 for i in 0..32 {
198 pk_ser[i + 1] ^= sig_sl[i] ^ msg_sl[i];
199 }
200 let mut idx = 0;
203 while secp256k1_ec_pubkey_parse(cx, pk, pk_ser.as_ptr(), 33) == 0 {
204 pk_ser[1 + idx / 8] ^= 1 << (idx % 8);
205 idx += 1;
206 }
207 1
208 }
209}
210
211#[cfg(secp256k1_fuzz)]
212pub use self::fuzz_dummy::*;