#!/bin/bash set -euo pipefail cat << 'EOF' // The synthesized parts are from fiat-crypto, copyright MIT 2017. // The synthesis framework is released under the MIT license. // The non-synthesized parts are from curve25519-donna by Adam Langley (Google): /* Copyright 2008, Google Inc. * All rights reserved. * * Code released into the public domain. * * curve25519-donna: Curve25519 elliptic curve, public key function * * http://code.google.com/p/curve25519-donna/ * * Adam Langley * Parts optimised by floodyberry * Derived from public domain C code by Daniel J. Bernstein * * More information about curve25519 can be found here * http://cr.yp.to/ecdh.html * * djb's sample implementation of curve25519 is written in a special assembly * language called qhasm and uses the floating point registers. * * This is, almost, a clean room reimplementation from the curve25519 paper. It * uses many of the tricks described therein. Only the crecip function is taken * from the sample implementation. */ #include #include #include typedef uint8_t u8; typedef uint64_t limb; typedef limb felem[5]; // This is a special gcc mode for 128-bit integers. It's implemented on 64-bit // platforms only as far as I know. typedef unsigned uint128_t __attribute__((mode(TI))); #undef force_inline #define force_inline __attribute__((always_inline)) /* Multiply two numbers: output = in2 * in */ static void force_inline fmul(felem output, const felem in2, const felem in) { EOF < src/Specific/IntegrationTestMulDisplay.log \ grep -- "λ '(" | \ grep -owP -- 'x\d+' | \ paste -d ' =;' \ <(for i in $(seq 1 10); do echo uint64_t; done) \ /dev/stdin \ <(echo {in2,in}\[{4,3,2,1,0}\] | tr ' ' '\n') \ /dev/null < src/Specific/IntegrationTestMulDisplay.log \ grep -oP '(bool|uint\d+_t)\W+\w+ = .*;$' < src/Specific/IntegrationTestMulDisplay.log \ grep -- return | sed 's:return::g' | sed 's:Return::g' | \ tr -d '(' | tr -d ')' | tr ',' '\n' | grep -o '\S.*\S' | \ paste -d '=;' \ <(echo output\[{4,3,2,1,0}\] | tr ' ' '\n') \ /dev/stdin \ /dev/null cat << 'EOF' } static void force_inline fsquare_times(felem output, const felem in, limb count) { uint128_t t[5]; limb r0,r1,r2,r3,r4,c; limb d0,d1,d2,d4,d419; r0 = in[0]; r1 = in[1]; r2 = in[2]; r3 = in[3]; r4 = in[4]; do { EOF < src/Specific/IntegrationTestSquareDisplay.log \ grep -- "λ '(" | \ grep -owP -- 'x\d+' | \ paste -d ' =;' \ <(for i in $(seq 1 5); do echo uint64_t; done) \ /dev/stdin \ <(echo r{4,3,2,1,0} | tr ' ' '\n') \ /dev/null < src/Specific/IntegrationTestSquareDisplay.log \ grep -oP '(bool|uint\d+_t)\W+\w+ = .*;$' < src/Specific/IntegrationTestSquareDisplay.log \ grep -- return | sed 's:return::g' | sed 's:Return::g' | \ tr -d '(' | tr -d ')' | tr ',' '\n' | grep -o '\S.*\S' | \ paste -d '=;' \ <(echo r{4,3,2,1,0} | tr ' ' '\n') \ /dev/stdin \ /dev/null cat << 'EOF' } while(--count); output[0] = r0; output[1] = r1; output[2] = r2; output[3] = r3; output[4] = r4; } /* Take a little-endian, 32-byte number and expand it into polynomial form */ static void fexpand(limb *output, const u8 *in) { output[0] = *((const uint64_t *)(in)) & 0x7ffffffffffff; output[1] = (*((const uint64_t *)(in+6)) >> 3) & 0x7ffffffffffff; output[2] = (*((const uint64_t *)(in+12)) >> 6) & 0x7ffffffffffff; output[3] = (*((const uint64_t *)(in+19)) >> 1) & 0x7ffffffffffff; output[4] = (*((const uint64_t *)(in+25)) >> 4) & 0x7ffffffffffff; } /* Take a fully reduced polynomial form number and contract it into a * little-endian, 32-byte array */ static void fcontract(u8 *output, const felem input) { uint128_t t[5]; t[0] = input[0]; t[1] = input[1]; t[2] = input[2]; t[3] = input[3]; t[4] = input[4]; t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff; t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff; t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff; t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff; t[0] += 19 * (t[4] >> 51); t[4] &= 0x7ffffffffffff; t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff; t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff; t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff; t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff; t[0] += 19 * (t[4] >> 51); t[4] &= 0x7ffffffffffff; /* now t is between 0 and 2^255-1, properly carried. */ /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ t[0] += 19; t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff; t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff; t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff; t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff; t[0] += 19 * (t[4] >> 51); t[4] &= 0x7ffffffffffff; /* now between 19 and 2^255-1 in both cases, and offset by 19. */ t[0] += 0x8000000000000 - 19; t[1] += 0x8000000000000 - 1; t[2] += 0x8000000000000 - 1; t[3] += 0x8000000000000 - 1; t[4] += 0x8000000000000 - 1; /* now between 2^255 and 2^256-20, and offset by 2^255. */ t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff; t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff; t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff; t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff; t[4] &= 0x7ffffffffffff; *((uint64_t *)(output)) = t[0] | (t[1] << 51); *((uint64_t *)(output+8)) = (t[1] >> 13) | (t[2] << 38); *((uint64_t *)(output+16)) = (t[2] >> 26) | (t[3] << 25); *((uint64_t *)(output+24)) = (t[3] >> 39) | (t[4] << 12); } /* Input: Q, Q', Q-Q' * Output: 2Q, Q+Q' */ static void fmonty(limb *x2, limb *z2, /* output 2Q */ limb *x3, limb *z3, /* output Q + Q' */ limb *x, limb *z, /* input Q */ limb *xprime, limb *zprime, /* input Q' */ const limb *qmqp /* input Q - Q' */) { EOF < src/Specific/IntegrationTestLadderstepDisplay.log \ grep -- "λ '(" | \ grep -owP -- 'x\d+' | \ paste -d ' =;' \ <(for i in $(seq 1 25); do echo uint64_t; done) \ /dev/stdin \ <(echo {qmqp,x,z,xprime,zprime}\[{4,3,2,1,0}\] | tr ' ' '\n') \ /dev/null < src/Specific/IntegrationTestLadderstepDisplay.log \ grep -oP '(bool|uint\d+_t)\W+\w+ = .*;$' < src/Specific/IntegrationTestLadderstepDisplay.log \ grep -- return | sed 's:return::g' | sed 's:Return::g' | \ tr -d '(' | tr -d ')' | tr ',' '\n' | grep -o '\S.*\S' | \ paste -d '=;' \ <(echo {x2,z2,x3,z3}\[{4,3,2,1,0}\] | tr ' ' '\n') \ /dev/stdin \ /dev/null cat <<'EOF' } // ----------------------------------------------------------------------------- // Maybe swap the contents of two limb arrays (@a and @b), each @len elements // long. Perform the swap iff @swap is non-zero. // // This function performs the swap without leaking any side-channel // information. // ----------------------------------------------------------------------------- static void swap_conditional(limb a[5], limb b[5], limb iswap) { unsigned i; const limb swap = -iswap; for (i = 0; i < 5; ++i) { const limb x = swap & (a[i] ^ b[i]); a[i] ^= x; b[i] ^= x; } } /* Calculates nQ where Q is the x-coordinate of a point on the curve * * resultx/resultz: the x coordinate of the resulting curve point (short form) * n: a little endian, 32-byte number * q: a point of the curve (short form) */ static void cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) { limb a[5] = {0}, b[5] = {1}, c[5] = {1}, d[5] = {0}; limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t; limb e[5] = {0}, f[5] = {1}, g[5] = {0}, h[5] = {1}; limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h; unsigned i, j; memcpy(nqpqx, q, sizeof(limb) * 5); for (i = 0; i < 32; ++i) { u8 byte = n[31 - i]; for (j = 0; j < 8; ++j) { const limb bit = byte >> 7; swap_conditional(nqx, nqpqx, bit); swap_conditional(nqz, nqpqz, bit); fmonty(nqx2, nqz2, nqpqx2, nqpqz2, nqx, nqz, nqpqx, nqpqz, q); swap_conditional(nqx2, nqpqx2, bit); swap_conditional(nqz2, nqpqz2, bit); t = nqx; nqx = nqx2; nqx2 = t; t = nqz; nqz = nqz2; nqz2 = t; t = nqpqx; nqpqx = nqpqx2; nqpqx2 = t; t = nqpqz; nqpqz = nqpqz2; nqpqz2 = t; byte <<= 1; } } memcpy(resultx, nqx, sizeof(limb) * 5); memcpy(resultz, nqz, sizeof(limb) * 5); } // ----------------------------------------------------------------------------- // Shamelessly copied from djb's code, tightened a little // ----------------------------------------------------------------------------- static void crecip(felem out, const felem z) { felem a,t0,b,c; /* 2 */ fsquare_times(a, z, 1); // a = 2 /* 8 */ fsquare_times(t0, a, 2); /* 9 */ fmul(b, t0, z); // b = 9 /* 11 */ fmul(a, b, a); // a = 11 /* 22 */ fsquare_times(t0, a, 1); /* 2^5 - 2^0 = 31 */ fmul(b, t0, b); /* 2^10 - 2^5 */ fsquare_times(t0, b, 5); /* 2^10 - 2^0 */ fmul(b, t0, b); /* 2^20 - 2^10 */ fsquare_times(t0, b, 10); /* 2^20 - 2^0 */ fmul(c, t0, b); /* 2^40 - 2^20 */ fsquare_times(t0, c, 20); /* 2^40 - 2^0 */ fmul(t0, t0, c); /* 2^50 - 2^10 */ fsquare_times(t0, t0, 10); /* 2^50 - 2^0 */ fmul(b, t0, b); /* 2^100 - 2^50 */ fsquare_times(t0, b, 50); /* 2^100 - 2^0 */ fmul(c, t0, b); /* 2^200 - 2^100 */ fsquare_times(t0, c, 100); /* 2^200 - 2^0 */ fmul(t0, t0, c); /* 2^250 - 2^50 */ fsquare_times(t0, t0, 50); /* 2^250 - 2^0 */ fmul(t0, t0, b); /* 2^255 - 2^5 */ fsquare_times(t0, t0, 5); /* 2^255 - 21 */ fmul(out, t0, a); } int crypto_scalarmult(u8 *mypublic, const u8 *secret, const u8 *basepoint) { limb bp[5], x[5], z[5], zmone[5]; uint8_t e[32]; int i; for (i = 0;i < 32;++i) e[i] = secret[i]; e[0] &= 248; e[31] &= 127; e[31] |= 64; fexpand(bp, basepoint); cmult(x, z, e, bp); crecip(zmone, z); fmul(z, x, zmone); fcontract(mypublic, z); return 0; } EOF