Ed25519
Due Friday, 31 Oct. at 1440 ET.
Setup
Requirements
- To complete this assignment, you must:
- Create a
82directory in your271rsrepository. - This folder must be a Cargo package.
- Create a
My responsibility
- I have adapted the official Python implementation to Python3 and added type hints.
- I provide, below, functions types for all functions used in my implementation.
- I provide a
main.rsfile which performance constant setup, shows an example of using a big number library, and checks validity using one of the test cases from the official Python implementation.
Your responsibility
- You will implement all functions of
ed25519.pyin Rust. - You will ensure your code meets validity checks.
- This will be as simple as
cargo runprovided you use the providedmain.rs.
- This will be as simple as
An Aside
- You will need to use
cargo addto use external packages.- While you may use
ixand your ownSHA, this is not necessary or required.
- While you may use
- Besides using
cargo add, you could also manually update the cratesCargo.tomlfile. - I will also provide my
Cargo.tomlfile.
Provided Files
Main
src/main.rs
use num::*;
use num_bigint::BigInt;
use num_traits::Euclid;
fn main() {
// --- 1. Constant Setup ---
const B: usize = 256;
// q: int = 2**255 - 19
let q = BigInt::from(2).pow(255) - BigInt::from(19);
// l: int = 2**252 + 27742317777372353535851937790883648493
let l_suffix = BigInt::parse_bytes(b"27742317777372353535851937790883648493", 10).unwrap();
let l = BigInt::from(2).pow(252) + l_suffix;
// d: int = -121665 * inv(121666)
let n_d = BigInt::from(-121665);
let d_inv = inv(&BigInt::from(121666), &q);
let d = (n_d * d_inv).rem_euclid(&q);
// I: int = expmod(2,(q-1)//4,q)
let exponent_i = (&q - BigInt::from(1)) / BigInt::from(4);
let i_const = expmod(&BigInt::from(2), &exponent_i, &q);
// By : int = 4 * inv(5)
let by = (BigInt::from(4) * inv(&BigInt::from(5), &q)).rem_euclid(&q);
// Bx : int = xrecover(By)
let bx = xrecover(&by, &q, &d, &i_const);
// B : List[int] = [Bx % q, By % q]
let b_point: Vec<BigInt> = vec![bx.rem_euclid(&q), by.rem_euclid(&q)];
// println!("Ed25519 Constant Initialization Complete.");
// --- 2. Test Case ---
// Line 2 of this file. https://ed25519.cr.yp.to/python/sign.input
// Secret Key (32-bytes, all zeros)
// 4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c
let sk = vec![0x4c, 0xcd, 0x08, 0x9b, 0x28, 0xff, 0x96, 0xda, 0x9d, 0xb6, 0xc3, 0x46, 0xec, 0x11, 0x4e, 0x0f, 0x5b, 0x8a, 0x31, 0x9f, 0x35, 0xab, 0xa6, 0x24, 0xda, 0x8c, 0xf6, 0xed, 0x4f, 0xb8, 0xa6, 0xfb, 0x3d, 0x40, 0x17, 0xc3, 0xe8, 0x43, 0x89, 0x5a, 0x92, 0xb7, 0x0a, 0xa7, 0x4d, 0x1b, 0x7e, 0xbc, 0x9c, 0x98, 0x2c, 0xcf, 0x2e, 0xc4, 0x96, 0x8c, 0xc0, 0xcd, 0x55, 0xf1, 0x2a, 0xf4, 0x66, 0x0c];
// Message
// 72
let m = 0x72;
// 3. Generate Public Key
let pk = publickey(&sk, B, &q, &d, &b_point);
// 4. Create Signature
let sig = signature(m, &sk, &pk, B, &q, &l, &d, &b_point);
// 5. Verify Signature
dbg!(checkvalid(&sig, m, &pk, B, &q, &d, &i_const, &b_point));
}Cargo
Lib
- In this case, I do not provide function bodies, but provide types, imports, and constants.
src/lib.rs
use num_bigint::BigInt;
use num_traits::{Zero, One, ToPrimitive, Euclid};
use num_integer::Integer;
use sha2::{Digest, Sha512};
// --- Global Helpers (No Dependencies) ---
// H(m: bytes) -> bytes
fn h(m: &[u8]) -> Vec<u8> {
// bit(h: bytes, i: int) -> int
fn bit(h_val: &[u8], i: usize) -> u8 {
// expmod(b:int,e:int,m:int) -> int
pub fn expmod(b_val: &BigInt, e: &BigInt, m: &BigInt) -> BigInt {
// inv(x:int, q: &BigInt) -> int
pub fn inv(x: &BigInt, q: &BigInt) -> BigInt {
// xrecover helper (nested for local use in setup and decode)
pub fn xrecover(y: &BigInt, q: &BigInt, d: &BigInt, i_const: &BigInt) -> BigInt {
// --- Core Functions (Require Constants) ---
fn edwards(p: &Vec<BigInt>, q_val: &Vec<BigInt>, q: &BigInt, d: &BigInt) -> Vec<BigInt> {
fn scalarmult(p: &Vec<BigInt>, e: &BigInt, q: &BigInt, d: &BigInt) -> Vec<BigInt> {
fn encodeint(y: &BigInt, b: usize) -> Vec<u8> {
fn encodepoint(p: &Vec<BigInt>, b: usize) -> Vec<u8> {
pub fn publickey(sk: &[u8], b: usize, q: &BigInt, d: &BigInt, b_point: &Vec<BigInt>) -> Vec<u8> {
fn hint(m: &[u8], b: usize) -> BigInt {
pub fn signature(m: &[u8], sk: &[u8], pk: &[u8], b: usize, q: &BigInt, l: &BigInt, d: &BigInt, b_point: &Vec<BigInt>) -> Vec<u8> {
fn isoncurve(p: &Vec<BigInt>, q: &BigInt, d: &BigInt) -> bool {
fn decodeint(s: &[u8], b: usize) -> BigInt {
fn decodepoint(s: &[u8], b: usize, q: &BigInt, d: &BigInt, i_const: &BigInt) -> Result<Point, &'static str> {
pub fn checkvalid(s: &[u8], m: &[u8], pk: &[u8], b: usize, q: &BigInt, d: &BigInt, i_const: &BigInt, b_point: &Vec<BigInt>) -> bool {