18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 OR MIT */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#ifndef CURVE25519_H
78c2ecf20Sopenharmony_ci#define CURVE25519_H
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <crypto/algapi.h> // For crypto_memneq.
108c2ecf20Sopenharmony_ci#include <linux/types.h>
118c2ecf20Sopenharmony_ci#include <linux/random.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cienum curve25519_lengths {
148c2ecf20Sopenharmony_ci	CURVE25519_KEY_SIZE = 32
158c2ecf20Sopenharmony_ci};
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ciextern const u8 curve25519_null_point[];
188c2ecf20Sopenharmony_ciextern const u8 curve25519_base_point[];
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_civoid curve25519_generic(u8 out[CURVE25519_KEY_SIZE],
218c2ecf20Sopenharmony_ci			const u8 scalar[CURVE25519_KEY_SIZE],
228c2ecf20Sopenharmony_ci			const u8 point[CURVE25519_KEY_SIZE]);
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_civoid curve25519_arch(u8 out[CURVE25519_KEY_SIZE],
258c2ecf20Sopenharmony_ci		     const u8 scalar[CURVE25519_KEY_SIZE],
268c2ecf20Sopenharmony_ci		     const u8 point[CURVE25519_KEY_SIZE]);
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_civoid curve25519_base_arch(u8 pub[CURVE25519_KEY_SIZE],
298c2ecf20Sopenharmony_ci			  const u8 secret[CURVE25519_KEY_SIZE]);
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistatic inline
328c2ecf20Sopenharmony_cibool __must_check curve25519(u8 mypublic[CURVE25519_KEY_SIZE],
338c2ecf20Sopenharmony_ci			     const u8 secret[CURVE25519_KEY_SIZE],
348c2ecf20Sopenharmony_ci			     const u8 basepoint[CURVE25519_KEY_SIZE])
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CURVE25519))
378c2ecf20Sopenharmony_ci		curve25519_arch(mypublic, secret, basepoint);
388c2ecf20Sopenharmony_ci	else
398c2ecf20Sopenharmony_ci		curve25519_generic(mypublic, secret, basepoint);
408c2ecf20Sopenharmony_ci	return crypto_memneq(mypublic, curve25519_null_point,
418c2ecf20Sopenharmony_ci			     CURVE25519_KEY_SIZE);
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic inline bool
458c2ecf20Sopenharmony_ci__must_check curve25519_generate_public(u8 pub[CURVE25519_KEY_SIZE],
468c2ecf20Sopenharmony_ci					const u8 secret[CURVE25519_KEY_SIZE])
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	if (unlikely(!crypto_memneq(secret, curve25519_null_point,
498c2ecf20Sopenharmony_ci				    CURVE25519_KEY_SIZE)))
508c2ecf20Sopenharmony_ci		return false;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CURVE25519))
538c2ecf20Sopenharmony_ci		curve25519_base_arch(pub, secret);
548c2ecf20Sopenharmony_ci	else
558c2ecf20Sopenharmony_ci		curve25519_generic(pub, secret, curve25519_base_point);
568c2ecf20Sopenharmony_ci	return crypto_memneq(pub, curve25519_null_point, CURVE25519_KEY_SIZE);
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic inline void curve25519_clamp_secret(u8 secret[CURVE25519_KEY_SIZE])
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	secret[0] &= 248;
628c2ecf20Sopenharmony_ci	secret[31] = (secret[31] & 127) | 64;
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic inline void curve25519_generate_secret(u8 secret[CURVE25519_KEY_SIZE])
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	get_random_bytes_wait(secret, CURVE25519_KEY_SIZE);
688c2ecf20Sopenharmony_ci	curve25519_clamp_secret(secret);
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci#endif /* CURVE25519_H */
72