1use dcrypt_api::{error::Error as ApiError, Result as ApiResult};
4
5pub(crate) fn is_high_s(s: &[u8], order: &[u8]) -> bool {
10 if s.len() != order.len() {
11 return true;
12 }
13 let mut carry = 0u8;
14 for (&scalar_byte, &order_byte) in s.iter().zip(order) {
15 let half_order_byte = (order_byte >> 1) | (carry << 7);
16 let next_carry = order_byte & 1;
17 if scalar_byte != half_order_byte {
18 return scalar_byte > half_order_byte;
19 }
20 carry = next_carry;
21 }
22 false
23}
24
25pub(crate) fn is_canonical_nonzero_scalar(value: &[u8], order: &[u8]) -> bool {
29 value.len() == order.len() && value.iter().any(|&byte| byte != 0) && value < order
30}
31
32#[derive(Clone, Debug)]
34pub struct SignatureComponents {
35 pub r: Vec<u8>,
36 pub s: Vec<u8>,
37}
38
39impl SignatureComponents {
40 pub fn to_der(&self) -> Vec<u8> {
42 let mut der = Vec::new();
44
45 der.push(0x30);
47
48 let r_bytes = self.encode_integer(&self.r);
49 let s_bytes = self.encode_integer(&self.s);
50
51 let mut sequence = Vec::with_capacity(2 + r_bytes.len() + 2 + s_bytes.len());
52 sequence.push(0x02); Self::encode_length(&mut sequence, r_bytes.len());
54 sequence.extend_from_slice(&r_bytes);
55
56 sequence.push(0x02); Self::encode_length(&mut sequence, s_bytes.len());
58 sequence.extend_from_slice(&s_bytes);
59
60 Self::encode_length(&mut der, sequence.len());
61 der.extend_from_slice(&sequence);
62 der
63 }
64
65 pub fn from_der(der: &[u8]) -> ApiResult<Self> {
67 if der.len() < 2 {
68 return Err(ApiError::InvalidSignature {
69 context: "ECDSA DER parsing",
70 #[cfg(feature = "std")]
71 message: "DER signature too short".to_string(),
72 });
73 }
74
75 if der[0] != 0x30 {
77 return Err(ApiError::InvalidSignature {
78 context: "ECDSA DER parsing",
79 #[cfg(feature = "std")]
80 message: "Invalid DER SEQUENCE tag".to_string(),
81 });
82 }
83
84 let (seq_len, mut pos) = Self::parse_length(der, 1)?;
85 let seq_end = pos
86 .checked_add(seq_len)
87 .ok_or_else(|| ApiError::InvalidSignature {
88 context: "ECDSA DER parsing",
89 #[cfg(feature = "std")]
90 message: "DER sequence length overflow".to_string(),
91 })?;
92
93 if seq_end != der.len() {
94 return Err(ApiError::InvalidSignature {
95 context: "ECDSA DER parsing",
96 #[cfg(feature = "std")]
97 message: "DER sequence length mismatch".to_string(),
98 });
99 }
100
101 let r = Self::parse_integer(der, &mut pos, "r")?;
102 let s = Self::parse_integer(der, &mut pos, "s")?;
103
104 if pos != seq_end {
105 return Err(ApiError::InvalidSignature {
106 context: "ECDSA DER parsing",
107 #[cfg(feature = "std")]
108 message: "Trailing data after ECDSA signature".to_string(),
109 });
110 }
111
112 Ok(SignatureComponents {
113 r: Self::decode_integer(&r),
114 s: Self::decode_integer(&s),
115 })
116 }
117
118 fn encode_integer(&self, bytes: &[u8]) -> Vec<u8> {
120 let mut start = 0usize;
121 while start + 1 < bytes.len() && bytes[start] == 0x00 {
122 start += 1;
123 }
124
125 let trimmed = if bytes.is_empty() {
126 &[0x00][..]
127 } else {
128 &bytes[start..]
129 };
130
131 if trimmed[0] & 0x80 == 0 {
132 trimmed.to_vec()
133 } else {
134 let mut result = vec![0x00];
135 result.extend_from_slice(trimmed);
136 result
137 }
138 }
139
140 fn decode_integer(bytes: &[u8]) -> Vec<u8> {
142 let mut result = bytes.to_vec();
143 while result.len() > 1 && result[0] == 0x00 {
144 result.remove(0);
145 }
146 result
147 }
148
149 fn encode_length(out: &mut Vec<u8>, len: usize) {
150 if len < 0x80 {
151 out.push(len as u8);
152 return;
153 }
154
155 let mut buf = [0u8; core::mem::size_of::<usize>()];
156 let mut written = 0usize;
157 let mut value = len;
158
159 while value > 0 {
160 buf[buf.len() - 1 - written] = (value & 0xFF) as u8;
161 value >>= 8;
162 written += 1;
163 }
164
165 out.push(0x80 | written as u8);
166 out.extend_from_slice(&buf[buf.len() - written..]);
167 }
168
169 fn parse_length(der: &[u8], pos: usize) -> ApiResult<(usize, usize)> {
170 let first = *der.get(pos).ok_or_else(|| ApiError::InvalidSignature {
171 context: "ECDSA DER parsing",
172 #[cfg(feature = "std")]
173 message: "Missing DER length".to_string(),
174 })?;
175
176 if first & 0x80 == 0 {
177 return Ok((first as usize, pos + 1));
178 }
179
180 let num_len_bytes = (first & 0x7F) as usize;
181 if num_len_bytes == 0 {
182 return Err(ApiError::InvalidSignature {
183 context: "ECDSA DER parsing",
184 #[cfg(feature = "std")]
185 message: "Indefinite DER lengths are not allowed".to_string(),
186 });
187 }
188 if num_len_bytes > core::mem::size_of::<usize>() {
189 return Err(ApiError::InvalidSignature {
190 context: "ECDSA DER parsing",
191 #[cfg(feature = "std")]
192 message: "DER length is too large".to_string(),
193 });
194 }
195
196 let len_end = pos + 1 + num_len_bytes;
197 let len_bytes = der
198 .get(pos + 1..len_end)
199 .ok_or_else(|| ApiError::InvalidSignature {
200 context: "ECDSA DER parsing",
201 #[cfg(feature = "std")]
202 message: "Truncated DER length".to_string(),
203 })?;
204
205 if len_bytes.first() == Some(&0x00) {
206 return Err(ApiError::InvalidSignature {
207 context: "ECDSA DER parsing",
208 #[cfg(feature = "std")]
209 message: "DER length must use minimal encoding".to_string(),
210 });
211 }
212
213 let mut len = 0usize;
214 for &byte in len_bytes {
215 len = len
216 .checked_shl(8)
217 .ok_or_else(|| ApiError::InvalidSignature {
218 context: "ECDSA DER parsing",
219 #[cfg(feature = "std")]
220 message: "DER length overflow".to_string(),
221 })?;
222 len |= byte as usize;
223 }
224
225 if len < 0x80 {
226 return Err(ApiError::InvalidSignature {
227 context: "ECDSA DER parsing",
228 #[cfg(feature = "std")]
229 message: "DER length must use short form".to_string(),
230 });
231 }
232
233 Ok((len, len_end))
234 }
235
236 fn parse_integer(der: &[u8], pos: &mut usize, name: &'static str) -> ApiResult<Vec<u8>> {
237 let tag = *der.get(*pos).ok_or_else(|| ApiError::InvalidSignature {
238 context: "ECDSA DER parsing",
239 #[cfg(feature = "std")]
240 message: format!("Missing DER INTEGER tag for {name}"),
241 })?;
242 if tag != 0x02 {
243 return Err(ApiError::InvalidSignature {
244 context: "ECDSA DER parsing",
245 #[cfg(feature = "std")]
246 message: format!("Invalid DER INTEGER tag for {name}"),
247 });
248 }
249 *pos += 1;
250
251 let (len, next_pos) = Self::parse_length(der, *pos)?;
252 *pos = next_pos;
253 if len == 0 {
254 return Err(ApiError::InvalidSignature {
255 context: "ECDSA DER parsing",
256 #[cfg(feature = "std")]
257 message: format!("DER INTEGER {name} cannot be empty"),
258 });
259 }
260
261 let int_end = pos
262 .checked_add(len)
263 .ok_or_else(|| ApiError::InvalidSignature {
264 context: "ECDSA DER parsing",
265 #[cfg(feature = "std")]
266 message: format!("DER INTEGER {name} length overflow"),
267 })?;
268
269 let value = der
270 .get(*pos..int_end)
271 .ok_or_else(|| ApiError::InvalidSignature {
272 context: "ECDSA DER parsing",
273 #[cfg(feature = "std")]
274 message: format!("Truncated DER INTEGER {name}"),
275 })?;
276
277 if value[0] & 0x80 != 0 {
281 return Err(ApiError::InvalidSignature {
282 context: "ECDSA DER parsing",
283 #[cfg(feature = "std")]
284 message: format!("DER INTEGER {name} must not be negative"),
285 });
286 }
287
288 if value.len() > 1 && value[0] == 0x00 && value[1] & 0x80 == 0 {
289 return Err(ApiError::InvalidSignature {
290 context: "ECDSA DER parsing",
291 #[cfg(feature = "std")]
292 message: format!("DER INTEGER {name} is not minimally encoded"),
293 });
294 }
295
296 *pos = int_end;
297 Ok(value.to_vec())
298 }
299}
300
301#[cfg(test)]
302mod tests {
303 use super::*;
304
305 #[test]
306 fn canonical_scalar_check_rejects_zero_order_and_larger_values() {
307 let order = [0x01, 0x00];
308 assert!(is_canonical_nonzero_scalar(&[0x00, 0xff], &order));
309 assert!(!is_canonical_nonzero_scalar(&[0x00, 0x00], &order));
310 assert!(!is_canonical_nonzero_scalar(&order, &order));
311 assert!(!is_canonical_nonzero_scalar(&[0x01, 0x01], &order));
312 assert!(!is_canonical_nonzero_scalar(&[0xff], &order));
313 }
314
315 #[test]
316 fn test_der_encoding() {
317 let sig = SignatureComponents {
318 r: vec![0x01, 0x23, 0x45, 0x67],
319 s: vec![0x89, 0xAB, 0xCD, 0xEF],
320 };
321
322 let der = sig.to_der();
323 let parsed = SignatureComponents::from_der(&der).unwrap();
324
325 assert_eq!(sig.r, parsed.r);
326 assert_eq!(sig.s, parsed.s);
327 }
328
329 #[test]
330 fn test_der_with_high_bit() {
331 let sig = SignatureComponents {
333 r: vec![0xFF, 0x23, 0x45, 0x67],
334 s: vec![0x79, 0xAB, 0xCD, 0xEF],
335 };
336
337 let der = sig.to_der();
338
339 assert_eq!(der[3], 5); assert_eq!(der[4], 0x00); assert_eq!(der[5], 0xFF); let parsed = SignatureComponents::from_der(&der).unwrap();
346 assert_eq!(sig.r, parsed.r);
347 assert_eq!(sig.s, parsed.s);
348 }
349
350 #[test]
351 fn test_der_long_form_sequence_length_roundtrip() {
352 let sig = SignatureComponents {
353 r: vec![0x7F; 66],
354 s: vec![0x80; 66],
355 };
356
357 let der = sig.to_der();
358 assert_eq!(der[0], 0x30);
359 assert_eq!(der[1], 0x81);
360
361 let parsed = SignatureComponents::from_der(&der).unwrap();
362 assert_eq!(sig.r, parsed.r);
363 assert_eq!(sig.s, parsed.s);
364 }
365
366 #[test]
367 fn test_der_rejects_truncated_lengths_without_panicking() {
368 let malformed = [0x30, 0x06, 0x02, 0x02, 0x01];
369 assert!(SignatureComponents::from_der(&malformed).is_err());
370 }
371
372 #[test]
373 fn test_der_rejects_trailing_bytes() {
374 let der = [0x30, 0x08, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00];
375 assert!(SignatureComponents::from_der(&der).is_err());
376 }
377
378 #[test]
379 fn test_der_rejects_negative_integers() {
380 let negative_r = [0x30, 0x06, 0x02, 0x01, 0x80, 0x02, 0x01, 0x01];
381 let negative_s = [0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0xff];
382 assert!(SignatureComponents::from_der(&negative_r).is_err());
383 assert!(SignatureComponents::from_der(&negative_s).is_err());
384 }
385}