Skip to content

Instantly share code, notes, and snippets.

@kelbyludwig
Created January 1, 2026 18:17
Show Gist options
  • Select an option

  • Save kelbyludwig/4af1aa477c8decc7878c58216068928d to your computer and use it in GitHub Desktop.

Select an option

Save kelbyludwig/4af1aa477c8decc7878c58216068928d to your computer and use it in GitHub Desktop.
Notebook version of https://kel.bz/post/sage-p256/
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This notebook demonstrates how to create a NIST P-256 curve ([aka secp256r1](https://tools.ietf.org/search/rfc4492#appendix-A)) and it's standard base point in [Sagemath](https://www.sagemath.org/).\n",
"\n",
"First, we define the parameters that make up the P-256 curve. The parameters are from \"[SEC 2: Recommended Elliptic Curve Domain Parameters](https://www.secg.org/SEC2-Ver-1.0.pdf)\"."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"# Finite field prime\n",
"p256 = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF\n",
"\n",
"# Curve parameters for the curve equation: y^2 = x^3 + a256*x +b256\n",
"a256 = p256 - 3 \n",
"b256 = 0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B\n",
"\n",
"# Base point (x, y) \n",
"gx = 0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296\n",
"gy = 0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5\n",
"\n",
"# Curve order\n",
"qq = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Then we can create a EllipticCurve sage object over a finite field."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# Create a finite field of order p256\n",
"FF = GF(p256) \n",
"\n",
"# Define a curve over that field with specified Weierstrass a and b parameters\n",
"EC = EllipticCurve([FF(a256), FF(b256)]) \n",
"\n",
"# Since we know P-256's order we can skip computing it and set it explicitly\n",
"EC.set_order(qq) \n",
"\n",
"# Create a variable for the base point\n",
"G = EC(FF(gx), FF(gy))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can compare results to a few [public test vectors](http://point-at-infinity.org/ecc/nisttv) to make sure everything is working as intended.\n",
"\n",
"These test vectors are defined as three-tuples: (scalar `k`, x-coordinate of `k*G`, y-coordinate of `k*G`)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"test_vectors = [\n",
" (1, \n",
" 0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296, \n",
" 0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5),\n",
" (2,\n",
" 0x7CF27B188D034F7E8A52380304B51AC3C08969E277F21B35A60B48FC47669978,\n",
" 0x07775510DB8ED040293D9AC69F7430DBBA7DADE63CE982299E04B79D227873D1),\n",
" (3,\n",
" 0x5ECBE4D1A6330A44C8F7EF951D4BF165E6C6B721EFADA985FB41661BC6E7FD6C,\n",
" 0x8734640C4998FF7E374B06CE1A64A2ECD82AB036384FB83D9A79B127A27D5032),\n",
" (4,\n",
" 0xE2534A3532D08FBBA02DDE659EE62BD0031FE2DB785596EF509302446B030852,\n",
" 0xE0F1575A4C633CC719DFEE5FDA862D764EFC96C3F30EE0055C42C23F184ED8C6),\n",
" (5,\n",
" 0x51590B7A515140D2D784C85608668FDFEF8C82FD1F5BE52421554A0DC3D033ED,\n",
" 0xE0C17DA8904A727D8AE1BF36BF8A79260D012F00D4D80888D1D0BB44FDA16DA4)\n",
"]\n",
"\n",
"for k, x, y in test_vectors:\n",
" P = k*G\n",
" Px, Py = P.xy()\n",
" assert Px == x\n",
" assert Py == y"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"That seems alright. We can do a simple ECDH to double check as well."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"for _ in range(100):\n",
" alice_private = randint(0, qq-1)\n",
" alice_public = alice_private*G\n",
"\n",
" bob_private = randint(0, qq-1)\n",
" bob_public = bob_private*G\n",
"\n",
" assert alice_private*bob_public == bob_private*alice_public"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "SageMath 8.6",
"language": "",
"name": "sagemath"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.16"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment