예제 #1
0
int
goldilocks_verify (
    const uint8_t signature[GOLDI_SIGNATURE_BYTES],
    const uint8_t *message,
    uint64_t message_len,
    const struct goldilocks_public_key_t *pubkey
) {
    if (!goldilocks_check_init()) {
        return GOLDI_EUNINIT;
    }
    
    struct field_t pk;
    word_t s[GOLDI_FIELD_WORDS];
    
    mask_t succ = field_deserialize(&pk,pubkey->opaque);
    if (!succ) return GOLDI_EINVAL;
    
    succ = barrett_deserialize(s, &signature[GOLDI_FIELD_BYTES], &curve_prime_order);
    if (!succ) return GOLDI_EINVAL;
    
    word_t challenge[GOLDI_FIELD_WORDS];
    goldilocks_derive_challenge(challenge, pubkey->opaque, signature, message, message_len);
    
    struct field_t eph;
    struct tw_extensible_t pk_text;
    
    /* deserialize [nonce]G */
    succ = field_deserialize(&eph, signature);
    if (!succ) return GOLDI_EINVAL;
    
    succ = deserialize_and_twist_approx(&pk_text, &sqrt_d_minus_1, &pk);
    if (!succ) return GOLDI_EINVAL;
    
    linear_combo_var_fixed_vt( &pk_text,
        challenge, GOLDI_SCALAR_BITS,
        s, GOLDI_SCALAR_BITS,
        goldilocks_global.wnafs, WNAF_PRECMP_BITS );
    
    untwist_and_double_and_serialize( &pk, &pk_text );
    field_sub(&eph, &eph, &pk);
    field_bias(&eph, 2);
    
    succ = field_is_zero(&eph);
    
    return succ ? 0 : GOLDI_EINVAL;
}
예제 #2
0
int
goldilocks_verify_precomputed (
    const uint8_t signature[GOLDI_SIGNATURE_BYTES],
    const uint8_t *message,
    uint64_t message_len,
    const struct goldilocks_precomputed_public_key_t *pubkey
) {
    if (!goldilocks_check_init()) {
        return GOLDI_EUNINIT;
    }

    word_t s[GOLDI_FIELD_WORDS];
    mask_t succ = barrett_deserialize(s, &signature[GOLDI_FIELD_BYTES], &curve_prime_order);
    if (!succ) return GOLDI_EINVAL;
    
    word_t challenge[GOLDI_FIELD_WORDS];
    goldilocks_derive_challenge(challenge, pubkey->pub.opaque, signature, message, message_len);
    
    struct field_t eph, pk;
    struct tw_extensible_t pk_text;
    
    /* deserialize [nonce]G */
    succ = field_deserialize(&eph, signature);
    if (!succ) return GOLDI_EINVAL;
        
    succ = linear_combo_combs_vt (
        &pk_text,
        challenge, GOLDI_SCALAR_BITS, &pubkey->table,
        s, GOLDI_SCALAR_BITS, &goldilocks_global.fixed_base
    );
    if (!succ) return GOLDI_EINVAL;
    
    untwist_and_double_and_serialize( &pk, &pk_text );
    field_sub(&eph, &eph, &pk);
    field_bias(&eph, 2);
    
    succ = field_is_zero(&eph);
    
    return succ ? 0 : GOLDI_EINVAL;
}
예제 #3
0
int
goldilocks_sign (
    uint8_t signature_out[GOLDI_SIGNATURE_BYTES],
    const uint8_t *message,
    uint64_t message_len,
    const struct goldilocks_private_key_t *privkey
) {
    if (!goldilocks_check_init()) {
        return GOLDI_EUNINIT;
    }

    /* challenge = H(pk, [nonceG], message). */
    word_t skw[GOLDI_FIELD_WORDS];
    mask_t succ = barrett_deserialize(skw,privkey->opaque,&curve_prime_order);
    if (!succ) {
        really_memset(skw,0,sizeof(skw));
        return GOLDI_ECORRUPT;
    }

    /* Derive a nonce.  TODO: use HMAC. FUTURE: factor. */
    unsigned char sha_out[SHA512_OUTPUT_BYTES];
    word_t tk[GOLDI_FIELD_WORDS];
    struct sha512_ctx_t ctx;
    sha512_init(&ctx);
    sha512_update(&ctx, (const unsigned char *)"signonce", 8);
    sha512_update(&ctx, &privkey->opaque[2*GOLDI_FIELD_BYTES], GOLDI_SYMKEY_BYTES);
    sha512_update(&ctx, message, message_len);
    sha512_update(&ctx, &privkey->opaque[2*GOLDI_FIELD_BYTES], GOLDI_SYMKEY_BYTES);
    sha512_final(&ctx, sha_out);
    barrett_deserialize_and_reduce(tk, sha_out, SHA512_OUTPUT_BYTES, &curve_prime_order);

    /* 4[nonce]G */
    uint8_t signature_tmp[GOLDI_FIELD_BYTES];
    struct tw_extensible_t exta;
    struct field_t gsk;
    scalarmul_fixed_base(&exta, tk, GOLDI_SCALAR_BITS, &goldilocks_global.fixed_base);
    double_tw_extensible(&exta);
    untwist_and_double_and_serialize(&gsk, &exta);
    field_serialize(signature_tmp, &gsk);

    word_t challenge[GOLDI_FIELD_WORDS];
    goldilocks_derive_challenge (
        challenge,
        &privkey->opaque[GOLDI_FIELD_BYTES],
        signature_tmp,
        message,
        message_len
    );

    /* reduce challenge and sub. */
    barrett_negate(challenge,GOLDI_FIELD_WORDS,&curve_prime_order);

    barrett_mac(
        tk,GOLDI_FIELD_WORDS,
        challenge,GOLDI_FIELD_WORDS,
        skw,GOLDI_FIELD_WORDS,
        &curve_prime_order
    );

    word_t carry = add_nr_ext_packed(tk,tk,GOLDI_FIELD_WORDS,tk,GOLDI_FIELD_WORDS,-1);
    barrett_reduce(tk,GOLDI_FIELD_WORDS,carry,&curve_prime_order);

    memcpy(signature_out, signature_tmp, GOLDI_FIELD_BYTES);
    barrett_serialize(signature_out+GOLDI_FIELD_BYTES, tk, GOLDI_FIELD_BYTES);
    really_memset((unsigned char *)tk,0,sizeof(tk));
    really_memset((unsigned char *)skw,0,sizeof(skw));
    really_memset((unsigned char *)challenge,0,sizeof(challenge));

    /* response = 2(nonce_secret - sk*challenge)
     * Nonce = 8[nonce_secret]*G
     * PK = 2[sk]*G, except doubled (TODO)
     * so [2] ( [response]G + 2[challenge]PK ) = Nonce
     */

    return 0;
}
예제 #4
0
static int
goldilocks_shared_secret_core (
    uint8_t shared[GOLDI_SHARED_SECRET_BYTES],
    const struct goldilocks_private_key_t *my_privkey,
    const struct goldilocks_public_key_t *your_pubkey,
    const struct goldilocks_precomputed_public_key_t *pre
) {
    /* This function doesn't actually need anything in goldilocks_global,
     * so it doesn't check init.
     */

    assert(GOLDI_SHARED_SECRET_BYTES == SHA512_OUTPUT_BYTES);

    word_t sk[GOLDI_FIELD_WORDS];
    struct field_t pk;

    mask_t succ = field_deserialize(&pk,your_pubkey->opaque), msucc = -1;

#ifdef EXPERIMENT_ECDH_STIR_IN_PUBKEYS
    struct field_t sum, prod;
    msucc &= field_deserialize(&sum,&my_privkey->opaque[GOLDI_FIELD_BYTES]);
    field_mul(&prod,&pk,&sum);
    field_add(&sum,&pk,&sum);
#endif

    msucc &= barrett_deserialize(sk,my_privkey->opaque,&curve_prime_order);

#if GOLDI_IMPLEMENT_PRECOMPUTED_KEYS
    if (pre) {
        struct tw_extensible_t tw;
        succ &= scalarmul_fixed_base(&tw, sk, GOLDI_SCALAR_BITS, &pre->table);
        untwist_and_double_and_serialize(&pk, &tw);
    } else {
        succ &= montgomery_ladder(&pk,&pk,sk,GOLDI_SCALAR_BITS,1);
    }
#else
    (void)pre;
    succ &= montgomery_ladder(&pk,&pk,sk,GOLDI_SCALAR_BITS,1);
#endif


    field_serialize(shared,&pk);

    /* obliterate records of our failure by adjusting with obliteration key */
    struct sha512_ctx_t ctx;
    sha512_init(&ctx);

#ifdef EXPERIMENT_ECDH_OBLITERATE_CT
    uint8_t oblit[GOLDI_DIVERSIFY_BYTES + GOLDI_SYMKEY_BYTES];
    unsigned i;
    for (i=0; i<GOLDI_DIVERSIFY_BYTES; i++) {
        oblit[i] = "noshared"[i] & ~(succ&msucc);
    }
    for (i=0; i<GOLDI_SYMKEY_BYTES; i++) {
        oblit[GOLDI_DIVERSIFY_BYTES+i] = my_privkey->opaque[2*GOLDI_FIELD_BYTES+i] & ~(succ&msucc);
    }
    sha512_update(&ctx, oblit, sizeof(oblit));
#endif

#ifdef EXPERIMENT_ECDH_STIR_IN_PUBKEYS
    /* stir in the sum and product of the pubkeys. */
    uint8_t a_pk[GOLDI_FIELD_BYTES];
    field_serialize(a_pk, &sum);
    sha512_update(&ctx, a_pk, GOLDI_FIELD_BYTES);
    field_serialize(a_pk, &prod);
    sha512_update(&ctx, a_pk, GOLDI_FIELD_BYTES);
#endif

    /* stir in the shared key and finish */
    sha512_update(&ctx, shared, GOLDI_FIELD_BYTES);
    sha512_final(&ctx, shared);

    return (GOLDI_ECORRUPT & ~msucc)
           | (GOLDI_EINVAL & msucc &~ succ)
           | (GOLDI_EOK & msucc & succ);
}