@ -1,79 +0,0 @@ |
|||||
load("fft.sage") |
|
||||
|
|
||||
##### |
|
||||
# Roots of Unity test: |
|
||||
q = 17 |
|
||||
F = GF(q) |
|
||||
n = 4 |
|
||||
g, primitive_w = get_primitive_root_of_unity(F, n) |
|
||||
print("generator:", g) |
|
||||
print("primitive_w:", primitive_w) |
|
||||
|
|
||||
w = get_nth_roots_of_unity(n, primitive_w) |
|
||||
print(f"{n}th roots of unity: {w}") |
|
||||
assert w == [1, 13, 16, 4] |
|
||||
|
|
||||
|
|
||||
##### |
|
||||
# FFT test: |
|
||||
|
|
||||
def isprime(num): |
|
||||
for n in range(2,int(num^1/2)+1): |
|
||||
if num%n==0: |
|
||||
return False |
|
||||
return True |
|
||||
|
|
||||
# list valid values for q |
|
||||
for i in range(20): |
|
||||
if isprime(8*i+1): |
|
||||
print("q =", 8*i+1) |
|
||||
|
|
||||
q = 41 |
|
||||
F = GF(q) |
|
||||
n = 4 |
|
||||
# q needs to be a prime, s.t. q-1 is divisible by n |
|
||||
assert (q-1)%n==0 |
|
||||
print("q =", q, "n = ", n) |
|
||||
|
|
||||
# ft: Vandermonde matrix for the nth roots of unity |
|
||||
w, ft, ft_inv = fft(F, n) |
|
||||
print("nth roots of unity:", w) |
|
||||
print("Vandermonde matrix:") |
|
||||
print(ft) |
|
||||
|
|
||||
a = vector([3,4,5,9]) |
|
||||
print("a:", a) |
|
||||
|
|
||||
# interpolate f_a(x) |
|
||||
fa_coef = ft_inv * a |
|
||||
print("fa_coef:", fa_coef) |
|
||||
|
|
||||
P.<x> = PolynomialRing(F) |
|
||||
fa = P(list(fa_coef)) |
|
||||
print("f_a(x):", fa) |
|
||||
|
|
||||
# check that evaluating fa(x) at the roots of unity returns the expected values of a |
|
||||
for i in range(len(a)): |
|
||||
assert fa(w[i]) == a[i] |
|
||||
|
|
||||
|
|
||||
|
|
||||
# Fast polynomial multiplicaton using FFT |
|
||||
print("\n---------") |
|
||||
print("---Fast polynomial multiplication using FFT") |
|
||||
|
|
||||
n = 8 |
|
||||
# q needs to be a prime, s.t. q-1 is divisible by n |
|
||||
assert (q-1)%n==0 |
|
||||
print("q =", q, "n = ", n) |
|
||||
|
|
||||
fa=P([1,2,3,4]) |
|
||||
fb=P([1,2,3,4]) |
|
||||
fc_expected = fa*fb |
|
||||
print("fc expected result:", fc_expected) # expected result |
|
||||
print("fc expected coef", fc_expected.coefficients()) |
|
||||
|
|
||||
fc, c_evals = poly_mul(fa, fb, F, n) |
|
||||
print("c_evals=(a_evals*b_evals)=", c_evals) |
|
||||
print("fc:", fc) |
|
||||
assert fc_expected == fc |
|
@ -1,161 +0,0 @@ |
|||||
import unittest, operator |
|
||||
load("ipa.sage") |
|
||||
|
|
||||
# Halo paper: https://eprint.iacr.org/2019/1021.pdf |
|
||||
# Bulletproofs paper: https://eprint.iacr.org/2017/1066.pdf |
|
||||
|
|
||||
# Ethereum elliptic curve |
|
||||
p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F |
|
||||
a = 0 |
|
||||
b = 7 |
|
||||
Fp = GF(p) |
|
||||
E = EllipticCurve(Fp, [a,b]) |
|
||||
GX = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798 |
|
||||
GY = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8 |
|
||||
g = E(GX,GY) |
|
||||
n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 |
|
||||
h = 1 |
|
||||
q = g.order() |
|
||||
Fq = GF(q) |
|
||||
|
|
||||
# simplier curve values |
|
||||
# p = 19 |
|
||||
# Fp = GF(p) |
|
||||
# E = EllipticCurve(Fp,[0,3]) |
|
||||
# g = E(1, 2) |
|
||||
# q = g.order() |
|
||||
# Fq = GF(q) |
|
||||
|
|
||||
print(E) |
|
||||
print(Fq) |
|
||||
assert is_prime(p) |
|
||||
assert is_prime(q) |
|
||||
assert g * q == 0 |
|
||||
|
|
||||
class TestUtils(unittest.TestCase): |
|
||||
def test_vecs(self): |
|
||||
a = [1, 2, 3, 4, 5] |
|
||||
b = [1, 2, 3, 4, 5] |
|
||||
|
|
||||
c = vec_scalar_mul_field(a, 10) |
|
||||
assert c == [10, 20, 30, 40, 50] |
|
||||
|
|
||||
c = inner_product_field(a, b) |
|
||||
assert c == 55 |
|
||||
|
|
||||
# check that <a, b> with b = (1, x, x^2, ..., x^{d-1}) is the same |
|
||||
# than evaluating p(x) with coefficients a_i, at x |
|
||||
a = [Fq(1), Fq(2), Fq(3), Fq(4), Fq(5), Fq(6), Fq(7), Fq(8)] |
|
||||
z = Fq(3) |
|
||||
b = powers_of(z, 8) |
|
||||
c = inner_product_field(a, b) |
|
||||
|
|
||||
x = PolynomialRing(Fq, 'x').gen() |
|
||||
px = 1 + 2*x + 3*x^2 + 4*x^3 + 5*x^4 + 6*x^5 + 7*x^6 + 8*x^7 |
|
||||
assert c == px(x=z) |
|
||||
|
|
||||
|
|
||||
class TestIPA_bulletproofs(unittest.TestCase): |
|
||||
def test_inner_product(self): |
|
||||
d = 8 |
|
||||
ipa = IPA_bulletproofs(Fq, E, g, d) |
|
||||
|
|
||||
# prover |
|
||||
# p(x) = 1 + 2x + 3x² + 4x³ + 5x⁴ + 6x⁵ + 7x⁶ + 8x⁷ |
|
||||
a = [ipa.F(1), ipa.F(2), ipa.F(3), ipa.F(4), ipa.F(5), ipa.F(6), ipa.F(7), ipa.F(8)] |
|
||||
x = ipa.F(3) |
|
||||
b = powers_of(x, ipa.d) # = b |
|
||||
|
|
||||
# prover |
|
||||
P = ipa.commit(a, b) |
|
||||
print("commit", P) |
|
||||
v = ipa.evaluate(a, b) |
|
||||
print("v", v) |
|
||||
|
|
||||
# verifier |
|
||||
# r = int(ipa.F.random_element()) |
|
||||
|
|
||||
# verifier generate random challenges {uᵢ} ∈ 𝕀 and U ∈ 𝔾 |
|
||||
U = ipa.E.random_element() |
|
||||
k = int(math.log(d, 2)) |
|
||||
u = [None] * k |
|
||||
for j in reversed(range(0, k)): |
|
||||
u[j] = ipa.F.random_element() |
|
||||
while (u[j] == 0): # prevent u[j] from being 0 |
|
||||
u[j] = ipa.F.random_element() |
|
||||
|
|
||||
P = P + int(inner_product_field(a, b)) * U |
|
||||
|
|
||||
# prover |
|
||||
a_ipa, b_ipa, G_ipa, H_ipa, L, R = ipa.ipa(a, b, u, U) |
|
||||
|
|
||||
# verifier |
|
||||
print("P", P) |
|
||||
print("a_ipa", a_ipa) |
|
||||
verif = ipa.verify(P, a_ipa, v, b, u, U, L, R, b_ipa, G_ipa, H_ipa) |
|
||||
print("Verification:", verif) |
|
||||
assert verif == True |
|
||||
|
|
||||
|
|
||||
class TestIPA_halo(unittest.TestCase): |
|
||||
def test_homomorphic_property(self): |
|
||||
ipa = IPA_halo(Fq, E, g, 5) |
|
||||
|
|
||||
a = [1, 2, 3, 4, 5] |
|
||||
b = [1, 2, 3, 4, 5] |
|
||||
c = vec_add(a, b) |
|
||||
assert c == [2,4,6,8,10] |
|
||||
|
|
||||
r = int(ipa.F.random_element()) |
|
||||
s = int(ipa.F.random_element()) |
|
||||
vc_a = ipa.commit(a, r) |
|
||||
vc_b = ipa.commit(b, s) |
|
||||
|
|
||||
# com(a, r) + com(b, s) == com(a+b, r+s) |
|
||||
expected_vc_c = ipa.commit(vec_add(a, b), r+s) |
|
||||
vc_c = vc_a + vc_b |
|
||||
assert vc_c == expected_vc_c |
|
||||
|
|
||||
def test_inner_product(self): |
|
||||
d = 8 |
|
||||
ipa = IPA_halo(Fq, E, g, d) |
|
||||
|
|
||||
# prover |
|
||||
# p(x) = 1 + 2x + 3x² + 4x³ + 5x⁴ + 6x⁵ + 7x⁶ + 8x⁷ |
|
||||
a = [ipa.F(1), ipa.F(2), ipa.F(3), ipa.F(4), ipa.F(5), ipa.F(6), ipa.F(7), ipa.F(8)] |
|
||||
x = ipa.F(3) |
|
||||
x_powers = powers_of(x, ipa.d) # = b |
|
||||
|
|
||||
# verifier |
|
||||
r = int(ipa.F.random_element()) |
|
||||
|
|
||||
# prover |
|
||||
P = ipa.commit(a, r) |
|
||||
print("commit", P) |
|
||||
v = ipa.evaluate(a, x_powers) |
|
||||
print("v", v) |
|
||||
|
|
||||
# verifier generate random challenges {uᵢ} ∈ 𝕀 and U ∈ 𝔾 |
|
||||
U = ipa.E.random_element() |
|
||||
k = int(math.log(ipa.d, 2)) |
|
||||
u = [None] * k |
|
||||
for j in reversed(range(0, k)): |
|
||||
u[j] = ipa.F.random_element() |
|
||||
while (u[j] == 0): # prevent u[j] from being 0 |
|
||||
u[j] = ipa.F.random_element() |
|
||||
|
|
||||
P = P + int(v) * U |
|
||||
|
|
||||
# prover |
|
||||
a_ipa, b_ipa, G_ipa, lj, rj, L, R = ipa.ipa(a, x_powers, u, U) |
|
||||
|
|
||||
# verifier |
|
||||
print("P", P) |
|
||||
print("a_ipa", a_ipa) |
|
||||
print("\n Verify:") |
|
||||
verif = ipa.verify(P, a_ipa, v, x_powers, r, u, U, lj, rj, L, R) |
|
||||
assert verif == True |
|
||||
|
|
||||
|
|
||||
if __name__ == '__main__': |
|
||||
unittest.main() |
|
@ -1,28 +0,0 @@ |
|||||
load("number-theory.sage") |
|
||||
|
|
||||
##### |
|
||||
# Chinese Remainder Theorem tests |
|
||||
a_i = [5, 3, 10] |
|
||||
m_i = [7, 11, 13] |
|
||||
assert crt(a_i, m_i) == 894 |
|
||||
|
|
||||
a_i = [3, 8] |
|
||||
m_i = [13, 17] |
|
||||
assert crt(a_i, m_i) == 42 |
|
||||
|
|
||||
|
|
||||
##### |
|
||||
# gcd, using Binary Euclidean algorithm tests |
|
||||
assert gcd(21, 12) == 3 |
|
||||
assert gcd(1_426_668_559_730, 810_653_094_756) == 1_417_082 |
|
||||
|
|
||||
assert gcd_recursive(21, 12) == 3 |
|
||||
|
|
||||
##### |
|
||||
# Extended Euclidean algorithm tests |
|
||||
assert egcd(7, 19) == (1, -8, 3) |
|
||||
assert egcd_recursive(7, 19) == (1, -8, 3) |
|
||||
|
|
||||
##### |
|
||||
# Inverse modulo N tests |
|
||||
assert inv_mod(7, 19) == 11 |
|
@ -1,56 +0,0 @@ |
|||||
import unittest, operator |
|
||||
load("ring-signatures.sage") |
|
||||
|
|
||||
# A Rust implementation of this scheme can be found at: |
|
||||
# https://github.com/arnaucube/ring-signatures-rs |
|
||||
|
|
||||
# ethereum elliptic curve |
|
||||
p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F |
|
||||
a = 0 |
|
||||
b = 7 |
|
||||
F = GF(p) |
|
||||
E = EllipticCurve(F, [a,b]) |
|
||||
GX = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798 |
|
||||
GY = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8 |
|
||||
g = E(GX,GY) |
|
||||
n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 |
|
||||
h = 1 |
|
||||
q = g.order() |
|
||||
assert is_prime(p) |
|
||||
assert is_prime(q) |
|
||||
assert g * q == 0 |
|
||||
|
|
||||
|
|
||||
class TestRingSignatures(unittest.TestCase): |
|
||||
def test_bLSAG_ring_of_5(self): |
|
||||
test_bLSAG(5, 3) |
|
||||
def test_bLSAG_ring_of_20(self): |
|
||||
test_bLSAG(20, 14) |
|
||||
|
|
||||
def test_bLSAG(ring_size, pi): |
|
||||
print(f"[bLSAG] Testing with a ring of {ring_size} keys") |
|
||||
prover = Prover(F, g) |
|
||||
n = ring_size |
|
||||
R = [None] * n |
|
||||
|
|
||||
# generate prover's key pair |
|
||||
K_pi = prover.new_key() |
|
||||
|
|
||||
# generate other n public keys |
|
||||
for i in range(0, n): |
|
||||
R[i] = g * i |
|
||||
|
|
||||
# set K_pi |
|
||||
R[pi] = K_pi |
|
||||
|
|
||||
# sign m |
|
||||
m = 1234 |
|
||||
print("sign") |
|
||||
sig = prover.sign(m, R) |
|
||||
|
|
||||
print("verify") |
|
||||
key_image = prover.w * hashToPoint(prover.K) |
|
||||
verify(g, R, m, key_image, sig) |
|
||||
|
|
||||
if __name__ == '__main__': |
|
||||
unittest.main() |
|
@ -1,131 +0,0 @@ |
|||||
import unittest, operator |
|
||||
load("sigma.sage") |
|
||||
|
|
||||
# Tests for Sigma protocol & OR proofs |
|
||||
|
|
||||
|
|
||||
# ethereum elliptic curve |
|
||||
p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F |
|
||||
a = 0 |
|
||||
b = 7 |
|
||||
F = GF(p) |
|
||||
E = EllipticCurve(F, [a,b]) |
|
||||
GX = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798 |
|
||||
GY = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8 |
|
||||
g = E(GX,GY) |
|
||||
n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 |
|
||||
h = 1 |
|
||||
q = g.order() |
|
||||
assert is_prime(p) |
|
||||
assert is_prime(q) |
|
||||
|
|
||||
class TestSigmaProtocol(unittest.TestCase): |
|
||||
def test_interactive(self): |
|
||||
alice = Prover_interactive(F, g) |
|
||||
|
|
||||
# Alice generates witness w & statement X |
|
||||
X = alice.new_key() |
|
||||
assert X == alice.g * int(alice.w) |
|
||||
|
|
||||
# Alice generates the commitment A |
|
||||
A = alice.new_commitment() |
|
||||
assert A == alice.g * int(alice.a) |
|
||||
|
|
||||
# Bob generates the challenge (and stores A) |
|
||||
bob = Verifier_interactive(F, g) |
|
||||
c = bob.new_challenge(A) |
|
||||
|
|
||||
# Alice generates the proof |
|
||||
z = alice.gen_proof(c) |
|
||||
|
|
||||
# Bob verifies the proof |
|
||||
assert bob.verify(X, z) |
|
||||
|
|
||||
# check with the generic_verify function |
|
||||
assert generic_verify(g, X, A, c, z) |
|
||||
|
|
||||
def test_non_interactive(self): |
|
||||
alice = Prover(F, g) |
|
||||
|
|
||||
# Alice generates witness w & statement X |
|
||||
X = alice.new_key() |
|
||||
assert X == alice.g * int(alice.w) |
|
||||
|
|
||||
# Alice generates the proof |
|
||||
A, z = alice.gen_proof(X) |
|
||||
|
|
||||
# Bob generates the challenge |
|
||||
bob = Verifier(F, g) |
|
||||
|
|
||||
# Bob verifies the proof |
|
||||
assert bob.verify(X, A, z) |
|
||||
|
|
||||
# check with the generic_verify function |
|
||||
c = hash_two_points(A, X) |
|
||||
assert generic_verify(g, X, A, c, z) |
|
||||
|
|
||||
def test_simulator(self): |
|
||||
sim = Simulator(F, g) |
|
||||
|
|
||||
# set a public key X, for which we don't know w |
|
||||
unknown_w = 3 |
|
||||
X = g * unknown_w |
|
||||
|
|
||||
# simulate for X |
|
||||
A, c, z = sim.simulate(X) |
|
||||
|
|
||||
# verify the simulated proof |
|
||||
assert generic_verify(g, X, A, c, z) |
|
||||
|
|
||||
class TestORProof(unittest.TestCase): |
|
||||
def test_2_parties(self): |
|
||||
# set a public key X, for which we don't know w |
|
||||
unknown_w = 3 |
|
||||
X_1 = g * unknown_w |
|
||||
|
|
||||
alice = ORProver_2parties(F, g) |
|
||||
|
|
||||
# Alice generates key pair |
|
||||
X = alice.new_key() |
|
||||
Xs = [X, X_1] |
|
||||
# Alice generates commitments (internally running the simulator) |
|
||||
As = alice.gen_commitments(Xs) |
|
||||
|
|
||||
# Bob generates the challenge (and stores As) |
|
||||
bob = ORVerifier_2parties(F, g) |
|
||||
s = bob.new_challenge(As) |
|
||||
|
|
||||
# Alice generates the ORproof |
|
||||
cs, zs = alice.gen_proof(s) |
|
||||
|
|
||||
# Bob verifies the proofs |
|
||||
bob.verify(Xs, cs, zs) |
|
||||
|
|
||||
def test_n_parties(self): |
|
||||
# set n public keys X, for which we don't know w |
|
||||
Xs = [] |
|
||||
for i in range(10): |
|
||||
X_i = g * i |
|
||||
Xs.append(X_i) |
|
||||
|
|
||||
alice = ORProver(F, g) |
|
||||
|
|
||||
# Alice generates key pair |
|
||||
X = alice.new_key() |
|
||||
Xs.insert(0, X) # add X at the begining of Xs array |
|
||||
|
|
||||
# Alice generates commitments (internally running the simulator) |
|
||||
As = alice.gen_commitments(Xs) |
|
||||
|
|
||||
# Bob generates the challenge (and stores As) |
|
||||
bob = ORVerifier(F, g) |
|
||||
s = bob.new_challenge(As) |
|
||||
|
|
||||
# Alice generates the ORproof |
|
||||
cs, zs = alice.gen_proof(s) |
|
||||
|
|
||||
# Bob verifies the proofs |
|
||||
bob.verify(Xs, cs, zs) |
|
||||
|
|
||||
if __name__ == '__main__': |
|
||||
unittest.main() |
|