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