From: Thomas Pornin Date: Mon, 16 Jan 2017 19:19:11 +0000 (+0100) Subject: Some cleanups (removed unused files, split i15 code into per-function files). X-Git-Tag: v0.4~15 X-Git-Url: https://bearssl.org/gitweb//home/git/?p=BearSSL;a=commitdiff_plain;h=2f454aad577ae53798935cc32438a2d3f02ba31f Some cleanups (removed unused files, split i15 code into per-function files). --- diff --git a/Makefile b/Makefile index 32980cc..f739d9a 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,7 @@ OBJCODEC = $(BUILD)/ccopy.o $(BUILD)/dec16be.o $(BUILD)/dec16le.o $(BUILD)/dec32 OBJEC = $(BUILD)/ec_all_m15.o $(BUILD)/ec_all_m31.o $(BUILD)/ec_c25519_i15.o $(BUILD)/ec_c25519_i31.o $(BUILD)/ec_c25519_m15.o $(BUILD)/ec_c25519_m31.o $(BUILD)/ec_curve25519.o $(BUILD)/ec_p256_m15.o $(BUILD)/ec_p256_m31.o $(BUILD)/ec_prime_i15.o $(BUILD)/ec_prime_i31.o $(BUILD)/ec_secp256r1.o $(BUILD)/ec_secp384r1.o $(BUILD)/ec_secp521r1.o $(BUILD)/ecdsa_atr.o $(BUILD)/ecdsa_i15_bits.o $(BUILD)/ecdsa_i15_sign_asn1.o $(BUILD)/ecdsa_i15_sign_raw.o $(BUILD)/ecdsa_i15_vrfy_asn1.o $(BUILD)/ecdsa_i15_vrfy_raw.o $(BUILD)/ecdsa_i31_bits.o $(BUILD)/ecdsa_i31_sign_asn1.o $(BUILD)/ecdsa_i31_sign_raw.o $(BUILD)/ecdsa_i31_vrfy_asn1.o $(BUILD)/ecdsa_i31_vrfy_raw.o $(BUILD)/ecdsa_rta.o # $(BUILD)/ec_prime_i31_secp256r1.o $(BUILD)/ec_prime_i31_secp384r1.o $(BUILD)/ec_prime_i31_secp521r1.o OBJHASH = $(BUILD)/dig_oid.o $(BUILD)/dig_size.o $(BUILD)/ghash_ctmul.o $(BUILD)/ghash_ctmul32.o $(BUILD)/ghash_ctmul64.o $(BUILD)/md5.o $(BUILD)/md5sha1.o $(BUILD)/multihash.o $(BUILD)/sha1.o $(BUILD)/sha2big.o $(BUILD)/sha2small.o -OBJINT15 = $(BUILD)/i15_core.o $(BUILD)/i15_ext1.o $(BUILD)/i15_ext2.o +OBJINT15 = $(BUILD)/i15_add.o $(BUILD)/i15_bitlen.o $(BUILD)/i15_decmod.o $(BUILD)/i15_decode.o $(BUILD)/i15_decred.o $(BUILD)/i15_encode.o $(BUILD)/i15_fmont.o $(BUILD)/i15_iszero.o $(BUILD)/i15_modpow.o $(BUILD)/i15_montmul.o $(BUILD)/i15_mulacc.o $(BUILD)/i15_muladd.o $(BUILD)/i15_ninv15.o $(BUILD)/i15_reduce.o $(BUILD)/i15_rshift.o $(BUILD)/i15_sub.o $(BUILD)/i15_tmont.o OBJINT31 = $(BUILD)/i31_add.o $(BUILD)/i31_bitlen.o $(BUILD)/i31_decmod.o $(BUILD)/i31_decode.o $(BUILD)/i31_decred.o $(BUILD)/i31_encode.o $(BUILD)/i31_fmont.o $(BUILD)/i31_iszero.o $(BUILD)/i31_modpow.o $(BUILD)/i31_montmul.o $(BUILD)/i31_mulacc.o $(BUILD)/i31_muladd.o $(BUILD)/i31_ninv31.o $(BUILD)/i31_reduce.o $(BUILD)/i31_rshift.o $(BUILD)/i31_sub.o $(BUILD)/i31_tmont.o OBJINT32 = $(BUILD)/i32_add.o $(BUILD)/i32_bitlen.o $(BUILD)/i32_decmod.o $(BUILD)/i32_decode.o $(BUILD)/i32_decred.o $(BUILD)/i32_div32.o $(BUILD)/i32_encode.o $(BUILD)/i32_fmont.o $(BUILD)/i32_iszero.o $(BUILD)/i32_modpow.o $(BUILD)/i32_montmul.o $(BUILD)/i32_mulacc.o $(BUILD)/i32_muladd.o $(BUILD)/i32_ninv32.o $(BUILD)/i32_reduce.o $(BUILD)/i32_sub.o $(BUILD)/i32_tmont.o OBJMAC = $(BUILD)/hmac.o $(BUILD)/hmac_ct.o @@ -282,14 +282,56 @@ $(BUILD)/sha2big.o: src/hash/sha2big.c $(HEADERS) $(BUILD)/sha2small.o: src/hash/sha2small.c $(HEADERS) $(CC) $(CFLAGS) -c -o $(BUILD)/sha2small.o src/hash/sha2small.c -$(BUILD)/i15_core.o: src/int/i15_core.c $(HEADERS) - $(CC) $(CFLAGS) -c -o $(BUILD)/i15_core.o src/int/i15_core.c +$(BUILD)/i15_add.o: src/int/i15_add.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $(BUILD)/i15_add.o src/int/i15_add.c -$(BUILD)/i15_ext1.o: src/int/i15_ext1.c $(HEADERS) - $(CC) $(CFLAGS) -c -o $(BUILD)/i15_ext1.o src/int/i15_ext1.c +$(BUILD)/i15_bitlen.o: src/int/i15_bitlen.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $(BUILD)/i15_bitlen.o src/int/i15_bitlen.c -$(BUILD)/i15_ext2.o: src/int/i15_ext2.c $(HEADERS) - $(CC) $(CFLAGS) -c -o $(BUILD)/i15_ext2.o src/int/i15_ext2.c +$(BUILD)/i15_decmod.o: src/int/i15_decmod.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $(BUILD)/i15_decmod.o src/int/i15_decmod.c + +$(BUILD)/i15_decode.o: src/int/i15_decode.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $(BUILD)/i15_decode.o src/int/i15_decode.c + +$(BUILD)/i15_decred.o: src/int/i15_decred.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $(BUILD)/i15_decred.o src/int/i15_decred.c + +$(BUILD)/i15_encode.o: src/int/i15_encode.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $(BUILD)/i15_encode.o src/int/i15_encode.c + +$(BUILD)/i15_fmont.o: src/int/i15_fmont.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $(BUILD)/i15_fmont.o src/int/i15_fmont.c + +$(BUILD)/i15_iszero.o: src/int/i15_iszero.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $(BUILD)/i15_iszero.o src/int/i15_iszero.c + +$(BUILD)/i15_modpow.o: src/int/i15_modpow.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $(BUILD)/i15_modpow.o src/int/i15_modpow.c + +$(BUILD)/i15_montmul.o: src/int/i15_montmul.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $(BUILD)/i15_montmul.o src/int/i15_montmul.c + +$(BUILD)/i15_mulacc.o: src/int/i15_mulacc.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $(BUILD)/i15_mulacc.o src/int/i15_mulacc.c + +$(BUILD)/i15_muladd.o: src/int/i15_muladd.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $(BUILD)/i15_muladd.o src/int/i15_muladd.c + +$(BUILD)/i15_ninv15.o: src/int/i15_ninv15.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $(BUILD)/i15_ninv15.o src/int/i15_ninv15.c + +$(BUILD)/i15_reduce.o: src/int/i15_reduce.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $(BUILD)/i15_reduce.o src/int/i15_reduce.c + +$(BUILD)/i15_rshift.o: src/int/i15_rshift.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $(BUILD)/i15_rshift.o src/int/i15_rshift.c + +$(BUILD)/i15_sub.o: src/int/i15_sub.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $(BUILD)/i15_sub.o src/int/i15_sub.c + +$(BUILD)/i15_tmont.o: src/int/i15_tmont.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $(BUILD)/i15_tmont.o src/int/i15_tmont.c $(BUILD)/i31_add.o: src/int/i31_add.c $(HEADERS) $(CC) $(CFLAGS) -c -o $(BUILD)/i31_add.o src/int/i31_add.c diff --git a/src/ec/ec_curve25519.c b/src/ec/ec_curve25519.c index de1a8f8..a47d215 100644 --- a/src/ec/ec_curve25519.c +++ b/src/ec/ec_curve25519.c @@ -32,10 +32,10 @@ static const unsigned char GEN[] = { }; static const unsigned char ORDER[] = { - 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x14, 0xDE, 0xF9, 0xDE, 0xA2, 0xF7, 0x9C, 0xD6, - 0x58, 0x12, 0x63, 0x1A, 0x5C, 0xF5, 0xD3, 0xED + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /* see inner.h */ diff --git a/src/inner.h b/src/inner.h index 9123a42..8ada612 100644 --- a/src/inner.h +++ b/src/inner.h @@ -1456,30 +1456,14 @@ extern const br_ec_curve_def br_secp256r1; extern const br_ec_curve_def br_secp384r1; extern const br_ec_curve_def br_secp521r1; -extern const br_ec_curve_def br_curve25519; - -#if 0 -/* obsolete */ /* - * Type for the parameters for a "prime curve": - * coordinates are in GF(p), with p prime - * curve equation is Y^2 = X^3 - 3*X + b - * b is in Montgomery representation - * curve order is n and is prime - * base point is G (encoded) and has order n + * For Curve25519, the advertised "order" really is 2^255-1, since the + * point multipliction function really works over arbitrary 255-bit + * scalars. This value is only meant as a hint for ECDH key generation; + * only ECDSA uses the exact curve order, and ECDSA is not used with + * that specific curve. */ -typedef struct { - const uint32_t *p; - const uint32_t *b; - const uint32_t p0i; -} br_ec_prime_i31_curve; - -extern const br_ec_prime_i31_curve br_ec_prime_i31_secp256r1; -extern const br_ec_prime_i31_curve br_ec_prime_i31_secp384r1; -extern const br_ec_prime_i31_curve br_ec_prime_i31_secp521r1; - -#define BR_EC_I31_LEN ((BR_MAX_EC_SIZE + 61) / 31) -#endif +extern const br_ec_curve_def br_curve25519; /* * Decode some bytes as an i31 integer, with truncation (corresponding diff --git a/src/ec/ec_prime_i31_secp256r1.c b/src/int/i15_add.c similarity index 70% rename from src/ec/ec_prime_i31_secp256r1.c rename to src/int/i15_add.c index 007b6b2..97e29b8 100644 --- a/src/ec/ec_prime_i31_secp256r1.c +++ b/src/int/i15_add.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Thomas Pornin + * Copyright (c) 2017 Thomas Pornin * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -24,23 +24,23 @@ #include "inner.h" -static const uint32_t P256_P[] = { - 0x00000108, - 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x00000007, - 0x00000000, 0x00000000, 0x00000040, 0x7FFFFF80, - 0x000000FF -}; +/* see inner.h */ +uint32_t +br_i15_add(uint16_t *a, const uint16_t *b, uint32_t ctl) +{ + uint32_t cc; + size_t u, m; -static const uint32_t P256_B[] = { - 0x00000108, - 0x6FEE1803, 0x6229C4BD, 0x21B139BE, 0x327150AA, - 0x3567802E, 0x3F7212ED, 0x012E4355, 0x782DD38D, - 0x0000000E -}; + cc = 0; + m = (a[0] + 31) >> 4; + for (u = 1; u < m; u ++) { + uint32_t aw, bw, naw; -/* see inner.h */ -const br_ec_prime_i31_curve br_ec_prime_i31_secp256r1 = { - P256_P, - P256_B, - 0x00000001 -}; + aw = a[u]; + bw = b[u]; + naw = aw + bw + cc; + cc = naw >> 15; + a[u] = MUX(ctl, naw & 0x7FFF, aw); + } + return cc; +} diff --git a/src/ec/ec_prime_i31_secp384r1.c b/src/int/i15_bitlen.c similarity index 66% rename from src/ec/ec_prime_i31_secp384r1.c rename to src/int/i15_bitlen.c index 9f92b4f..ad74467 100644 --- a/src/ec/ec_prime_i31_secp384r1.c +++ b/src/int/i15_bitlen.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Thomas Pornin + * Copyright (c) 2017 Thomas Pornin * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -24,25 +24,21 @@ #include "inner.h" -static const uint32_t P384_P[] = { - 0x0000018C, - 0x7FFFFFFF, 0x00000001, 0x00000000, 0x7FFFFFF8, - 0x7FFFFFEF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, - 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, - 0x00000FFF -}; +/* see inner.h */ +uint32_t +br_i15_bit_length(uint16_t *x, size_t xlen) +{ + uint32_t tw, twk; -static const uint32_t P384_B[] = { - 0x0000018C, - 0x6E666840, 0x070D0392, 0x5D810231, 0x7651D50C, - 0x17E218D6, 0x1B192002, 0x44EFE441, 0x3A524E2B, - 0x2719BA5F, 0x41F02209, 0x36C5643E, 0x5813EFFE, - 0x000008A5 -}; + tw = 0; + twk = 0; + while (xlen -- > 0) { + uint32_t w, c; -/* see inner.h */ -const br_ec_prime_i31_curve br_ec_prime_i31_secp384r1 = { - P384_P, - P384_B, - 0x00000001 -}; + c = EQ(tw, 0); + w = x[xlen]; + tw = MUX(c, w, tw); + twk = MUX(c, (uint32_t)xlen, twk); + } + return (twk << 4) + BIT_LENGTH(tw); +} diff --git a/src/int/i15_core.c b/src/int/i15_core.c deleted file mode 100644 index a33469a..0000000 --- a/src/int/i15_core.c +++ /dev/null @@ -1,480 +0,0 @@ -/* - * Copyright (c) 2017 Thomas Pornin - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "inner.h" - -/* - * This file contains the core "big integer" functions for the i15 - * implementation, that represents integers as sequences of 15-bit - * words. - */ - -/* see inner.h */ -uint32_t -br_i15_iszero(const uint16_t *x) -{ - uint32_t z; - size_t u; - - z = 0; - for (u = (x[0] + 15) >> 4; u > 0; u --) { - z |= x[u]; - } - return ~(z | -z) >> 31; -} - -/* see inner.h */ -uint16_t -br_i15_ninv15(uint16_t x) -{ - uint32_t y; - - y = 2 - x; - y = MUL15(y, 2 - MUL15(x, y)); - y = MUL15(y, 2 - MUL15(x, y)); - y = MUL15(y, 2 - MUL15(x, y)); - return MUX(x & 1, -y, 0) & 0x7FFF; -} - -/* see inner.h */ -uint32_t -br_i15_add(uint16_t *a, const uint16_t *b, uint32_t ctl) -{ - uint32_t cc; - size_t u, m; - - cc = 0; - m = (a[0] + 31) >> 4; - for (u = 1; u < m; u ++) { - uint32_t aw, bw, naw; - - aw = a[u]; - bw = b[u]; - naw = aw + bw + cc; - cc = naw >> 15; - a[u] = MUX(ctl, naw & 0x7FFF, aw); - } - return cc; -} - -/* see inner.h */ -uint32_t -br_i15_sub(uint16_t *a, const uint16_t *b, uint32_t ctl) -{ - uint32_t cc; - size_t u, m; - - cc = 0; - m = (a[0] + 31) >> 4; - for (u = 1; u < m; u ++) { - uint32_t aw, bw, naw; - - aw = a[u]; - bw = b[u]; - naw = aw - bw - cc; - cc = naw >> 31; - a[u] = MUX(ctl, naw & 0x7FFF, aw); - } - return cc; -} - -/* - * Constant-time division. The divisor must not be larger than 16 bits, - * and the quotient must fit on 17 bits. - */ -static uint32_t -divrem16(uint32_t x, uint32_t d, uint32_t *r) -{ - int i; - uint32_t q; - - q = 0; - d <<= 16; - for (i = 16; i >= 0; i --) { - uint32_t ctl; - - ctl = LE(d, x); - q |= ctl << i; - x -= (-ctl) & d; - d >>= 1; - } - if (r != NULL) { - *r = x; - } - return q; -} - -/* see inner.h */ -void -br_i15_muladd_small(uint16_t *x, uint16_t z, const uint16_t *m) -{ - /* - * Constant-time: we accept to leak the exact bit length of the - * modulus m. - */ - unsigned m_bitlen, mblr; - size_t u, mlen; - uint32_t hi, a0, a, b, q; - uint32_t cc, tb, over, under; - - /* - * Simple case: the modulus fits on one word. - */ - m_bitlen = m[0]; - if (m_bitlen == 0) { - return; - } - if (m_bitlen <= 15) { - uint32_t rem; - - divrem16(((uint32_t)x[1] << 15) | z, m[1], &rem); - x[1] = rem; - return; - } - mlen = (m_bitlen + 15) >> 4; - mblr = m_bitlen & 15; - - /* - * Principle: we estimate the quotient (x*2^15+z)/m by - * doing a 30/15 division with the high words. - * - * Let: - * w = 2^15 - * a = (w*a0 + a1) * w^N + a2 - * b = b0 * w^N + b2 - * such that: - * 0 <= a0 < w - * 0 <= a1 < w - * 0 <= a2 < w^N - * w/2 <= b0 < w - * 0 <= b2 < w^N - * a < w*b - * I.e. the two top words of a are a0:a1, the top word of b is - * b0, we ensured that b0 is "full" (high bit set), and a is - * such that the quotient q = a/b fits on one word (0 <= q < w). - * - * If a = b*q + r (with 0 <= r < q), then we can estimate q by - * using a division on the top words: - * a0*w + a1 = b0*u + v (with 0 <= v < b0) - * Then the following holds: - * 0 <= u <= w - * u-2 <= q <= u - */ - hi = x[mlen]; - if (mblr == 0) { - a0 = x[mlen]; - memmove(x + 2, x + 1, (mlen - 1) * sizeof *x); - x[1] = z; - a = (a0 << 15) + x[mlen]; - b = m[mlen]; - } else { - a0 = (x[mlen] << (15 - mblr)) | (x[mlen - 1] >> mblr); - memmove(x + 2, x + 1, (mlen - 1) * sizeof *x); - x[1] = z; - a = (a0 << 15) | (((x[mlen] << (15 - mblr)) - | (x[mlen - 1] >> mblr)) & 0x7FFF); - b = (m[mlen] << (15 - mblr)) | (m[mlen - 1] >> mblr); - } - q = divrem16(a, b, NULL); - - /* - * We computed an estimate for q, but the real one may be q, - * q-1 or q-2; moreover, the division may have returned a value - * 8000 or even 8001 if the two high words were identical, and - * we want to avoid values beyond 7FFF. We thus adjust q so - * that the "true" multiplier will be q+1, q or q-1, and q is - * in the 0000..7FFF range. - */ - q = MUX(EQ(b, a0), 0x7FFF, q - 1 + ((q - 1) >> 31)); - - /* - * We subtract q*m from x (x has an extra high word of value 'hi'). - * Since q may be off by 1 (in either direction), we may have to - * add or subtract m afterwards. - * - * The 'tb' flag will be true (1) at the end of the loop if the - * result is greater than or equal to the modulus (not counting - * 'hi' or the carry). - */ - cc = 0; - tb = 1; - for (u = 1; u <= mlen; u ++) { - uint32_t mw, zl, xw, nxw; - - mw = m[u]; - zl = MUL15(mw, q) + cc; - cc = zl >> 15; - zl &= 0x7FFF; - xw = x[u]; - nxw = xw - zl; - cc += nxw >> 31; - nxw &= 0x7FFF; - x[u] = nxw; - tb = MUX(EQ(nxw, mw), tb, GT(nxw, mw)); - } - - /* - * If we underestimated q, then either cc < hi (one extra bit - * beyond the top array word), or cc == hi and tb is true (no - * extra bit, but the result is not lower than the modulus). - * - * If we overestimated q, then cc > hi. - */ - over = GT(cc, hi); - under = ~over & (tb | LT(cc, hi)); - br_i15_add(x, m, over); - br_i15_sub(x, m, under); -} - -/* see inner.h */ -void -br_i15_montymul(uint16_t *d, const uint16_t *x, const uint16_t *y, - const uint16_t *m, uint16_t m0i) -{ - size_t len, len4, u, v; - uint32_t dh; - - len = (m[0] + 15) >> 4; - len4 = len & ~(size_t)3; - br_i15_zero(d, m[0]); - dh = 0; - for (u = 0; u < len; u ++) { - uint32_t f, xu, r, zh; - - xu = x[u + 1]; - f = MUL15((d[1] + MUL15(x[u + 1], y[1])) & 0x7FFF, m0i) - & 0x7FFF; - - r = 0; - for (v = 0; v < len4; v += 4) { - uint32_t z; - - z = d[v + 1] + MUL15(xu, y[v + 1]) - + MUL15(f, m[v + 1]) + r; - r = z >> 15; - d[v + 0] = z & 0x7FFF; - z = d[v + 2] + MUL15(xu, y[v + 2]) - + MUL15(f, m[v + 2]) + r; - r = z >> 15; - d[v + 1] = z & 0x7FFF; - z = d[v + 3] + MUL15(xu, y[v + 3]) - + MUL15(f, m[v + 3]) + r; - r = z >> 15; - d[v + 2] = z & 0x7FFF; - z = d[v + 4] + MUL15(xu, y[v + 4]) - + MUL15(f, m[v + 4]) + r; - r = z >> 15; - d[v + 3] = z & 0x7FFF; - } - for (; v < len; v ++) { - uint32_t z; - - z = d[v + 1] + MUL15(xu, y[v + 1]) - + MUL15(f, m[v + 1]) + r; - r = z >> 15; - d[v + 0] = z & 0x7FFF; - } - - zh = dh + r; - d[len] = zh & 0x7FFF; - dh = zh >> 15; - } - - /* - * Restore the bit length (it was overwritten in the loop above). - */ - d[0] = m[0]; - - /* - * d[] may be greater than m[], but it is still lower than twice - * the modulus. - */ - br_i15_sub(d, m, NEQ(dh, 0) | NOT(br_i15_sub(d, m, 0))); -} - -/* see inner.h */ -void -br_i15_to_monty(uint16_t *x, const uint16_t *m) -{ - unsigned k; - - for (k = (m[0] + 15) >> 4; k > 0; k --) { - br_i15_muladd_small(x, 0, m); - } -} - -/* see inner.h */ -void -br_i15_modpow(uint16_t *x, - const unsigned char *e, size_t elen, - const uint16_t *m, uint16_t m0i, uint16_t *t1, uint16_t *t2) -{ - size_t mlen; - unsigned k; - - mlen = ((m[0] + 31) >> 4) * sizeof m[0]; - memcpy(t1, x, mlen); - br_i15_to_monty(t1, m); - br_i15_zero(x, m[0]); - x[1] = 1; - for (k = 0; k < ((unsigned)elen << 3); k ++) { - uint32_t ctl; - - ctl = (e[elen - 1 - (k >> 3)] >> (k & 7)) & 1; - br_i15_montymul(t2, x, t1, m, m0i); - CCOPY(ctl, x, t2, mlen); - br_i15_montymul(t2, t1, t1, m, m0i); - memcpy(t1, t2, mlen); - } -} - -/* see inner.h */ -void -br_i15_encode(void *dst, size_t len, const uint16_t *x) -{ - unsigned char *buf; - size_t u, xlen; - uint32_t acc; - int acc_len; - - xlen = (x[0] + 15) >> 4; - if (xlen == 0) { - memset(dst, 0, len); - return; - } - u = 1; - acc = 0; - acc_len = 0; - buf = dst; - while (len -- > 0) { - if (acc_len < 8) { - if (u <= xlen) { - acc += (uint32_t)x[u ++] << acc_len; - } - acc_len += 15; - } - buf[len] = (unsigned char)acc; - acc >>= 8; - acc_len -= 8; - } -} - -/* see inner.h */ -uint32_t -br_i15_decode_mod(uint16_t *x, const void *src, size_t len, const uint16_t *m) -{ - /* - * Two-pass algorithm: in the first pass, we determine whether the - * value fits; in the second pass, we do the actual write. - * - * During the first pass, 'r' contains the comparison result so - * far: - * 0x00000000 value is equal to the modulus - * 0x00000001 value is greater than the modulus - * 0xFFFFFFFF value is lower than the modulus - * - * Since we iterate starting with the least significant bytes (at - * the end of src[]), each new comparison overrides the previous - * except when the comparison yields 0 (equal). - * - * During the second pass, 'r' is either 0xFFFFFFFF (value fits) - * or 0x00000000 (value does not fit). - * - * We must iterate over all bytes of the source, _and_ possibly - * some extra virutal bytes (with value 0) so as to cover the - * complete modulus as well. We also add 4 such extra bytes beyond - * the modulus length because it then guarantees that no accumulated - * partial word remains to be processed. - */ - const unsigned char *buf; - size_t mlen, tlen; - int pass; - uint32_t r; - - buf = src; - mlen = (m[0] + 15) >> 4; - tlen = (mlen << 1); - if (tlen < len) { - tlen = len; - } - tlen += 4; - r = 0; - for (pass = 0; pass < 2; pass ++) { - size_t u, v; - uint32_t acc; - int acc_len; - - v = 1; - acc = 0; - acc_len = 0; - for (u = 0; u < tlen; u ++) { - uint32_t b; - - if (u < len) { - b = buf[len - 1 - u]; - } else { - b = 0; - } - acc |= (b << acc_len); - acc_len += 8; - if (acc_len >= 15) { - uint32_t xw; - - xw = acc & (uint32_t)0x7FFF; - acc_len -= 15; - acc = b >> (8 - acc_len); - if (v <= mlen) { - if (pass) { - x[v] = r & xw; - } else { - uint32_t cc; - - cc = (uint32_t)CMP(xw, m[v]); - r = MUX(EQ(cc, 0), r, cc); - } - } else { - if (!pass) { - r = MUX(EQ(xw, 0), r, 1); - } - } - v ++; - } - } - - /* - * When we reach this point at the end of the first pass: - * r is either 0, 1 or -1; we want to set r to 0 if it - * is equal to 0 or 1, and leave it to -1 otherwise. - * - * When we reach this point at the end of the second pass: - * r is either 0 or -1; we want to leave that value - * untouched. This is a subcase of the previous. - */ - r >>= 1; - r |= (r << 1); - } - - x[0] = m[0]; - return r & (uint32_t)1; -} diff --git a/src/int/i15_decmod.c b/src/int/i15_decmod.c new file mode 100644 index 0000000..be955e3 --- /dev/null +++ b/src/int/i15_decmod.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint32_t +br_i15_decode_mod(uint16_t *x, const void *src, size_t len, const uint16_t *m) +{ + /* + * Two-pass algorithm: in the first pass, we determine whether the + * value fits; in the second pass, we do the actual write. + * + * During the first pass, 'r' contains the comparison result so + * far: + * 0x00000000 value is equal to the modulus + * 0x00000001 value is greater than the modulus + * 0xFFFFFFFF value is lower than the modulus + * + * Since we iterate starting with the least significant bytes (at + * the end of src[]), each new comparison overrides the previous + * except when the comparison yields 0 (equal). + * + * During the second pass, 'r' is either 0xFFFFFFFF (value fits) + * or 0x00000000 (value does not fit). + * + * We must iterate over all bytes of the source, _and_ possibly + * some extra virutal bytes (with value 0) so as to cover the + * complete modulus as well. We also add 4 such extra bytes beyond + * the modulus length because it then guarantees that no accumulated + * partial word remains to be processed. + */ + const unsigned char *buf; + size_t mlen, tlen; + int pass; + uint32_t r; + + buf = src; + mlen = (m[0] + 15) >> 4; + tlen = (mlen << 1); + if (tlen < len) { + tlen = len; + } + tlen += 4; + r = 0; + for (pass = 0; pass < 2; pass ++) { + size_t u, v; + uint32_t acc; + int acc_len; + + v = 1; + acc = 0; + acc_len = 0; + for (u = 0; u < tlen; u ++) { + uint32_t b; + + if (u < len) { + b = buf[len - 1 - u]; + } else { + b = 0; + } + acc |= (b << acc_len); + acc_len += 8; + if (acc_len >= 15) { + uint32_t xw; + + xw = acc & (uint32_t)0x7FFF; + acc_len -= 15; + acc = b >> (8 - acc_len); + if (v <= mlen) { + if (pass) { + x[v] = r & xw; + } else { + uint32_t cc; + + cc = (uint32_t)CMP(xw, m[v]); + r = MUX(EQ(cc, 0), r, cc); + } + } else { + if (!pass) { + r = MUX(EQ(xw, 0), r, 1); + } + } + v ++; + } + } + + /* + * When we reach this point at the end of the first pass: + * r is either 0, 1 or -1; we want to set r to 0 if it + * is equal to 0 or 1, and leave it to -1 otherwise. + * + * When we reach this point at the end of the second pass: + * r is either 0 or -1; we want to leave that value + * untouched. This is a subcase of the previous. + */ + r >>= 1; + r |= (r << 1); + } + + x[0] = m[0]; + return r & (uint32_t)1; +} diff --git a/src/ec/ec_prime_i31_secp521r1.c b/src/int/i15_decode.c similarity index 63% rename from src/ec/ec_prime_i31_secp521r1.c rename to src/int/i15_decode.c index 84d7d54..fc2c0be 100644 --- a/src/ec/ec_prime_i31_secp521r1.c +++ b/src/int/i15_decode.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Thomas Pornin + * Copyright (c) 2017 Thomas Pornin * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -24,27 +24,33 @@ #include "inner.h" -static const uint32_t P521_P[] = { - 0x00000219, - 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, - 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, - 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, - 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, - 0x01FFFFFF -}; +/* see inner.h */ +void +br_i15_decode(uint16_t *x, const void *src, size_t len) +{ + const unsigned char *buf; + size_t v; + uint32_t acc; + int acc_len; -static const uint32_t P521_B[] = { - 0x00000219, - 0x540FC00A, 0x228FEA35, 0x2C34F1EF, 0x67BF107A, - 0x46FC1CD5, 0x1605E9DD, 0x6937B165, 0x272A3D8F, - 0x42785586, 0x44C8C778, 0x15F3B8B4, 0x64B73366, - 0x03BA8B69, 0x0D05B42A, 0x21F929A2, 0x2C31C393, - 0x00654FAE -}; + buf = src; + v = 1; + acc = 0; + acc_len = 0; + while (len -- > 0) { + uint32_t b; -/* see inner.h */ -const br_ec_prime_i31_curve br_ec_prime_i31_secp521r1 = { - P521_P, - P521_B, - 0x00000001 -}; + b = buf[len]; + acc |= (b << acc_len); + acc_len += 8; + if (acc_len >= 15) { + x[v ++] = acc & 0x7FFF; + acc_len -= 15; + acc >>= 15; + } + } + if (acc_len != 0) { + x[v ++] = acc; + } + x[0] = br_i15_bit_length(x + 1, v - 1); +} diff --git a/src/int/i15_ext2.c b/src/int/i15_decred.c similarity index 64% rename from src/int/i15_ext2.c rename to src/int/i15_decred.c index 84fc2d6..81e7dd1 100644 --- a/src/int/i15_ext2.c +++ b/src/int/i15_decred.c @@ -24,11 +24,6 @@ #include "inner.h" -/* - * This file contains some additional functions for "i15" big integers. - * These functions are needed to support RSA. - */ - /* see inner.h */ void br_i15_decode_reduce(uint16_t *x, @@ -103,71 +98,3 @@ br_i15_decode_reduce(uint16_t *x, br_i15_muladd_small(x, acc, m); } } - -/* see inner.h */ -void -br_i15_reduce(uint16_t *x, const uint16_t *a, const uint16_t *m) -{ - uint32_t m_bitlen, a_bitlen; - size_t mlen, alen, u; - - m_bitlen = m[0]; - mlen = (m_bitlen + 15) >> 4; - - x[0] = m_bitlen; - if (m_bitlen == 0) { - return; - } - - /* - * If the source is shorter, then simply copy all words from a[] - * and zero out the upper words. - */ - a_bitlen = a[0]; - alen = (a_bitlen + 15) >> 4; - if (a_bitlen < m_bitlen) { - memcpy(x + 1, a + 1, alen * sizeof *a); - for (u = alen; u < mlen; u ++) { - x[u + 1] = 0; - } - return; - } - - /* - * The source length is at least equal to that of the modulus. - * We must thus copy N-1 words, and input the remaining words - * one by one. - */ - memcpy(x + 1, a + 2 + (alen - mlen), (mlen - 1) * sizeof *a); - x[mlen] = 0; - for (u = 1 + alen - mlen; u > 0; u --) { - br_i15_muladd_small(x, a[u], m); - } -} - -/* see inner.h */ -void -br_i15_mulacc(uint16_t *d, const uint16_t *a, const uint16_t *b) -{ - size_t alen, blen, u; - - alen = (a[0] + 15) >> 4; - blen = (b[0] + 15) >> 4; - d[0] = a[0] + b[0]; - for (u = 0; u < blen; u ++) { - uint32_t f; - size_t v; - uint32_t cc; - - f = b[1 + u]; - cc = 0; - for (v = 0; v < alen; v ++) { - uint32_t z; - - z = (uint32_t)d[1 + u + v] + MUL15(f, a[1 + v]) + cc; - cc = z >> 15; - d[1 + u + v] = z & 0x7FFF; - } - d[1 + u + alen] = cc; - } -} diff --git a/src/int/i15_encode.c b/src/int/i15_encode.c new file mode 100644 index 0000000..50668f4 --- /dev/null +++ b/src/int/i15_encode.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i15_encode(void *dst, size_t len, const uint16_t *x) +{ + unsigned char *buf; + size_t u, xlen; + uint32_t acc; + int acc_len; + + xlen = (x[0] + 15) >> 4; + if (xlen == 0) { + memset(dst, 0, len); + return; + } + u = 1; + acc = 0; + acc_len = 0; + buf = dst; + while (len -- > 0) { + if (acc_len < 8) { + if (u <= xlen) { + acc += (uint32_t)x[u ++] << acc_len; + } + acc_len += 15; + } + buf[len] = (unsigned char)acc; + acc >>= 8; + acc_len -= 8; + } +} diff --git a/src/int/i15_ext1.c b/src/int/i15_fmont.c similarity index 61% rename from src/int/i15_ext1.c rename to src/int/i15_fmont.c index a99ac1a..3450b72 100644 --- a/src/int/i15_ext1.c +++ b/src/int/i15_fmont.c @@ -24,83 +24,6 @@ #include "inner.h" -/* - * This file contains some additional functions for "i15" big integers. - * These functions are needed to support ECDSA. - */ - -/* see inner.h */ -void -br_i15_rshift(uint16_t *x, int count) -{ - size_t u, len; - unsigned r; - - len = (x[0] + 15) >> 4; - if (len == 0) { - return; - } - r = x[1] >> count; - for (u = 2; u <= len; u ++) { - unsigned w; - - w = x[u]; - x[u - 1] = ((w << (15 - count)) | r) & 0x7FFF; - r = w >> count; - } - x[len] = r; -} - -/* see inner.h */ -uint32_t -br_i15_bit_length(uint16_t *x, size_t xlen) -{ - uint32_t tw, twk; - - tw = 0; - twk = 0; - while (xlen -- > 0) { - uint32_t w, c; - - c = EQ(tw, 0); - w = x[xlen]; - tw = MUX(c, w, tw); - twk = MUX(c, (uint32_t)xlen, twk); - } - return (twk << 4) + BIT_LENGTH(tw); -} - -/* see inner.h */ -void -br_i15_decode(uint16_t *x, const void *src, size_t len) -{ - const unsigned char *buf; - size_t v; - uint32_t acc; - int acc_len; - - buf = src; - v = 1; - acc = 0; - acc_len = 0; - while (len -- > 0) { - uint32_t b; - - b = buf[len]; - acc |= (b << acc_len); - acc_len += 8; - if (acc_len >= 15) { - x[v ++] = acc & 0x7FFF; - acc_len -= 15; - acc >>= 15; - } - } - if (acc_len != 0) { - x[v ++] = acc; - } - x[0] = br_i15_bit_length(x + 1, v - 1); -} - /* see inner.h */ void br_i15_from_monty(uint16_t *x, const uint16_t *m, uint16_t m0i) diff --git a/src/int/i15_iszero.c b/src/int/i15_iszero.c new file mode 100644 index 0000000..d4b6f10 --- /dev/null +++ b/src/int/i15_iszero.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint32_t +br_i15_iszero(const uint16_t *x) +{ + uint32_t z; + size_t u; + + z = 0; + for (u = (x[0] + 15) >> 4; u > 0; u --) { + z |= x[u]; + } + return ~(z | -z) >> 31; +} diff --git a/src/int/i15_modpow.c b/src/int/i15_modpow.c new file mode 100644 index 0000000..9bf304e --- /dev/null +++ b/src/int/i15_modpow.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i15_modpow(uint16_t *x, + const unsigned char *e, size_t elen, + const uint16_t *m, uint16_t m0i, uint16_t *t1, uint16_t *t2) +{ + size_t mlen; + unsigned k; + + mlen = ((m[0] + 31) >> 4) * sizeof m[0]; + memcpy(t1, x, mlen); + br_i15_to_monty(t1, m); + br_i15_zero(x, m[0]); + x[1] = 1; + for (k = 0; k < ((unsigned)elen << 3); k ++) { + uint32_t ctl; + + ctl = (e[elen - 1 - (k >> 3)] >> (k & 7)) & 1; + br_i15_montymul(t2, x, t1, m, m0i); + CCOPY(ctl, x, t2, mlen); + br_i15_montymul(t2, t1, t1, m, m0i); + memcpy(t1, t2, mlen); + } +} diff --git a/src/int/i15_montmul.c b/src/int/i15_montmul.c new file mode 100644 index 0000000..8da938f --- /dev/null +++ b/src/int/i15_montmul.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i15_montymul(uint16_t *d, const uint16_t *x, const uint16_t *y, + const uint16_t *m, uint16_t m0i) +{ + size_t len, len4, u, v; + uint32_t dh; + + len = (m[0] + 15) >> 4; + len4 = len & ~(size_t)3; + br_i15_zero(d, m[0]); + dh = 0; + for (u = 0; u < len; u ++) { + uint32_t f, xu, r, zh; + + xu = x[u + 1]; + f = MUL15((d[1] + MUL15(x[u + 1], y[1])) & 0x7FFF, m0i) + & 0x7FFF; + + r = 0; + for (v = 0; v < len4; v += 4) { + uint32_t z; + + z = d[v + 1] + MUL15(xu, y[v + 1]) + + MUL15(f, m[v + 1]) + r; + r = z >> 15; + d[v + 0] = z & 0x7FFF; + z = d[v + 2] + MUL15(xu, y[v + 2]) + + MUL15(f, m[v + 2]) + r; + r = z >> 15; + d[v + 1] = z & 0x7FFF; + z = d[v + 3] + MUL15(xu, y[v + 3]) + + MUL15(f, m[v + 3]) + r; + r = z >> 15; + d[v + 2] = z & 0x7FFF; + z = d[v + 4] + MUL15(xu, y[v + 4]) + + MUL15(f, m[v + 4]) + r; + r = z >> 15; + d[v + 3] = z & 0x7FFF; + } + for (; v < len; v ++) { + uint32_t z; + + z = d[v + 1] + MUL15(xu, y[v + 1]) + + MUL15(f, m[v + 1]) + r; + r = z >> 15; + d[v + 0] = z & 0x7FFF; + } + + zh = dh + r; + d[len] = zh & 0x7FFF; + dh = zh >> 15; + } + + /* + * Restore the bit length (it was overwritten in the loop above). + */ + d[0] = m[0]; + + /* + * d[] may be greater than m[], but it is still lower than twice + * the modulus. + */ + br_i15_sub(d, m, NEQ(dh, 0) | NOT(br_i15_sub(d, m, 0))); +} diff --git a/src/int/i15_mulacc.c b/src/int/i15_mulacc.c new file mode 100644 index 0000000..7bde395 --- /dev/null +++ b/src/int/i15_mulacc.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i15_mulacc(uint16_t *d, const uint16_t *a, const uint16_t *b) +{ + size_t alen, blen, u; + + alen = (a[0] + 15) >> 4; + blen = (b[0] + 15) >> 4; + d[0] = a[0] + b[0]; + for (u = 0; u < blen; u ++) { + uint32_t f; + size_t v; + uint32_t cc; + + f = b[1 + u]; + cc = 0; + for (v = 0; v < alen; v ++) { + uint32_t z; + + z = (uint32_t)d[1 + u + v] + MUL15(f, a[1 + v]) + cc; + cc = z >> 15; + d[1 + u + v] = z & 0x7FFF; + } + d[1 + u + alen] = cc; + } +} diff --git a/src/int/i15_muladd.c b/src/int/i15_muladd.c new file mode 100644 index 0000000..c4b7216 --- /dev/null +++ b/src/int/i15_muladd.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* + * Constant-time division. The divisor must not be larger than 16 bits, + * and the quotient must fit on 17 bits. + */ +static uint32_t +divrem16(uint32_t x, uint32_t d, uint32_t *r) +{ + int i; + uint32_t q; + + q = 0; + d <<= 16; + for (i = 16; i >= 0; i --) { + uint32_t ctl; + + ctl = LE(d, x); + q |= ctl << i; + x -= (-ctl) & d; + d >>= 1; + } + if (r != NULL) { + *r = x; + } + return q; +} + +/* see inner.h */ +void +br_i15_muladd_small(uint16_t *x, uint16_t z, const uint16_t *m) +{ + /* + * Constant-time: we accept to leak the exact bit length of the + * modulus m. + */ + unsigned m_bitlen, mblr; + size_t u, mlen; + uint32_t hi, a0, a, b, q; + uint32_t cc, tb, over, under; + + /* + * Simple case: the modulus fits on one word. + */ + m_bitlen = m[0]; + if (m_bitlen == 0) { + return; + } + if (m_bitlen <= 15) { + uint32_t rem; + + divrem16(((uint32_t)x[1] << 15) | z, m[1], &rem); + x[1] = rem; + return; + } + mlen = (m_bitlen + 15) >> 4; + mblr = m_bitlen & 15; + + /* + * Principle: we estimate the quotient (x*2^15+z)/m by + * doing a 30/15 division with the high words. + * + * Let: + * w = 2^15 + * a = (w*a0 + a1) * w^N + a2 + * b = b0 * w^N + b2 + * such that: + * 0 <= a0 < w + * 0 <= a1 < w + * 0 <= a2 < w^N + * w/2 <= b0 < w + * 0 <= b2 < w^N + * a < w*b + * I.e. the two top words of a are a0:a1, the top word of b is + * b0, we ensured that b0 is "full" (high bit set), and a is + * such that the quotient q = a/b fits on one word (0 <= q < w). + * + * If a = b*q + r (with 0 <= r < q), then we can estimate q by + * using a division on the top words: + * a0*w + a1 = b0*u + v (with 0 <= v < b0) + * Then the following holds: + * 0 <= u <= w + * u-2 <= q <= u + */ + hi = x[mlen]; + if (mblr == 0) { + a0 = x[mlen]; + memmove(x + 2, x + 1, (mlen - 1) * sizeof *x); + x[1] = z; + a = (a0 << 15) + x[mlen]; + b = m[mlen]; + } else { + a0 = (x[mlen] << (15 - mblr)) | (x[mlen - 1] >> mblr); + memmove(x + 2, x + 1, (mlen - 1) * sizeof *x); + x[1] = z; + a = (a0 << 15) | (((x[mlen] << (15 - mblr)) + | (x[mlen - 1] >> mblr)) & 0x7FFF); + b = (m[mlen] << (15 - mblr)) | (m[mlen - 1] >> mblr); + } + q = divrem16(a, b, NULL); + + /* + * We computed an estimate for q, but the real one may be q, + * q-1 or q-2; moreover, the division may have returned a value + * 8000 or even 8001 if the two high words were identical, and + * we want to avoid values beyond 7FFF. We thus adjust q so + * that the "true" multiplier will be q+1, q or q-1, and q is + * in the 0000..7FFF range. + */ + q = MUX(EQ(b, a0), 0x7FFF, q - 1 + ((q - 1) >> 31)); + + /* + * We subtract q*m from x (x has an extra high word of value 'hi'). + * Since q may be off by 1 (in either direction), we may have to + * add or subtract m afterwards. + * + * The 'tb' flag will be true (1) at the end of the loop if the + * result is greater than or equal to the modulus (not counting + * 'hi' or the carry). + */ + cc = 0; + tb = 1; + for (u = 1; u <= mlen; u ++) { + uint32_t mw, zl, xw, nxw; + + mw = m[u]; + zl = MUL15(mw, q) + cc; + cc = zl >> 15; + zl &= 0x7FFF; + xw = x[u]; + nxw = xw - zl; + cc += nxw >> 31; + nxw &= 0x7FFF; + x[u] = nxw; + tb = MUX(EQ(nxw, mw), tb, GT(nxw, mw)); + } + + /* + * If we underestimated q, then either cc < hi (one extra bit + * beyond the top array word), or cc == hi and tb is true (no + * extra bit, but the result is not lower than the modulus). + * + * If we overestimated q, then cc > hi. + */ + over = GT(cc, hi); + under = ~over & (tb | LT(cc, hi)); + br_i15_add(x, m, over); + br_i15_sub(x, m, under); +} diff --git a/src/int/i15_ninv15.c b/src/int/i15_ninv15.c new file mode 100644 index 0000000..de3a3ba --- /dev/null +++ b/src/int/i15_ninv15.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint16_t +br_i15_ninv15(uint16_t x) +{ + uint32_t y; + + y = 2 - x; + y = MUL15(y, 2 - MUL15(x, y)); + y = MUL15(y, 2 - MUL15(x, y)); + y = MUL15(y, 2 - MUL15(x, y)); + return MUX(x & 1, -y, 0) & 0x7FFF; +} diff --git a/src/int/i15_reduce.c b/src/int/i15_reduce.c new file mode 100644 index 0000000..0931b10 --- /dev/null +++ b/src/int/i15_reduce.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i15_reduce(uint16_t *x, const uint16_t *a, const uint16_t *m) +{ + uint32_t m_bitlen, a_bitlen; + size_t mlen, alen, u; + + m_bitlen = m[0]; + mlen = (m_bitlen + 15) >> 4; + + x[0] = m_bitlen; + if (m_bitlen == 0) { + return; + } + + /* + * If the source is shorter, then simply copy all words from a[] + * and zero out the upper words. + */ + a_bitlen = a[0]; + alen = (a_bitlen + 15) >> 4; + if (a_bitlen < m_bitlen) { + memcpy(x + 1, a + 1, alen * sizeof *a); + for (u = alen; u < mlen; u ++) { + x[u + 1] = 0; + } + return; + } + + /* + * The source length is at least equal to that of the modulus. + * We must thus copy N-1 words, and input the remaining words + * one by one. + */ + memcpy(x + 1, a + 2 + (alen - mlen), (mlen - 1) * sizeof *a); + x[mlen] = 0; + for (u = 1 + alen - mlen; u > 0; u --) { + br_i15_muladd_small(x, a[u], m); + } +} diff --git a/src/int/i15_rshift.c b/src/int/i15_rshift.c new file mode 100644 index 0000000..f9991ab --- /dev/null +++ b/src/int/i15_rshift.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i15_rshift(uint16_t *x, int count) +{ + size_t u, len; + unsigned r; + + len = (x[0] + 15) >> 4; + if (len == 0) { + return; + } + r = x[1] >> count; + for (u = 2; u <= len; u ++) { + unsigned w; + + w = x[u]; + x[u - 1] = ((w << (15 - count)) | r) & 0x7FFF; + r = w >> count; + } + x[len] = r; +} diff --git a/src/int/i15_sub.c b/src/int/i15_sub.c new file mode 100644 index 0000000..1983c4d --- /dev/null +++ b/src/int/i15_sub.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +uint32_t +br_i15_sub(uint16_t *a, const uint16_t *b, uint32_t ctl) +{ + uint32_t cc; + size_t u, m; + + cc = 0; + m = (a[0] + 31) >> 4; + for (u = 1; u < m; u ++) { + uint32_t aw, bw, naw; + + aw = a[u]; + bw = b[u]; + naw = aw - bw - cc; + cc = naw >> 31; + a[u] = MUX(ctl, naw & 0x7FFF, aw); + } + return cc; +} diff --git a/src/int/i15_tmont.c b/src/int/i15_tmont.c new file mode 100644 index 0000000..d5c4b8b --- /dev/null +++ b/src/int/i15_tmont.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "inner.h" + +/* see inner.h */ +void +br_i15_to_monty(uint16_t *x, const uint16_t *m) +{ + unsigned k; + + for (k = (m[0] + 15) >> 4; k > 0; k --) { + br_i15_muladd_small(x, 0, m); + } +} diff --git a/test/test_speed.c b/test/test_speed.c index db65edc..0d440ff 100644 --- a/test/test_speed.c +++ b/test/test_speed.c @@ -885,120 +885,6 @@ test_speed_ecdsa_i31(void) &br_ecdsa_i31_vrfy_asn1); } -#if 0 -/* obsolete */ -static void -test_speed_ec_prime_i31_inner(const char *name, - const unsigned char *bg, const br_ec_prime_i31_curve *cc) -{ - unsigned char bx[80], point[160]; - uint32_t x[BR_EC_I31_LEN]; - br_ec_prime_i31_jacobian P; - uint32_t xbl; - size_t plen; - int i; - long num; - - xbl = cc->p[0]; - xbl -= (xbl >> 5); - plen = (xbl + 7) >> 3; - memset(bx, 'T', sizeof bx); - br_i31_decode_reduce(x, bx, sizeof bx, cc->p); - br_i31_encode(bx, plen, x); - br_ec_prime_i31_decode(&P, bg, 1 + (plen << 1), cc); - for (i = 0; i < 10; i ++) { - br_ec_prime_i31_mul(&P, bx, plen, cc); - br_ec_prime_i31_encode(point, &P, cc); - } - num = 10; - for (;;) { - clock_t begin, end; - double tt; - long k; - - begin = clock(); - for (k = num; k > 0; k --) { - br_ec_prime_i31_mul(&P, bx, plen, cc); - br_ec_prime_i31_encode(point, &P, cc); - } - end = clock(); - tt = (double)(end - begin) / CLOCKS_PER_SEC; - if (tt >= 2.0) { - printf("%-30s %8.2f mul/s\n", name, - (double)num / tt); - fflush(stdout); - break; - } - num <<= 1; - } -} - -static void -test_speed_ec_prime_i31(void) -{ - test_speed_ec_prime_i31_inner("EC i31 P-256", - br_g_secp256r1, &br_ec_prime_i31_secp256r1); - test_speed_ec_prime_i31_inner("EC i31 P-384", - br_g_secp384r1, &br_ec_prime_i31_secp384r1); - test_speed_ec_prime_i31_inner("EC i31 P-521", - br_g_secp521r1, &br_ec_prime_i31_secp521r1); -} - -static void -test_speed_ec_prime_i32_inner(const char *name, - const unsigned char *bg, const br_ec_prime_i32_curve *cc) -{ - unsigned char bx[80], point[160]; - uint32_t x[BR_EC_I32_LEN]; - br_ec_prime_i32_jacobian P; - size_t plen; - int i; - long num; - - plen = (cc->p[0] + 7) >> 3; - memset(bx, 'T', sizeof bx); - br_i32_decode_reduce(x, bx, sizeof bx, cc->p); - br_i32_encode(bx, plen, x); - br_ec_prime_i32_decode(&P, bg, 1 + (plen << 1), cc); - for (i = 0; i < 10; i ++) { - br_ec_prime_i32_mul(&P, bx, plen, cc); - br_ec_prime_i32_encode(point, &P, cc); - } - num = 10; - for (;;) { - clock_t begin, end; - double tt; - long k; - - begin = clock(); - for (k = num; k > 0; k --) { - br_ec_prime_i32_mul(&P, bx, plen, cc); - br_ec_prime_i32_encode(point, &P, cc); - } - end = clock(); - tt = (double)(end - begin) / CLOCKS_PER_SEC; - if (tt >= 2.0) { - printf("%-30s %8.2f mul/s\n", name, - (double)num / tt); - fflush(stdout); - break; - } - num <<= 1; - } -} - -static void -test_speed_ec_prime_i32(void) -{ - test_speed_ec_prime_i32_inner("EC i32 P-256", - br_g_secp256r1, &br_ec_prime_i32_secp256r1); - test_speed_ec_prime_i32_inner("EC i32 P-384", - br_g_secp384r1, &br_ec_prime_i32_secp384r1); - test_speed_ec_prime_i32_inner("EC i32 P-521", - br_g_secp521r1, &br_ec_prime_i32_secp521r1); -} -#endif - static void test_speed_i31(void) {