1#[cfg(feature = "arithmetic")]
14use {
15 crate::{RecoveryId, SignatureSize},
16 core::borrow::Borrow,
17 elliptic_curve::{
18 group::Curve as _,
19 ops::{Invert, LinearCombination, Reduce},
20 subtle::CtOption,
21 AffineArithmetic, AffineXCoordinate, Field, Group, ProjectiveArithmetic, ProjectivePoint,
22 Scalar, ScalarArithmetic,
23 },
24};
25
26#[cfg(feature = "digest")]
27use {
28 core::cmp,
29 elliptic_curve::{bigint::Encoding, FieldSize},
30 signature::{digest::Digest, PrehashSignature},
31};
32
33#[cfg(any(feature = "arithmetic", feature = "digest"))]
34use crate::{
35 elliptic_curve::{generic_array::ArrayLength, FieldBytes, PrimeCurve},
36 Error, Result, Signature,
37};
38
39#[cfg(all(feature = "arithmetic", feature = "digest"))]
40use signature::digest::FixedOutput;
41
42#[cfg(all(feature = "rfc6979"))]
43use {
44 elliptic_curve::ScalarCore,
45 signature::digest::{core_api::BlockSizeUser, FixedOutputReset},
46};
47
48#[cfg(feature = "arithmetic")]
53#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
54pub trait SignPrimitive<C>: Field + Into<FieldBytes<C>> + Reduce<C::UInt> + Sized
55where
56 C: PrimeCurve + ProjectiveArithmetic + ScalarArithmetic<Scalar = Self>,
57 SignatureSize<C>: ArrayLength<u8>,
58{
59 #[allow(non_snake_case)]
72 fn try_sign_prehashed<K>(
73 &self,
74 k: K,
75 z: FieldBytes<C>,
76 ) -> Result<(Signature<C>, Option<RecoveryId>)>
77 where
78 K: Borrow<Self> + Invert<Output = CtOption<Self>>,
79 {
80 if k.borrow().is_zero().into() {
81 return Err(Error::new());
82 }
83
84 let z = Self::from_be_bytes_reduced(z);
85
86 let k_inv = Option::<Scalar<C>>::from(k.invert()).ok_or_else(Error::new)?;
88
89 let R = (C::ProjectivePoint::generator() * k.borrow()).to_affine();
91
92 let r = Self::from_be_bytes_reduced(R.x());
95
96 let s = k_inv * (z + (r * self));
98
99 if s.is_zero().into() {
100 return Err(Error::new());
101 }
102
103 Ok((Signature::from_scalars(r, s)?, None))
105 }
106
107 #[cfg(all(feature = "rfc6979"))]
116 #[cfg_attr(docsrs, doc(cfg(feature = "rfc6979")))]
117 fn try_sign_prehashed_rfc6979<D>(
118 &self,
119 z: FieldBytes<C>,
120 ad: &[u8],
121 ) -> Result<(Signature<C>, Option<RecoveryId>)>
122 where
123 Self: From<ScalarCore<C>>,
124 C::UInt: for<'a> From<&'a Self>,
125 D: Digest + BlockSizeUser + FixedOutput<OutputSize = FieldSize<C>> + FixedOutputReset,
126 {
127 let x = C::UInt::from(self);
128 let k = rfc6979::generate_k::<D, C::UInt>(&x, &C::ORDER, &z, ad);
129 let k = Self::from(ScalarCore::<C>::new(*k).unwrap());
130 self.try_sign_prehashed(k, z)
131 }
132
133 #[cfg(all(feature = "rfc6979"))]
138 #[cfg_attr(docsrs, doc(cfg(feature = "rfc6979")))]
139 fn try_sign_digest_rfc6979<D>(
140 &self,
141 msg_digest: D,
142 ad: &[u8],
143 ) -> Result<(Signature<C>, Option<RecoveryId>)>
144 where
145 Self: From<ScalarCore<C>>,
146 C::UInt: for<'a> From<&'a Self>,
147 D: Digest + BlockSizeUser + FixedOutput<OutputSize = FieldSize<C>> + FixedOutputReset,
148 {
149 self.try_sign_prehashed_rfc6979::<D>(msg_digest.finalize_fixed(), ad)
150 }
151}
152
153#[cfg(feature = "arithmetic")]
159#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
160pub trait VerifyPrimitive<C>: AffineXCoordinate<C> + Copy + Sized
161where
162 C: PrimeCurve + AffineArithmetic<AffinePoint = Self> + ProjectiveArithmetic,
163 Scalar<C>: Reduce<C::UInt>,
164 SignatureSize<C>: ArrayLength<u8>,
165{
166 fn verify_prehashed(&self, z: FieldBytes<C>, sig: &Signature<C>) -> Result<()> {
174 let z = Scalar::<C>::from_be_bytes_reduced(z);
175 let (r, s) = sig.split_scalars();
176 let s_inv = *s.invert();
177 let u1 = z * s_inv;
178 let u2 = *r * s_inv;
179 let x = ProjectivePoint::<C>::lincomb(
180 &ProjectivePoint::<C>::generator(),
181 &u1,
182 &ProjectivePoint::<C>::from(*self),
183 &u2,
184 )
185 .to_affine()
186 .x();
187
188 if Scalar::<C>::from_be_bytes_reduced(x) == *r {
189 Ok(())
190 } else {
191 Err(Error::new())
192 }
193 }
194
195 #[cfg(feature = "digest")]
197 #[cfg_attr(docsrs, doc(cfg(feature = "digest")))]
198 fn verify_digest<D>(&self, msg_digest: D, sig: &Signature<C>) -> Result<()>
199 where
200 D: FixedOutput<OutputSize = FieldSize<C>>,
201 {
202 self.verify_prehashed(msg_digest.finalize_fixed(), sig)
203 }
204}
205
206#[cfg(feature = "digest")]
217#[cfg_attr(docsrs, doc(cfg(feature = "digest")))]
218pub trait DigestPrimitive: PrimeCurve {
219 type Digest: Digest;
224
225 fn prehash_to_field_bytes(prehash: &[u8]) -> Result<FieldBytes<Self>> {
228 if prehash.len() < Self::UInt::BYTE_SIZE / 2 {
230 return Err(Error::new());
231 }
232
233 let mut field_bytes = FieldBytes::<Self>::default();
234
235 match prehash.len().cmp(&Self::UInt::BYTE_SIZE) {
239 cmp::Ordering::Equal => field_bytes.copy_from_slice(prehash),
240 cmp::Ordering::Less => {
241 field_bytes[(Self::UInt::BYTE_SIZE - prehash.len())..].copy_from_slice(prehash);
243 }
244 cmp::Ordering::Greater => {
245 field_bytes.copy_from_slice(&prehash[..Self::UInt::BYTE_SIZE]);
247 }
248 }
249
250 Ok(field_bytes)
251 }
252}
253
254#[cfg(feature = "digest")]
255impl<C> PrehashSignature for Signature<C>
256where
257 C: DigestPrimitive,
258 <FieldSize<C> as core::ops::Add>::Output: ArrayLength<u8>,
259{
260 type Digest = C::Digest;
261}