@ -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() |