Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
336 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
""" | ||
Implementation of proofs for checking commitment equality and if a commitment is a square ("Efficient Proofs that a | ||
Committed NumberLies in an Interval" by F. Boudot). | ||
Modified for use with range proofs ("An efficient range proof scheme." by K. Peng and F. Bao). | ||
""" | ||
from __future__ import absolute_import, division | ||
|
||
from binascii import hexlify | ||
from math import ceil, log | ||
from os import urandom | ||
from struct import pack, unpack | ||
|
||
from ..primitives.attestation import sha256_as_int | ||
from ..primitives.structs import ipack, iunpack | ||
from ..primitives.value import FP2Value | ||
|
||
|
||
def secure_randint(nmin, nmax): | ||
normalized_range = nmax - nmin | ||
n = int(ceil(log(normalized_range, 2)/8.0)) | ||
rbytes_int = int(hexlify(urandom(n)), 16) | ||
return nmin + (rbytes_int % normalized_range) | ||
|
||
|
||
def _sipack(*n): | ||
if len(n) > 8: | ||
raise RuntimeError("More than 8 values specified to _sipack") | ||
sign_byte = 0 | ||
packed = b'' | ||
for i in n: | ||
sign_byte = sign_byte << 1 | ||
sign_byte |= 1 if i < 0 else 0 | ||
packed = ipack(-i if i < 0 else i) + packed | ||
return pack(">B", sign_byte) + packed | ||
|
||
|
||
def _siunpack(buf, amount): | ||
rem = buf[1:] | ||
nums = [] | ||
sign_byte, = unpack(">B", buf[0:1]) | ||
while rem and len(nums) < amount: | ||
unpacked, rem = iunpack(rem) | ||
negative = sign_byte & 0x01 | ||
sign_byte = sign_byte >> 1 | ||
nums.append(-unpacked if negative else unpacked) | ||
return reversed(nums) | ||
|
||
|
||
class EL(object): | ||
|
||
def __init__(self, c, D, D1, D2): | ||
self.c = c | ||
self.D = D | ||
self.D1 = D1 | ||
self.D2 = D2 | ||
|
||
@classmethod | ||
def create(cls, x, r1, r2, g1, h1, g2, h2, b, bitspace, t=80, l=40): | ||
maxrange_w = 2^(l+t) * b - 1 | ||
maxrange_n = 2^(l+t+bitspace) * g1.mod - 1 | ||
w = secure_randint(1, maxrange_w) | ||
n1 = secure_randint(1, maxrange_n) | ||
n2 = secure_randint(1, maxrange_n) | ||
W1 = g1.intpow(w) * h1.intpow(n1) | ||
W2 = g2.intpow(w) * h2.intpow(n2) | ||
cW1 = (W1.wp_nominator() * W1.wp_denom_inverse()).normalize() | ||
cW2 = (W2.wp_nominator() * W2.wp_denom_inverse()).normalize() | ||
|
||
c = sha256_as_int(str(cW1.a) + str(cW1.b) + str(cW2.a) + str(cW2.b)) | ||
D = w + c * x | ||
D1 = n1 + c * r1 | ||
D2 = n2 + c * r2 | ||
return cls(c, D, D1, D2) | ||
|
||
def check(self, g1, h1, g2, h2, y1, y2): | ||
if self.D1 >= 0: | ||
cW1 = g1.intpow(self.D) * h1.intpow(self.D1) * y1.intpow(self.c).inverse() | ||
else: | ||
cW1 = g1.intpow(self.D) * h1.intpow(-self.D1).inverse() * y1.intpow(self.c).inverse() | ||
if self.D2 >= 0: | ||
cW2 = g2.intpow(self.D) * h2.intpow(self.D2) * y2.intpow(self.c).inverse() | ||
else: | ||
cW2 = g2.intpow(self.D) * h2.intpow(-self.D2).inverse() * y2.intpow(self.c).inverse() | ||
cW1 = (cW1.wp_nominator() * cW1.wp_denom_inverse()).normalize() | ||
cW2 = (cW2.wp_nominator() * cW2.wp_denom_inverse()).normalize() | ||
|
||
return self.c == sha256_as_int(str(cW1.a) + str(cW1.b) + str(cW2.a) + str(cW2.b)) | ||
|
||
def serialize(self): | ||
return _sipack(self.c, self.D, self.D1, self.D2) | ||
|
||
@classmethod | ||
def unserialize(cls, s): | ||
return cls(*_siunpack(s, 4)) | ||
|
||
def __eq__(self, other): | ||
if not isinstance(other, EL): | ||
return False | ||
return (self.c == other.c) and (self.D == other.D) and (self.D1 == other.D1) and (self.D2 == other.D2) | ||
|
||
def __hash__(self): | ||
return 6976 | ||
|
||
def __str__(self): | ||
return 'EL<%d,%d,%d,%d>' % (self.c, self.D, self.D1, self.D2) | ||
|
||
|
||
class SQR(object): | ||
|
||
def __init__(self, F, el): | ||
self.F = F | ||
self.el = el | ||
|
||
@classmethod | ||
def create(cls, x, r1, g, h, b, bitspace): | ||
r2 = secure_randint(-2^bitspace * g.mod + 1, 2^bitspace * g.mod -1) | ||
if r2 >= 0: | ||
F = g.intpow(x) * h.intpow(r2) | ||
else: | ||
F = g.intpow(x) * h.intpow(-r2).inverse() | ||
r3 = r1 - r2 * x | ||
return cls(F, EL.create(x, r2, r3, g, h, F, h, b, bitspace)) | ||
|
||
def check(self, g, h, y): | ||
return self.el.check(g, h, self.F, h, self.F, y) | ||
|
||
def serialize(self): | ||
norm_f = self.F.normalize() | ||
min_f = norm_f.wp_nominator() * norm_f.wp_denom_inverse() | ||
return ipack(min_f.mod) + ipack(min_f.a) + ipack(min_f.b) + self.el.serialize() | ||
|
||
@classmethod | ||
def unserialize(cls, s): | ||
rem = s | ||
mod, rem = iunpack(rem) | ||
Fa, rem = iunpack(rem) | ||
Fb, rem = iunpack(rem) | ||
el = EL.unserialize(rem) | ||
return cls(FP2Value(mod, Fa, Fb), el) | ||
|
||
def __eq__(self, other): | ||
if not isinstance(other, SQR): | ||
return False | ||
return (self.F == other.F) and (self.el == other.el) | ||
|
||
def __hash__(self): | ||
return 838182 | ||
|
||
def __str__(self): | ||
return 'SQR<%s,%s>' % (str(self.F), str(self.el)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
from hashlib import sha256, sha512 | ||
|
||
|
||
def sha512_as_int(value): | ||
""" | ||
Convert a SHA512 hash to an integer. | ||
""" | ||
out = 0 | ||
hashed = sha512(value).digest() | ||
for i in range(len(hashed)): | ||
out <<= 8 | ||
out |= ord(hashed[i:i + 1]) | ||
return out | ||
|
||
|
||
def sha256_as_int(value): | ||
""" | ||
Convert a SHA256 hash to an integer. | ||
""" | ||
out = 0 | ||
hashed = sha256(value).digest() | ||
for i in range(len(hashed)): | ||
out <<= 8 | ||
out |= ord(hashed[i:i + 1]) | ||
return out | ||
|
||
|
||
def sha256_4_as_int(value): | ||
""" | ||
Convert a SHA256 4 byte hash to an integer. | ||
""" | ||
out = 0 | ||
hashed = sha256(value).digest()[:4] | ||
for i in range(len(hashed)): | ||
out <<= 8 | ||
out |= ord(hashed[i:i + 1]) | ||
return out |
Oops, something went wrong.