hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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:
Mcrypto/ecdsa/ecdsa.ha | 32+++++++++++++++++++-------------
Acrypto/ecdsa/error.ha | 21+++++++++++++++++++++
Mcrypto/ecdsa/key.ha | 3---
Mcrypto/ecdsa/rfc6979+test.ha | 4++--
Mcrypto/ecdsa/validate+test.ha | 8++++----
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); };