Path: blob/master/arch/powerpc/crypto/curve25519-ppc64le-core.c
26424 views
// SPDX-License-Identifier: GPL-2.0-or-later1/*2* Copyright 2024- IBM Corp.3*4* X25519 scalar multiplication with 51 bits limbs for PPC64le.5* Based on RFC7748 and AArch64 optimized implementation for X255196* - Algorithm 1 Scalar multiplication of a variable point7*/89#include <crypto/curve25519.h>10#include <crypto/internal/kpp.h>1112#include <linux/types.h>13#include <linux/jump_label.h>14#include <linux/kernel.h>15#include <linux/module.h>16#include <linux/scatterlist.h>1718#include <linux/cpufeature.h>19#include <linux/processor.h>2021typedef uint64_t fe51[5];2223asmlinkage void x25519_fe51_mul(fe51 h, const fe51 f, const fe51 g);24asmlinkage void x25519_fe51_sqr(fe51 h, const fe51 f);25asmlinkage void x25519_fe51_mul121666(fe51 h, fe51 f);26asmlinkage void x25519_fe51_sqr_times(fe51 h, const fe51 f, int n);27asmlinkage void x25519_fe51_frombytes(fe51 h, const uint8_t *s);28asmlinkage void x25519_fe51_tobytes(uint8_t *s, const fe51 h);29asmlinkage void x25519_cswap(fe51 p, fe51 q, unsigned int bit);3031#define fmul x25519_fe51_mul32#define fsqr x25519_fe51_sqr33#define fmul121666 x25519_fe51_mul12166634#define fe51_tobytes x25519_fe51_tobytes3536static void fadd(fe51 h, const fe51 f, const fe51 g)37{38h[0] = f[0] + g[0];39h[1] = f[1] + g[1];40h[2] = f[2] + g[2];41h[3] = f[3] + g[3];42h[4] = f[4] + g[4];43}4445/*46* Prime = 2 ** 255 - 19, 255 bits47* (0x7fffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffed)48*49* Prime in 5 51-bit limbs50*/51static fe51 prime51 = { 0x7ffffffffffed, 0x7ffffffffffff, 0x7ffffffffffff, 0x7ffffffffffff, 0x7ffffffffffff};5253static void fsub(fe51 h, const fe51 f, const fe51 g)54{55h[0] = (f[0] + ((prime51[0] * 2))) - g[0];56h[1] = (f[1] + ((prime51[1] * 2))) - g[1];57h[2] = (f[2] + ((prime51[2] * 2))) - g[2];58h[3] = (f[3] + ((prime51[3] * 2))) - g[3];59h[4] = (f[4] + ((prime51[4] * 2))) - g[4];60}6162static void fe51_frombytes(fe51 h, const uint8_t *s)63{64/*65* Make sure 64-bit aligned.66*/67unsigned char sbuf[32+8];68unsigned char *sb = PTR_ALIGN((void *)sbuf, 8);6970memcpy(sb, s, 32);71x25519_fe51_frombytes(h, sb);72}7374static void finv(fe51 o, const fe51 i)75{76fe51 a0, b, c, t00;7778fsqr(a0, i);79x25519_fe51_sqr_times(t00, a0, 2);8081fmul(b, t00, i);82fmul(a0, b, a0);8384fsqr(t00, a0);8586fmul(b, t00, b);87x25519_fe51_sqr_times(t00, b, 5);8889fmul(b, t00, b);90x25519_fe51_sqr_times(t00, b, 10);9192fmul(c, t00, b);93x25519_fe51_sqr_times(t00, c, 20);9495fmul(t00, t00, c);96x25519_fe51_sqr_times(t00, t00, 10);9798fmul(b, t00, b);99x25519_fe51_sqr_times(t00, b, 50);100101fmul(c, t00, b);102x25519_fe51_sqr_times(t00, c, 100);103104fmul(t00, t00, c);105x25519_fe51_sqr_times(t00, t00, 50);106107fmul(t00, t00, b);108x25519_fe51_sqr_times(t00, t00, 5);109110fmul(o, t00, a0);111}112113static void curve25519_fe51(uint8_t out[32], const uint8_t scalar[32],114const uint8_t point[32])115{116fe51 x1, x2, z2, x3, z3;117uint8_t s[32];118unsigned int swap = 0;119int i;120121memcpy(s, scalar, 32);122s[0] &= 0xf8;123s[31] &= 0x7f;124s[31] |= 0x40;125fe51_frombytes(x1, point);126127z2[0] = z2[1] = z2[2] = z2[3] = z2[4] = 0;128x3[0] = x1[0];129x3[1] = x1[1];130x3[2] = x1[2];131x3[3] = x1[3];132x3[4] = x1[4];133134x2[0] = z3[0] = 1;135x2[1] = z3[1] = 0;136x2[2] = z3[2] = 0;137x2[3] = z3[3] = 0;138x2[4] = z3[4] = 0;139140for (i = 254; i >= 0; --i) {141unsigned int k_t = 1 & (s[i / 8] >> (i & 7));142fe51 a, b, c, d, e;143fe51 da, cb, aa, bb;144fe51 dacb_p, dacb_m;145146swap ^= k_t;147x25519_cswap(x2, x3, swap);148x25519_cswap(z2, z3, swap);149swap = k_t;150151fsub(b, x2, z2); // B = x_2 - z_2152fadd(a, x2, z2); // A = x_2 + z_2153fsub(d, x3, z3); // D = x_3 - z_3154fadd(c, x3, z3); // C = x_3 + z_3155156fsqr(bb, b); // BB = B^2157fsqr(aa, a); // AA = A^2158fmul(da, d, a); // DA = D * A159fmul(cb, c, b); // CB = C * B160161fsub(e, aa, bb); // E = AA - BB162fmul(x2, aa, bb); // x2 = AA * BB163fadd(dacb_p, da, cb); // DA + CB164fsub(dacb_m, da, cb); // DA - CB165166fmul121666(z3, e); // 121666 * E167fsqr(z2, dacb_m); // (DA - CB)^2168fsqr(x3, dacb_p); // x3 = (DA + CB)^2169fadd(b, bb, z3); // BB + 121666 * E170fmul(z3, x1, z2); // z3 = x1 * (DA - CB)^2171fmul(z2, e, b); // z2 = e * (BB + (DA + CB)^2)172}173174finv(z2, z2);175fmul(x2, x2, z2);176fe51_tobytes(out, x2);177}178179void curve25519_arch(u8 mypublic[CURVE25519_KEY_SIZE],180const u8 secret[CURVE25519_KEY_SIZE],181const u8 basepoint[CURVE25519_KEY_SIZE])182{183curve25519_fe51(mypublic, secret, basepoint);184}185EXPORT_SYMBOL(curve25519_arch);186187void curve25519_base_arch(u8 pub[CURVE25519_KEY_SIZE],188const u8 secret[CURVE25519_KEY_SIZE])189{190curve25519_fe51(pub, secret, curve25519_base_point);191}192EXPORT_SYMBOL(curve25519_base_arch);193194static int curve25519_set_secret(struct crypto_kpp *tfm, const void *buf,195unsigned int len)196{197u8 *secret = kpp_tfm_ctx(tfm);198199if (!len)200curve25519_generate_secret(secret);201else if (len == CURVE25519_KEY_SIZE &&202crypto_memneq(buf, curve25519_null_point, CURVE25519_KEY_SIZE))203memcpy(secret, buf, CURVE25519_KEY_SIZE);204else205return -EINVAL;206return 0;207}208209static int curve25519_generate_public_key(struct kpp_request *req)210{211struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);212const u8 *secret = kpp_tfm_ctx(tfm);213u8 buf[CURVE25519_KEY_SIZE];214int copied, nbytes;215216if (req->src)217return -EINVAL;218219curve25519_base_arch(buf, secret);220221/* might want less than we've got */222nbytes = min_t(size_t, CURVE25519_KEY_SIZE, req->dst_len);223copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst,224nbytes),225buf, nbytes);226if (copied != nbytes)227return -EINVAL;228return 0;229}230231static int curve25519_compute_shared_secret(struct kpp_request *req)232{233struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);234const u8 *secret = kpp_tfm_ctx(tfm);235u8 public_key[CURVE25519_KEY_SIZE];236u8 buf[CURVE25519_KEY_SIZE];237int copied, nbytes;238239if (!req->src)240return -EINVAL;241242copied = sg_copy_to_buffer(req->src,243sg_nents_for_len(req->src,244CURVE25519_KEY_SIZE),245public_key, CURVE25519_KEY_SIZE);246if (copied != CURVE25519_KEY_SIZE)247return -EINVAL;248249curve25519_arch(buf, secret, public_key);250251/* might want less than we've got */252nbytes = min_t(size_t, CURVE25519_KEY_SIZE, req->dst_len);253copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst,254nbytes),255buf, nbytes);256if (copied != nbytes)257return -EINVAL;258return 0;259}260261static unsigned int curve25519_max_size(struct crypto_kpp *tfm)262{263return CURVE25519_KEY_SIZE;264}265266static struct kpp_alg curve25519_alg = {267.base.cra_name = "curve25519",268.base.cra_driver_name = "curve25519-ppc64le",269.base.cra_priority = 200,270.base.cra_module = THIS_MODULE,271.base.cra_ctxsize = CURVE25519_KEY_SIZE,272273.set_secret = curve25519_set_secret,274.generate_public_key = curve25519_generate_public_key,275.compute_shared_secret = curve25519_compute_shared_secret,276.max_size = curve25519_max_size,277};278279280static int __init curve25519_mod_init(void)281{282return IS_REACHABLE(CONFIG_CRYPTO_KPP) ?283crypto_register_kpp(&curve25519_alg) : 0;284}285286static void __exit curve25519_mod_exit(void)287{288if (IS_REACHABLE(CONFIG_CRYPTO_KPP))289crypto_unregister_kpp(&curve25519_alg);290}291292module_init(curve25519_mod_init);293module_exit(curve25519_mod_exit);294295MODULE_ALIAS_CRYPTO("curve25519");296MODULE_ALIAS_CRYPTO("curve25519-ppc64le");297MODULE_DESCRIPTION("PPC64le Curve25519 scalar multiplication with 51 bits limbs");298MODULE_LICENSE("GPL v2");299MODULE_AUTHOR("Danny Tsen <[email protected]>");300301302