Cleanup pyUmbral codebase and resolve various issues#127
Cleanup pyUmbral codebase and resolve various issues#127tuxxy merged 10 commits intonucypher:masterfrom
Conversation
64df4cc to
cdcf50f
Compare
Use BN_cmp instead of BN_is_zero since it's not exposed Add EC_POINT operations to openssl module
Change all references from BigNum to CurveBN
af358fb to
b8af78a
Compare
CorrectnessProof. Fix syntax error
cygnusv
left a comment
There was a problem hiding this comment.
Good work, tuxxy :) Just some minor comments, apart from the remaining issue of CurveBN vs BigNum (which we decided to leave it as that for the moment)
| def test_private_key_serialization(random_ec_bignum1): | ||
| priv_key = random_ec_bignum1 | ||
| def test_private_key_serialization(random_ec_curvebn1): | ||
| priv_key = random_ec_curvebn1 |
There was a problem hiding this comment.
random_ec_curvebn1 reads strange. The c in ec is already "curve", so perhaps you should drop ec from the name. Apart from that – and I don't want to add fuel to the fire – I have to say I don't see immediately that curvebn1 is a BigNum, since the bn bit doesn't stand out. Perhaps random_curve_bn1?
There was a problem hiding this comment.
Yeah, I noticed this when I was refactoring it. I can change it now, or when I pull CurveBN out later. Is there a preference?
There was a problem hiding this comment.
This also refactors the pytest fixtures, if we change it too.
| def check_bignum_ctypes(*bignums): | ||
| for bn in bignums: | ||
| def check_curvebn_ctypes(*curvebns): | ||
| for bn in curvebns: |
There was a problem hiding this comment.
There's definitely an issue when CurveBN is all in lowercase...
umbral/curvebn.py
Outdated
| class CurveBN(object): | ||
| """ | ||
| Represents an OpenSSL BIGNUM except more Pythonic | ||
| Represents an OpenSSL Bignum modulo the order of a curve. |
There was a problem hiding this comment.
Perhaps we should add here that some operations only work modulo a prime
There was a problem hiding this comment.
Something like, "Some of these operations only work with a prime modulus, ie: a prime order curve."?
umbral/curvebn.py
Outdated
| def gen_rand(cls, curve: ec.EllipticCurve = None): | ||
| """ | ||
| Returns a BigNum object with a cryptographically secure BigNum based | ||
| Returns a CurveBN object with a cryptographically secure Bignum based |
There was a problem hiding this comment.
What's a Bignum here? you mean an OpenSSL BIGNUM or just a generic Big Number?
There was a problem hiding this comment.
Yeah, an OpenSSL BIGNUM.
| point_size = Point.get_size(curve) | ||
|
|
||
| return (bn_size * 4) + (point_size * 2) | ||
|
|
| """ | ||
| Returns the size (in bytes) of a CapsuleFrag given the curve. | ||
| If no curve is provided, it will use the default curve. | ||
| """ |
There was a problem hiding this comment.
We should mention that the CapsuleFrag contains a CorrectnessProof object of variable size, which is not considered in this method
umbral/openssl.py
Outdated
| ec_order = _get_ec_order_by_curve_nid(curve_nid) | ||
|
|
||
| # is_zero workaround since BN_is_zero is not exposed yet. | ||
| is_zero = backend._lib.BN_cmp(check_bn, backend._int_to_bn(0)) |
There was a problem hiding this comment.
is_zero should be greater_than_zero, right?
There was a problem hiding this comment.
I think below this line I check that is_zero == 1, right?
There was a problem hiding this comment.
What I mean is that the name is_zero doesn't make sense. You are not testing if check_bn == 0, but getting a comparison that returns -1, 0 or 1.
There was a problem hiding this comment.
🤔 I haven't thought about it like that. Given the comment above it, it should be enough to determine, but I think I might prefer bn_is_zero over greater_than_zero. Thoughts?
There was a problem hiding this comment.
Ah OK, I see what you mean here. You intention is to validate that check_bn is different than 0, but you end up comparing if check_bn > 0. Both are equivalent for BIGNUMs. In any case, the name is_zero doesn't seem very appropriate, because you end up testing if check_bn is greater than 0.
There was a problem hiding this comment.
Specifically, I am computing whether this statement is true:
0 < check_bn < ec_order
How do you mean that check_bn > 0 and is_zero are both equivalent?
umbral/point.py
Outdated
| If no curve is provided, it uses the default curve. | ||
| """ | ||
| curve = curve if curve is not None else default_curve() | ||
| return get_curve_keysize_bytes(curve) |
There was a problem hiding this comment.
Shouldn't the size be +1 for compressed points, in order to account for the 0x02 (or 0x03) byte at the beginning? Apart from that, there is no guarantee that the underlying field order has the same size than keys, although I can't think of a counterexample.
Maybe the comment should say that this is the size of a curve field element (e.g., a coordinate of the point), which is the size of a compressed point without the 0x02 byte
There was a problem hiding this comment.
Oh, yep. You're absolutely right, good catch.
umbral/utils.py
Outdated
| def get_curve_keysize_bytes(curve): | ||
| # We use the ceil operation to fit all bytes on curve sizes where eight is | ||
| # not evenly divisible. | ||
| return int(math.ceil(curve.key_size / 8.00)) |
There was a problem hiding this comment.
I think it's more common to see this expressed as (curve.key_size + 7) // 8
See e.g., https://github.com/pyca/cryptography/blob/master/src/cryptography/utils.py#L66
There was a problem hiding this comment.
It also seems to be much faster:
>>> timeit.repeat('for i in range(1024): (i+7)//8', number=10000, repeat=3)
[2.6502825429779477, 2.350924202008173, 2.525679681042675]
>>> timeit.repeat('for i in range(1024): int(math.ceil(i/8.00))', number=10000, setup='import math')
[6.333626834035385, 6.332635344995651, 6.0212114860187285]
Remove unused Capsule._contents
michwill
left a comment
There was a problem hiding this comment.
Read through, looks great! Of course, keeping in mind what we discussed today
| order = openssl._get_ec_order_by_curve_nid(curve_nid) | ||
|
|
||
| new_rand_bn = openssl._get_new_BN() | ||
| rand_res = backend._lib.BN_rand_range(new_rand_bn, order) |
There was a problem hiding this comment.
I just noticed that this allows the BN to be 0, which we don't want (we want it to be in the interval [1, q-1], for q the order of the curve). A better way would be to call BN_rand_range(new_rand_bn, q_minus_1) and then add 1 to the result. This ensures the resulting BN is in [1, q-1]
There was a problem hiding this comment.
BN_rand_range generates numbers where 0 <= RAND < Order.
So, it's still possible that a number can be generated as 0, but not as the actual order.
…ated bn is on curve; update CurveBN docstring
What this does:
BigNum(nowCurveBN) andPointto theopensslmodule and resolves the third TODO in Clean-up the codebase #119.BigNumtoCurveBNand resolves the first TODO in Clean-up the codebase #119.UmbralPublicKeyinUmbralPrivateKey.get_pubkey()? #121 by caching the public key onUmbralPrivateKey.get_sizeclassmethods toCurveBN,Point,KFrag,CapsuleFrag, andChallengeResponse.Capsule._attached_cfragsto a list.