package ecdsa import "core:crypto/hash" import secec "core:crypto/_weierstrass" // verify_raw returns true if and only if (⟺) sig is a valid signature by pub_key over // msg, hased using hash_algo, per the verification procedure specifed // in SEC 1, Version 2.0, Section 4.1.4. // // The signature format is `r | s`. @(require_results) verify_raw :: proc(pub_key: ^Public_Key, hash_algo: hash.Algorithm, msg, sig: []byte) -> bool { ensure(hash_algo != .Invalid, "crypto/edsa: invalid hash algorithm") ensure(pub_key._curve != .Invalid, "crypto/edsa: invalid curve") if len(sig) != RAW_SIGNATURE_SIZES[pub_key._curve] { return false } #partial switch pub_key._curve { case .SECP256R1: SC_SZ :: secec.SC_SIZE_P256R1 r_bytes, s_bytes := sig[:SC_SZ], sig[SC_SZ:] pk := &pub_key._impl.(secec.Point_p256r1) return verify_internal(pk, hash_algo, r_bytes, s_bytes, msg) case .SECP384R1: SC_SZ :: secec.SC_SIZE_P384R1 r_bytes, s_bytes := sig[:SC_SZ], sig[SC_SZ:] pk := &pub_key._impl.(secec.Point_p384r1) return verify_internal(pk, hash_algo, r_bytes, s_bytes, msg) } panic("crypto/ecdsa: invalid curve") } // verify_asn1 returns true if and only if (⟺) sig is a valid signature by pub_key over // msg, hased using hash_algo, per the verification procedure specifed // in SEC 1, Version 2.0, Section 4.1.4. // // The signature format is ASN.1 `SEQUENCE { r INTEGER, s INTEGER }`. @(require_results) verify_asn1 :: proc(pub_key: ^Public_Key, hash_algo: hash.Algorithm, msg, sig: []byte) -> bool { ensure(hash_algo != .Invalid, "crypto/edsa: invalid hash algorithm") ensure(pub_key._curve != .Invalid, "crypto/edsa: invalid curve") r_bytes, s_bytes, ok := parse_asn1_sig(sig) if !ok { return false } #partial switch pub_key._curve { case .SECP256R1: pk := &pub_key._impl.(secec.Point_p256r1) return verify_internal(pk, hash_algo, r_bytes, s_bytes, msg) case .SECP384R1: pk := &pub_key._impl.(secec.Point_p384r1) return verify_internal(pk, hash_algo, r_bytes, s_bytes, msg) } panic("crypto/ecdsa: invalid curve") } @(private,require_results) verify_internal :: proc(pub_key: ^$T, hash_algo: hash.Algorithm, sig_r, sig_s, msg: []byte) -> bool { when T == secec.Point_p256r1 { r, s, e, v: secec.Scalar_p256r1 = ---, ---, ---, --- u1, u2, s_inv: secec.Scalar_p256r1 = ---, ---, --- SC_SZ :: secec.SC_SIZE_P256R1 } else when T == secec.Point_p384r1 { r, s, e, v: secec.Scalar_p384r1 = ---, ---, ---, --- u1, u2, s_inv: secec.Scalar_p384r1 = ---, ---, --- SC_SZ :: secec.SC_SIZE_P384R1 } else { #panic("crypto/ecdsa: invalid curve") } if len(sig_r) > SC_SZ || len(sig_s) > SC_SZ { return false } // 1. If r and s are not both integers in the interval [1, n − 1], // output “invalid” and stop. if did_reduce := secec.sc_set_bytes(&r, sig_r); did_reduce { return false } if did_reduce := secec.sc_set_bytes(&s, sig_s); did_reduce { return false } if secec.sc_is_zero(&r) == 1 || secec.sc_is_zero(&s) == 1 { return false } // 2. Use the hash function established during the setup procedure // to compute the hash value: // H = Hash(M) // of length hashlen octets as specified in Section 3.5. If the // hash function outputs “invalid”, output “invalid” and stop. // 3. Derive an integer e from H as follows: // 3.1. Convert the octet string H to a bit string H using the // conversion routine specified in Section 2.3.2. // 3.2. Set E = H if ceil(log2(n)) >= 8(hashlen), and set E equal // to the leftmost ceil(log2(n)) bits of H if ceil(log2(n)) < // 8(hashlen). // 3.3. Convert the bit string E to an octet string E using the // conversion routine specified in Section 2.3.1. // 3.4. Convert the octet string E to an integer e using the // conversion routine specified in Section 2.3.8. h_bytes: [hash.MAX_DIGEST_SIZE]byte = --- e_bytes := hash.hash_bytes_to_buffer(hash_algo, msg, h_bytes[:]) if len(e_bytes) > SC_SZ { e_bytes = e_bytes[:SC_SZ] } _ = secec.sc_set_bytes(&e, e_bytes) // 4. Compute: u1 = e(s^−1) mod n and u2 = r(s^-1) mod n. secec.sc_inv(&s_inv, &s) secec.sc_mul(&u1, &e, &s_inv) secec.sc_mul(&u2, &r, &s_inv) // 5. Compute: R = (xR, yR) = u1 * G + u2 * QU. r_pt: T = --- secec.pt_double_scalar_mul_generator_vartime(&r_pt, pub_key, &u1, &u2) // If R = O, output “invalid” and stop. if secec.pt_is_identity(&r_pt) == 1 { return false } // 6. Convert the field element xR to an integer xR using the // conversion routine specified in Section 2.3.9. // // 7. Set v = xR mod n. r_x: [SC_SZ]byte = --- _ = secec.pt_bytes(r_x[:], nil, &r_pt) _ = secec.sc_set_bytes(&v, r_x[:]) // 8. Compare v and r — if v = r, output “valid”, and if // v != r, output “invalid”. return secec.sc_equal(&r, &v) == 1 }