Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HW accelerated tagged_sha256 #35

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions ngu/hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,41 @@ STATIC const mp_obj_type_t modngu_hash_sha512_type = {
.locals_dict = (void *)&modngu_hash_sha512_locals_dict,
};

// Tagged sha256 = SHA256(SHA256(tag)||SHA256(tag)||msg)
STATIC mp_obj_t hm_tagged_sha256(size_t n_args, const mp_obj_t *args) {
mp_obj_t tag = args[0];
mp_obj_t msg = args[1];
bool is_tag_hashed = false;
if(n_args > 2) {
is_tag_hashed = mp_obj_is_true(args[2]);
}
mp_buffer_info_t t;
mp_buffer_info_t m;
mp_get_buffer_raise(tag, &t, MP_BUFFER_READ);
mp_get_buffer_raise(msg, &m, MP_BUFFER_READ);

uint8_t s0[32];
if (is_tag_hashed) {
if (t.len != 32) {
mp_raise_ValueError(MP_ERROR_TEXT("len tag_hash != 32"));
}
memcpy(s0, t.buf, 32);
} else {
sha256_single(t.buf, t.len, s0);
}
int ser_len = 64 + m.len;
uint8_t ser[ser_len];
memcpy(ser, s0, 32);
memcpy(ser + 32, s0, 32);
memcpy(ser + 64, m.buf, m.len);

vstr_t res;
vstr_init_len(&res, 32);
sha256_single(ser, ser_len, (uint8_t *)res.buf);

return mp_obj_new_str_from_vstr(&mp_type_bytes, &res);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(hm_tagged_sha256_obj,2,3, hm_tagged_sha256);

// Double sha256 = sha256(sha256('foo').digest()).digest() ... in one step
STATIC mp_obj_t hm_double_sha256(mp_obj_t arg) {
Expand Down Expand Up @@ -258,6 +293,7 @@ STATIC const mp_rom_map_elem_t mp_module_hash_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_ripemd160), MP_ROM_PTR(&hm_single_ripemd160_obj) },
{ MP_ROM_QSTR(MP_QSTR_sha256s), MP_ROM_PTR(&hm_single_sha256_obj) },
{ MP_ROM_QSTR(MP_QSTR_sha256d), MP_ROM_PTR(&hm_double_sha256_obj) },
{ MP_ROM_QSTR(MP_QSTR_sha256t), MP_ROM_PTR(&hm_tagged_sha256_obj) },
{ MP_ROM_QSTR(MP_QSTR_hash160), MP_ROM_PTR(&hm_hash160_obj) },
{ MP_ROM_QSTR(MP_QSTR_pbkdf2_sha512), MP_ROM_PTR(&pbkdf2_sha512_obj) },

Expand Down
22 changes: 0 additions & 22 deletions ngu/k1.c
Original file line number Diff line number Diff line change
Expand Up @@ -368,27 +368,6 @@ STATIC mp_obj_t s_verify_schnorr(mp_obj_t compact_sig_in, mp_obj_t digest_in, mp
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(s_verify_schnorr_obj, s_verify_schnorr);

STATIC mp_obj_t s_tagged_sha256(mp_obj_t tag_in, mp_obj_t msg_in) {
// Compute a tagged hash as defined in BIP-340.
//
// This is useful for creating a message hash and achieving domain separation
// through an application-specific tag. This function returns
// SHA256(SHA256(tag)||SHA256(tag)||msg).
mp_buffer_info_t tag;
mp_get_buffer_raise(tag_in, &tag, MP_BUFFER_READ);
mp_buffer_info_t msg;
mp_get_buffer_raise(msg_in, &msg, MP_BUFFER_READ);
vstr_t rv;
vstr_init_len(&rv, 32);

int ok = secp256k1_tagged_sha256(lib_ctx, (uint8_t *)rv.buf, tag.buf, tag.len, msg.buf, msg.len);
if (ok != 1) {
mp_raise_ValueError(MP_ERROR_TEXT("secp256k1_tagged_sha256 invalid arguments"));
}
return mp_obj_new_str_from_vstr(&mp_type_bytes, &rv);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(s_tagged_sha256_obj, s_tagged_sha256);


STATIC mp_obj_t s_sign_schnorr(mp_obj_t privkey_in, mp_obj_t digest_in, mp_obj_t aux_rand_in)
{
Expand Down Expand Up @@ -679,7 +658,6 @@ STATIC const mp_rom_map_elem_t globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_sign), MP_ROM_PTR(&s_sign_obj) },
{ MP_ROM_QSTR(MP_QSTR_sign_schnorr), MP_ROM_PTR(&s_sign_schnorr_obj) },
{ MP_ROM_QSTR(MP_QSTR_verify_schnorr), MP_ROM_PTR(&s_verify_schnorr_obj) },
{ MP_ROM_QSTR(MP_QSTR_tagged_sha256), MP_ROM_PTR(&s_tagged_sha256_obj) },
{ MP_ROM_QSTR(MP_QSTR_ctx_rnd), MP_ROM_PTR(&s_ctx_rnd_obj) },
};

Expand Down
14 changes: 14 additions & 0 deletions ngu/ngu_tests/test_hash.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,20 @@ def expect2(func, msg, dig):
expect2(lambda x: sha512(x).digest(), abc,
'ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f')

# test custom implementation of tagged sha256 (with midstate)
for tag, msg in [(b"BIP0XYZ/nonce", b"a" * 92), (b"a", b"b")]:
tag_hash = ngu.hash.sha256s(tag)
assert ngu.hash.sha256s(ngu.hash.sha256s(tag) + ngu.hash.sha256s(tag) + msg) \
== ngu.hash.sha256t(tag, msg) \
== ngu.hash.sha256t(tag_hash, msg, True)

# passing already hashed tag value - len must be 32 bytes
try:
ngu.hash.sha256t(b"a" * 20, b"a" * 96, True)
assert False
except ValueError:
pass

except ImportError:
import hashlib
from binascii import b2a_hex, a2b_hex
Expand Down
6 changes: 1 addition & 5 deletions ngu/ngu_tests/test_k1.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,6 @@
pubkey3 = sig3.verify_recover(md)
assert pubkey3 != pubkey

assert ngu.secp256k1.tagged_sha256(b"tag", b"msg") == ngu.hash.sha256s(
ngu.hash.sha256s(b"tag") + ngu.hash.sha256s(b"tag") + b"msg"
)

# keypair tweaking
kp = ngu.secp256k1.keypair()
tweak32 = ngu.random.bytes(32)
Expand Down Expand Up @@ -130,7 +126,7 @@
assert xonly_pub_clone.to_bytes() == xonly_pub_bytes
# random msg
msg = ngu.random.bytes(32)
msg_hash = ngu.secp256k1.tagged_sha256(b"ngu_tests", msg)
msg_hash = ngu.hash.sha256t(b"ngu_tests", msg)
aux_rand = ngu.random.bytes(32)
sig_kp = ngu.secp256k1.sign_schnorr(kp, msg_hash, aux_rand)
sig_raw = ngu.secp256k1.sign_schnorr(kp.privkey(), msg_hash, aux_rand)
Expand Down