diff options
Diffstat (limited to 'src/libsodium/crypto_sign/ed25519/ref10/open.c')
-rw-r--r-- | src/libsodium/crypto_sign/ed25519/ref10/open.c | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/src/libsodium/crypto_sign/ed25519/ref10/open.c b/src/libsodium/crypto_sign/ed25519/ref10/open.c new file mode 100644 index 0000000..36eb084 --- /dev/null +++ b/src/libsodium/crypto_sign/ed25519/ref10/open.c @@ -0,0 +1,78 @@ + +#include <limits.h> +#include <string.h> + +#include "api.h" +#include "crypto_hash_sha512.h" +#include "crypto_verify_32.h" +#include "ge.h" +#include "sc.h" +#include "utils.h" + +int +crypto_sign_verify_detached(const unsigned char *sig, const unsigned char *m, + unsigned long long mlen, const unsigned char *pk) +{ + crypto_hash_sha512_state hs; + unsigned char h[64]; + unsigned char rcheck[32]; + unsigned int i; + unsigned char d = 0; + ge_p3 A; + ge_p2 R; + + if (sig[63] & 224) { + return -1; + } + if (ge_frombytes_negate_vartime(&A, pk) != 0) { + return -1; + } + for (i = 0; i < 32; ++i) { + d |= pk[i]; + } + if (d == 0) { + return -1; + } + crypto_hash_sha512_init(&hs); + crypto_hash_sha512_update(&hs, sig, 32); + crypto_hash_sha512_update(&hs, pk, 32); + crypto_hash_sha512_update(&hs, m, mlen); + crypto_hash_sha512_final(&hs, h); + sc_reduce(h); + + ge_double_scalarmult_vartime(&R, h, &A, sig + 32); + ge_tobytes(rcheck, &R); + + if (crypto_verify_32(rcheck, sig) != 0) { + return -1; + } + if (sig == rcheck) { + return -1; + } + if (sodium_memcmp(sig, rcheck, 32) != 0) { + return -1; + } + return 0; +} + +int +crypto_sign_open(unsigned char *m, unsigned long long *mlen, + const unsigned char *sm, unsigned long long smlen, + const unsigned char *pk) +{ + if (smlen < 64 || smlen > SIZE_MAX) { + goto badsig; + } + if (crypto_sign_verify_detached(sm, sm + 64, smlen - 64, pk) != 0) { + memset(m, 0, smlen - 64); + goto badsig; + } + *mlen = smlen - 64; + memmove(m, sm + 64, *mlen); + + return 0; + +badsig: + *mlen = 0; + return -1; +} |