1use crate::{EcdsaCurve, Error, Result};
16use core::cmp;
17use elliptic_curve::{FieldBytes, array::typenum::Unsigned};
18
19#[cfg(feature = "algorithm")]
20use {
21 crate::{RecoveryId, Signature, SignatureSize},
22 elliptic_curve::{
23 CurveArithmetic, NonZeroScalar, ProjectivePoint, Scalar,
24 array::ArraySize,
25 ff::PrimeField,
26 field,
27 group::{Curve as _, Group},
28 ops::{Invert, MulByGeneratorVartime, Reduce},
29 point::AffineCoordinates,
30 scalar::IsHigh,
31 },
32};
33
34#[cfg(feature = "digest")]
35use digest::{Digest, FixedOutput, FixedOutputReset, common::BlockSizeUser};
36
37#[cfg(feature = "digest")]
42pub trait DigestAlgorithm: EcdsaCurve {
43 type Digest: BlockSizeUser + Digest + FixedOutput + FixedOutputReset;
46}
47
48pub fn bits2field<C: EcdsaCurve>(bits: &[u8]) -> Result<FieldBytes<C>> {
58 if bits.len() < 16 {
62 return Err(Error::new());
63 }
64
65 let mut field_bytes = FieldBytes::<C>::default();
66
67 match bits.len().cmp(&C::FieldBytesSize::USIZE) {
68 cmp::Ordering::Equal => field_bytes.copy_from_slice(bits),
69 cmp::Ordering::Less => {
70 field_bytes[(C::FieldBytesSize::USIZE - bits.len())..].copy_from_slice(bits);
72 }
73 cmp::Ordering::Greater => {
74 field_bytes.copy_from_slice(&bits[..C::FieldBytesSize::USIZE]);
76 }
77 }
78
79 Ok(field_bytes)
80}
81
82#[cfg(feature = "algorithm")]
106#[allow(non_snake_case)]
107pub fn sign_prehashed<C>(
108 d: &NonZeroScalar<C>,
109 k: &NonZeroScalar<C>,
110 z: &FieldBytes<C>,
111) -> Result<(Signature<C>, RecoveryId)>
112where
113 C: EcdsaCurve + CurveArithmetic,
114 SignatureSize<C>: ArraySize,
115{
116 let z = Scalar::<C>::reduce(z);
117
118 let k_inv = k.invert();
120
121 let R = ProjectivePoint::<C>::mul_by_generator(k).to_affine();
123
124 let r = Scalar::<C>::reduce(&R.x());
127
128 let s = *k_inv * (z + (r * d.as_ref()));
130
131 let mut signature = Signature::from_scalars(r, s)?;
133
134 let x_is_reduced = r.to_repr() != R.x();
136 let y_is_odd = R.y_is_odd();
137 let mut recovery_id = RecoveryId::new(y_is_odd.into(), x_is_reduced);
138
139 if C::NORMALIZE_S {
141 recovery_id.0 ^= s.is_high().unwrap_u8();
142 signature = signature.normalize_s();
143 }
144
145 Ok((signature, recovery_id))
146}
147
148#[cfg(feature = "algorithm")]
163pub fn sign_prehashed_rfc6979<C, D>(
164 d: &NonZeroScalar<C>,
165 z: &FieldBytes<C>,
166 ad: &[u8],
167) -> Result<(Signature<C>, RecoveryId)>
168where
169 C: EcdsaCurve + CurveArithmetic,
170 D: Digest + BlockSizeUser + FixedOutput + FixedOutputReset,
171 SignatureSize<C>: ArraySize,
172{
173 let z2 = Scalar::<C>::reduce(z);
180
181 let k = NonZeroScalar::<C>::from_repr(rfc6979::generate_k::<D, _>(
182 &d.to_repr(),
183 &field::uint_to_bytes::<C>(&C::ORDER),
184 &z2.to_repr(),
185 ad,
186 ))
187 .unwrap();
188
189 sign_prehashed(d, &k, z)
190}
191
192#[cfg(feature = "algorithm")]
201pub fn verify_prehashed<C>(
202 q: &ProjectivePoint<C>,
203 z: &FieldBytes<C>,
204 sig: &Signature<C>,
205) -> Result<()>
206where
207 C: EcdsaCurve + CurveArithmetic,
208 SignatureSize<C>: ArraySize,
209{
210 if C::NORMALIZE_S && sig.s().is_high().into() {
211 return Err(Error::new());
212 }
213
214 let z = Scalar::<C>::reduce(z);
215 let (r, s) = sig.split_scalars();
216 let s_inv = *s.invert_vartime();
217 let u1 = z * s_inv;
218 let u2 = *r * s_inv;
219 let x = ProjectivePoint::<C>::mul_by_generator_and_mul_add_vartime(&u1, &u2, q)
220 .to_affine()
221 .x();
222
223 if *r == Scalar::<C>::reduce(&x) {
224 Ok(())
225 } else {
226 Err(Error::new())
227 }
228}
229
230#[cfg(all(test, feature = "dev"))]
231mod tests {
232 use super::bits2field;
233 use elliptic_curve::dev::MockCurve;
234 use hex_literal::hex;
235
236 #[test]
237 fn bits2field_too_small() {
238 assert!(bits2field::<MockCurve>(b"").is_err());
239 let prehash = hex!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
241 assert!(bits2field::<MockCurve>(&prehash).is_err());
242 }
243
244 #[test]
245 fn bits2field_size_less() {
246 let prehash = hex!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
247 let field_bytes = bits2field::<MockCurve>(&prehash).expect("field bytes");
248 assert_eq!(
249 field_bytes.as_slice(),
250 &hex!("00000000000000000000000000000000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
251 );
252 }
253
254 #[test]
255 fn bits2field_size_eq() {
256 let prehash = hex!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
257 let field_bytes = bits2field::<MockCurve>(&prehash).expect("field bytes");
258 assert_eq!(field_bytes.as_slice(), &prehash);
259 }
260
261 #[test]
262 fn bits2field_size_greater() {
263 let prehash = hex!(
264 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
265 );
266 let field_bytes = bits2field::<MockCurve>(&prehash).expect("field bytes");
267 assert_eq!(
268 field_bytes.as_slice(),
269 &hex!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
270 );
271 }
272}