Alien-libsecp256k1
view release on metacpan or search on metacpan
libsecp256k1/src/modules/ellswift/main_impl.h view on Meta::CPAN
/* Let v = (r/s-u)/2. */
secp256k1_fe_inv_var(&v, &s); /* v = 1/s [no div by 0] */
secp256k1_fe_mul(&v, &v, &r); /* v = r/s */
secp256k1_fe_add(&v, &m); /* v = r/s-u */
secp256k1_fe_half(&v); /* v = (r/s-u)/2 */
}
/* Let w = sqrt(s). */
ret = secp256k1_fe_sqrt(&m, &s); /* m = sqrt(s) = w */
VERIFY_CHECK(ret);
/* Return logic. */
if ((c & 5) == 0 || (c & 5) == 5) {
secp256k1_fe_negate(&m, &m, 1); /* m = -w */
}
/* Now m = {-w if c&5=0 or c&5=5; w otherwise}. */
secp256k1_fe_mul(&u, &u, c&1 ? &secp256k1_ellswift_c4 : &secp256k1_ellswift_c3);
/* u = {c4 if c&1=1; c3 otherwise}*u */
secp256k1_fe_add(&u, &v); /* u = {c4 if c&1=1; c3 otherwise}*u + v */
secp256k1_fe_mul(t, &m, &u);
return 1;
}
/** Use SHA256 as a PRNG, returning SHA256(hasher || cnt).
*
* hasher is a SHA256 object to which an incrementing 4-byte counter is written to generate randomness.
* Writing 13 bytes (4 bytes for counter, plus 9 bytes for the SHA256 padding) cannot cross a
* 64-byte block size boundary (to make sure it only triggers a single SHA256 compression). */
static void secp256k1_ellswift_prng(unsigned char* out32, const secp256k1_sha256 *hasher, uint32_t cnt) {
secp256k1_sha256 hash = *hasher;
unsigned char buf4[4];
#ifdef VERIFY
size_t blocks = hash.bytes >> 6;
#endif
buf4[0] = cnt;
buf4[1] = cnt >> 8;
buf4[2] = cnt >> 16;
buf4[3] = cnt >> 24;
secp256k1_sha256_write(&hash, buf4, 4);
secp256k1_sha256_finalize(&hash, out32);
/* Writing and finalizing together should trigger exactly one SHA256 compression. */
VERIFY_CHECK(((hash.bytes) >> 6) == (blocks + 1));
}
/** Find an ElligatorSwift encoding (u, t) for X coordinate x, and random Y coordinate.
*
* u32 is the 32-byte big endian encoding of u; t is the output field element t that still
* needs encoding.
*
* hasher is a hasher in the secp256k1_ellswift_prng sense, with the same restrictions. */
static void secp256k1_ellswift_xelligatorswift_var(unsigned char *u32, secp256k1_fe *t, const secp256k1_fe *x, const secp256k1_sha256 *hasher) {
/* Pool of 3-bit branch values. */
unsigned char branch_hash[32];
/* Number of 3-bit values in branch_hash left. */
int branches_left = 0;
/* Field elements u and branch values are extracted from RNG based on hasher for consecutive
* values of cnt. cnt==0 is first used to populate a pool of 64 4-bit branch values. The 64
* cnt values that follow are used to generate field elements u. cnt==65 (and multiples
* thereof) are used to repopulate the pool and start over, if that were ever necessary.
* On average, 4 iterations are needed. */
uint32_t cnt = 0;
while (1) {
int branch;
secp256k1_fe u;
/* If the pool of branch values is empty, populate it. */
if (branches_left == 0) {
secp256k1_ellswift_prng(branch_hash, hasher, cnt++);
branches_left = 64;
}
/* Take a 3-bit branch value from the branch pool (top bit is discarded). */
--branches_left;
branch = (branch_hash[branches_left >> 1] >> ((branches_left & 1) << 2)) & 7;
/* Compute a new u value by hashing. */
secp256k1_ellswift_prng(u32, hasher, cnt++);
/* overflow is not a problem (we prefer uniform u32 over uniform u). */
secp256k1_fe_set_b32_mod(&u, u32);
/* Since u is the output of a hash, it should practically never be 0. We could apply the
* u=0 to u=1 correction here too to deal with that case still, but it's such a low
* probability event that we do not bother. */
VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(&u));
/* Find a remainder t, and return it if found. */
if (EXPECT(secp256k1_ellswift_xswiftec_inv_var(t, x, &u, branch), 0)) break;
}
}
/** Find an ElligatorSwift encoding (u, t) for point P.
*
* This is similar secp256k1_ellswift_xelligatorswift_var, except it takes a full group element p
* as input, and returns an encoding that matches the provided Y coordinate rather than a random
* one.
*/
static void secp256k1_ellswift_elligatorswift_var(unsigned char *u32, secp256k1_fe *t, const secp256k1_ge *p, const secp256k1_sha256 *hasher) {
secp256k1_ellswift_xelligatorswift_var(u32, t, &p->x, hasher);
secp256k1_fe_normalize_var(t);
if (secp256k1_fe_is_odd(t) != secp256k1_fe_is_odd(&p->y)) {
secp256k1_fe_negate(t, t, 1);
secp256k1_fe_normalize_var(t);
}
}
/** Set hash state to the BIP340 tagged hash midstate for "secp256k1_ellswift_encode". */
static void secp256k1_ellswift_sha256_init_encode(secp256k1_sha256* hash) {
secp256k1_sha256_initialize(hash);
hash->s[0] = 0xd1a6524bul;
hash->s[1] = 0x028594b3ul;
hash->s[2] = 0x96e42f4eul;
hash->s[3] = 0x1037a177ul;
hash->s[4] = 0x1b8fcb8bul;
hash->s[5] = 0x56023885ul;
hash->s[6] = 0x2560ede1ul;
hash->s[7] = 0xd626b715ul;
hash->bytes = 64;
}
int secp256k1_ellswift_encode(const secp256k1_context *ctx, unsigned char *ell64, const secp256k1_pubkey *pubkey, const unsigned char *rnd32) {
secp256k1_ge p;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(ell64 != NULL);
( run in 0.798 second using v1.01-cache-2.11-cpan-71847e10f99 )