\begin{lstlisting}[style=bfh-c,language=C,, caption={Crypto Implementation API}, label={lst:cryptoapi}] #include /** * IMPLEMENTATION NOTICE: * * This is an implementation of the Schnorr, Blind Schnorr and * Clause Blind Schnorr Signature Scheme using Curve25519. * We use libsodium wherever possible. * * Blind Schnorr: The Blind Schnorr Signature Scheme is BROKEN! * Use the Clause Blind Schnorr Signature Scheme instead. * * Clause Blind Schnorr Signature Scheme: * This is a variation of the Blind Schnorr Signature Scheme where all operations * before the signature creation are performed twice. * The signer randomly chooses one of the two sessions and only creates the signature for this session. * Note that the Clause part needs to be implemented by whoever uses this API. * Further details about the Clause Blind Schnorr Signature Scheme can be found here: * https://eprint.iacr.org/2019/877.pdf */ /** * Curve25519 Scalar */ struct GNUNET_CRYPTO_Cs25519Scalar { /** * 32 byte scalar */ unsigned char d[crypto_core_ed25519_SCALARBYTES]; }; /** * Curve25519 point */ struct GNUNET_CRYPTO_Cs25519Point { /** * This is a point on the Curve25519. * The x coordinate can be restored using the y coordinate */ unsigned char y[crypto_core_ed25519_BYTES]; }; /** * The private information of an Schnorr key pair. */ struct GNUNET_CRYPTO_CsPrivateKey { struct GNUNET_CRYPTO_Cs25519Scalar scalar; }; /** * The public information of an Schnorr key pair. */ struct GNUNET_CRYPTO_CsPublicKey { struct GNUNET_CRYPTO_Cs25519Point point; }; /** * Secret used for blinding (alpha and beta). */ struct GNUNET_CRYPTO_CsBlindingSecret { struct GNUNET_CRYPTO_Cs25519Scalar alpha; struct GNUNET_CRYPTO_Cs25519Scalar beta; }; /** * the private r used in the signature */ struct GNUNET_CRYPTO_CsRSecret { struct GNUNET_CRYPTO_Cs25519Scalar scalar; }; /** * the public R (derived from r) used in c */ struct GNUNET_CRYPTO_CsRPublic { struct GNUNET_CRYPTO_Cs25519Point point; }; /** * Schnorr c to be signed */ struct GNUNET_CRYPTO_CsC { struct GNUNET_CRYPTO_Cs25519Scalar scalar; }; /** * s in the signature */ struct GNUNET_CRYPTO_CsS { struct GNUNET_CRYPTO_Cs25519Scalar scalar; }; /** * blinded s in the signature */ struct GNUNET_CRYPTO_CsBlindS { struct GNUNET_CRYPTO_Cs25519Scalar scalar; }; /** * CS Signtature containing scalar s and point R */ struct GNUNET_CRYPTO_CsSignature { /** * Schnorr signatures are composed of a scalar s and a curve point */ struct GNUNET_CRYPTO_CsS s_scalar; struct GNUNET_CRYPTO_Cs25519Point r_point; }; /** * Nonce */ struct GNUNET_CRYPTO_CsNonce { /*a nonce*/ unsigned char nonce[256 / 8]; }; /** * Create a new random private key. * * @param[out] priv where to write the fresh private key */ void GNUNET_CRYPTO_cs_private_key_generate (struct GNUNET_CRYPTO_CsPrivateKey *priv); /** * Extract the public key of the given private key. * * @param priv the private key * @param[out] pub where to write the public key */ void GNUNET_CRYPTO_cs_private_key_get_public (const struct GNUNET_CRYPTO_CsPrivateKey *priv, struct GNUNET_CRYPTO_CsPublicKey *pub); /** * Derive a new secret r pair r0 and r1. * In original papers r is generated randomly * To provide abort-idempotency, r needs to be derived but still needs to be UNPREDICTABLE * To ensure unpredictability a new nonce should be used when a new r needs to be derived. * Uses HKDF internally. * Comment: Can be done in one HKDF shot and split output. * * @param nonce is a random nonce * @param lts is a long-term-secret in form of a private key * @param[out] r array containing derived secrets r0 and r1 */ void GNUNET_CRYPTO_cs_r_derive (const struct GNUNET_CRYPTO_CsNonce *nonce, const struct GNUNET_CRYPTO_CsPrivateKey *lts, struct GNUNET_CRYPTO_CsRSecret r[2]); /** * Extract the public R of the given secret r. * * @param r_priv the private key * @param[out] r_pub where to write the public key */ void GNUNET_CRYPTO_cs_r_get_public (const struct GNUNET_CRYPTO_CsRSecret *r_priv, struct GNUNET_CRYPTO_CsRPublic *r_pub); /** * Derives new random blinding factors. * In original papers blinding factors are generated randomly * To provide abort-idempotency, blinding factors need to be derived but still need to be UNPREDICTABLE * To ensure unpredictability a new nonce has to be used. * Uses HKDF internally * * @param secret is secret to derive blinding factors * @param secret_len secret length * @param[out] bs array containing the two derivedGNUNET_CRYPTO_CsBlindingSecret */ void GNUNET_CRYPTO_cs_blinding_secrets_derive (const struct GNUNET_CRYPTO_CsNonce *blind_seed, struct GNUNET_CRYPTO_CsBlindingSecret bs[2]); /** * Calculate two blinded c's * Comment: One would be insecure due to Wagner's algorithm solving ROS * * @param bs array of the two blinding factor structs each containing alpha and beta * @param r_pub array of the two signer's nonce R * @param pub the public key of the signer * @param msg the message to blind in preparation for signing * @param msg_len length of message msg * @param[out] blinded_c array of the two blinded c's */ void GNUNET_CRYPTO_cs_calc_blinded_c (const struct GNUNET_CRYPTO_CsBlindingSecret bs[2], const struct GNUNET_CRYPTO_CsRPublic r_pub[2], const struct GNUNET_CRYPTO_CsPublicKey *pub, const void *msg, size_t msg_len, struct GNUNET_CRYPTO_CsC blinded_c[2]); /** * Sign a blinded c * This function derives b from a nonce and a longterm secret * In original papers b is generated randomly * To provide abort-idempotency, b needs to be derived but still need to be UNPREDICTABLE. * To ensure unpredictability a new nonce has to be used for every signature * HKDF is used internally for derivation * r0 and r1 can be derived prior by using GNUNET_CRYPTO_cs_r_derive * * @param priv private key to use for the signing and as LTS in HKDF * @param r array of the two secret nonce from the signer * @param c array of the two blinded c to sign c_b * @param nonce is a random nonce * @param[out] blinded_signature_scalar where to write the signature * @return 0 or 1 for b (see Clause Blind Signature Scheme) */ int GNUNET_CRYPTO_cs_sign_derive(const struct GNUNET_CRYPTO_CsPrivateKey *priv, const struct GNUNET_CRYPTO_CsRSecret r[2], const struct GNUNET_CRYPTO_CsC c[2], const struct GNUNET_CRYPTO_CsNonce *nonce, struct GNUNET_CRYPTO_CsBlindS *blinded_signature_scalar ); /** * Unblind a blind-signed signature using a c that was blinded * * @param blinded_signature_scalar the signature made on the blinded c * @param bs the blinding factors used in the blinding * @param[out] signature_scalar where to write the unblinded signature */ void GNUNET_CRYPTO_cs_unblind (const struct GNUNET_CRYPTO_CsBlindS *blinded_signature_scalar, const struct GNUNET_CRYPTO_CsBlindingSecret *bs, struct GNUNET_CRYPTO_CsS *signature_scalar); /** * Verify whether the given message corresponds to the given signature and the * signature is valid with respect to the given public key. * * @param sig signature that is being validated * @param pub public key of the signer * @param msg is the message that should be signed by @a sig (message is used to calculate c) * @param msg_len is the message length * @returns #GNUNET_YES on success, #GNUNET_SYSERR if key parameter(s) invalid #GNUNET_NO if signature invalid */ enum GNUNET_GenericReturnValue GNUNET_CRYPTO_cs_verify (const struct GNUNET_CRYPTO_CsSignature *sig, const struct GNUNET_CRYPTO_CsPublicKey *pub, const void *msg, size_t msg_len); \end{lstlisting}