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

Modify the way hashG1 is computed #7

Open
jstuczyn opened this issue Oct 8, 2018 · 1 comment
Open

Modify the way hashG1 is computed #7

jstuczyn opened this issue Oct 8, 2018 · 1 comment

Comments

@jstuczyn
Copy link

jstuczyn commented Oct 8, 2018

I'm trying to ensure my implementation of Coconut in Go is consistent and fully compatible (if used on BN254 curve) with the one created in Python, however, I've stumbled upon an implementation issue that goes all the way to bplib, such that I can't modify my own code to make it compatible.

Basically the issue comes from the ways openSSL and amcl recover a BigNum from bytes. OpenSSL (and by extension bplib), from what I've figured, allows an arbitrary long array of bytes and creates an equally long Bn, while amcl ignores chunks that are beyond number of bytes used by a particular curve (in the case of BN254, 32bytes). And so it would be ideal if they would always be given such inputs that they would produce same results.

The problematic code in question is the following: https://github.com/gdanezis/bplib/blob/master/bplib/bp.py#L141

while ret == 0:
    xhash = sha512(xhash).digest()
    x = Bn.from_binary(xhash) % self.p
    ret = _C.G1_ELEM_set_compressed_coordinates(self.bpg, pt.elem, x.bn, y, _FFI.NULL)

SHA512 by definition produces a 64byte length result, which when converted into a BigNum produces the described issue as amcl only considers first 32bytes of the resultant hash.

The two solutions that I've tested to be fully working (for both implementations) were to either introduce a flag to set the hash algorithm used or to keep SHA512 but truncate the result to however many bytes particular curve uses before converting it to BigNum.:

Solution 1:

while ret == 0:
    if SHA_FLAG == SHA256:
        xhash = sha256(xhash).digest()
    elif SHA_FLAG == SHA386:
        xhash = sha386(xhash).digest()
    else:
        xhash = sha512(xhash).digest()
    x = Bn.from_binary(xhash) % self.p
    ret = _C.G1_ELEM_set_compressed_coordinates(self.bpg, pt.elem, x.bn, y, _FFI.NULL)

Solution 2 (with additional C binding):

while ret == 0:
    xhash = sha512(xhash).digest()
    xhash = xhash[:num_bytes]
    x = Bn.from_binary(xhash) % self.p
    ret = _C.G1_ELEM_set_compressed_coordinates(self.bpg, pt.elem, x.bn, y, _FFI.NULL)

note that number of bytes used by a curve is stored in BN_BYTES constant (or via BN_num_bytes() function), which would probably require an additional C binding to obtain.

Solution 2 (without any more bindings):

while ret == 0:
    xhash = sha512(xhash).digest()
    if self.nid == NID_fp254bnb: # basically hardcoding the lenghts
        xhash_trunc = xhash[:32]
    elif: 
        ...
    x = Bn.from_binary(xhash_trunc) % self.p
    ret = _C.G1_ELEM_set_compressed_coordinates(self.bpg, pt.elem, x.bn, y, _FFI.NULL)

Do you think it would be possible to introduce either of those changes?

@gdanezis
Copy link
Owner

Nice catch -- do you want to send me a patch / pull request? I prefer the python only solution 2.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants