we (web engine): Experimental web browser project to understand the limits of Claude
at js-bytecode 1286 lines 43 kB view raw
1//! ECDSA signature verification for P-256 and P-384 (FIPS 186-4). 2//! 3//! Supports verification of ECDSA signatures using the NIST P-256 (secp256r1) 4//! and P-384 (secp384r1) curves with SHA-256 and SHA-384 respectively. 5 6use crate::asn1::{ 7 self, Asn1Error, OID_EC_PUBLIC_KEY, OID_PRIME256V1, OID_SECP384R1, TAG_SEQUENCE, 8}; 9use crate::bigint::BigUint; 10use crate::sha2::{sha256, sha384}; 11 12use core::cmp::Ordering; 13use core::fmt; 14 15// --------------------------------------------------------------------------- 16// Error type 17// --------------------------------------------------------------------------- 18 19#[derive(Debug, Clone, PartialEq, Eq)] 20pub enum EcdsaError { 21 /// ASN.1 parsing error. 22 Asn1(Asn1Error), 23 /// Unsupported or unknown curve. 24 UnsupportedCurve, 25 /// Invalid public key (not on curve, wrong format, etc.). 26 InvalidPublicKey, 27 /// Invalid signature format. 28 InvalidSignature, 29 /// Signature component r or s is out of range [1, n-1]. 30 SignatureOutOfRange, 31 /// Signature verification failed. 32 VerificationFailed, 33 /// Invalid key format. 34 InvalidKeyFormat, 35} 36 37impl fmt::Display for EcdsaError { 38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 39 match self { 40 Self::Asn1(e) => write!(f, "ASN.1 error: {e}"), 41 Self::UnsupportedCurve => write!(f, "unsupported elliptic curve"), 42 Self::InvalidPublicKey => write!(f, "invalid EC public key"), 43 Self::InvalidSignature => write!(f, "invalid ECDSA signature format"), 44 Self::SignatureOutOfRange => write!(f, "signature component out of range"), 45 Self::VerificationFailed => write!(f, "ECDSA verification failed"), 46 Self::InvalidKeyFormat => write!(f, "invalid key format"), 47 } 48 } 49} 50 51impl From<Asn1Error> for EcdsaError { 52 fn from(e: Asn1Error) -> Self { 53 Self::Asn1(e) 54 } 55} 56 57pub type Result<T> = core::result::Result<T, EcdsaError>; 58 59// --------------------------------------------------------------------------- 60// Curve identifiers 61// --------------------------------------------------------------------------- 62 63/// Supported elliptic curves. 64#[derive(Debug, Clone, Copy, PartialEq, Eq)] 65pub enum Curve { 66 P256, 67 P384, 68} 69 70// --------------------------------------------------------------------------- 71// Modular arithmetic helpers (over BigUint) 72// --------------------------------------------------------------------------- 73 74fn mod_add(a: &BigUint, b: &BigUint, m: &BigUint) -> BigUint { 75 a.add(b).modulo(m) 76} 77 78fn mod_sub(a: &BigUint, b: &BigUint, m: &BigUint) -> BigUint { 79 if a.cmp(b) != Ordering::Less { 80 a.sub(b) 81 } else { 82 // a < b: result = m - (b - a) 83 m.sub(&b.sub(a)) 84 } 85} 86 87fn mod_mul(a: &BigUint, b: &BigUint, m: &BigUint) -> BigUint { 88 a.mul(b).modulo(m) 89} 90 91/// Modular inverse using Fermat's little theorem (for prime moduli). 92/// a^(-1) = a^(p-2) mod p 93fn mod_inv(a: &BigUint, p: &BigUint) -> BigUint { 94 let exp = p.sub(&BigUint::from_u64(2)); 95 a.modpow(&exp, p) 96} 97 98// --------------------------------------------------------------------------- 99// Curve parameters 100// --------------------------------------------------------------------------- 101 102struct CurveParams { 103 /// Field prime p. 104 p: BigUint, 105 /// Curve parameter a. 106 a: BigUint, 107 /// Curve parameter b. 108 b: BigUint, 109 /// Generator x-coordinate. 110 gx: BigUint, 111 /// Generator y-coordinate. 112 gy: BigUint, 113 /// Curve order n. 114 n: BigUint, 115 /// Byte length of field elements. 116 field_len: usize, 117} 118 119fn from_hex(s: &str) -> Vec<u8> { 120 (0..s.len()) 121 .step_by(2) 122 .map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap()) 123 .collect() 124} 125 126fn p256_params() -> CurveParams { 127 let p = BigUint::from_be_bytes(&from_hex( 128 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", 129 )); 130 let a = BigUint::from_be_bytes(&from_hex( 131 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", 132 )); 133 let b = BigUint::from_be_bytes(&from_hex( 134 "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", 135 )); 136 let gx = BigUint::from_be_bytes(&from_hex( 137 "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", 138 )); 139 let gy = BigUint::from_be_bytes(&from_hex( 140 "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", 141 )); 142 let n = BigUint::from_be_bytes(&from_hex( 143 "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", 144 )); 145 CurveParams { 146 p, 147 a, 148 b, 149 gx, 150 gy, 151 n, 152 field_len: 32, 153 } 154} 155 156fn p384_params() -> CurveParams { 157 let p = BigUint::from_be_bytes(&from_hex( 158 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF", 159 )); 160 let a = BigUint::from_be_bytes(&from_hex( 161 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC", 162 )); 163 let b = BigUint::from_be_bytes(&from_hex( 164 "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF", 165 )); 166 let gx = BigUint::from_be_bytes(&from_hex( 167 "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7", 168 )); 169 let gy = BigUint::from_be_bytes(&from_hex( 170 "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F", 171 )); 172 let n = BigUint::from_be_bytes(&from_hex( 173 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973", 174 )); 175 CurveParams { 176 p, 177 a, 178 b, 179 gx, 180 gy, 181 n, 182 field_len: 48, 183 } 184} 185 186fn curve_params(curve: Curve) -> CurveParams { 187 match curve { 188 Curve::P256 => p256_params(), 189 Curve::P384 => p384_params(), 190 } 191} 192 193// --------------------------------------------------------------------------- 194// Point types 195// --------------------------------------------------------------------------- 196 197/// A point on the curve in Jacobian coordinates (X, Y, Z). 198/// Affine (x, y) = (X/Z^2, Y/Z^3). Point at infinity has Z = 0. 199#[derive(Clone)] 200struct JacobianPoint { 201 x: BigUint, 202 y: BigUint, 203 z: BigUint, 204} 205 206impl JacobianPoint { 207 fn infinity() -> Self { 208 Self { 209 x: BigUint::one(), 210 y: BigUint::one(), 211 z: BigUint::zero(), 212 } 213 } 214 215 fn from_affine(x: &BigUint, y: &BigUint) -> Self { 216 Self { 217 x: x.clone(), 218 y: y.clone(), 219 z: BigUint::one(), 220 } 221 } 222 223 fn is_infinity(&self) -> bool { 224 self.z.is_zero() 225 } 226 227 /// Convert to affine coordinates (x, y). 228 fn to_affine(&self, p: &BigUint) -> (BigUint, BigUint) { 229 if self.is_infinity() { 230 return (BigUint::zero(), BigUint::zero()); 231 } 232 233 let z_inv = mod_inv(&self.z, p); 234 let z_inv2 = mod_mul(&z_inv, &z_inv, p); 235 let z_inv3 = mod_mul(&z_inv2, &z_inv, p); 236 237 let x = mod_mul(&self.x, &z_inv2, p); 238 let y = mod_mul(&self.y, &z_inv3, p); 239 (x, y) 240 } 241} 242 243// --------------------------------------------------------------------------- 244// Elliptic curve point operations 245// --------------------------------------------------------------------------- 246 247/// Point doubling in Jacobian coordinates. 248/// Uses the optimization for a = p - 3 (both P-256 and P-384). 249fn point_double(pt: &JacobianPoint, params: &CurveParams) -> JacobianPoint { 250 let p = &params.p; 251 252 if pt.is_infinity() { 253 return JacobianPoint::infinity(); 254 } 255 256 // For a = -3 (mod p): M = 3*(X - Z^2)*(X + Z^2) 257 let z2 = mod_mul(&pt.z, &pt.z, p); 258 let x_minus_z2 = mod_sub(&pt.x, &z2, p); 259 let x_plus_z2 = mod_add(&pt.x, &z2, p); 260 let m = mod_mul(&x_minus_z2, &x_plus_z2, p); 261 let m = mod_mul(&BigUint::from_u64(3), &m, p); 262 263 // S = 4*X*Y^2 264 let y2 = mod_mul(&pt.y, &pt.y, p); 265 let s = mod_mul(&BigUint::from_u64(4), &mod_mul(&pt.x, &y2, p), p); 266 267 // X3 = M^2 - 2*S 268 let m2 = mod_mul(&m, &m, p); 269 let two_s = mod_add(&s, &s, p); 270 let x3 = mod_sub(&m2, &two_s, p); 271 272 // Y3 = M*(S - X3) - 8*Y^4 273 let s_minus_x3 = mod_sub(&s, &x3, p); 274 let y4 = mod_mul(&y2, &y2, p); 275 let eight_y4 = mod_mul(&BigUint::from_u64(8), &y4, p); 276 let y3 = mod_sub(&mod_mul(&m, &s_minus_x3, p), &eight_y4, p); 277 278 // Z3 = 2*Y*Z 279 let z3 = mod_mul(&BigUint::from_u64(2), &mod_mul(&pt.y, &pt.z, p), p); 280 281 JacobianPoint { 282 x: x3, 283 y: y3, 284 z: z3, 285 } 286} 287 288/// Point addition in Jacobian coordinates. 289fn point_add(p1: &JacobianPoint, p2: &JacobianPoint, params: &CurveParams) -> JacobianPoint { 290 let p = &params.p; 291 292 if p1.is_infinity() { 293 return p2.clone(); 294 } 295 if p2.is_infinity() { 296 return p1.clone(); 297 } 298 299 // U1 = X1*Z2^2, U2 = X2*Z1^2 300 let z1_sq = mod_mul(&p1.z, &p1.z, p); 301 let z2_sq = mod_mul(&p2.z, &p2.z, p); 302 let u1 = mod_mul(&p1.x, &z2_sq, p); 303 let u2 = mod_mul(&p2.x, &z1_sq, p); 304 305 // S1 = Y1*Z2^3, S2 = Y2*Z1^3 306 let z1_cu = mod_mul(&z1_sq, &p1.z, p); 307 let z2_cu = mod_mul(&z2_sq, &p2.z, p); 308 let s1 = mod_mul(&p1.y, &z2_cu, p); 309 let s2 = mod_mul(&p2.y, &z1_cu, p); 310 311 if u1 == u2 { 312 if s1 == s2 { 313 // Points are equal, use doubling. 314 return point_double(p1, params); 315 } 316 // Points are inverses of each other. 317 return JacobianPoint::infinity(); 318 } 319 320 // H = U2 - U1 321 let h = mod_sub(&u2, &u1, p); 322 // R = S2 - S1 323 let r = mod_sub(&s2, &s1, p); 324 325 let h2 = mod_mul(&h, &h, p); 326 let h3 = mod_mul(&h2, &h, p); 327 let u1_h2 = mod_mul(&u1, &h2, p); 328 329 // X3 = R^2 - H^3 - 2*U1*H^2 330 let r2 = mod_mul(&r, &r, p); 331 let two_u1_h2 = mod_add(&u1_h2, &u1_h2, p); 332 let x3 = mod_sub(&mod_sub(&r2, &h3, p), &two_u1_h2, p); 333 334 // Y3 = R*(U1*H^2 - X3) - S1*H^3 335 let y3 = mod_sub( 336 &mod_mul(&r, &mod_sub(&u1_h2, &x3, p), p), 337 &mod_mul(&s1, &h3, p), 338 p, 339 ); 340 341 // Z3 = H*Z1*Z2 342 let z3 = mod_mul(&h, &mod_mul(&p1.z, &p2.z, p), p); 343 344 JacobianPoint { 345 x: x3, 346 y: y3, 347 z: z3, 348 } 349} 350 351/// Scalar multiplication using the Montgomery ladder (constant-time w.r.t. scalar bits). 352#[cfg_attr(not(test), allow(dead_code))] 353fn scalar_mult(k: &BigUint, point: &JacobianPoint, params: &CurveParams) -> JacobianPoint { 354 let bits = k.bit_len(); 355 if bits == 0 { 356 return JacobianPoint::infinity(); 357 } 358 359 // Montgomery ladder: R0 = infinity, R1 = point. 360 // For each bit from MSB to LSB: 361 // if bit == 0: R1 = R0 + R1, R0 = 2*R0 362 // if bit == 1: R0 = R0 + R1, R1 = 2*R1 363 let mut r0 = JacobianPoint::infinity(); 364 let mut r1 = point.clone(); 365 366 for i in (0..bits).rev() { 367 if k.bit(i) { 368 r0 = point_add(&r0, &r1, params); 369 r1 = point_double(&r1, params); 370 } else { 371 r1 = point_add(&r0, &r1, params); 372 r0 = point_double(&r0, params); 373 } 374 } 375 376 r0 377} 378 379/// Multi-scalar multiplication: k1*G + k2*Q using Shamir's trick. 380fn multi_scalar_mult( 381 k1: &BigUint, 382 g: &JacobianPoint, 383 k2: &BigUint, 384 q: &JacobianPoint, 385 params: &CurveParams, 386) -> JacobianPoint { 387 // Precompute G + Q. 388 let g_plus_q = point_add(g, q, params); 389 390 let bits1 = k1.bit_len(); 391 let bits2 = k2.bit_len(); 392 let max_bits = bits1.max(bits2); 393 394 let mut result = JacobianPoint::infinity(); 395 396 for i in (0..max_bits).rev() { 397 result = point_double(&result, params); 398 399 let b1 = k1.bit(i); 400 let b2 = k2.bit(i); 401 402 match (b1, b2) { 403 (true, true) => result = point_add(&result, &g_plus_q, params), 404 (true, false) => result = point_add(&result, g, params), 405 (false, true) => result = point_add(&result, q, params), 406 (false, false) => {} 407 } 408 } 409 410 result 411} 412 413// --------------------------------------------------------------------------- 414// Point validation 415// --------------------------------------------------------------------------- 416 417/// Verify that (x, y) is a valid point on the curve: y^2 = x^3 + ax + b (mod p). 418fn is_on_curve(x: &BigUint, y: &BigUint, params: &CurveParams) -> bool { 419 let p = &params.p; 420 421 // y^2 mod p 422 let y2 = mod_mul(y, y, p); 423 424 // x^3 + ax + b mod p 425 let x2 = mod_mul(x, x, p); 426 let x3 = mod_mul(&x2, x, p); 427 let ax = mod_mul(&params.a, x, p); 428 let rhs = mod_add(&mod_add(&x3, &ax, p), &params.b, p); 429 430 y2 == rhs 431} 432 433// --------------------------------------------------------------------------- 434// ECDSA public key 435// --------------------------------------------------------------------------- 436 437/// An ECDSA public key. 438#[derive(Debug, Clone)] 439pub struct EcdsaPublicKey { 440 /// The curve this key is on. 441 pub curve: Curve, 442 /// The public key point x-coordinate. 443 pub x: BigUint, 444 /// The public key point y-coordinate. 445 pub y: BigUint, 446} 447 448impl EcdsaPublicKey { 449 /// Create a public key from uncompressed point bytes (0x04 || x || y). 450 pub fn from_uncompressed(curve: Curve, data: &[u8]) -> Result<Self> { 451 let params = curve_params(curve); 452 let expected_len = 1 + 2 * params.field_len; 453 454 if data.len() != expected_len || data[0] != 0x04 { 455 return Err(EcdsaError::InvalidPublicKey); 456 } 457 458 let x = BigUint::from_be_bytes(&data[1..1 + params.field_len]); 459 let y = BigUint::from_be_bytes(&data[1 + params.field_len..]); 460 461 // Validate the point is on the curve. 462 if !is_on_curve(&x, &y, &params) { 463 return Err(EcdsaError::InvalidPublicKey); 464 } 465 466 Ok(Self { curve, x, y }) 467 } 468 469 /// Parse an EC public key from DER-encoded SubjectPublicKeyInfo. 470 /// 471 /// ```asn1 472 /// SubjectPublicKeyInfo ::= SEQUENCE { 473 /// algorithm AlgorithmIdentifier, 474 /// subjectPublicKey BIT STRING 475 /// } 476 /// AlgorithmIdentifier ::= SEQUENCE { 477 /// algorithm OID, -- ecPublicKey 478 /// parameters OID -- curve OID 479 /// } 480 /// ``` 481 pub fn from_spki_der(data: &[u8]) -> Result<Self> { 482 let seq = asn1::parse_one(data)?; 483 if seq.tag != TAG_SEQUENCE { 484 return Err(EcdsaError::InvalidKeyFormat); 485 } 486 487 let items = seq.sequence_items()?; 488 if items.len() != 2 { 489 return Err(EcdsaError::InvalidKeyFormat); 490 } 491 492 // Parse AlgorithmIdentifier. 493 let alg_id = &items[0]; 494 if alg_id.tag != TAG_SEQUENCE { 495 return Err(EcdsaError::InvalidKeyFormat); 496 } 497 let alg_items = alg_id.sequence_items()?; 498 if alg_items.len() < 2 { 499 return Err(EcdsaError::InvalidKeyFormat); 500 } 501 502 // Verify algorithm OID is ecPublicKey. 503 let alg_oid = alg_items[0].as_oid()?; 504 if !alg_oid.matches(OID_EC_PUBLIC_KEY) { 505 return Err(EcdsaError::InvalidKeyFormat); 506 } 507 508 // Determine curve from parameters OID. 509 let curve_oid = alg_items[1].as_oid()?; 510 let curve = if curve_oid.matches(OID_PRIME256V1) { 511 Curve::P256 512 } else if curve_oid.matches(OID_SECP384R1) { 513 Curve::P384 514 } else { 515 return Err(EcdsaError::UnsupportedCurve); 516 }; 517 518 // Parse the BIT STRING containing the uncompressed point. 519 let (unused_bits, key_data) = items[1].as_bit_string()?; 520 if unused_bits != 0 { 521 return Err(EcdsaError::InvalidKeyFormat); 522 } 523 524 Self::from_uncompressed(curve, key_data) 525 } 526 527 /// Verify an ECDSA signature over a message. 528 /// 529 /// The hash algorithm is determined by the curve: 530 /// - P-256 uses SHA-256 531 /// - P-384 uses SHA-384 532 pub fn verify(&self, message: &[u8], signature: &EcdsaSignature) -> Result<()> { 533 let hash = match self.curve { 534 Curve::P256 => sha256(message).to_vec(), 535 Curve::P384 => sha384(message).to_vec(), 536 }; 537 538 self.verify_prehashed(&hash, signature) 539 } 540 541 /// Verify an ECDSA signature given a pre-computed hash. 542 pub fn verify_prehashed(&self, hash: &[u8], signature: &EcdsaSignature) -> Result<()> { 543 let params = curve_params(self.curve); 544 let n = &params.n; 545 let one = BigUint::one(); 546 547 // Verify r, s in [1, n-1]. 548 let n_minus_1 = n.sub(&one); 549 if signature.r.is_zero() 550 || signature.r.cmp(&n_minus_1) == Ordering::Greater 551 || signature.s.is_zero() 552 || signature.s.cmp(&n_minus_1) == Ordering::Greater 553 { 554 return Err(EcdsaError::SignatureOutOfRange); 555 } 556 557 // Convert hash to integer z (truncated to field length if needed). 558 let z = hash_to_integer(hash, &params); 559 560 // w = s^(-1) mod n 561 let w = mod_inv(&signature.s, n); 562 563 // u1 = z * w mod n 564 let u1 = mod_mul(&z, &w, n); 565 // u2 = r * w mod n 566 let u2 = mod_mul(&signature.r, &w, n); 567 568 // (x1, y1) = u1*G + u2*Q 569 let g = JacobianPoint::from_affine(&params.gx, &params.gy); 570 let q = JacobianPoint::from_affine(&self.x, &self.y); 571 572 let point = multi_scalar_mult(&u1, &g, &u2, &q, &params); 573 574 if point.is_infinity() { 575 return Err(EcdsaError::VerificationFailed); 576 } 577 578 let (x1, _) = point.to_affine(&params.p); 579 580 // v = x1 mod n 581 let v = x1.modulo(n); 582 583 if v == signature.r { 584 Ok(()) 585 } else { 586 Err(EcdsaError::VerificationFailed) 587 } 588 } 589} 590 591/// Convert hash bytes to an integer, truncating to the curve's bit length if needed. 592fn hash_to_integer(hash: &[u8], params: &CurveParams) -> BigUint { 593 let n_bits = params.n.bit_len(); 594 let hash_bits = hash.len() * 8; 595 596 if hash_bits <= n_bits { 597 BigUint::from_be_bytes(hash) 598 } else { 599 // Truncate: take the leftmost n_bits bits. 600 let z = BigUint::from_be_bytes(hash); 601 let shift = hash_bits - n_bits; 602 // Right-shift by `shift` bits to keep only the top n_bits. 603 // Since BigUint doesn't expose a general right-shift, we use division. 604 let divisor = BigUint::from_u64(1u64 << shift.min(63)); 605 if shift <= 63 { 606 z.div_rem(&divisor).0 607 } else { 608 // For very large shifts, this shouldn't happen with P-256/P-384 + SHA-256/384. 609 z 610 } 611 } 612} 613 614// --------------------------------------------------------------------------- 615// ECDSA signature 616// --------------------------------------------------------------------------- 617 618/// An ECDSA signature (r, s). 619#[derive(Debug, Clone)] 620pub struct EcdsaSignature { 621 pub r: BigUint, 622 pub s: BigUint, 623} 624 625impl EcdsaSignature { 626 /// Create from raw r, s values. 627 pub fn new(r: BigUint, s: BigUint) -> Self { 628 Self { r, s } 629 } 630 631 /// Parse from DER-encoded signature. 632 /// 633 /// ```asn1 634 /// ECDSA-Sig-Value ::= SEQUENCE { 635 /// r INTEGER, 636 /// s INTEGER 637 /// } 638 /// ``` 639 pub fn from_der(data: &[u8]) -> Result<Self> { 640 let seq = asn1::parse_one(data)?; 641 if seq.tag != TAG_SEQUENCE { 642 return Err(EcdsaError::InvalidSignature); 643 } 644 645 let items = seq.sequence_items()?; 646 if items.len() != 2 { 647 return Err(EcdsaError::InvalidSignature); 648 } 649 650 let r_bytes = items[0] 651 .as_positive_integer() 652 .map_err(|_| EcdsaError::InvalidSignature)?; 653 let s_bytes = items[1] 654 .as_positive_integer() 655 .map_err(|_| EcdsaError::InvalidSignature)?; 656 657 Ok(Self { 658 r: BigUint::from_be_bytes(r_bytes), 659 s: BigUint::from_be_bytes(s_bytes), 660 }) 661 } 662} 663 664// --------------------------------------------------------------------------- 665// Tests 666// --------------------------------------------------------------------------- 667 668#[cfg(test)] 669mod tests { 670 use super::*; 671 672 fn hex_to_bytes(s: &str) -> Vec<u8> { 673 let s = s.replace(' ', "").replace('\n', ""); 674 (0..s.len()) 675 .step_by(2) 676 .map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap()) 677 .collect() 678 } 679 680 // ------------------------------------------------------------------- 681 // Curve parameter validation 682 // ------------------------------------------------------------------- 683 684 #[test] 685 fn p256_generator_on_curve() { 686 let params = p256_params(); 687 assert!(is_on_curve(&params.gx, &params.gy, &params)); 688 } 689 690 #[test] 691 fn p384_generator_on_curve() { 692 let params = p384_params(); 693 assert!(is_on_curve(&params.gx, &params.gy, &params)); 694 } 695 696 // ------------------------------------------------------------------- 697 // Point arithmetic 698 // ------------------------------------------------------------------- 699 700 #[test] 701 fn point_double_p256() { 702 let params = p256_params(); 703 let g = JacobianPoint::from_affine(&params.gx, &params.gy); 704 let two_g = point_double(&g, &params); 705 let (x, y) = two_g.to_affine(&params.p); 706 assert!(is_on_curve(&x, &y, &params)); 707 } 708 709 #[test] 710 fn point_add_p256() { 711 let params = p256_params(); 712 let g = JacobianPoint::from_affine(&params.gx, &params.gy); 713 let two_g = point_double(&g, &params); 714 let three_g = point_add(&two_g, &g, &params); 715 let (x, y) = three_g.to_affine(&params.p); 716 assert!(is_on_curve(&x, &y, &params)); 717 } 718 719 #[test] 720 fn scalar_mult_identity() { 721 let params = p256_params(); 722 let g = JacobianPoint::from_affine(&params.gx, &params.gy); 723 let result = scalar_mult(&BigUint::one(), &g, &params); 724 let (x, y) = result.to_affine(&params.p); 725 assert_eq!(x, params.gx); 726 assert_eq!(y, params.gy); 727 } 728 729 #[test] 730 fn scalar_mult_two() { 731 let params = p256_params(); 732 let g = JacobianPoint::from_affine(&params.gx, &params.gy); 733 let two_g_direct = point_double(&g, &params); 734 let two_g_scalar = scalar_mult(&BigUint::from_u64(2), &g, &params); 735 736 let (x1, y1) = two_g_direct.to_affine(&params.p); 737 let (x2, y2) = two_g_scalar.to_affine(&params.p); 738 assert_eq!(x1, x2); 739 assert_eq!(y1, y2); 740 } 741 742 #[test] 743 fn scalar_mult_three() { 744 let params = p256_params(); 745 let g = JacobianPoint::from_affine(&params.gx, &params.gy); 746 let two_g = point_double(&g, &params); 747 let three_g_direct = point_add(&two_g, &g, &params); 748 let three_g_scalar = scalar_mult(&BigUint::from_u64(3), &g, &params); 749 750 let (x1, y1) = three_g_direct.to_affine(&params.p); 751 let (x2, y2) = three_g_scalar.to_affine(&params.p); 752 assert_eq!(x1, x2); 753 assert_eq!(y1, y2); 754 } 755 756 #[test] 757 fn scalar_mult_order_gives_infinity() { 758 // n * G = O (point at infinity) 759 let params = p256_params(); 760 let g = JacobianPoint::from_affine(&params.gx, &params.gy); 761 let result = scalar_mult(&params.n, &g, &params); 762 assert!(result.is_infinity()); 763 } 764 765 #[test] 766 fn point_add_inverse_gives_infinity() { 767 // G + (-G) = O 768 let params = p256_params(); 769 let g = JacobianPoint::from_affine(&params.gx, &params.gy); 770 // -G has y-coordinate = p - Gy 771 let neg_gy = params.p.sub(&params.gy); 772 let neg_g = JacobianPoint::from_affine(&params.gx, &neg_gy); 773 let result = point_add(&g, &neg_g, &params); 774 assert!(result.is_infinity()); 775 } 776 777 // ------------------------------------------------------------------- 778 // Public key parsing and validation 779 // ------------------------------------------------------------------- 780 781 #[test] 782 fn public_key_from_uncompressed_p256() { 783 let params = p256_params(); 784 let mut data = vec![0x04]; 785 data.extend_from_slice(&params.gx.to_be_bytes_padded(32)); 786 data.extend_from_slice(&params.gy.to_be_bytes_padded(32)); 787 788 let key = EcdsaPublicKey::from_uncompressed(Curve::P256, &data).unwrap(); 789 assert_eq!(key.x, params.gx); 790 assert_eq!(key.y, params.gy); 791 } 792 793 #[test] 794 fn public_key_reject_not_on_curve() { 795 let mut data = vec![0x04]; 796 data.extend_from_slice(&[0x01; 32]); // x = 1 797 data.extend_from_slice(&[0x01; 32]); // y = 1 798 let result = EcdsaPublicKey::from_uncompressed(Curve::P256, &data); 799 assert_eq!(result.unwrap_err(), EcdsaError::InvalidPublicKey); 800 } 801 802 #[test] 803 fn public_key_reject_wrong_prefix() { 804 let params = p256_params(); 805 let mut data = vec![0x03]; // compressed, not supported 806 data.extend_from_slice(&params.gx.to_be_bytes_padded(32)); 807 data.extend_from_slice(&params.gy.to_be_bytes_padded(32)); 808 809 let result = EcdsaPublicKey::from_uncompressed(Curve::P256, &data); 810 assert_eq!(result.unwrap_err(), EcdsaError::InvalidPublicKey); 811 } 812 813 #[test] 814 fn public_key_reject_wrong_length() { 815 let result = EcdsaPublicKey::from_uncompressed(Curve::P256, &[0x04; 10]); 816 assert_eq!(result.unwrap_err(), EcdsaError::InvalidPublicKey); 817 } 818 819 // ------------------------------------------------------------------- 820 // Signature parsing 821 // ------------------------------------------------------------------- 822 823 #[test] 824 fn signature_from_der() { 825 // SEQUENCE { INTEGER 1, INTEGER 2 } 826 let der = hex_to_bytes("3006020101020102"); 827 let sig = EcdsaSignature::from_der(&der).unwrap(); 828 assert_eq!(sig.r, BigUint::from_u64(1)); 829 assert_eq!(sig.s, BigUint::from_u64(2)); 830 } 831 832 #[test] 833 fn signature_reject_invalid_der() { 834 let result = EcdsaSignature::from_der(&[0x00, 0x01]); 835 assert!(result.is_err()); 836 } 837 838 // ------------------------------------------------------------------- 839 // ECDSA verification: self-generated test vectors 840 // ------------------------------------------------------------------- 841 842 /// Generate an ECDSA signature for testing (not for production use). 843 /// Returns (public_key_x, public_key_y, r, s). 844 fn sign_for_test( 845 d: &BigUint, 846 k: &BigUint, 847 msg_hash: &[u8], 848 params: &CurveParams, 849 ) -> (BigUint, BigUint, BigUint, BigUint) { 850 let n = &params.n; 851 let g = JacobianPoint::from_affine(&params.gx, &params.gy); 852 853 // Q = d*G 854 let q = scalar_mult(d, &g, params); 855 let (qx, qy) = q.to_affine(&params.p); 856 857 // (rx, _) = k*G 858 let kg = scalar_mult(k, &g, params); 859 let (kgx, _) = kg.to_affine(&params.p); 860 let r = kgx.modulo(n); 861 862 // s = k^(-1) * (z + r*d) mod n 863 let z = hash_to_integer(msg_hash, params); 864 let k_inv = mod_inv(k, n); 865 let rd = mod_mul(&r, d, n); 866 let z_plus_rd = mod_add(&z, &rd, n); 867 let s = mod_mul(&k_inv, &z_plus_rd, n); 868 869 (qx, qy, r, s) 870 } 871 872 #[test] 873 fn verify_self_generated_p256() { 874 let params = p256_params(); 875 let msg = b"hello world"; 876 let hash = sha256(msg); 877 878 // Arbitrary private key and nonce (must be in [1, n-1]). 879 let d = BigUint::from_u64(123456789); 880 let k = BigUint::from_u64(987654321); 881 882 let (qx, qy, r, s) = sign_for_test(&d, &k, &hash, &params); 883 884 let mut point_data = vec![0x04]; 885 point_data.extend_from_slice(&qx.to_be_bytes_padded(32)); 886 point_data.extend_from_slice(&qy.to_be_bytes_padded(32)); 887 let key = EcdsaPublicKey::from_uncompressed(Curve::P256, &point_data).unwrap(); 888 889 let sig = EcdsaSignature::new(r, s); 890 let result = key.verify(msg, &sig); 891 assert!( 892 result.is_ok(), 893 "self-generated P-256 signature should verify: {result:?}" 894 ); 895 } 896 897 #[test] 898 fn verify_self_generated_p256_different_key() { 899 let params = p256_params(); 900 let msg = b"test message for ecdsa verification"; 901 let hash = sha256(msg); 902 903 let d = BigUint::from_be_bytes(&hex_to_bytes( 904 "c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721", 905 )); 906 let k = BigUint::from_be_bytes(&hex_to_bytes( 907 "a6e3c57dd01abe90086538398355dd4c3b17aa873382b0f24d6129493d8aad60", 908 )); 909 910 let (qx, qy, r, s) = sign_for_test(&d, &k, &hash, &params); 911 912 let mut point_data = vec![0x04]; 913 point_data.extend_from_slice(&qx.to_be_bytes_padded(32)); 914 point_data.extend_from_slice(&qy.to_be_bytes_padded(32)); 915 let key = EcdsaPublicKey::from_uncompressed(Curve::P256, &point_data).unwrap(); 916 917 let sig = EcdsaSignature::new(r, s); 918 let result = key.verify(msg, &sig); 919 assert!( 920 result.is_ok(), 921 "P-256 with RFC 6979 key should verify: {result:?}" 922 ); 923 } 924 925 #[test] 926 fn verify_self_generated_p256_tampered() { 927 let params = p256_params(); 928 let msg = b"hello world"; 929 let hash = sha256(msg); 930 931 let d = BigUint::from_u64(123456789); 932 let k = BigUint::from_u64(987654321); 933 934 let (qx, qy, r, s) = sign_for_test(&d, &k, &hash, &params); 935 936 let mut point_data = vec![0x04]; 937 point_data.extend_from_slice(&qx.to_be_bytes_padded(32)); 938 point_data.extend_from_slice(&qy.to_be_bytes_padded(32)); 939 let key = EcdsaPublicKey::from_uncompressed(Curve::P256, &point_data).unwrap(); 940 941 // Tamper with the signature. 942 let tampered_s = s.add(&BigUint::one()); 943 let sig = EcdsaSignature::new(r, tampered_s); 944 let result = key.verify(msg, &sig); 945 assert!(result.is_err(), "tampered signature should fail"); 946 } 947 948 #[test] 949 fn verify_self_generated_p256_wrong_message() { 950 let params = p256_params(); 951 let msg = b"hello world"; 952 let hash = sha256(msg); 953 954 let d = BigUint::from_u64(123456789); 955 let k = BigUint::from_u64(987654321); 956 957 let (qx, qy, r, s) = sign_for_test(&d, &k, &hash, &params); 958 959 let mut point_data = vec![0x04]; 960 point_data.extend_from_slice(&qx.to_be_bytes_padded(32)); 961 point_data.extend_from_slice(&qy.to_be_bytes_padded(32)); 962 let key = EcdsaPublicKey::from_uncompressed(Curve::P256, &point_data).unwrap(); 963 964 let sig = EcdsaSignature::new(r, s); 965 let result = key.verify(b"wrong message", &sig); 966 assert!(result.is_err(), "wrong message should fail verification"); 967 } 968 969 #[test] 970 fn verify_self_generated_p384() { 971 let params = p384_params(); 972 let msg = b"hello p384"; 973 let hash = sha384(msg); 974 975 let d = BigUint::from_u64(999999937); // a prime number 976 let k = BigUint::from_u64(999999893); // another prime 977 978 let (qx, qy, r, s) = sign_for_test(&d, &k, &hash, &params); 979 980 let mut point_data = vec![0x04]; 981 point_data.extend_from_slice(&qx.to_be_bytes_padded(48)); 982 point_data.extend_from_slice(&qy.to_be_bytes_padded(48)); 983 let key = EcdsaPublicKey::from_uncompressed(Curve::P384, &point_data).unwrap(); 984 985 let sig = EcdsaSignature::new(r, s); 986 let result = key.verify(msg, &sig); 987 assert!( 988 result.is_ok(), 989 "self-generated P-384 signature should verify: {result:?}" 990 ); 991 } 992 993 #[test] 994 fn verify_self_generated_p384_wrong_message() { 995 let params = p384_params(); 996 let msg = b"hello p384"; 997 let hash = sha384(msg); 998 999 let d = BigUint::from_u64(999999937); 1000 let k = BigUint::from_u64(999999893); 1001 1002 let (qx, qy, r, s) = sign_for_test(&d, &k, &hash, &params); 1003 1004 let mut point_data = vec![0x04]; 1005 point_data.extend_from_slice(&qx.to_be_bytes_padded(48)); 1006 point_data.extend_from_slice(&qy.to_be_bytes_padded(48)); 1007 let key = EcdsaPublicKey::from_uncompressed(Curve::P384, &point_data).unwrap(); 1008 1009 let sig = EcdsaSignature::new(r, s); 1010 let result = key.verify(b"different message", &sig); 1011 assert!(result.is_err(), "P-384 wrong message should fail"); 1012 } 1013 1014 // ------------------------------------------------------------------- 1015 // RFC 6979 test vector (P-256, SHA-256, message "sample") 1016 // ------------------------------------------------------------------- 1017 1018 #[test] 1019 fn verify_rfc6979_p256_sha256() { 1020 // From RFC 6979, Appendix A.2.5. 1021 // Private key x = C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721 1022 // Public key: 1023 let qx = hex_to_bytes("60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6"); 1024 let qy = hex_to_bytes("7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299"); 1025 // Message: "sample", signature with SHA-256: 1026 let r = hex_to_bytes("EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716"); 1027 let s = hex_to_bytes("F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8"); 1028 1029 let mut point_data = vec![0x04]; 1030 point_data.extend_from_slice(&qx); 1031 point_data.extend_from_slice(&qy); 1032 let key = EcdsaPublicKey::from_uncompressed(Curve::P256, &point_data).unwrap(); 1033 1034 let sig = EcdsaSignature::new(BigUint::from_be_bytes(&r), BigUint::from_be_bytes(&s)); 1035 1036 let result = key.verify(b"sample", &sig); 1037 assert!( 1038 result.is_ok(), 1039 "RFC 6979 P-256/SHA-256 'sample' should verify: {result:?}" 1040 ); 1041 } 1042 1043 #[test] 1044 fn verify_rfc6979_p256_sha256_test() { 1045 // From RFC 6979, Appendix A.2.5, message "test". 1046 let qx = hex_to_bytes("60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6"); 1047 let qy = hex_to_bytes("7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299"); 1048 let r = hex_to_bytes("F1ABB023518351CD71D881567B1EA663ED3EFCF6C5132B354F28D3B0B7D38367"); 1049 let s = hex_to_bytes("019F4113742A2B14BD25926B49C649155F267E60D3814B4C0CC84250E46F0083"); 1050 1051 let mut point_data = vec![0x04]; 1052 point_data.extend_from_slice(&qx); 1053 point_data.extend_from_slice(&qy); 1054 let key = EcdsaPublicKey::from_uncompressed(Curve::P256, &point_data).unwrap(); 1055 1056 let sig = EcdsaSignature::new(BigUint::from_be_bytes(&r), BigUint::from_be_bytes(&s)); 1057 1058 let result = key.verify(b"test", &sig); 1059 assert!( 1060 result.is_ok(), 1061 "RFC 6979 P-256/SHA-256 'test' should verify: {result:?}" 1062 ); 1063 } 1064 1065 // ------------------------------------------------------------------- 1066 // Prehashed verification 1067 // ------------------------------------------------------------------- 1068 1069 #[test] 1070 fn verify_prehashed_p256() { 1071 let params = p256_params(); 1072 let msg = b"prehash test"; 1073 let hash = sha256(msg); 1074 1075 let d = BigUint::from_u64(42424242); 1076 let k = BigUint::from_u64(13131313); 1077 1078 let (qx, qy, r, s) = sign_for_test(&d, &k, &hash, &params); 1079 1080 let mut point_data = vec![0x04]; 1081 point_data.extend_from_slice(&qx.to_be_bytes_padded(32)); 1082 point_data.extend_from_slice(&qy.to_be_bytes_padded(32)); 1083 let key = EcdsaPublicKey::from_uncompressed(Curve::P256, &point_data).unwrap(); 1084 1085 let sig = EcdsaSignature::new(r, s); 1086 let result = key.verify_prehashed(&hash, &sig); 1087 assert!(result.is_ok(), "prehashed verify should pass: {result:?}"); 1088 } 1089 1090 // ------------------------------------------------------------------- 1091 // Signature rejection tests 1092 // ------------------------------------------------------------------- 1093 1094 #[test] 1095 fn reject_signature_r_zero() { 1096 let params = p256_params(); 1097 let mut point_data = vec![0x04]; 1098 point_data.extend_from_slice(&params.gx.to_be_bytes_padded(32)); 1099 point_data.extend_from_slice(&params.gy.to_be_bytes_padded(32)); 1100 let key = EcdsaPublicKey::from_uncompressed(Curve::P256, &point_data).unwrap(); 1101 1102 let sig = EcdsaSignature::new(BigUint::zero(), BigUint::one()); 1103 let result = key.verify(b"test", &sig); 1104 assert_eq!(result.unwrap_err(), EcdsaError::SignatureOutOfRange); 1105 } 1106 1107 #[test] 1108 fn reject_signature_s_zero() { 1109 let params = p256_params(); 1110 let mut point_data = vec![0x04]; 1111 point_data.extend_from_slice(&params.gx.to_be_bytes_padded(32)); 1112 point_data.extend_from_slice(&params.gy.to_be_bytes_padded(32)); 1113 let key = EcdsaPublicKey::from_uncompressed(Curve::P256, &point_data).unwrap(); 1114 1115 let sig = EcdsaSignature::new(BigUint::one(), BigUint::zero()); 1116 let result = key.verify(b"test", &sig); 1117 assert_eq!(result.unwrap_err(), EcdsaError::SignatureOutOfRange); 1118 } 1119 1120 #[test] 1121 fn reject_signature_r_equals_n() { 1122 let params = p256_params(); 1123 let mut point_data = vec![0x04]; 1124 point_data.extend_from_slice(&params.gx.to_be_bytes_padded(32)); 1125 point_data.extend_from_slice(&params.gy.to_be_bytes_padded(32)); 1126 let key = EcdsaPublicKey::from_uncompressed(Curve::P256, &point_data).unwrap(); 1127 1128 let sig = EcdsaSignature::new(params.n.clone(), BigUint::one()); 1129 let result = key.verify(b"test", &sig); 1130 assert_eq!(result.unwrap_err(), EcdsaError::SignatureOutOfRange); 1131 } 1132 1133 // ------------------------------------------------------------------- 1134 // SPKI DER parsing 1135 // ------------------------------------------------------------------- 1136 1137 /// Encode a DER length. 1138 fn der_length(len: usize) -> Vec<u8> { 1139 if len < 0x80 { 1140 vec![len as u8] 1141 } else if len < 0x100 { 1142 vec![0x81, len as u8] 1143 } else { 1144 vec![0x82, (len >> 8) as u8, len as u8] 1145 } 1146 } 1147 1148 /// Build a DER TLV. 1149 fn der_tlv(tag: u8, value: &[u8]) -> Vec<u8> { 1150 let mut out = vec![tag]; 1151 out.extend_from_slice(&der_length(value.len())); 1152 out.extend_from_slice(value); 1153 out 1154 } 1155 1156 #[test] 1157 fn parse_spki_p256() { 1158 let params = p256_params(); 1159 1160 // Build AlgorithmIdentifier: SEQUENCE { OID ecPublicKey, OID prime256v1 } 1161 let alg_oid = der_tlv(0x06, OID_EC_PUBLIC_KEY); 1162 let curve_oid = der_tlv(0x06, OID_PRIME256V1); 1163 let mut alg_content = Vec::new(); 1164 alg_content.extend_from_slice(&alg_oid); 1165 alg_content.extend_from_slice(&curve_oid); 1166 let alg_id = der_tlv(0x30, &alg_content); 1167 1168 // Build BIT STRING with uncompressed point. 1169 let mut point = vec![0x04]; 1170 point.extend_from_slice(&params.gx.to_be_bytes_padded(32)); 1171 point.extend_from_slice(&params.gy.to_be_bytes_padded(32)); 1172 let mut bit_string_value = vec![0x00]; // unused bits 1173 bit_string_value.extend_from_slice(&point); 1174 let bit_string = der_tlv(0x03, &bit_string_value); 1175 1176 let mut spki_content = Vec::new(); 1177 spki_content.extend_from_slice(&alg_id); 1178 spki_content.extend_from_slice(&bit_string); 1179 let spki = der_tlv(0x30, &spki_content); 1180 1181 let key = EcdsaPublicKey::from_spki_der(&spki).unwrap(); 1182 assert_eq!(key.curve, Curve::P256); 1183 assert_eq!(key.x, params.gx); 1184 assert_eq!(key.y, params.gy); 1185 } 1186 1187 #[test] 1188 fn parse_spki_p384() { 1189 let params = p384_params(); 1190 1191 let alg_oid = der_tlv(0x06, OID_EC_PUBLIC_KEY); 1192 let curve_oid = der_tlv(0x06, OID_SECP384R1); 1193 let mut alg_content = Vec::new(); 1194 alg_content.extend_from_slice(&alg_oid); 1195 alg_content.extend_from_slice(&curve_oid); 1196 let alg_id = der_tlv(0x30, &alg_content); 1197 1198 let mut point = vec![0x04]; 1199 point.extend_from_slice(&params.gx.to_be_bytes_padded(48)); 1200 point.extend_from_slice(&params.gy.to_be_bytes_padded(48)); 1201 let mut bit_string_value = vec![0x00]; 1202 bit_string_value.extend_from_slice(&point); 1203 let bit_string = der_tlv(0x03, &bit_string_value); 1204 1205 let mut spki_content = Vec::new(); 1206 spki_content.extend_from_slice(&alg_id); 1207 spki_content.extend_from_slice(&bit_string); 1208 let spki = der_tlv(0x30, &spki_content); 1209 1210 let key = EcdsaPublicKey::from_spki_der(&spki).unwrap(); 1211 assert_eq!(key.curve, Curve::P384); 1212 assert_eq!(key.x, params.gx); 1213 assert_eq!(key.y, params.gy); 1214 } 1215 1216 #[test] 1217 fn parse_spki_reject_wrong_algorithm() { 1218 let params = p256_params(); 1219 1220 // Use RSA OID instead of ecPublicKey. 1221 let wrong_oid = der_tlv( 1222 0x06, 1223 &[0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01], 1224 ); 1225 let curve_oid = der_tlv(0x06, OID_PRIME256V1); 1226 let mut alg_content = Vec::new(); 1227 alg_content.extend_from_slice(&wrong_oid); 1228 alg_content.extend_from_slice(&curve_oid); 1229 let alg_id = der_tlv(0x30, &alg_content); 1230 1231 let mut point = vec![0x04]; 1232 point.extend_from_slice(&params.gx.to_be_bytes_padded(32)); 1233 point.extend_from_slice(&params.gy.to_be_bytes_padded(32)); 1234 let mut bit_string_value = vec![0x00]; 1235 bit_string_value.extend_from_slice(&point); 1236 let bit_string = der_tlv(0x03, &bit_string_value); 1237 1238 let mut spki_content = Vec::new(); 1239 spki_content.extend_from_slice(&alg_id); 1240 spki_content.extend_from_slice(&bit_string); 1241 let spki = der_tlv(0x30, &spki_content); 1242 1243 let result = EcdsaPublicKey::from_spki_der(&spki); 1244 assert_eq!(result.unwrap_err(), EcdsaError::InvalidKeyFormat); 1245 } 1246 1247 // ------------------------------------------------------------------- 1248 // Modular arithmetic 1249 // ------------------------------------------------------------------- 1250 1251 #[test] 1252 fn mod_sub_no_underflow() { 1253 let a = BigUint::from_u64(10); 1254 let b = BigUint::from_u64(3); 1255 let m = BigUint::from_u64(17); 1256 assert_eq!(mod_sub(&a, &b, &m), BigUint::from_u64(7)); 1257 } 1258 1259 #[test] 1260 fn mod_sub_with_underflow() { 1261 let a = BigUint::from_u64(3); 1262 let b = BigUint::from_u64(10); 1263 let m = BigUint::from_u64(17); 1264 // 3 - 10 mod 17 = -7 mod 17 = 10 1265 assert_eq!(mod_sub(&a, &b, &m), BigUint::from_u64(10)); 1266 } 1267 1268 #[test] 1269 fn mod_inv_basic() { 1270 // 3^(-1) mod 7 = 5 (since 3*5 = 15 = 1 mod 7) 1271 let a = BigUint::from_u64(3); 1272 let m = BigUint::from_u64(7); 1273 let inv = mod_inv(&a, &m); 1274 assert_eq!(inv, BigUint::from_u64(5)); 1275 } 1276 1277 #[test] 1278 fn mod_inv_verify() { 1279 // a * a^(-1) mod p = 1 1280 let a = BigUint::from_u64(12345); 1281 let p = BigUint::from_u64(65537); // prime 1282 let inv = mod_inv(&a, &p); 1283 let product = mod_mul(&a, &inv, &p); 1284 assert_eq!(product, BigUint::one()); 1285 } 1286}