static themis_status_t ed_point_sign(uint8_t pos, const uint8_t *scalar, const ge_p3 *point, uint8_t *signature) { uint8_t r[ED25519_GE_LENGTH]; ge_p3 R; uint8_t k[64]; soter_hash_ctx_t hash_ctx; size_t hash_length = 64; themis_status_t res; generate_random_32(r); ge_scalarmult_base(&R, r); ge_p3_tobytes(k, &R); res = soter_hash_init(&hash_ctx, SOTER_HASH_SHA512); if (THEMIS_SUCCESS != res) { return res; } res = soter_hash_update(&hash_ctx, k, ED25519_GE_LENGTH); if (THEMIS_SUCCESS != res) { soter_hash_final(&hash_ctx, k, &hash_length); return res; } ge_scalarmult_blinded(&R, r, point); ge_p3_tobytes(k, &R); res = soter_hash_update(&hash_ctx, k, ED25519_GE_LENGTH); if (THEMIS_SUCCESS != res) { soter_hash_final(&hash_ctx, k, &hash_length); return res; } res = soter_hash_update(&hash_ctx, &pos, sizeof(pos)); if (THEMIS_SUCCESS != res) { soter_hash_final(&hash_ctx, k, &hash_length); return res; } res = soter_hash_final(&hash_ctx, k, &hash_length); if (THEMIS_SUCCESS != res) { return res; } if (THEMIS_SUCCESS == res) { sc_reduce(k); memcpy(signature, k, ED25519_GE_LENGTH); sc_muladd(signature + ED25519_GE_LENGTH, k, scalar, r); } return res; }
int ge_cmp(const ge_p3 *a, const ge_p3 *b) { unsigned char a_comp[ED25519_GE_LENGTH]; unsigned char b_comp[ED25519_GE_LENGTH]; ge_p3_tobytes(a_comp, a); ge_p3_tobytes(b_comp, b); return crypto_verify_32(a_comp, b_comp); }
void Sign_signMsg(uint8_t keyPair[64], struct Message* msg, struct Random* rand) { // az is set to the secret key followed by another secret value // which since we don't have a secret seed in this algorithm is just the // hash of the secret key and 32 bytes of random uint8_t az[64]; uint8_t r[64]; ge_p3 R; uint8_t hram[64]; Bits_memcpy(az, keyPair, 32); Random_bytes(rand, &az[32], 32); crypto_hash_sha512(az,az,64); Bits_memcpy(az, keyPair, 32); az[0] &= 248; az[31] &= 63; az[31] |= 64; // hash message + secret number Message_push(msg, &az[32], 32, NULL); crypto_hash_sha512(r, msg->bytes, msg->length); // Replace secret number with public key Bits_memcpy(msg->bytes, &keyPair[32], 32); // push pointMul(r) to message sc_reduce(r); ge_scalarmult_base(&R,r); Message_shift(msg, 32, NULL); ge_p3_tobytes(msg->bytes,&R); crypto_hash_sha512(hram, msg->bytes, msg->length); sc_reduce(hram); sc_muladd(&msg->bytes[32], hram, az, r); }
void ed25519_sign(unsigned char *signature, const unsigned char *message, int32_t message_len, const unsigned char *public_key, const unsigned char *private_key) { sha3_context ctx; unsigned char hram[64]; unsigned char r[64]; ge_p3 R; sha3_init512(&ctx); sha3_update(&ctx, private_key + 32, 32); sha3_update(&ctx, message, message_len); sha3_finalize(&ctx, &r); sc_reduce(r); ge_scalarmult_base(&R, r); ge_p3_tobytes(signature, &R); sha3_init512(&ctx); sha3_update(&ctx, signature, 32); sha3_update(&ctx, public_key, 32); sha3_update(&ctx, message, message_len); sha3_finalize(&ctx, hram); sc_reduce(hram); sc_muladd(signature + 32, hram, private_key, r); }
int curve25519_sign(unsigned char* signature_out, const unsigned char* curve25519_privkey, const unsigned char* msg, const unsigned long msg_len, const unsigned char* random) { ge_p3 ed_pubkey_point; /* Ed25519 pubkey point */ unsigned char ed_pubkey[32]; /* Ed25519 encoded pubkey */ unsigned char sigbuf[MAX_MSG_LEN + 128]; /* working buffer */ unsigned char sign_bit = 0; if (msg_len > MAX_MSG_LEN) { 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(ed_pubkey, &ed_pubkey_point); sign_bit = ed_pubkey[31] & 0x80; /* Perform an Ed25519 signature with explicit private key */ crypto_sign_modified(sigbuf, msg, msg_len, curve25519_privkey, ed_pubkey, random); memmove(signature_out, sigbuf, 64); /* Encode the sign bit into signature (in unused high bit of S) */ signature_out[63] &= 0x7F; /* bit should be zero already, but just in case */ signature_out[63] |= sign_bit; return 0; }
void ed25519_sign(unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key, const unsigned char *private_key) { sha512_context hash; unsigned char hram[64]; unsigned char r[64]; ge_p3 R; sha512_init(&hash); sha512_update(&hash, private_key + 32, 32); sha512_update(&hash, message, message_len); sha512_final(&hash, r); sc_reduce(r); ge_scalarmult_base(&R, r); ge_p3_tobytes(signature, &R); sha512_init(&hash); sha512_update(&hash, signature, 32); sha512_update(&hash, public_key, 32); sha512_update(&hash, message, message_len); sha512_final(&hash, hram); sc_reduce(hram); sc_muladd(signature + 32, hram, private_key, r); }
/* generate an ed25519 key pair. * returns 0 on success */ int wc_ed25519_make_key(WC_RNG* rng, int keySz, ed25519_key* key) { byte az[ED25519_PRV_KEY_SIZE]; int ret; ge_p3 A; if (rng == NULL || key == NULL) return BAD_FUNC_ARG; /* ed25519 has 32 byte key sizes */ if (keySz != ED25519_KEY_SIZE) return BAD_FUNC_ARG; ret = wc_RNG_GenerateBlock(rng, key->k, ED25519_KEY_SIZE); if (ret != 0) return ret; ret = wc_Sha512Hash(key->k, ED25519_KEY_SIZE, az); if (ret != 0) { ForceZero(key->k, ED25519_KEY_SIZE); return ret; } /* apply clamp */ az[0] &= 248; az[31] &= 63; /* same than az[31] &= 127 because of az[31] |= 64 */ az[31] |= 64; ge_scalarmult_base(&A, az); ge_p3_tobytes(key->p, &A); /* put public key after private key, on the same buffer */ XMEMMOVE(key->k + ED25519_KEY_SIZE, key->p, ED25519_PUB_KEY_SIZE); return ret; }
int crypto_sign( unsigned char *sm,unsigned long long *smlen, const unsigned char *m,unsigned long long mlen, const unsigned char *sk ) { unsigned char az[64]; unsigned char r[64]; unsigned char hram[64]; ge_p3 R; unsigned long long i; crypto_hash_sha512(az,sk,32); az[0] &= 248; az[31] &= 63; az[31] |= 64; *smlen = mlen + 64; for (i = 0;i < mlen;++i) sm[64 + i] = m[i]; for (i = 0;i < 32;++i) sm[32 + i] = az[32 + i]; crypto_hash_sha512(r,sm + 32,mlen + 32); for (i = 0;i < 32;++i) sm[32 + i] = sk[32 + i]; sc_reduce(r); ge_scalarmult_base(&R,r); ge_p3_tobytes(sm,&R); crypto_hash_sha512(hram,sm,mlen + 64); sc_reduce(hram); sc_muladd(sm + 32,hram,az,r); return 0; }
void crypto_ops::generate_keys(public_key &pub, secret_key &sec) { lock_guard<mutex> lock(random_lock); ge_p3 point; random_scalar(sec); ge_scalarmult_base(&point, &sec); ge_p3_tobytes(&pub, &point); }
static themis_status_t ed_dbl_base_sign(uint8_t pos, const uint8_t *scalar1, const uint8_t *scalar2, const ge_p3 *base1, const ge_p3 *base2, uint8_t *signature) { uint8_t r1[ED25519_GE_LENGTH]; uint8_t r2[ED25519_GE_LENGTH]; ge_p3 R1; ge_p2 R2; uint8_t k[64]; soter_hash_ctx_t hash_ctx; size_t hash_length = 64; themis_status_t res; generate_random_32(r1); generate_random_32(r2); ge_scalarmult_blinded(&R1, r1, base2); ge_double_scalarmult_vartime(&R2, r2, base1, r1); res = soter_hash_init(&hash_ctx, SOTER_HASH_SHA512); if (THEMIS_SUCCESS != res) { return res; } ge_p3_tobytes(k, &R1); res = soter_hash_update(&hash_ctx, k, ED25519_GE_LENGTH); if (THEMIS_SUCCESS != res) { soter_hash_final(&hash_ctx, k, &hash_length); return res; } ge_tobytes(k, &R2); res = soter_hash_update(&hash_ctx, k, ED25519_GE_LENGTH); if (THEMIS_SUCCESS != res) { soter_hash_final(&hash_ctx, k, &hash_length); return res; } res = soter_hash_update(&hash_ctx, &pos, sizeof(pos)); if (THEMIS_SUCCESS != res) { soter_hash_final(&hash_ctx, k, &hash_length); return res; } res = soter_hash_final(&hash_ctx, k, &hash_length); if (THEMIS_SUCCESS == res) { sc_reduce(k); memcpy(signature, k, ED25519_GE_LENGTH); sc_muladd(signature + ED25519_GE_LENGTH, k, scalar1, r1); sc_muladd(signature + (2 * ED25519_GE_LENGTH), k, scalar2, r2); } return res; }
//does a * G where a is a scalar and G is the curve basepoint key scalarmultBase(const key & a) { ge_p3 point; key aG; sc_reduce32copy(aG.bytes, a.bytes); //do this beforehand ge_scalarmult_base(&point, aG.bytes); ge_p3_tobytes(aG.bytes, &point); return aG; }
bool crypto_ops::secret_key_to_public_key(const secret_key &sec, public_key &pub) { ge_p3 point; if (sc_check(&sec) != 0) { return false; } ge_scalarmult_base(&point, &sec); ge_p3_tobytes(&pub, &point); return true; }
int crypto_sign_pubkey(unsigned char *pk,const unsigned char *sk) { ge_p3 A; ge_scalarmult_base(&A,sk); ge_p3_tobytes(pk,&A); return 0; }
static void corrupt_bob_step2(secure_comparator_t *bob, const void *input, size_t input_length, void *output, size_t *output_length) { /* Let's assume bob is malicious and uses zeroes instead of random numbers */ ge_p3 g2a; ge_p3 g3a; ge_p3 g2b; ge_p3 g3b; ge_frombytes_vartime(&g2a, (const unsigned char *)input); ge_frombytes_vartime(&g3a, ((const unsigned char *)input) + (3 * ED25519_GE_LENGTH)); if (THEMIS_SCOMPARE_SEND_OUTPUT_TO_PEER != secure_comparator_proceed_compare(bob, input, input_length, output, output_length)) { testsuite_fail_if(true, "secure_comparator_proceed_compare failed"); return; } memset(bob->rand2, 0, sizeof(bob->rand2)); memset(bob->rand3, 0, sizeof(bob->rand3)); ge_scalarmult_base(&g2b, bob->rand2); ge_scalarmult_base(&g3b, bob->rand3); ge_scalarmult_blinded(&(bob->g2), bob->rand2, &g2a); ge_scalarmult_blinded(&(bob->g3), bob->rand3, &g3a); memset(bob->rand, 0, sizeof(bob->rand)); ge_scalarmult_blinded(&(bob->P), bob->rand, &(bob->g3)); ge_double_scalarmult_vartime((ge_p2 *)&(bob->Q), bob->secret, &(bob->g2), bob->rand); ge_p2_to_p3(&(bob->Q), (const ge_p2 *)&(bob->Q)); ge_p3_tobytes((unsigned char *)output, &g2b); ed_sign(3, bob->rand2, ((unsigned char *)output) + ED25519_GE_LENGTH); ge_p3_tobytes(((unsigned char *)output) + (3 * ED25519_GE_LENGTH), &g3b); ed_sign(4, bob->rand3, ((unsigned char *)output) + (4 * ED25519_GE_LENGTH)); ge_p3_tobytes(((unsigned char *)output) + (6 * ED25519_GE_LENGTH), &(bob->P)); ge_p3_tobytes(((unsigned char *)output) + (7 * ED25519_GE_LENGTH), &(bob->Q)); ed_dbl_base_sign(5, bob->rand, bob->secret, &(bob->g2), &(bob->g3), ((unsigned char *)output) + (8 * ED25519_GE_LENGTH)); }
void Sign_signingKeyPairFromCurve25519(uint8_t keypairOut[64], uint8_t secretCryptoKey[32]) { Bits_memcpy(keypairOut, secretCryptoKey, 32); keypairOut[0] &= 248; keypairOut[31] &= 63; keypairOut[31] |= 64; ge_p3 A; ge_scalarmult_base(&A, keypairOut); ge_p3_tobytes(&keypairOut[32], &A); }
void hashToPoint(key & pointk, const key & hh) { ge_p2 point; ge_p1p1 point2; ge_p3 res; key h = cn_fast_hash(hh); ge_fromfe_frombytes_vartime(&point, h.bytes); ge_mul8(&point2, &point); ge_p1p1_to_p3(&res, &point2); ge_p3_tobytes(pointk.bytes, &res); }
static void corrupt_alice_step1(secure_comparator_t *alice, void *output) { /* Let's assume alice is malicious and uses zeroes instead of random numbers */ ge_p3 g2a; ge_p3 g3a; memset(alice->rand2, 0, sizeof(alice->rand2)); memset(alice->rand3, 0, sizeof(alice->rand3)); ge_scalarmult_base(&g2a, alice->rand2); ge_scalarmult_base(&g3a, alice->rand3); ge_p3_tobytes((unsigned char *)output, &g2a); ed_sign(1, alice->rand2, ((unsigned char *)output) + ED25519_GE_LENGTH); ge_p3_tobytes(((unsigned char *)output) + (3 * ED25519_GE_LENGTH), &g3a); ed_sign(2, alice->rand3, ((unsigned char *)output) + (4 * ED25519_GE_LENGTH)); }
//subtract Keys (subtracts curve points) //AB = A - B where A, B are curve points void subKeys(key & AB, const key &A, const key &B) { ge_p3 B2, A2; CHECK_AND_ASSERT_THROW_MES(ge_frombytes_vartime(&B2, B.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__)); CHECK_AND_ASSERT_THROW_MES(ge_frombytes_vartime(&A2, A.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__)); ge_cached tmp2; ge_p3_to_cached(&tmp2, &B2); ge_p1p1 tmp3; ge_sub(&tmp3, &A2, &tmp2); ge_p1p1_to_p3(&A2, &tmp3); ge_p3_tobytes(AB.bytes, &A2); }
void ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed) { ge_p3 A; sha512(seed, 32, private_key); private_key[0] &= 248; private_key[31] &= 63; private_key[31] |= 64; ge_scalarmult_base(&A, private_key); ge_p3_tobytes(public_key, &A); }
key hashToPointSimple(const key & hh) { key pointk; ge_p1p1 point2; ge_p2 point; ge_p3 res; key h = cn_fast_hash(hh); CHECK_AND_ASSERT_THROW_MES(ge_frombytes_vartime(&res, h.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__)); ge_p3_to_p2(&point, &res); ge_mul8(&point2, &point); ge_p1p1_to_p3(&res, &point2); ge_p3_tobytes(pointk.bytes, &res); return pointk; }
void crypto_ops::generate_signature(const hash &prefix_hash, const public_key &pub, const secret_key &sec, signature &sig) { lock_guard<mutex> lock(random_lock); ge_p3 tmp3; ec_scalar k; s_comm buf; #if !defined(NDEBUG) { ge_p3 t; public_key t2; assert(sc_check(&sec) == 0); ge_scalarmult_base(&t, &sec); ge_p3_tobytes(&t2, &t); assert(pub == t2); } #endif buf.h = prefix_hash; buf.key = pub; random_scalar(k); ge_scalarmult_base(&tmp3, &k); ge_p3_tobytes(&buf.comm, &tmp3); hash_to_scalar(&buf, sizeof(s_comm), sig.c); sc_mulsub(&sig.r, &sig.c, &sec, &k); }
/* see http://crypto.stackexchange.com/a/6215/4697 */ void ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key, const unsigned char *scalar) { const unsigned char SC_1[32] = {1}; /* scalar with value 1 */ unsigned char n[32]; ge_p3 nB; ge_p1p1 A_p1p1; ge_p3 A; ge_p3 public_key_unpacked; ge_cached T; int i; /* copy the scalar and clear highest bit */ for (i = 0; i < 31; ++i) { n[i] = scalar[i]; } n[31] = scalar[31] & 127; /* private key: a = n + t */ if (private_key) { sc_muladd(private_key, SC_1, n, private_key); } /* public key: A = nB + T */ if (public_key) { /* if we know the private key we don't need a point addition, which is faster */ /* using a "timing attack" you could find out wether or not we know the private key, but this information seems rather useless - if this is important pass public_key and private_key seperately in 2 function calls */ if (private_key) { ge_scalarmult_base(&A, private_key); } else { /* unpack public key into T */ ge_frombytes_negate_vartime(&public_key_unpacked, public_key); fe_neg(public_key_unpacked.X, public_key_unpacked.X); // undo negate fe_neg(public_key_unpacked.T, public_key_unpacked.T); // undo negate ge_p3_to_cached(&T, &public_key_unpacked); /* calculate n*B */ ge_scalarmult_base(&nB, n); /* A = n*B + T */ ge_add(&A_p1p1, &nB, &T); ge_p1p1_to_p3(&A, &A_p1p1); } /* pack public key */ ge_p3_tobytes(public_key, &A); } }
int crypto_sign_edwards25519sha512batch(unsigned char *sm, unsigned long long *smlen_p, const unsigned char *m, unsigned long long mlen, const unsigned char *sk) { crypto_hash_sha512_state hs; unsigned char nonce[64]; unsigned char hram[64]; unsigned char sig[64]; ge_p3 A; ge_p3 R; crypto_hash_sha512_init(&hs); crypto_hash_sha512_update(&hs, sk + 32, 32); crypto_hash_sha512_update(&hs, m, mlen); crypto_hash_sha512_final(&hs, nonce); ge_scalarmult_base(&A, sk); ge_p3_tobytes(sig + 32, &A); sc_reduce(nonce); ge_scalarmult_base(&R, nonce); ge_p3_tobytes(sig, &R); crypto_hash_sha512_init(&hs); crypto_hash_sha512_update(&hs, sig, 32); crypto_hash_sha512_update(&hs, m, mlen); crypto_hash_sha512_final(&hs, hram); sc_reduce(hram); sc_muladd(sig + 32, hram, nonce, sk); sodium_memzero(hram, sizeof hram); memmove(sm + 32, m, (size_t) mlen); memcpy(sm, sig, 32); memcpy(sm + 32 + mlen, sig + 32, 32); *smlen_p = mlen + 64U; return 0; }
int crypto_sign_edwards25519sha512batch_keypair(unsigned char *pk, unsigned char *sk) { ge_p3 A; randombytes_buf(sk, 32); crypto_hash_sha512(sk, sk, 32); sk[0] &= 248; sk[31] &= 63; sk[31] |= 64; ge_scalarmult_base(&A, sk); ge_p3_tobytes(pk, &A); return 0; }
int _crypto_sign_ed25519_detached(unsigned char *sig, unsigned long long *siglen_p, const unsigned char *m, unsigned long long mlen, const unsigned char *sk, int prehashed) { crypto_hash_sha512_state hs; unsigned char az[64]; unsigned char nonce[64]; unsigned char hram[64]; ge_p3 R; _crypto_sign_ed25519_ref10_hinit(&hs, prehashed); #ifdef ED25519_NONDETERMINISTIC memcpy(az, sk, 32); _crypto_sign_ed25519_synthetic_r_hv(&hs, nonce, az); #else crypto_hash_sha512(az, sk, 32); crypto_hash_sha512_update(&hs, az + 32, 32); #endif crypto_hash_sha512_update(&hs, m, mlen); crypto_hash_sha512_final(&hs, nonce); memmove(sig + 32, sk + 32, 32); sc_reduce(nonce); ge_scalarmult_base(&R, nonce); ge_p3_tobytes(sig, &R); _crypto_sign_ed25519_ref10_hinit(&hs, prehashed); crypto_hash_sha512_update(&hs, sig, 64); crypto_hash_sha512_update(&hs, m, mlen); crypto_hash_sha512_final(&hs, hram); sc_reduce(hram); _crypto_sign_ed25519_clamp(az); sc_muladd(sig + 32, hram, az, nonce); sodium_memzero(az, sizeof az); sodium_memzero(nonce, sizeof nonce); if (siglen_p != NULL) { *siglen_p = 64U; } return 0; }
int crypto_sign_edwards25519sha512batch_open(unsigned char *m, unsigned long long *mlen_p, const unsigned char *sm, unsigned long long smlen, const unsigned char *pk) { unsigned char h[64]; unsigned char t1[32], t2[32]; unsigned long long mlen; ge_cached Ai; ge_p1p1 csa; ge_p2 cs; ge_p3 A; ge_p3 R; ge_p3 cs3; *mlen_p = 0; if (smlen < 64 || smlen > SIZE_MAX) { return -1; } mlen = smlen - 64; if (sm[smlen - 1] & 224) { return -1; } if (ge_frombytes_negate_vartime(&A, pk) != 0 || ge_frombytes_negate_vartime(&R, sm) != 0) { return -1; } ge_p3_to_cached(&Ai, &A); crypto_hash_sha512(h, sm, mlen + 32); sc_reduce(h); ge_scalarmult_vartime(&cs3, h, &R); ge_add(&csa, &cs3, &Ai); ge_p1p1_to_p2(&cs, &csa); ge_tobytes(t1, &cs); t1[31] ^= 1 << 7; ge_scalarmult_base(&R, sm + 32 + mlen); ge_p3_tobytes(t2, &R); if (crypto_verify_32(t1, t2) != 0) { return -1; } *mlen_p = mlen; memmove(m, sm + 32, mlen); return 0; }
int crypto_sign_compute_public_key(const unsigned char *skin, unsigned char *pk) { IN(); unsigned char h[64]; ge_p3 A; crypto_hash_sha512(h,skin,32); h[0] &= 248; h[31] &= 63; h[31] |= 64; ge_scalarmult_base(&A,h); ge_p3_tobytes(pk,&A); RETURN(0); OUT(); }
int crypto_sign_seed_keypair(unsigned char *pk, unsigned char *sk, const unsigned char *seed) { ge_p3 A; crypto_hash_sha512(sk,seed,32); sk[0] &= 248; sk[31] &= 63; sk[31] |= 64; ge_scalarmult_base(&A,sk); ge_p3_tobytes(pk,&A); memmove(sk, seed, 32); memmove(sk + 32, pk, 32); return 0; }
int crypto_sign_detached(unsigned char *sig, unsigned long long *siglen, const unsigned char *m, unsigned long long mlen, const unsigned char *sk) { crypto_hash_sha512_state hs; unsigned char pk[32]; unsigned char az[64]; unsigned char nonce[64]; unsigned char hram[64]; ge_p3 R; memmove(pk, sk + 32, 32); crypto_hash_sha512(az, sk, 32); az[0] &= 248; az[31] &= 63; az[31] |= 64; crypto_hash_sha512_init(&hs); crypto_hash_sha512_update(&hs, az + 32, 32); crypto_hash_sha512_update(&hs, m, mlen); crypto_hash_sha512_final(&hs, nonce); memmove(sig + 32, pk, 32); sc_reduce(nonce); ge_scalarmult_base(&R, nonce); ge_p3_tobytes(sig, &R); crypto_hash_sha512_init(&hs); crypto_hash_sha512_update(&hs, sig, 64); crypto_hash_sha512_update(&hs, m, mlen); crypto_hash_sha512_final(&hs, hram); sc_reduce(hram); sc_muladd(sig + 32, hram, az, nonce); sodium_memzero(az, sizeof az); sodium_memzero(nonce, sizeof nonce); if (siglen != NULL) { *siglen = 64U; } return 0; }
int crypto_sign_keypair(unsigned char *pk, unsigned char *sk) { unsigned char h[64]; ge_p3 A; int i; SHA512(sk, 32, h); h[0] &= 248; h[31] &= 63; h[31] |= 64; ge_scalarmult_base(&A,h); ge_p3_tobytes(pk,&A); for (i = 0;i < 32;++i) sk[32 + i] = pk[i]; return 0; }