Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean up and include discrete logarithm functions into fmpz_mod #85

Merged
merged 16 commits into from
Sep 19, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 39 additions & 8 deletions src/flint/flintlib/fmpz_mod.pxd
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from flint.flintlib.flint cimport ulong, slong
from flint.flintlib.fmpz cimport fmpz_t, fmpz_preinvn_struct
from flint.flintlib.fmpz cimport fmpz_t, fmpz_struct, fmpz_preinvn_struct
from flint.flintlib.nmod cimport nmod_t

# unimported types {'fmpz_mod_discrete_log_pohlig_hellman_t'}

cdef extern from "flint/fmpz_mod.h":
#
# fmpz_mod structs, a la Pohlig - Hellman
#
ctypedef struct fmpz_mod_ctx_struct:
fmpz_t n
nmod_t mod
Expand All @@ -13,6 +14,36 @@ cdef extern from "flint/fmpz_mod.h":
fmpz_preinvn_struct * ninv_huge
ctypedef fmpz_mod_ctx_struct fmpz_mod_ctx_t[1]

#
# discrete logs structs, a la Pohlig - Hellman
#

ctypedef struct fmpz_mod_discrete_log_pohlig_hellman_table_entry_struct:
fmpz_t gammapow
ulong cm

ctypedef struct fmpz_mod_discrete_log_pohlig_hellman_entry_struct:
slong exp
ulong prime
fmpz_t gamma
fmpz_t gammainv
fmpz_t startingbeta
fmpz_t co
fmpz_t startinge
fmpz_t idem
ulong cbound
ulong dbound
fmpz_mod_discrete_log_pohlig_hellman_table_entry_struct * table # length cbound */

ctypedef struct fmpz_mod_discrete_log_pohlig_hellman_struct:
fmpz_mod_ctx_t fpctx
fmpz_t pm1 # p - 1 */
fmpz_t alpha # p.r. of p */
fmpz_t alphainv
slong num_factors # factors of p - 1
fmpz_mod_discrete_log_pohlig_hellman_entry_struct * entries
ctypedef fmpz_mod_discrete_log_pohlig_hellman_struct fmpz_mod_discrete_log_pohlig_hellman_t[1]

# Parsed from here
void fmpz_mod_ctx_init(fmpz_mod_ctx_t ctx, const fmpz_t n)
void fmpz_mod_ctx_clear(fmpz_mod_ctx_t ctx)
Expand All @@ -37,9 +68,9 @@ cdef extern from "flint/fmpz_mod.h":
int fmpz_mod_divides(fmpz_t a, const fmpz_t b, const fmpz_t c, const fmpz_mod_ctx_t ctx)
void fmpz_mod_pow_ui(fmpz_t a, const fmpz_t b, ulong e, const fmpz_mod_ctx_t ctx)
int fmpz_mod_pow_fmpz(fmpz_t a, const fmpz_t b, const fmpz_t e, const fmpz_mod_ctx_t ctx)
# void fmpz_mod_discrete_log_pohlig_hellman_init(fmpz_mod_discrete_log_pohlig_hellman_t L)
# void fmpz_mod_discrete_log_pohlig_hellman_clear(fmpz_mod_discrete_log_pohlig_hellman_t L)
# double fmpz_mod_discrete_log_pohlig_hellman_precompute_prime(fmpz_mod_discrete_log_pohlig_hellman_t L, const fmpz_t p)
# const fmpz_struct * fmpz_mod_discrete_log_pohlig_hellman_primitive_root(const fmpz_mod_discrete_log_pohlig_hellman_t L)
# void fmpz_mod_discrete_log_pohlig_hellman_run(fmpz_t x, const fmpz_mod_discrete_log_pohlig_hellman_t L, const fmpz_t y)
void fmpz_mod_discrete_log_pohlig_hellman_init(fmpz_mod_discrete_log_pohlig_hellman_t L)
void fmpz_mod_discrete_log_pohlig_hellman_clear(fmpz_mod_discrete_log_pohlig_hellman_t L)
double fmpz_mod_discrete_log_pohlig_hellman_precompute_prime(fmpz_mod_discrete_log_pohlig_hellman_t L, const fmpz_t p)
const fmpz_struct * fmpz_mod_discrete_log_pohlig_hellman_primitive_root(const fmpz_mod_discrete_log_pohlig_hellman_t L)
void fmpz_mod_discrete_log_pohlig_hellman_run(fmpz_t x, const fmpz_mod_discrete_log_pohlig_hellman_t L, const fmpz_t y)
int fmpz_next_smooth_prime(fmpz_t a, const fmpz_t b)
45 changes: 45 additions & 0 deletions src/flint/test/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1770,6 +1770,50 @@ def test_fmpz_mod():
assert fmpz(test_y) / F_test(test_x) == (test_y * pow(test_x, -1, test_mod)) % test_mod
assert test_y / F_test(test_x) == (test_y * pow(test_x, -1, test_mod)) % test_mod

