{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## A tutorial on how to use AVIsogenies in SageMath\n", "\n", "With this notebook we introduce the main functionalities of the AVIsogenies package.\n", "\n", "### Table of contents\n", "\n", "1. [Introduction](#intro)\n", "2. [Basic arithmetic](#arithmetic)\n", "3. [Morphisms](#morphisms)\n", " * [In level 4](#m-lvl4)\n", " * [In level 2](#m-lvl2)\n", " * [Change of coordinates](#m-change)\n", "\n", "\n", "\n", "### Introduction \n", "\n", "To import the functionalities of this package, start with the following line:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "from avisogenies_sage import *" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The following cell shows how to create an Abelian Variety with theta structure, by giving its Theta Null point." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "FF = GF(331); n = 2; g = 2\n", "\n", "pt = [328 , 213 , 75 , 1]\n", "A = KummerVariety(FF, g, pt)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is possible to check that the given point is a valid Theta Null point. It checks that the given data satisfies the Riemann Relations. This is not tested unless it is specified." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Abelian variety of dimension 1 with theta null point (26 : 191 : 70 : 130) defined over Finite Field of size 331" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "B = AbelianVariety(GF(331), 4, 1, [26, 191, 70, 130]); B" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "scrolled": true, "tags": [ "raises-exception" ] }, "outputs": [ { "ename": "ValueError", "evalue": "The given list does not define a valid thetanullpoint", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m/tmp/ipykernel_44692/81372161.py\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mB\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mAbelianVariety\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mGF\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mInteger\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m331\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mInteger\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m4\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mInteger\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m[\u001b[0m\u001b[0mInteger\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m26\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mInteger\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m191\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mInteger\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m70\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mInteger\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m130\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcheck\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;32m~/anaconda3/envs/sage-cgf/lib/python3.10/site-packages/avisogenies_sage/constructor.py\u001b[0m in \u001b[0;36mAbelianVariety\u001b[1;34m(*data, **kwargs)\u001b[0m\n\u001b[0;32m 86\u001b[0m \u001b[0mdata\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mdata\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0mdata\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 87\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mtheta_null_point\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mKummerVariety\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 88\u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0mtheta_null_point\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mAbelianVariety_ThetaStructure\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 89\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 90\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mModularAbelianVariety\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;32m~/anaconda3/envs/sage-cgf/lib/python3.10/site-packages/avisogenies_sage/theta_null_point.py\u001b[0m in \u001b[0;36m__init__\u001b[1;34m(self, R, n, g, T, check)\u001b[0m\n\u001b[0;32m 532\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 533\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0many\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mT\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0midx\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m-\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m!=\u001b[0m \u001b[0mval\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mi\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mval\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mzip\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mD\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mT\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 534\u001b[1;33m \u001b[1;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'The given list does not define a valid thetanullpoint'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 535\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 536\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0midxi\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mi\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0midxj\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mj\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mproduct\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0menumerate\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mD\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mrepeat\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;31mValueError\u001b[0m: The given list does not define a valid thetanullpoint" ] } ], "source": [ "B = AbelianVariety(GF(331), 4, 1, [26, 191, 70, 130], check=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The following cell shows how to define a point in the constructed abelian variety." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "P0 = A(0)\n", "P = A([255 , 89 , 30 , 1])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As with the theta null point, it is possible to check that the given data defines a valid point, but it is not tested unless it is specified. For that we need to use the AbelianVariety method `point`." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "Q = B([1 , 1 , 1 , 1])" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "tags": [ "raises-exception" ] }, "outputs": [ { "ename": "AttributeError", "evalue": "'AbelianVarietyPoint' object has no attribute 'level'", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m/tmp/ipykernel_44692/3498440664.py\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mQ\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mB\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mpoint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mInteger\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m,\u001b[0m \u001b[0mInteger\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m,\u001b[0m \u001b[0mInteger\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m,\u001b[0m \u001b[0mInteger\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcheck\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;32m~/anaconda3/envs/sage-cgf/lib/python3.10/site-packages/avisogenies_sage/theta_null_point.py\u001b[0m in \u001b[0;36mpoint\u001b[1;34m(self, P, **kwds)\u001b[0m\n\u001b[0;32m 235\u001b[0m \u001b[0mAP\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mA\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mP\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 236\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mAP\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mto_algebraic\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mA\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 237\u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_point\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mP\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwds\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 238\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 239\u001b[0m \u001b[0m__call__\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mpoint\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;32m~/anaconda3/envs/sage-cgf/lib/python3.10/site-packages/avisogenies_sage/theta_point.py\u001b[0m in \u001b[0;36m__init__\u001b[1;34m(self, X, v, check)\u001b[0m\n\u001b[0;32m 788\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mcheck\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 789\u001b[0m \u001b[0mO\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mX\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtheta_null_point\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 790\u001b[1;33m \u001b[0midx\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mpartial\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtools\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0midx\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mn\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mO\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlevel\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 791\u001b[0m \u001b[0mdual\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mX\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_dual\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 792\u001b[0m \u001b[0mD\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mX\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_D\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;32m~/anaconda3/envs/sage-cgf/lib/python3.10/site-packages/sage/structure/element.pyx\u001b[0m in \u001b[0;36msage.structure.element.Element.__getattr__ (build/cythonized/sage/structure/element.c:4826)\u001b[1;34m()\u001b[0m\n\u001b[0;32m 492\u001b[0m \u001b[0mAttributeError\u001b[0m\u001b[1;33m:\u001b[0m \u001b[1;34m'LeftZeroSemigroup_with_category.element_class'\u001b[0m \u001b[0mobject\u001b[0m \u001b[0mhas\u001b[0m \u001b[0mno\u001b[0m \u001b[0mattribute\u001b[0m \u001b[1;34m'blah_blah'\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 493\u001b[0m \"\"\"\n\u001b[1;32m--> 494\u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mgetattr_from_category\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mname\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 495\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 496\u001b[0m \u001b[0mcdef\u001b[0m \u001b[0mgetattr_from_category\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mname\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;32m~/anaconda3/envs/sage-cgf/lib/python3.10/site-packages/sage/structure/element.pyx\u001b[0m in \u001b[0;36msage.structure.element.Element.getattr_from_category (build/cythonized/sage/structure/element.c:4938)\u001b[1;34m()\u001b[0m\n\u001b[0;32m 505\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 506\u001b[0m \u001b[0mcls\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mP\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_abstract_element_class\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 507\u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0mgetattr_from_other_class\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcls\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mname\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 508\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 509\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0m__dir__\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;32m~/anaconda3/envs/sage-cgf/lib/python3.10/site-packages/sage/cpython/getattr.pyx\u001b[0m in \u001b[0;36msage.cpython.getattr.getattr_from_other_class (build/cythonized/sage/cpython/getattr.c:2702)\u001b[1;34m()\u001b[0m\n\u001b[0;32m 359\u001b[0m \u001b[0mdummy_error_message\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcls\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mtype\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 360\u001b[0m \u001b[0mdummy_error_message\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mname\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mname\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 361\u001b[1;33m \u001b[1;32mraise\u001b[0m \u001b[0mAttributeError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdummy_error_message\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 362\u001b[0m \u001b[0mattribute\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m<\u001b[0m\u001b[0mobject\u001b[0m\u001b[1;33m>\u001b[0m\u001b[0mattr\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 363\u001b[0m \u001b[1;31m# Check for a descriptor (__get__ in Python)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;31mAttributeError\u001b[0m: 'AbelianVarietyPoint' object has no attribute 'level'" ] } ], "source": [ "Q = B.point([1 , 1 , 1 , 1], check=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can access a given coordinate using the corresponding element of $(\\mathbb{Z}/n\\mathbb{Z})^g$:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "89" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "P[[1,0]]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Basic arithmetic \n", "Follows the example in Section 6 of 'Efficient Pairing Computation with theta functions' by David Lubicz and Damien Robert." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l = 1889\n", "lP = l*P; lP\n", "lP == A(0) #as projective points" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "((221*t^3 + 178*t^2 + 126*t + 27 : 32*t^3 + 17*t^2 + 175*t + 171 : 180*t^3 + 188*t^2 + 161*t + 119 : 261*t^3 + 107*t^2 + 37*t + 135),\n", " (1 : 56*t^3 + 312*t^2 + 147*t + 287 : 277*t^3 + 295*t^2 + 7*t + 287 : 290*t^3 + 203*t^2 + 274*t + 10))" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "R. = PolynomialRing(FF)\n", "poly = X^4 + 3*X^2 + 290*X + 3\n", "FF2. = poly.splitting_field()\n", "\n", "Q_list = [158*t^3 + 67*t^2 + 9*t + 293, 290*t^3 + 25*t^2 + 235*t + 280,\n", " 155*t^3 + 84*t^2 + 15*t + 170, 1]\n", "A2 = A.change_ring(FF2)\n", "P = A2(P)\n", "Q = A2(Q_list)\n", "\n", "P + Q #returns P + Q and P - Q" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(261*t^3 + 107*t^2 + 37*t + 135 : 205*t^3 + 88*t^2 + 195*t + 125 : 88*t^3 + 99*t^2 + 164*t + 98 : 159*t^3 + 279*t^2 + 254*t + 276)" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "PmQ_list = (62*t^3 + 16*t^2 + 255*t + 129 , 172*t^3 + 157*t^2 + 43*t + 222 ,\n", " 258*t^3 + 39*t^2 + 313*t + 150 , 1)\n", "PmQ = A2.point(PmQ_list)\n", "\n", "PQ = Q.diff_add(P, PmQ); PQ" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "17*t^3 + 153*t^2 + 305*t + 187" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "P.weil_pairing(l, Q, PQ)" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "17*t^3 + 153*t^2 + 305*t + 187" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lPQ, lP = P.diff_multadd(l, PQ, Q)\n", "PlQ, lQ = Q.diff_multadd(l, PQ, P)\n", "P._weil_pairing_from_points(Q, lP, lQ, lPQ, PlQ)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Computing points from other data \n", "\n", "This section focuses on the computation of morphisms between hyperelliptic curves and the corresponding abelian varieties (their jacobians) with theta functions of level 2 and 4.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can define a curve and its Jacobian" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Hyperelliptic Curve over Finite Field in z2 of size 83^2 defined by y^2 = x^5 + 44*x^4 + 28*x^3 + 23*x^2 + 70*x" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "F = GF(83^2); z, = F.gens(); Fx. = PolynomialRing(F)\n", "\n", "g = 2\n", "a = [F(0), 1, 3, 15, 20]\n", "rac = sqrt(a[1] - a[0])\n", "\n", "f = prod(x - al for al in a)\n", "C = HyperellipticCurve(f); C" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The most natural way to construct the corresponding Abelian Variety is with the function `AbelianVariety.from_curve`:" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Abelian variety of dimension 2 with theta null point (68 : z2 + 33 : 46 : z2 + 33 : 2*z2 + 29 : 77*z2 + 58 : 81*z2 + 31 : 38*z2 + 16 : 8 : 67*z2 + 53 : 48 : 67*z2 + 53 : 2*z2 + 29 : 38*z2 + 16 : 81*z2 + 31 : 77*z2 + 58) defined over Finite Field in z2 of size 83^2" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A = AbelianVariety.from_curve(C); A" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternatively, if we have the classical theta constants associated to the Jacobian, we can also use `AbelianVariety.with_theta_basis('F(2,2)')`" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "thc = [0]*(2**(2*g))\n", "idx = lambda x : ZZ(x, 2)\n", "thc[idx([0,0,0,0])]=F(1)\n", "thc[idx([0,0,1,1])]=z^1491\n", "thc[idx([0,0,1,0])]=z^777\n", "thc[idx([0,0,0,1])]=F(30)\n", "thc[idx([1,0,0,0])]=F(37)\n", "thc[idx([1,0,0,1])]=z^2058\n", "thc[idx([0,1,0,0])]=F(56)\n", "thc[idx([1,1,0,0])]=F(57)\n", "thc[idx([0,1,1,0])]=z^609\n", "thc[idx([1,1,1,1])]=z^1533\n", "thc[idx([0,1,0,1])]=F(0)\n", "thc[idx([0,1,1,1])]=F(0)\n", "thc[idx([1,0,1,0])]=F(0)\n", "thc[idx([1,1,1,0])]=F(0)\n", "thc[idx([1,0,1,1])]=F(0)\n", "thc[idx([1,1,0,1])]=F(0)\n", "thc = AbelianVariety.with_theta_basis('F(2,2)', F, 4, g, thc, curve=C, wp=a, rac=rac)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we can map some points between Mumford and Theta representation.\n", "\n", "We define the jacobian of C and consider the Mumford divisor defined by:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(x^2 + 30*x + 15, y + (21*z2 + 71)*x + 10*z2 + 10)" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "J = Jacobian(C)\n", "u = (x-43)*(x-10); v = z^954*x + z^2518;\n", "D = J([u,v]); D" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then we can simply create a point of the abelian variety with this data:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": [ "thD = thc(D);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that, even if internally we use the classical basis for these computations, the result is always given with basis $\\mathcal{F}(4)$:" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "Abelian variety of dimension 2 with theta null point (68 : z2 + 33 : 46 : z2 + 33 : 2*z2 + 29 : 77*z2 + 58 : 81*z2 + 31 : 38*z2 + 16 : 8 : 67*z2 + 53 : 48 : 67*z2 + 53 : 2*z2 + 29 : 38*z2 + 16 : 81*z2 + 31 : 77*z2 + 58) defined over Finite Field in z2 of size 83^2" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "thD.abelian_variety()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "But one can always recover the point in terms of the basis $\\mathcal{F}(2,2)$ as follows:" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(78*z2 + 13 : 77*z2 + 26 : 43*z2 + 3 : 54*z2 + 67 : 77*z2 + 61 : 35*z2 + 2 : 31*z2 + 8 : 19*z2 + 38 : 25*z2 + 9 : z2 + 65 : 17*z2 + 75 : 18*z2 + 38 : 50*z2 + 17 : 41*z2 + 6 : 18*z2 + 48 : 39*z2 + 73)" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "thD.with_theta_basis('F(2,2)')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Conversely, if we define the theta point" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "th = [0]*(2**(2*g))\n", "th[idx([0,0,0,0])] = z^1755\n", "th[idx([0,0,1,1])] = z^1179\n", "th[idx([0,0,1,0])] = z^977\n", "th[idx([0,0,0,1])] = z^1105\n", "th[idx([1,0,0,0])] = z^352\n", "th[idx([1,0,0,1])] = z^1674\n", "th[idx([0,1,0,0])] = z^2523\n", "th[idx([1,1,0,0])] = z^5890\n", "th[idx([0,1,1,0])] = z^5051\n", "th[idx([1,1,1,1])] = z^5243\n", "th[idx([0,1,0,1])] = z^4021\n", "th[idx([0,1,1,1])] = z^4716\n", "th[idx([1,0,1,0])] = z^139\n", "th[idx([1,1,1,0])] = z^507\n", "th[idx([1,0,1,1])] = z^2832\n", "th[idx([1,1,0,1])] = z^3382\n", "th = thc(th, basis='F(2,2)')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The function `Level4ThetaPointToMumford` returns the corresponding Mumford polynomials" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from avisogenies_sage.morphisms_level4 import Level4ThetaPointToMumford\n", "u,v = Level4ThetaPointToMumford(a, rac, th.with_theta_basis('F(2,2)'))\n", "D == J([u, v])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### In level 2 \n", "\n", "First we define the curve and its Kummer surface\n", "\n", "A curve y² = f(x) is defined by a list `a` containing the roots of f(x); it is important that f be of odd degree and `a` be ordered (the Theta constants depend on this ordering).\n", "\n", "First defined the curve and the Kummer Surface" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Hyperelliptic Curve over Finite Field in z2 of size 83^2 defined by y^2 = x^5 + 44*x^4 + 28*x^3 + 23*x^2 + 70*x" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "F = GF(83^2); z, = F.gens(); Fx. = PolynomialRing(F)\n", "\n", "g = 2;\n", "a = [F(el) for el in [0,1,3,15,20]]\n", "f = prod(x - al for al in a)\n", "C = HyperellipticCurve(f); C" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The Theta constants of the Kummer surface." ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [], "source": [ "thc2 = [0]*(2**(2*g))\n", "idx = lambda x : ZZ(x, 2)\n", "thc2[idx([0,0,0,0])] = F(1)\n", "thc2[idx([0,0,1,1])] = z^2982\n", "thc2[idx([0,0,1,0])] = z^1554\n", "thc2[idx([0,0,0,1])] = F(70)\n", "thc2[idx([1,0,0,0])] = F(41)\n", "thc2[idx([1,0,0,1])] = F(76)\n", "thc2[idx([0,1,0,0])] = F(65)\n", "thc2[idx([1,1,0,0])] = F(12)\n", "thc2[idx([0,1,1,0])] = z^1218\n", "thc2[idx([1,1,1,1])] = z^3066\n", "thc2[idx([0,1,0,1])] = F(0)\n", "thc2[idx([0,1,1,1])] = F(0)\n", "thc2[idx([1,0,1,0])] = F(0)\n", "thc2[idx([1,1,1,0])] = F(0)\n", "thc2[idx([1,0,1,1])] = F(0)\n", "thc2[idx([1,1,0,1])] = F(0)\n", "thc2 = KummerVariety.with_theta_basis('F(2,2)^2', F, 2, g, thc2, curve=C, wp=a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we can map points between Mumford and Theta representations.\n", "Consider the Mumford divisor defined by:" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(x^2 + 30*x + 15, y + (21*z2 + 71)*x + 10*z2 + 10)" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "J = Jacobian(C)\n", "u = (x-43)*(x-10); v2 = (z^954*x + z^2518)^2; \n", "D = J([u,v]); D" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And as we did for level 4, we compute the corresponding point." ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [], "source": [ "th2D = thc2(D)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Conversely, define the Theta functions" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [], "source": [ "th2 = [0]*(2**(2*g))\n", "th2[idx([0,0,0,0])] = z^3608\n", "th2[idx([0,0,1,1])] = z^5026\n", "th2[idx([0,0,1,0])] = z^1654\n", "th2[idx([0,0,0,1])] = z^6408\n", "th2[idx([1,0,0,0])] = z^5576\n", "th2[idx([1,0,0,1])] = z^3952\n", "th2[idx([0,1,0,0])] = z^734\n", "th2[idx([1,1,0,0])] = z^2674\n", "th2[idx([0,1,1,0])] = z^3262\n", "th2[idx([1,1,1,1])] = z^5436\n", "th2[idx([0,1,0,1])] = F(82)\n", "th2[idx([0,1,1,1])] = z^6258\n", "th2[idx([1,0,1,0])] = z^4746\n", "th2[idx([1,1,1,0])] = z^798\n", "th2[idx([1,0,1,1])] = z^5082\n", "th2[idx([1,1,0,1])] = F(2)\n", "th2 = thc2(th2, basis='F(2,2)^2')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The function `Level2ThetaPointToMumford` returns the corresponding Mumford polynomials (u, v²)" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from avisogenies_sage.morphisms_level2 import Level2ThetaPointToMumford\n", "uth,v2th = Level2ThetaPointToMumford(a, th2.with_theta_basis('F(2,2)^2'))\n", "D == J([uth, sqrt(v2th)])" ] } ], "metadata": { "kernelspec": { "display_name": "SageMath 9.5", "language": "sage", "name": "sagemath" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.2" } }, "nbformat": 4, "nbformat_minor": 2 }