commit 1a8c646542dcd7f6dad59f60c303289565cef824
parent 1481cf2a473459597adeec3358d6c522343afbfe
Author: Armin Preiml <apreiml@strohwolke.at>
Date: Sat, 22 Jun 2024 15:47:00 +0200
crypto::ecdsa: change api to match other crypto apis
Signed-off-by: Armin Preiml <apreiml@strohwolke.at>
Diffstat:
5 files changed, 46 insertions(+), 22 deletions(-)
diff --git a/crypto/ecdsa/ecdsa.ha b/crypto/ecdsa/ecdsa.ha
@@ -60,9 +60,11 @@ export def P384_SIGSZ = 96;
export def P521_SIGSZ = 132;
// Verifies the signature 'sig' with message 'hash' using the public key 'pub'.
-// Returns 1 on success and 0 on error. Verification is done in constant time,
-// but may return earlier if the signature format is not valid.
-export fn verify(pub: *pubkey, hash: []u8, sig: []u8) u32 = {
+// Returns [[invalidkey]] or [[invalidsig]] in case of error. An invalid key may
+// not be detected and causes an [[invalidsig]] in this case. Verification is
+// done in constant time, but may return earlier if the signature format is not
+// valid.
+export fn verify(pub: *pubkey, hash: []u8, sig: []u8) (void | error) = {
// IMPORTANT: this code is fit only for curves with a prime
// order. This is needed so that modular reduction of the X
// coordinate of a point can be done with a simple subtraction.
@@ -84,14 +86,14 @@ export fn verify(pub: *pubkey, hash: []u8, sig: []u8) u32 = {
// Signature length must be even.
if (len(sig) & 1 == 1) {
- return 0;
+ return invalidsig;
};
let rlen = len(sig) >> 1;
let generator = pub.curve.generator();
// Public key point must have the proper size for this curve.
if (len(q) != len(generator)) {
- return 0;
+ return invalidkey;
};
// Get modulus; then decode the r and s values. They must be
@@ -103,13 +105,13 @@ export fn verify(pub: *pubkey, hash: []u8, sig: []u8) u32 = {
bigint::encode(n, order);
let n0i = bigint::ninv(n[1]);
if (bigint::encodemod(r, sig[..rlen], n) == 0) {
- return 0;
+ return invalidsig;
};
if (bigint::encodemod(s, sig[rlen..2 * rlen], n) == 0) {
- return 0;
+ return invalidsig;
};
if (bigint::iszero(s) == 1) {
- return 0;
+ return invalidsig;
};
// Invert s. We do that with a modular exponentiation; we use
@@ -159,13 +161,17 @@ export fn verify(pub: *pubkey, hash: []u8, sig: []u8) u32 = {
bigint::sub(t1, n, bigint::sub(t1, n, 0) ^ 1);
res &= ~bigint::sub(t1, r, 1);
res &= bigint::iszero(t1);
- return res;
+
+ if (res == 0) {
+ return invalidsig;
+ };
};
def ORDER_LEN = (ec::MAX_COORDBITSZ + 7) >> 3;
// Signs hashed message 'hash' with the private key and stores it into 'sig'.
-// Returns the number of bytes written to sig on success or 0 on failure.
+// Returns the number of bytes written to sig on success or [[invalidkey]]
+// otherwise.
//
// The signature is done in a deterministic way according to RFC 6979, hence
// 'hashfn' and 'hashbuf' are required. 'hashfn' can be the same as the one that
@@ -180,7 +186,7 @@ export fn sign(
hashfn: *hash::hash,
hashbuf: []u8,
sig: []u8
-) u32 = {
+) (u32 | invalidkey) = {
// IMPORTANT: this code is fit only for curves with a prime
// order. This is needed so that modular reduction of the X
// coordinate of a point can be done with a simple subtraction.
@@ -211,10 +217,10 @@ export fn sign(
// private key is well-defined (not zero, and less than the
// curve order).
if (bigint::encodemod(x, priv.get_x(priv), n) == 0) {
- return 0;
+ return invalidkey;
};
if (bigint::iszero(x) == 1) {
- return 0;
+ return invalidkey;
};
// Truncate and reduce the hash value modulo the curve order.
diff --git a/crypto/ecdsa/error.ha b/crypto/ecdsa/error.ha
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: MPL-2.0
+// (c) Hare authors <https://harelang.org>
+
+// Invalid key.
+export type invalidkey = !void;
+
+// Invalid signature.
+export type invalidsig = !void;
+
+// Possible ecdsa errors.
+export type error = !(invalidkey | invalidsig);
+
+// String representation of error 'e'.
+export fn strerror(e: error) str = {
+ match (e) {
+ case invalidkey =>
+ return "Invalid key";
+ case invalidsig =>
+ return "Invalid sig";
+ };
+};
diff --git a/crypto/ecdsa/key.ha b/crypto/ecdsa/key.ha
@@ -4,9 +4,6 @@
use crypto::ec;
use io;
-// Invalid key.
-export type invalidkey = !void;
-
export type pubkey = struct {
curve: *ec::curve,
get_q: *fn (pub: *pubkey) []u8,
diff --git a/crypto/ecdsa/rfc6979+test.ha b/crypto/ecdsa/rfc6979+test.ha
@@ -377,7 +377,7 @@ fn rfc6979_cases() []testcase = alloc([
sigbuf[..len(sig)] = sig[..];
- assert(verify(pub, sum, sigbuf[..len(sig)]) == 1);
+ verify(pub, sum, sigbuf[..len(sig)])!;
let priv: *privkey = switch (tc.curve) {
case tcurveid::P256 =>
yield &p256priv();
@@ -391,7 +391,7 @@ fn rfc6979_cases() []testcase = alloc([
privkey_buf(priv)[..] = tc.x[..];
- const n = sign(priv, sum, h, hashbuf, sigbuf);
+ const n = sign(priv, sum, h, hashbuf, sigbuf)!;
assert(n == sigsz(pub));
assert(bytes::equal(sigbuf[..n], sig));
};
diff --git a/crypto/ecdsa/validate+test.ha b/crypto/ecdsa/validate+test.ha
@@ -41,15 +41,15 @@ const randbuf: [_]u8 = [
let sig: [P256_SIGSZ]u8 = [0...];
- assert(sign(&k, msghash, &hashfn, hashbuf, sig) == len(sig));
- assert(verify(&p, msghash, sig) == 1);
+ assert(sign(&k, msghash, &hashfn, hashbuf, sig)! == len(sig));
+ verify(&p, msghash, sig)!;
const save = sig[4];
sig[4] = 0xff;
- assert(verify(&p, msghash, sig) == 0);
+ assert(verify(&p, msghash, sig) is invalidsig);
sig[4] = save;
pubkey_buf(&p)[1] = 0xff;
- assert(verify(&p, msghash, sig) == 0);
+ assert(verify(&p, msghash, sig) is invalidsig);
assert(pubkey_validate(&p) is invalidkey);
};