micro-ecc icon indicating copy to clipboard operation
micro-ecc copied to clipboard

Implementing brainpool curves

Open Seechay opened this issue 8 years ago • 11 comments

I've looked at previous issues on implementing new curves, but I'm not sure about the differences between the brainpool curves and the nist curves. Obviously the domain parameters are different, but do they require they're own specialized double_jacobian and x_side functions? I've re-used the double_jacobian and made a new x_side using the brainpoolP256r1 parameters.

static void x_side_brain(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve) {
    uECC_word_t _a[uECC_MAX_WORDS] = { 
        BYTES_TO_WORDS_8(D9, B5, 30, F3, 44, 4B, 4A, E9),
        BYTES_TO_WORDS_8(6C, 5C, DC, 26, C1, 55, 80, FB),
        BYTES_TO_WORDS_8(E7, FF, 7A, 41, 30, 75, F6, EE),
        BYTES_TO_WORDS_8(57, 30, 2C, FC, 75, 09, 5A, 7D) }; /* -a = 3 */
    wordcount_t num_words = curve->num_words;

    uECC_vli_modSquare_fast(result, x, curve);                             /* r = x^2 */
    uECC_vli_modSub(result, result, _a, curve->p, num_words);       /* r = x^2 - 3 */
    uECC_vli_modMult_fast(result, result, x, curve);                       /* r = x^3 - 3x */
    uECC_vli_modAdd(result, result, curve->b, curve->p, num_words); /* r = x^3 - 3x + b */
}

My curve is:

static const struct uECC_Curve_t curve_brainpoolP256r1 = {
    num_words_brainpoolP256r1,
    num_bytes_brainpoolP256r1,
    256, /* num_n_bits */
    { BYTES_TO_WORDS_8(77, 53, 6E, 1F, 1D, 48, 13, 20),
        BYTES_TO_WORDS_8(28, 20, 26, D5, 23, F6, 3B, 6E),
        BYTES_TO_WORDS_8(72, 8D, 83, 9D, 90, 0A, 66, 3E),
        BYTES_TO_WORDS_8(BC, A9, EE, A1, DB, 57, FB, A9) },
    { BYTES_TO_WORDS_8(A7, 56, 48, 97, 82, 0E, 1E, 90),
        BYTES_TO_WORDS_8(F7, A6, 61, B5, A3, 7A, 39, 8C),
        BYTES_TO_WORDS_8(71, 8D, 83, 9D, 90, 0A, 66, 3E),
        BYTES_TO_WORDS_8(BC, A9, EE, A1, DB, 57, FB, A9) },
    { BYTES_TO_WORDS_8(62, 32, CE, 9A, BD, 53, 44, 3A),
        BYTES_TO_WORDS_8(C2, 23, BD, E3, E1, 27, DE, B9),
        BYTES_TO_WORDS_8(AF, B7, 81, FC, 2F, 48, 4B, 2C),
        BYTES_TO_WORDS_8(CB, 57, 7E, CB, B9, AE, D2, 8B),

        BYTES_TO_WORDS_8(97, 69, 04, 2F, C7, 54, 1D, 5C),
        BYTES_TO_WORDS_8(54, 8E, ED, 2D, 13, 45, 77, C2),
        BYTES_TO_WORDS_8(C9, 1D, 61, 14, 1A, 46, F8, 97),
        BYTES_TO_WORDS_8(FD, C4, DA, C3, 35, F8, 7E, 54) },
    { BYTES_TO_WORDS_8(B6, 07, 8C, FF, 18, DC, CC, 6B),
        BYTES_TO_WORDS_8(CE, E1, F7, 5C, 29, 16, 84, 95),
        BYTES_TO_WORDS_8(BF, 7C, D7, BB, D9, B5, 30, F3),
        BYTES_TO_WORDS_8(44, 4B, 4A, E9, 6C, 5C, DC, 26) },
    &double_jacobian_default,
#if uECC_SUPPORT_COMPRESSED_POINT
    &mod_sqrt_default,
#endif
    &x_side_brain,
#if (uECC_OPTIMIZATION_LEVEL > 0)
    &vli_mmod_fast_brainpoolP256r1
#endif
};

I tried making a key, and it did so without errors, but the key is invalid from uECC_valid_public_key(), it signed okay, but the verify failed. A second key pair was generated for the shared secret, but they were both different. Does this require it's own implementations of the mod, x_side and double_jacobian functions?

Seechay avatar Jun 02 '16 20:06 Seechay

The double_jacobian_default() function only works if a ≣ -3 (mod p). Since that isn't true for the Brainpool curves, you'll need to implement a separate version.

kmackay avatar Jun 04 '16 23:06 kmackay

I've made my own jacobian function, but my public key is considered invalid and signature verification fails. Is the vli_mmod_fast_secp256r1 specific to that curve, or would that work on any 256 bit curve? Here's the jacobian I implemented, I also added a new field to the uECC_Curve_t to include the a parameter. The x_side_brainpoolP256r1 function was updated to utilize the new field, and was also changed from subtract to addition.