def test_fmpz_mod_dlog():
from flint import fmpz, fmpz_mod_ctx

# Input modulus must be prime
F = fmpz_mod_ctx(4)
g, a = F(1), F(2)
assert raises(lambda: g.discrete_log(a, check=True), ValueError)

# Moduli must match
F1, F2 = fmpz_mod_ctx(2), fmpz_mod_ctx(3)
g = F1(2)
a = F2(4)
assert raises(lambda: g.discrete_log(a, check=True), ValueError)

# Need to use either fmpz_mod or something which can be case to
# fmpz
assert raises(lambda: g.discrete_log("A", check=True), TypeError)

F = fmpz_mod_ctx(163)
g = F(2)
a = g**123

assert 123 == g.discrete_log(a)

a_int = pow(2, 123, 163)
a_fmpz = fmpz(a_int)
assert 123 == g.discrete_log(a_int)
assert 123 == g.discrete_log(a_fmpz)

# Randomised testing with smooth large modulus
e2, e3 = 92, 79
p = 2**e2 * 3**e3 + 1
F = fmpz_mod_ctx(p)

import random
for _ in range(10):
g = F(random.randint(0,p))
for _ in range(10):
i = random.randint(0,p)
a = g**i
x = g.discrete_log(a)
assert g**x == a



all_tests = [
test_pyflint,
Expand All @@ -1790,4 +1834,5 @@ def test_fmpz_mod():
test_nmod_mat,
test_arb,
test_fmpz_mod,
test_fmpz_mod_dlog
]
16 changes: 11 additions & 5 deletions src/flint/types/fmpz_mod.pxd
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
from flint.flint_base.flint_base cimport flint_scalar
from flint.flintlib.fmpz cimport fmpz_t
from flint.flintlib.fmpz_mod cimport fmpz_mod_ctx_t
from flint.flintlib.fmpz_mod cimport (
fmpz_mod_ctx_t,
fmpz_mod_discrete_log_pohlig_hellman_t
)


cdef class fmpz_mod_ctx:
cdef fmpz_mod_ctx_t val

cdef fmpz_mod_discrete_log_pohlig_hellman_t L
cdef bint _dlog_precomputed
cdef any_as_fmpz_mod(self, obj)
cdef _precompute_dlog_prime(self)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In memory terms the first element of L is an fmpz_mod_ctx_t which would end up being a copy of val. If we include the struct L inline here then we don't need val.

I think it is better though to just have a pointer like

cdef fmpz_mod_discrete_log_pohlig_hellman_t *L

If the pointer is set to NULL in __cinit__ then there is no need for a separate _dlog_computed variable. The _precompute_dlog_prime method can just check for NULL and then call malloc etc.

Copy link
Contributor Author

@GiacomoPope GiacomoPope Sep 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not addressed this yet. So you think I should set the pointer to NULL for __cinit__ and then when I do the normal discrete log stuff then I want to work with the pointer self.ctx.L?

I guess I can also do something similar for x_g with a pointer?

EDIT: hmmm, I'm not sure how to dereference the pointer for the dlog call... I'm pretty stupid with the cython pointers.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's like f(L[0]). You can't use f(*L) because that means something else in Python.

Copy link
Contributor Author

@GiacomoPope GiacomoPope Sep 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh got it! The real issue was my malloc which was poorly written before.

self.L = <fmpz_mod_discrete_log_pohlig_hellman_t *>libc.stdlib.malloc(cython.sizeof(fmpz_mod_discrete_log_pohlig_hellman_struct))

Seems to work

Copy link
Contributor Author

@GiacomoPope GiacomoPope Sep 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(There was no flint_malloc which I could see, so I did it this way, but we could maybe write a small function to do this?)


cdef class fmpz_mod(flint_scalar):
cdef fmpz_mod_ctx ctx
cdef fmpz_t val

cdef any_as_fmpz_mod(self, obj)

cdef bint base_dlog_precomputed
cdef fmpz_t x_g
Loading