diff --git a/py_ecc/optimized_bn128/__init__.py b/py_ecc/optimized_bn128/__init__.py index c2f7bd7a..f22d647d 100644 --- a/py_ecc/optimized_bn128/__init__.py +++ b/py_ecc/optimized_bn128/__init__.py @@ -1,3 +1,4 @@ -from .optimized_field_elements import field_modulus, FQ, FQP, FQ2, FQ12 -from .optimized_curve import add, double, multiply, is_inf, is_on_curve, eq, neg, twist, b, b2, b12, curve_order, G1, G2, G12, normalize +from .optimized_field_elements import FQ, FQP, FQ2, FQ12 +from .optimized_curve import add, double, multiply, is_inf, is_on_curve, eq, neg, twist, b, b2, b12, curve_order, G1, normalize from .optimized_pairing import pairing, final_exponentiate +from .parameters import field_modulus diff --git a/py_ecc/optimized_bn128/optimized_curve.py b/py_ecc/optimized_bn128/optimized_curve.py index f8a872da..fd554ae5 100644 --- a/py_ecc/optimized_bn128/optimized_curve.py +++ b/py_ecc/optimized_bn128/optimized_curve.py @@ -1,6 +1,6 @@ -from .optimized_field_elements import FQ2, FQ12, field_modulus, FQ +from .optimized_field_elements import FQ2, FQ12, FQ -curve_order = 21888242871839275222246405745257275088548364400416034343698204186575808495617 +from .parameters import curve_order, field_modulus # Curve order should be prime assert pow(2, curve_order, curve_order) == 2 @@ -16,9 +16,6 @@ # Generator for curve over FQ G1 = (FQ(1), FQ(2), FQ(1)) -# Generator for twisted curve over FQ2 -G2 = (FQ2([10857046999023057135944570762232829481370756359578518086990519993285655852781, 11559732032986387107991004021392285783925812861821192530917403151452391805634]), - FQ2([8495653923123431417604973247489272438418190587263600148770280649306958101930, 4082367875863433681332203403145435568316851327593401208105741076214120093531]), FQ2.one()) # Check if a point is the point at infinity def is_inf(pt): @@ -31,9 +28,6 @@ def is_on_curve(pt, b): x, y, z = pt return y**2 * z - x**3 == b * z**3 -assert is_on_curve(G1, b) -assert is_on_curve(G2, b2) - # Elliptic curve doubling def double(pt): x, y, z = pt @@ -118,6 +112,23 @@ def twist(pt): nz = FQ12([zcoeffs[0]] + [0] * 5 + [zcoeffs[1]] + [0] * 5) return (nx * w **2, ny * w**3, nz) + +""" +# Generators for twisted curve over FQ2 + +# Generator used in libsnark alt_bn128 implementation +alt_bn128_G2 = (FQ2([10857046999023057135944570762232829481370756359578518086990519993285655852781, 11559732032986387107991004021392285783925812861821192530917403151452391805634]), + FQ2([8495653923123431417604973247489272438418190587263600148770280649306958101930, 4082367875863433681332203403145435568316851327593401208105741076214120093531]), FQ2.one()) +assert is_on_curve(alt_bn128_G2, b) + +# Generator used in libsnark bn128 implementation +bn128_G2 = (FQ2([15267802884793550383558706039165621050290089775961208824303765753922461897946, 9034493566019742339402378670461897774509967669562610788113215988055021632533]), + FQ2([644888581738283025171396578091639672120333224302184904896215738366765861164, 20532875081203448695448744255224543661959516361327385779878476709582931298750]), FQ2.one()) +assert is_on_curve(bn128_G2, b2) + # Check that the twist creates a point that is on the curve -G12 = twist(G2) +G12 = twist(alt_bn128_G2) +assert is_on_curve(G12, b12) +G12 = twist(bn128_G2) assert is_on_curve(G12, b12) +""" diff --git a/py_ecc/optimized_bn128/optimized_field_elements.py b/py_ecc/optimized_bn128/optimized_field_elements.py index 61ae1c6a..7e12c49d 100644 --- a/py_ecc/optimized_bn128/optimized_field_elements.py +++ b/py_ecc/optimized_bn128/optimized_field_elements.py @@ -1,5 +1,4 @@ -field_modulus = 21888242871839275222246405745257275088696311157297823662689037894645226208583 -FQ12_modulus_coeffs = [82, 0, 0, 0, 0, 0, -18, 0, 0, 0, 0, 0] # Implied + [1] +from .parameters import field_modulus, FQ12_modulus_coeffs FQ12_mc_tuples = [(i, c) for i, c in enumerate(FQ12_modulus_coeffs) if c] # python3 compatibility diff --git a/py_ecc/optimized_bn128/optimized_pairing.py b/py_ecc/optimized_bn128/optimized_pairing.py index 2dc4113b..61fa6ab4 100644 --- a/py_ecc/optimized_bn128/optimized_pairing.py +++ b/py_ecc/optimized_bn128/optimized_pairing.py @@ -1,15 +1,6 @@ -from .optimized_curve import double, add, multiply, is_on_curve, neg, twist, b, b2, b12, curve_order, G1, G2, G12, normalize +from .optimized_curve import double, add, multiply, is_on_curve, neg, twist, b, b2, b12, curve_order, G1, normalize from .optimized_field_elements import FQ2, FQ12, field_modulus, FQ - -ate_loop_count = 29793968203157093288 -log_ate_loop_count = 63 -pseudo_binary_encoding = [0, 0, 0, 1, 0, 1, 0, -1, 0, 0, 1, -1, 0, 0, 1, 0, - 0, 1, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 0, 0, 1, 1, - 1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 1, - 1, 0, 0, -1, 0, 0, 0, 1, 1, 0, -1, 0, 0, 1, 0, 1, 1] - -assert sum([e * 2**i for i, e in enumerate(pseudo_binary_encoding)]) == ate_loop_count - +from .parameters import pseudo_binary_encoding def normalize1(p): x, y = normalize(p) @@ -68,7 +59,7 @@ def miller_loop(Q, P, final_exponentiate=True): return FQ12.one() R = Q f_num, f_den = FQ12.one(), FQ12.one() - for b in pseudo_binary_encoding[63::-1]: + for b in pseudo_binary_encoding[-2::-1]: #for i in range(log_ate_loop_count, -1, -1): _n, _d = linefunc(R, R, P) f_num = f_num * f_num * _n diff --git a/py_ecc/optimized_bn128/parameters.py b/py_ecc/optimized_bn128/parameters.py new file mode 100644 index 00000000..281f37a7 --- /dev/null +++ b/py_ecc/optimized_bn128/parameters.py @@ -0,0 +1,41 @@ +# for an explanation of the BN parameters, see https://eprint.iacr.org/2010/429.pdf +# and https://eprint.iacr.org/2005/133.pdf + +BN_PARAM_U = 4965661367192848881 + +curve_order = 36*(BN_PARAM_U**4) + 36*(BN_PARAM_U**3) + 18*(BN_PARAM_U**2) + 6*BN_PARAM_U + 1 +field_modulus = 36*(BN_PARAM_U**4) + 36*(BN_PARAM_U**3) + 24*(BN_PARAM_U**2) + 6*BN_PARAM_U + 1 +ate_loop_count = 6*BN_PARAM_U + 2 + +#frobenius_trace = 6*(BN_PARAM_U**2) + 1 +#assert field_modulus == 21888242871839275222246405745257275088696311157297823662689037894645226208583 +#assert curve_order == 21888242871839275222246405745257275088548364400416034343698204186575808495617 +#assert ate_loop_count = 29793968203157093288 +#assert log_ate_loop_count = 63 + + +# extension field coefficients derived (somehow?) from w^6 = (i + 9) +FQ12_modulus_coeffs = [82, 0, 0, 0, 0, 0, -18, 0, 0, 0, 0, 0] # Implied + [1] + + +# Non-Adjacent Form +def naf(d): + naf_repr = [] + while d > 0: + d_j = d % 2 + if d_j == 1 and ( (((d - d_j)//2) % 2) == 1): + d_j = -1 + d = (d - d_j) // 2 + naf_repr.append(d_j) + return naf_repr + + +# used for the miller loop in the pairing check +pseudo_binary_encoding = naf(ate_loop_count) + +#pseudo_binary_encoding = [0, 0, 0, 1, 0, 1, 0, -1, 0, 0, 1, -1, 0, 0, 1, 0, +# 0, 1, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 0, 0, 1, 1, +# 1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 1, +# 1, 0, 0, -1, 0, 0, 0, 1, 1, 0, -1, 0, 0, 1, 0, 1, 1] + +assert sum([e * 2**i for i, e in enumerate(pseudo_binary_encoding)]) == ate_loop_count