├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE ├── README.md ├── benchmarks └── dusk_benchmarks.rs ├── docs ├── Safe Curve criteria ├── lit.bib ├── main.tex └── zerocaf.pdf ├── examples └── basic_ops.rs ├── sage_codes ├── LFACTOR_comp ├── Point computation ├── Safe Curve code ├── curve_derivation └── sage_weierstrass_code ├── src ├── backend │ ├── mod.rs │ └── u64 │ │ ├── constants.rs │ │ ├── field.rs │ │ ├── mod.rs │ │ └── scalar.rs ├── constants.rs ├── edwards.rs ├── field.rs ├── lib.rs ├── montgomery.rs ├── ristretto.rs ├── scalar.rs └── traits.rs └── tools ├── Cargo.toml ├── kalinski_inv.py ├── src └── main.rs └── tonelli.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target 4 | /tools/target 5 | 6 | 7 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 8 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 9 | Cargo.lock 10 | /tools/Cargo.lock/ 11 | # These are backup files generated by rustfmt 12 | **/*.rs.bk 13 | 14 | ## Latex/pdflatex auxiliary files: 15 | *.aux 16 | *.bbl 17 | *.blg 18 | *.log 19 | *.out 20 | *synctex.gz 21 | *.synctex.gz(busy) 22 | *.toc 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | sudo: true 3 | cache: cargo 4 | os: 5 | - linux 6 | # - osx CodeCov doesn't support it so it's non tested now. 7 | 8 | matrix: 9 | fast_finish: false 10 | include: 11 | - rust: stable 12 | - rust: beta 13 | - rust: nightly 14 | 15 | 16 | before_install: 17 | - sudo apt-get update 18 | 19 | addons: 20 | apt: 21 | packages: 22 | - libcurl4-openssl-dev 23 | - libelf-dev 24 | - libdw-dev 25 | - cmake 26 | - gcc 27 | - binutils-dev 28 | 29 | 30 | # Main build 31 | script: 32 | - cargo check 33 | - cargo build --release --no-default-features --features "u64_backend" --verbose --all 34 | - cargo test --verbose --all 35 | 36 | # Upload docs 37 | after_success: 38 | # Coverage report 39 | - | 40 | if [[ "$TRAVIS_OS_NAME" == "linux" && "$TRAVIS_RUST_VERSION" == "stable" ]]; then 41 | wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz && 42 | tar xzf master.tar.gz && 43 | cd kcov-master && 44 | mkdir build && 45 | cd build && 46 | cmake .. && 47 | make && 48 | sudo make install && 49 | cd ../.. && 50 | rm -rf kcov-master && 51 | for file in target/debug/zerocaf-*[^\.d]; do mkdir -p "target/cov/$(basename $file)"; kcov --exclude-pattern=/.cargo,/usr/lib --verify "target/cov/$(basename $file)" "$file"; done && 52 | bash <(curl -s https://codecov.io/bash) && 53 | echo "Uploaded code coverage" 54 | fi 55 | 56 | # Upload docs 57 | - | 58 | if [[ "$TRAVIS_OS_NAME" == "linux" && "$TRAVIS_RUST_VERSION" == "stable" && "$TRAVIS_PULL_REQUEST" = "false" && "$TRAVIS_BRANCH" == "master" ]]; then 59 | cargo doc --no-deps && 60 | echo "" > target/doc/index.html && 61 | git clone https://github.com/davisp/ghp-import.git && 62 | ./ghp-import/ghp_import.py -n -p -f -m "Documentation upload" -r https://"$GH_TOKEN"@github.com/"$TRAVIS_REPO_SLUG.git" target/doc && 63 | echo "Uploaded documentation" 64 | fi 65 | 66 | # Send a notification to the Dusk build Status Telegram channel once the CI build completes 67 | after_script: 68 | - bash <(curl -s https://raw.githubusercontent.com/dusk-network/tools/master/bash/telegram_ci_notifications.sh) 69 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zerocaf" 3 | version = "0.2.0" 4 | authors = ["Luke Pearson ", 5 | "CPerezz "] 6 | readme = "README.md" 7 | documentation = "https://dusk-network.github.io/dusk-zerocaf/zerocaf/index.html" 8 | repository = "https://github.com/dusk-network/Dusk-Zerocaf" 9 | keywords = ["cryptography", "ristretto", "doppio-curve", "ECC"] 10 | categories =["Algorithms", "Cryptography", "Development tools"] 11 | description = "A pure-Rust implementation of elliptic curve operations over the Sonny-curve" 12 | exclude = [ 13 | "**/.gitignore", 14 | ".gitignore", 15 | "**/tools", 16 | "**/sage_codes", 17 | "**/examples" 18 | ] 19 | license = "MIT" 20 | edition = "2018" 21 | 22 | [dependencies] 23 | subtle = { version = "2", default-features = false } 24 | num = "0.2.0" 25 | curve25519-dalek = "1.1.3" 26 | rand = "0.7.0" 27 | 28 | [dev-dependencies] 29 | criterion = "0.3.0" 30 | rand = "0.7.0" 31 | hex = "0.3.2" 32 | 33 | 34 | # Criterion benchmarks 35 | [[bench]] 36 | path = "./benchmarks/dusk_benchmarks.rs" 37 | name = "dusk_benchmarks" 38 | harness = false 39 | 40 | 41 | [features] 42 | nightly = ["subtle/nightly"] 43 | # The u64 backend uses u64s with u128 products. 44 | u64_backend = [] 45 | default = ["u64_backend"] 46 | 47 | [profile.release] 48 | opt-level = 3 49 | incremental = false 50 | codegen-units = 1 51 | debug = false 52 | #rpath = false 53 | lto = true 54 | overflow-checks = false 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2019 - Dusk Network B.V. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dusk-Zerocaf [![Build Status](https://travis-ci.com/dusk-network/Dusk-Zerocaf.svg?branch=master)](https://travis-ci.com/dusk-network/Dusk-Zerocaf) [![codecov](https://codecov.io/gh/dusk-network/dusk-zerocaf/branch/master/graph/badge.svg)](https://codecov.io/gh/dusk-network/dusk-zerocaf) ![GitHub closed issues](https://img.shields.io/github/issues-closed/dusk-network/dusk-zerocaf.svg?color=4C4CFF) ![Crates.io](https://img.shields.io/crates/v/zerocaf.svg) 2 | 3 | 6 | 7 | # WARNING: WIP Repo. 8 | 9 | ## Fast, efficient and bulletproof-friendly cryptographic operations. 10 | 11 | **This repository contains an implementation of the Sonny curve over the `Ristretto Scalar field`: a pure Rust implementation designed by [Dusk](https://dusk.network) team.** 12 | 13 | 14 | Special thanks to Isis Agora Lovecruft and Henry de Valence for their implementation of [Curve25519-dalek library](https://github.com/dalek-cryptography/curve25519-dalek), 15 | which has been so useful in order to get some of the basic arithmetic ops and the structure of our library. 16 | 17 | ### Ristretto curve 18 | 19 | Ristretto is a technique for constructing prime order elliptic curve groups with non-malleable encodings. 20 | 21 | The [Ristretto protocol](https://ristretto.group/ristretto.html) arose as an extension of [Mike Hamburg's Decaf](https://www.shiftleft.org/papers/decaf/decaf.pdf) approach to cofactor elimination, which is applicable to curves of cofactor 4, whereas the Ristretto is designed for non-prime-order curves of cofactor 8 or 4. 22 | Ristretto was designed by the [dalek-cryprography](https://github.com/dalek-cryptography) team, specifically, Henry de Valence and Isis Agora Lovecruft to whom we greatly appreciate their work and dedication. 23 | 24 | ### Ristretto Scalar Field And Bulletproofs. 25 | 26 | Originally designed to abstract _non-prime-order curves into prime-order scalar fields_, the `Ristretto` abstraction would have been far too inefficient to implement for Bulletproofs zero-knowledge proof. Therefore the `Ristretto scalar field` is used to **solve all negative impacts of using cofactors equalling 8 on the Ristretto curve.**. The strategy is to use a _Ristretto embedded curve_ (also called `Sonny Curve`), as the initial operations within `zerocaf` are performed therein. `zerocaf` opens up new opportunities for the use cases of **zero-knowledge proofs** inside the Dusk Network protocol as well as making a _Bulletproof-integrated ring signature substitute possible_, with orders of magnitude performance improvements compared to the fastest ringsig implementation. 27 | 28 | Within this library, the implementation of the Ristretto to construct the curve with desired properties is made possible by 29 | defining the curve over the scalar field, using only a thin abstraction layer, which in turn allows for systems that use signatures to be safely extended with zero-knowledge protocols. These zero-knowledge protocols are utilised with no additional cryptographic assumptions and minimal changes in the code. The Ristretto scalar field is Bulletproof friendly, which makes it possible to use both cryptographic protocols in tandem with one another, as they are centric to contemporary applications of elliptic curve operations. 30 | 31 | 32 | ## Details 33 | 34 | ### Curve parameters: 35 | 36 | | Variable | Value | Explanation | 37 | |--|--|--| 38 | | Equation | Edwards -x²+y²=1-$`\frac{126296}{126297}`$x²y² | -| 39 | | a | -1 | - | 40 | | d | $`-\frac{126296}{126297}`$ | - | 41 | | B | $`\frac{3}{5}`$ | Edwards Basepoint Y-coordinate With X > 0 | 42 | 43 |
44 | 45 | | Montgomery | y²=x³+505186*x²+x | 46 | |--|--| 47 | | u(P) | 4 | `u` coordinate of the Montgomery Basepoint, X-coordinate | \ 48 | | A | 505186 | | 49 | 50 |
51 | 52 | | Weierstrass | y²=x³+ax+b | 53 | |--|--| 54 | | a | 7237005577332262213973186563042994240857116359379907606001950828033483786813 | | 55 | | b | 445582015604702849664 | | 56 | 57 | | Variable | Value | Explanation | 58 | |--|--|--| 59 | | G | 2²⁵² + 115924404605461509904689566245241897752 | Curve order | 60 | | p | 2²⁵² + 27742317777372353535851937790883648493 | Prime of the field | 61 | | r | 2²⁴⁹ + 15114490550575682688738086195780655237219 | Prime of the Sub-Group |\ 62 | 63 |
64 | 65 | ### Encoding / Decoding tools 66 | In order to work with our points along the curve, or any non trivial computuaions, for example those with tough notations - there has been a set of tools and examples which have been created to make facilitate the Encoding/Decoding processes. These can be found at: `tools/src/main.rs` 67 | 68 | ### Examples 69 | 70 | ```rust 71 | num_from_bytes_le(&[76, 250, 187, 243, 105, 92, 117, 70, 234, 124, 126, 180, 87, 149, 62, 249, 16, 149, 138, 56, 26, 87, 14, 76, 251, 39, 168, 74, 176, 202, 26, 84]); 72 | // Prints: 38041616210253564751207933125345413214423929536328854382158537130491690875468 73 | 74 | let res = to_field_elem_51(&"1201935917638644956968126114584555454358623906841733991436515590915937358637"); 75 | println!("{:?}", res); 76 | // Gives us: [939392471225133, 1174884015108736, 2226020409917912, 1948943783348399, 46747909865470] 77 | 78 | hex_bytes_le("120193591763864495696812611458455545435862390684173399143651559091593735863735685683568356835683"); 79 | // Prints: Encoding result -> [63, 41, b7, c, b, 79, 94, 7b, 21, d2, fe, 7b, c8, 89, c9, 7f, 76, c8, 9b, a3, 58, 18, 39, a, f2, d2, 7c, 17, ed, 7f, 6, c4, 9d, 44, f3, 7c, 85, c2, 67, e] 80 | // Put the 0x by yourseleves and if there's any value alone like `c` padd it with a 0 on the left like: `0x0c` 81 | 82 | from_radix_to_radix_10("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", 16u32); 83 | // Prints: 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787 84 | 85 | ``` 86 | 87 | > When performing operations with large values, such as: `2²⁵² - 121160309657751286123858757838224683208`, it is recomended to compute them through `SageMath`, as the user interface adheres to these types of functions. From `SageMath`, they can be converted in a consistent format and easily compiled into Rust. 88 | 89 | ### Roadmap: 90 | 91 | Note: the refactoring relations are expressed as indentations 92 | 93 | 94 | - [x] Build Scalar Arithmetics and Scalar Struct definition. 95 | - [x] Find the proper radix value for FieldElement. 96 | - [x] Add the required constants for computation. 97 | - [x] Implement Addition. 98 | - [x] implement Subtraction. 99 | - [x] Implement Byte-encoding/decoding. 100 | - [x] Implement From for uint native types. 101 | - [x] Implement Ord, PartialOrd, Eq & PartialEq. 102 | - [x] Implement Multiplication on u64-backend with u128 usage. 103 | - [x] Implement Squaring. 104 | - [x] Implement Half for even numbers. 105 | - [x] Implement Modular Negation. 106 | - [x] Implement Montgomery_reduction. 107 | - [x] Define Montgomery_reduction algorithm. 108 | - [x] Create FieldElement Struct and implement the basic operations we need on a u64 backend. 109 | - [x] Find the proper radix value for FieldElement. 110 | - [x] Add basic and needed constants. 111 | - [x] Implement Reduce function to make the FieldElements fit on a 5 u64-bit limbs. 112 | - [x] Implement Addition. 113 | - [x] Implement Subtraction. 114 | - [x] Implement Byte-encoding/decoding. 115 | - [x] Implement From for uint native types. 116 | - [x] Implement Ord, PartialOrd, Eq & PartialEq. 117 | - [x] Implement Multiplication on u64-backend with u128 usage. 118 | - [x] Implement Squaring. 119 | - [x] Implement Half for even numbers 120 | - [x] Implement Modular Negation. 121 | - [x] Implement Montgomery_reduction. 122 | - [x] Define Montgomery_reduction algorithm. 123 | - [x] Implement Modular inversion. 124 | - [x] Research about addition chains inversion methods. 125 | - [x] Add proper tests for every function. 126 | - [x] Implement Edwards Points 127 | - [x] Implement Twisted Edwards Extended Coordiantes. 128 | - [x] Implement Point Addition. 129 | - [x] Implement Point Subtraction. 130 | - [x] Implement Point Doubling. 131 | - [x] Implement Scalar Mul. 132 | - [x] Implement from_bytes conversions. 133 | - [x] Implement to byte conversions. 134 | - [x] Implement compressed Edwards point Y-coordinate. 135 | - [x] Implement Twisted Edwards Projective Coordiates. 136 | - [x] Implement Point Addition. 137 | - [x] Implement Point Subtraction. 138 | - [x] Implement Point Doubling. 139 | - [x] Implement Scalar Mul. 140 | - [x] Implement from_bytes conversions. 141 | - [x] Implement to byte conversions. 142 | - [x] Implement compressed Edwards point Y-coordinate. 143 | - [x] Represent Edwards points as Ristretto points using wrapping type or struct. 144 | - [x] Cargo doc testing and improvement. 145 | - [x] Decide the best use cases of the various Edwards coordinate types (compressed, standard, extended, projective). 146 | - [x] Benchmark different implementations and algorithms. 147 | - [x] Implement Ristretto Mapping. 148 | - [x] Implement 4coset debugging function. 149 | - [x] Build and test torsion points. 150 | - [x] Implement Ecoding & Decoding algorithms. 151 | - [x] Implement Equalty testing. 152 | - [x] Implement Elligator-ristretto-flavour. 153 | - [x] Test all of the algorithms implemented. 154 | -------------------------------------------------------------------------------- /benchmarks/dusk_benchmarks.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | #[macro_use] 4 | extern crate criterion; 5 | 6 | use criterion::{criterion_group, criterion_main, Criterion, BenchmarkId}; 7 | 8 | use zerocaf::edwards::*; 9 | use zerocaf::ristretto::*; 10 | use zerocaf::traits::ops::*; 11 | use zerocaf::constants::*; 12 | use zerocaf::field::*; 13 | use zerocaf::scalar::*; 14 | #[allow(unused_imports)] 15 | use zerocaf::traits::Identity; 16 | 17 | use rand::rngs::OsRng; 18 | 19 | mod field_benches { 20 | 21 | use super::*; 22 | use subtle::Choice; 23 | 24 | /// `B = 904625697166532776746648320197686575422163851717637391703244652875051672039` 25 | pub static B: FieldElement = FieldElement([ 26 | 2766226127823335, 27 | 4237835465749098, 28 | 4503599626623787, 29 | 4503599627370493, 30 | 2199023255551, 31 | ]); 32 | 33 | /// `A = 182687704666362864775460604089535377456991567872` 34 | pub static A: FieldElement = FieldElement([0, 0, 0, 2, 0]); 35 | 36 | pub fn bench_field_element_ops(c: &mut Criterion) { 37 | let inp = (A, B); 38 | let inp2 = (A, Choice::from(1u8)); 39 | let pow = 249u64; 40 | 41 | c.bench_with_input( 42 | BenchmarkId::new("Addition", "Fixed FieldElements"), &inp , |b, &inp| { 43 | b.iter(|| inp.1 + inp.0); 44 | } 45 | ); 46 | 47 | c.bench_with_input( 48 | BenchmarkId::new("Subtraction", "Fixed FieldElements"), &inp , |b, &inp| { 49 | b.iter(|| inp.0 - inp.1); 50 | } 51 | ); 52 | 53 | c.bench_with_input( 54 | BenchmarkId::new("Multiplication", "Fixed FieldElements"), &inp , |b, &inp| { 55 | b.iter(|| inp.0 * inp.1); 56 | } 57 | ); 58 | 59 | c.bench_with_input( 60 | BenchmarkId::new("Division", "Fixed FieldElements"), &inp , |b, &inp| { 61 | b.iter(|| inp.0/inp.1); 62 | } 63 | ); 64 | 65 | c.bench_with_input( 66 | BenchmarkId::new("Square", "Fixed FieldElements"), &inp , |b, &inp| { 67 | b.iter(|| inp.1.square()); 68 | } 69 | ); 70 | 71 | c.bench_with_input( 72 | BenchmarkId::new("Half", "Fixed FieldElements"), &inp , |b, &inp| { 73 | b.iter(|| inp.0.half()); 74 | } 75 | ); 76 | 77 | c.bench_with_input( 78 | BenchmarkId::new("Two pow K", "Fixed constant"), &pow , |b, &pow| { 79 | b.iter(|| FieldElement::two_pow_k(pow)) 80 | } 81 | ); 82 | 83 | c.bench_with_input( 84 | BenchmarkId::new("Power", "Fixed FieldElements"), &inp , |b, &inp| { 85 | b.iter(|| inp.0.pow(&inp.1)); 86 | } 87 | ); 88 | 89 | c.bench_with_input( 90 | BenchmarkId::new("Legendre Symbol", "Fixed FieldElement"), &inp , |b, &inp| { 91 | b.iter(|| inp.0.legendre_symbol()); 92 | } 93 | ); 94 | 95 | c.bench_with_input( 96 | BenchmarkId::new("Modular Sqrt", "Fixed FieldElements"), &inp2 , |b, &inp| { 97 | b.iter(|| inp2.0.mod_sqrt(inp2.1)); 98 | } 99 | ); 100 | 101 | c.bench_with_input( 102 | BenchmarkId::new("Modular inverse", "Fixed FieldElements"), &inp , |b, &inp| { 103 | b.iter(|| inp.0.inverse()); 104 | } 105 | ); 106 | 107 | c.bench_with_input( 108 | BenchmarkId::new("Sqrt ratio i", "Fixed FieldElements"), &inp , |b, &inp| { 109 | b.iter(|| inp.0.sqrt_ratio_i(&inp.1)); 110 | } 111 | ); 112 | 113 | c.bench_with_input( 114 | BenchmarkId::new("Inverse sqrt", "Fixed FieldElements"), &inp , |b, &inp| { 115 | b.iter(|| inp.0.inv_sqrt()); 116 | } 117 | ); 118 | 119 | c.bench_function("Random FieldElement generation", |b| b.iter(|| FieldElement::random(&mut OsRng))); 120 | } 121 | } 122 | 123 | mod scalar_benches { 124 | use super::*; 125 | use zerocaf::scalar::Scalar; 126 | 127 | /// `C = 182687704666362864775460604089535377456991567872`. 128 | pub static C: Scalar = Scalar([0, 0, 0, 2, 0]); 129 | 130 | /// `D = 904625697166532776746648320197686575422163851717637391703244652875051672039` 131 | pub static D: Scalar = Scalar([ 132 | 2766226127823335, 133 | 4237835465749098, 134 | 4503599626623787, 135 | 4503599627370493, 136 | 2199023255551, 137 | ]); 138 | 139 | pub fn bench_scalar_element_ops(c: &mut Criterion) { 140 | let inp = (C, D, 4u8); 141 | let pow = 215u64; 142 | 143 | c.bench_with_input( 144 | BenchmarkId::new("Addition", "Fixed Scalars"), &inp , |b, &inp| { 145 | b.iter(|| inp.0 + inp.1); 146 | } 147 | ); 148 | 149 | c.bench_with_input( 150 | BenchmarkId::new("Subtraction", "Fixed Scalars"), &inp , |b, &inp| { 151 | b.iter(|| inp.0 - inp.1); 152 | } 153 | ); 154 | 155 | c.bench_with_input( 156 | BenchmarkId::new("Mul", "Fixed Scalars"), &inp , |b, &inp| { 157 | b.iter(|| inp.0 * inp.1); 158 | } 159 | ); 160 | 161 | c.bench_with_input( 162 | BenchmarkId::new("Squaring", "Fixed Scalars"), &inp , |b, &inp| { 163 | b.iter(|| inp.1.square()); 164 | } 165 | ); 166 | 167 | c.bench_with_input( 168 | BenchmarkId::new("Half", "Fixed Scalars"), &inp , |b, &inp| { 169 | b.iter(|| inp.0.half()); 170 | } 171 | ); 172 | 173 | c.bench_with_input( 174 | BenchmarkId::new("Two pow K", "Fixed Scalar"), &pow , |b, &pow| { 175 | b.iter(|| Scalar::two_pow_k(pow)); 176 | } 177 | ); 178 | 179 | c.bench_with_input( 180 | BenchmarkId::new("Power", "Fixed Scalars"), &inp , |b, &inp| { 181 | b.iter(|| inp.0.pow(&inp.1)); 182 | } 183 | ); 184 | 185 | c.bench_with_input( 186 | BenchmarkId::new("Into-bits conversion", "Fixed Scalar"), &inp , |b, &inp| { 187 | b.iter(|| inp.1.into_bits()); 188 | } 189 | ); 190 | 191 | c.bench_with_input( 192 | BenchmarkId::new("Shr", "Fixed Scalar"), &inp , |b, &inp| { 193 | b.iter(|| inp.1 >> 135); 194 | } 195 | ); 196 | 197 | c.bench_with_input( 198 | BenchmarkId::new("Scalar mod 4", "Fixed Scalar"), &inp , |b, &inp| { 199 | b.iter(|| inp.1.mod_2_pow_k(inp.2)); 200 | } 201 | ); 202 | 203 | c.bench_with_input( 204 | BenchmarkId::new("Compute NAF", "Fixed Scalar"), &inp , |b, &inp| { 205 | b.iter(|| inp.1.compute_NAF()); 206 | } 207 | ); 208 | 209 | c.bench_with_input( 210 | BenchmarkId::new("Compute windowed-NAF", "Fixed Scalar"), &inp , |b, &inp| { 211 | b.iter(|| inp.1.compute_window_NAF(inp.2)); 212 | } 213 | ); 214 | 215 | c.bench_function("Random Scalar generation", |b| b.iter(|| Scalar::random(&mut OsRng))); 216 | } 217 | } 218 | 219 | mod edwards_benches { 220 | 221 | use super::*; 222 | use subtle::Choice; 223 | 224 | pub static P1_EXTENDED: EdwardsPoint = EdwardsPoint { 225 | X: FieldElement([13, 0, 0, 0, 0]), 226 | Y: FieldElement([ 227 | 606320128494542, 228 | 1597163540666577, 229 | 1835599237877421, 230 | 1667478411389512, 231 | 3232679738299, 232 | ]), 233 | Z: FieldElement([1, 0, 0, 0, 0]), 234 | T: FieldElement([ 235 | 2034732376387996, 236 | 3922598123714460, 237 | 1344791952818393, 238 | 3662820838581677, 239 | 6840464509059, 240 | ]), 241 | }; 242 | 243 | pub static P2_EXTENDED: EdwardsPoint = EdwardsPoint { 244 | X: FieldElement([67, 0, 0, 0, 0]), 245 | Y: FieldElement([ 246 | 2369245568431362, 247 | 2665603790611352, 248 | 3317390952748653, 249 | 1908583331312524, 250 | 8011773354506, 251 | ]), 252 | Z: FieldElement([1, 0, 0, 0, 0]), 253 | T: FieldElement([ 254 | 3474019263728064, 255 | 2548729061993416, 256 | 1588812051971430, 257 | 1774293631565269, 258 | 9023233419450, 259 | ]), 260 | }; 261 | 262 | pub static P1_PROJECTIVE: ProjectivePoint = ProjectivePoint { 263 | X: FieldElement([13, 0, 0, 0, 0]), 264 | Y: FieldElement([ 265 | 606320128494542, 266 | 1597163540666577, 267 | 1835599237877421, 268 | 1667478411389512, 269 | 3232679738299, 270 | ]), 271 | Z: FieldElement([1, 0, 0, 0, 0]), 272 | }; 273 | 274 | pub static P2_PROJECTIVE: ProjectivePoint = ProjectivePoint { 275 | X: FieldElement([67, 0, 0, 0, 0]), 276 | Y: FieldElement([ 277 | 2369245568431362, 278 | 2665603790611352, 279 | 3317390952748653, 280 | 1908583331312524, 281 | 8011773354506, 282 | ]), 283 | Z: FieldElement([1, 0, 0, 0, 0]), 284 | }; 285 | 286 | /// `D = 904625697166532776746648320197686575422163851717637391703244652875051672039` 287 | pub static D: Scalar = Scalar([ 288 | 2766226127823335, 289 | 4237835465749098, 290 | 4503599626623787, 291 | 4503599627370493, 292 | 2199023255551, 293 | ]); 294 | 295 | /// `P1_EXTENDED on `CompressedEdwardsY` format. 296 | pub(self) static P1_COMPRESSED: CompressedEdwardsY = CompressedEdwardsY([ 297 | 206, 11, 225, 231, 113, 39, 18, 141, 213, 215, 201, 201, 90, 173, 14, 134, 192, 119, 133, 298 | 134, 164, 26, 38, 1, 201, 94, 187, 59, 186, 170, 240, 2, 299 | ]); 300 | 301 | pub fn bench_extended_point_ops(c: &mut Criterion) { 302 | 303 | let extend_inp = (P1_EXTENDED, P2_EXTENDED, D); 304 | let y_gen = (FieldElement([ 305 | 2369245568431362, 306 | 2665603790611352, 307 | 3317390952748653, 308 | 1908583331312524, 309 | 8011773354506, 310 | ]), Choice::from(1u8)); 311 | 312 | c.bench_with_input( 313 | BenchmarkId::new("Extended Coordinates Point Addition", "Fixed Points"), &extend_inp , |b, &extend_inp| { 314 | b.iter(|| extend_inp.0 + extend_inp.1); 315 | } 316 | ); 317 | 318 | c.bench_with_input( 319 | BenchmarkId::new("Extended Coordinates Point Subtraction", "Fixed Points"), &extend_inp , |b, &extend_inp| { 320 | b.iter(|| extend_inp.0 - extend_inp.1); 321 | } 322 | ); 323 | 324 | c.bench_with_input( 325 | BenchmarkId::new("Extended Coordinates Point Doubling", "Fixed Points"), &extend_inp , |b, &extend_inp| { 326 | b.iter(|| extend_inp.0.double()); 327 | } 328 | ); 329 | 330 | c.bench_with_input( 331 | BenchmarkId::new("Extended Coordinates Point Multiplication", "Fixed Points"), &extend_inp , |b, &extend_inp| { 332 | b.iter(|| extend_inp.0 * extend_inp.2); 333 | } 334 | ); 335 | 336 | c.bench_with_input( 337 | BenchmarkId::new("Extended Coordinates Point Generation", "Fixed y-coordinate"), &y_gen , |b, &y_gen| { 338 | b.iter(|| EdwardsPoint::new_from_y_coord(&y_gen.0, y_gen.1)); 339 | } 340 | ); 341 | 342 | c.bench_function("Random EdwardsPoint generation", |b| b.iter(|| EdwardsPoint::new_random_point(&mut OsRng))); 343 | } 344 | 345 | pub fn bench_projective_point_ops(c: &mut Criterion) { 346 | 347 | let proj_inp = (P1_PROJECTIVE, P2_PROJECTIVE, D); 348 | let y_gen = (FieldElement([ 349 | 2369245568431362, 350 | 2665603790611352, 351 | 3317390952748653, 352 | 1908583331312524, 353 | 8011773354506, 354 | ]), Choice::from(1u8)); 355 | 356 | c.bench_with_input( 357 | BenchmarkId::new("Projective Coordinates Point Addition", "Fixed Points"), &proj_inp , |b, &proj_inp| { 358 | b.iter(|| proj_inp.0 + proj_inp.1); 359 | } 360 | ); 361 | 362 | c.bench_with_input( 363 | BenchmarkId::new("Projective Coordinates Point Subtraction", "Fixed Points"), &proj_inp , |b, &proj_inp| { 364 | b.iter(|| proj_inp.0 - proj_inp.1); 365 | } 366 | ); 367 | 368 | c.bench_with_input( 369 | BenchmarkId::new("Projective Coordinates Point Doubling", "Fixed Point"), &proj_inp , |b, &proj_inp| { 370 | b.iter(|| proj_inp.0.double()); 371 | } 372 | ); 373 | 374 | c.bench_with_input( 375 | BenchmarkId::new("Projective Coordinates Point Multiplication", "Fixed Points"), &proj_inp , |b, &proj_inp| { 376 | b.iter(|| proj_inp.0 * proj_inp.2); 377 | } 378 | ); 379 | 380 | c.bench_with_input( 381 | BenchmarkId::new("Projective Coordinates Point Generation", "Fixed y-coordinate"), &y_gen , |b, &y_gen| { 382 | b.iter(|| ProjectivePoint::new_from_y_coord(&y_gen.0, y_gen.1)); 383 | } 384 | ); 385 | 386 | c.bench_function("Random ProjectivePoint generation", |b| b.iter(|| ProjectivePoint::new_random_point(&mut OsRng))); 387 | } 388 | 389 | pub fn bench_point_compression_decompression(c: &mut Criterion) { 390 | let cd_inp = (P1_COMPRESSED, P1_EXTENDED); 391 | 392 | c.bench_with_input( 393 | BenchmarkId::new("Point Compression", "Fixed Extended Point"), &cd_inp , |b, &cd_inp| { 394 | b.iter(|| cd_inp.1.compress()); 395 | } 396 | ); 397 | 398 | c.bench_with_input( 399 | BenchmarkId::new("Point Decompression", "Fixed Compressed-Point"), &cd_inp , |b, &cd_inp| { 400 | b.iter(|| cd_inp.0.decompress().unwrap()); 401 | } 402 | ); 403 | } 404 | } 405 | 406 | mod ristretto_benches { 407 | use super::*; 408 | 409 | /// `D = 904625697166532776746648320197686575422163851717637391703244652875051672039` 410 | pub static D: Scalar = Scalar([ 411 | 2766226127823335, 412 | 4237835465749098, 413 | 4503599626623787, 414 | 4503599627370493, 415 | 2199023255551, 416 | ]); 417 | 418 | pub fn bench_ristretto_point_ops(c: &mut Criterion) { 419 | 420 | let proj_inp = (RISTRETTO_BASEPOINT, D); 421 | 422 | c.bench_with_input( 423 | BenchmarkId::new("Ristretto Random Point Addition", "Fixed Points"), &proj_inp , |b, &proj_inp| { 424 | b.iter(|| proj_inp.0 + proj_inp.0); 425 | } 426 | ); 427 | 428 | c.bench_with_input( 429 | BenchmarkId::new("Ristretto Random Point Subtraction", "Fixed Points"), &proj_inp , |b, &proj_inp| { 430 | b.iter(|| proj_inp.0 + -proj_inp.0); 431 | } 432 | ); 433 | 434 | c.bench_with_input( 435 | BenchmarkId::new("Ristretto Random Point Doubling", "Fixed Point"), &proj_inp , |b, &proj_inp| { 436 | b.iter(|| proj_inp.0.double()); 437 | } 438 | ); 439 | 440 | c.bench_with_input( 441 | BenchmarkId::new("Ristretto Random Point Multiplication", "Fixed Points"), &proj_inp , |b, &proj_inp| { 442 | b.iter(|| proj_inp.0 * proj_inp.1); 443 | } 444 | ); 445 | 446 | c.bench_function("Ristretto random Point generation", |b| b.iter(|| RistrettoPoint::new_random_point(&mut OsRng))); 447 | } 448 | 449 | pub fn bench_ristretto_protocol_impl(c: &mut Criterion) { 450 | 451 | let inputs = (RISTRETTO_BASEPOINT, 452 | FieldElement([ 453 | 2369245568431362, 454 | 2665603790611352, 455 | 3317390952748653, 456 | 1908583331312524, 457 | 8011773354506, 458 | ]), 459 | RISTRETTO_BASEPOINT_COMPRESSED); 460 | 461 | c.bench_with_input( 462 | BenchmarkId::new("Ristretto Encoding", "Ristretto Basepoint"), &inputs , |b, &inputs| { 463 | b.iter(|| inputs.0.compress()); 464 | } 465 | ); 466 | 467 | c.bench_with_input( 468 | BenchmarkId::new("Ristretto Decoding", "Ristretto Basepoint"), &inputs , |b, &inputs| { 469 | b.iter(|| inputs.2.decompress().unwrap()); 470 | } 471 | ); 472 | 473 | c.bench_with_input( 474 | BenchmarkId::new("Ristretto Elligator", "Fixed FieldElement"), &inputs , |b, &inputs| { 475 | b.iter(|| RistrettoPoint::elligator_ristretto_flavor(&inputs.1)); 476 | } 477 | ); 478 | 479 | c.bench_with_input( 480 | BenchmarkId::new("Ristretto Equalty", "Ristretto Basepoint"), &inputs , |b, &inputs| { 481 | b.iter(|| inputs.0 == inputs.0); 482 | } 483 | ); 484 | } 485 | } 486 | 487 | mod comparaisons { 488 | use super::*; 489 | use rand::rngs::OsRng; 490 | use zerocaf::constants::RISTRETTO_BASEPOINT; 491 | 492 | static P1_EXTENDED: RistrettoPoint = RistrettoPoint( EdwardsPoint { 493 | X: FieldElement([13, 0, 0, 0, 0]), 494 | Y: FieldElement([ 495 | 606320128494542, 496 | 1597163540666577, 497 | 1835599237877421, 498 | 1667478411389512, 499 | 3232679738299, 500 | ]), 501 | Z: FieldElement([1, 0, 0, 0, 0]), 502 | T: FieldElement([ 503 | 2034732376387996, 504 | 3922598123714460, 505 | 1344791952818393, 506 | 3662820838581677, 507 | 6840464509059, 508 | ]), 509 | }); 510 | 511 | /// `D = 904625697166532776746648320197686575422163851717637391703244652875051672038` 512 | pub static D: Scalar = Scalar([ 513 | 2766226127823334, 514 | 4237835465749098, 515 | 4503599626623787, 516 | 4503599627370493, 517 | 2199023255551, 518 | ]); 519 | 520 | pub fn bench_point_ops_impl(c: &mut Criterion) { 521 | let i = P1_EXTENDED; 522 | let mul = (RISTRETTO_BASEPOINT, D); 523 | 524 | let mut group = c.benchmark_group("Half"); 525 | 526 | group.bench_with_input(BenchmarkId::new("Fast Even Half", "Fixed even FieldElement"), &i, 527 | |b, &i| b.iter(|| i.0.T.old_half())); 528 | group.bench_with_input(BenchmarkId::new("Constant usage impl", "Fixed even FieldElement"), &i, 529 | |b, &i| b.iter(|| i.0.T.half())); 530 | 531 | group.finish(); 532 | 533 | 534 | // Equalty 535 | let mut group = c.benchmark_group("Equalty"); 536 | 537 | group.bench_with_input(BenchmarkId::new("Compressing", "Fixed Point"), &i, 538 | |b, &i| b.iter(|| i.compress() == i.compress())); 539 | group.bench_with_input(BenchmarkId::new("To Affine", "Fixed Point"), &i, 540 | |b, &i| b.iter(|| i == i)); 541 | 542 | group.finish(); 543 | 544 | // Point Mul 545 | let mut group = c.benchmark_group("Point Multiplication"); 546 | 547 | group.bench_with_input(BenchmarkId::new("Double And Add", "Fixed inputs"), &mul, 548 | |b, &mul| b.iter(|| double_and_add(&mul.0, &mul.1))); 549 | group.bench_with_input(BenchmarkId::new("Left to right binary method", "Fixed inputs"), &mul, 550 | |b, &mul| b.iter(|| ltr_bin_mul(&mul.0, &mul.1))); 551 | group.bench_with_input(BenchmarkId::new("NAF binary", "Fixed inputs"), &mul, 552 | |b, &mul| b.iter(|| binary_naf_mul(&mul.0, &mul.1))); 553 | group.bench_with_input(BenchmarkId::new("Window w-NAF binary", "Fixed inputs"), &mul, 554 | |b, &mul| b.iter(|| window_naf_mul(&mul.1, 5u8))); 555 | 556 | group.finish(); 557 | } 558 | 559 | // Helpers for benchmarking the whole ECDH process // 560 | 561 | // Left to right shift method. 562 | fn generate_kp_ltrs() -> (Scalar, RistrettoPoint) { 563 | let sk = Scalar::random(&mut OsRng); 564 | let pk = ltr_bin_mul(&RISTRETTO_BASEPOINT, &sk); 565 | 566 | (sk, pk) 567 | } 568 | 569 | fn ecdh_ltrs() -> () { 570 | let alice_kp = generate_kp_ltrs(); 571 | let bob_kp = generate_kp_ltrs(); 572 | 573 | let alice_computes_S = ltr_bin_mul(&bob_kp.1, &alice_kp.0); 574 | let bob_computes_S = ltr_bin_mul(&alice_kp.1, &bob_kp.0); 575 | } 576 | 577 | // Binary NAF 578 | fn generate_kp_binary_naf() -> (Scalar, RistrettoPoint) { 579 | let sk = Scalar::random(&mut OsRng); 580 | let pk = binary_naf_mul(&RISTRETTO_BASEPOINT, &sk); 581 | 582 | (sk, pk) 583 | } 584 | 585 | fn ecdh_binary_naf() -> () { 586 | let alice_kp = generate_kp_binary_naf(); 587 | let bob_kp = generate_kp_binary_naf(); 588 | 589 | let alice_computes_S = binary_naf_mul(&bob_kp.1, &alice_kp.0); 590 | let bob_computes_S = binary_naf_mul(&alice_kp.1, &bob_kp.0); 591 | } 592 | 593 | // Double and Add 594 | fn generate_kp_double_add() -> (Scalar, RistrettoPoint) { 595 | let sk = Scalar::random(&mut OsRng); 596 | let pk = double_and_add(&RISTRETTO_BASEPOINT, &sk); 597 | 598 | (sk, pk) 599 | } 600 | 601 | fn ecdh_double_add() -> () { 602 | let alice_kp = generate_kp_double_add(); 603 | let bob_kp = generate_kp_double_add(); 604 | 605 | let alice_computes_S = double_and_add(&bob_kp.1, &alice_kp.0); 606 | let bob_computes_S = double_and_add(&alice_kp.1, &bob_kp.0); 607 | } 608 | 609 | 610 | 611 | /// ECDH bench function. 612 | pub fn bench_ecdh(c: &mut Criterion) { 613 | let mut group = c.benchmark_group("ECDH"); 614 | 615 | group.bench_function("Double and Add", |b| b.iter(|| ecdh_double_add())); 616 | group.bench_function("Left to right binary method", |b| b.iter(|| ecdh_ltrs())); 617 | group.bench_function("Binary NAF method", |b| b.iter(|| ecdh_binary_naf())); 618 | 619 | group.finish(); 620 | } 621 | 622 | } 623 | 624 | criterion_group!( 625 | benchmarks, 626 | comparaisons::bench_point_ops_impl, 627 | comparaisons::bench_ecdh, 628 | field_benches::bench_field_element_ops, 629 | scalar_benches::bench_scalar_element_ops, 630 | edwards_benches::bench_extended_point_ops, 631 | edwards_benches::bench_projective_point_ops, 632 | edwards_benches::bench_point_compression_decompression, 633 | ristretto_benches::bench_ristretto_point_ops, 634 | ristretto_benches::bench_ristretto_protocol_impl, 635 | ); 636 | criterion_main!( 637 | benchmarks, 638 | ); 639 | -------------------------------------------------------------------------------- /docs/Safe Curve criteria: -------------------------------------------------------------------------------- 1 | ### Documentation of save curve criteria for Sonny 2 | 3 | Safe Curve criteria checklist: 4 | 5 | - [x] The curve must be defined over a prime field F_p 6 | - [x] The conditions on the curve constants for the relevant curve shape must be met 7 | - [x] The cost of a rho attack must be > 2^100 8 | - [x] Let l be the large prime factor of the group order. l must be relatively prime to p, and the embedding degree must be at least (l-1)/100 9 | - [x] The CM discriminant must be > 2^100 10 | - [x] There must be an explanation of how the curve constants were derived 11 | - [x] The curve must admit a Montgomery ladder; this effectively restricts the shape to Montgomery or [twisted] Edwards 12 | - [ ] The security against "combined attacks" on the twist, which is the a generalisation of rho security, must be > 2^100 13 | - [x] The curve must admit a simple complete addition law; this further restricts which Montgomery and Edwards curves are admitted 14 | - [x] The Elligator 2 algorithm for hashing to the curve must work 15 | - [x] There is proven birationality between the Edwards and Montgomery forms of the curve 16 | 17 | The factors to document against can be found at https://safecurves.cr.yp.to/ 18 | 19 | 20 | -------------------------------------------------------------------------------- /docs/lit.bib: -------------------------------------------------------------------------------- 1 | @misc{bulletproofs, 2 | author = {Benedikt Bünz and Jonathan Bootle and Dan Boneh and Andrew Poelstra and Pieter Wuille and Greg Maxwell}, 3 | title = {Bulletproofs: Short Proofs for Confidential Transactions and More}, 4 | howpublished = {Cryptology ePrint Archive, Report 2017/1066}, 5 | year = {2017}, 6 | note = {\url{https://eprint.iacr.org/2017/1066}}, 7 | } 8 | 9 | @InProceedings{stoc85, 10 | author={Shafi Goldwasser and Silvio Micali and Charles Rackoff}, 11 | title={The knowledge complexity of interactive 12 | proof-systems (extended abstract)}, 13 | booktitle={STOC '85: Proceedings of the seventeenth annual ACM symposium on Theory of computing}, 14 | year=1985, 15 | pages={291--304}, 16 | } 17 | 18 | @InProceedings{pedersen, 19 | author="Pedersen, Torben Pryds", 20 | editor="Feigenbaum, Joan", 21 | title="Non-Interactive and Information-Theoretic Secure Verifiable Secret Sharing", 22 | booktitle="Advances in Cryptology --- CRYPTO '91", 23 | series="Lecture Notes in Computer Science", 24 | volume = "576", 25 | year="1992", 26 | publisher="Springer Berlin Heidelberg", 27 | address="Berlin, Heidelberg", 28 | pages="129--140", 29 | } 30 | 31 | @misc{ristretto, 32 | title = {The ristretto255 Group}, 33 | author = {Henry de~Valence and Jack Grigg and George Tankersley and Filippo Valsorda and Isis Lovecruft}, 34 | series = {Crypto Forum Research Group. IETF Internet-Draft.}, 35 | year = {January, 2019}, 36 | note = {\url{https://tools.ietf.org/pdf/draft-hdevalence-cfrg-ristretto-00.pdf}}, 37 | } 38 | 39 | 40 | @misc{eddsa, 41 | title = {Edwards-Curve {D}igital {S}ignature {A}lgorithm {(EdDSA)}}, 42 | author = {Simon Josefsson and Ilari Liusvaara}, 43 | series = {Request for Comments}, 44 | number = 8032, 45 | year = {January, 2017}, 46 | note = {\url{https://tools.ietf.org/html/8032}}, 47 | } 48 | 49 | @misc{decaf, 50 | author = {Mike Hamburg}, 51 | title = {Decaf: Eliminating cofactors through point compression}, 52 | howpublished = {Cryptology ePrint Archive, Report 2015/673}, 53 | year = {2015}, 54 | note = {\url{https://eprint.iacr.org/2015/673}}, 55 | } 56 | 57 | @misc{hao, 58 | author = {Feng Hao}, 59 | title = {On Small Subgroup Non-confinement Attack}, 60 | howpublished = {Cryptology ePrint Archive, Report 2010/149}, 61 | year = {2010}, 62 | note = {\url{https://eprint.iacr.org/2010/149}}, 63 | } 64 | 65 | 66 | @InProceedings{dijkgraaf, 67 | author="Dijkgraaf, Robbert", 68 | editor="Dijkgraaf, Robbert H. 69 | and Faber, Carel F. 70 | and van der Geer, Gerard B. M.", 71 | title="Mirror Symmetry and Elliptic Curves", 72 | booktitle="The Moduli Space of Curves", 73 | year="1995", 74 | publisher="Birkh{\"a}user Boston", 75 | address="Boston, MA", 76 | pages="149--163", 77 | } 78 | 79 | 80 | @InProceedings{bit-shifting, 81 | author="B. Ravi Kumar, P.R.K.Murti", 82 | title="Data Encryption and Decryption process Using Bit Shifting and Stuffing BSS Methodology", 83 | booktitle="International Journal on Computer Science and Engineering (IJCSE)", 84 | year="2011", 85 | volume = "3", 86 | number = "7", 87 | pages="2818--2827", 88 | } 89 | 90 | @unpublished {safe-curves, 91 | AUTHOR = {Daniel J. Bernstein and Tanja Lange}, 92 | TITLE = {SafeCurves: choosing safe curves for elliptic-curve cryptography}, 93 | NOTE = {\url{https://safecurves.cr.yp.to}}, 94 | YEAR = {Accessed February 25, 2019}, 95 | } 96 | 97 | @unpublished {github:daira:safe, 98 | AUTHOR = {Daira Hopwood}, 99 | TITLE = {Supporting evidence for security of the Jubjub curve to be used in Zcash 100 | }, 101 | NOTE = {\url{https://github.com/daira/jubjub/blob/master/verify.sage}}, 102 | YEAR = {November 2, 2017}, 103 | } 104 | 105 | @book {seroussi, 106 | AUTHOR = {Ian Blake and Gadiel Seroussi and Nigel Smart}, 107 | TITLE = {Elliptic Curves in Cryptography}, 108 | PUBLISHER = {Cambridge University Press}, 109 | SERIES = {London Mathematical Society Lecture Note Series}, 110 | VOLUME = {256}, 111 | ADDRESS = {Cambridge}, 112 | YEAR = {1999}, 113 | } 114 | 115 | @article{montgomery, 116 | author = {L. Montgomery, Peter}, 117 | year = {1987}, 118 | month = {01}, 119 | pages = {243-243}, 120 | title = {Montgomery, P.L.: Speeding the Pollard and Elliptic Curve Methods of Factorization}, 121 | volume = {48}, 122 | journal = {Mathematics of Computation - Math. Comput.}, 123 | doi = {10.1090/S0025-5718-1987-0866113-7} 124 | } 125 | 126 | @misc{indist, 127 | author = {Daniel J. Bernstein and Mike Hamburg and Anna Krasnova and Tanja Lange}, 128 | title = {Elligator: Elliptic-curve points indistinguishable from uniform random strings}, 129 | howpublished = {Cryptology ePrint Archive, Report 2013/325}, 130 | year = {2013}, 131 | note = {\url{https://eprint.iacr.org/2013/325}}, 132 | } 133 | 134 | @misc{teds, 135 | author = {Daniel J. Bernstein and Peter Birkner and Marc Joye and Tanja Lange and Christiane Peters}, 136 | title = {Twisted Edwards Curves}, 137 | howpublished = {Cryptology ePrint Archive, Report 2008/013}, 138 | year = {2008}, 139 | note = {\url{https://eprint.iacr.org/2008/013}}, 140 | } 141 | 142 | @misc{scaling, 143 | author = {Huseyin Hisil and Kenneth Koon-Ho Wong and Gary Carter and Ed Dawson}, 144 | title = {Twisted Edwards Curves Revisited}, 145 | howpublished = {Cryptology ePrint Archive, Report 2008/522}, 146 | year = {2008}, 147 | note = {\url{https://eprint.iacr.org/2008/522}}, 148 | } 149 | 150 | @misc{generation, 151 | series = {Request for Comments}, 152 | number = 7748, 153 | howpublished = {RFC 7748}, 154 | publisher = {RFC Editor}, 155 | doi = {10.17487/RFC7748}, 156 | note = {\url{https://rfc-editor.org/rfc/rfc7748.txt}}, 157 | author = {Adam Langley and Mike Hamburg and Sean Turner}, 158 | title = {{Elliptic Curves for Security}}, 159 | pagetotal = 22, 160 | year = {January, 2016}, 161 | } 162 | 163 | @unpublished {github:zkcrypto:derive, 164 | AUTHOR = {Sean Bowe}, 165 | TITLE = {Derivation of Jubjub elliptic curve}, 166 | NOTE = {\url{https://github.com/zkcrypto/jubjub/blob/master/doc/derive/derive.sage}}, 167 | YEAR = {May 10, 2019}, 168 | } 169 | -------------------------------------------------------------------------------- /docs/main.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | 3 | \usepackage[colorlinks=true, urlcolor=black, linkcolor=black, citecolor=black]{hyperref} 4 | 5 | \usepackage[english]{babel} 6 | \usepackage[utf8]{inputenc} 7 | \usepackage{amsmath, amsthm, amssymb, mathtools} 8 | \usepackage{enumerate, enumitem} 9 | \usepackage{graphicx, color, xcolor} 10 | \usepackage{epsfig, wrapfig, caption} 11 | 12 | \graphicspath{ {images/} } 13 | \newcommand{\N}{\ensuremath{\mathbb{N}}} 14 | \newcommand{\Np}{\ensuremath{\mathbb{N}^{+}}} 15 | \newcommand{\Z}{\ensuremath{\mathbb{Z}}} 16 | \newcommand{\Q}{\ensuremath{\mathbb{Q}}} 17 | \newcommand{\R}{\ensuremath{\mathbb{R}}} 18 | \newcommand{\C}{\ensuremath{\mathbb{C}}} 19 | \newcommand{\F}{\ensuremath{\mathbb{F}}} 20 | \newcommand{\Fp}{\ensuremath{\mathbb{F}_p}} 21 | \newcommand{\Fq}{\ensuremath{\mathbb{F}_q}} 22 | \newcommand{\Fr}{\ensuremath{\mathbb{F}_r}} 23 | \newcommand{\Fl}{\ensuremath{\mathbb{F}_l}} 24 | \newcommand{\G}{\ensuremath{\mathbb{G}}} 25 | \newcommand{\point}[1]{P_{#1} = (x_{#1}, y_{#1})} 26 | \newcommand{\noi}{\noindent} 27 | \newcommand{\Prover}{\ensuremath{\mathcal{P }}} 28 | \newcommand{\V}{\ensuremath{\mathcal{V }}} 29 | 30 | \newtheorem{thm}{Theorem}[section] 31 | \newtheorem{lem}[thm]{Lemma} 32 | \newtheorem{prop}[thm]{Proposition} 33 | \newtheorem{cor}[thm]{Corollary} 34 | \newtheorem{grouplaw}[thm]{Group Law} 35 | \newtheorem{prob}[thm]{Problem} 36 | \theoremstyle{definition} 37 | \newtheorem{defn}[thm]{Definition} 38 | \theoremstyle{remark} 39 | \newtheorem{rem}[thm]{Remark} 40 | \newtheorem{exmp}[thm]{Example} 41 | 42 | \begin{document} 43 | 44 | \title{Sonny: A Bulletproof Friendly Elliptic Curve\\ 45 | (Draft)} 46 | \author{ 47 | Carlos Pérez\\ 48 | {\small Dusk Foundation\footnote{https://dusk.network/}}\\ 49 | \texttt{\small carlos@dusk.network} 50 | \and 51 | Luke Pearson\\ 52 | {\small Dusk Foundation}\\ 53 | \texttt{\small luke@dusk.network} 54 | \and 55 | Marta Bell\'es-Mu\~noz\\ 56 | {\small Dusk Foundation}\\ 57 | \texttt{\small marta@dusk.network} 58 | } 59 | 60 | \date{April 2020} 61 | 62 | \maketitle 63 | 64 | \begin{abstract} 65 | 66 | Signature schemes are used to verify signatures and statements. These schemes and their statements oft rely upon Elliptic Curve Cryptography (ECC), which use primitives where the discrete logarithm problems are assumed to be hard. A lot of zero-knowledge proofs use elliptic curves in their construction, to aid in proving a statement. However, zero-knowledge proofs are built from a circuit, which is defined over a different group to a signature scheme. In order to prove a signature in zero knowledge, a scheme cannot utilise the properties of only curve, as the modular operations are asynchronous. To counter this problem, zero knowledge statements and other ECC operations can rely upon a curve, which is embedded within another curve. This work presents a new elliptic curve, named Sonny, which is suitable for performing signature algorithms in zero-knowledge. When constructing elliptic curves, there are many features which must be considered and amongst the all the possible choices, Sonny was designed to operate with high speed and rigid security for both theory and implementations. The curve is a Montgomery Curve, with a birationally equivalent twisted Edwards curve - this allows for the use of high speed curve formulae for operations, performed in and out of arithmetic circuits. In addition to the speed, the curve can make use of complete formulas to increase the security of the curve arithmetic. Twisted Edwards curves have a group of points which have non-prime order and the points instead have a small cofactor, of order 8. The Sonny curve was constructed to be compatible with the Ristretto technique of cofactor compression, which can omit any cofactor related issues.\\ 67 | 68 | {\bf Keywords:} Elliptic curve cryptography, signature verification, blockchain, zero-knowledge proofs, bulletproof, embedded curve, cofactor security. \\ 69 | 70 | \end{abstract} 71 | 72 | \newpage 73 | 74 | \tableofcontents 75 | 76 | \newpage 77 | 78 | \section{Introduction} 79 | 80 | \subsection{Motivation} 81 | 82 | A significant portion of contemporary cryptography is in someway connected to zero knowledge proofs. With the benefit of greater privacy, many new practical systems utilise zero knowledge proofs in their design. Alongside the incorporation of these privacy preserving features into novel techniques and designs, there is also a large effort to port them onto existing systems - including already standardised models. There are many different curves or primitives and thus choices for outlining protocols, the need for ECC in zero knowledge is fundamental to the design of a lot of modern ideas. Many blockchains need to use signature schemes in order to achieve scalability. The underlying ideas is that signature schemes can be used to reduce the size of the signature, or compress multiple signatures into one and ultimately reduce the size of the block - which allows more transactions per block. Notable signature schemes which are interoperable with elliptic curves are the Elliptic Curve Digital Signature Algorithm (ECDSA), which is used in Bitcoin. As well as Edwards-curve Digital Signature Algorithm (EdDSA), which was designed by Bernstein et al. in 2011 to provide high speed signatures that do not forgo any security parameters. EdDSA is a variant of the Schnorr signature algorithm, which was designed by Claus Schnorr to generate short and efficient signatures.\\\\ 83 | 84 | Having statements proved in zero-knowledge is paramount in maintaining a high level of privacy. Unfortunately, conducting proofs about signature schemes, in zero knowledge, is non-trivial; this is because of the fields in which the two different protocols operate. A signature algorithm, such as ECDSA relies upon a finite base field of an elliptic curve, where all of the operations are performed across the integers, made modular for some $prime$ $p$. However, to perform signatures in zero knowledge inexpensively, they need to be done in the scalar field of the group where the proof system operates; this difference in use of finite fields is where we have the mismatch when trying to align the protocols. \\\\ 85 | 86 | In 1985, Koblitz and Miller independently introduced elliptic curves into public key cryptography (PKC), they proved to be an improvement to existing primitves due to their short key sizes which lead to no compromise in security - as a 256 bit elliptic curve public key will provide similar security to a 3072 bit RSA public key. Since the 2004, there has been a surge in the use of elliptic curves for PKG; the choice for elliptic curves has grown tremendously and has lead to an eclectic range of options when selecting or constructing elliptic curves. Being spoilt for choice sadly doesn't mean each option is an all-purpose fit, as elliptic curve models have multitude of features which differ depending on design; often regarded as factors of opportunity cost within ECC. \\\\ 87 | 88 | {\bf A profound solution}. In this work, we present an elliptic curve that is capable of performing ECC operations in zero knowledge, with bulletproofs as the argument. elaborate on how to use embedded curves to to extend the circuit operations to those which exceed the traditional bounds of constraint systems. We have constructed a curve, across the scalar field of curve25519 to extend the rang of EC operations inside bulletproofs, with increased security at minimal overhead.\\\\ 89 | 90 | curves elliptic curve cryptography performed perfo l all of these operations can be performed a with those which rely upon elliptic curves there are a multitude of features which are affected depending on design; often regarded as factors of opportunity cost within Elliptic Curve Cryptography (ECC). However, some contemporary techniques can be used to better facilitate systems that rely so heavily upon these primitives. Since many previous protocols are proven to be secure, it is $often$ far more efficient to add to these standards with compound technologies rather than seeking entire system replacements. \\\\ 91 | 92 | One of the most used in state of the art cryptography is the constructing of Zero Knowledge (ZK) proofs for nearly universal computation. As is with many cryptographic protocols, there is a choice of which proof system is best tailored to a system. Which includes a trade off, between proof sizes, verification times and other factors making up a ZK proof. For particular proof systems, their expression relies upon an elliptic curve and an arithmetic circuit. The elliptic curve here is a function used to encode the public outputs which are represented as field elements, upon which a lot of operations rely. The operations for these proofs systems, however, are expressed in terms of a circuit which is determined by scalar curve arithmetic. This unfortunately restricts the operations which can be performed as they are dependent upon standard arithmetic circuit outputs - addition, multiplication, subtraction and division. Many protocols such as Elliptic Curve Digital Signature Algorithms (ECDSA), which are performed using field encodings, are in operable through the medium of generic ZK proofs which are expressed in terms of a circuit. \\\\ 93 | 94 | {\bf A profound solution}. 95 | In section 3, we elaborate on how to use embedded curves to to extend the circuit operations to those which exceed the traditional bounds of constraint systems. We have constructed a curve, across the scalar field of curve25519 to extend the rang of EC operations inside bulletproofs, with increased security at minimal overhead.\\\\ 96 | As with all elliptic curves, their construction will strongly influence the outcomes of the protocols in which they are implemented. In addition to this, there can be discrepancies in both the security and speed of cryptographic systems dependant upon on how they're implemented. For this reason, we wanted to construct the embedded curve such that we can make use of the the fastest formulas for elliptic curves, which are for Twisted Edwards curves. The Edwards form of a curve is considered complete, as any two inputs, given as x and y, provide a correct result. In conjunction to their complete formulas, Twisted Edwards curves have been proven by Bernstein et al, to be Birationally equivalent to Montgomery curves. Which fit the purpose of the augmented construction, as Montgomery operations in arithmetic circuits were proven by the Z-cash team to provide a fast Montgomery ladder for in circuit multiplication. Whilst these curves models can provide some of the fastest and most simplistic operations, they do provide issues in security. Neither Montgomery, nor Edwards curves deliver prime order groups in their implementations. They provide curves which have a cofactor, $h$, which multiplies the prime of the subgroup to give the group order. Whereas curves like Weierstrass give prime order but their formulas are too inefficient for circuit operations.\\\\ 97 | 98 | For non prime order curve groups, the mismatch in desirability of prime order curves and inability to implement one directly from the curve can be patched with uniquely tailored modifications. However, these fixes oft become perplexing to the non-implementors and with higher level protocols they are seldom straightforward. Using curves which provide prime order groups, such as Weierstrass Curves, have slower formulae and are very difficult to implement in constant time. Plentiful curve families allow for the encoding of different related curves for protocol specific purposes. For example, [] library uses Twisted Edwards forms for out of circuit operations like public key generation to exploit the high speed formula but uses Montgomery form for in circuit operations to benefit from the ladder multiplication. If an ad hoc fix needs to be given to each related curve model, then the implementation can become tedious and very complex.\\\\ 99 | 100 | {\bf A centric solution}. 101 | In section 4, we explain how to use the Ristretto technique, which constructs prime order Edwards curves from non prime order groups, with our embedded curve, to compress the cofactor such that $h$ = 1. Ristretto makes use of the relationship between curves and provides a fix for the cofactor complication for all models in one place.\\\\ 102 | 103 | Alongside the companies which revolve around the idea of privacy at the grassroots of society, such as Z-cash and Monero, the privacy cryptocurrencies, there are many more areas where signature schemes are handling sensitive data which can be easily expoloited. For example, when signing to a website the website privacy. 104 | 105 | \subsection{State of the Art} 106 | 107 | [Work in progress] 108 | 109 | %TODO: Talk about zcash, ethereum, etc. 110 | 111 | \subsection{Our Contributions} 112 | 113 | Here we present an elliptic curve, created for a safe and efficient elliptic curve operations inside discrete log based proofs; called Sonny. Sonny is defined as an embedded curve which the gives the input for the proofs and the outer curve, Curve25519, will be used to implement the proof itself. \\\\ 114 | 115 | This curve is used to prove the outcomes of elliptic curve functions in general knowledge. An elliptic curve statement, such as a signature scheme, allows a for the generation and verification of digital signatures from an EC key pair. However, such statements cannot be made in ZK as they are made with the Elliptic curve operations and not scalar arithmetic. With the Sonny curve, elliptic curve operations can be performed using inside circuits, with bulletproofs as the argument, so that we have ZK proof statements for signatures. \\ 116 | 117 | 118 | \section{Notation and Formulae} 119 | 120 | \subsection{Elliptic Curves} 121 | 122 | \begin{itemize} 123 | 124 | \item Finite field: let \Fp{ }denote a prime finite field with characteristic $\neq {2}\vee{3}$. 125 | 126 | \item Edwards curve: let $\varepsilon_{a,d}$ denote an Edwards curve, given by equation 127 | $$ {a}x^2+y^2=1+{d}x^2y^2, $$ 128 | where {$d$} and {$ad$} are non-square elements of $\Fp$ and with no points at infinity. %TODO: what do you mean with no points at infinity? 129 | In this paper, the primary focus is upon Twisted Edwards curves, where $a = -1$. 130 | The identity point of an Edwards curve, $\varepsilon$, where (X,Y) $\epsilon$ in \Fp, is given encoded to $(0,1)$. When Edwards points are expressed in Extended Twisted coordinates, the identity encoding is given by $(X : Y : Z : T) = (0 : 1 : 1 : 0)$. 131 | 132 | \item Montgomery curve: ${M}_{a,\frac{2-4d}{a}}$ is a Montgomery curve, given by equation 133 | $$y^2=x^3+Ax^2+Bx.$$ 134 | A Montgomery curve is birationally equivalent to an Edwards curve - a definition used for algebraic substitution - where its point at of infinity is the identity point, denoted as $(0 : 1 : 0)$. 135 | 136 | \item Jacobi curve: $\jmath_{a^{2},a-{2d}}$ is a Jacobi curve, given by an equation of the form 137 | $$y^2 = {e}x^4 + 2Ax^2 + 1.$$ 138 | A Jacobi curve, better known as a Jacobi quartic, is central to all curve models and to utilise this curve relationship we will only be using Jacobi curves where $e = {a}^2$, as such curves have a full 2-torsion point. 139 | 140 | \item Torsion points: An element $[P]$ in $G$ is a torsion point if there is a mapping of $M$, by means of multiplication, where $M \cdot\ [P] = 0_{G}$. Torquing elements for a curve form a subgroup, $G[M]$, where the order is divisible by ${M}^2$. The torsion subgroups for this curve family have order 1, 2 or 4. 141 | 142 | \item Isogeny: An isogeny $\varphi$ is a function which maps algebraic groups whilst preserving the group structure. This mapping must satisfy the properties of being surjective and having a finite kernel. The isogeny, in this paper, is used to transport an encoding between different curve models. 143 | 144 | \item Curve forms: $\varepsilon_{a,d}$; ${M}_{a,\frac{2-4d}{a}}$; $\jmath_{a^{2},a-{2d}}$ These curve models are all isogenous to one another. The Edwards, Montgomery and Twisted Edwards are independently 2-isogenous to the Jacobi quartic and are therefore 4-isogenous to one another. 145 | 146 | \item Arithmetic circuits: These are the computational models for computing circuits. They are universally bound to add and multiply, which are the functions performed at each node on all given inputs. 147 | 148 | \item Cofactor compression: This refers a quasi-construction of cofactor 1 curves from cofactor 8 groups. Also known as cofactor division, it involves the process of point compression when points of order 4 or 8 are produced. 149 | 150 | \end{itemize} 151 | 152 | \subsection{Zero-Knowledge Proofs} 153 | 154 | [Work in progress] 155 | 156 | \subsubsection{Bulletproofs} 157 | 158 | [Work in progress] 159 | 160 | \newpage 161 | 162 | \section{Sonny Elliptic Curve} 163 | 164 | %TODO: Explain Ed-255, etc. 165 | 166 | 167 | \subsection{Definition} 168 | \noindent 169 | Let $\Fp$ be the prime finite field with $p$ elements, where 170 | \begin{align*} 171 | p = 2^{252} + 27742317777372353535851937790883648493. 172 | \end{align*} 173 | 174 | \begin{defn}[Sonny] 175 | Let $C$ be the twisted Edwards elliptic curve defined over $\Fp$ 176 | described by equation 177 | $$ -x^2 + y^2 = 1 + \frac{126296}{126297}x^2y^2. $$ 178 | We call {\it Sonny} the curve $E = C(\Fp)$. That is, $E$ is the subgroup of $\Fp$-rational points of $C$. 179 | \end{defn} 180 | % 181 | \subsection{Order} 182 | \noindent Sonny has order 183 | \begin{align*} 184 | n = 2^{252}+115924404605461509904689566245241897752, 185 | \end{align*} 186 | which factors in $h \times r$ where $h=8$ and 187 | \begin{align*} 188 | r = 2^{249}+15114490550575682688738086195780655237219 189 | \end{align*} 190 | is a prime number.\\ 191 | 192 | \subsection{Security Level} 193 | %TODO: Luke? 194 | It is claimed that the security level of the curve is of $N\approx 127$. We show why here. 195 | 196 | 197 | \subsection{Forms} 198 | 199 | \subsubsection{Montgomery} 200 | \begin{itemize} 201 | \item Equation $B y^2 = x^3 + A x^2 + x$ 202 | \item Parameters $A = 505186$, $B = 1$ 203 | \item Generator $G = (x_0, y_0)$ with coordinates 204 | \begin{align*} 205 | x_0 = \\ 206 | y_0 = 207 | \end{align*} 208 | \item Base point $B = (x_1, y_1)$ with coordinates 209 | \begin{align*} 210 | x_1 = \\ 211 | y_1 = 212 | \end{align*} 213 | \end{itemize} 214 | 215 | \subsubsection{Twisted Edwards} 216 | \begin{itemize} 217 | \item Equation $a x^2 + y^2 = 1 + d x^2 y^2$ 218 | \item Parameters $a = -1$, $d= -\frac{126296}{126297}$. %TODO: Change to field rep. 219 | \item Generator $G = (x_0, y_0)$ with coordinates 220 | \begin{align*} 221 | x_0 = \\ 222 | y_0 = 223 | \end{align*} 224 | \item Base point $B = (x_1, y_1)$ with coordinates 225 | \begin{align*} 226 | x_1 = \\ 227 | y_1 = 228 | \end{align*} 229 | \end{itemize} 230 | 231 | \subsubsection{Conversion maps} 232 | The following rational maps convert points of Sonny from one form of the curve to another \cite[Theorem 3.2]{teds}. %TODO: Add reference. 233 | \begin{itemize} 234 | \item Montgomery to Twisted Edwards 235 | \begin{align} 236 | \label{eq-mon-to-ted} 237 | (u, v)&\mapsto \left(\frac{u}{v}, \frac{u-1}{u+1}\right) 238 | \end{align} 239 | \item Twisted Edwards to Montgomery 240 | \begin{align} 241 | \label{eq-ted-to-mon} 242 | (x, y)&\mapsto \left(\frac{1+y}{1-y}, \frac{1+y}{(1-y)x}\right) 243 | \end{align} 244 | \end{itemize} 245 | 246 | \subsection{Curve Generation} 247 | 248 | We start by deterministically generating a Montgomery elliptic curve $E^M$ over $\Fp$ and then setting the generator and base points. Afterwards, we convert the curve and the points to twisted Edwards form using the maps of theorem [REF]. %TODO: Add ref. 249 | We finally rescale all parameters so that the parameter $a = -1$. This last step has the advantage that the arithmetic in the curve can be speeded up \cite{scaling}. %it requires less operations 250 | 251 | Our algorithm takes prime number $p$ and returns a twisted Edwards curve defined over $\Fp$. The specific outputs of the algorithm are: 252 | \begin{itemize} 253 | \item The prime order of the finite field the curve is defined over (which is the input $p$). 254 | \item Parameters $a$ and $d$ of the equation that defines the twisted Edwards curve. 255 | \item Order of the curve and its decomposition into the product of a cofactor and a large prime. 256 | \item Generator and base points. 257 | \end{itemize} 258 | 259 | As the finite field is defined by the input $p$, no specification of this parameter is required. In the same way, the order of the curve and its decomposition is determined once the parameters of the equation describing the curve are fixed. Hence, the only remaining specifications are parameters $a$ and $d$ and the choice of generator and base point. 260 | 261 | \subsubsection{Choice of Montgomery Equation} 262 | 263 | We start by finding a Montgomery curve defined over $\Fp$ where $p$ is the order of Ed255 used to generate and verify Bulletproofs. given prime number. The assumptions and algorithm presented are based on the work of \cite{generation} and Zcash team \cite{github:zkcrypto:derive}. 264 | 265 | The algorithm takes a prime $p$, fixes $B = 1$ and returns the Montgomery elliptic curve defined over $\Fp$ with smallest coefficient $A$ such that $A-2$ is a multiple of 4. 266 | % Choosing curve constants with extremely small sizes or extremely low (or high) hamming weight can be used to eliminate the computational overhead of a field multiplication. 267 | This comes from the fact that this value is used in many operations, so trying to keep it smaller and divisible by four is a reasonable assumption \cite{generation}. As with $A=1$ and $A=2$ the equation does not describe a smooth curve, the algorithm starts with $A=3$. 268 | 269 | For primes congruent to 1 mod 4, the minimal cofactors of the curve and its twist are either $\{4, 8\}$ or $\{8, 4\}$. We choose a curve with the latter cofactors so that any algorithms that take the cofactor into account don't have to worry about checking for points on the twist, because the twist cofactor will be the smaller of the two \cite{generation}. For a prime congruent to 3 mod 4, both the curve and twist cofactors can be 4, and this is minimal. 270 | 271 | \subsubsection{Choice of Generator and Base Points} 272 | 273 | To pick a generator $G_0$ of the curve, we choose the smallest element of $\Fp$ that corresponds to an $x$-coordinate of a point in the curve of order $n$. Then as a base point, we define $G_1 = 8\cdot G_0$, which has order $l$. 274 | 275 | \subsubsection{Transformation to Twisted Edwards} 276 | 277 | Use the birational map of equation (\ref{eq-mon-to-ted}) to get the coefficients, generator and base points in twisted Edwards form. 278 | 279 | \subsubsection{Optimisation of Parameters} 280 | 281 | As pointed out in \cite[Sec. 3.1]{scaling}, if $-a$ is a square in $\Fp$, it is possible to optimise the number of operations in a twisted Edwards curve by scaling it. 282 | 283 | \begin{thm} \label{thm-scale} %[Rescaling of E] 284 | Consider a twisted Edwards curve defined over $\Fp$ given by equation $ax^2+y^2= 1 +dx^2y^2.$ If $-a$ is a square in $\Fp$, then the map $(x, y) \to (x/\sqrt{-a}, y)$ defines the curve $-x^2+y^2= 1 +(-d/a)x^2y^2.$ We denote by $f = \sqrt{-a}$ the scaling factor. 285 | \end{thm} 286 | 287 | \begin{proof} 288 | The result follows directly from the map's definition. 289 | \end{proof} 290 | 291 | \subsection{Security Analysis} 292 | 293 | This section specifies the safety criteria that the elliptic curve should satisfy. The choices of security parameters are based on the joint work of Bernstein and Lange summarised in \cite{safe-curves}. To this purpose, we defined an algorithm that should be run after finding the elliptic curve as proposed in previous section. The algorithm is based on the the code of Daira Hopewood \cite{github:daira:safe}, which is an extension of the original SAGE code \cite{safe-curves} to general twisted Edwards curves. 294 | 295 | \subsubsection{Curve Parameters} 296 | 297 | Check all given parameters describe a well-defined elliptic curve over a prime finite field. 298 | 299 | \begin{itemize} 300 | \item The given number $p$ is prime. 301 | \item The given parameters define an equation that corresponds to an elliptic curve. 302 | \item The product of $h$ and $l$ results into the order of the curve and the point $G_0$ is a generator. 303 | \item The given number $l$ is prime and the point $G_1$ is a generator of $\G$. 304 | \end{itemize} 305 | 306 | \subsubsection{Elliptic Curve Discrete Logarithm Problem} 307 | 308 | Check that the discrete logarithm problem remains difficult in the given curve. For that, we check it is resistant to the following known attacks. %ECDLP attacks. 309 | 310 | \begin{itemize} 311 | \item {\it Rho method} \cite[Sec. V.1]{seroussi}: we require the cost for the rho method, which takes on average around $0.886 \sqrt{l}$ additions, to be above $2^{100}$. 312 | \item {\it Additive and multiplicative %(MOV attacks) 313 | transfers} \cite[Sec. V.2]{seroussi}: we require the embedding degree to be at least $(l-1)/100$. 314 | \item {\it High discriminant} \cite[Sec. IX.3]{seroussi}: we require the complex-multiplication field discriminant $D$ to be larger than $2^{100}$. 315 | % Although it is not clear it is better for security to have large $|D|$, there are speed ups to the rho method for some curves where this value is very small. 316 | \end{itemize} 317 | 318 | \subsubsection{Elliptic Curve Cryptography} 319 | 320 | \begin{itemize} 321 | \item {\it Ladders} \cite{montgomery}: check the curve supports the Montgomery ladder. 322 | \item {\it Twists} \cite[twist]{safe-curves}: check it is secure against the small-subgroup attack, invalid-curve attacks and twisted-attacks. 323 | \item {\it Completeness} \cite[complete]{safe-curves}: check if the curve has complete single-scalar and multiple-scalar formulas. It is enough to check that there is only one point of order 2 and 2 of order 4. 324 | \item {\it Indistinguishability} \cite{indist}: check availability of maps that turn elliptic-curve points indistinguishable from uniform random strings. 325 | \end{itemize} 326 | 327 | \subsection{Cofactor Compression} 328 | 329 | \subsubsection{Isogenies} 330 | 331 | \subsubsection {Curve Mappings} 332 | 333 | \section{ECC for Zero Knowledge Proofs} 334 | 335 | Elliptic Curve arithmetic uses the finite field of integers reduced mod$p$, where $p$ is some usually large prime. The use of finite fields as the extension of elliptic curves allows make certain cryptographic assumptions about the order of the set. The choice of finite fields for elliptic curves, known as base curves, provide a cyclic group which gives precise knowledge to the amount of bits that need to be stored by point outputs. As stated, the base fields dictate the operations for the elliptic curves and thus selection of these fields affects the security, speed and simplicity of the implementation of the curve. Supplementary to standard operations performed mod $p$, there are many protocols can be performed in ECC which are implemented using finite sets but do not make use of the base field. As previously touched on, they rely upon another prime order field, which is the curves scalar field, also known as the prime subgroup. Elliptic curve operations are utilised for an eclectic variety of reasons within cryptography, the predominant reason is the security that couples each of operations - resulting from hard a DLP.\\\\ 336 | 337 | Elliptic curves are capable of generating public/private key pairs, which can be signed with a digital signature scheme to become security keys, and these security keys are rapidly becoming replacements for many password schemes. For example, security keys are used to show attestation certificates for websites, which allows the website to verify that a user is genuine by receiving a copy of a users authenticity. The issue arises when a verified key is registered, as becomes possible for a server to learn the make, model, and batch of the verification for the key. This data can be manipulated by website owners and then used to discriminate which batches and models can be trusted in the future. If these key signatures and EC statements are generated in Zero Knowledge, we can provide the proof of the users signed certificate without providing additional information about the signature; this can mitigate the security risks that are tied to the data sensitivity.\\\\ 338 | 339 | Solving this issue involves using a zero-knowledge proof schemes. For our scheme, we choose bulletproofs. The existing systems like the verification systems are already deployed and because their operations are performed on on the base field, and not a scalar field, they are not directly updateable with a large range of contemporary techniques. This paper and findings focuses on Zero Knowledge proofs as the 'add-on technology' for existing schemes. \\\\ 340 | 341 | Elliptic curves have both a base field, which is the finite field in which they are defined; and a scalar field, which is associated with the number of points on the curve. DL based proofs which use a curve and a circuit rely upon both of the finite fields. The base field here is a function used to encode the public coordinates which are represented as field elements. However, as the operations are performed mod$p$, where $p$ is prime, the outputs are reduced to the prime scalar field. Thus operations which require the base field, cannot be performed inside proof systems which use arithmetic circuits as an expression. As a result the ZK outputs are limited to what circuit operations can be performed by the elliptic curves scalar field. The circuit, in this case, encodes relation between the input and outputs. 342 | 343 | \subsection{Efficient ZK for higher operability} 344 | 345 | To extend the range of ZK elliptic curves operations to those which employ the base field, we have built a curve which has a base field equal to the scalar field of Curve25519. This is defined in the following manner: Let $\varepsilon_{1}$ and $\varepsilon_{2}$ be elliptic curves. Where the prime subgroup order, or scalar field, of $\varepsilon_{1}$ is $r$; we define $\varepsilon_{2}$ over the base field $F_p$, where \#$F_p$ = $r$. 346 | This will allow us to perform fast in circuit operations using $\varepsilon_{2}$ as the embedded curve within the scalar field of $\varepsilon_{1}$.One particular current issue that embedding curves helps to alleviate is the adding to, or updating of, existing software protocols with privacy techniques so that already deployed systems can benefit from high levels of privacy preservation. By constructing this, we are making a quasi representation of one finite field as both a scalar and a base field. We can therefore encode the field based protocols curve over the scalar field of existing systems - and protocols such as key signature verification, can be performed inside a Zero Knowledge proof. We present a means of verifying only the scalar operation, in Zero Knowledge , so that Zero Knowledge proof of statements derived for signature schemes can be proven rather than the signature itself. This is performed by expressing ZK proof of computations as the argument for computational models, such as arithmetic circuits.\\\\ 347 | 348 | In the case of Zerocaf protocol, we have the outer curve operations, using Curve25519, which implement the ZK proof system, where the operations are performed as integers mod the base field. Then there is Sonny, the inner curve, known as the embedded curve which is the curve we make the proofs about. For the case of signature schemes, like Elliptic Curve Digital Signature Algorithm (ECDSA), the operations for the signature generation are made using Sonny then the Zero Knowledge arguments for these outputs are generated using Curve25519. By setting the scalar field of Curve25519 as the base field of Sonny, all the operations are efficient when expressed in terms of a circuit. The validation keys here are effectively turned into discrete log proofs, as the generation of ZK values is performed in one amalgamated protocol, even though it comes from two different curves. \\\\ 349 | 350 | Many software layers require information from the user - just like authentication certificates for websites, where the type of secret keys is known to the website for verification. The information given is often burnt into the hard memory of the website, which can be used by the software owners to discriminate against different keys and brands of keys hence the need to preserve privacy on these existing protocols. 351 | 352 | \subsection{Circuits} 353 | 354 | An circuit is combinational set of operations which are aligned in a set or series for the ultimate purpose of optimising otherwise standardised mathematical process. The operations, better known as the basic arithmetic operations (addition, subtraction, multiplication, and division), are theoretically performed in constant time. This statement is derived from the fact that the required RAM required is roughly equal for all operations. However, when computing these operations for some large integers, it is apparent that the magnitude greatly affects the costs of RAM. Thus giving a discrepancy for computational time between the theoretical arguments and the practical implementation. When the expression of these arithmetic operations is performed in a circuit, it is referred to as an arithmetic circuit. When expressed for computations within computer systems, any arithmetic circuit is constructed from various combinational elements, which are connected by wires. A combinational element is fixed element which performs a specific function from a constant number of inputs and outputs. Circuits are used alongside the elliptic curves to construct discrete log based proof systems; when the circuit is defined over the scalar field. 355 | 356 | \section{Prime Order Groups} 357 | 358 | 'A group of prime order' is always a cyclic group, that has a mapping - which respects the group structure - to the quotient of the group of integers by a subgroup. This subgroup is generated by a prime number. Groups of prime order are often a prerequisite to crytpographic prototcols, as they provide the basis for a hard DLP and thus increased security for implementation. For implementation, we have made efficiency the most paramount factor for curve selection, which led to us choosing a Twisted Edwards curve form. This is because the Edwards forms of the curves provide the fastest known formulas, which can be accredited to extended Twisted Edwards, introduced by Hysil et al, where auxiliary points are used with fewer field inversions. As elliptic curves are Abelian groups, they provide varying order for their respective groups. Edwards curves and their birational Montgomery equivalents, provide 'not quite' prime order groups over finite fields - the absence of prime groups can lead to timing variations when implementing protocols such as the signature schemes Sonny implements. Instead of certain Elliptic curve groups being prime, they have a cofactor $h$, meaning that $h \cdot q$ is the group order, where $h > 1$ and $q$ is a large prime. Having this property where $h > 1$ can lead to many implementation complexities.\\\\ 359 | 360 | There are cofactor relates attacks designed to extract information, in the form of bits, about a users private key. When generating a public key, it is ideally performed using a point operation on a given curve point, where a chosen scalar outputs a new point, modulo the base field. This provides a public key, from which the scalar, known as the private key, cannot be extracted. However, if points on the curve are selected by attackers to have order which divides $h$, then presented as valid curve points, they can be mistakenly used by a user. If an incognizant user generates a public key by inputting a secret scalar to a function which operates with points of order $h$, then the attacker can gain some bits about the input scalar. Whereas within a prime order group, there is no means of generating valid points which have order dividing $h$. The abstraction of having non prime order groups can be solved with specialised modifications towards individual protocols. One notorious method is to multiply points by the cofactor and check the result; if the resulting point is the identity point then it can be discarded. Many of the individual techniques produce continuous and substantial flaws, especially with regards to patchwork comprehension, which occurs when the protocols are being implemented by those who did not design them, i.e. Implementors not knowing at which step to multiply by $h$. 361 | 362 | \subsection{Cofactor Compression} 363 | 364 | There are various advantages and disadvantages to having a cofactor larger than one, therefore a thorough analysis must be performed, so that it is known whether or not cofactor manipulation is needed. For all curves, except for Hessian curves, the cofactor is divisible by 4. To become more useful to a broad spectrum of cryptography, Ristretto is apt for a large number of curves, which have a cofactor of 8 or 4. When the cofactor is greater than 1 multiple operations can be hindered. A quotient group can be constructed to allow for the implementation of prime order groups, thus effectively compressing the cofactor, by applying the Ristretto technique. This technique requires just one additional step to Mike Hamburgs decaf proposal for cofactor-4 curves. The technique works using following four functions:\\\\ 365 | 366 | ${Equality}$ ${testing}$ This function checks the equality of group elements. \\\\ 367 | 368 | ${Encode}$\ The encoding function is applied to an Edwards point and this becomes the internal representation for the new "Ristretto point', meaning the same Edwards point operations are performed on the Ristretto point, and with no overhead cost. The function encodes the elements as byte strings so that that the Ristretto elements can be encoded identically.\\\\ 369 | 370 | ${Decode}$\ This function decodes the byte strings into the internal representations of Ristretto points. There is also a validity check which assesses the canonical representation of points, and only accepts those which are outputs of the encoding function. \\\\ 371 | 372 | ${Curve}$ ${hashing}$\ For many protocols, mapping elements in a group to a curve is done by a hash function, as it provides standardised digests which can be encoded. Ristretto using an Elligator 2, which gives a 1:1 mapping of group elements to the curve. Elliga 373 | 374 | \subsection{Isogenies} 375 | 376 | By using the Ristretto technique, we are able to solve all cofactor related issues in one place and with one step. This is facilitated by its use in the relationship of the curves, and how this lets us transport the cofactor compression for curves, via the isogeny, to another curve in the same family. Which in turn means we work with prime order points in any operations of ECC. Otherwise, the implementation would have to deal with the issue at varying stages which is dependent upon a protocols ultimate design. An isogeny is a function which maps one algebraic group to another, whilst maintaining the structure of the group - which in terms of elliptic curves, means that a curve is allowed curve to take on the values of another and preserve the same point addition method. These functions are non-constant and are used as a tool for effective 'transportation' between curve models. Just as with all concrete mathematical formulae, these functions have a domain and co-domain, which means that given these two, it is possible to compute the function itself. In this document isogenies will be given the generalization as the multiplication by $m$ map, where they have a finite kernel and are restricted to rational mappings. 377 | A deeper understanding of isogenies for elliptic curves has greatly advanced the field of ECC, as it is possible to deduce one mapping from the form of another. Additionally, if these relationships are well understood then they can be applied or integrated into other functions and broaden their domain of propriety to more use cases.\\\\ 378 | 379 | When there exists a non-constant function, $\varphi$, which gives a rational mapping from one group to another denoted as $\varphi$ : $\varepsilon$ $\rightarrow$ $\varepsilon\prime$. This mapping from $\varepsilon$ to $\varepsilon\prime$ has degree $n$. Where there is this separable isogeny, then exists a mapping from $\varepsilon$ to $\varepsilon\prime$, which is known as the dual isogeny, $\hat{\varphi}$, where both functions have degree $n$. The dual isogeny is conveyed as $\hat{\varphi}$ : $\varepsilon\prime$ $\rightarrow$ $\varepsilon$ of degree $n$. The isogeny $\hat{\varphi}$ here is known as the dual of $\varphi$, such that $\hat{\varphi}$ $\circ$ $\varphi$ is the multiplication by $n$, where $n$ = $\hat{\varphi}$ $\circ$ $\varphi$, from $\varepsilon$ to $\varepsilon\prime$. This dual isogeny has certain properties which allow for the two way transportation of functions between curves. These can be exploited to provide abstraction of protocols where it would otherwise be inapplicable. 380 | 381 | \subsubsection {Curve Mappings} 382 | 383 | As curve models $\varepsilon_{a,d}$; ${M}_{a,\frac{2-4d}{a}}$; $\jmath_{a^{2},a-{2d}}$, have different implementation features we can utilise these relationships to achieve the implementation we desire, namely a prime order curve. It is possible to construct prime order curves using the Montgomery and Edwards curve forms by transporting encoding to and from the Jacobi quartic, via isogenies. The functions for cofactor compression would typically be used on the Jacobi quartic form, by means of canonically selecting outputs for curve points. Now this selection process can be applied to the Edwards and Montgomery form by integrating it to the function which maps between them. \\\\ 384 | 385 | \section{Elliptic Curve Operations in Zero Knowledge} 386 | 387 | Elliptic curve operations are utilised for an eclectic variety of reasons within cryptography, the predominant reason is the security that couples each of operations - resulting from hard a DLP. Elliptic curves are capable of generating public/private key pairs, as well as signing with them for accessing websites, and these keys are rapidly becoming replacements for many password schemes. The issue arises when a verified key is registered, as becomes possible for a server to learn the make, model, and batch of the verification for the key. This data can be manipulated by website owners and then used to discriminate which batches and models can be trusted in the future. If we generate these key signatures and EC statements in Zero Knowledge then we can mitigate the security risks that are tied to the data sensitivity. 388 | 389 | Unfortunately, in their raw form, elliptic curve field operations are not compatible with zero knowledge proof systems which 390 | 391 | \section{Implementation} 392 | 393 | There exists a comprehensive and detailed implementation of Sonny Curve in a cryptographic library named Zerocaf. This implementation is done by Dusk Network and can be found here {\url{https://github.com/dusk-network/dusk-zerocaf}}.\\\\ 394 | 395 | The difficulty of breaking cryptographic systems stems solely from the hardness of the mathematical problems on which they are based. However, this proves not to be the case in practical implementations because of side channel attacks, which target the implementation as medium of encoding the cryptography - to circumvent these attacks, the operations are performed in constant time. The use of Edwards curve form results in a uniform implementation which better facilitates these constant time operations. Whereas the efficiency for in circuit operations can greater benefit from the variable time implementations. These operations are applied when there is no secret data to protect. We therefore present an implementation which performs statement proofs in constant time with high security, and verification in variable time and high speed. \\ 396 | 397 | 398 | 399 | 400 | 401 | 402 | \section{Future Work} 403 | 404 | R1CS optimisation for constraints 405 | 406 | Further isogeny use cases 407 | 408 | \section{Conclusions} 409 | 410 | \section{Acknowledgements} 411 | 412 | We would like to give special thanks to Henry de Valence for his personalised help in understanding the Ristretto Protocol and being so responsive for questions regarding the implementation. 413 | %We would also like to show our strong appreciation for Marta Bellés Muñoz for her contributions with the discrete log based theory used in the understanding of this project. 414 | 415 | \newpage 416 | 417 | %\bibliographystyle{unsrt} 418 | \bibliographystyle{alpha} 419 | \bibliography{lit} 420 | 421 | \end{document} 422 | -------------------------------------------------------------------------------- /examples/basic_ops.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | extern crate rand; 3 | /// The purpose of this implementation is to provide support for one of the most 4 | /// commonly used operations in Elliptic Curve Cryptography (ECC), which is Random Scalar Mul. 5 | /// 6 | /// This is one of the first steps to take on the implementation of algorithms, 7 | /// such as Diffie-Hellman Key Exchange. 8 | /// 9 | /// Let G be a point over Sonny, let k = Scalar random value over the Sonny Sub-group. 10 | /// Let P = G*k; 11 | extern crate zerocaf; 12 | 13 | use zerocaf::edwards::EdwardsPoint; 14 | use zerocaf::field::FieldElement; 15 | use zerocaf::scalar::Scalar; 16 | 17 | use rand::{thread_rng, Rng}; 18 | 19 | fn main() -> () { 20 | // Let G be an `EdwardsPoint` which is a point over the Twisted Edwards Extended Coordinates. 21 | let G: EdwardsPoint = EdwardsPoint { 22 | X: FieldElement([23, 0, 0, 0, 0]), 23 | Y: FieldElement([ 24 | 1664892896009688, 25 | 132583819244870, 26 | 812547420185263, 27 | 637811013879057, 28 | 13284180325998, 29 | ]), 30 | Z: FieldElement([1, 0, 0, 0, 0]), 31 | T: FieldElement([ 32 | 4351986304670635, 33 | 4020128726404030, 34 | 674192131526433, 35 | 1158854437106827, 36 | 6468984742885, 37 | ]), 38 | }; 39 | 40 | let scalar: Scalar = rand_scalar_generation(); 41 | println!("{:?}", scalar); 42 | 43 | // Perform G*k, Point mul uses the `add_and_double` standard algorithm. 44 | let P = &G * &scalar; 45 | println!("{:?}", P); 46 | } 47 | 48 | /// Generate a random `Scalar` defined over the sub-group field 49 | /// modulo: `2^249 - 15145038707218910765482344729778085401` 50 | pub fn rand_scalar_generation() -> Scalar { 51 | // Gen random 32-byte array. 52 | let mut bytes = [0u8; 32]; 53 | 54 | // Fill the bytes varible with random bytes. We can use the 32 bytes to give 55 | // total randomness, but then we will need to be aware because we can also generate 56 | // values greater than `L = 2^252 + 27742317777372353535851937790883648493` and 57 | // the program will panic if we don't catch the error correctly on the 58 | // `from_bytes()` Scalar method call. 59 | thread_rng() 60 | .try_fill(&mut bytes[..31]) 61 | .expect("Error getting the random bytes"); 62 | 63 | Scalar::from_bytes(&bytes) 64 | } 65 | -------------------------------------------------------------------------------- /sage_codes/LFACTOR_comp: -------------------------------------------------------------------------------- 1 | // LFACTOR Computation 2 | 3 | sage: l = 2^249 + 14490550575682688738086195780655237219 4 | sage: l 5 | 904625697166532776746648320380374280118162305775999595296348570842476562531 6 | sage: (-1 / l) % (2^52) 7 | 1331240223835829 8 | 9 | 10 | //The result is the LFACTOR needed on the Montgomery Reduction algorithm to adjust the number to be divisible 11 | by R mod L it also fits on an u64 as 1331240223835829 < 2^64 -------------------------------------------------------------------------------- /sage_codes/Point computation : -------------------------------------------------------------------------------- 1 | \\\ Base point computation for Sonny Curve. 2 | 3 | sage: prime = 2^252 + 27742317777372353535851937790883648493 4 | 5 | sage: A = 505186 6 | 7 | sage: def findBasepoint(prime, A): 8 | F = GF(prime) 9 | E = EllipticCurve(F, [0, A, 0, 1, 0]) 10 | for uInt in range(1, 1e3): 11 | u = F(uInt) 12 | v2 = u^3 + A*u^2 + u 13 | if not v2.is_square(): 14 | v = v2.sqrt() 15 | point = E(u, v) 16 | pointOrder = point.order() 17 | if pointOrder > 8 and pointOrder.is_prime(): 18 | Q=u^3 + A*u^2 + u 19 | return u, Q, sqrt(Q), point 20 | 21 | sage: res = findBasepoint(prime, A) 22 | 23 | sage: res 24 | 25 | (4, 26 | 8083044, 27 | 2387694734969974503585694617203302024142786955946516383730480941479078023877, 28 | 29 | (4 : 2387694734969974503585694617203302024142786955946516383730480941479078023877 : 1) 30 | 31 | /// Computation of Edwards points in Twisted Edwards format to produce (X:Y:T:Z) from given a X value. 32 | /// Using a manipulated version of the Edwards equation, 33 | /// written below, allows for the computation. 34 | /// a*X^2+Y^2 = 1+d*X^2*Y^2 35 | /// a = -1, d = -126296/126297 36 | /// In fractions in the mod l need to be `inverse_mod`, calculated for d as below: 37 | 38 | sage: p = 2^252 + 27742317777372353535851937790883648493 39 | sage: d = -(126296)/(126297) 40 | sage: d = ((-126296)*inverse_mod(126297,p))%p 41 | sage: d 42 | 951605751702391019481481818669129158712512026257330939079110344917983315091 43 | 44 | /// For use in the equation Y^2 will be written as Y, as sage will attempt to compute the square root. 45 | /// For arbitrarlily chosen X = 14 46 | 47 | sage: X = 14 48 | sage: Y = (-(X)^2-1)*inverse_mod(d*(X)^2-1,p)%p 49 | sage: Y 50 | 51 | 4097294349129061626216953635182512769012007176856180609903321124717525537317 52 | 53 | /// It needs to be checked if the Y here is a quadratic residue in p, 54 | /// using the legendre symbol [http://people.bath.ac.uk/masgks/XX10190/legendresymbol.pdf], 55 | /// if confirmed as QR in p, then tonelli-shanks is used to find the corresponing Y coordinates. 56 | 57 | sage: legendre_symbol(Y,p) 58 | 1 59 | sage: z += 1 60 | ....: c = pow(z, q, p) 61 | ....: 62 | ....: # Search for a solution 63 | ....: x = pow(a, (q + 1)/2, p) 64 | ....: t = pow(a, q, p) 65 | ....: m = s 66 | ....: while t != 1: 67 | ....: # Find the lowest i such that t^(2^i) = 1 68 | ....: i, e = 0, 2 69 | ....: for i in xrange(1, m): 70 | ....: if pow(t, e, p) == 1: 71 | ....: break 72 | ....: e *= 2 73 | ....: 74 | ....: # Update next value to iterate 75 | ....: b = pow(c, 2**(m - i - 1), p) 76 | ....: x = (x * b) % p 77 | ....: t = (t * b * b) % p 78 | ....: c = (b * b) % p 79 | ....: m = i 80 | ....: 81 | ....: return [x, p-x] 82 | ....: 83 | sage: prime_mod_sqrt(Y,p) 84 | [7027685437011822135117075804201712829494335458984232261155589991678118276875, 85 | 209320140320440078856110758841281411362780900395675344846360946607335974114] 86 | 87 | /// Using formulae from (http://eprint.iacr.org/2008/522), Section 3.1., compute T. 88 | /// Set initial Z = 1 89 | 90 | Y = 209320140320440078856110758841281411362780900395675344846360946607335974114 91 | sage: T = (X*Y)%p 92 | sage: T 93 | 2930481964486161103985550623777939759078932605539454827849053252502703637596 94 | sage: print X, Y, T, Z 95 | 14, 96 | 209320140320440078856110758841281411362780900395675344846360946607335974114, 97 | 2930481964486161103985550623777939759078932605539454827849053252502703637596, 98 | 1 99 | 100 | ///Using formulae from (http://eprint.iacr.org/2008/522), Section 3.1. 101 | /// We can perform addition for twisted edwards on two points computed 102 | /// using the aforementioned method. Addition requires two points, P and Q. 103 | 104 | X3 = (X1Y2 + Y1X2)(Z1Z2 − d*T1T2), 105 | Y3 = (Y1Y2 − a*X1X2)(T1T2 + d*T1T2), 106 | T3 = (Y1Y2 − a*X1X2)(X1Y2 + Y1X2), 107 | Z3 = (Z1Z2 − d*T1T2)(Z1Z2 + d*T1T2) 108 | ///all of the above operations are to be performed in modp 109 | 110 | /// Define the above calculated variables as follows: X = X1 : Y = Y1 : T = T1 : Z = Z1 111 | sage: print X1, Y1, T1, Z1 112 | 14, 113 | 209320140320440078856110758841281411362780900395675344846360946607335974114, 114 | 2930481964486161103985550623777939759078932605539454827849053252502703637596, 115 | 1 116 | 117 | /// In order to show a complete Edwards addition in Twisted extended coordinates, 118 | /// a second point must be computed. 119 | /// Take an arbitrary X as 67 and perform the same process. 120 | 121 | sage: X = 67 122 | sage: Y = (-(X)^2-1)*inverse_mod(d*(X)^2-1,p)%p 123 | sage: Y 124 | 2083393178995948293615321623635643301289972308686668478963476666090583806680 125 | sage: legendre_symbol(Y,p) 126 | 1 127 | sage: prime_mod_sqrt(Y,p) 128 | [3941153185566030503197827307080909868202351422646487319508322021660996132587, 129 | 3295852391766231710775359255962084372654764936733420286493628916624458118402] 130 | Y = 32958523917662317107753592559620843726547649367334202 131 | sage: Z = 1 132 | sage: T = X*Y%p 133 | sage: T 134 | 3711942928369658202753473258169825742155759979741931015014609265275066403264 135 | /// /// Define the above calculated variables as follows: X = X2 : Y = Y2 : T = T2 : Z = Z2 136 | sage: print X2, Y2, T2, Z2 137 | 67, 138 | 3295852391766231710775359255962084372654764936733420286493628916624458118402, 139 | 3711942928369658202753473258169825742155759979741931015014609265275066403264, 140 | 1 141 | 142 | sage: print a,d 143 | -1, 951605751702391019481481818669129158712512026257330939079110344917983315091 144 | 145 | sage: print p 146 | 7237005577332262213973186563042994240857116359379907606001950938285454250989 147 | 148 | sage: X3 = ((X1*Y2+Y1*X2)*(Z1*Z2-d*T1*T2))%p 149 | sage: Y3 = ((Y1*Y2-a*X1*X2)*(Z1*Z2+d*T1*T2))%p 150 | sage: t3 = ((Y1*Y2-a*X1*X2)*(X1*Y2+Y1*X2))%p 151 | sage: z3 = ((Z1*Z2-d*T1*T2)*(Z1*Z2+d*T1*T2))%p 152 | sage: print X3, Y3, T3, Z3 153 | 6071577539228590191219387911031602982956051495655581694654126271979753651722, 154 | 837202702872841412924343780706778248153230580612427863707303374823451692769, 155 | 3870569102798123767101920828945730089305537575358572428982223506408632563886, 156 | 5030678076965133398451320860257582818948884882165145613987735041289292101393 157 | 158 | ///Using formulae from (http://eprint.iacr.org/2008/522), Section 3.1. 159 | /// We can perform doubling for twisted edwards on two points computed 160 | /// using the aforementioned method. Doubling requires only one point, P. 161 | 162 | X3 = 2X1Y1(2*Z1^2-Y1^2-a*X1^2) 163 | Y3 = (Y1^2+a*X1^2)(Y1^2-a*X1^2) 164 | T3 = 2X1Y1(Y1^2-a*X1^2) 165 | Z3 = (Y1^2+a*X1^2)(2*Z1^2-Y1^2-a*X1^2) 166 | 167 | sage: print X1, Y1, T1, Z1 168 | sage: print X1, Y1, T1, Z1 169 | 14, 170 | 209320140320440078856110758841281411362780900395675344846360946607335974114, 171 | 2930481964486161103985550623777939759078932605539454827849053252502703637596, 172 | 1 173 | sage: print a,d 174 | -1, 951605751702391019481481818669129158712512026257330939079110344917983315091 175 | sage: print p 176 | 7237005577332262213973186563042994240857116359379907606001950938285454250989 177 | 178 | sage: X3 = (2*X1*Y1)*(2*z1^2-Y1^2-a*X1^2)%p 179 | sage: Y3 = (Y1^2+a*X1^2)*(Y1^2-a*X1^2)%p 180 | sage: T3 = ((2*X1*Y1)*(Y1^2-a*X1^2))%p 181 | sage: z3 = (Y1^2+a*X1^2)*(2*z1^2-Y1^2-a*X1^2)%p 182 | sage: print X3, Y3, t3, z3 183 | 149787030802898863214220589614787467360377956858885734134859441157998105502, 184 | 4114181249139963708922561672280278463269518807069632207462778037420327721750, 185 | 465221815300404819953157336686579853418396566040992296296754217912562254655, 186 | 3604554139948105518509753594085031057181477091926039562012636801913890184366 187 | 188 | 189 | 190 | 191 | /// For scalar multiplication, where the input is a random chosen 192 | /// scalar - denoted by k. A random point P is computed k times, 193 | /// to achieve a new output. First define constants and algorithm 194 | /// then perform computation and check. 195 | 196 | sage: x = 2^252 + 27742317777372353535851937790883648493 197 | sage: F = GF(x) 198 | sage: E = EllipticCurve(F,[0,505186,0,1,0]) 199 | sage: def mult(P,k): 200 | ....: if k == 0: 201 | ....: return E(0) 202 | ....: elif k%2 ==1: 203 | ....: return P + mult(P+P,k//2) 204 | ....: else: 205 | ....: return mult(P+P,k//2) 206 | ....: 207 | sage: P = E.random_element();P 208 | 5051189995337479708433119006747039364870785988521470496097671181243562411695, 209 | 7155958472685660389975401207154951743382380416674787893210035445445872196541, 210 | 1 211 | sage: mult(P,8) 212 | 1868330701290932041393248498391407583880515981499204757603220260047257156875, 213 | 5999066270237031196158421153363394298942525294456370395071609058345162660448, 214 | 1 215 | sage: 8*P 216 | 1868330701290932041393248498391407583880515981499204757603220260047257156875, 217 | 5999066270237031196158421153363394298942525294456370395071609058345162660448, 218 | 1 219 | 220 | -------------------------------------------------------------------------------- /sage_codes/Safe Curve code: -------------------------------------------------------------------------------- 1 | /// This section shows all of the proofs from their 2 | /// written in line with the safecurves document. 3 | 4 | /// Here is the outline of the sage code for 5 | /// the compuatation of values for proving 6 | /// all safe curve criteria. 7 | /// Taken from https://safecurves.cr.yp.to/ (July, 2019) 8 | 9 | import os 10 | import sys 11 | 12 | def readfile(fn): 13 | fd = open(fn,'r') 14 | r = fd.read() 15 | fd.close() 16 | return r 17 | 18 | def writefile(fn,s): 19 | fd = open(fn,'w') 20 | fd.write(s) 21 | fd.close() 22 | 23 | def expand2(n): 24 | s = "" 25 | 26 | while n != 0: 27 | j = 16 28 | while 2**j < abs(n): j += 1 29 | if 2**j - abs(n) > abs(n) - 2**(j-1): j -= 1 30 | 31 | if abs(abs(n) - 2**j) > 2**(j - 10): 32 | if n > 0: 33 | if s != "": s += " + " 34 | s += str(n) 35 | else: 36 | s += " - " + str(-n) 37 | n = 0 38 | elif n > 0: 39 | if s != "": s += " + " 40 | s += "2^" + str(j) 41 | n -= 2**j 42 | else: 43 | s += " - 2^" + str(j) 44 | n += 2**j 45 | 46 | return s 47 | 48 | def requirement(fn,istrue): 49 | writefile(fn,str(istrue) + '\n') 50 | return istrue 51 | 52 | def verify(): 53 | p = Integer(readfile('p')) 54 | k = GF(p) 55 | kz. = k[] 56 | l = Integer(readfile('l')) 57 | x0 = Integer(readfile('x0')) 58 | y0 = Integer(readfile('y0')) 59 | x1 = Integer(readfile('x1')) 60 | y1 = Integer(readfile('y1')) 61 | shape = readfile('shape').strip() 62 | s = readfile('primes') 63 | rigid = readfile('rigid').strip() 64 | 65 | safefield = True 66 | safeeq = True 67 | safebase = True 68 | saferho = True 69 | safetransfer = True 70 | safedisc = True 71 | saferigid = True 72 | safeladder = True 73 | safetwist = True 74 | safecomplete = True 75 | safeind = True 76 | 77 | V = [] # distinct verified primes 78 | for line in s.split(): 79 | n = Integer(line) 80 | if not n.is_prime(): continue 81 | if n == 2: 82 | if not n in V: V += [n] 83 | continue 84 | for trybase in primes(2,10000): 85 | base = Integers(n)(trybase) 86 | if base^(n-1) != 1: continue 87 | proof = 'Primality proof for n = %s:\n' % n 88 | proof += '