/* Double in place */
static void double_jacobian_brainpoolP256r1(uECC_word_t * X1,
                                      uECC_word_t * Y1,
                                      uECC_word_t * Z1,
                                      uECC_Curve curve) {
    /* t1 = X, t2 = Y, t3 = Z */
    uECC_word_t t4[num_words_brainpoolP256r1];
    uECC_word_t t5[num_words_brainpoolP256r1];
    uECC_word_t t6[num_words_brainpoolP256r1];

    if (uECC_vli_isZero(Z1, num_words_brainpoolP256r1)) {
        return;
    }

    uECC_vli_modSquare_fast(t4, X1, curve);   /* t4 = x1^2 */
    uECC_vli_modSquare_fast(t5, Y1, curve); /* t5 = y1^2 */
    uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 =  x1*y1^2 = A */
    uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = y1^4 */
    uECC_vli_modSquare_fast(t6, Z1, curve); /* t6 = z1^2 */
    uECC_vli_modSquare_fast(t6, t6, curve); /* t6 = z1^4 */
    uECC_vli_modMult_fast(Z1, Y1, Z1, curve); /* t3 =  y1*z1 = z3 */
    uECC_vli_modAdd(Y1, t4, t4, curve->p, num_words_brainpoolP256r1); /* t2 = 2*x1^2 */
    uECC_vli_modAdd(t4, t4, Y1, curve->p, num_words_brainpoolP256r1); /* t2 = 3*x1^2 */
    uECC_vli_modMult_fast(t6, curve->a, t6, curve); /* t6 =  a*z1^4 */
    uECC_vli_modAdd(t4, t4, t6, curve->p, num_words_brainpoolP256r1); /* t4 = 3*x1^2 + a*z1^4 */

    if (uECC_vli_testBit(t4, 0)) {
        uECC_word_t carry = uECC_vli_add(t4, t4, curve->p, num_words_brainpoolP256r1);
        uECC_vli_rshift1(t4, num_words_brainpoolP256r1);
        t4[num_words_brainpoolP256r1 - 1] |= carry << (uECC_WORD_BITS - 1);
    } else {
        uECC_vli_rshift1(t4, num_words_brainpoolP256r1);
    }
    /* t4 = 1/2*(3*x1^2 + a*z1^4) = B */

    uECC_vli_modSquare_fast(t6, t4, curve);                     /* t6 = B^2 */
    uECC_vli_modAdd(Y1, X1, X1, curve->p, num_words_brainpoolP256r1); /* t2 = 2A */ 
    uECC_vli_modSub(t6, t6, t2, curve->p, num_words_brainpoolP256r1); /* t1 = B^2 - 2A = x3 */    
    uECC_vli_modSub(X1, X1, t6, curve->p, num_words_brainpoolP256r1); /* t4 = A - x3 */ 
    uECC_vli_modMult_fast(t4, t4, X1, curve);                   /* t4 = B * (A - x3) */
    uECC_vli_modSub(X1, t4, t5, curve->p, num_words_brainpoolP256r1); /* t2 = B * (A - x3) - y1^4 = y3 */

    uECC_vli_set(Y1, X1, num_words);
    uECC_vli_set(X1, t6, num_words);
}

Is there anything you can think of that would be wrong/missing?

Seechay avatar Jun 05 '16 05:06 Seechay

Yes, vli_mmod_fast_secp256r1() is specific to that curve.

kmackay avatar Jun 06 '16 01:06 kmackay

Is there anything else I'd need to implement specifically for the brainpool curves? On Jun 5, 2016 9:33 PM, "Ken MacKay" [email protected] wrote:

Yes, vli_mmod_fast_secp256r1() is specific to that curve.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/kmackay/micro-ecc/issues/82#issuecomment-223851700, or mute the thread https://github.com/notifications/unsubscribe/AHYfXcWRU5rQZkwEE8A4dEFJdh8iSAHFks5qI3kAgaJpZM4Is7p0 .

Seechay avatar Jun 06 '16 01:06 Seechay

The prime == 3 (mod 4), so the default mod_sqrt function should be correct. I think if you implement double_jacobian() and vli_mmod_fast(), that should be sufficient.

kmackay avatar Jun 07 '16 05:06 kmackay

Is there a specific algorithm you recommend implementing that would work with this? I don't see anything similar to the nist routine publications for brainpool. Is there any general ECC mod function that would work?

Seechay avatar Jun 08 '16 22:06 Seechay

You can use the existing uECC_vli_mmod() function. It is pretty slow though.

kmackay avatar Jun 09 '16 01:06 kmackay

Ahh! That worked beautifully. You are right, it is a tad slow. It will do what I need though. If I'd like to implement a faster mod function, do you have any suggestions where to look?

Seechay avatar Jun 09 '16 13:06 Seechay

A cursory search found this: https://eprint.iacr.org/2014/040.pdf

kmackay avatar Jun 09 '16 15:06 kmackay

Hello Seechay,

I am also working on brainpool256 support. can you provide reference code if you have any. Thanks for your help in advance.

vikasshah1991 avatar Aug 17 '16 08:08 vikasshah1991

The "twisted" Brainpool curves have a=-1 (mod p) so would be much easier to integrate. The untwisted curves were generated (IMHO) only as part of the provable provance (nothing up their sleeve) and the twisted versions are equivelent in security.

nymble avatar Mar 08 '18 19:03 nymble