You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

201 lines
7.7 KiB

/**********************************************************************
* Copyright (c) 2014, 2015 Gregory Maxwell *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef _SECP256K1_BORROMEAN_IMPL_H_
#define _SECP256K1_BORROMEAN_IMPL_H_
#include "scalar.h"
#include "field.h"
#include "group.h"
#include "ecmult.h"
#include "ecmult_gen.h"
#include "borromean.h"
#include <limits.h>
#ifdef WORDS_BIGENDIAN
#define BE32(x) (x)
#else
#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24))
#endif
SECP256K1_INLINE static void secp256k1_borromean_hash(unsigned char *hash, const unsigned char *m, int mlen, const unsigned char *e, int elen,
int ridx, int eidx) {
uint32_t ring;
uint32_t epos;
secp256k1_sha256_t sha256_en;
secp256k1_sha256_initialize(&sha256_en);
ring = BE32((uint32_t)ridx);
epos = BE32((uint32_t)eidx);
secp256k1_sha256_write(&sha256_en, e, elen);
secp256k1_sha256_write(&sha256_en, m, mlen);
secp256k1_sha256_write(&sha256_en, (unsigned char*)&ring, 4);
secp256k1_sha256_write(&sha256_en, (unsigned char*)&epos, 4);
secp256k1_sha256_finalize(&sha256_en, hash);
}
/** "Borromean" ring signature.
* Verifies nrings concurrent ring signatures all sharing a challenge value.
* Signature is one s value per pubkey and a hash.
* Verification equation:
* | m = H(P_{0..}||message) (Message must contain pubkeys or a pubkey commitment)
* | For each ring i:
* | | en = to_scalar(H(e0||m||i||0))
* | | For each pubkey j:
* | | | r = s_i_j G + en * P_i_j
* | | | e = H(r||m||i||j)
* | | | en = to_scalar(e)
* | | r_i = r
* | return e_0 ==== H(r_{0..i}||m)
*/
int secp256k1_borromean_verify(const secp256k1_ecmult_context_t* ecmult_ctx, secp256k1_scalar_t *evalues, const unsigned char *e0,
const secp256k1_scalar_t *s, const secp256k1_gej_t *pubs, const int *rsizes, int nrings, const unsigned char *m, int mlen) {
secp256k1_gej_t rgej;
secp256k1_ge_t rge;
secp256k1_scalar_t ens;
secp256k1_sha256_t sha256_e0;
unsigned char tmp[33];
int i;
int j;
int count;
int size;
int overflow;
VERIFY_CHECK(ecmult_ctx != NULL);
VERIFY_CHECK(e0 != NULL);
VERIFY_CHECK(s != NULL);
VERIFY_CHECK(pubs != NULL);
VERIFY_CHECK(rsizes != NULL);
VERIFY_CHECK(nrings > 0);
VERIFY_CHECK(m != NULL);
count = 0;
secp256k1_sha256_initialize(&sha256_e0);
for (i = 0; i < nrings; i++) {
VERIFY_CHECK(INT_MAX - count > rsizes[i]);
secp256k1_borromean_hash(tmp, m, mlen, e0, 32, i, 0);
secp256k1_scalar_set_b32(&ens, tmp, &overflow);
for (j = 0; j < rsizes[i]; j++) {
if (overflow || secp256k1_scalar_is_zero(&s[count]) || secp256k1_scalar_is_zero(&ens) || secp256k1_gej_is_infinity(&pubs[count])) {
return 0;
}
if (evalues) {
/*If requested, save the challenges for proof rewind.*/
evalues[count] = ens;
}
secp256k1_ecmult(ecmult_ctx, &rgej, &pubs[count], &ens, &s[count]);
if (secp256k1_gej_is_infinity(&rgej)) {
return 0;
}
/* OPT: loop can be hoisted and split to use batch inversion across all the rings; this would make it much faster. */
secp256k1_ge_set_gej_var(&rge, &rgej);
secp256k1_eckey_pubkey_serialize(&rge, tmp, &size, 1);
if (j != rsizes[i] - 1) {
secp256k1_borromean_hash(tmp, m, mlen, tmp, 33, i, j + 1);
secp256k1_scalar_set_b32(&ens, tmp, &overflow);
} else {
secp256k1_sha256_write(&sha256_e0, tmp, size);
}
count++;
}
}
secp256k1_sha256_write(&sha256_e0, m, mlen);
secp256k1_sha256_finalize(&sha256_e0, tmp);
return memcmp(e0, tmp, 32) == 0;
}
int secp256k1_borromean_sign(const secp256k1_ecmult_context_t* ecmult_ctx, const secp256k1_ecmult_gen_context_t *ecmult_gen_ctx,
unsigned char *e0, secp256k1_scalar_t *s, const secp256k1_gej_t *pubs, const secp256k1_scalar_t *k, const secp256k1_scalar_t *sec,
const int *rsizes, const int *secidx, int nrings, const unsigned char *m, int mlen) {
secp256k1_gej_t rgej;
secp256k1_ge_t rge;
secp256k1_scalar_t ens;
secp256k1_sha256_t sha256_e0;
unsigned char tmp[33];
int i;
int j;
int count;
int size;
int overflow;
VERIFY_CHECK(ecmult_ctx != NULL);
VERIFY_CHECK(ecmult_gen_ctx != NULL);
VERIFY_CHECK(e0 != NULL);
VERIFY_CHECK(s != NULL);
VERIFY_CHECK(pubs != NULL);
VERIFY_CHECK(k != NULL);
VERIFY_CHECK(sec != NULL);
VERIFY_CHECK(rsizes != NULL);
VERIFY_CHECK(secidx != NULL);
VERIFY_CHECK(nrings > 0);
VERIFY_CHECK(m != NULL);
secp256k1_sha256_initialize(&sha256_e0);
count = 0;
for (i = 0; i < nrings; i++) {
VERIFY_CHECK(INT_MAX - count > rsizes[i]);
secp256k1_ecmult_gen(ecmult_gen_ctx, &rgej, &k[i]);
secp256k1_ge_set_gej(&rge, &rgej);
if (secp256k1_gej_is_infinity(&rgej)) {
return 0;
}
secp256k1_eckey_pubkey_serialize(&rge, tmp, &size, 1);
for (j = secidx[i] + 1; j < rsizes[i]; j++) {
secp256k1_borromean_hash(tmp, m, mlen, tmp, 33, i, j);
secp256k1_scalar_set_b32(&ens, tmp, &overflow);
if (overflow || secp256k1_scalar_is_zero(&ens)) {
return 0;
}
/** The signing algorithm as a whole is not memory uniform so there is likely a cache sidechannel that
* leaks which members are non-forgeries. That the forgeries themselves are variable time may leave
* an additional privacy impacting timing side-channel, but not a key loss one.
*/
secp256k1_ecmult(ecmult_ctx, &rgej, &pubs[count + j], &ens, &s[count + j]);
if (secp256k1_gej_is_infinity(&rgej)) {
return 0;
}
secp256k1_ge_set_gej_var(&rge, &rgej);
secp256k1_eckey_pubkey_serialize(&rge, tmp, &size, 1);
}
secp256k1_sha256_write(&sha256_e0, tmp, size);
count += rsizes[i];
}
secp256k1_sha256_write(&sha256_e0, m, mlen);
secp256k1_sha256_finalize(&sha256_e0, e0);
count = 0;
for (i = 0; i < nrings; i++) {
VERIFY_CHECK(INT_MAX - count > rsizes[i]);
secp256k1_borromean_hash(tmp, m, mlen, e0, 32, i, 0);
secp256k1_scalar_set_b32(&ens, tmp, &overflow);
if (overflow || secp256k1_scalar_is_zero(&ens)) {
return 0;
}
for (j = 0; j < secidx[i]; j++) {
secp256k1_ecmult(ecmult_ctx, &rgej, &pubs[count + j], &ens, &s[count + j]);
if (secp256k1_gej_is_infinity(&rgej)) {
return 0;
}
secp256k1_ge_set_gej_var(&rge, &rgej);
secp256k1_eckey_pubkey_serialize(&rge, tmp, &size, 1);
secp256k1_borromean_hash(tmp, m, mlen, tmp, 33, i, j + 1);
secp256k1_scalar_set_b32(&ens, tmp, &overflow);
if (overflow || secp256k1_scalar_is_zero(&ens)) {
return 0;
}
}
secp256k1_scalar_mul(&s[count + j], &ens, &sec[i]);
secp256k1_scalar_negate(&s[count + j], &s[count + j]);
secp256k1_scalar_add(&s[count + j], &s[count + j], &k[i]);
if (secp256k1_scalar_is_zero(&s[count + j])) {
return 0;
}
count += rsizes[i];
}
secp256k1_scalar_clear(&ens);
secp256k1_ge_clear(&rge);
secp256k1_gej_clear(&rgej);
memset(tmp, 0, 33);
return 1;
}
#endif