1use super::arith::Field;
25use super::point::{AffinePoint, Curve, Point};
26use ic_core::traits::{Digest, Mac};
27use ic_core::{ensure, Result, Zeroize};
28
29pub trait EcdsaCurve: Curve + crate::nist::gentable::HasGeneratorTable {
31 type Digest: Digest;
33 type Hmac: Mac;
35}
36
37const MAX_SCALAR: usize = 66;
39
40const MAX_T: usize = 128;
46
47fn bits2int(t: &[u8], order_bits: usize, out: &mut [u8]) {
56 let m = order_bits.div_ceil(8);
57 let shift = m * 8 - order_bits;
58 for i in 0..m {
59 let hi = if i == 0 { 0 } else { t[i - 1] };
60 let carry = if shift == 0 { 0 } else { hi << (8 - shift) };
61 out[i] = (t[i] >> shift) | carry;
62 }
63}
64
65fn rfc6979_nonce<C: EcdsaCurve>(
72 private_key: &[u8],
73 h1: &[u8],
74 attempt: usize,
75) -> Result<C::Scalar> {
76 let n = C::SCALAR_BYTES;
77 ensure!(n <= MAX_SCALAR, InvalidParameter, "scalar too wide");
78
79 let e = C::scalar_reduce_slice(h1);
81 let e_octets = e.to_bytes();
82 let e_octets = e_octets.as_ref();
83
84 let tag_len = <C::Hmac as Mac>::TAG_LEN;
85 let mut v_buf = [0x01u8; MAX_SCALAR];
86 let mut k_buf = [0x00u8; MAX_SCALAR];
87 let v = &mut v_buf[..tag_len];
88 let k = &mut k_buf[..tag_len];
89
90 let mut mac = C::Hmac::new(k)?;
92 mac.update(v);
93 mac.update(&[0x00]);
94 mac.update(private_key);
95 mac.update(e_octets);
96 k.copy_from_slice(mac.finalize().as_ref());
97 let t = C::Hmac::mac(k, v)?;
98 v.copy_from_slice(t.as_ref());
99
100 let mut mac = C::Hmac::new(k)?;
102 mac.update(v);
103 mac.update(&[0x01]);
104 mac.update(private_key);
105 mac.update(e_octets);
106 k.copy_from_slice(mac.finalize().as_ref());
107 let t = C::Hmac::mac(k, v)?;
108 v.copy_from_slice(t.as_ref());
109
110 let mut found = 0usize;
111 let mut t_buf = [0u8; MAX_T];
112 let mut candidate_buf = [0u8; MAX_SCALAR];
113
114 for _ in 0..(attempt + 1) * 8 + 16 {
116 let mut tlen = 0usize;
121 while tlen * 8 < C::ORDER_BITS {
122 let block = C::Hmac::mac(k, v)?;
123 v.copy_from_slice(block.as_ref());
124 let take = core::cmp::min(tag_len, MAX_T - tlen);
125 t_buf[tlen..tlen + take].copy_from_slice(&v[..take]);
126 tlen += take;
127 }
128 bits2int(&t_buf[..tlen], C::ORDER_BITS, &mut candidate_buf);
129
130 if let Some(candidate) = C::scalar_from_slice(&candidate_buf[..n]) {
132 if !bool::from(candidate.is_zero()) {
133 if found == attempt {
134 k_buf.zeroize();
135 v_buf.zeroize();
136 t_buf.zeroize();
137 candidate_buf.zeroize();
138 return Ok(candidate);
139 }
140 found += 1;
141 }
142 }
143
144 let mut mac = C::Hmac::new(k)?;
146 mac.update(v);
147 mac.update(&[0x00]);
148 k.copy_from_slice(mac.finalize().as_ref());
149 let t = C::Hmac::mac(k, v)?;
150 v.copy_from_slice(t.as_ref());
151 }
152
153 k_buf.zeroize();
154 v_buf.zeroize();
155 t_buf.zeroize();
156 candidate_buf.zeroize();
157 Err(ic_core::err!(
158 Internal,
159 "rfc6979 nonce generation did not converge"
160 ))
161}
162
163fn load_private_key<C: Curve>(bytes: &[u8]) -> Result<C::Scalar> {
165 ensure!(
166 bytes.len() == C::SCALAR_BYTES,
167 InvalidLength,
168 "ecdsa private key"
169 );
170 let d = C::scalar_from_slice(bytes).ok_or(ic_core::err!(
171 InvalidParameter,
172 "ecdsa private key is not less than n"
173 ))?;
174 ensure!(
175 !bool::from(d.is_zero()),
176 InvalidParameter,
177 "ecdsa private key must not be zero"
178 );
179 Ok(d)
180}
181
182pub fn public_key<C: EcdsaCurve>(private_key: &[u8], out: &mut [u8]) -> Result<()> {
184 ic_core::module::operational()?;
185 ensure!(
186 out.len() == 1 + 2 * C::FIELD_BYTES,
187 InvalidLength,
188 "ecdsa public key buffer"
189 );
190 let d = load_private_key::<C>(private_key)?;
191 let q = Point::<C>::mul_generator(&d)
192 .to_affine()
193 .ok_or(ic_core::err!(Internal, "public key is the identity"))?;
194 ensure!(
197 q.write_uncompressed(out),
198 Internal,
199 "public key buffer length disagrees with the encoder"
200 );
201 Ok(())
202}
203
204pub fn public_key_compressed<C: EcdsaCurve>(private_key: &[u8], out: &mut [u8]) -> Result<()> {
206 ic_core::module::operational()?;
207 ensure!(
208 out.len() == 1 + C::FIELD_BYTES,
209 InvalidLength,
210 "ecdsa compressed key buffer"
211 );
212 let d = load_private_key::<C>(private_key)?;
213 let q = Point::<C>::mul_generator(&d)
214 .to_affine()
215 .ok_or(ic_core::err!(Internal, "public key is the identity"))?;
216 ensure!(
217 q.write_compressed(out),
218 Internal,
219 "compressed key buffer length disagrees with the encoder"
220 );
221 Ok(())
222}
223
224pub fn sign<C: EcdsaCurve>(private_key: &[u8], message: &[u8], signature: &mut [u8]) -> Result<()> {
226 ic_core::module::operational()?;
227 let n = C::SCALAR_BYTES;
228 ensure!(
229 signature.len() == 2 * n,
230 InvalidLength,
231 "ecdsa signature buffer"
232 );
233 let d = load_private_key::<C>(private_key)?;
234
235 let digest = C::Digest::digest(message);
236 let h1 = digest.as_ref();
237 let e = C::scalar_reduce_slice(h1);
238
239 for attempt in 0..8 {
242 let k = rfc6979_nonce::<C>(private_key, h1, attempt)?;
243
244 let point = Point::<C>::mul_generator(&k)
245 .to_affine()
246 .ok_or(ic_core::err!(Internal, "kG is the identity"))?;
247 let r = C::scalar_reduce_slice(point.x.to_bytes().as_ref());
248 if bool::from(r.is_zero()) {
249 continue;
250 }
251
252 let s = k.invert().mul(&e.add(&r.mul(&d)));
254 if bool::from(s.is_zero()) {
255 continue;
256 }
257
258 signature[..n].copy_from_slice(r.to_bytes().as_ref());
259 signature[n..].copy_from_slice(s.to_bytes().as_ref());
260 return Ok(());
261 }
262
263 Err(ic_core::err!(Internal, "ecdsa signing did not converge"))
264}
265
266pub fn verify<C: EcdsaCurve>(public_key: &[u8], message: &[u8], signature: &[u8]) -> Result<()> {
268 ic_core::module::operational()?;
269 let digest = C::Digest::digest(message);
270 verify_digest::<C>(public_key, digest.as_ref(), signature)
271}
272
273pub const PREHASH_LENS: [usize; 4] = [28, 32, 48, 64];
281
282pub fn verify_prehash<C: EcdsaCurve>(
303 public_key: &[u8],
304 digest: &[u8],
305 signature: &[u8],
306) -> Result<()> {
307 ic_core::module::operational()?;
308 ensure!(
309 PREHASH_LENS.contains(&digest.len()),
310 InvalidLength,
311 "ecdsa digest must be 28, 32, 48 or 64 bytes"
312 );
313 ensure!(
314 digest.len() >= min_prehash_len::<C>(),
315 InvalidLength,
316 "ecdsa digest narrower than the curve's strength"
317 );
318 verify_digest::<C>(public_key, digest, signature)
319}
320
321pub fn min_prehash_len<C: EcdsaCurve>() -> usize {
324 core::cmp::min(C::SCALAR_BYTES, 64)
325}
326
327fn verify_digest<C: EcdsaCurve>(public_key: &[u8], digest: &[u8], signature: &[u8]) -> Result<()> {
329 let n = C::SCALAR_BYTES;
330 ensure!(signature.len() == 2 * n, InvalidLength, "ecdsa signature");
331
332 let q = AffinePoint::<C>::from_sec1(public_key).ok_or(ic_core::err!(
333 MalformedEncoding,
334 "ecdsa public key is not a curve point"
335 ))?;
336
337 let r = C::scalar_from_slice(&signature[..n]).ok_or(ic_core::err!(
341 MalformedEncoding,
342 "ecdsa r is not less than n"
343 ))?;
344 let s = C::scalar_from_slice(&signature[n..]).ok_or(ic_core::err!(
345 MalformedEncoding,
346 "ecdsa s is not less than n"
347 ))?;
348 ensure!(
349 !bool::from(r.is_zero()) && !bool::from(s.is_zero()),
350 MalformedEncoding,
351 "ecdsa r and s must be non-zero"
352 );
353
354 let e = C::scalar_reduce_slice(digest);
355
356 let w = s.invert();
357 let u1 = e.mul(&w);
358 let u2 = r.mul(&w);
359
360 let point = Point::<C>::mul_double(&u1, &Point::<C>::from_affine(&q), &u2);
361 let affine = point
362 .to_affine()
363 .ok_or(ic_core::err!(AuthenticationFailed, "ecdsa"))?;
364
365 let v = C::scalar_reduce_slice(affine.x.to_bytes().as_ref());
366 if bool::from(v.ct_eq(&r)) {
367 Ok(())
368 } else {
369 Err(ic_core::err!(AuthenticationFailed, "ecdsa"))
370 }
371}
372
373fn is_high_s<C: Curve>(s: &C::Scalar) -> bool {
375 let bytes = s.to_bytes();
376 let bytes = bytes.as_ref();
377
378 let n_bytes = C::Scalar::ZERO.sub(&C::Scalar::ONE).to_bytes();
380 let n_bytes = n_bytes.as_ref();
381 let mut half = [0u8; MAX_SCALAR];
384 let len = n_bytes.len();
385 let mut carry = 0u8;
386 for i in 0..len {
387 let v = n_bytes[i];
388 half[i] = (v >> 1) | (carry << 7);
389 carry = v & 1;
390 }
391
392 for i in 0..len {
395 if bytes[i] != half[i] {
396 return bytes[i] > half[i];
397 }
398 }
399 false
400}
401
402pub fn normalize_s<C: EcdsaCurve>(signature: &mut [u8]) -> Result<()> {
410 let n = C::SCALAR_BYTES;
411 ensure!(signature.len() == 2 * n, InvalidLength, "ecdsa signature");
412 let s = C::scalar_from_slice(&signature[n..]).ok_or(ic_core::err!(
413 MalformedEncoding,
414 "ecdsa s is not less than n"
415 ))?;
416 if is_high_s::<C>(&s) {
417 let flipped = C::Scalar::ZERO.sub(&s);
418 signature[n..].copy_from_slice(flipped.to_bytes().as_ref());
419 }
420 Ok(())
421}
422
423pub fn has_low_s<C: EcdsaCurve>(signature: &[u8]) -> Result<bool> {
425 let n = C::SCALAR_BYTES;
426 ensure!(signature.len() == 2 * n, InvalidLength, "ecdsa signature");
427 let s = C::scalar_from_slice(&signature[n..]).ok_or(ic_core::err!(
428 MalformedEncoding,
429 "ecdsa s is not less than n"
430 ))?;
431 Ok(!is_high_s::<C>(&s))
432}