def test_second_generator() -> None: """ important remarks on secp256-zkp prefix for compressed encoding of the second generator: https://github.com/garyyu/rust-secp256k1-zkp/wiki/Pedersen-Commitment """ H = ( 0x50929B74C1A04954B78B4B6035E97A5E078A5A0F28EC96D547BFEE9ACE803AC0, 0x31D3C6863973926E049E637CB1B5F40A36DAC28AF1766968C30C2313F3A38904, ) assert H == pedersen.second_generator(secp256k1, sha256) H = pedersen.second_generator(secp256r1, sha256) H = pedersen.second_generator(secp384r1, sha384)
def test_assorted_mult() -> None: ec = ec23_31 H = second_generator(ec) for k1 in range(-ec.n + 1, ec.n): K1 = mult(k1, ec.G, ec) for k2 in range(ec.n): K2 = mult(k2, H, ec) shamir = double_mult(k1, ec.G, k2, ec.G, ec) assert shamir == mult(k1 + k2, ec.G, ec) shamir = double_mult(k1, INF, k2, H, ec) assert ec.is_on_curve(shamir) assert shamir == K2 shamir = double_mult(k1, ec.G, k2, INF, ec) assert ec.is_on_curve(shamir) assert shamir == K1 shamir = double_mult(k1, ec.G, k2, H, ec) assert ec.is_on_curve(shamir) K1K2 = ec.add(K1, K2) assert K1K2 == shamir k3 = 1 + secrets.randbelow(ec.n - 1) K3 = mult(k3, ec.G, ec) K1K2K3 = ec.add(K1K2, K3) assert ec.is_on_curve(K1K2K3) boscoster = multi_mult([k1, k2, k3], [ec.G, H, ec.G], ec) assert ec.is_on_curve(boscoster) assert K1K2K3 == boscoster, k3 k4 = 1 + secrets.randbelow(ec.n - 1) K4 = mult(k4, H, ec) K1K2K3K4 = ec.add(K1K2K3, K4) assert ec.is_on_curve(K1K2K3K4) points = [ec.G, H, ec.G, H] boscoster = multi_mult([k1, k2, k3, k4], points, ec) assert ec.is_on_curve(boscoster) assert K1K2K3K4 == boscoster, k4 assert K1K2K3 == multi_mult([k1, k2, k3, 0], points, ec) assert K1K2 == multi_mult([k1, k2, 0, 0], points, ec) assert K1 == multi_mult([k1, 0, 0, 0], points, ec) assert INF == multi_mult([0, 0, 0, 0], points, ec) err_msg = "mismatch between number of scalars and points: " with pytest.raises(ValueError, match=err_msg): multi_mult([k1, k2, k3, k4], [ec.G, H, ec.G], ec)
def test_assorted_mult(): ec = ec23_31 H = second_generator(ec) HJ = _jac_from_aff(H) for k1 in range(ec.n): K1J = _mult_jac(k1, ec.GJ, ec) for k2 in range(ec.n): K2J = _mult_jac(k2, HJ, ec) shamir = _double_mult(k1, ec.GJ, k2, ec.GJ, ec) assert ec._jac_equality(shamir, _mult_jac(k1 + k2, ec.GJ, ec)) shamir = _double_mult(k1, INFJ, k2, HJ, ec) assert ec._jac_equality(shamir, K2J) shamir = _double_mult(k1, ec.GJ, k2, INFJ, ec) assert ec._jac_equality(shamir, K1J) shamir = _double_mult(k1, ec.GJ, k2, HJ, ec) K1JK2J = ec._add_jac(K1J, K2J) assert ec._jac_equality(K1JK2J, shamir) k3 = 1 + secrets.randbelow(ec.n - 1) K3J = _mult_jac(k3, ec.GJ, ec) K1JK2JK3J = ec._add_jac(K1JK2J, K3J) boscoster = _multi_mult([k1, k2, k3], [ec.GJ, HJ, ec.GJ], ec) assert ec._jac_equality(K1JK2JK3J, boscoster) k4 = 1 + secrets.randbelow(ec.n - 1) K4J = _mult_jac(k4, HJ, ec) K1JK2JK3JK4J = ec._add_jac(K1JK2JK3J, K4J) points = [ec.GJ, HJ, ec.GJ, HJ] boscoster = _multi_mult([k1, k2, k3, k4], points, ec) assert ec._jac_equality(K1JK2JK3JK4J, boscoster) assert ec._jac_equality(K1JK2JK3J, _multi_mult([k1, k2, k3, 0], points, ec)) assert ec._jac_equality(K1JK2J, _multi_mult([k1, k2, 0, 0], points, ec)) assert ec._jac_equality(K1J, _multi_mult([k1, 0, 0, 0], points, ec)) assert ec._jac_equality(INFJ, _multi_mult([0, 0, 0, 0], points, ec)) err_msg = "mismatch between number of scalars and points: " with pytest.raises(ValueError, match=err_msg): _multi_mult([k1, k2, k3, k4], [ec.GJ, HJ, ec.GJ], ec) with pytest.raises(ValueError, match="negative first coefficient: "): _double_mult(-5, HJ, 1, ec.GJ, ec) with pytest.raises(ValueError, match="negative second coefficient: "): _double_mult(1, HJ, -5, ec.GJ, ec)
def test_second_generator(self): """ important remark on secp256-zkp prefix for compressed encoding of the second generator: https://github.com/garyyu/rust-secp256k1-zkp/wiki/Pedersen-Commitment """ ec = secp256k1 hf = sha256 H = pedersen.second_generator(ec, hf) self.assertEqual( H, point_from_octets( '0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0', ec)) # 0*G + 1*H T = double_mult(1, H, 0, ec.G, ec) self.assertEqual( T, point_from_octets( '0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0', ec)) # 0*G + 2*H T = double_mult(2, H, 0, ec.G, ec) self.assertEqual( T, point_from_octets( '03fad265e0a0178418d006e247204bcf42edb6b92188074c9134704c8686eed37a', ec)) T = mult(2, H, ec) self.assertEqual( T, point_from_octets( '03fad265e0a0178418d006e247204bcf42edb6b92188074c9134704c8686eed37a', ec)) # 0*G + 3*H T = double_mult(3, H, 0, ec.G, ec) self.assertEqual( T, point_from_octets( '025ef47fcde840a435e831bbb711d466fc1ee160da3e15437c6c469a3a40daacaa', ec)) T = mult(3, H, ec) self.assertEqual( T, point_from_octets( '025ef47fcde840a435e831bbb711d466fc1ee160da3e15437c6c469a3a40daacaa', ec)) # 1*G+0*H T = double_mult(0, H, 1, ec.G, ec) self.assertEqual( T, point_from_octets( '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', ec)) T = ec.G self.assertEqual( T, point_from_octets( '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', ec)) # 2*G+0*H T = double_mult(0, H, 2, ec.G, ec) self.assertEqual( T, point_from_octets( '02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5', ec)) T = mult(2, ec.G, ec) self.assertEqual( T, point_from_octets( '02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5', ec)) # 3*G+0*H T = double_mult(0, H, 3, ec.G, ec) self.assertEqual( T, point_from_octets( '02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9', ec)) T = mult(3, ec.G, ec) self.assertEqual( T, point_from_octets( '02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9', ec)) # 0*G+5*H T = double_mult(5, H, 0, ec.G, ec) self.assertEqual( T, point_from_octets( '039e431be0851721f9ce35cc0f718fce7d6d970e3ddd796643d71294d7a09b554e', ec)) T = mult(5, H, ec) self.assertEqual( T, point_from_octets( '039e431be0851721f9ce35cc0f718fce7d6d970e3ddd796643d71294d7a09b554e', ec)) # 0*G-5*H T = double_mult(-5, H, 0, ec.G, ec) self.assertEqual( T, point_from_octets( '029e431be0851721f9ce35cc0f718fce7d6d970e3ddd796643d71294d7a09b554e', ec)) T = mult(-5, H, ec) self.assertEqual( T, point_from_octets( '029e431be0851721f9ce35cc0f718fce7d6d970e3ddd796643d71294d7a09b554e', ec)) # 1*G-5*H U = double_mult(-5, H, 1, ec.G, ec) self.assertEqual( U, point_from_octets( '02b218ddacb34d827c71760e601b41d309bc888cf7e3ab7cc09ec082b645f77e5a', ec)) U = ec.add(ec.G, T) # reusing previous T value self.assertEqual( U, point_from_octets( '02b218ddacb34d827c71760e601b41d309bc888cf7e3ab7cc09ec082b645f77e5a', ec)) H = pedersen.second_generator(secp256r1, hf) H = pedersen.second_generator(secp384r1, sha384)
def test_mult_double_mult(): H = second_generator(secp256k1) G = secp256k1.G # 0*G + 1*H T = double_mult(1, H, 0, G) assert T == H T = multi_mult([1, 0], [H, G]) assert T == H # 0*G + 2*H exp = mult(2, H) T = double_mult(2, H, 0, G) assert T == exp T = multi_mult([2, 0], [H, G]) assert T == exp # 0*G + 3*H exp = mult(3, H) T = double_mult(3, H, 0, G) assert T == exp T = multi_mult([3, 0], [H, G]) assert T == exp # 1*G + 0*H T = double_mult(0, H, 1, G) assert T == G T = multi_mult([0, 1], [H, G]) assert T == G # 2*G + 0*H exp = mult(2, G) T = double_mult(0, H, 2, G) assert T == exp T = multi_mult([0, 2], [H, G]) assert T == exp # 3*G + 0*H exp = mult(3, G) T = double_mult(0, H, 3, G) assert T == exp T = multi_mult([0, 3], [H, G]) assert T == exp # 0*G + 5*H exp = mult(5, H) T = double_mult(5, H, 0, G) assert T == exp T = multi_mult([5, 0], [H, G]) assert T == exp # 0*G - 5*H exp = mult(-5, H) T = double_mult(-5, H, 0, G) assert T == exp T = multi_mult([-5, 0], [H, G]) assert T == exp # 1*G - 5*H exp = secp256k1.add(G, T) T = double_mult(-5, H, 1, G) assert T == exp
def test_threshold() -> None: "testing 2-of-3 threshold signature (Pedersen secret sharing)" ec = CURVES["secp256k1"] # parameters m = 2 H = second_generator(ec) # FIRST PHASE: key pair generation ################################### # 1.1 signer one acting as the dealer commits1: List[Point] = [] q1, _ = ssa.gen_keys() q1_prime, _ = ssa.gen_keys() commits1.append(double_mult(q1_prime, H, q1, ec.G)) # sharing polynomials f1 = [q1] f1_prime = [q1_prime] for i in range(1, m): f1.append(ssa.gen_keys()[0]) f1_prime.append(ssa.gen_keys()[0]) commits1.append(double_mult(f1_prime[i], H, f1[i], ec.G)) # shares of the secret alpha12 = 0 # share of q1 belonging to signer two alpha12_prime = 0 alpha13 = 0 # share of q1 belonging to signer three alpha13_prime = 0 for i in range(m): alpha12 += (f1[i] * pow(2, i)) % ec.n alpha12_prime += (f1_prime[i] * pow(2, i)) % ec.n alpha13 += (f1[i] * pow(3, i)) % ec.n alpha13_prime += (f1_prime[i] * pow(3, i)) % ec.n # signer two verifies consistency of his share RHS = INF for i in range(m): RHS = ec.add(RHS, mult(pow(2, i), commits1[i])) t = double_mult(alpha12_prime, H, alpha12, ec.G) assert t == RHS, "signer one is cheating" # signer three verifies consistency of his share RHS = INF for i in range(m): RHS = ec.add(RHS, mult(pow(3, i), commits1[i])) t = double_mult(alpha13_prime, H, alpha13, ec.G) assert t == RHS, "signer one is cheating" # 1.2 signer two acting as the dealer commits2: List[Point] = [] q2, _ = ssa.gen_keys() q2_prime, _ = ssa.gen_keys() commits2.append(double_mult(q2_prime, H, q2, ec.G)) # sharing polynomials f2 = [q2] f2_prime = [q2_prime] for i in range(1, m): f2.append(ssa.gen_keys()[0]) f2_prime.append(ssa.gen_keys()[0]) commits2.append(double_mult(f2_prime[i], H, f2[i], ec.G)) # shares of the secret alpha21 = 0 # share of q2 belonging to signer one alpha21_prime = 0 alpha23 = 0 # share of q2 belonging to signer three alpha23_prime = 0 for i in range(m): alpha21 += (f2[i] * pow(1, i)) % ec.n alpha21_prime += (f2_prime[i] * pow(1, i)) % ec.n alpha23 += (f2[i] * pow(3, i)) % ec.n alpha23_prime += (f2_prime[i] * pow(3, i)) % ec.n # signer one verifies consistency of his share RHS = INF for i in range(m): RHS = ec.add(RHS, mult(pow(1, i), commits2[i])) t = double_mult(alpha21_prime, H, alpha21, ec.G) assert t == RHS, "signer two is cheating" # signer three verifies consistency of his share RHS = INF for i in range(m): RHS = ec.add(RHS, mult(pow(3, i), commits2[i])) t = double_mult(alpha23_prime, H, alpha23, ec.G) assert t == RHS, "signer two is cheating" # 1.3 signer three acting as the dealer commits3: List[Point] = [] q3, _ = ssa.gen_keys() q3_prime, _ = ssa.gen_keys() commits3.append(double_mult(q3_prime, H, q3, ec.G)) # sharing polynomials f3 = [q3] f3_prime = [q3_prime] for i in range(1, m): f3.append(ssa.gen_keys()[0]) f3_prime.append(ssa.gen_keys()[0]) commits3.append(double_mult(f3_prime[i], H, f3[i], ec.G)) # shares of the secret alpha31 = 0 # share of q3 belonging to signer one alpha31_prime = 0 alpha32 = 0 # share of q3 belonging to signer two alpha32_prime = 0 for i in range(m): alpha31 += (f3[i] * pow(1, i)) % ec.n alpha31_prime += (f3_prime[i] * pow(1, i)) % ec.n alpha32 += (f3[i] * pow(2, i)) % ec.n alpha32_prime += (f3_prime[i] * pow(2, i)) % ec.n # signer one verifies consistency of his share RHS = INF for i in range(m): RHS = ec.add(RHS, mult(pow(1, i), commits3[i])) t = double_mult(alpha31_prime, H, alpha31, ec.G) assert t == RHS, "signer three is cheating" # signer two verifies consistency of his share RHS = INF for i in range(m): RHS = ec.add(RHS, mult(pow(2, i), commits3[i])) t = double_mult(alpha32_prime, H, alpha32, ec.G) assert t == RHS, "signer three is cheating" # shares of the secret key q = q1 + q2 + q3 alpha1 = (alpha21 + alpha31) % ec.n alpha2 = (alpha12 + alpha32) % ec.n alpha3 = (alpha13 + alpha23) % ec.n for i in range(m): alpha1 += (f1[i] * pow(1, i)) % ec.n alpha2 += (f2[i] * pow(2, i)) % ec.n alpha3 += (f3[i] * pow(3, i)) % ec.n # 1.4 it's time to recover the public key # each participant i = 1, 2, 3 shares Qi as follows # Q = Q1 + Q2 + Q3 = (q1 + q2 + q3) G A1: List[Point] = [] A2: List[Point] = [] A3: List[Point] = [] for i in range(m): A1.append(mult(f1[i])) A2.append(mult(f2[i])) A3.append(mult(f3[i])) # signer one checks others' values RHS2 = INF RHS3 = INF for i in range(m): RHS2 = ec.add(RHS2, mult(pow(1, i), A2[i])) RHS3 = ec.add(RHS3, mult(pow(1, i), A3[i])) assert mult(alpha21) == RHS2, "signer two is cheating" assert mult(alpha31) == RHS3, "signer three is cheating" # signer two checks others' values RHS1 = INF RHS3 = INF for i in range(m): RHS1 = ec.add(RHS1, mult(pow(2, i), A1[i])) RHS3 = ec.add(RHS3, mult(pow(2, i), A3[i])) assert mult(alpha12) == RHS1, "signer one is cheating" assert mult(alpha32) == RHS3, "signer three is cheating" # signer three checks others' values RHS1 = INF RHS2 = INF for i in range(m): RHS1 = ec.add(RHS1, mult(pow(3, i), A1[i])) RHS2 = ec.add(RHS2, mult(pow(3, i), A2[i])) assert mult(alpha13) == RHS1, "signer one is cheating" assert mult(alpha23) == RHS2, "signer two is cheating" # commitment at the global sharing polynomial A: List[Point] = [] for i in range(m): A.append(ec.add(A1[i], ec.add(A2[i], A3[i]))) # aggregated public key Q = A[0] if Q[1] % 2: # print('Q has been negated') A[1] = ec.negate(A[1]) # pragma: no cover alpha1 = ec.n - alpha1 # pragma: no cover alpha2 = ec.n - alpha2 # pragma: no cover alpha3 = ec.n - alpha3 # pragma: no cover Q = ec.negate(Q) # pragma: no cover # SECOND PHASE: generation of the nonces' pair ###################### # Assume signer one and three want to sign msg = "message to sign" # 2.1 signer one acting as the dealer commits1 = [] k1 = ssa.det_nonce(msg, q1, ec, hf) k1_prime = ssa.det_nonce(msg, q1_prime, ec, hf) commits1.append(double_mult(k1_prime, H, k1, ec.G)) # sharing polynomials f1 = [k1] f1_prime = [k1_prime] for i in range(1, m): f1.append(ssa.gen_keys()[0]) f1_prime.append(ssa.gen_keys()[0]) commits1.append(double_mult(f1_prime[i], H, f1[i], ec.G)) # shares of the secret beta13 = 0 # share of k1 belonging to signer three beta13_prime = 0 for i in range(m): beta13 += (f1[i] * pow(3, i)) % ec.n beta13_prime += (f1_prime[i] * pow(3, i)) % ec.n # signer three verifies consistency of his share RHS = INF for i in range(m): RHS = ec.add(RHS, mult(pow(3, i), commits1[i])) t = double_mult(beta13_prime, H, beta13, ec.G) assert t == RHS, "signer one is cheating" # 2.2 signer three acting as the dealer commits3 = [] k3 = ssa.det_nonce(msg, q3, ec, hf) k3_prime = ssa.det_nonce(msg, q3_prime, ec, hf) commits3.append(double_mult(k3_prime, H, k3, ec.G)) # sharing polynomials f3 = [k3] f3_prime = [k3_prime] for i in range(1, m): f3.append(ssa.gen_keys()[0]) f3_prime.append(ssa.gen_keys()[0]) commits3.append(double_mult(f3_prime[i], H, f3[i], ec.G)) # shares of the secret beta31 = 0 # share of k3 belonging to signer one beta31_prime = 0 for i in range(m): beta31 += (f3[i] * pow(1, i)) % ec.n beta31_prime += (f3_prime[i] * pow(1, i)) % ec.n # signer one verifies consistency of his share RHS = INF for i in range(m): RHS = ec.add(RHS, mult(pow(1, i), commits3[i])) t = double_mult(beta31_prime, H, beta31, ec.G) assert t == RHS, "signer three is cheating" # 2.3 shares of the secret nonce beta1 = beta31 % ec.n beta3 = beta13 % ec.n for i in range(m): beta1 += (f1[i] * pow(1, i)) % ec.n beta3 += (f3[i] * pow(3, i)) % ec.n # 2.4 it's time to recover the public nonce # each participant i = 1, 3 shares Qi as follows B1: List[Point] = [] B3: List[Point] = [] for i in range(m): B1.append(mult(f1[i])) B3.append(mult(f3[i])) # signer one checks values from signer three RHS3 = INF for i in range(m): RHS3 = ec.add(RHS3, mult(pow(1, i), B3[i])) assert mult(beta31) == RHS3, "signer three is cheating" # signer three checks values from signer one RHS1 = INF for i in range(m): RHS1 = ec.add(RHS1, mult(pow(3, i), B1[i])) assert mult(beta13) == RHS1, "signer one is cheating" # commitment at the global sharing polynomial B: List[Point] = [] for i in range(m): B.append(ec.add(B1[i], B3[i])) # aggregated public nonce K = B[0] if K[1] % 2: # print('K has been negated') B[1] = ec.negate(B[1]) # pragma: no cover beta1 = ec.n - beta1 # pragma: no cover beta3 = ec.n - beta3 # pragma: no cover K = ec.negate(K) # pragma: no cover # PHASE THREE: signature generation ### # partial signatures e = ssa.challenge(msg, Q[0], K[0], ec, hf) gamma1 = (beta1 + e * alpha1) % ec.n gamma3 = (beta3 + e * alpha3) % ec.n # each participant verifies the other partial signatures # signer one RHS3 = ec.add(K, mult(e, Q)) for i in range(1, m): temp = double_mult(pow(3, i), B[i], e * pow(3, i), A[i]) RHS3 = ec.add(RHS3, temp) assert mult(gamma3) == RHS3, "signer three is cheating" # signer three RHS1 = ec.add(K, mult(e, Q)) for i in range(1, m): temp = double_mult(pow(1, i), B[i], e * pow(1, i), A[i]) RHS1 = ec.add(RHS1, temp) assert mult(gamma1) == RHS1, "signer one is cheating" # PHASE FOUR: aggregating the signature ### omega1 = 3 * mod_inv(3 - 1, ec.n) % ec.n omega3 = 1 * mod_inv(1 - 3, ec.n) % ec.n sigma = (gamma1 * omega1 + gamma3 * omega3) % ec.n sig = K[0], sigma assert ssa.verify(msg, Q[0], sig) # ADDITIONAL PHASE: reconstruction of the private key ### secret = (omega1 * alpha1 + omega3 * alpha3) % ec.n assert (q1 + q2 + q3) % ec.n in (secret, ec.n - secret)
def test_threshold(self): """testing 2-of-3 threshold signature (Pedersen secret sharing)""" ec = secp256k1 hf = sha256 # parameters t = 2 H = second_generator(ec, hf) msg = hf(b'message to sign').digest() ### FIRST PHASE: key pair generation ### # signer one acting as the dealer commits1: List[Point] = list() q1 = (1 + random.getrandbits(ec.nlen)) % ec.n q1_prime = (1 + random.getrandbits(ec.nlen)) % ec.n commits1.append(double_mult(q1_prime, H, q1)) # sharing polynomials f1: List[int] = list() f1.append(q1) f1_prime: List[int] = list() f1_prime.append(q1_prime) for i in range(1, t): temp = (1 + random.getrandbits(ec.nlen)) % ec.n f1.append(temp) temp = (1 + random.getrandbits(ec.nlen)) % ec.n f1_prime.append(temp) commits1.append(double_mult(f1_prime[i], H, f1[i])) # shares of the secret alpha12 = 0 # share of q1 belonging to P2 alpha12_prime = 0 alpha13 = 0 # share of q1 belonging to P3 alpha13_prime = 0 for i in range(t): alpha12 += (f1[i] * pow(2, i)) % ec.n alpha12_prime += (f1_prime[i] * pow(2, i)) % ec.n alpha13 += (f1[i] * pow(3, i)) % ec.n alpha13_prime += (f1_prime[i] * pow(3, i)) % ec.n # player two verifies consistency of his share RHS = 1, 0 for i in range(t): RHS = ec.add(RHS, mult(pow(2, i), commits1[i])) assert double_mult(alpha12_prime, H, alpha12) == RHS, 'player one is cheating' # player three verifies consistency of his share RHS = 1, 0 for i in range(t): RHS = ec.add(RHS, mult(pow(3, i), commits1[i])) assert double_mult(alpha13_prime, H, alpha13) == RHS, 'player one is cheating' # signer two acting as the dealer commits2: List[Point] = list() q2 = (1 + random.getrandbits(ec.nlen)) % ec.n q2_prime = (1 + random.getrandbits(ec.nlen)) % ec.n commits2.append(double_mult(q2_prime, H, q2)) # sharing polynomials f2: List[int] = list() f2.append(q2) f2_prime: List[int] = list() f2_prime.append(q2_prime) for i in range(1, t): temp = (1 + random.getrandbits(ec.nlen)) % ec.n f2.append(temp) temp = (1 + random.getrandbits(ec.nlen)) % ec.n f2_prime.append(temp) commits2.append(double_mult(f2_prime[i], H, f2[i])) # shares of the secret alpha21 = 0 # share of q2 belonging to P1 alpha21_prime = 0 alpha23 = 0 # share of q2 belonging to P3 alpha23_prime = 0 for i in range(t): alpha21 += (f2[i] * pow(1, i)) % ec.n alpha21_prime += (f2_prime[i] * pow(1, i)) % ec.n alpha23 += (f2[i] * pow(3, i)) % ec.n alpha23_prime += (f2_prime[i] * pow(3, i)) % ec.n # player one verifies consistency of his share RHS = 1, 0 for i in range(t): RHS = ec.add(RHS, mult(pow(1, i), commits2[i])) assert double_mult(alpha21_prime, H, alpha21) == RHS, 'player two is cheating' # player three verifies consistency of his share RHS = 1, 0 for i in range(t): RHS = ec.add(RHS, mult(pow(3, i), commits2[i])) assert double_mult(alpha23_prime, H, alpha23) == RHS, 'player two is cheating' # signer three acting as the dealer commits3: List[Point] = list() q3 = (1 + random.getrandbits(ec.nlen)) % ec.n q3_prime = (1 + random.getrandbits(ec.nlen)) % ec.n commits3.append(double_mult(q3_prime, H, q3)) # sharing polynomials f3: List[int] = list() f3.append(q3) f3_prime: List[int] = list() f3_prime.append(q3_prime) for i in range(1, t): temp = (1 + random.getrandbits(ec.nlen)) % ec.n f3.append(temp) temp = (1 + random.getrandbits(ec.nlen)) % ec.n f3_prime.append(temp) commits3.append(double_mult(f3_prime[i], H, f3[i])) # shares of the secret alpha31 = 0 # share of q3 belonging to P1 alpha31_prime = 0 alpha32 = 0 # share of q3 belonging to P2 alpha32_prime = 0 for i in range(t): alpha31 += (f3[i] * pow(1, i)) % ec.n alpha31_prime += (f3_prime[i] * pow(1, i)) % ec.n alpha32 += (f3[i] * pow(2, i)) % ec.n alpha32_prime += (f3_prime[i] * pow(2, i)) % ec.n # player one verifies consistency of his share RHS = 1, 0 for i in range(t): RHS = ec.add(RHS, mult(pow(1, i), commits3[i])) assert double_mult(alpha31_prime, H, alpha31) == RHS, 'player three is cheating' # player two verifies consistency of his share RHS = 1, 0 for i in range(t): RHS = ec.add(RHS, mult(pow(2, i), commits3[i])) assert double_mult(alpha32_prime, H, alpha32) == RHS, 'player two is cheating' # shares of the secret key q = q1 + q2 + q3 alpha1 = (alpha21 + alpha31) % ec.n alpha2 = (alpha12 + alpha32) % ec.n alpha3 = (alpha13 + alpha23) % ec.n for i in range(t): alpha1 += (f1[i] * pow(1, i)) % ec.n alpha2 += (f2[i] * pow(2, i)) % ec.n alpha3 += (f3[i] * pow(3, i)) % ec.n # it's time to recover the public key Q = Q1 + Q2 + Q3 = (q1 + q2 + q3)G A1: List[Point] = list() A2: List[Point] = list() A3: List[Point] = list() # each participant i = 1, 2, 3 shares Qi as follows # he broadcasts these values for i in range(t): A1.append(mult(f1[i])) A2.append(mult(f2[i])) A3.append(mult(f3[i])) # he checks the others' values # player one RHS2 = 1, 0 RHS3 = 1, 0 for i in range(t): RHS2 = ec.add(RHS2, mult(pow(1, i), A2[i])) RHS3 = ec.add(RHS3, mult(pow(1, i), A3[i])) assert mult(alpha21) == RHS2, 'player two is cheating' assert mult(alpha31) == RHS3, 'player three is cheating' # player two RHS1 = 1, 0 RHS3 = 1, 0 for i in range(t): RHS1 = ec.add(RHS1, mult(pow(2, i), A1[i])) RHS3 = ec.add(RHS3, mult(pow(2, i), A3[i])) assert mult(alpha12) == RHS1, 'player one is cheating' assert mult(alpha32) == RHS3, 'player three is cheating' # player three RHS1 = 1, 0 RHS2 = 1, 0 for i in range(t): RHS1 = ec.add(RHS1, mult(pow(3, i), A1[i])) RHS2 = ec.add(RHS2, mult(pow(3, i), A2[i])) assert mult(alpha13) == RHS1, 'player one is cheating' assert mult(alpha23) == RHS2, 'player two is cheating' A: List[Point] = list() # commitment at the global sharing polynomial for i in range(t): A.append(ec.add(A1[i], ec.add(A2[i], A3[i]))) Q = A[0] # aggregated public key ### SECOND PHASE: generation of the nonces' pair ### # This phase follows exactly the key generation procedure # suppose that player one and three want to sign # signer one acting as the dealer commits1: List[Point] = list() k1 = (1 + random.getrandbits(ec.nlen)) % ec.n k1_prime = (1 + random.getrandbits(ec.nlen)) % ec.n commits1.append(double_mult(k1_prime, H, k1)) # sharing polynomials f1: List[int] = list() f1.append(k1) f1_prime: List[int] = list() f1_prime.append(k1_prime) for i in range(1, t): temp = (1 + random.getrandbits(ec.nlen)) % ec.n f1.append(temp) temp = (1 + random.getrandbits(ec.nlen)) % ec.n f1_prime.append(temp) commits1.append(double_mult(f1_prime[i], H, f1[i])) # shares of the secret beta13 = 0 # share of k1 belonging to P3 beta13_prime = 0 for i in range(t): beta13 += (f1[i] * pow(3, i)) % ec.n beta13_prime += (f1_prime[i] * pow(3, i)) % ec.n # player three verifies consistency of his share RHS = 1, 0 for i in range(t): RHS = ec.add(RHS, mult(pow(3, i), commits1[i])) assert double_mult(beta13_prime, H, beta13) == RHS, 'player one is cheating' # signer three acting as the dealer commits3: List[Point] = list() k3 = (1 + random.getrandbits(ec.nlen)) % ec.n k3_prime = (1 + random.getrandbits(ec.nlen)) % ec.n commits3.append(double_mult(k3_prime, H, k3)) # sharing polynomials f3: List[int] = list() f3.append(k3) f3_prime: List[int] = list() f3_prime.append(k3_prime) for i in range(1, t): temp = (1 + random.getrandbits(ec.nlen)) % ec.n f3.append(temp) temp = (1 + random.getrandbits(ec.nlen)) % ec.n f3_prime.append(temp) commits3.append(double_mult(f3_prime[i], H, f3[i])) # shares of the secret beta31 = 0 # share of k3 belonging to P1 beta31_prime = 0 for i in range(t): beta31 += (f3[i] * pow(1, i)) % ec.n beta31_prime += (f3_prime[i] * pow(1, i)) % ec.n # player one verifies consistency of his share RHS = 1, 0 for i in range(t): RHS = ec.add(RHS, mult(pow(1, i), commits3[i])) assert double_mult(beta31_prime, H, beta31) == RHS, 'player three is cheating' # shares of the secret nonce beta1 = beta31 % ec.n beta3 = beta13 % ec.n for i in range(t): beta1 += (f1[i] * pow(1, i)) % ec.n beta3 += (f3[i] * pow(3, i)) % ec.n # it's time to recover the public nonce B1: List[Point] = list() B3: List[Point] = list() # each participant i = 1, 3 shares Qi as follows # he broadcasts these values for i in range(t): B1.append(mult(f1[i])) B3.append(mult(f3[i])) # he checks the others' values # player one RHS3 = 1, 0 for i in range(t): RHS3 = ec.add(RHS3, mult(pow(1, i), B3[i])) assert mult(beta31) == RHS3, 'player three is cheating' # player three RHS1 = 1, 0 for i in range(t): RHS1 = ec.add(RHS1, mult(pow(3, i), B1[i])) assert mult(beta13) == RHS1, 'player one is cheating' B: List[Point] = list() # commitment at the global sharing polynomial for i in range(t): B.append(ec.add(B1[i], B3[i])) K = B[0] # aggregated public nonce if legendre_symbol(K[1], ec._p) != 1: beta1 = ec.n - beta1 beta3 = ec.n - beta3 ### PHASE THREE: signature generation ### # partial signatures ebytes = K[0].to_bytes(32, byteorder='big') ebytes += octets_from_point(Q, True, ec) ebytes += msg e = int_from_bits(hf(ebytes).digest(), ec) gamma1 = (beta1 + e * alpha1) % ec.n gamma3 = (beta3 + e * alpha3) % ec.n # each participant verifies the other partial signatures # player one if legendre_symbol(K[1], ec._p) == 1: RHS3 = ec.add(K, mult(e, Q)) for i in range(1, t): temp = double_mult(pow(3, i), B[i], e * pow(3, i), A[i]) RHS3 = ec.add(RHS3, temp) else: assert legendre_symbol(K[1], ec._p) != 1 RHS3 = ec.add(ec.opposite(K), mult(e, Q)) for i in range(1, t): temp = double_mult(pow(3, i), ec.opposite(B[i]), e * pow(3, i), A[i]) RHS3 = ec.add(RHS3, temp) assert mult(gamma3) == RHS3, 'player three is cheating' # player three if legendre_symbol(K[1], ec._p) == 1: RHS1 = ec.add(K, mult(e, Q)) for i in range(1, t): temp = double_mult(pow(1, i), B[i], e * pow(1, i), A[i]) RHS1 = ec.add(RHS1, temp) else: assert legendre_symbol(K[1], ec._p) != 1 RHS1 = ec.add(ec.opposite(K), mult(e, Q)) for i in range(1, t): temp = double_mult(pow(1, i), ec.opposite(B[i]), e * pow(1, i), A[i]) RHS1 = ec.add(RHS1, temp) assert mult(gamma1) == RHS1, 'player two is cheating' ### PHASE FOUR: aggregating the signature ### omega1 = 3 * mod_inv(3 - 1, ec.n) % ec.n omega3 = 1 * mod_inv(1 - 3, ec.n) % ec.n sigma = (gamma1 * omega1 + gamma3 * omega3) % ec.n sig = K[0], sigma self.assertTrue(ssa._verify(msg, Q, sig)) ### ADDITIONAL PHASE: reconstruction of the private key ### secret = (omega1 * alpha1 + omega3 * alpha3) % ec.n self.assertEqual((q1 + q2 + q3) % ec.n, secret)