#include #include "ge.h" #include "crypto_additions.h" #include "zeroize.h" #include "xeddsa.h" #include "crypto_verify_32.h" int xed25519_sign(unsigned char* signature_out, const unsigned char* curve25519_privkey, const unsigned char* msg, const unsigned long msg_len, const unsigned char* random) { unsigned char a[32], aneg[32]; unsigned char A[32]; ge_p3 ed_pubkey_point; unsigned char *sigbuf; /* working buffer */ unsigned char sign_bit = 0; if ((sigbuf = malloc(msg_len + 128)) == 0) { memset(signature_out, 0, 64); return -1; } /* Convert the Curve25519 privkey to an Ed25519 public key */ ge_scalarmult_base(&ed_pubkey_point, curve25519_privkey); ge_p3_tobytes(A, &ed_pubkey_point); /* Force Edwards sign bit to zero */ sign_bit = (A[31] & 0x80) >> 7; memcpy(a, curve25519_privkey, 32); sc_neg(aneg, a); sc_cmov(a, aneg, sign_bit); A[31] &= 0x7F; /* Perform an Ed25519 signature with explicit private key */ crypto_sign_modified(sigbuf, msg, msg_len, a, A, random); memmove(signature_out, sigbuf, 64); zeroize(a, 32); zeroize(aneg, 32); free(sigbuf); return 0; } int xed25519_verify(const unsigned char* signature, const unsigned char* curve25519_pubkey, const unsigned char* msg, const unsigned long msg_len) { fe u; fe y; unsigned char ed_pubkey[32]; unsigned char verifybuf[MAX_MSG_LEN + 64]; /* working buffer */ unsigned char verifybuf2[MAX_MSG_LEN + 64]; /* working buffer #2 */ if (msg_len > MAX_MSG_LEN) { return -1; } /* Convert the Curve25519 public key into an Ed25519 public key. y = (u - 1) / (u + 1) NOTE: u=-1 is converted to y=0 since fe_invert is mod-exp */ if (!fe_isreduced(curve25519_pubkey)) return -1; fe_frombytes(u, curve25519_pubkey); fe_montx_to_edy(y, u); fe_tobytes(ed_pubkey, y); memmove(verifybuf, signature, 64); memmove(verifybuf+64, msg, msg_len); /* Then perform a normal Ed25519 verification, return 0 on success */ /* The below call has a strange API: */ /* verifybuf = R || S || message */ /* verifybuf2 = internal to next call gets a copy of verifybuf, S gets replaced with pubkey for hashing */ return crypto_sign_open_modified(verifybuf2, verifybuf, 64 + msg_len, ed_pubkey); }