def to_affine(self) -> AffinePoint: if self.infinity: return AffinePoint(Fq.zero(self.ec.q), Fq.zero(self.ec.q), self.infinity, self.ec) new_x = self.x / (self.z**2) new_y = self.y / (self.z**3) return AffinePoint(new_x, new_y, self.infinity, self.ec)
def divide_by(self, divisor_signatures): """ Signature division (elliptic curve subtraction). This is useful if you have already verified parts of the tree, since verification of the resulting quotient signature will be faster (less pairings have to be perfomed). This function Divides an aggregate signature by other signatures in the aggregate trees. A signature can only be divided if it is part of the subset, and all message/public key pairs in the aggregationInfo for the divisor signature are unique. i.e you cannot divide s1 / s2, if s2 is an aggregate signature containing m1,pk1, which is also present somewhere else in s1's tree. Note, s2 itself does not have to be unique. """ message_hashes_to_remove = [] pubkeys_to_remove = [] prod = JacobianPoint(Fq2.one(default_ec.q), Fq2.one(default_ec.q), Fq2.zero(default_ec.q), True, default_ec) for divisor_sig in divisor_signatures: pks = divisor_sig.aggregation_info.public_keys message_hashes = divisor_sig.aggregation_info.message_hashes if len(pks) != len(message_hashes): raise Exception("Invalid aggregation info") for i in range(len(pks)): divisor = divisor_sig.aggregation_info.tree[ (message_hashes[i], pks[i])] try: dividend = self.aggregation_info.tree[ (message_hashes[i], pks[i])] except KeyError: raise Exception("Signature is not a subset") if i == 0: quotient = (Fq(default_ec.n, dividend) / Fq(default_ec.n, divisor)) else: # Makes sure the quotient is identical for each public # key, which means message/pk pair is unique. new_quotient = (Fq(default_ec.n, dividend) / Fq(default_ec.n, divisor)) if quotient != new_quotient: raise Exception("Cannot divide by aggregate signature," + "msg/pk pairs are not unique") message_hashes_to_remove.append(message_hashes[i]) pubkeys_to_remove.append(pks[i]) prod += (divisor_sig.value * -quotient) copy = Signature(deepcopy(self.value + prod), deepcopy(self.aggregation_info)) for i in range(len(message_hashes_to_remove)): a = message_hashes_to_remove[i] b = pubkeys_to_remove[i] if (a, b) in copy.aggregation_info.tree: del copy.aggregation_info.tree[(a, b)] sorted_keys = list(copy.aggregation_info.tree.keys()) sorted_keys.sort() copy.aggregation_info.message_hashes = [t[0] for t in sorted_keys] copy.aggregation_info.public_keys = [t[1] for t in sorted_keys] return copy
def to_affine(self): if self.infinity: return AffinePoint(Fq.zero(self.ec.q), Fq.zero(self.ec.q), self.infinity, self.ec) new_x = self.x / pow(self.z, 2) new_y = self.y / pow(self.z, 3) return AffinePoint(new_x, new_y, self.infinity, self.ec)
def test_ec(): q = default_ec.q g = G1Generator() assert g.is_on_curve() assert 2 * g == g + g assert (3 * g).is_on_curve() assert 3 * g == g + g + g g2 = G2Generator() assert g2.x * (Fq(q, 2) * g2.y) == Fq(q, 2) * (g2.x * g2.y) assert g2.is_on_curve() s = g2 + g2 assert untwist(twist(s.to_affine())) == s.to_affine() assert untwist(5 * twist(s.to_affine())) == (5 * s).to_affine() assert 5 * twist(s.to_affine()) == twist((5 * s).to_affine()) assert s.is_on_curve() assert g2.is_on_curve() assert g2 + g2 == 2 * g2 assert g2 * 5 == (g2 * 2) + (2 * g2) + g2 y = y_for_x(g2.x, default_ec_twist, Fq2) assert y == g2.y or -y == g2.y g_j = G1Generator() g2_j = G2Generator() g2_j2 = G2Generator() * 2 assert g.to_affine().to_jacobian() == g assert (g_j * 2).to_affine() == g.to_affine() * 2 assert (g2_j + g2_j2).to_affine() == g2.to_affine() * 3
def double_point_jacobian(p1: JacobianPoint, ec=default_ec, FE=Fq) -> JacobianPoint: """ Jacobian elliptic curve point doubling http://www.hyperelliptic.org/EFD/oldefd/jacobian.html """ X, Y, Z = p1.x, p1.y, p1.z if Y == FE.zero(ec.q) or p1.infinity: return JacobianPoint(FE.one(ec.q), FE.one(ec.q), FE.zero(ec.q), True, ec) # S = 4*X*Y^2 S = Fq(ec.q, 4) * X * Y * Y Z_sq = Z * Z Z_4th = Z_sq * Z_sq Y_sq = Y * Y Y_4th = Y_sq * Y_sq # M = 3*X^2 + a*Z^4 M = Fq(ec.q, 3) * X * X M += ec.a * Z_4th # X' = M^2 - 2*S X_p = M * M - Fq(ec.q, 2) * S # Y' = M*(S - X') - 8*Y^4 Y_p = M * (S - X_p) - Fq(ec.q, 8) * Y_4th # Z' = 2*Y*Z Z_p = Fq(ec.q, 2) * Y * Z return JacobianPoint(X_p, Y_p, Z_p, False, ec)
def lagrange_coeffs_at_zero(X: List[int], ec=default_ec) -> List[Fq]: """ We have k+1 integers X[i], all less than ec.n and non-zero. The points (X[i], P(X[i])) interpolate into P(X), a degree k polynomial. Returns coefficients L_i such that P(0) = sum L_i * P(X[i]). """ N = len(X) # Check all x values are different, less than ec.n, and non-zero. assert len(set(X)) == N and all(0 != x < ec.n for x in X) def weight(j): ans = Fq(ec.n, 1) for i in range(N): if i != j: ans *= Fq(ec.n, X[j] - X[i]) return ~ans # Using the second barycentric form, # P(0) = (sum_j (y_j * w_j / x_j)) / (sum_j w_j/x_j) # If desired, the weights can be precomputed. ans = [] denominator = Fq(ec.n, 0) for j in range(N): shift = weight(j) * ~Fq(ec.n, -X[j]) ans.append(shift) denominator += shift denominator = ~denominator for i in range(len(ans)): ans[i] *= denominator return ans
def hash_to_point_prehashed_Fq(m, ec=default_ec): if type(m) != bytes: m = m.encode("utf-8") t0 = Fq(ec.q, int.from_bytes(hash512(m + b"G1_0"), "big")) t1 = Fq(ec.q, int.from_bytes(hash512(m + b"G1_1"), "big")) P = sw_encode(t0, ec, Fq) + sw_encode(t1, ec, Fq) return P * ec.h # Scaling by cofactor
def test_ec(): g = generator_Fq(default_ec) assert g.is_on_curve() assert 2 * g == g + g assert (3 * g).is_on_curve() assert 3 * g == g + g + g P = hash_to_point_Fq(bytes([])) assert P.is_on_curve() assert P.serialize() == bytes.fromhex( "12fc5ad5a2fbe9d4b6eb0bc16d530e5f263b6d59cbaf26c3f2831962924aa588ab84d46cc80d3a433ce064adb307f256" ) g2 = generator_Fq2(default_ec_twist) assert g2.x * (2 * g2.y) == 2 * (g2.x * g2.y) assert g2.is_on_curve() s = g2 + g2 assert untwist(twist(s)) == s assert untwist(5 * twist(s)) == 5 * s assert 5 * twist(s) == twist(5 * s) assert s.is_on_curve() assert g2.is_on_curve() assert g2 + g2 == 2 * g2 assert g2 * 5 == (g2 * 2) + (2 * g2) + g2 y = y_for_x(g2.x, default_ec_twist, Fq2) assert y[0] == g2.y or y[1] == g2.y assert hash_to_point_Fq2("chia") == hash_to_point_Fq2("chia") g_j = generator_Fq(default_ec_twist).to_jacobian() g2_j = generator_Fq2(default_ec_twist).to_jacobian() g2_j2 = (generator_Fq2(default_ec_twist) * 2).to_jacobian() assert g.to_jacobian().to_affine() == g assert (g_j * 2).to_affine() == g * 2 assert (g2_j + g2_j2).to_affine() == g2 * 3 assert sw_encode(Fq(default_ec.q, 0)).infinity assert sw_encode(Fq(default_ec.q, 1)) == sw_encode(Fq(default_ec.q, -1)).negate() assert ( sw_encode( Fq( default_ec.q, 0x019CFABA0C258165D092F6BCA9A081871E62A126C499340DC71C0E9527F923F3B299592A7A9503066CC5362484D96DD7, ) ) == generator_Fq() ) assert ( sw_encode( Fq( default_ec.q, 0x186417302D5A65347A88B0F999AB2B504614AA5E2EEBDEB1A014C40BCEB7D2306C12A6D436BEFCF94D39C9DB7B263CD4, ) ) == generator_Fq().negate() )
def test_edge_case_sign_Fq2(): q = default_ec.q a = Fq(q, 62323) test_case_1 = Fq2(q, a, Fq(q, 0)) test_case_2 = Fq2(q, -a, Fq(q, 0)) assert sign_Fq2(test_case_1) != sign_Fq2(test_case_2) test_case_3 = Fq2(q, Fq(q, 0), a) test_case_4 = Fq2(q, Fq(q, 0), -a) assert sign_Fq2(test_case_3) != sign_Fq2(test_case_4)
def double_point(p1: AffinePoint, ec=default_ec, FE=Fq) -> AffinePoint: """ Basic elliptic curve point doubling """ x, y = p1.x, p1.y left = Fq(ec.q, 3) * x * x left = left + ec.a s = left / (Fq(ec.q, 2) * y) new_x = s * s - x - x new_y = s * (x - new_x) - y return AffinePoint(new_x, new_y, False, ec)
def from_bytes(buffer): bit1 = buffer[0] & 0x80 buffer = bytes([buffer[0] & 0x1f]) + buffer[1:] x = Fq(default_ec.q, int.from_bytes(buffer, "big")) y_values = y_for_x(Fq(default_ec.q, x)) y_values.sort() y = y_values[0] if bit1: y = y_values[1] return PublicKey(AffinePoint(x, y, False, default_ec).to_jacobian())
def double_line_eval(R: AffinePoint, P: AffinePoint, ec=default_ec): """ Creates an equation for a line tangent to R, and evaluates this at the point P. f(x) = y - sv - v. f(P). """ R12 = untwist(R) slope = (Fq(ec.q, 3) * (R12.x**2) + ec.a) / (Fq(ec.q, 2) * R12.y) v = R12.y - slope * R12.x return P.y - P.x * slope - v
def setUp(self): self.a1 = Fq(48, 199) self.b1 = Fq(50, 199) self.c1 = Fq(62, 199) self.A1 = EC.get_point_from_x(self.a1) self.B1 = EC.get_point_from_x(self.b1) self.a2 = Fq2(self.b1, self.a1) self.b2 = Fq2(self.b1, self.c1) self.A2 = TwistedEC.get_point_from_x(self.a2) self.B2 = TwistedEC.get_point_from_x(self.b2) self.g1 = EC.from_affine(g1_x, g1_y) self.g2 = TwistedEC.from_affine(g2_x, g2_y)
def test_frobenius_coefficients(self): self.assertEqual((Fq(1, q), Fq(-1, q)), FROB_FQ2) self.assertEqual( tuple( Fq2.all_one_poly(q)**(((q**i) - 1) // 3) for i in range(0, 6)), FROB_FQ6_C1) self.assertEqual( tuple( Fq2.all_one_poly(q)**(((2 * q**i) - 2) // 3) for i in range(0, 6)), FROB_FQ6_C2) self.assertEqual( tuple( Fq2.all_one_poly(q)**(((q**i) - 1) // 6) for i in range(0, 12)), FROB_FQ12_C1)
def verify(self): """ This implementation of verify has several steps. First, it reorganizes the pubkeys and messages into groups, where each group corresponds to a message. Then, it checks if the siganture has info on how it was aggregated. If so, we exponentiate each pk based on the exponent in the AggregationInfo. If not, we find public keys that share messages with others, and aggregate all of these securely (with exponents.). Finally, since each public key now corresponds to a unique message (since we grouped them), we can verify using the distinct verification procedure. """ message_hashes = self.aggregation_info.message_hashes public_keys = self.aggregation_info.public_keys assert (len(message_hashes) == len(public_keys)) hash_to_public_keys = {} for i in range(len(message_hashes)): if message_hashes[i] in hash_to_public_keys: hash_to_public_keys[message_hashes[i]].append(public_keys[i]) else: hash_to_public_keys[message_hashes[i]] = [public_keys[i]] final_message_hashes = [] final_public_keys = [] ec = public_keys[0].value.ec for message_hash, mapped_keys in hash_to_public_keys.items(): dedup = list(set(mapped_keys)) public_key_sum = JacobianPoint(Fq.one(ec.q), Fq.one(ec.q), Fq.zero(ec.q), True, ec) for public_key in dedup: try: exponent = self.aggregation_info.tree[(message_hash, public_key)] public_key_sum += (public_key.value * exponent) except KeyError: return False final_message_hashes.append(message_hash) final_public_keys.append(public_key_sum.to_affine()) mapped_hashes = [ hash_to_point_prehashed_Fq2(mh) for mh in final_message_hashes ] g1 = Fq(default_ec.n, -1) * generator_Fq() Ps = [g1] + final_public_keys Qs = [self.value.to_affine()] + mapped_hashes res = ate_pairing_multi(Ps, Qs, default_ec) return res == Fq12.one(default_ec.q)
def test_ec(): g = generator_Fq(default_ec) assert (g.is_on_curve()) assert (2 * g == g + g) assert ((3 * g).is_on_curve()) assert (3 * g == g + g + g) P = hash_to_point_Fq(bytes([])) assert (P.is_on_curve()) assert (P.serialize() == bytes.fromhex( "12fc5ad5a2fbe9d4b6eb0bc16d530e5f263b6d59cbaf26c3f2831962924aa588ab84d46cc80d3a433ce064adb307f256" )) g2 = generator_Fq2(default_ec_twist) assert (g2.x * (2 * g2.y) == 2 * (g2.x * g2.y)) assert (g2.is_on_curve()) s = g2 + g2 assert (untwist(twist(s)) == s) assert (untwist(5 * twist(s)) == 5 * s) assert (5 * twist(s) == twist(5 * s)) assert (s.is_on_curve()) assert (g2.is_on_curve()) assert (g2 + g2 == 2 * g2) assert (g2 * 5 == (g2 * 2) + (2 * g2) + g2) y = y_for_x(g2.x, default_ec_twist, Fq2) assert (y[0] == g2.y or y[1] == g2.y) assert (hash_to_point_Fq2("chia") == hash_to_point_Fq2("chia")) g_j = generator_Fq(default_ec_twist).to_jacobian() g2_j = generator_Fq2(default_ec_twist).to_jacobian() g2_j2 = (generator_Fq2(default_ec_twist) * 2).to_jacobian() assert (g.to_jacobian().to_affine() == g) assert ((g_j * 2).to_affine() == g * 2) assert ((g2_j + g2_j2).to_affine() == g2 * 3) assert (sw_encode(Fq(default_ec.q, 0)).infinity) assert (sw_encode(Fq(default_ec.q, 1)) == sw_encode(Fq(default_ec.q, -1)).negate()) assert (sw_encode( Fq( default_ec.q, 0x019cfaba0c258165d092f6bca9a081871e62a126c499340dc71c0e9527f923f3b299592a7a9503066cc5362484d96dd7 )) == generator_Fq()) assert (sw_encode( Fq( default_ec.q, 0x186417302d5a65347a88b0f999ab2b504614aa5e2eebdeb1a014c40bceb7d2306c12a6d436befcf94d39c9db7b263cd4 )) == generator_Fq().negate())
def create(T, N): """ Create a new private key with associated data suitable for T of N threshold signatures under a Joint-Feldman scheme. After the dealing phase, one needs cooperation of T players out of N in order to sign a message with the master key pair. Return: - poly[0] - your share of the master secret key - commitments to your polynomial P - secret_fragments[j] = P(j), to be sent to player j (All N secret_fragments[j] can be combined to make a secret share.) """ assert 1 <= T <= N g1 = generator_Fq() poly = [ Fq(default_ec.n, RNG.randint(1, default_ec.n - 1)) for _ in range(T) ] commitments = [g1 * c for c in poly] secret_fragments = [ sum(c * pow(x, i, default_ec.n) for i, c in enumerate(poly)) for x in range(1, N + 1) ] return PrivateKey(poly[0]), commitments, secret_fragments
def main(): for Pinf in ((F1_zero, F1_one, F1_zero), (F2_zero, F2_one, F2_zero)): test_ell(Pinf) sys.stdout.write('.') sys.stdout.flush() for _ in range(0, 32): sys.stdout.write('.') sys.stdout.flush() test_ell(opt_swu_map(Fq(p, random.getrandbits(380)))) test_ell( opt_swu2_map( Fq2(p, random.getrandbits(380), random.getrandbits(380)))) for (ell2, invals) in ((False, invalid_inputs_1), (True, invalid_inputs_2)): curve_name = "E2" if ell2 else "E1" for (idx, inval) in enumerate(invals): try: deserialize(binascii.unhexlify(inval), ell2) except DeserError: sys.stdout.write('*') sys.stdout.flush() else: raise DeserError( "expected failed deserialization of #%d on %s" % (idx, curve_name)) sys.stdout.write('\n')
def sw_encode(t, ec=default_ec, FE=Fq): if t == 0: # Maps t=0 to the point at infinity return JacobianPoint(FE.one(ec.q), FE.one(ec.q), FE.zero(ec.q), True, ec) # Parity will ensure that sw_encode(t) = -sw_encode(-t) parity = False if FE == Fq: if t > -t: parity = True elif FE == Fq2: if t[1] > (-t)[1]: parity = True # w = t^2 + b + 1 w = t * t + ec.b + 1 # Map w=0 to generator and its negation if w == 0: if FE == Fq: ret = generator_Fq(ec) else: return generator_Fq2(ec) if parity: ret = ret.negate() return ret w = ~w * ec.sqrt_n3 * t # At least 1 of x1, x2, x3 is guaranteed to be a valid x # x1 = -wt + sqrt(-3) x1 = -w * t + ec.sqrt_n3m1o2 # x2 = -x1 - 1 x2 = FE.from_fq(ec.q, Fq(ec.q, -1)) - x1 # x3 = 1/w^2 + 1 x3 = ~(w * w) + 1 # Constant time algorithm for finding the correct x, from # FT paper. Xx1 = 1 Xx2 = 1 try: y_for_x(x1, ec, FE) except: # noqa: E772 Xx1 = -1 try: y_for_x(x2, ec, FE) except: # noqa: E772 Xx2 = -1 index = (((Xx1 - 1) * Xx2) % 3) xs = [x1, x2, x3] ys = y_for_x(xs[index], ec, FE) ret = AffinePoint(xs[index], ys[0], False, ec) if ret.lex_gt_neg() is not parity: ret = ret.negate() return ret
def from_bytes(buffer, aggregation_info=None): use_big_y = buffer[0] & 0x80 buffer = bytes([buffer[0] & 0x1f]) + buffer[1:] x0 = int.from_bytes(buffer[:48], "big") x1 = int.from_bytes(buffer[48:], "big") x = Fq2(default_ec.q, Fq(default_ec.q, x0), Fq(default_ec.q, x1)) ys = y_for_x(x, default_ec_twist, Fq2) y = ys[0] if ((use_big_y and ys[1][1] > default_ec.q // 2) or (not use_big_y and ys[1][1] < default_ec.q // 2)): y = ys[1] return Signature(AffinePoint(x, y, False, default_ec_twist) .to_jacobian(), aggregation_info)
def _from_bytes_F1(data): assert len(data) == 48 ret = 0 for d in data: ret = ret << 8 ret += d if ret >= p: raise DeserError("invalid encoded value: not a residue mod p") return Fq(p, ret)
class TestFields(unittest.TestCase): def setUp(self): self.a1 = Fq(3, 11) self.b1 = Fq(4, 11) self.c1 = Fq(7, 11) self.d1 = Fq(12, 11) self.e1 = Fq(2, 11) self.f1 = Fq(9, 11) self.g1 = Fq(6, 11) self.a2 = Fq2(self.a1, self.b1) self.b2 = Fq2(self.b1, self.c1) self.c2 = Fq2(self.c1, self.d1) self.d2 = Fq2(self.d1, self.e1) self.e2 = Fq2(self.e1, self.f1) self.f2 = Fq2(self.f1, self.g1) self.a6 = Fq6(self.a2, self.b2, self.c2) self.b6 = Fq6(self.b2, self.c2, self.d2) self.c6 = Fq6(self.d2, self.e2, self.f2) self.a12 = Fq12(self.a6, self.b6) self.b12 = Fq12(self.b6, self.c6) def test_Fq(self): self.assertEqual(self.a1 + self.a1, self.a1 * 2) self.assertTrue((self.a1 - self.a1).is_zero()) self.assertEqual(self.a1 + self.a1 + self.a1 + self.b1 + self.b1, 3 * self.a1 + 2 * self.b1) self.assertTrue((self.a1 * self.b1 / self.b1 / self.a1).is_one()) self.assertEqual(self.a1.sqrt().square(), self.a1) self.assertEqual(self.a1**3, self.a1 * self.a1 * self.a1) def test_Fq2(self): self.assertEqual(self.a2 + self.a2, self.a2 * 2) self.assertTrue((self.a2 - self.a2).is_zero()) self.assertEqual(self.a2 + self.a2 + self.a2 + self.b2 + self.b2, 3 * self.a2 + 2 * self.b2) self.assertTrue((self.a2 * self.b2 / self.b2 / self.a2).is_one()) self.assertEqual(self.a2.sqrt().square(), self.a2) self.assertEqual(self.a2**3, self.a2 * self.a2 * self.a2) def test_Fq6(self): self.assertEqual(self.a6 + self.a6, self.a6 * 2) self.assertTrue((self.a6 - self.a6).is_zero()) self.assertEqual(self.a6 + self.a6 + self.a6 + self.b6 + self.b6, 3 * self.a6 + 2 * self.b6) self.assertTrue((self.a6 * self.b6 / self.b6 / self.a6).is_one()) self.assertEqual(self.a6**3, self.a6 * self.a6 * self.a6) def test_Fq12(self): self.assertEqual(self.a12 + self.a12, self.a12 * 2) self.assertTrue((self.a12 - self.a12).is_zero()) self.assertEqual(self.a12 + self.a12 + self.a12 + self.b12 + self.b12, 3 * self.a12 + 2 * self.b12) self.assertTrue((self.a12 * self.b12 / self.b12 / self.a12).is_one()) self.assertEqual(self.a12**3, self.a12 * self.a12 * self.a12)
def from_bytes(buffer): use_big_y = buffer[0] & 0x80 prepend = buffer[0] & 0x40 if not prepend: raise "Should have prepend bit set" buffer = bytes([buffer[0] & 0x1f]) + buffer[1:] x0 = int.from_bytes(buffer[:48], "big") x1 = int.from_bytes(buffer[48:], "big") x = Fq2(default_ec.q, Fq(default_ec.q, x0), Fq(default_ec.q, x1)) ys = y_for_x(x, default_ec_twist, Fq2) y = ys[0] if ((use_big_y and ys[1][1] > default_ec.q // 2) or (not use_big_y and ys[1][1] < default_ec.q // 2)): y = ys[1] return PrependSignature( AffinePoint(x, y, False, default_ec_twist).to_jacobian())
def test_fields(): a = Fq(17, 30) b = Fq(17, -18) c = Fq2(17, a, b) d = Fq2(17, a + a, -5) e = c * d f = e * d assert f != e e_sq = e * e e_sqrt = e_sq.modsqrt() assert pow(e_sqrt, 2) == e_sq a2 = Fq( 172487123095712930573140951348, 3012492130751239573498573249085723940848571098237509182375, ) b2 = Fq(172487123095712930573140951348, 3432984572394572309458723045723849) c2 = Fq2(172487123095712930573140951348, a2, b2) assert b2 != c2 g = Fq6(17, c, d, d * d * c) h = Fq6(17, a + a * c, c * b * a, b * b * d * 21) i = Fq12(17, g, h) assert ~(~i) == i assert (~(i.root)) * i.root == Fq6.one(17) x = Fq12(17, Fq6.zero(17), i.root) assert (~x) * x == Fq12.one(17) j = Fq6(17, a + a * c, Fq2.zero(17), Fq2.zero(17)) j2 = Fq6(17, a + a * c, Fq2.zero(17), Fq2.one(17)) assert j == (a + a * c) assert j2 != (a + a * c) assert j != j2 # Test frob_coeffs one = Fq(default_ec.q, 1) two = one + one a = Fq2(default_ec.q, two, two) b = Fq6(default_ec.q, a, a, a) c = Fq12(default_ec.q, b, b) for base in (a, b, c): for expo in range(1, base.extension): assert base.qi_power(expo) == pow(base, pow(default_ec.q, expo))
def interpolate_at_zero(X: List[int], Y: List[Fq], ec=default_ec) -> Fq: """ The k+1 points (X[i], Y[i]) interpolate into P(X), a degree k polynomial. Returns P(0). """ ans = Fq(ec.n, 0) for lamb, y in zip(Threshold.lagrange_coeffs_at_zero(X, ec), Y): ans += lamb * y return ans
def from_bytes(buffer, aggregation_info=None): use_big_y = buffer[0] & 0x80 prepend = buffer[0] & 0x40 if prepend: raise Exception("Should not have prepend bit set") buffer = bytes([buffer[0] & 0x1F]) + buffer[1:] x0 = int.from_bytes(buffer[:48], "big") x1 = int.from_bytes(buffer[48:], "big") x = Fq2(default_ec.q, Fq(default_ec.q, x0), Fq(default_ec.q, x1)) ys = y_for_x(x, default_ec_twist, Fq2) y = ys[0] if (use_big_y and ys[1][1] > default_ec.q // 2) or ( not use_big_y and ys[1][1] < default_ec.q // 2): y = ys[1] return Signature( AffinePoint(x, y, False, default_ec_twist).to_jacobian(), aggregation_info)
def aggregate(public_keys, secure): """ Aggregates public keys together """ if len(public_keys) < 1: raise Exception("Invalid number of keys") public_keys.sort() computed_Ts = BLS.hash_pks(len(public_keys), public_keys) ec = public_keys[0].value.ec sum_keys = JacobianPoint(Fq.one(ec.q), Fq.one(ec.q), Fq.zero(ec.q), True, ec) for i in range(len(public_keys)): addend = public_keys[i].value if secure: addend *= computed_Ts[i] sum_keys += addend return PublicKey.from_g1(sum_keys)
def run_tests(): import random for _ in range(0, 128): t1 = Fq(p, random.getrandbits(380)) t2 = Fq(p, random.getrandbits(380)) # test helpers individually for t in (t1, t2): P = osswu_help(t) Pp = from_jacobian(P) assert Pp[0]**3 + EllP_a * Pp[0] + EllP_b == Pp[1]**2 P = iso11(P) Pp = from_jacobian(P) assert Pp[0]**3 + 4 == Pp[1]**2 P = clear_h(P) Pp = from_jacobian(P) assert Pp[0]**3 + 4 == Pp[1]**2 # now test end-to-end P = from_jacobian(opt_swu_map(t1, t2)) assert P[0]**3 + 4 == P[1]**2 sys.stdout.write('.') sys.stdout.flush() sys.stdout.write("\n")
def osswu2_help(t): assert isinstance(t, Fq2) # first, compute X0(t), detecting and handling exceptional case num_den_common = xi_2**2 * t**4 + xi_2 * t**2 x0_num = Ell2p_b * (num_den_common + Fq(q, 1)) x0_den = -Ell2p_a * num_den_common x0_den = Ell2p_a * xi_2 if x0_den == 0 else x0_den # compute num and den of g(X0(t)) gx0_den = pow(x0_den, 3) gx0_num = Ell2p_b * gx0_den gx0_num += Ell2p_a * x0_num * pow(x0_den, 2) gx0_num += pow(x0_num, 3) # try taking sqrt of g(X0(t)) # this uses the trick for combining division and sqrt from Section 5 of # Bernstein, Duif, Lange, Schwabe, and Yang, "High-speed high-security signatures." # J Crypt Eng 2(2):77--89, Sept. 2012. http://ed25519.cr.yp.to/ed25519-20110926.pdf tmp1 = pow(gx0_den, 7) # v^7 tmp2 = gx0_num * tmp1 # u v^7 tmp1 = tmp1 * tmp2 * gx0_den # u v^15 sqrt_candidate = tmp2 * pow(tmp1, (q**2 - 9) // 16) # check if g(X0(t)) is square and return the sqrt if so for root in roots_of_unity: y0 = sqrt_candidate * root if y0**2 * gx0_den == gx0_num: # found sqrt(g(X0(t))). force sign of y to equal sign of t if sgn0(y0) != sgn0(t): y0 = -y0 assert sgn0(y0) == sgn0(t) return JacobianPoint(x0_num * x0_den, y0 * pow(x0_den, 3), x0_den, False, default_ec_twist) # if we've gotten here, then g(X0(t)) is not square. convert srqt_candidate to sqrt(g(X1(t))) (x1_num, x1_den) = (xi_2 * t**2 * x0_num, x0_den) (gx1_num, gx1_den) = (xi_2**3 * t**6 * gx0_num, gx0_den) sqrt_candidate *= t**3 for eta in etas: y1 = eta * sqrt_candidate if y1**2 * gx1_den == gx1_num: # found sqrt(g(X1(t))). force sign of y to equal sign of t if sgn0(y1) != sgn0(t): y1 = -y1 assert sgn0(y1) == sgn0(t) return JacobianPoint(x1_num * x1_den, y1 * pow(x1_den, 3), x1_den, False, default_ec_twist) # if we got here, something is wrong raise RuntimeError("osswu2_help failed for unknown reasons")
def hash_to_point_prehashed_Fq2(m, ec=default_ec_twist): if type(m) != bytes: m = m.encode("utf-8") t0_0 = Fq(ec.q, int.from_bytes(hash512(m + b"G2_0_c0"), "big")) t0_1 = Fq(ec.q, int.from_bytes(hash512(m + b"G2_0_c1"), "big")) t1_0 = Fq(ec.q, int.from_bytes(hash512(m + b"G2_1_c0"), "big")) t1_1 = Fq(ec.q, int.from_bytes(hash512(m + b"G2_1_c1"), "big")) t0 = Fq2(ec.q, t0_0, t0_1) t1 = Fq2(ec.q, t1_0, t1_1) P = sw_encode(t0, ec, Fq2) + sw_encode(t1, ec, Fq2) # This is the cofactor multiplication, done in a more # efficient way. See page 11 of "Efficient hash maps # to G2 on BLS curves" by Budrioni and Pintore. x = -ec.x psi2P = psi(psi(2 * P, ec), ec) t0 = x * P t1 = x * t0 t2 = (t1 + t0) - P t3 = psi((x + 1) * P, ec) return t2 - t3 + psi2P