Take b = %s.\n' % base 89 | proof += '

b^(n-1) mod n = 1.\n' 90 | f = factor(1) 91 | for v in reversed(V): 92 | if f.prod()^2 <= n: 93 | if n % v == 1: 94 | u = base^((n-1)/v)-1 95 | if u.is_unit(): 96 | proof += '

%s is prime.\n' % (v,v) 97 | proof += '
b^((n-1)/%s)-1 mod n = %s, which is a unit, inverse %s.\n' % (v,u,1/u) 98 | f *= factor(v)^(n-1).valuation(v) 99 | if f.prod()^2 <= n: continue 100 | if n % f.prod() != 1: continue 101 | proof += '

(%s) divides n-1.\n' % f 102 | proof += '

(%s)^2 > n.\n' % f 103 | proof += "

n is prime by Pocklington's theorem.\n" 104 | proof += '\n' 105 | writefile('../../../proof/%s.html' % n,proof) 106 | if not n in V: V += [n] 107 | break 108 | 109 | writefile('verify-primes',''.join('%s\n' % (v,v) for v in V)) 110 | 111 | pstatus = 'Unverified' 112 | if not p.is_prime(): pstatus = 'False' 113 | if p in V: pstatus = 'True' 114 | if pstatus != 'True': safefield = False 115 | writefile('verify-pisprime',pstatus + '\n') 116 | 117 | pstatus = 'Unverified' 118 | if not l.is_prime(): pstatus = 'False' 119 | if l in V: pstatus = 'True' 120 | if pstatus != 'True': safebase = False 121 | writefile('verify-lisprime',pstatus + '\n') 122 | 123 | writefile('expand2-p','= %s\n' % expand2(p)) 124 | writefile('expand2-l','
= %s\n' % expand2(l)) 125 | 126 | writefile('hex-p',hex(p) + '\n') 127 | writefile('hex-l',hex(l) + '\n') 128 | writefile('hex-x0',hex(x0) + '\n') 129 | writefile('hex-x1',hex(x1) + '\n') 130 | writefile('hex-y0',hex(y0) + '\n') 131 | writefile('hex-y1',hex(y1) + '\n') 132 | 133 | gcdlpis1 = gcd(l,p) == 1 134 | safetransfer &= requirement('verify-gcdlp1',gcdlpis1) 135 | 136 | writefile('verify-movsafe','Unverified\n') 137 | writefile('verify-embeddingdegree','Unverified\n') 138 | if gcdlpis1 and l.is_prime(): 139 | u = Integers(l)(p) 140 | d = l-1 141 | for v in V: 142 | while d % v == 0: d /= v 143 | if d == 1: 144 | d = l-1 145 | for v in V: 146 | while d % v == 0: 147 | if u^(d/v) != 1: break 148 | d /= v 149 | safetransfer &= requirement('verify-movsafe',(l-1)/d <= 100) 150 | writefile('verify-embeddingdegree','%s
= (l-1)/%s\n' % (d,(l-1)/d)) 151 | 152 | t = p+1-l*round((p+1)/l) 153 | if l^2 > 16*p: 154 | writefile('verify-trace','%s\n' % t) 155 | f = factor(1) 156 | d = (p+1-t)/l 157 | for v in V: 158 | while d % v == 0: 159 | d //= v 160 | f *= factor(v) 161 | writefile('verify-cofactor','%s\n' % f) 162 | else: 163 | writefile('verify-trace','Unverified\n') 164 | writefile('verify-cofactor','Unverified\n') 165 | 166 | D = t^2-4*p 167 | for v in V: 168 | while D % v^2 == 0: D /= v^2 169 | if prod([v for v in V if D % v == 0]) != -D: 170 | writefile('verify-disc','Unverified\n') 171 | writefile('verify-discisbig','Unverified\n') 172 | safedisc = False 173 | else: 174 | f = -prod([factor(v) for v in V if D % v == 0]) 175 | if D % 4 != 1: 176 | D *= 4 177 | f = factor(4) * f 178 | Dbits = (log(-D)/log(2)).numerical_approx() 179 | writefile('verify-disc','%s
= %s
≈ -2^%.1f\n' % (D,f,Dbits)) 180 | safedisc &= requirement('verify-discisbig',D < -2^100) 181 | 182 | pi4 = 0.78539816339744830961566084581987572105 183 | rho = log(pi4*l)/log(4) 184 | writefile('verify-rho','%.1f\n' % rho) 185 | saferho &= requirement('verify-rhoabove100',rho.numerical_approx() >= 100) 186 | 187 | twistl = 'Unverified' 188 | d = p+1+t 189 | for v in V: 190 | while d % v == 0: d /= v 191 | if d == 1: 192 | d = p+1+t 193 | for v in V: 194 | if d % v == 0: 195 | if twistl == 'Unverified' or v > twistl: twistl = v 196 | 197 | writefile('verify-twistl','%s\n' % twistl) 198 | writefile('verify-twistembeddingdegree','Unverified\n') 199 | writefile('verify-twistmovsafe','Unverified\n') 200 | if twistl == 'Unverified': 201 | writefile('hex-twistl','Unverified\n') 202 | writefile('expand2-twistl','Unverified\n') 203 | writefile('verify-twistcofactor','Unverified\n') 204 | writefile('verify-gcdtwistlp1','Unverified\n') 205 | writefile('verify-twistrho','Unverified\n') 206 | safetwist = False 207 | else: 208 | writefile('hex-twistl',hex(twistl) + '\n') 209 | writefile('expand2-twistl','
= %s\n' % expand2(twistl)) 210 | f = factor(1) 211 | d = (p+1+t)/twistl 212 | for v in V: 213 | while d % v == 0: 214 | d //= v 215 | f *= factor(v) 216 | writefile('verify-twistcofactor','%s\n' % f) 217 | gcdtwistlpis1 = gcd(twistl,p) == 1 218 | safetwist &= requirement('verify-gcdtwistlp1',gcdtwistlpis1) 219 | 220 | movsafe = 'Unverified' 221 | embeddingdegree = 'Unverified' 222 | if gcdtwistlpis1 and twistl.is_prime(): 223 | u = Integers(twistl)(p) 224 | d = twistl-1 225 | for v in V: 226 | while d % v == 0: d /= v 227 | if d == 1: 228 | d = twistl-1 229 | for v in V: 230 | while d % v == 0: 231 | if u^(d/v) != 1: break 232 | d /= v 233 | safetwist &= requirement('verify-twistmovsafe',(twistl-1)/d <= 100) 234 | writefile('verify-twistembeddingdegree',"%s
= (l'-1)/%s\n" % (d,(twistl-1)/d)) 235 | 236 | rho = log(pi4*twistl)/log(4) 237 | writefile('verify-twistrho','%.1f\n' % rho) 238 | safetwist &= requirement('verify-twistrhoabove100',rho.numerical_approx() >= 100) 239 | 240 | precomp = 0 241 | joint = l 242 | for v in V: 243 | d1 = p+1-t 244 | d2 = p+1+t 245 | while d1 % v == 0 or d2 % v == 0: 246 | if d1 % v == 0: d1 //= v 247 | if d2 % v == 0: d2 //= v 248 | # best case for attack: cyclic; each power is usable 249 | # also assume that kangaroo is as efficient as rho 250 | if v + sqrt(pi4*joint/v) < sqrt(pi4*joint): 251 | precomp += v 252 | joint /= v 253 | 254 | rho = log(precomp + sqrt(pi4 * joint))/log(2) 255 | writefile('verify-jointrho','%.1f\n' % rho) 256 | safetwist &= requirement('verify-jointrhoabove100',rho.numerical_approx() >= 100) 257 | 258 | 259 | x0 = k(x0) 260 | y0 = k(y0) 261 | x1 = k(x1) 262 | y1 = k(y1) 263 | 264 | if shape == 'edwards': 265 | d = Integer(readfile('d')) 266 | writefile('verify-shape','Edwards\n') 267 | writefile('verify-equation','x^2+y^2 = 1%+dx^2y^2\n' % d) 268 | 269 | d = k(d) 270 | elliptic = d*(1-d) 271 | level0 = x0^2+y0^2-1-d*x0^2*y0^2 272 | level1 = x1^2+y1^2-1-d*x1^2*y1^2 273 | 274 | if shape == 'montgomery': 275 | writefile('verify-shape','Montgomery\n') 276 | A = Integer(readfile('A')) 277 | B = Integer(readfile('B')) 278 | equation = '%sy^2 = x^3%+dx^2+x' % (B,A) 279 | if B == 1: 280 | equation = 'y^2 = x^3%+dx^2+x' % A 281 | writefile('verify-equation',equation + '\n') 282 | 283 | A = k(A) 284 | B = k(B) 285 | elliptic = B*(A^2-4) 286 | level0 = B*y0^2-x0^3-A*x0^2-x0 287 | level1 = B*y1^2-x1^3-A*x1^2-x1 288 | 289 | if shape == 'shortw': 290 | writefile('verify-shape','short Weierstrass\n') 291 | a = Integer(readfile('a')) 292 | b = Integer(readfile('b')) 293 | writefile('verify-equation','y^2 = x^3%+dx%+d\n' % (a,b)) 294 | 295 | a = k(a) 296 | b = k(b) 297 | elliptic = 4*a^3+27*b^2 298 | level0 = y0^2-x0^3-a*x0-b 299 | level1 = y1^2-x1^3-a*x1-b 300 | 301 | writefile('verify-elliptic',str(elliptic) + '\n') 302 | safeeq &= requirement('verify-iselliptic',elliptic != 0) 303 | safebase &= requirement('verify-isoncurve0',level0 == 0) 304 | safebase &= requirement('verify-isoncurve1',level1 == 0) 305 | 306 | if shape == 'edwards': 307 | A = 2*(1+d)/(1-d) 308 | B = 4/(1-d) 309 | x0,y0 = (1+y0)/(1-y0),((1+y0)/(1-y0))/x0 310 | x1,y1 = (1+y1)/(1-y1),((1+y1)/(1-y1))/x1 311 | shape = 'montgomery' 312 | 313 | if shape == 'montgomery': 314 | a = (3-A^2)/(3*B^2) 315 | b = (2*A^3-9*A)/(27*B^3) 316 | x0,y0 = (x0+A/3)/B,y0/B 317 | x1,y1 = (x1+A/3)/B,y1/B 318 | shape = 'shortw' 319 | 320 | try: 321 | E = EllipticCurve([a,b]) 322 | numorder2 = 0 323 | numorder4 = 0 324 | for P in E(0).division_points(4): 325 | if P != 0 and 2*P == 0: 326 | numorder2 += 1 327 | if 2*P != 0 and 4*P == 0: 328 | numorder4 += 1 329 | writefile('verify-numorder2',str(numorder2) + '\n') 330 | writefile('verify-numorder4',str(numorder4) + '\n') 331 | completesingle = False 332 | completemulti = False 333 | if numorder4 == 2 and numorder2 == 1: 334 | # complete edwards form, and montgomery with unique point of order 2 335 | completesingle = True 336 | completemulti = True 337 | # should extend this to allow complete twisted hessian 338 | safecomplete &= requirement('verify-completesingle',completesingle) 339 | safecomplete &= requirement('verify-completemulti',completemulti) 340 | safecomplete &= requirement('verify-ltimesbase1is0',l * E([x1,y1]) == 0) 341 | writefile('verify-ltimesbase1',str(l * E([x1,y1])) + '\n') 342 | writefile('verify-cofactorbase01',str(((p+1-t)//l) * E([x0,y0]) == E([x1,y1])) + '\n') 343 | except: 344 | writefile('verify-numorder2','Unverified\n') 345 | writefile('verify-numorder4','Unverified\n') 346 | writefile('verify-ltimesbase1','Unverified\n') 347 | writefile('verify-cofactorbase01','Unverified\n') 348 | safecomplete = False 349 | 350 | montladder = False 351 | for r,e in (z^3+a*z+b).roots(): 352 | if (3*r^2+a).is_square(): 353 | montladder = True 354 | safeladder &= requirement('verify-montladder',montladder) 355 | 356 | indistinguishability = False 357 | elligator2 = False 358 | if (p+1-t) % 2 == 0: 359 | if b != 0: 360 | indistinguishability = True 361 | elligator2 = True 362 | safeind &= requirement('verify-indistinguishability',indistinguishability) 363 | writefile('verify-ind-notes','Elligator 2: %s.\n' % ['No','Yes'][elligator2]) 364 | 365 | saferigid &= (rigid == 'fully rigid' or rigid == 'somewhat rigid') 366 | 367 | safecurve = True 368 | safecurve &= requirement('verify-safefield',safefield) 369 | safecurve &= requirement('verify-safeeq',safeeq) 370 | safecurve &= requirement('verify-safebase',safebase) 371 | safecurve &= requirement('verify-saferho',saferho) 372 | safecurve &= requirement('verify-safetransfer',safetransfer) 373 | safecurve &= requirement('verify-safedisc',safedisc) 374 | safecurve &= requirement('verify-saferigid',saferigid) 375 | safecurve &= requirement('verify-safeladder',safeladder) 376 | safecurve &= requirement('verify-safetwist',safetwist) 377 | safecurve &= requirement('verify-safecomplete',safecomplete) 378 | safecurve &= requirement('verify-safeind',safeind) 379 | requirement('verify-safecurve',safecurve) 380 | 381 | originaldir = os.open('.',os.O_RDONLY) 382 | for i in range(1,len(sys.argv)): 383 | /// implement for different operating systems 384 | os.fchdir(originaldir) 385 | /// as well as 386 | os.chdir(sys.argv[i]) 387 | verify() 388 | 389 | ## Curve Paramaters section. 390 | /// The size of the prime field when Sonny is 391 | /// a curve defined as E where #E(Fp), and p 392 | /// is the prime of the field, defined as: 393 | sage: p 394 | 7237005577332262213973186563042994240857116359379907606001950938285454250989 395 | /// also written as 396 | sage: p 397 | 2^252 + 27742317777372353535851937790883648493 398 | 399 | /// A montgomery form of the curve 400 | /// Y^2 = X^3 + A*X^2 + B*X, 401 | /// A = 505186, B = 1 402 | 403 | /// Basepoint calculation 404 | sage: prime = 2^252 + 27742317777372353535851937790883648493 405 | 406 | sage: A = 505186 407 | 408 | sage: def findBasepoint(prime, A): 409 | F = GF(prime) 410 | E = EllipticCurve(F, [0, A, 0, 1, 0]) 411 | for uInt in range(1, 1e3): 412 | u = F(uInt) 413 | v2 = u^3 + A*u^2 + u 414 | if not v2.is_square(): 415 | v = v2.sqrt() 416 | point = E(u, v) 417 | pointOrder = point.order() 418 | if pointOrder > 8 and pointOrder.is_prime(): 419 | Q=u^3 + A*u^2 + u 420 | return u, Q, sqrt(Q), point 421 | 422 | sage: res = findBasepoint(prime, A) 423 | 424 | sage: res 425 | 426 | (4, 427 | 8083044, 428 | 2387694734969974503585694617203302024142786955946516383730480941479078023877, 429 | 430 | (4 : 5476327F819F419674D6ECE6CD9CC73DD90461A0D99B2A65D27C9881ABA52C5 : 1) 431 | 432 | /// Hexidecimal representation 433 | (4 : 23E4A96ED9E13AF0600EA21DB1007D9FB6E47BDD233BBBD82EB8E634305E0B1 : 1) 434 | 435 | /// Prime order of curve, l 436 | sage: E 437 | Elliptic Curve defined by y^2 = x^3 + 505186*x^2 + x over Finite Field of size 7237005577332262213973186563042994240857116359379907606001950938285454250989 438 | sage: q = E.cardinality() 439 | sage: print q 440 | 7237005577332262213973186563042994240945298446207996762370788566739812500248 441 | sage: l = q/8; 442 | sage: print l 443 | 904625697166532776746648320380374280118162305775999595296348570842476562531 444 | 445 | 446 | ///Curve complex multiplicative(CM) discriminant must be > 2^100 447 | ///For this to hold true a calculation of varying values must be 448 | ///obtained. 449 | /// The first step is to obtain the trace of frobenius. 450 | /// Then check if the prime field satisfies Hasses theorem and is bound by: 451 | /// -2*sqrt(q) < t < 2*sqrt(q) 452 | /// Then compute D using 453 | 454 | sage: E.frobenius_order() 455 | Order in Number Field in phi with defining polynomial x^2 + 88182086828089156368837628454358249258*x + 7237005577332262213973186563042994240857116359379907606001950938285454250989 456 | sage: E.trace_of_frobenius() 457 | 88182086828089156368837628454358249258 458 | 459 | /// Alternatively, the trace of frobenius 460 | /// can be computed using #E(Fp) = q + 1 - t, 461 | /// where #E(Fp) is P, the prime of the field. 462 | /// As shown below. 463 | 464 | sage: P 465 | 7237005577332262213973186563042994240857116359379907606001950938285454250989 466 | sage: q 467 | 7237005577332262213973186563042994240945298446207996762370788566739812500248 468 | sage: t = q+1-P 469 | sage: t 470 | 88182086828089156368837628454358249260 471 | 472 | -------------------------------------------------------------------------------- /sage_codes/curve_derivation: -------------------------------------------------------------------------------- 1 | sage: q = 2^252 + 27742317777372353535851937790883648493 2 | ....: Fq = GF(q) 3 | ....: 4 | ....: # We wish to find a Montgomery curve with B = 1 and A the smallest such 5 | ....: # that (A - 2) / 4 is a small integer. As well as fitting the isogeny 6 | ....: # needed for the cofactor compression algorithms. Therefore creating 7 | ....: # A+2 as square in q.. 8 | ....: def get_A(n): 9 | ....: return (n * 4) + 2 10 | ....: 11 | ....: # A = 2 is invalid (singular curve), so we start at i = 1 (A = 6) 12 | ....: i = 1 13 | ....: 14 | ....: while True: 15 | ....: A = Fq(get_A(i)) 16 | ....: i = i + 1 17 | ....: 18 | ....: # We also want that A^2 - 4 is nonsquare. 19 | ....: if ((A^2) - 4).is_square() && legendre_symbol(A+2, q) == 1: 20 | ....: continue 21 | ....: 22 | ....: ec = EllipticCurve(Fq, [0, A, 0, 1, 0]) 23 | ....: o = ec.order() 24 | ....: 25 | ....: if (o % 8 == 0): 26 | ....: o = o // 8 27 | ....: if is_prime(o): 28 | ....: twist = ec.quadratic_twist() 29 | ....: otwist = twist.order() 30 | ....: if (otwist % 4 == 0): 31 | ....: otwist = otwist // 4 32 | ....: if is_prime(otwist): 33 | ....: print "A = %s" % A 34 | ....: exit(0) 35 | sage: A 36 | sage: 505186 37 | 38 | -------------------------------------------------------------------------------- /sage_codes/sage_weierstrass_code: -------------------------------------------------------------------------------- 1 | sage: def egcd(a, b): 2 | ....: ^Iif a == 0: 3 | ....: ^I^Ireturn (b, 0, 1) 4 | ....: ^Ielse: 5 | ....: ^I^Ig, y, x = egcd(b % a, a) 6 | ....: ^I^Ireturn (g, x - (b // a) * y, y) 7 | ....: 8 | sage: def modinv(a, m): 9 | ....: ^Ig, x, y = egcd(a, m) 10 | ....: ^Iif g != 1: 11 | ....: ^I^Iraise Exception('modular inverse does not exist') 12 | ....: ^Ielse: 13 | ....: ^I^Ireturn x % m 14 | ....: 15 | sage: ^I^Ireturn pow(a, (p + 1) / 4, p) 16 | ....: 17 | ....: ^I# Partition p-1 to s * 2^e for an odd s (i.e. 18 | ....: ^I# reduce all the powers of 2 from p-1) 19 | ....: ^I# 20 | ....: ^Is = p - 1 21 | ....: ^Ie = 0 22 | ....: ^Iwhile s % 2 == 0: 23 | ....: ^I^Is /= 2 24 | ....: ^I^Ie += 1 25 | ....: 26 | ....: ^I# Find some 'n' with a legendre symbol n|p = -1. 27 | ....: ^I# Shouldn't take long. 28 | ....: ^I# 29 | ....: ^In = 2 30 | ....: ^Iwhile legendre_symbol(n, p) != -1: 31 | ....: ^I^In += 1 32 | ....: 33 | ....: ^I# Here be dragons! 34 | ....: ^I# Read the paper "Square roots from 1; 24, 51, 35 | ....: ^I# 10 to Dan Shanks" by Ezra Brown for more 36 | ....: ^I# information 37 | ....: ^I# 38 | ....: 39 | ....: ^I# x is a guess of the square root that gets better 40 | ....: ^I# with each iteration. 41 | ....: ^I# b is the "fudge factor" - by how much we're off 42 | ....: ^I# with the guess. The invariant x^2 = ab (mod p)gx_w = (9 + a_m/3)%p 43 | ....: ^I# is maintained throughout the loop. 44 | ....: ^I# g is used for successive powers of n to update 45 | ....: ^I# both a and b 46 | ....: ^I# r is the exponent - decreases with each update 47 | ....: ^I# 48 | ....: ^Ix = pow(a, (s + 1) / 2, p) 49 | ....: ^Ib = pow(a, s, p) 50 | ....: ^Ig = pow(n, s, p) 51 | ....: ^Ir = e 52 | ....: 53 | ....: ^Iwhile True: 54 | ....: ^I^It = b 55 | ....: ^I^Im = 0 56 | ....: ^I^Ifor m in xrange(r): 57 | ....: ^I^I^Iif t == 1: 58 | ....: ^I^I^I^Ibreak 59 | ....: ^I^I^It = pow(t, 2, p) 60 | ....: 61 | ....: ^I^Iif m == 0: 62 | ....: ^I^I^Ireturn x 63 | ....: 64 | ....: ^I^Igs = pow(g, 2 ** (r - m - 1), p) 65 | ....: ^I^Ig = (gs * gs) % p 66 | ....: ^I^Ix = (x * gs) % p 67 | ....: ^I^Ib = (b * g) % p 68 | ....: ^I^Ir = m 69 | ....: 70 | sage: 71 | sage: def legendre_symbol(a, p): 72 | ....: ^I""" Compute the Legendre symbol a|p using 73 | ....: ^I^IEuler's criterion. p is a prime, a is 74 | ....: ^I^Irelatively prime to p (if p divides 75 | ....: ^I^Ia, then a|p = 0) 76 | ....: 77 | ....: ^I^IReturns 1 if a has a square root modulo 78 | ....: ^I^Ip, -1 otherwise. 79 | ....: ^I""" 80 | ....: ^Ils = pow(a, (p - 1) / 2, p) 81 | ....: ^Ireturn -1 if ls == p - 1 else ls 82 | ....: 83 | sage: p = pow(2,255)-19 84 | sage: a_m = 486662 85 | sage: b_m = 1 86 | sage: interim_a_numerator = 3-pow(a_m,2) 87 | sage: interim_a_denominator = 3*pow(b_m,2) 88 | sage: interim_a_denominator = modinv(interim_a_denominator,p) 89 | sage: a_w = interim_a_numerator * interim_a_denominator 90 | sage: a_w = a_w % p 91 | sage: interim_b_numerator = 2*pow(a_m,3)-9*a_m 92 | sage: interim_b_denominator = 27 * pow(b_m,3) 93 | sage: interim_b_denominator = modinv(interim_b_denominator, p) 94 | sage: b_w = interim_b_numerator * interim_b_denominator 95 | sage: b_w = b_w % p 96 | sage: x = 9 97 | sage: x = (x + a_m * modinv(3,p))%p 98 | sage: y2 = pow(x,3) + a_w*x + b_w 99 | sage: y2 = y2 % p 100 | sage: y = modular_sqrt(y2,p) 101 | sage: P 102 | --------------------------------------------------------------------------- 103 | NameError Traceback (most recent call last) 104 | in () 105 | ----> 1 P 106 | 107 | NameError: name 'P' is not defined 108 | sage: 109 | sage: p 110 | 57896044618658097711785492504343953926634992332820282019728792003956564819949 111 | sage: a_w 112 | 19298681539552699237261830834781317975544997444273427339909597334573241639236 113 | sage: b_w 114 | 55751746669818908907645289078257140818241103727901012315294400837956729358436 115 | sage: x 116 | 19298681539552699237261830834781317975544997444273427339909597334652188435546 117 | sage: y 118 | 14781619447589544791020593568409986887264606134616475288964881837755586237401 119 | sage: p = pow(2,252) + 27742317777372353535851937790883648493 120 | sage: a_m = 346598 121 | sage: b_m = 1 122 | sage: interim_a_numerator = 3-pow(a_m,2) 123 | sage: interim_a_denominator = 3*pow(b_m,2) 124 | sage: interim_a_denominator = modinv(interim_a_denominator,p) 125 | sage: a_w = interim_a_numerator * interim_a_denominator 126 | sage: a_w = a_w % p 127 | sage: interim_b_numerator = 2*pow(a_m,3)-9*a_m 128 | ....: 129 | sage: interim_b_denominator = 27 * pow(b_m,3) 130 | sage: interim_b_denominator = modinv(interim_b_denominator, p) 131 | sage: b_w = interim_b_numerator * interim_b_denominator 132 | sage: b_w = b_w % p 133 | ....: 134 | sage: x = 17 135 | sage: x = (x + a_m * modinv(3,p))%p 136 | sage: y2 = pow(x,3) + a_w*x + b_w 137 | sage: y2 = y2 % p 138 | sage: y = modular_sqrt(y2,p) 139 | sage: p 140 | 7237005577332262213973186563042994240857116359379907606001950938285454250989 141 | sage: a_w 142 | 2412335192444087404657728854347664746952372119793302535333983646055108025796 143 | sage: b_w 144 | 1340186218024493002587627141304258192751317844329612519629993998710484804961 145 | sage: x 146 | 2412335192444087404657728854347664746952372119793302535333983646095151532546 147 | sage: y 148 | 6222320563903764848551041754877036140234555813488015858364752483591799173948 149 | -------------------------------------------------------------------------------- /src/backend/mod.rs: -------------------------------------------------------------------------------- 1 | //! This contains the different backend implementations: `u64` and further comming ones. . 2 | //! 3 | //! On this module you can find the different implementations 4 | //! done for Finite Fields mathematical-backends. 5 | 6 | /// The u64 backend contains the implementation of all of the 7 | /// mathematical base eg. Arithmetics over Finite Fields with 8 | /// a design specially thought out 64-bit architectures. 9 | pub mod u64; 10 | #[cfg(not(any(feature = "u64_backend")))] 11 | 12 | // A backend feature must fair be chosen. 13 | compile_error!( 14 | "no zerocaf backend cargo feature enabled! \ 15 | please enable u64_backend" 16 | ); 17 | -------------------------------------------------------------------------------- /src/backend/u64/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod constants; 2 | pub mod field; 3 | pub mod scalar; 4 | -------------------------------------------------------------------------------- /src/backend/u64/scalar.rs: -------------------------------------------------------------------------------- 1 | //! Arithmetic mod `2^249 + 14490550575682688738086195780655237219` 2 | //! with five 52-bit unsigned limbs 3 | //! represented in radix `2^52`. 4 | //! 5 | //! //! The basic modular operations have been taken from the 6 | //! [curve25519-dalek repository](https://github.com/dalek-cryptography/curve25519-dalek) and refactored to work 7 | //! for the Sonny sub-group field. 8 | 9 | use core::fmt::Debug; 10 | use core::ops::{Add, Mul, Neg, Sub}; 11 | use core::ops::{Index, IndexMut}; 12 | 13 | use std::cmp::{Ord, Ordering, PartialOrd}; 14 | use std::ops::Shr; 15 | 16 | use num::Integer; 17 | 18 | use crate::backend::u64::constants; 19 | use crate::traits::ops::*; 20 | use crate::traits::Identity; 21 | 22 | 23 | /// The `Scalar` struct represents an Scalar over the modulo 24 | /// `2^249 + 14490550575682688738086195780655237219` as 5 52-bit limbs 25 | /// represented in radix `2^52`. 26 | #[derive(Copy, Clone)] 27 | pub struct Scalar(pub [u64; 5]); 28 | 29 | impl Debug for Scalar { 30 | fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { 31 | write!(f, "Scalar: {:?}", &self.0[..]) 32 | } 33 | } 34 | 35 | impl Index for Scalar { 36 | type Output = u64; 37 | fn index(&self, _index: usize) -> &u64 { 38 | &(self.0[_index]) 39 | } 40 | } 41 | 42 | impl IndexMut for Scalar { 43 | fn index_mut(&mut self, _index: usize) -> &mut u64 { 44 | &mut (self.0[_index]) 45 | } 46 | } 47 | 48 | impl PartialOrd for Scalar { 49 | fn partial_cmp(&self, other: &Scalar) -> Option { 50 | Some(self.cmp(&other)) 51 | } 52 | } 53 | 54 | impl Ord for Scalar { 55 | fn cmp(&self, other: &Self) -> Ordering { 56 | for i in (0..5).rev() { 57 | if self[i] > other[i] { 58 | return Ordering::Greater; 59 | } else if self[i] < other[i] { 60 | return Ordering::Less; 61 | } 62 | } 63 | Ordering::Equal 64 | } 65 | } 66 | 67 | //-------------- From Implementations -----------------// 68 | impl From for Scalar { 69 | /// Performs the conversion. 70 | fn from(_inp: i8) -> Scalar { 71 | let mut res = Scalar::zero(); 72 | 73 | match _inp >= 0 { 74 | true => { 75 | res[0] = _inp as u64; 76 | return res 77 | }, 78 | false => { 79 | res[0] = _inp.abs() as u64; 80 | return -res 81 | } 82 | } 83 | } 84 | } 85 | impl From for Scalar { 86 | /// Performs the conversion. 87 | fn from(_inp: u8) -> Scalar { 88 | let mut res = Scalar::zero(); 89 | res[0] = _inp as u64; 90 | res 91 | } 92 | } 93 | 94 | impl From for Scalar { 95 | /// Performs the conversion. 96 | fn from(_inp: u16) -> Scalar { 97 | let mut res = Scalar::zero(); 98 | res[0] = _inp as u64; 99 | res 100 | } 101 | } 102 | 103 | impl From for Scalar { 104 | /// Performs the conversion. 105 | fn from(_inp: u32) -> Scalar { 106 | let mut res = Scalar::zero(); 107 | res[0] = _inp as u64; 108 | res 109 | } 110 | } 111 | 112 | impl From for Scalar { 113 | /// Performs the conversion. 114 | fn from(_inp: u64) -> Scalar { 115 | let mut res = Scalar::zero(); 116 | let mask = (1u64 << 52) - 1; 117 | res[0] = _inp & mask; 118 | res[1] = _inp >> 52; 119 | res 120 | } 121 | } 122 | 123 | impl From for Scalar { 124 | /// Performs the conversion. 125 | fn from(_inp: u128) -> Scalar { 126 | let mut res = Scalar::zero(); 127 | let mask = (1u128 << 52) - 1; 128 | 129 | // Since 128 / 52 < 4 , we only need to care 130 | // about the first three limbs. 131 | res[0] = (_inp & mask) as u64; 132 | res[1] = ((_inp >> 52) & mask) as u64; 133 | res[2] = (_inp >> 104) as u64; 134 | 135 | res 136 | } 137 | } 138 | 139 | impl<'a> Neg for &'a Scalar { 140 | type Output = Scalar; 141 | /// Performs the negate operation over the 142 | /// sub-group modulo l. 143 | fn neg(self) -> Scalar { 144 | &Scalar::zero() - &self 145 | } 146 | } 147 | 148 | impl Neg for Scalar { 149 | type Output = Scalar; 150 | /// Performs the negate operation over the 151 | /// sub-group modulo l. 152 | fn neg(self) -> Scalar { 153 | -&self 154 | } 155 | } 156 | 157 | impl Identity for Scalar { 158 | /// Returns the `Identity` element for `Scalar` 159 | /// which equals `1 (mod l)`. 160 | fn identity() -> Scalar { 161 | Scalar::one() 162 | } 163 | } 164 | 165 | impl Shr for Scalar { 166 | type Output = Scalar; 167 | 168 | fn shr(self, _rhs: u8) -> Scalar { 169 | let mut res = self; 170 | 171 | for _ in 0.._rhs { 172 | let mut carry = 0u64; 173 | for i in (0..5).rev() { 174 | res[i] = res[i] | carry; 175 | 176 | carry = (res[i] & 1) << 52; 177 | res[i] >>= 1; 178 | } 179 | } 180 | res 181 | } 182 | } 183 | 184 | impl<'a, 'b> Add<&'b Scalar> for &'a Scalar { 185 | type Output = Scalar; 186 | /// Compute `a + b (mod l)`. 187 | fn add(self, b: &'b Scalar) -> Scalar { 188 | let mut sum = Scalar::zero(); 189 | let mask = (1u64 << 52) - 1; 190 | 191 | // a + b 192 | let mut carry: u64 = 0; 193 | for i in 0..5 { 194 | carry = self.0[i] + b[i] + (carry >> 52); 195 | sum[i] = carry & mask; 196 | } 197 | // subtract l if the sum is >= l 198 | sum - constants::L 199 | } 200 | } 201 | 202 | impl Add for Scalar { 203 | type Output = Scalar; 204 | /// Compute `a + b (mod l)`. 205 | fn add(self, b: Scalar) -> Scalar { 206 | &self + &b 207 | } 208 | } 209 | 210 | impl<'a, 'b> Sub<&'b Scalar> for &'a Scalar { 211 | type Output = Scalar; 212 | /// Compute `a - b (mod l)`. 213 | fn sub(self, b: &'b Scalar) -> Scalar { 214 | let mut difference = Scalar::zero(); 215 | let mask = (1u64 << 52) - 1; 216 | 217 | // a - b 218 | let mut borrow: u64 = 0; 219 | // Save the wrapping_sub in borrow and add the remainder to the next limb. 220 | for i in 0..5 { 221 | // Borrow >> 63 so the Most Significant Bit of the remainder (2^64) can be carried to the next limb. 222 | borrow = self.0[i].wrapping_sub(b[i] + (borrow >> 63)); 223 | difference[i] = borrow & mask; 224 | } 225 | 226 | // conditionally add `l` if the difference is negative. 227 | // Note that here borrow tells us the Most Signif Bit of the last limb so then we know if it's greater than `l`. 228 | let underflow_mask = ((borrow >> 63) ^ 1).wrapping_sub(1); // If isn't greater, we will not add it as XOR = 0. 229 | let mut carry: u64 = 0; 230 | for i in 0..5 { 231 | carry = (carry >> 52) + difference[i] + (constants::L[i] & underflow_mask); 232 | difference[i] = carry & mask; 233 | } 234 | 235 | difference 236 | } 237 | } 238 | 239 | impl Sub for Scalar { 240 | type Output = Scalar; 241 | /// Compute `a - b (mod l)`. 242 | fn sub(self, b: Scalar) -> Scalar { 243 | &self - &b 244 | } 245 | } 246 | 247 | impl<'a, 'b> Mul<&'a Scalar> for &'b Scalar { 248 | type Output = Scalar; 249 | /// This `Mul` implementation returns a double precision result. 250 | /// The result of the standard mul is stored on a [u128; 9]. 251 | /// 252 | /// Then, we apply the Montgomery Reduction function to perform 253 | /// the modulo and the reduction to the `Scalar` format: [u64; 5]. 254 | fn mul(self, b: &'a Scalar) -> Scalar { 255 | let ab = Scalar::montgomery_reduce(&Scalar::mul_internal(self, b)); 256 | Scalar::montgomery_reduce(&Scalar::mul_internal(&ab, &constants::RR)) 257 | } 258 | } 259 | 260 | impl Mul for Scalar { 261 | type Output = Scalar; 262 | /// This `Mul` implementation returns a double precision result. 263 | /// The result of the standard mul is stored on a [u128; 9]. 264 | /// 265 | /// Then, we apply the Montgomery Reduction function to perform 266 | /// the modulo and the reduction to the `Scalar` format: [u64; 5]. 267 | fn mul(self, b: Scalar) -> Scalar { 268 | &self * &b 269 | } 270 | } 271 | 272 | impl<'a> Square for &'a Scalar { 273 | type Output = Scalar; 274 | /// This `Square` implementation returns a double precision result. 275 | /// The result of the standard mul is stored on a [u128; 9]. 276 | /// 277 | /// Then, we apply the Montgomery Reduction function to perform 278 | /// the modulo and the reduction to the `Scalar` format: [u64; 5]. 279 | fn square(self) -> Scalar { 280 | let aa = Scalar::montgomery_reduce(&Scalar::square_internal(self)); 281 | Scalar::montgomery_reduce(&Scalar::mul_internal(&aa, &constants::RR)) 282 | } 283 | } 284 | 285 | impl<'a> Half for &'a Scalar { 286 | type Output = Scalar; 287 | /// Give the half of the Scalar value (mod l). 288 | fn half(self) -> Scalar { 289 | self * &constants::SCALAR_INVERSE_MOD_TWO 290 | } 291 | } 292 | 293 | /// Performs the op: `a^b (mod l)`. 294 | /// 295 | /// Exponentiation by squaring classical algorithm 296 | /// implementation for `Scalar`. 297 | /// 298 | /// Schneier, Bruce (1996). Applied Cryptography: Protocols, 299 | /// Algorithms, and Source Code in C, Second Edition (2nd ed.). 300 | impl<'a, 'b> Pow<&'b Scalar> for &'a Scalar { 301 | type Output = Scalar; 302 | 303 | fn pow(self, exp: &'b Scalar) -> Scalar { 304 | let mut base = *self; 305 | let mut res = Scalar::one(); 306 | let mut expon = *exp; 307 | 308 | while expon > Scalar::zero() { 309 | if expon.is_even() { 310 | expon = expon.half_without_mod(); 311 | base = base.square(); 312 | } else { 313 | expon = expon - Scalar::one(); 314 | res = res * base; 315 | 316 | expon = expon.half(); 317 | base = base.square(); 318 | } 319 | } 320 | res 321 | } 322 | } 323 | 324 | /// u64 * u64 = u128 inline func multiply helper 325 | fn m(x: u64, y: u64) -> u128 { 326 | (x as u128) * (y as u128) 327 | } 328 | 329 | impl Scalar { 330 | /// Return a Scalar with value = `0`. 331 | pub const fn zero() -> Scalar { 332 | Scalar([0, 0, 0, 0, 0]) 333 | } 334 | 335 | /// Return a Scalar with value = `1`. 336 | pub const fn one() -> Scalar { 337 | Scalar([1, 0, 0, 0, 0]) 338 | } 339 | 340 | /// Return a Scalar with value = `-1 (mod l)`. 341 | pub const fn minus_one() -> Scalar { 342 | Scalar([1129677152307298, 1363544697812651, 714439, 0, 2199023255552]) 343 | } 344 | 345 | /// Evaluate if a `Scalar` is even or not. 346 | pub fn is_even(self) -> bool { 347 | self.0[0].is_even() 348 | } 349 | 350 | /// Returns the bit representation of the given `Scalar` as 351 | /// an array of 256 bits represented as `u8`. 352 | pub fn into_bits(&self) -> [u8; 256] { 353 | let bytes = self.to_bytes(); 354 | let mut res = [0u8; 256]; 355 | 356 | let mut j = 0; 357 | 358 | for byte in &bytes { 359 | for i in 0..8 { 360 | let bit = byte >> i as u8; 361 | res[j] = !bit.is_even() as u8; 362 | j+=1; 363 | }; 364 | }; 365 | res 366 | } 367 | 368 | #[allow(non_snake_case)] 369 | /// Compute the Non-Adjacent Form of a given `Scalar`. 370 | pub fn compute_NAF(&self) -> [i8; 256] { 371 | let mut k = *self; 372 | let mut i = 0; 373 | let one = Scalar::one(); 374 | let mut res = [0i8; 256]; 375 | 376 | while k >= one { 377 | if !k.is_even() { 378 | let ki = 2i8 - k.mod_2_pow_k(2u8) as i8; 379 | res[i] = ki; 380 | k = k - Scalar::from(ki); 381 | } else { 382 | res[i] = 0i8; 383 | }; 384 | 385 | k = k.half_without_mod(); 386 | i +=1; 387 | } 388 | res 389 | } 390 | 391 | #[allow(non_snake_case)] 392 | /// Compute the Windowed-Non-Adjacent Form of a given `Scalar`. 393 | /// 394 | /// ## Inputs 395 | /// - `width` => Represents the window-width i.e. `width = 2^width`. 396 | pub fn compute_window_NAF(&self, width: u8) -> [i8; 256] { 397 | let mut k = *self; 398 | let mut i = 0; 399 | let one = Scalar::one(); 400 | let mut res = [0i8; 256]; 401 | 402 | while k >= one { 403 | if !k.is_even() { 404 | let ki = k.mods_2_pow_k(width); 405 | res[i] = ki; 406 | k = k - Scalar::from(ki); 407 | } else { 408 | res[i] = 0i8; 409 | }; 410 | 411 | k = k.half_without_mod(); 412 | i+=1; 413 | } 414 | res 415 | } 416 | 417 | /// Compute the result from `Scalar (mod 2^k)`. 418 | /// 419 | /// # Panics 420 | /// 421 | /// If the given k is > 32 (5 bits) as the value gets 422 | /// greater than the limb. 423 | pub fn mod_2_pow_k(&self, k: u8) -> u8 { 424 | (self.0[0] & ((1 << k) -1)) as u8 425 | } 426 | 427 | /// Compute the result from `Scalar (mods k)`. 428 | /// 429 | /// # Panics 430 | /// 431 | /// If the given `k > 32 (5 bits)` || `k == 0` as the value gets 432 | /// greater than the limb. 433 | pub fn mods_2_pow_k(&self, w: u8) -> i8 { 434 | assert!(w < 32u8); 435 | let modulus = self.mod_2_pow_k(w) as i8; 436 | let two_pow_w_minus_one = 1i8 << (w - 1); 437 | 438 | match modulus >= two_pow_w_minus_one { 439 | false => return modulus, 440 | true => return modulus - ((1u8 << w) as i8), 441 | } 442 | } 443 | 444 | /// Unpack a 32 byte / 256 bit Scalar into 5 52-bit limbs. 445 | pub fn from_bytes(bytes: &[u8; 32]) -> Scalar { 446 | let mut words = [0u64; 4]; 447 | for i in 0..4 { 448 | for j in 0..8 { 449 | words[i] |= (bytes[(i * 8) + j] as u64) << (j * 8); 450 | } 451 | } 452 | 453 | let mask = (1u64 << 52) - 1; 454 | let top_mask = (1u64 << 48) - 1; 455 | let mut s = Scalar::zero(); 456 | 457 | s[0] = words[0] & mask; 458 | // Get the 64-52 = 12 bits and add words[1] (shifting 12 to the left) on the front with `|` then apply mask. 459 | s[1] = ((words[0] >> 52) | (words[1] << 12)) & mask; 460 | s[2] = ((words[1] >> 40) | (words[2] << 24)) & mask; 461 | s[3] = ((words[2] >> 28) | (words[3] << 36)) & mask; 462 | // Shift 16 to the right to get the 52 bits of the scalar on that limb. Then apply top_mask. 463 | s[4] = (words[3] >> 16) & top_mask; 464 | 465 | assert!(s <= Scalar::minus_one()); 466 | s 467 | } 468 | 469 | /// Reduce a 64 byte / 512 bit scalar mod l 470 | pub fn from_bytes_wide(_bytes: &[u8; 64]) -> Scalar { 471 | // We could provide 512 bit scalar support using Montgomery Reduction. 472 | // But first we need to finnish the 256-bit implementation. 473 | unimplemented!() 474 | } 475 | 476 | /// Pack the limbs of this `Scalar` into 32 bytes 477 | pub fn to_bytes(&self) -> [u8; 32] { 478 | let mut res = [0u8; 32]; 479 | 480 | res[0] = (self.0[0] >> 0) as u8; 481 | res[1] = (self.0[0] >> 8) as u8; 482 | res[2] = (self.0[0] >> 16) as u8; 483 | res[3] = (self.0[0] >> 24) as u8; 484 | res[4] = (self.0[0] >> 32) as u8; 485 | res[5] = (self.0[0] >> 40) as u8; 486 | res[6] = ((self.0[0] >> 48) | (self.0[1] << 4)) as u8; 487 | res[7] = (self.0[1] >> 4) as u8; 488 | res[8] = (self.0[1] >> 12) as u8; 489 | res[9] = (self.0[1] >> 20) as u8; 490 | res[10] = (self.0[1] >> 28) as u8; 491 | res[11] = (self.0[1] >> 36) as u8; 492 | res[12] = (self.0[1] >> 44) as u8; 493 | res[13] = (self.0[2] >> 0) as u8; 494 | res[14] = (self.0[2] >> 8) as u8; 495 | res[15] = (self.0[2] >> 16) as u8; 496 | res[16] = (self.0[2] >> 24) as u8; 497 | res[17] = (self.0[2] >> 32) as u8; 498 | res[18] = (self.0[2] >> 40) as u8; 499 | res[19] = ((self.0[2] >> 48) | (self.0[3] << 4)) as u8; 500 | res[20] = (self.0[3] >> 4) as u8; 501 | res[21] = (self.0[3] >> 12) as u8; 502 | res[22] = (self.0[3] >> 20) as u8; 503 | res[23] = (self.0[3] >> 28) as u8; 504 | res[24] = (self.0[3] >> 36) as u8; 505 | res[25] = (self.0[3] >> 44) as u8; 506 | res[26] = (self.0[4] >> 0) as u8; 507 | res[27] = (self.0[4] >> 8) as u8; 508 | res[28] = (self.0[4] >> 16) as u8; 509 | res[29] = (self.0[4] >> 24) as u8; 510 | res[30] = (self.0[4] >> 32) as u8; 511 | res[31] = (self.0[4] >> 40) as u8; 512 | 513 | // High bit should be zero. 514 | //debug_assert!((res[31] & 0b1000_0000u8) == 0u8); 515 | res 516 | } 517 | 518 | /// Given a `k`: u64, compute `2^k` giving the resulting result 519 | /// as a `Scalar`. 520 | /// 521 | /// See that the input must be between the range => 0..250. 522 | /// 523 | /// # Panics 524 | /// If the input is greater than the Sub-group order. 525 | pub fn two_pow_k(exp: u64) -> Scalar { 526 | // Check that exp has to be less than 260. 527 | // Note that a Scalar can be as much 528 | // `2^249 - 15145038707218910765482344729778085401` so we pick 529 | // 250 knowing that 249 will be lower than the prime of the 530 | // sub group. 531 | assert!(exp < 250u64, "Exponent can't be greater than the sub-group order"); 532 | 533 | let mut res = Scalar::zero(); 534 | match exp { 535 | 0..=51 => { 536 | res[0] = 1u64 << exp; 537 | } 538 | 52..=103 => { 539 | res[1] = 1u64 << (exp - 52); 540 | } 541 | 104..=155 => { 542 | res[2] = 1u64 << (exp - 104); 543 | } 544 | 156..=207 => { 545 | res[3] = 1u64 << (exp - 156); 546 | } 547 | _ => { 548 | res[4] = 1u64 << (exp - 208); 549 | } 550 | } 551 | res 552 | } 553 | 554 | /// Returns the half of an **EVEN** `Scalar`. 555 | /// 556 | /// This function performs almost 4x faster than the 557 | /// `Half` implementation but SHOULD be used carefully. 558 | /// 559 | /// # Panics 560 | /// 561 | /// When the `Scalar` provided is not even. 562 | pub fn half_without_mod(self) -> Scalar { 563 | //assert!(self.is_even()); 564 | let mut carry = 0u64; 565 | let mut res = self; 566 | 567 | for i in (0..5).rev() { 568 | res[i] = res[i] | carry; 569 | 570 | carry = (res[i] & 1) << 52; 571 | res[i] >>= 1; 572 | } 573 | res 574 | } 575 | 576 | /// Compute `a * b`. 577 | /// Note that this is just the normal way of performing a product. 578 | /// This operation returns back a double precision result stored 579 | /// on a `[u128; 9] in order to avoid overflowings. 580 | pub(self) fn mul_internal(a: &Scalar, b: &Scalar) -> [u128; 9] { 581 | let mut res = [0u128; 9]; 582 | 583 | res[0] = m(a[0], b[0]); 584 | res[1] = m(a[0], b[1]) + m(a[1], b[0]); 585 | res[2] = m(a[0], b[2]) + m(a[1], b[1]) + m(a[2], b[0]); 586 | res[3] = m(a[0], b[3]) + m(a[1], b[2]) + m(a[2], b[1]) + m(a[3], b[0]); 587 | res[4] = m(a[0], b[4]) + m(a[1], b[3]) + m(a[2], b[2]) + m(a[3], b[1]) + m(a[4], b[0]); 588 | res[5] = m(a[1], b[4]) + m(a[2], b[3]) + m(a[3], b[2]) + m(a[4], b[1]); 589 | res[6] = m(a[2], b[4]) + m(a[3], b[3]) + m(a[4], b[2]); 590 | res[7] = m(a[3], b[4]) + m(a[4], b[3]); 591 | res[8] = m(a[4], b[4]); 592 | 593 | res 594 | } 595 | 596 | /// Compute `a^2`. 597 | /// 598 | /// This operation returns a double precision result. 599 | /// So it gives back a `[u128; 9]` with the result of the squaring. 600 | pub(self) fn square_internal(a: &Scalar) -> [u128; 9] { 601 | let a_sqrt = [a[0] * 2, a[1] * 2, a[2] * 2, a[3] * 2]; 602 | 603 | [ 604 | m(a[0], a[0]), 605 | m(a_sqrt[0], a[1]), 606 | m(a_sqrt[0], a[2]) + m(a[1], a[1]), 607 | m(a_sqrt[0], a[3]) + m(a_sqrt[1], a[2]), 608 | m(a_sqrt[0], a[4]) + m(a_sqrt[1], a[3]) + m(a[2], a[2]), 609 | m(a_sqrt[1], a[4]) + m(a_sqrt[2], a[3]), 610 | m(a_sqrt[2], a[4]) + m(a[3], a[3]), 611 | m(a_sqrt[3], a[4]), 612 | m(a[4], a[4]), 613 | ] 614 | } 615 | 616 | /// Compute `limbs/R` (mod l), where R is the Montgomery modulus 2^260 617 | pub(self) fn montgomery_reduce(limbs: &[u128; 9]) -> Scalar { 618 | 619 | fn adjustment_fact(sum: u128) -> (u128, u64) { 620 | let p = (sum as u64).wrapping_mul(constants::LFACTOR) & ((1u64 << 52) - 1); 621 | ((sum + m(p, constants::L[0])) >> 52, p) 622 | } 623 | 624 | 625 | fn montg_red_res(sum: u128) -> (u128, u64) { 626 | let w = (sum as u64) & ((1u64 << 52) - 1); 627 | (sum >> 52, w) 628 | } 629 | 630 | let l = &constants::L; 631 | 632 | // the first half computes the Montgomery adjustment factor n, and begins adding n*l to make limbs divisible by R 633 | let (carry, n0) = adjustment_fact(limbs[0]); 634 | let (carry, n1) = adjustment_fact(carry + limbs[1] + m(n0, l[1])); 635 | let (carry, n2) = adjustment_fact(carry + limbs[2] + m(n0, l[2]) + m(n1, l[1])); 636 | let (carry, n3) = 637 | adjustment_fact(carry + limbs[3] + m(n0, l[3]) + m(n1, l[2]) + m(n2, l[1])); 638 | let (carry, n4) = adjustment_fact( 639 | carry + limbs[4] + m(n0, l[4]) + m(n1, l[3]) + m(n2, l[2]) + m(n3, l[1]), 640 | ); 641 | 642 | // limbs is divisible by R now, so we can divide by R by simply storing the upper half as the result 643 | let (carry, r0) = 644 | montg_red_res(carry + limbs[5] + m(n1, l[4]) + m(n2, l[3]) + m(n3, l[2]) + m(n4, l[1])); 645 | let (carry, r1) = montg_red_res(carry + limbs[6] + m(n2, l[4]) + m(n3, l[3]) + m(n4, l[2])); 646 | let (carry, r2) = montg_red_res(carry + limbs[7] + m(n3, l[4]) + m(n4, l[3])); 647 | let (carry, r3) = montg_red_res(carry + limbs[8] + m(n4, l[4])); 648 | let r4 = carry as u64; 649 | 650 | // result may be >= r, so attempt to subtract l 651 | &Scalar([r0, r1, r2, r3, r4]) - l 652 | } 653 | 654 | /// Compute `(a * b) / R` (mod l), where R is the Montgomery modulus 2^260 655 | #[allow(dead_code)] 656 | pub(self) fn montgomery_mul(a: &Scalar, b: &Scalar) -> Scalar { 657 | Scalar::montgomery_reduce(&Scalar::mul_internal(a, b)) 658 | } 659 | 660 | /// Puts a Scalar into Montgomery form, i.e. computes `a*R (mod l)` 661 | #[allow(dead_code)] 662 | pub(self) fn to_montgomery(&self) -> Scalar { 663 | Scalar::montgomery_mul(self, &constants::RR) 664 | } 665 | 666 | /// Takes a Scalar out of Montgomery form, i.e. computes `a/R (mod l)` 667 | #[allow(dead_code)] 668 | pub(self) fn from_montgomery(&self) -> Scalar { 669 | let mut limbs = [0u128; 9]; 670 | for i in 0..5 { 671 | limbs[i] = self[i] as u128; 672 | } 673 | Scalar::montgomery_reduce(&limbs) 674 | } 675 | } 676 | 677 | #[cfg(test)] 678 | mod tests { 679 | use super::*; 680 | 681 | /// `A = 182687704666362864775460604089535377456991567872`. 682 | pub static A: Scalar = Scalar([0, 0, 0, 2, 0]); 683 | 684 | /// `B = 904625697166532776746648320197686575422163851717637391703244652875051672039` 685 | pub static B: Scalar = Scalar([ 686 | 2766226127823335, 687 | 4237835465749098, 688 | 4503599626623787, 689 | 4503599627370493, 690 | 2199023255551, 691 | ]); 692 | 693 | /// `AB = A - B (mod l) = `365375409332725729550921208179070754913983135744`. 694 | pub static AB: Scalar = Scalar([2867050651854460, 1629308859434048, 1461147, 4, 0]); 695 | 696 | /// `BA = B - A = 904625697166532776746648320014998870755800986942176787613709275418060104167`. 697 | pub static BA: Scalar = Scalar([ 698 | 2766226127823335, 699 | 4237835465749098, 700 | 4503599626623787, 701 | 4503599627370491, 702 | 2199023255551, 703 | ]); 704 | 705 | /// `A ^ B (mod l) = 722079218299359393463304261975695272152587797512052686822897975048879125727`. 706 | pub static A_POW_B: Scalar = Scalar([ 707 | 2191545792217572, 708 | 448661815025744, 709 | 1377760471467833, 710 | 2830870192895755, 711 | 435342682203, 712 | ]); 713 | 714 | /// A in Montgomery domain; `A_MONT = (A * R) (mod l) = 74956990360519859676823980567085929151483724995760953292439364863916993608`. 715 | pub static A_MONT: Scalar = Scalar([ 716 | 690508070349896, 717 | 1499135165000273, 718 | 3323154938341339, 719 | 2542801086174134, 720 | 182210350076, 721 | ]); 722 | 723 | /// `X = 1809251394333065553493296640760748560207343510400633813116524750123642650623` 724 | pub static X: Scalar = Scalar([ 725 | 4503599627370495, 726 | 4503599627370495, 727 | 4503599627370495, 728 | 4503599627370495, 729 | 4398046511103, 730 | ]); 731 | 732 | /// `Y = 717350576871794411262215878514291949349241575907629849852603275827191647632`. 733 | pub static Y: Scalar = Scalar([ 734 | 138340288859536, 735 | 461913478537005, 736 | 1182880083788836, 737 | 1688835920473363, 738 | 1743782656037, 739 | ]); 740 | 741 | /// `Y^2 (mod l) = 480582312179500987438513229347407841000328373586967991836637456597269397662`. 742 | pub static Y_SQ: Scalar = Scalar([ 743 | 3511508334592158, 744 | 913859277470939, 745 | 3383393792942685, 746 | 3918279098243301, 747 | 1168230887094, 748 | ]); 749 | 750 | /// `Y/2 = 358675288435897205631107939257145974674620787953814924926301637913595823816`. 751 | pub static Y_HALF: Scalar = Scalar([ 752 | 2320969958115016, 753 | 230956739268502, 754 | 2843239855579666, 755 | 3096217773921929, 756 | 871891328018, 757 | ]); 758 | 759 | /// Y in Montgomery domain; `Y_MONT = (Y * R) (mod l) = 181593701473289124342215660240169352515908506664531442677698834953613087302`. 760 | pub static Y_MONT: Scalar = Scalar([ 761 | 2880674519323206, 762 | 1234984943133080, 763 | 2849728124521957, 764 | 4421863362992372, 765 | 441429835402, 766 | ]); 767 | 768 | /// `(X * Y)/R (mod l) = 394801755993377774325488732071130802534479695819740243486564413323892352807`. 769 | pub static X_TIMES_Y_MONT: Scalar = Scalar([ 770 | 228255815821095, 771 | 3571367814561020, 772 | 2885104738833919, 773 | 415982367220597, 774 | 959709905966, 775 | ]); 776 | 777 | /// `X * Y (mod l) = 72607398683238392972008549298495917621610972793940628309128483126058020327` 778 | pub static X_TIMES_Y: Scalar = Scalar([ 779 | 3955754814270951, 780 | 1675310998682037, 781 | 4396625830536378, 782 | 1174212537684658, 783 | 176498809098, 784 | ]); 785 | 786 | //------------------ Tests ------------------// 787 | 788 | #[test] 789 | fn partial_ord_and_eq() { 790 | assert!(Y.is_even()); 791 | assert!(!X.is_even()); 792 | 793 | assert!(A_MONT < Y); 794 | assert!(Y < X); 795 | 796 | assert!(Y >= Y); 797 | assert!(X == X); 798 | } 799 | 800 | #[test] 801 | fn add_with_modulo() { 802 | let res = AB + BA; 803 | let zero = Scalar::zero(); 804 | 805 | for i in 0..5 { 806 | assert!(res[i] == zero[i]); 807 | } 808 | } 809 | 810 | #[test] 811 | fn add_without_modulo() { 812 | let res = BA + A; 813 | 814 | for i in 0..5 { 815 | assert!(res[i] == B[i]); 816 | } 817 | } 818 | 819 | #[test] 820 | fn sub_with_modulo() { 821 | let res = A - B; 822 | for i in 0..5 { 823 | assert!(res[i] == AB[i]); 824 | } 825 | } 826 | 827 | #[test] 828 | fn sub_without_modulo() { 829 | let res = B - A; 830 | for i in 0..5 { 831 | assert!(res[i] == BA[i]); 832 | } 833 | } 834 | 835 | #[test] 836 | fn square_internal() { 837 | let easy_res = Scalar::square_internal(&A); 838 | let res_correct: [u128; 9] = [0, 0, 0, 0, 0, 0, 4, 0, 0]; 839 | for i in 0..5 { 840 | assert!(easy_res[i] == res_correct[i]); 841 | } 842 | } 843 | 844 | #[test] 845 | fn to_montgomery_conversion() { 846 | let a = Scalar::to_montgomery(&A); 847 | for i in 0..5 { 848 | assert!(a[i] == A_MONT[i]); 849 | } 850 | } 851 | 852 | #[test] 853 | fn from_montgomery_conversion() { 854 | let y = Scalar::from_montgomery(&Y_MONT); 855 | for i in 0..5 { 856 | assert!(y[i] == Y[i]); 857 | } 858 | } 859 | 860 | #[test] 861 | fn scalar_mul() { 862 | let res = &X * &Y; 863 | for i in 0..5 { 864 | assert!(res[i] == X_TIMES_Y[i]); 865 | } 866 | } 867 | 868 | #[test] 869 | fn mul_by_identity() { 870 | let res = &Y * &Scalar::identity(); 871 | 872 | for i in 0..5 { 873 | assert!(res[i] == Y[i]); 874 | } 875 | } 876 | 877 | #[test] 878 | fn mul_by_zero() { 879 | let res = &Y * &Scalar::zero(); 880 | for i in 0..5 { 881 | assert!(res[i] == Scalar::zero()[i]); 882 | } 883 | } 884 | 885 | #[test] 886 | fn montgomery_mul() { 887 | let res = Scalar::montgomery_mul(&X, &Y); 888 | for i in 0..5 { 889 | assert!(res[i] == X_TIMES_Y_MONT[i]); 890 | } 891 | } 892 | 893 | #[test] 894 | fn square() { 895 | let res = &Y.square(); 896 | 897 | for i in 0..5 { 898 | assert!(res[i] == Y_SQ[i]); 899 | } 900 | } 901 | 902 | #[test] 903 | fn square_zero_and_identity() { 904 | let zero = &Scalar::zero().square(); 905 | let one = &Scalar::identity().square(); 906 | 907 | for i in 0..5 { 908 | assert!(zero[i] == Scalar::zero()[i]); 909 | assert!(one[i] == Scalar::one()[i]); 910 | } 911 | } 912 | 913 | #[test] 914 | fn half() { 915 | let res = &Y.half(); 916 | for i in 0..5 { 917 | assert!(res[i] == Y_HALF[i]); 918 | } 919 | 920 | let a_half = Scalar([0, 0, 0, 1, 0]); 921 | let a_half_half = Scalar([0, 0, 2251799813685248, 0, 0]); 922 | 923 | for i in 0..5 { 924 | assert!(a_half[i] == A.half()[i]); 925 | assert!(a_half_half[i] == A.half().half()[i]); 926 | } 927 | } 928 | 929 | #[test] 930 | fn mod_pow() { 931 | let res = A.pow(&B); 932 | 933 | assert!(res == A_POW_B); 934 | } 935 | 936 | #[test] 937 | fn even_scalar() { 938 | assert!(Y.is_even()); 939 | assert!(!X.is_even()); 940 | assert!(Scalar::zero().is_even()); 941 | } 942 | 943 | #[test] 944 | fn ct_eq() { 945 | use subtle::ConstantTimeEq; 946 | assert!(A.ct_eq(&A).unwrap_u8() == 1u8); 947 | assert!(A.ct_eq(&B).unwrap_u8() == 0u8); 948 | } 949 | 950 | 951 | #[test] 952 | fn two_pow_k() { 953 | // 0 case. 954 | assert!(Scalar::two_pow_k(0) == Scalar::one()); 955 | // 1 case. 956 | assert!(Scalar::two_pow_k(1) == Scalar::from(2u8)); 957 | // Normal case. 958 | assert!(Scalar::two_pow_k(249) == Scalar([0, 0, 0, 0, 2199023255552])); 959 | assert!(Scalar::two_pow_k(248) == Scalar([0, 0, 0, 0, 1099511627776])); 960 | } 961 | 962 | #[test] 963 | fn shr() { 964 | // Normal case. 965 | assert!(A >>1 == Scalar([0, 0, 0, 1, 0])); 966 | // Limb reduction case. 967 | assert!(Scalar([0, 0, 0, 1, 0]) >>1 == Scalar([0, 0, 2251799813685248, 0, 0])); 968 | // Last limb with 1 case. 969 | assert!(Scalar::one() >>1 == Scalar([0, 0, 0, 0, 0])); 970 | // Zero case. 971 | assert!(Scalar::zero() >>1 == Scalar::zero()); 972 | // Max case. 973 | assert!(Scalar::minus_one() >>250 == Scalar::zero()); 974 | assert!(Scalar::two_pow_k(249)>>248 == Scalar::from(2u8)); 975 | // Reduction 976 | assert!(Scalar::two_pow_k(249)>>249 == Scalar::one()); 977 | } 978 | 979 | #[test] 980 | fn into_bits() { 981 | // Define following results as bit-arrays. 982 | let zero = [0u8; 256]; 983 | let one = { 984 | let mut res = zero.clone(); 985 | res[0] = 1; 986 | res 987 | }; 988 | let nine = { 989 | let mut res = one.clone(); 990 | res[3] = 1; 991 | res 992 | }; 993 | let two_pow_249 = { 994 | let mut res = zero.clone(); 995 | res[249] = 1; 996 | res 997 | }; 998 | let minus_one = [0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]; 999 | 1000 | // 0 case. 1001 | assert!(&Scalar::zero().into_bits()[..] == &zero[..]); 1002 | // 1 case. 1003 | assert!(&Scalar::one().into_bits()[..] == &one[..]); 1004 | // Odd case. 1005 | assert!(&Scalar::from(9u8).into_bits()[..] == &nine[..]); 1006 | // Even case. 1007 | assert!(&Scalar::two_pow_k(249).into_bits()[..] == &two_pow_249[..]); 1008 | // MAX case. 1009 | assert!(&Scalar::minus_one().into_bits()[..] == &minus_one[..]); 1010 | } 1011 | 1012 | #[test] 1013 | fn mod_four() { 1014 | // Modulo case. 1015 | assert!(Scalar::from(4u8).mod_2_pow_k(2u8) == 0u8); 1016 | // Low case. 1017 | assert!(Scalar::from(3u8).mod_2_pow_k(2u8) == 3u8); 1018 | // Bignum case. 1019 | assert!(Scalar::from(557u16).mod_2_pow_k(2u8) == 1u8); 1020 | assert!(Scalar::from(42535295865117307932887201356513780707u128).mod_2_pow_k(2u8) == 3u8); 1021 | } 1022 | 1023 | #[test] 1024 | fn naf() { 1025 | let seven_in_naf = [-1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; 1026 | assert!(&Scalar::from(7u8).compute_NAF()[..4] == &seven_in_naf[..4]); 1027 | } 1028 | 1029 | #[test] 1030 | fn window_naf() { 1031 | let scalar = Scalar::from(1122334455u64); 1032 | // Case NAF2 1033 | let naf2_scalar = [-1, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, -1, 0, 1, 0, -1, 0, 0 ,-1, 0,1,0,0,0,1]; 1034 | assert!(&naf2_scalar[..] == &scalar.compute_window_NAF(2)[..31]); 1035 | 1036 | // Case NAF3 1037 | let naf3_scalar = [-1, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, -1, 0, 0, 0, 3,0,0,1,0,0,-1,0,0,3,0,0,0,0,0,1]; 1038 | assert!(&naf3_scalar[..] == &scalar.compute_window_NAF(3)[..31]); 1039 | 1040 | // Case NAF4 1041 | let naf4_scalar = [7,0,0,0,-1,0,0,0,7,0,0,0,7,0,0,0,5,0,0,0,0,7,0,0,0,1,0,0,0,0,1]; 1042 | assert!(&naf4_scalar[..] == &scalar.compute_window_NAF(4)[..31]); 1043 | 1044 | // Case NAF5 1045 | let naf5_scalar = [-9,0,0,0,0,0,0,0,-9,0,0,0,0,0,0,11,0,0,0,0,0,-9,0,0,0,0,-15,0,0,0,0,1]; 1046 | assert!(&naf5_scalar[..] == &scalar.compute_window_NAF(5)[..32]); 1047 | 1048 | //Case NAF6 1049 | let naf6_scalar = [-9,0,0,0,0,0,0,0,-9,0,0,0,0,0,0,11,0,0,0,0,0,23,0,0,0,0,0,0,0,0,1]; 1050 | assert!(&naf6_scalar[..] == &scalar.compute_window_NAF(6)[..31]); 1051 | 1052 | } 1053 | } 1054 | -------------------------------------------------------------------------------- /src/constants.rs: -------------------------------------------------------------------------------- 1 | //! Contains the curve-constants needed by different algorithm implementations. 2 | 3 | use crate::edwards::CompressedEdwardsY; 4 | use crate::ristretto::CompressedRistretto; 5 | 6 | #[cfg(feature = "u64_backend")] 7 | pub use crate::backend::u64::constants::*; 8 | 9 | /// Holds the value of the Curve basepoint, which has been constructed 10 | /// from taking `y-coodrinate = 3/5 (mod l)`. 11 | /// The positive sign is choosen for it, so we leave it on it's cannonical bytes 12 | /// encoding. 13 | pub const BASEPOINT_COMPRESSED: CompressedEdwardsY = CompressedEdwardsY([ 14 | 194, 24, 45, 158, 220, 161, 164, 1, 231, 42, 46, 200, 184, 98, 31, 166, 153, 153, 153, 153, 15 | 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 9, 16 | ]); 17 | 18 | /// Ristretto Basepoint on compressed format. 19 | pub const RISTRETTO_BASEPOINT_COMPRESSED: CompressedRistretto = CompressedRistretto([ 20 | 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21 | ]); 22 | -------------------------------------------------------------------------------- /src/field.rs: -------------------------------------------------------------------------------- 1 | //! A `FieldElement` represents an element of the finite field 2 | //! modulo `2^252 + 27742317777372353535851937790883648493`. 3 | //! 4 | //! The `FieldElement` type is an alias for one of the backend 5 | //! implementations. 6 | //! 7 | //! `ConstantTimeEq` and `PartialEq` traits have been implemented 8 | //! here since they will be the samme across all of the different backends. 9 | //! 10 | //! # Examples 11 | //! ```rust 12 | //! use zerocaf::field::FieldElement; 13 | //! use zerocaf::traits::ops::*; 14 | //! use zerocaf::constants::EDWARDS_D; 15 | //! 16 | //! use subtle::Choice; 17 | //! use rand::rngs::OsRng; 18 | //! 19 | //! // You can create a FieldElement from a byte-array as follows: 20 | //! let a = FieldElement::from_bytes(&[0u8;32]); 21 | //! 22 | //! // You ca also create a FieldElement from an uint type as follows: 23 | //! let b = FieldElement::from(126296u128); 24 | //! let c = FieldElement::from(126297u64); 25 | //! 26 | //! // You can create random FieldElements by calling: 27 | //! let rand = FieldElement::random(&mut OsRng); 28 | //! 29 | //! // The last way of creating a FieldElement it by calling the 30 | //! // constructor. THIS IS NOT RECOMMENDED since NO checks about 31 | //! // the correctness of the input will be done at all. 32 | //! // It can be done as follows: 33 | //! let d: FieldElement = FieldElement([0, 1, 0, 0, 0]); // d = 2^52. 34 | //! assert!(d == FieldElement::two_pow_k(52u64)); 35 | //! 36 | //! // All of the basuc modular operations are implemented 37 | //! // for FieldElement type: 38 | //! let mut res = &a + &b; // Performs a + b (mod l). 39 | //! res = a - b; // Performs a - b (mod l). 40 | //! res = a * b; // Performs a * b (mod l). 41 | //! res = a.square(); // Performs a^2 (mod l). 42 | //! res = -&a; // Performs Negation over the modulo l. 43 | //! res = a.pow(&b); // Performs Modular exponentiation. 44 | //! res = a.mod_sqrt(Choice::from(1u8)).unwrap(); //Performs 45 | //! // modular sqrt. 46 | //! // Returs `None` if the input is not a QR on the field. 47 | //! // Returns Some(result) if everything is correct. 48 | //! 49 | //! // Division has been also implemented. Remember that when we write 50 | //! // a/b (mod l), we are indeed performing a * inverse_mod(b, l) (mod l). 51 | //! assert!((-b / c) == EDWARDS_D); 52 | //! 53 | //! // Dividing by two even FieldElements is recommended through the `Half` 54 | //! // trait implmementation since it's much faster. 55 | //! if a.is_even() { 56 | //! let half_a = &a.half(); // This will panic if a isn't even. 57 | //! }; 58 | //! 59 | //! // We can finally perform inversion modulo l for a FieldElement: 60 | //! let inv_a = &c.inverse(); // Performs a^-1 (mod l). 61 | //! 62 | //! // You can export your `FieldElement` as an slice of 32 bytes in Little 63 | //! // Endian encoding by: 64 | //! let c_bytes: [u8; 32] = c.to_bytes(); 65 | //! ``` 66 | //! 67 | //! `PartialOrd`, `Ord`, `PartialEq` and `Eq` are also implemented for 68 | //! `FieldElement` type. 69 | //! 70 | //! All `std::core::ops traits -> (Add, Sub, Mul, Div)` are implemented 71 | //! for both, `&FieldElement` and `FieldElement`. 72 | 73 | use core::cmp::PartialEq; 74 | 75 | use subtle::{Choice, ConditionallySelectable, ConstantTimeEq}; 76 | 77 | use rand::{CryptoRng, Rng}; 78 | 79 | use curve25519_dalek::scalar::Scalar; 80 | 81 | use crate::backend; 82 | 83 | #[cfg(feature = "u64_backend")] 84 | pub use backend::u64::field::*; 85 | /// A `FieldElement` represents an element of the field 86 | /// `2^252 + 27742317777372353535851937790883648493` 87 | /// 88 | /// The `FieldElement` type is an alias for one of the platform-specific 89 | /// implementations. 90 | #[cfg(feature = "u64_backend")] 91 | pub type FieldElement = backend::u64::field::FieldElement; 92 | 93 | impl PartialEq for FieldElement { 94 | fn eq(&self, other: &FieldElement) -> bool { 95 | self.ct_eq(other).unwrap_u8() == 1u8 96 | } 97 | } 98 | 99 | impl ConstantTimeEq for FieldElement { 100 | /// Test equality between two `FieldElement`s. Since the 101 | /// internal representation is not canonical, the field elements 102 | /// are normalized to wire format before comparison. 103 | fn ct_eq(&self, other: &FieldElement) -> Choice { 104 | self.to_bytes().ct_eq(&other.to_bytes()) 105 | } 106 | } 107 | 108 | impl ConditionallySelectable for FieldElement { 109 | fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { 110 | FieldElement([ 111 | u64::conditional_select(&a.0[0], &b.0[0], choice), 112 | u64::conditional_select(&a.0[1], &b.0[1], choice), 113 | u64::conditional_select(&a.0[2], &b.0[2], choice), 114 | u64::conditional_select(&a.0[3], &b.0[3], choice), 115 | u64::conditional_select(&a.0[4], &b.0[4], choice), 116 | ]) 117 | } 118 | } 119 | 120 | impl Into for &FieldElement { 121 | fn into(self) -> Scalar { 122 | Scalar::from_bytes_mod_order(self.to_bytes()) 123 | } 124 | } 125 | 126 | impl FieldElement { 127 | /// Generate a valid FieldElement choosen uniformly using user- 128 | /// provided rng. 129 | /// 130 | /// By `rng` we mean any Rng that implements: `Rng` + `CryptoRng`. 131 | pub fn random(rand: &mut T) -> FieldElement 132 | where 133 | T: Rng + CryptoRng, 134 | { 135 | let mut bytes = [0u8; 32]; 136 | rand.fill_bytes(&mut bytes); 137 | // Ensure that the value is lower than `FIELD_L`. 138 | bytes[31] &= 0b0000_0111; 139 | FieldElement::from_bytes(&bytes) 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc( 2 | html_logo_url = "https://lh3.googleusercontent.com/SmwswGxtgIANTbDrCOn5EKcRBnVdHjmYsHYxLq2HZNXWCQ9-fZyaea-bNgdX9eR0XGSqiMFi=w128-h128-e365" 3 | )] 4 | #![doc(html_favicon_url = "https://dusk.network/lib/img/favicon-16x16.png")] 5 | //! 6 | //! 7 | //! 8 | //! 9 | //! 10 | //! 11 | //! 12 | //! GitHub closed issues 13 | //! 14 | //! 15 | //! Crates.io 16 | //! 17 | //! 18 | //! 19 | //!

20 | //! 21 | //!
22 | //!
23 | //! 24 | //! # What is Zerocaf? 25 | //! Zerocaf is a pure Rust cryptographic library constructed to define operations for an elliptic curve embedded 26 | //! into the Ristretto scalar field, which allows the construction of prime order groups 27 | //! from an otherwise non prime order curve.
28 | //! 29 | //! The ultimate purpose of defining operations is for set inclusion proofs - where it is shown, in zero-knowledge, 30 | //! that a private key exists in a set of many public keys.
31 | //! 32 | //! Additionally, the zero-knowledge proofs use Bulletproofs as the argument for arithmetic circuits 33 | //! that are used to form arbitrary constraint systems. 34 | //! 35 | //! # What can it be used for? 36 | //! The main goal of the library, as said before, is to be the base of operations over set inclusion proofs 37 | //! and other Zero-Knowledge protocols.
38 | //! 39 | //! But since Zerocaf is build upon the SonnyCurve using the Ristretto protocol, it allows other devs to build 40 | //! cryptographic protocols over it without needing to take care about the co-factor of the curve.
41 | //! 42 | //! This, brings to developers, a good mathematical backend library which can be used as a `mid-level` API 43 | //! for building all kinds of cryptographic protocols over it such as key agreement, signatures, 44 | //! anonymous credentials, rangeproofs...
45 | //! 46 | //! # Usage 47 | //! To import the library as a dependency of your project, just add on your `Cargo.toml`s project file: 48 | //! ```toml 49 | //! zerocaf = "0.1.1" 50 | //! ``` 51 | //! 52 | //! Then import the crate as: 53 | //! ```rust 54 | //! extern crate zerocaf; 55 | //! ``` 56 | //! 57 | //! # Backends. 58 | //! Zerocaf has been built following the [Curve25519-dalek](https://docs.rs/curve25519-dalek/1.2.1/curve25519_dalek/) library structure, which allows for multiple 59 | //! backend implementations. All of the works are built to enable modularity.
60 | //! 61 | //! Currently, `Zerocaf` has implemented the u64 backend. 62 | //! By default, the `u64` backend is the one which is used to perform all of 63 | //! the operations. 64 | //! Additionly, for future works, we would like to implement a `u32` backend aswell.
65 | //! 66 | //! To select a backend type, the following method can be used: 67 | //! ```sh 68 | //! // For unoptimized builds: 69 | //! cargo build --features "u64_backend" 70 | //! 71 | //! // For optimized/release builds: 72 | //! cargo build --release --features "u64_backend" 73 | //! ``` 74 | //!
75 | //! 76 | //! NOTE: If no backend is selected, the compilation will fail!
77 | //! 78 | //! # Security and features of Zerocaf 79 | //! 80 | //! As is previously mentioned, zerocaf is designed to host the fastest possible curve operations whilst 81 | //! simultaneously avoiding all of the drawbacks associated with having a cofactor such that h > 1.
82 | //! 83 | //! To achieve this we make use of Ristretto, which is a technique to construct prime order elliptic curve groups. 84 | //! The Ristretto protocol compresses the cofactor by adding a thin abstraction layer to allow small changes 85 | //! in code to ultimately omit the cofactor issues.
86 | //! 87 | //! This is achieved by having defining the twisted edwards curve over the ristretto scalar field, 88 | //! which means to perform every operation on the curve in modulo L, 89 | //! where L is the order of the ristretto scalar field.
90 | //! 91 | //! `L = 2^252 + 27742317777372353535851937790883648493`.
92 | //! 93 | //! By expounding the operations in this manner, we can benefit from the speed of a non-prime order twisted 94 | //! edwards curve whilst not suffering the pitfalls of a cofactor greater than one. 95 | //! 96 | //! 97 | //! # Performance & Benchmarks 98 | //! Benchmarks have been implemented using [Criterion.rs](https://docs.rs/criterion/0.2.11/criterion/). 99 | //! To run them just execute `cargo bench` on the repository root.
100 | //! 101 | //! All of the operatons have been implemented using bit-shifting techniques to allow better performance 102 | //! and a significant reduction in execution time. 103 | //! 104 | //! # Examples 105 | //! We are planning to add some examples about tha basics of the `Zerocaf` library usage.
106 | //! They will be uploaded to the [examples](https://github.com/dusk-network/dusk-zerocaf/tree/master/docs) folder.
107 | //! 108 | //! This is a very basic usage example of the Zerocaf lib: 109 | //! ```rust 110 | //! extern crate zerocaf; 111 | //! extern crate rand; 112 | //! 113 | //! use zerocaf::field::FieldElement; 114 | //! use zerocaf::scalar::Scalar; 115 | //! use zerocaf::edwards::EdwardsPoint; 116 | //! 117 | //! use rand::{Rng, thread_rng}; 118 | //! 119 | //! fn main() -> () { 120 | //! 121 | //! // Let G be an `EdwardsPoint` which is a point over the Twisted Eds Extended Coordinates. 122 | //! let G: EdwardsPoint = EdwardsPoint { 123 | //! X: FieldElement([23, 0, 0, 0, 0]), 124 | //! Y: FieldElement([1664892896009688, 132583819244870, 812547420185263, 637811013879057, 13284180325998]), 125 | //! Z: FieldElement([1, 0, 0, 0, 0]), 126 | //! T: FieldElement([4351986304670635, 4020128726404030, 674192131526433, 1158854437106827, 6468984742885]) 127 | //! }; 128 | //! 129 | //! let scalar: Scalar = rand_scalar_generation(); 130 | //! println!("{:?}", scalar); 131 | //! 132 | //! // Perform G*k, Point mul uses the `add_and_double` standard algorithm. 133 | //! let P = &G * &scalar; 134 | //! println!("{:?}", P); 135 | //! } 136 | //! 137 | //! /// Generate a random `Scalar` defined over the sub-group field 138 | //! /// modulo: `2^249 - 15145038707218910765482344729778085401` 139 | //! pub fn rand_scalar_generation() -> Scalar { 140 | //! // Gen random 32-byte array. 141 | //! let mut bytes = [0u8;32]; 142 | //! 143 | //! // Fill the bytes varible with random bytes. We can use the 32 bytes co give 144 | //! // total randomness but then we will need to be aware because we can generate 145 | //! // values greater than `L = 2^252 + 27742317777372353535851937790883648493` and 146 | //! // the program will panic if we don't catch the error correctly on the 147 | //! // `from_bytes()` Scalar method call. 148 | //! thread_rng().try_fill(&mut bytes[..31]).expect("Error getting the random bytes"); 149 | //! 150 | //! Scalar::from_bytes(&bytes) 151 | //! } 152 | //! ``` 153 | //!
154 | //! We will also publish some videos talking about how is the library built and 155 | //! the maths that are happening behind the scenes.
156 | //! Videos can also include programming examples using `Zerocaf` as a dependency.
157 | //! You can check them on the [Dusk Network Youtube Channel](https://www.youtube.com/channel/UCAfY3VcuaxAelPp44B253Rw). 158 | //! 159 | 160 | // Used for traits related to constant-time code. 161 | extern crate subtle; 162 | // Used for Ristretto255Scalar trait. 163 | extern crate curve25519_dalek; 164 | extern crate num; 165 | 166 | pub mod backend; 167 | pub mod constants; 168 | pub mod edwards; 169 | pub mod field; 170 | pub mod montgomery; 171 | pub mod ristretto; 172 | pub mod scalar; 173 | pub mod traits; 174 | -------------------------------------------------------------------------------- /src/montgomery.rs: -------------------------------------------------------------------------------- 1 | //! Implementation that provides support for Montgomery Points 2 | //! over the Sonnycurve. 3 | //! 4 | //! A `MontgomeryPoint` is represented as the `u-coordinate` 5 | //! of itself in LE bytes-format. 6 | 7 | use crate::edwards::EdwardsPoint; 8 | use crate::field::FieldElement; 9 | 10 | use subtle::Choice; 11 | use subtle::ConstantTimeEq; 12 | 13 | /// Holds the u-coordinate of a point on the Montgomery form of 14 | /// Doppio-curve or its twist. 15 | #[derive(Copy, Clone, Debug)] 16 | pub struct MontgomeryPoint(pub [u8; 32]); 17 | 18 | /// Equality of `MontgomeryPoint`s is defined mod p. 19 | impl ConstantTimeEq for MontgomeryPoint { 20 | fn ct_eq(&self, other: &MontgomeryPoint) -> Choice { 21 | let self_fe = FieldElement::from_bytes(&self.0); 22 | let other_fe = FieldElement::from_bytes(&other.0); 23 | 24 | self_fe.ct_eq(&other_fe) 25 | } 26 | } 27 | 28 | impl Default for MontgomeryPoint { 29 | fn default() -> MontgomeryPoint { 30 | MontgomeryPoint([0u8; 32]) 31 | } 32 | } 33 | 34 | impl PartialEq for MontgomeryPoint { 35 | fn eq(&self, other: &MontgomeryPoint) -> bool { 36 | self.ct_eq(other).unwrap_u8() == 1u8 37 | } 38 | } 39 | 40 | impl Eq for MontgomeryPoint {} 41 | 42 | impl MontgomeryPoint { 43 | /// View this `MontgomeryPoint` as an array of bytes. 44 | pub fn as_bytes<'a>(&'a self) -> &'a [u8; 32] { 45 | &self.0 46 | } 47 | 48 | /// Convert this `MontgomeryPoint` to an array of bytes. 49 | pub fn to_bytes(&self) -> [u8; 32] { 50 | self.0 51 | } 52 | 53 | /// Attempt to convert to an `EdwardsPoint`, using the supplied 54 | /// choice of sign for the `EdwardsPoint`. 55 | pub fn to_edwards(&self, _sign: u8) -> Option { 56 | unimplemented!() 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/ristretto.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | #![allow(non_snake_case)] 3 | //! Implementation of the Ristretto Protocol over the 4 | //! Sonnycurve. 5 | //! 6 | //! Notes extracted from: https://ristretto.group/ristretto.html. 7 | //! Go there for the full lecture or check the paper here: 8 | //! https://tools.ietf.org/pdf/draft-hdevalence-cfrg-ristretto-00.pdf 9 | //! 10 | //! The code wa originaly created by Isis Agora Lovecruft and 11 | //! Henry de Valence [here](https://github.com/dalek-cryptography/curve25519-dalek/blob/master/src/ristretto.rs) 12 | //! 13 | //! # What's Ristretto? 14 | //! Ristretto is a construction of a prime-order group using a non-prime-order Edwards curve. 15 | //! The Decaf paper suggests using a non-prime-order curve E\mathcal EE to implement a prime-order 16 | //! group by constructing a quotient group. Ristretto uses the same idea, but with different formulas, 17 | //! in order to allow the use of cofactor 8 curves such as Curve25519. 18 | //! 19 | //! Internally, a Ristretto point is represented by an Edwards point. 20 | //! Two Edwards points `P, Q` may represent the same Ristretto point, in the same way that 21 | //! different projective (X,Y,Z) coordinates may represent the same Edwards point. 22 | //! 23 | //! Group operations on Ristretto points are carried out with no overhead by performing the 24 | //! operations on the representative Edwards points. 25 | //! 26 | //! Reference: https://tools.ietf.org/html/draft-hdevalence-cfrg-ristretto-00 27 | use crate::constants; 28 | use crate::edwards::{double_and_add, EdwardsPoint}; 29 | use crate::field::FieldElement; 30 | use crate::scalar::Scalar; 31 | use crate::traits::ops::*; 32 | use crate::traits::{Identity, ValidityCheck}; 33 | 34 | use core::ops::{Add, Sub, Index, Mul, Neg}; 35 | 36 | use std::fmt::Debug; 37 | 38 | use rand::{CryptoRng, Rng}; 39 | use subtle::{Choice, ConditionallyNegatable, ConditionallySelectable, ConstantTimeEq}; 40 | 41 | /// Ristretto Point expressed in wire format. 42 | /// Since the Ristretto bytes encoding is canonical, 43 | /// two points are equal if their encodin form is equal. 44 | #[derive(Debug, Clone, Copy)] 45 | pub struct CompressedRistretto(pub [u8; 32]); 46 | 47 | impl Index for CompressedRistretto { 48 | type Output = u8; 49 | fn index(&self, _index: usize) -> &u8 { 50 | &(self.0[_index]) 51 | } 52 | } 53 | 54 | impl ConstantTimeEq for CompressedRistretto { 55 | fn ct_eq(&self, other: &Self) -> Choice { 56 | self.as_bytes().ct_eq(&other.as_bytes()) 57 | } 58 | } 59 | 60 | impl PartialEq for CompressedRistretto { 61 | fn eq(&self, other: &CompressedRistretto) -> bool { 62 | self.ct_eq(other).unwrap_u8() == 1u8 63 | } 64 | } 65 | 66 | impl Eq for CompressedRistretto {} 67 | 68 | impl Identity for CompressedRistretto { 69 | /// Returns the Identity point on `CompressedRistretto` 70 | /// format. 71 | fn identity() -> CompressedRistretto { 72 | CompressedRistretto([0u8; 32]) 73 | } 74 | } 75 | 76 | impl CompressedRistretto { 77 | /// Get the bytes of the `CompressedRistretto` point. 78 | pub fn as_bytes(&self) -> [u8; 32] { 79 | self.0 80 | } 81 | 82 | pub fn copy_from_slice(bytes: &[u8]) -> CompressedRistretto { 83 | let mut inp = [0u8; 32]; 84 | inp.copy_from_slice(bytes); 85 | CompressedRistretto(inp) 86 | } 87 | 88 | #[allow(non_snake_case)] 89 | /// Attempt to decompress a `CompressedRistretto` point. 90 | /// This proces is done following the formulas derived from the 91 | /// isogenies that suit for our curve selection. 92 | /// 93 | /// # Returns 94 | /// - If the decompression/decoding succeeds -> `Some(RistrettoPoint)`. 95 | /// - If the decompression/decoding fails -> `None`. 96 | pub fn decompress(&self) -> Option { 97 | // Step 1: Check that the byte-string is a valid FieldElement. 98 | 99 | // As Ristretto paper says: "If the implementation's field element 100 | // encoding function produces canonical outputs, one way to check 101 | // that s_bytes is a canonical encoding (in step 1) is to decode 102 | // s_bytes into sss, then re-encode sss into s_bytes_check, and ensure 103 | // that s_bytes == s_bytes_check. 104 | let s: FieldElement = FieldElement::from_bytes(&self.as_bytes()); 105 | let s_check = s.to_bytes(); 106 | let s_correct_enc = s_check.ct_eq(&self.as_bytes()); 107 | let s_is_positive = s.is_positive(); 108 | 109 | // If the byte-encoding was incorrect or the representation is 110 | // a negative `FieldElement` (according to the definition of 111 | // positive found on Decaf paper), return `None`. 112 | if s_is_positive.unwrap_u8() == 0u8 || s_correct_enc.unwrap_u8() == 0u8 { 113 | return None; 114 | }; 115 | // Step 2: Attempt to decompress the CompressedRistretto. 116 | let one = FieldElement::one(); 117 | 118 | // u1 = 1 + as² with a = -1. 119 | let u1 = one - s.square(); 120 | // u2 = 1 - as² with a = -1. 121 | let u2 = one + s.square(); 122 | let u2_sq = u2.square(); 123 | 124 | // v = a*d*u1² - u2² 125 | let v = -(constants::EDWARDS_D * u1.square()) - u2_sq; 126 | // I = 1/sqrt(v*u2²), returns `None` if the sqrt does not exist. 127 | let (ok, I) = (v * u2_sq).inv_sqrt(); 128 | if ok.unwrap_u8() == 0 { 129 | return None; 130 | }; 131 | 132 | // Compute the Extended Point Coordinates Y & T 133 | let Dx = I * u2; 134 | let Dy = I * Dx * v; 135 | 136 | // Compute ABS(2*s*Dx) and negate if it is negative. 137 | let mut x = (s + s) * Dx; 138 | let x_is_pos = x.is_positive(); 139 | x.conditional_negate(!x_is_pos); 140 | // Compute Y and T coordinates. 141 | let y = u1 * Dy; 142 | let t = x * y; 143 | 144 | if t.is_positive().unwrap_u8() == 0u8 || y == FieldElement::zero() { 145 | return None; 146 | }; 147 | 148 | Some(RistrettoPoint(EdwardsPoint { 149 | X: x, 150 | Y: y, 151 | Z: one, 152 | T: t, 153 | })) 154 | } 155 | } 156 | 157 | #[derive(Clone, Copy)] 158 | pub struct RistrettoPoint(pub EdwardsPoint); 159 | 160 | impl Debug for RistrettoPoint { 161 | fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { 162 | write!(f, "{:?}", &self.0) 163 | } 164 | } 165 | 166 | impl ConstantTimeEq for RistrettoPoint { 167 | /// As specified on the Ristretto protocol docs: 168 | /// https://ristretto.group/formulas/equality.html 169 | /// and we are on the twisted case, we compare 170 | /// `X1*Y2 == Y1*X2 | X1*X2 == Y1*Y2`. 171 | fn ct_eq(&self, other: &RistrettoPoint) -> Choice { 172 | let a = (self.0.X * other.0.Y).ct_eq(&(self.0.Y * other.0.X)); 173 | let b = (self.0.X * other.0.X).ct_eq(&(self.0.Y * other.0.Y)); 174 | a | b 175 | } 176 | } 177 | 178 | impl PartialEq for RistrettoPoint { 179 | fn eq(&self, other: &RistrettoPoint) -> bool { 180 | self.ct_eq(&other).unwrap_u8() == 1u8 181 | } 182 | } 183 | 184 | impl Eq for RistrettoPoint {} 185 | 186 | impl Identity for RistrettoPoint { 187 | /// Gives back the Identity point for the Extended Edwards Coordinates 188 | /// which is endoded as a `RistrettoPoint` with coordinates: 189 | /// `(X, Y, Z, T)` = `(0, 1, 1, 0)`. 190 | fn identity() -> RistrettoPoint { 191 | RistrettoPoint(EdwardsPoint::identity()) 192 | } 193 | } 194 | 195 | impl Default for RistrettoPoint { 196 | /// Gives back the Identity point for the Extended Edwards Coordinates 197 | /// which is endoded as a `RistrettoPoint` with coordinates: 198 | /// `(X, Y, Z, T)` = `(0, 1, 1, 0)`. 199 | fn default() -> RistrettoPoint { 200 | RistrettoPoint::identity() 201 | } 202 | } 203 | 204 | //TODO: Review RistrettoPoint original implementation correctness: #83. 205 | impl ValidityCheck for RistrettoPoint { 206 | /// A valid `RistrettoPoint` should have exactly 207 | /// order `L` (Scalar Field Order) and also 208 | /// verify the curve equation. 209 | /// 210 | /// This trait is mostly implemented for debugging purposes. 211 | /// 212 | /// # Returns 213 | /// - `Choice(1) if the point has order L (not 2L, 4L or 8L) & 214 | /// satisfies the curve equation. 215 | /// - `Choice(0) if the point does not satisfy one of the conditions 216 | /// mentioned avobe. 217 | fn is_valid(&self) -> Choice { 218 | // Verify that the point has order `L` (Sub group order). 219 | let has_order_l = (self.0 * constants::L).ct_eq(&EdwardsPoint::identity()); 220 | has_order_l & self.0.is_valid() 221 | } 222 | } 223 | 224 | impl<'a> Neg for &'a RistrettoPoint { 225 | type Output = RistrettoPoint; 226 | /// Negates a `RistrettoPoint` giving it's negated representation 227 | /// as a result. 228 | /// 229 | /// Since the negative of a point is (-X:Y:Z:-T), it 230 | /// gives as a result: `(-X:Y:Z:-T)`. 231 | fn neg(self) -> RistrettoPoint { 232 | RistrettoPoint(-self.0) 233 | } 234 | } 235 | 236 | impl Neg for RistrettoPoint { 237 | type Output = RistrettoPoint; 238 | /// Negates a `RistrettoPoint` giving it's negated representation 239 | /// as a result. 240 | /// 241 | /// Since the negative of a point is (-X:Y:Z:-T), it 242 | /// gives as a result: `(-X:Y:Z:-T)`. 243 | fn neg(self) -> RistrettoPoint { 244 | RistrettoPoint(-&self.0) 245 | } 246 | } 247 | 248 | impl<'a, 'b> Add<&'a RistrettoPoint> for &'b RistrettoPoint { 249 | type Output = RistrettoPoint; 250 | /// Performs the addition of two RistrettoPoints following the 251 | /// Twisted Edwards Extended Coordinates formulae. 252 | /// 253 | /// This implementation is specific for curves with `a = -1` as 254 | /// the isomorphic twist is for Doppio. 255 | /// 256 | /// [Source: 2008 Hisil–Wong–Carter–Dawson], 257 | /// (http://eprint.iacr.org/2008/522), Section 3.1. 258 | fn add(self, other: &'a RistrettoPoint) -> RistrettoPoint { 259 | RistrettoPoint(&self.0 + &other.0) 260 | } 261 | } 262 | 263 | impl Add for RistrettoPoint { 264 | type Output = RistrettoPoint; 265 | /// Performs the addition of two RistrettoPoints following the 266 | /// Twisted Edwards Extended Coordinates formulae. 267 | /// 268 | /// This implementation is specific for curves with `a = -1` as 269 | /// the isomorphic twist is for Doppio. 270 | /// 271 | /// [Source: 2008 Hisil–Wong–Carter–Dawson], 272 | /// (http://eprint.iacr.org/2008/522), Section 3.1. 273 | fn add(self, other: RistrettoPoint) -> RistrettoPoint { 274 | &self + &other 275 | } 276 | } 277 | 278 | impl<'a, 'b> Sub<&'a RistrettoPoint> for &'b RistrettoPoint { 279 | type Output = RistrettoPoint; 280 | /// Performs the subtraction of two RistrettoPoints following the 281 | /// Twisted Edwards Extended Coordinates formulae. 282 | /// 283 | /// Note that Subtraction is basically the addition of the first 284 | /// point by the second negated. 285 | /// 286 | /// This implementation is specific for curves with `a = -1` as 287 | /// the isomorphic twist is for Doppio. 288 | /// 289 | /// [Source: 2008 Hisil–Wong–Carter–Dawson], 290 | /// (http://eprint.iacr.org/2008/522), Section 3.1. 291 | fn sub(self, other: &'a RistrettoPoint) -> RistrettoPoint { 292 | self + &-other 293 | } 294 | } 295 | 296 | impl Sub for RistrettoPoint { 297 | type Output = RistrettoPoint; 298 | /// Performs the subtraction of two RistrettoPoints following the 299 | /// Twisted Edwards Extended Coordinates formulae. 300 | /// 301 | /// Note that Subtraction is basically the addition of the first 302 | /// point by the second negated. 303 | /// 304 | /// This implementation is specific for curves with `a = -1` as 305 | /// the isomorphic twist is for Doppio. 306 | /// 307 | /// [Source: 2008 Hisil–Wong–Carter–Dawson], 308 | /// (http://eprint.iacr.org/2008/522), Section 3.1. 309 | fn sub(self, other: RistrettoPoint) -> RistrettoPoint { 310 | &self - &other 311 | } 312 | } 313 | 314 | impl<'a> Double for &'a RistrettoPoint { 315 | type Output = RistrettoPoint; 316 | /// Performs the point doubling operation 317 | /// ie. `2*P` over the Twisted Edwards Extended 318 | /// Coordinates. 319 | /// 320 | /// This implementation is specific for curves with `a = -1` as 321 | /// the isomorphic twist is. 322 | /// Source: 2008 Hisil–Wong–Carter–Dawson, 323 | /// http://eprint.iacr.org/2008/522, Section 3.1. 324 | /// Cost: 4M+ 4S+ 1D 325 | fn double(self) -> RistrettoPoint { 326 | RistrettoPoint(self.0.double()) 327 | } 328 | } 329 | 330 | impl<'a, 'b> Mul<&'b Scalar> for &'a RistrettoPoint { 331 | type Output = RistrettoPoint; 332 | /// Scalar multiplication: compute `self * Scalar`. 333 | /// This implementation uses the algorithm: 334 | /// `add_and_doubling` which is the standard one for 335 | /// this operations and also adds less constraints on 336 | /// R1CS. 337 | /// 338 | /// Hankerson, Darrel; Vanstone, Scott; Menezes, Alfred (2004). 339 | /// Guide to Elliptic Curve Cryptography. 340 | /// Springer Professional Computing. New York: Springer-Verlag. 341 | fn mul(self, scalar: &'b Scalar) -> RistrettoPoint { 342 | double_and_add(self, scalar) 343 | } 344 | } 345 | 346 | impl<'a, 'b> Mul<&'b RistrettoPoint> for &'a Scalar { 347 | type Output = RistrettoPoint; 348 | /// Scalar multiplication: compute `self * Scalar`. 349 | /// This implementation uses the algorithm: 350 | /// `add_and_doubling` which is the standard one for 351 | /// this operations and also adds less constraints on 352 | /// R1CS. 353 | /// 354 | /// Hankerson, Darrel; Vanstone, Scott; Menezes, Alfred (2004). 355 | /// Guide to Elliptic Curve Cryptography. 356 | /// Springer Professional Computing. New York: Springer-Verlag. 357 | fn mul(self, point: &'b RistrettoPoint) -> RistrettoPoint { 358 | double_and_add(point, &self) 359 | } 360 | } 361 | 362 | impl Mul for RistrettoPoint { 363 | type Output = RistrettoPoint; 364 | /// Scalar multiplication: compute `self * Scalar`. 365 | /// This implementation uses the algorithm: 366 | /// `add_and_doubling` which is the standard one for 367 | /// this operations and also adds less constraints on 368 | /// R1CS. 369 | /// 370 | /// Hankerson, Darrel; Vanstone, Scott; Menezes, Alfred (2004). 371 | /// Guide to Elliptic Curve Cryptography. 372 | /// Springer Professional Computing. New York: Springer-Verlag. 373 | fn mul(self, scalar: Scalar) -> RistrettoPoint { 374 | &self * &scalar 375 | } 376 | } 377 | 378 | impl Mul for Scalar { 379 | type Output = RistrettoPoint; 380 | /// Scalar multiplication: compute `self * Scalar`. 381 | /// This implementation uses the algorithm: 382 | /// `add_and_doubling` which is the standard one for 383 | /// this operations and also adds less constraints on 384 | /// R1CS. 385 | /// 386 | /// Hankerson, Darrel; Vanstone, Scott; Menezes, Alfred (2004). 387 | /// Guide to Elliptic Curve Cryptography. 388 | /// Springer Professional Computing. New York: Springer-Verlag. 389 | fn mul(self, point: RistrettoPoint) -> RistrettoPoint { 390 | &self * &point 391 | } 392 | } 393 | 394 | impl RistrettoPoint { 395 | /// Encode a Ristretto point represented by the point `(X:Y:Z:T)` 396 | /// in extended coordinates. 397 | #[allow(non_snake_case)] 398 | pub fn compress(&self) -> CompressedRistretto { 399 | let u1 = (self.0.Z + self.0.Y) * (self.0.Z - self.0.Y); 400 | let u2 = self.0.X * self.0.Y; 401 | let (_, I) = (u1 * u2.square()).inv_sqrt(); 402 | let D1 = u1 * I; 403 | let D2 = u2 * I; 404 | let Zinv = D1 * D2 * self.0.T; 405 | let mut xy; 406 | let D; 407 | if (self.0.T * Zinv).is_positive().unwrap_u8() == 0u8 { 408 | xy = ( 409 | constants::SQRT_MINUS_ONE * self.0.Y, 410 | constants::SQRT_MINUS_ONE * self.0.X, 411 | ); 412 | D = D1 * constants::INV_SQRT_A_MINUS_D; 413 | } else { 414 | xy = (self.0.X, self.0.Y); 415 | D = D2; 416 | }; 417 | 418 | xy.1.conditional_negate(!(xy.0 * Zinv).is_positive()); 419 | // We are on the Twisted case, so a = -1. 420 | // Then s = ABS((Z-Y) * D) 421 | let mut s = (self.0.Z - xy.1) * D; 422 | s.conditional_negate(!s.is_positive()); 423 | 424 | CompressedRistretto(s.to_bytes()) 425 | } 426 | 427 | /// Computes the Ristretto Elligator map. 428 | /// This gets a `RistrettoPoint` from a given 429 | /// `FieldElement´. 430 | pub fn elligator_ristretto_flavor(r_0: &FieldElement) -> RistrettoPoint { 431 | let d = constants::EDWARDS_D; 432 | let one = FieldElement::one(); 433 | let mut c = -one; 434 | // 1 - d^2 435 | let one_minus_d_sq = one - d.square(); 436 | 437 | // r = i*r0^2 438 | let r = constants::SQRT_MINUS_ONE * r_0.square(); 439 | // Ns = a(r+1)*(a+d)*(a-d) 440 | let N_s = (r + one) * one_minus_d_sq; 441 | // D = (d*r -a)*(a*r -d) 442 | let D = (c - (d * r)) * (r + d); 443 | // s = sqrt(Ns/D) 444 | let (Ns_D_is_sq, mut s) = N_s.sqrt_ratio_i(&D); 445 | 446 | //s' = -ABS(s*r0) 447 | let mut s_prim = &s * r_0; 448 | s_prim.conditional_negate(s_prim.is_positive()); 449 | 450 | s.conditional_assign(&s_prim, !Ns_D_is_sq); 451 | c.conditional_assign(&r, !Ns_D_is_sq); 452 | // Nt = c(r-1)*(d-1)^2 - D 453 | let N_t = ((c * (r - one)) * (d - one).square()) - D; 454 | let s_square = s.square(); 455 | 456 | // Get the `CompletePoint` coordinates. 457 | let W0 = (s + s) * D; 458 | let W1 = N_t * constants::SQRT_AD_MINUS_ONE; 459 | let W2 = one - s_square; 460 | let W3 = one + s_square; 461 | 462 | // Get the `EdwardsPoint` that comes from the 463 | // `CompletePoint` obtained by the original 464 | // algorithm. 465 | RistrettoPoint(EdwardsPoint { 466 | X: W0 * W3, 467 | Y: W2 * W1, 468 | Z: W1 * W3, 469 | T: W0 * W2, 470 | }) 471 | } 472 | 473 | /// Debugging function used to get the 4coset where a point 474 | /// lives. 475 | pub(self) fn coset4(&self) -> [EdwardsPoint; 4] { 476 | self.0.coset4() 477 | } 478 | 479 | /// Construct a `RistrettoPoint` from 64 bytes of data. 480 | /// 481 | /// If the input bytes are uniformly distributed, the resulting 482 | /// point will be uniformly distributed over the group, and its 483 | /// discrete log with respect to other points should be unknown. 484 | /// 485 | /// # Implementation 486 | /// 487 | /// This function splits the input array into two 32-byte halves, 488 | /// takes the low 255 bits of each half mod p, applies the 489 | /// Ristretto-flavored Elligator map to each, and adds the results. 490 | /// 491 | /// This function is taken from the Ristretto255 implementation found 492 | /// in [curve25519-dalek](https://github.com/dalek-cryptography/curve25519-dalek/blob/cf03d39f0fc3e1c625b9f1e9be0473758b324526/src/ristretto.rs#L713) 493 | pub fn from_uniform_bytes(bytes: &[u8; 64]) -> RistrettoPoint { 494 | let mut r_1_bytes = [0u8; 32]; 495 | r_1_bytes.copy_from_slice(&bytes[0..32]); 496 | let r_1 = FieldElement::from_bytes(&r_1_bytes); 497 | let R_1 = RistrettoPoint::elligator_ristretto_flavor(&r_1); 498 | 499 | let mut r_2_bytes = [0u8; 32]; 500 | r_2_bytes.copy_from_slice(&bytes[32..64]); 501 | let r_2 = FieldElement::from_bytes(&r_2_bytes); 502 | let R_2 = RistrettoPoint::elligator_ristretto_flavor(&r_2); 503 | 504 | // Applying Elligator twice and adding the results ensures a 505 | // uniform distribution. 506 | R_1 + R_2 507 | } 508 | 509 | /// Generate a random `RistrettoPoint` from a 64-byte array generated 510 | /// with user-provided rng. 511 | /// 512 | /// The provided `rng` has to implement: `Rng` + `CryptoRng`. 513 | /// 514 | /// This function uses the elligator hash map twice, once for [0..31] & 515 | /// another for [32..64] giving a uniformly distributed random value. 516 | /// 517 | /// This implementation follows the idea pointed on the 518 | /// random point generation used in [curve25519-dalek](https://github.com/dalek-cryptography/curve25519-dalek). 519 | pub fn new_random_point(rand: &mut T) -> RistrettoPoint { 520 | let mut bytes = [0u8; 64]; 521 | rand.try_fill(&mut bytes).unwrap(); 522 | RistrettoPoint::from_uniform_bytes(&bytes) 523 | } 524 | } 525 | 526 | #[cfg(test)] 527 | mod tests { 528 | use super::*; 529 | 530 | #[cfg(feature = "rand")] 531 | use rand::rngs::OsRng; 532 | 533 | #[test] 534 | fn basepoint_compr_decompr() { 535 | let compress = RistrettoPoint(constants::BASEPOINT).compress(); 536 | 537 | let decompress = compress.decompress().unwrap(); 538 | assert!(decompress == RistrettoPoint(constants::BASEPOINT)); 539 | } 540 | 541 | #[test] 542 | fn valid_encoding_test_vectors() { 543 | // The following are the byte encodings of small multiples 544 | // [0]B, [1]B, ..., [15]B 545 | // of the basepoint, represented as hex strings. 546 | let encodings_of_small_multiples = [ 547 | // This is the identity point 548 | "0000000000000000000000000000000000000000000000000000000000000000", 549 | // This is the basepoint 550 | "0200000000000000000000000000000000000000000000000000000000000000", 551 | // These are small multiples of the basepoint 552 | "abe4ea98eaaeda5a9c63879cb3c4d9b4a01ed31ac383acefd7ed49861e1a8002", 553 | "1064fe35b16525f90f1d2f7d3dc448ba31a118f136c53eed88c2e951f1832907", 554 | "a826cf66461dea21e51187dddd8753299b726a7d4217cb75758aefbf5a2d4f01", 555 | "4d2e0705a9b47d122f98bd74808d386cf1691bc5407af703dd0c4808038b7f07", 556 | "f3a3592fde5fa05a881b80b4e732b37c32c7f684a5be33cdb8b7bdaf53db6f04", 557 | "51626c7960da63010efc5e064e62962f158f59928914fc108257ec2653745e01", 558 | "d5f8144c1b04954291785be578633a79131752e82afb990bd4a25b41cbd49001", 559 | "1372ed81add54633970746cd4b38ceb8a3e538b916288ac3d7c0dfbd54a42b06", 560 | "a83d7a262a80926724a0beb75a5f26e9a622205e6a64730e14ce64c4b2acf704", 561 | "a6b2712a6e586ab552f7bcf438168304b8b8a3f3b2852a06ae183e6303406503", 562 | "7876266b939b889c1da827a76da5c220eb1ff934472d35de60c9e4c3528fcc06", 563 | "11a0f75ab351572b572c38bf073b076aa964cdff70d53ad7588174dae2729306", 564 | "64f2fb80b45fbf73793e9e8e509f98848ecdb452c98c83c55c5c31fb233d9907", 565 | "1de5afbe9fd279f1651306d8ac0f68f0cb2689609ccfe8db1636f9481a33e205", 566 | ]; 567 | 568 | // Test the encodings of small multiples 569 | 570 | let B = constants::RISTRETTO_BASEPOINT; 571 | let mut P = RistrettoPoint::identity(); 572 | for i in 0..16 { 573 | assert_eq!( 574 | hex::encode(P.compress().as_bytes()), 575 | encodings_of_small_multiples[i], 576 | ); 577 | P = P + B; 578 | } 579 | } 580 | 581 | #[test] 582 | fn decompress_id() { 583 | use crate::edwards::CompressedEdwardsY; 584 | 585 | let compressed_id = CompressedRistretto::identity(); 586 | let id = compressed_id.decompress().unwrap(); 587 | let mut identity_in_coset = false; 588 | for P in &id.0.coset4() { 589 | if P.compress() == CompressedEdwardsY::identity() { 590 | identity_in_coset = true; 591 | } 592 | } 593 | assert!(identity_in_coset); 594 | } 595 | 596 | #[test] 597 | fn four_torsion_diff() { 598 | use crate::edwards::{mul_by_pow_2, CompressedEdwardsY}; 599 | 600 | let bp_compr_decompr = constants::RISTRETTO_BASEPOINT 601 | .compress() 602 | .decompress() 603 | .unwrap() 604 | .0; 605 | 606 | // Check that bp_compr_decompr differs from the 607 | // original RistrettoBasepoint by a point of order 4. 608 | let point_order_4 = &constants::RISTRETTO_BASEPOINT.0 - &bp_compr_decompr; 609 | 610 | let verif = mul_by_pow_2(&point_order_4, 2); 611 | assert_eq!(verif.compress(), CompressedEdwardsY::identity()); 612 | } 613 | 614 | #[cfg(feature = "rand")] 615 | #[test] 616 | fn four_torsion_diff_random() { 617 | let mut rng = OsRng::new().unwrap(); 618 | let B = &constants::RISTRETTO_BASEPOINT; 619 | let P = B * &Scalar::random(&mut rng); 620 | let P_coset = P.coset4(); 621 | for i in 0..4 { 622 | assert_eq!(P, RistrettoPoint(P_coset[i])); 623 | } 624 | 625 | // Check that P_compr_decompr differs from the 626 | // original P by a point of order 4 627 | let P_compr_decompr = P.compress().decompress().unwrap(); 628 | let point_order_4 = &P + &-P_compr_decompr; 629 | assert!(mul_by_pow_2(&point_order_4, &2) == RistrettoPoint::identity()) 630 | } 631 | 632 | #[test] 633 | fn four_coset_eq_basepoint() { 634 | let basepoint = constants::RISTRETTO_BASEPOINT; 635 | let basep_coset = basepoint.coset4(); 636 | 637 | for coset_point in &basep_coset { 638 | assert!(RistrettoPoint(*coset_point) == basepoint); 639 | } 640 | } 641 | 642 | #[test] 643 | fn validity_check() { 644 | // RISTRETTO_BASEPOINT should be valid. 645 | assert!(constants::RISTRETTO_BASEPOINT.is_valid().unwrap_u8() == 1u8); 646 | // The identity and multiples of the basepoint should also be valid. 647 | let mut P = RistrettoPoint::identity(); 648 | let basep = constants::RISTRETTO_BASEPOINT; 649 | for _i in 0..16 { 650 | assert!(P.is_valid().unwrap_u8() == 1u8); 651 | P = P + basep; 652 | } 653 | 654 | // This point has order `8L` is a valid `EdwardsPoint` 655 | // but it's not a valid `RistrettoPoint`. 656 | let y_coord_bytes_8L = FieldElement::from_bytes(&[ 657 | 177, 118, 250, 81, 30, 181, 58, 122, 224, 214, 112, 52, 50, 60, 95, 199, 213, 167, 143, 658 | 108, 154, 218, 242, 27, 175, 111, 152, 152, 213, 211, 157, 15, 659 | ]); 660 | let point_8L = 661 | EdwardsPoint::new_from_y_coord(&y_coord_bytes_8L, Choice::from(0u8)).unwrap(); 662 | assert!(point_8L.is_valid().unwrap_u8() == 1u8); 663 | assert!(RistrettoPoint(point_8L).is_valid().unwrap_u8() == 0u8); 664 | } 665 | 666 | #[cfg(feature = "rand")] 667 | #[test] 668 | fn random_point_validity() { 669 | let mut rng = OsRng::new().unwrap(); 670 | for i in 0..100 { 671 | let P = RistrettoPoint::new_random_point(&mut rng); 672 | // Check that the resulting `EdwardsPoint` relies on the curve. 673 | assert!(P.0.is_valid().unwrap_u8() == 1u8); 674 | P.compress().decompress(); 675 | } 676 | } 677 | 678 | #[test] 679 | fn elligator_vs_ristretto_sage() { 680 | // This test uses the Sage script `ristretto.sage` located in the 681 | // `curve25519-dalek` repository in order to get test vectors of the 682 | // ristretto_elligator algorithm. 683 | let expected_point = RistrettoPoint(EdwardsPoint { 684 | X: FieldElement([ 685 | 520984263488427, 686 | 2866053035698784, 687 | 356812350072736, 688 | 1177086814167286, 689 | 17585355348321, 690 | ]), 691 | Y: FieldElement([ 692 | 2224110940152212, 693 | 767723869121786, 694 | 2519083920383090, 695 | 3478258567033985, 696 | 6072297619626, 697 | ]), 698 | Z: FieldElement([1, 0, 0, 0, 0]), 699 | T: FieldElement([ 700 | 3761248848988017, 701 | 3474827148739807, 702 | 3137090891116602, 703 | 1521420215868592, 704 | 8052069914602, 705 | ]), 706 | }); 707 | assert!(expected_point.is_valid().unwrap_u8() == 1u8); 708 | 709 | let raw_bytes = 710 | hex::decode("2e2d7c6f887c81c1593f32e2fa31a7b65d4fbbf38f8ab3045ead22fc45743219") 711 | .unwrap(); 712 | let mut bytes = [0u8; 32]; 713 | bytes.copy_from_slice(&raw_bytes); 714 | let point_from_ellig = 715 | RistrettoPoint::elligator_ristretto_flavor(&FieldElement::from_bytes(&bytes)); 716 | 717 | assert!(point_from_ellig.0.is_valid().unwrap_u8() == 1u8); 718 | assert!(point_from_ellig == expected_point); 719 | assert!(point_from_ellig.compress() == expected_point.compress()) 720 | } 721 | } 722 | -------------------------------------------------------------------------------- /src/scalar.rs: -------------------------------------------------------------------------------- 1 | //! A `Scalar` represents an element of the finite field 2 | //! modulo `2^249 - 15145038707218910765482344729778085401`. 3 | //! 4 | //! The `Scalar` type is an alias for one of the backend 5 | //! implementations. 6 | //! 7 | //! `ConstantTimeEq` and `PartialEq` traits have been implemented 8 | //! here since they will be the samme across all of the different 9 | //! backends. 10 | //! 11 | //! Here it is also defined the `Ristretto255Scalar` type, 12 | //! which is a type-alias for the curve25519-dalek Scalar Struct. 13 | //! 14 | //! # Examples 15 | //! ```rust 16 | //! use zerocaf::scalar::Scalar; 17 | //! use zerocaf::traits::ops::*; 18 | //! 19 | //! // You can create a Scalar from a byte-array as follows: 20 | //! let a = Scalar::from_bytes(&[0u8;32]); 21 | //! 22 | //! // You ca also create a Scalar from an uint type as follows: 23 | //! let b = Scalar::from(43325u128); 24 | //! let c = Scalar::from(86650u64); 25 | //! 26 | //! // The last way of creating a Scalar it by calling the 27 | //! // constructor. THIS IS NOT RECOMMENDED since ANY checks about 28 | //! // the correctness of the input will be done. It can be done as 29 | //! // follows: 30 | //! let d: Scalar = Scalar([0, 1, 0, 0, 0]); // d = 2^52. 31 | //! assert!(d == Scalar::two_pow_k(52u64)); 32 | //! 33 | //! // All of the basuc modular operations are implemented 34 | //! // for Scalar type: 35 | //! let mut res = a + b; // Performs a + b (mod l). 36 | //! res = a - b; // Performs a - b (mod l). 37 | //! res = c * d; // Performs c * d (mod l). 38 | //! res = a.square(); // Performs a^2 (mod l). 39 | //! res = -&a; // Performs Negation over the modulo l. 40 | //! 41 | //! // Dividing even Scalars by two is recommended through the `Half` 42 | //! // trait implmementation since it's much faster. 43 | //! if a.is_even() { 44 | //! let half_c = c.half(); // This will panic if a isn't even. 45 | //! assert!(half_c == b); 46 | //! } 47 | //! 48 | //! // You can export your `Scalar` as an slice of 32 bytes in Little 49 | //! // Endian encoding by: 50 | //! let d_bytes: [u8; 32] = d.to_bytes(); 51 | //! ``` 52 | //! 53 | //! 54 | //! 55 | //! `PartialOrd`, `Ord`, `PartialEq` and `Eq` are also implemented for 56 | //! `Scalar` type. 57 | //! 58 | //! All `std::core::ops traits -> (Add, Sub, Mul)` are implemented 59 | //! for both, `&Scalar` and `Scalar`. 60 | 61 | use crate::backend; 62 | 63 | use subtle::Choice; 64 | use subtle::ConstantTimeEq; 65 | 66 | use rand::{CryptoRng, Rng}; 67 | 68 | #[cfg(feature = "u64_backend")] 69 | pub use backend::u64::scalar::*; 70 | /// A `Scalar` represents an element of the field generated by 71 | /// the prime of the sub-group: `2^249 - 15145038707218910765482344729778085401`. 72 | /// 73 | /// This is a type alias for one of the Scalar types in the `backend` 74 | /// module. 75 | #[cfg(feature = "u64_backend")] 76 | pub type Scalar = backend::u64::scalar::Scalar; 77 | 78 | impl PartialEq for Scalar { 79 | fn eq(&self, other: &Scalar) -> bool { 80 | self.ct_eq(other).unwrap_u8() == 1u8 81 | } 82 | } 83 | 84 | impl ConstantTimeEq for Scalar { 85 | /// Test equality between two `Scalar`s. Since the 86 | /// internal representation is not canonical, the field elements 87 | /// are normalized to wire format before comparison. 88 | fn ct_eq(&self, other: &Scalar) -> Choice { 89 | self.to_bytes().ct_eq(&other.to_bytes()) 90 | } 91 | } 92 | 93 | impl Eq for Scalar {} 94 | 95 | impl Scalar { 96 | /// Generate a valid Scalar choosen uniformly using user- 97 | /// provided rng. 98 | /// 99 | /// By `rng` we mean any Rng that implements: `Rng` + `CryptoRng`. 100 | pub fn random(rand: &mut T) -> Scalar 101 | where 102 | T: Rng + CryptoRng, 103 | { 104 | let mut bytes = [0u8; 32]; 105 | rand.fill_bytes(&mut bytes); 106 | // Ensure that the value is lower than `L`. 107 | bytes[31] &= 0b0000_0001; 108 | Scalar::from_bytes(&bytes) 109 | } 110 | } 111 | 112 | /// This is a type alias for the Scalar type in the `curve25519-dalek` lib. 113 | pub type Ristretto255Scalar = curve25519_dalek::scalar::Scalar; 114 | -------------------------------------------------------------------------------- /src/traits.rs: -------------------------------------------------------------------------------- 1 | //! Module for Public Trait implementations. 2 | 3 | use subtle::Choice; 4 | 5 | /// Gives the Identity element for the 6 | /// type which it has been implemented on. 7 | /// 8 | /// This trait is implemented following the rules that 9 | /// mandate over the Type that is being implemented. 10 | pub trait Identity { 11 | #[must_use] 12 | /// Returns the identity element for the implemented 13 | /// type, following it's mathematical rules. 14 | fn identity() -> Self; 15 | } 16 | 17 | /// This trait pretends to be a verification in ct_time 18 | /// about a point correctness. 19 | /// 20 | /// This is done through checking that the (X, Y) coordinates 21 | /// of the point are valid and satisfy the curve equation. 22 | pub trait ValidityCheck { 23 | #[must_use] 24 | /// Checks the point coordinates agains the curve equation 25 | /// to validate that the point relies on the curve and its 26 | /// valid. 27 | /// 28 | /// # Returns 29 | /// - `Choice(0)` if the point isn't a valid point. 30 | /// - `Choice(1)` if the point is valid. 31 | fn is_valid(&self) -> Choice; 32 | } 33 | 34 | pub mod ops { 35 | use super::*; 36 | 37 | /// Trait that represents the `^2` operation for any 38 | /// kind of element on the library. 39 | /// 40 | /// This trait is implemented following the rules that 41 | /// mandate over the Type that is being implemented. 42 | pub trait Square { 43 | type Output; 44 | 45 | #[must_use] 46 | /// Returns the square of the input: `x^2`. 47 | fn square(self) -> Self::Output; 48 | } 49 | 50 | /// Trait that represents the Point doubling operation 51 | /// for any type of Point that is used on the lib. 52 | /// 53 | /// This trait is implemented following the rules that 54 | /// mandate over the Type that is being implemented. 55 | pub trait Double { 56 | type Output; 57 | 58 | #[must_use] 59 | /// Performs the point-doubling operation over the 60 | /// coordinates which this trait has been implemented 61 | /// for. 62 | fn double(self) -> Self::Output; 63 | } 64 | 65 | /// Trait that represents the `/2` operation for any 66 | /// kind of element on the library. 67 | /// 68 | /// This is a more performant way of performing the 69 | /// division by 2 that dividing by 2 with the `Div` 70 | /// trait implementation. 71 | /// 72 | /// This trait is implemented following the rules that 73 | /// mandate over the Type that is being implemented. 74 | pub trait Half { 75 | type Output; 76 | 77 | #[must_use] 78 | /// Returns the half of the input: `x/2`. 79 | fn half(self) -> Self::Output; 80 | } 81 | 82 | /// Trait that represents the modular exponentiation 83 | /// operation, ie.`a ^ b (mod l)`, for any 84 | /// kind of element on the library (except points). 85 | /// 86 | /// This trait is implemented following the rules that 87 | /// mandate over the Type that is being implemented. 88 | pub trait Pow { 89 | type Output; 90 | 91 | #[must_use] 92 | /// Returns `a^b (mod l)`. 93 | fn pow(self, exp: T) -> Self::Output; 94 | } 95 | 96 | pub trait ModSqrt { 97 | type Output; 98 | 99 | #[must_use] 100 | /// Performs the modular Square Root operation over a finite 101 | /// field ie. `sqrt(x) (mod l)`. 102 | /// 103 | /// With the given `Choice`, the impl is able to provide the 104 | /// result that corresponds to the positive or negative sign choosen. 105 | /// 106 | /// # Returns 107 | /// 108 | /// `Some(symb_choosen_result)` if the input is a QR for the prime modulo. 109 | /// Otherways it returns `None` 110 | fn mod_sqrt(self, choice: Choice) -> Self::Output; 111 | } 112 | 113 | pub trait InvSqrt { 114 | type Output; 115 | 116 | #[must_use] 117 | /// Performs the Inverse Square root of a given value. 118 | /// 119 | /// This operation returns always the positive result of the 120 | /// modular sqrt, understanding positive as the definition that 121 | /// appears on the Decaf paper: 0 < result < (P - 1)/2. 122 | fn inv_sqrt(self) -> Self::Output; 123 | } 124 | 125 | pub trait SqrtRatioI { 126 | type Output; 127 | 128 | #[must_use] 129 | /// Using the same trick as in ed25519 decoding, we merge the 130 | /// inversion, the square root, and the square test.AsMut 131 | /// 132 | /// The first part of the return value signals whether u/v was square, 133 | /// and the second part contains a square root. 134 | /// Specifically, it returns: 135 | /// 136 | ///- (true, +sqrt(u/v)) if v is nonzero and u/v is square; 137 | ///- (true, zero) if u is zero; 138 | ///- (false, zero) if v is zero and uuu is nonzero; 139 | ///- (false, +sqrt(i*u/v)) if u/v is nonsquare (so iu/v is square). 140 | fn sqrt_ratio_i(&self, v: T) -> Self::Output; 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /tools/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "param_translator" 3 | version = "0.1.0" 4 | authors = ["CPerez19 "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | num-bigint = "0.2.2" 9 | num = "0.2.0" 10 | num-traits = "0.2.6" -------------------------------------------------------------------------------- /tools/kalinski_inv.py: -------------------------------------------------------------------------------- 1 | 2 | import math 3 | 4 | def random_prime(bound): 5 | warnings.simplefilter('ignore') 6 | chck = False 7 | while chck == False: 8 | p = random.randrange(bound>>1, bound) 9 | chck = pyprimes.isprime(p) 10 | warnings.simplefilter('default') 11 | return p 12 | 13 | def fieldElement(a): 14 | f0 = a % pow(2,52) 15 | a = a / pow(2,52) 16 | f1 = a % pow(2,52) 17 | a = a / pow(2,52) 18 | f2 = a % pow(2,52) 19 | a = a / pow(2,52) 20 | f3 = a % pow(2,52) 21 | a = a / pow(2,52) 22 | f4 = a % pow(2,52) 23 | arr = [f0, f1, f2, f3, f4] 24 | return '[' + ', '.join([str(x) for x in arr]) + ']' 25 | 26 | 27 | def AlmostMontInv(x, p): 28 | u = p 29 | v = x 30 | r = 0 31 | s = 1 32 | k = 0 33 | while (v>0): 34 | if (u%2 == 0): 35 | u = u >> 1 36 | s = s << 1 37 | elif (v%2 == 0): 38 | v = v >> 1 39 | r = r << 1 40 | elif u > v: 41 | u = (u-v) >> 1 42 | r = r+s 43 | s = s << 1 44 | else: 45 | v = (v-u) >> 1 46 | s = r+s 47 | r = r << 1 48 | k += 1 49 | #print('Values on iteration: ' + str(k) + ':') 50 | #print('r = ' + str(fieldElement(r))) 51 | #print('s = ' + str(fieldElement(s))) 52 | #print('v = ' + str(fieldElement(v))) 53 | #print('u = ' + str(fieldElement(u))) 54 | 55 | if r>p: 56 | r = r-p 57 | 58 | return p-r, k 59 | 60 | 61 | def phase2(r, k): 62 | for i in range(0, k-253): 63 | if (r % 2 == 0): 64 | r = (r >> 1) % p 65 | else: 66 | r = (r+p) >> 1 67 | #print('r on iter: ' + str(i) + '= ' + str(r)) 68 | print('iter: ' + str(i) + ': FieldElement(' + fieldElement(r) + ')') 69 | return r 70 | 71 | # random.seed(11) # for debug 72 | 73 | p = 7237005577332262213973186563042994240857116359379907606001950938285454250989 74 | 75 | # Input to change value to get the AlmostMontInv. 76 | a = 904625697166532776746648320197686575422163851717637391703244652875051672039 77 | 78 | ainv, k = AlmostMontInv(a, p) 79 | print('r:FieldElement' + str(fieldElement(ainv))) 80 | print('r:FieldElement' + str(ainv)) 81 | print('k:' + str(k)) 82 | print('p:' + str(fieldElement(p))) 83 | ainv = phase2(ainv, k) 84 | 85 | print(ainv, k) 86 | print('ainv:FieldElement' + str(fieldElement(ainv))) 87 | -------------------------------------------------------------------------------- /tools/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate num_bigint; 2 | extern crate num; 3 | 4 | use num_bigint::BigUint; 5 | use num::{Zero, One, Integer, Num}; 6 | use std::str::FromStr; 7 | use num_traits::cast::ToPrimitive; 8 | use num_traits::pow; 9 | use core::fmt::Debug; 10 | 11 | 12 | 13 | fn main() { 14 | /*Examples of function calls 15 | num_from_bytes_le(&[76, 250, 187, 243, 105, 92, 117, 70, 234, 124, 126, 180, 87, 149, 62, 249, 16, 149, 138, 56, 26, 87, 14, 76, 251, 39, 168, 74, 176, 202, 26, 84]); 16 | 17 | let res = to_field_elem_51(&"1201935917638644956968126114584555454358623906841733991436515590915937358637"); 18 | println!("{:?}", res); 19 | 20 | let scalar_res = to_scalar_base_52(&"1201935917638644956968126114584555454358623906841733991436515590915937358637"); 21 | println!("{:?}", res); 22 | 23 | hex_bytes_le("120193591763864495696812611458455545435862390684173399143651559091593735863735685683568356835683"); 24 | from_radix_to_radix_10("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", 16u32); 25 | 26 | let m = BigUint::from_str("750791094644726559640638407699").unwrap(); 27 | let x1 = BigUint::from_str("540019781128412936473322405310").unwrap(); 28 | let x2 = BigUint::from_str("515692107665463680305819378593").unwrap(); 29 | 30 | reduction(m, x1, x2).unwrap(); 31 | 32 | 33 | let x = to_scalar_base_52("1809251394333065553493296640760748560207343510400633813116524750123642650623"); 34 | println!("R: {:?}", x); 35 | let y = to_scalar_base_52("6145104759870991071742105800796537629880401874866217824609283457819451087098"); 36 | println!("R: {:?}", y); 37 | let x_y_mont = to_scalar_base_52("532695731852302855127194384594826090862673352940952884676179882511233227548"); 38 | println!("R: {:?}", x_y_mont); 39 | let x_y = to_scalar_base_52("890263784947025690345271110799906008759402458672628420828189878638015362081"); 40 | println!("R: {:?}", x_y); 41 | let mont_x = to_scalar_base_52("658448296334113745583381664921721413881518248721417041768778176391714104386"); 42 | println!("{:?}", mont_x); 43 | */ 44 | 45 | let a = to_scalar_base_52("452312848583266388373324160190187140059081152887999797648174285421238281266"); 46 | println!("{:?}", a); 47 | 48 | let a = to_scalar_base_52("452312848583266388373324160190187140051835877600158453279131187530910662656"); 49 | println!("{:?}", a); 50 | } 51 | 52 | /// The num has to be positive! Otherways it will fail 53 | pub fn hex_bytes_le(num: &str) { 54 | let num: BigUint = BigUint::from_str(num).unwrap(); 55 | println!("Encoding result -> {:x?}", num.to_bytes_le()); 56 | } 57 | 58 | /// Prints a number in radix 10 given a reference of a slice of Little Endian bytes of it. 59 | pub fn num_from_bytes_le(num: &[u8]){ 60 | println!("{}", BigUint::from_bytes_le(num)); 61 | } 62 | 63 | /// Changes a number from radix X to radix 10 64 | pub fn from_radix_to_radix_10(num: &str, radix: u32) { 65 | println!("{}",BigUint::from_str_radix(num, radix).unwrap()); 66 | } 67 | 68 | /// Gets a number as a &str and encodes it like a FieldElement51 representation of zerocaf repo. 69 | pub fn to_field_elem_51(num: &str) -> [u64; 5] { 70 | let mut resp_as_array = [0u64;5]; 71 | let mut response = vec!(); 72 | let two_pow_51 = BigUint::from_str("2251799813685248").unwrap(); 73 | let mut num = BigUint::from_str(num).unwrap(); 74 | 75 | for _i in 0..5 { 76 | response.push(&num % &two_pow_51); 77 | num = &num / &two_pow_51; 78 | } 79 | 80 | let mut res2: Vec = response.iter().map(|x| u64::from_str(&x.to_str_radix(10u32)).unwrap()).collect(); 81 | resp_as_array.swap_with_slice(&mut res2); 82 | resp_as_array 83 | } 84 | 85 | /// Gets a number as a &str and encodes it like a Scalar representation of zerocaf repo. 86 | pub fn to_scalar_base_52(num: &str) -> [u64; 5] { 87 | let mut resp_as_array = [0u64;5]; 88 | let mut response = vec!(); 89 | let two_pow_52 = BigUint::from_str("4503599627370496").unwrap(); 90 | let mut num = BigUint::from_str(num).unwrap(); 91 | 92 | for _i in 0..5 { 93 | response.push(&num % &two_pow_52); 94 | num = &num / &two_pow_52; 95 | } 96 | 97 | let mut res2: Vec = response.iter().map(|x| u64::from_str(&x.to_str_radix(10u32)).unwrap()).collect(); 98 | resp_as_array.swap_with_slice(&mut res2); 99 | resp_as_array 100 | } 101 | 102 | /// Gets a Scalar in base 52 and transforms it into a normal representation 103 | pub fn from_scalar_base_52(limbs: &[u64; 5]) -> () { 104 | let mut res: BigUint = BigUint::zero(); 105 | let two_pow_52 = BigUint::from_str("4503599627370496").unwrap(); 106 | for i in 0..5 { 107 | res = res + (pow(two_pow_52.clone(), i) * limbs[i]); 108 | } 109 | println!("{}", res) 110 | } 111 | 112 | /// Gets a FieldElement in base 51 and transforms it into a normal representation 113 | pub fn from_field_elem_base_51(limbs: &[u64; 5]) -> () { 114 | let mut res: BigUint = BigUint::zero(); 115 | let two_pow_51 = BigUint::from_str("2251799813685248").unwrap(); 116 | for i in 0..5 { 117 | res = res + (pow(two_pow_51.clone(), i) * limbs[i]); 118 | } 119 | println!("{}", res) 120 | } 121 | 122 | /// Montgomery struct 123 | #[derive(Debug)] 124 | pub struct Montgomery { 125 | pub BASE: BigUint, 126 | pub m: BigUint, 127 | pub rrm: BigUint, 128 | pub n: i32 129 | } 130 | 131 | impl Montgomery { 132 | pub fn new(m: BigUint) -> Result { 133 | if m < BigUint::zero() || m.is_even() { 134 | Err("Invalid input!") 135 | } else { 136 | let mont = Montgomery { 137 | BASE: BigUint::from(2u32), 138 | m: m.clone(), 139 | n: m.bits() as i32, 140 | rrm: (BigUint::one() << (m.bits() * 2)) % m 141 | }; 142 | return Ok(mont) 143 | } 144 | } 145 | 146 | pub fn reduce(&self, prop: BigUint) -> BigUint { 147 | let mut a: BigUint = prop.clone(); 148 | for i in 0..self.n { 149 | if !a.is_even() {a+=self.m.clone()} 150 | a = a.clone() >> 1; 151 | } 152 | if a >= self.m {a -= self.m.clone()} 153 | a 154 | } 155 | } 156 | 157 | pub fn reduction(m: BigUint, x1: BigUint, x2: BigUint) -> Result<(), &'static str> { 158 | let mont = Montgomery::new(m.clone()).unwrap(); 159 | let t1 = x1.clone() * mont.rrm.clone(); 160 | let t2 = x2.clone() * mont.rrm.clone(); 161 | 162 | let r1 = mont.reduce(t1.clone()); 163 | let r2 = mont.reduce(t2.clone()); 164 | 165 | let r = BigUint::one() << mont.n.clone() as usize; 166 | println!("b = {}\n", mont.BASE); 167 | println!("n = {}\n", mont.n); 168 | println!("r = {}\n", r); 169 | println!("m = {}\n", m); 170 | println!("t1 = {}\n", t1); 171 | println!("t2 = {}\n", t2); 172 | println!("r1 = {}\n", r1); 173 | println!("r2 = {}\n", r2); 174 | println!("Original x1: {}\n", x1.clone()); 175 | println!("Recovered from r1: {}\n", mont.reduce(r1.clone())); 176 | println!("Original x2: {}\n", x2.clone()); 177 | println!("Recovered from r2: {}\n", mont.reduce(r2.clone())); 178 | println!("Montgomery computation of x1 ^ x2 mod m :"); 179 | let prod = x1.modpow(&x2, &mont.m); 180 | 181 | println!("{}\n", prod); 182 | 183 | Ok(()) 184 | } 185 | 186 | pub fn phase1(input: &BigUint) -> BigUint { 187 | let p = BigUint::from_str("7237005577332262213973186563042994240832148273380272487819684194273658967345").unwrap(); 188 | let mut u = p.clone(); 189 | let mut v = input.clone(); 190 | let mut r = BigUint::zero(); 191 | let mut s = BigUint::one(); 192 | let two = &s + &s; 193 | let mut k: u64 = 0; 194 | while v > BigUint::zero() { 195 | 196 | match(u.is_even(), v.is_even(), u > v, v >= u) { 197 | // u is even 198 | (true, _, _, _) => { 199 | 200 | u = &u / &two; 201 | s = (&s * &two); 202 | }, 203 | // u isn't even but v is even 204 | (false, true, _, _) => { 205 | 206 | v = &v / &two; 207 | r = (&r * &two); 208 | }, 209 | // u and v aren't even and u > v 210 | (false, false, true, _) => { 211 | 212 | u = (&u - &v); 213 | u = &u / &two; 214 | r = (&r + &s); 215 | s = (&s * &two); 216 | }, 217 | // u and v aren't even and v > u 218 | (false, false, false, true) => { 219 | 220 | v = (&v - &u); 221 | v = &v / &two; 222 | s = (&r + &s); 223 | r = (&r * &two); 224 | }, 225 | (false, false, false, false) => panic!("InverseMod does not exist"), 226 | } 227 | k+=1; 228 | println!("Values on iteration: {}: \nr = {:?}\ns = {:?}\nv = {:?}\nu = {:?}", k, to_scalar_base_52(&r.to_str_radix(10)), to_scalar_base_52(&s.to_str_radix(10)),to_scalar_base_52(&v.to_str_radix(10)),to_scalar_base_52(&u.to_str_radix(10))); 229 | } 230 | if r >= p { 231 | println!("Inside if: {:?}", to_scalar_base_52(&(&r - &p).to_str_radix(10))); 232 | r = &r - &p; 233 | } 234 | println!("Outside if: {}", (&p - &r)); 235 | &p - &r 236 | } 237 | 238 | 239 | pub struct EdwardsPoint { 240 | pub X: [u64; 5], 241 | pub Y: [u64; 5], 242 | pub Z: [u64; 5], 243 | pub T: [u64; 5] 244 | } 245 | 246 | impl Debug for EdwardsPoint { 247 | fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { 248 | write!(f, " 249 | EdwardsPoint {{ 250 | X: FieldElement({:?}), 251 | Y: FieldElement({:?}), 252 | Z: FieldElement({:?}), 253 | T: FieldElement({:?}) 254 | }};", self.X, self.Y, self.Z, self.T) 255 | } 256 | } 257 | 258 | 259 | 260 | impl EdwardsPoint { 261 | 262 | pub fn new(x: &str, y: &str, z: &str, t: &str) -> EdwardsPoint { 263 | 264 | let mut res: EdwardsPoint = EdwardsPoint{ 265 | X: [0u64; 5], 266 | Y: [0u64; 5], 267 | Z: [0u64; 5], 268 | T: [0u64; 5] 269 | }; 270 | res.X = to_scalar_base_52(x); 271 | res.Y = to_scalar_base_52(y); 272 | res.Z = to_scalar_base_52(z); 273 | res.T = to_scalar_base_52(t); 274 | 275 | res 276 | } 277 | } 278 | -------------------------------------------------------------------------------- /tools/tonelli.py: -------------------------------------------------------------------------------- 1 | def legendre_symbol(a, p): 2 | """ 3 | Legendre symbol 4 | Define if a is a quadratic residue modulo odd prime 5 | http://en.wikipedia.org/wiki/Legendre_symbol 6 | """ 7 | ls = pow(a, (p - 1)/2, p) 8 | if ls == p - 1: 9 | return -1 10 | return ls 11 | 12 | 13 | def prime_mod_sqrt(a, p): 14 | """ 15 | Square root modulo prime number 16 | Solve the equation 17 | x^2 = a mod p 18 | and return list of x solution 19 | http://en.wikipedia.org/wiki/Tonelli-Shanks_algorithm 20 | """ 21 | a %= p 22 | 23 | # Simple case 24 | if a == 0: 25 | return [0] 26 | if p == 2: 27 | return [a] 28 | 29 | # Check solution existence on odd prime 30 | if legendre_symbol(a, p) != 1: 31 | return [] 32 | 33 | # Simple case 34 | if p % 4 == 3: 35 | x = pow(a, (p + 1)/4, p) 36 | return [x, p-x] 37 | 38 | # Factor p-1 on the form q * 2^s (with Q odd) 39 | q, s = p - 1, 0 40 | while q % 2 == 0: 41 | s += 1 42 | q //= 2 43 | 44 | # Select a z which is a quadratic non resudue modulo p 45 | z = 1 46 | while legendre_symbol(z, p) != -1: 47 | z += 1 48 | c = pow(z, q, p) 49 | 50 | # Search for a solution 51 | x = pow(a, (q + 1)/2, p) 52 | t = pow(a, q, p) 53 | m = s 54 | while t != 1: 55 | # Find the lowest i such that t^(2^i) = 1 56 | i, e = 0, 2 57 | for i in xrange(1, m): 58 | if pow(t, e, p) == 1: 59 | break 60 | e *= 2 61 | 62 | # Update next value to iterate 63 | b = pow(c, 2**(m - i - 1), p) 64 | x = (x * b) % p 65 | t = (t * b * b) % p 66 | c = (b * b) % p 67 | m = i 68 | 69 | return [x, p-x] 70 | 71 | y = 39450438318983875225554878125429420291626370862048309987484807859947766635845 72 | l = 7237005577332262213973186563042994240857116359379907606001950938285454250989 73 | 74 | print(prime_mod_sqrt(y,l)) 75 | --------------------------------------------------------------------------------