├── .github └── workflows │ └── rust.yml ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── examples ├── basic.rs ├── cli.rs ├── generate_secp256k1.rs └── secp256k1.json └── src ├── dummy.rs ├── lib.rs └── openssl ├── mod.rs └── utils.rs /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | 14 | build: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v1 18 | - uses: actions-rs/toolchain@v1 19 | with: 20 | profile: minimal 21 | toolchain: stable 22 | override: true 23 | - name: Build 24 | run: cargo build --verbose 25 | 26 | rustfmt: 27 | name: rustfmt 28 | runs-on: ubuntu-latest 29 | steps: 30 | - uses: actions/checkout@v2 31 | - uses: actions-rs/toolchain@v1 32 | with: 33 | toolchain: stable 34 | override: true 35 | profile: minimal 36 | components: rustfmt 37 | - name: Check formatting 38 | run: cargo fmt -- --check 39 | 40 | clippy: 41 | runs-on: ubuntu-latest 42 | steps: 43 | - uses: actions/checkout@v2 44 | - uses: actions-rs/toolchain@v1 45 | with: 46 | toolchain: stable 47 | components: clippy 48 | override: true 49 | - uses: actions-rs/clippy-check@v1 50 | with: 51 | token: ${{ secrets.GITHUB_TOKEN }} 52 | args: --all-features -- -D warnings 53 | - name: Run clippy 54 | run: cargo clippy --all-features -- -D warnings 55 | 56 | test: 57 | runs-on: ubuntu-latest 58 | steps: 59 | - uses: actions/checkout@v2 60 | - uses: actions-rs/toolchain@v1 61 | with: 62 | profile: minimal 63 | toolchain: stable 64 | override: true 65 | - name: Build tests 66 | run: cargo test --verbose --no-run 67 | - name: Run tests 68 | run: cargo test --verbose --no-fail-fast -- --test-threads=1 69 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | /.idea -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vrf" 3 | version = "0.2.4" 4 | description = "Fast and extensible Verifiable Random Function (VRF) library; currently supporting secp256k1, secp256r1 and sect163k1 curves" 5 | keywords = ["vrf", "ecvrf", "secp256k1", "p256", "k163"] 6 | categories = ["algorithms", "cryptography"] 7 | license = "MIT" 8 | authors = ["Witnet Foundation "] 9 | edition = "2018" 10 | homepage = "https://github.com/witnet/vrf-rs" 11 | documentation = "https://docs.rs/vrf/" 12 | repository = "https://github.com/witnet/vrf-rs" 13 | readme = "README.md" 14 | exclude = ["/.travis.yml"] 15 | 16 | [badges] 17 | travis-ci = { repository = "witnet/vrf-rs", branch = "master" } 18 | 19 | [dependencies] 20 | failure = "0.1.8" 21 | openssl = "0.10.38" 22 | hmac-sha256 = "1.1.2" 23 | 24 | [dev-dependencies] 25 | clap = "2.32.0" 26 | hex = "0.3.2" 27 | serde = { version = "1.0.90", features = ["derive"] } 28 | serde_json = "1.0.39" 29 | 30 | [features] 31 | vendored = ["openssl/vendored"] 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Witnet Foundation 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 all 13 | 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 THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vrf-rs 2 | [![](https://img.shields.io/crates/v/vrf.svg)](https://crates.io/crates/vrf) [![](https://docs.rs/vrf/badge.svg)](https://docs.rs/vrf) [![](https://github.com/witnet/vrf-rs/actions/workflows/rust.yml/badge.svg)](https://github.com/witnet/vrf-rs/actions/workflows/rust.yml) 3 | 4 | `vrf-rs` is an open source implementation of Verifiable Random Functions (VRFs) written in Rust. 5 | 6 | _DISCLAIMER: This is experimental software. Be careful!_ 7 | 8 | The library can be built using `cargo` and the examples can be executed with: 9 | 10 | ```bash 11 | cargo build 12 | cargo run --example 13 | ``` 14 | 15 | ## Elliptic Curve VRF 16 | 17 | This module uses the OpenSSL library to offer Elliptic Curve Verifiable Random Function (VRF) functionality. 18 | 19 | It follows the algorithms described in: 20 | 21 | * [VRF-draft-05](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05) 22 | * [RFC6979](https://tools.ietf.org/html/rfc6979) 23 | 24 | Currently the supported cipher suites are: 25 | 26 | * `P256_SHA256_TAI`: the aforementioned algorithms with `SHA256` and the `secp256r1` curve (aka `NIST P-256`). 27 | * `K163_SHA256_TAI`: the aforementioned algorithms with `SHA256` and the `sect163k1` curve (aka `NIST K-163`). 28 | * `SECP256K1_SHA256_TAI`: the aforementioned algorithms with `SHA256` and the `secp256k1` curve. 29 | 30 | ### Example 31 | 32 | Create and verify a VRF proof by using the cipher suite `SECP256K1_SHA256_TAI`: 33 | 34 | ```rust 35 | use vrf::openssl::{CipherSuite, ECVRF}; 36 | use vrf::VRF; 37 | 38 | fn main() { 39 | // Initialization of VRF context by providing a curve 40 | let mut vrf = ECVRF::from_suite(CipherSuite::SECP256K1_SHA256_TAI).unwrap(); 41 | // Inputs: Secret Key, Public Key (derived) & Message 42 | let secret_key = 43 | hex::decode("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721").unwrap(); 44 | let public_key = vrf.derive_public_key(&secret_key).unwrap(); 45 | let message: &[u8] = b"sample"; 46 | 47 | // VRF proof and hash output 48 | let pi = vrf.prove(&secret_key, &message).unwrap(); 49 | let hash = vrf.proof_to_hash(&pi).unwrap(); 50 | 51 | // VRF proof verification (returns VRF hash output) 52 | let beta = vrf.verify(&public_key, &pi, &message); 53 | } 54 | ``` 55 | 56 | A complete example can be found in [examples/basic.rs](https://github.com/witnet/vrf-rs/blob/master/examples/basic.rs). It can be executed with: 57 | 58 | ```bash 59 | cargo run --example basic 60 | ``` 61 | 62 | ## Adding unsupported cipher suites 63 | 64 | This library defines a `VRF` trait which can be extended in order to use different curves and algorithms. 65 | 66 | ```rust 67 | pub trait VRF { 68 | type Error; 69 | 70 | fn prove(&mut self, x: SecretKey, alpha: &[u8]) -> Result, Self::Error>; 71 | 72 | fn verify(&mut self, y: PublicKey, pi: &[u8], alpha: &[u8]) -> Result, Self::Error>; 73 | } 74 | ``` 75 | 76 | ## License 77 | 78 | `vrf-rs` is published under the [MIT license][license]. 79 | 80 | [license]: https://github.com/witnet/vrf-rs/blob/master/LICENSE -------------------------------------------------------------------------------- /examples/basic.rs: -------------------------------------------------------------------------------- 1 | //! # Basic example 2 | //! 3 | //! This example shows a basic usage of the `vrf-rs` crate: 4 | //! 5 | //! 1. Instantiate the `ECVRF` by specifying the `CipherSuite` 6 | //! 2. Generate a VRF proof by using the `prove()` function 7 | //! 3. (Optional) Convert the VRF proof to a hash (e.g. to be used as pseudo-random value) 8 | //! 4. Verify a VRF proof by using `verify()` function 9 | 10 | use vrf::openssl::{CipherSuite, ECVRF}; 11 | use vrf::VRF; 12 | 13 | fn main() { 14 | let mut vrf = ECVRF::from_suite(CipherSuite::SECP256K1_SHA256_TAI).unwrap(); 15 | // Inputs: Secret Key, Public Key (derived) & Message 16 | let secret_key = 17 | hex::decode("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721").unwrap(); 18 | let public_key = vrf.derive_public_key(&secret_key).unwrap(); 19 | let message: &[u8] = b"sample"; 20 | 21 | // VRF proof and hash output 22 | let pi = vrf.prove(&secret_key, &message).unwrap(); 23 | let hash = vrf.proof_to_hash(&pi).unwrap(); 24 | println!("Generated VRF proof: {}", hex::encode(&pi)); 25 | 26 | // VRF proof verification (returns VRF hash output) 27 | let beta = vrf.verify(&public_key, &pi, &message); 28 | 29 | match beta { 30 | Ok(beta) => { 31 | println!("VRF proof is valid!\nHash output: {}", hex::encode(&beta)); 32 | assert_eq!(hash, beta); 33 | } 34 | Err(e) => { 35 | println!("VRF proof is not valid: {}", e); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /examples/cli.rs: -------------------------------------------------------------------------------- 1 | //! # Client example 2 | //! 3 | //! This example shows a command line client usage of the `vrf-rs` crate: 4 | //! 5 | //! 1. Instantiate the `ECVRF` by specifying the `CipherSuite` 6 | //! 2. Generate a VRF proof by using the `prove()` function 7 | //! 3. (Optional) Convert the VRF proof to a hash (e.g. to be used as pseudo-random value) 8 | //! 4. Verify a VRF proof by using `verify()` function 9 | 10 | use hex; 11 | use vrf::openssl::{CipherSuite, ECVRF}; 12 | use vrf::VRF; 13 | 14 | #[macro_use] 15 | extern crate clap; 16 | 17 | macro_rules! gen_validator { 18 | ($name:ident : $type:ty) => { 19 | gen_validator!($name, str::parse::<$type>); 20 | }; 21 | ($name:ident, $expr:expr) => { 22 | fn $name(obj: String) -> Result<(), String> { 23 | $expr(&obj).map(drop).map_err(|x| format!("{}", x)) 24 | } 25 | }; 26 | } 27 | gen_validator!(is_hex_ok, hex::decode); 28 | 29 | fn main() { 30 | let matches = clap_app!(vrf => 31 | (version: crate_version!()) 32 | (author: "Vixify Network") 33 | (about: "Client to Verifiable Random Functions") 34 | (@arg VERBOSE: -v --verbose "Log verbosely to stderr. This command does not currently log anything, so this option currently has no affect.") 35 | (@arg SECRET_KEY: +required {is_hex_ok} "Secret key to be used to print or validate proof" ) 36 | (@arg MESSAGE: +required "Message to be used to print or validate proof." ) 37 | (@arg PROOF: {is_hex_ok} "Optional VRF Proof to be validated. If missing, proof is printed for secret and message." ) 38 | ) 39 | .get_matches(); 40 | 41 | let mut vrf = ECVRF::from_suite(CipherSuite::SECP256K1_SHA256_TAI).unwrap(); 42 | // Inputs: Secret Key, Public Key (derived) & Message 43 | let secret_key = hex::decode(&matches.value_of("SECRET_KEY").unwrap()).unwrap(); 44 | let public_key = vrf.derive_public_key(&secret_key).unwrap(); 45 | let message = &matches.value_of("MESSAGE").unwrap().as_bytes(); 46 | 47 | let mut pi = vrf.prove(&secret_key, &message).unwrap(); 48 | let hash = vrf.proof_to_hash(&pi).unwrap(); 49 | 50 | // VRF proof and hash output 51 | let proof_given = matches.value_of("PROOF") != None; 52 | if proof_given { 53 | pi = hex::decode(&matches.value_of("PROOF").unwrap()).unwrap(); 54 | } else { 55 | println!("{}", hex::encode(&pi)); 56 | } 57 | 58 | let beta = vrf.verify(&public_key, &pi, &message); 59 | 60 | if proof_given { 61 | match beta { 62 | Ok(beta) => { 63 | println!("VRF proof is valid!"); 64 | assert_eq!(hash, beta); 65 | } 66 | Err(_e) => { 67 | println!("VRF proof is not valid!"); 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /examples/generate_secp256k1.rs: -------------------------------------------------------------------------------- 1 | //! # Generate `Secp256k1` VRF test vectors 2 | //! 3 | //! This example generates VRF proofs (using the ciphersuite `SECP256K1_SHA256_TAI`) 4 | //! and writes them into a JSON file (`vrf.json`). 5 | //! 6 | //! The input data (in `secp256k1.json` file) is extracted from the 7 | //! [Chuck Batson Secp256k1 test vectors](https://chuckbatson.wordpress.com/2014/11/26/secp256k1-test-vectors/). 8 | //! 9 | //! This example expects uses a file with a JSON array with objects with the following keys: 10 | //! 11 | //! - `k`: private key 12 | //! - `x`: coordinate `x` of public key 13 | //! - `y`: coordinate `y` of public key 14 | //! 15 | //! This example outputs a JSON file with test vectors with the following keys: 16 | //! 17 | //! - `priv`: private key 18 | //! - `pub`: compressed public key 19 | //! - `message`: message used for VRF 20 | //! - `pi`: computed VRF proof 21 | 22 | use std::fs::File; 23 | use std::io::{BufWriter, Write}; 24 | 25 | use openssl::bn::BigNum; 26 | use serde_json::{json, Value}; 27 | 28 | use vrf::openssl::{CipherSuite, ECVRF}; 29 | use vrf::VRF; 30 | 31 | fn to_hex_string(bytes: Vec) -> String { 32 | bytes 33 | .iter() 34 | .fold(String::from("0x"), |acc, x| format!("{}{:02x}", acc, x)) 35 | } 36 | 37 | fn main() { 38 | let mut vrf = ECVRF::from_suite(CipherSuite::SECP256K1_SHA256_TAI).expect("VRF should init"); 39 | 40 | // VRF inputs extracted from `Secp256k1` test vectors + `sample` message 41 | let file = File::open("./examples/secp256k1.json").expect("File should open read only"); 42 | let json: Value = serde_json::from_reader(file).expect("File should be proper JSON"); 43 | let inputs = json.as_array().expect("File should have priv key"); 44 | let message: &[u8] = b"sample"; 45 | 46 | // VRF outputs 47 | let outputs: Vec = inputs 48 | .iter() 49 | .map(|val| { 50 | // Private key as input 51 | let secret_key_str = val.get("k").unwrap().as_str().unwrap(); 52 | let secret_key = BigNum::from_dec_str(secret_key_str).unwrap().to_vec(); 53 | // Derive public key 54 | let public_key = vrf.derive_public_key(&secret_key).unwrap(); 55 | // VRF proof 56 | let pi = vrf.prove(&secret_key, &message).unwrap(); 57 | // VRF proof to hash 58 | let hash = vrf.proof_to_hash(&pi).unwrap(); 59 | 60 | json!({ 61 | "priv": val.get("k"), 62 | "pub": to_hex_string(public_key), 63 | "message": to_hex_string(message.to_vec()), 64 | "pi": to_hex_string(pi), 65 | "hash": to_hex_string(hash) 66 | }) 67 | }) 68 | .collect(); 69 | 70 | // Write results into file `vrf.json` 71 | let f = File::create("./vrf.json").expect("Unable to create file"); 72 | serde_json::to_writer_pretty(BufWriter::new(f).by_ref(), &json!(outputs)).unwrap(); 73 | } 74 | -------------------------------------------------------------------------------- /examples/secp256k1.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "k": "1", 4 | "x": "0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 5 | "y": "0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8" 6 | }, 7 | { 8 | "k": "2", 9 | "x": "0xC6047F9441ED7D6D3045406E95C07CD85C778E4B8CEF3CA7ABAC09B95C709EE5", 10 | "y": "0x1AE168FEA63DC339A3C58419466CEAEEF7F632653266D0E1236431A950CFE52A" 11 | }, 12 | { 13 | "k": "3", 14 | "x": "0xF9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9", 15 | "y": "0x388F7B0F632DE8140FE337E62A37F3566500A99934C2231B6CB9FD7584B8E672" 16 | }, 17 | { 18 | "k": "4", 19 | "x": "0xE493DBF1C10D80F3581E4904930B1404CC6C13900EE0758474FA94ABE8C4CD13", 20 | "y": "0x51ED993EA0D455B75642E2098EA51448D967AE33BFBDFE40CFE97BDC47739922" 21 | }, 22 | { 23 | "k": "5", 24 | "x": "0x2F8BDE4D1A07209355B4A7250A5C5128E88B84BDDC619AB7CBA8D569B240EFE4", 25 | "y": "D8AC222636E5E3D6D4DBA9DDA6C9C426F788271BAB0D6840DCA87D3AA6AC62D6" 26 | }, 27 | { 28 | "k": "6", 29 | "x": "FFF97BD5755EEEA420453A14355235D382F6472F8568A18B2F057A1460297556", 30 | "y": "AE12777AACFBB620F3BE96017F45C560DE80F0F6518FE4A03C870C36B075F297" 31 | }, 32 | { 33 | "k": "7", 34 | "x": "5CBDF0646E5DB4EAA398F365F2EA7A0E3D419B7E0330E39CE92BDDEDCAC4F9BC", 35 | "y": "6AEBCA40BA255960A3178D6D861A54DBA813D0B813FDE7B5A5082628087264DA" 36 | }, 37 | { 38 | "k": "8", 39 | "x": "2F01E5E15CCA351DAFF3843FB70F3C2F0A1BDD05E5AF888A67784EF3E10A2A01", 40 | "y": "5C4DA8A741539949293D082A132D13B4C2E213D6BA5B7617B5DA2CB76CBDE904" 41 | }, 42 | { 43 | "k": "9", 44 | "x": "ACD484E2F0C7F65309AD178A9F559ABDE09796974C57E714C35F110DFC27CCBE", 45 | "y": "CC338921B0A7D9FD64380971763B61E9ADD888A4375F8E0F05CC262AC64F9C37" 46 | }, 47 | { 48 | "k": "10", 49 | "x": "A0434D9E47F3C86235477C7B1AE6AE5D3442D49B1943C2B752A68E2A47E247C7", 50 | "y": "893ABA425419BC27A3B6C7E693A24C696F794C2ED877A1593CBEE53B037368D7" 51 | }, 52 | { 53 | "k": "11", 54 | "x": "774AE7F858A9411E5EF4246B70C65AAC5649980BE5C17891BBEC17895DA008CB", 55 | "y": "D984A032EB6B5E190243DD56D7B7B365372DB1E2DFF9D6A8301D74C9C953C61B" 56 | }, 57 | { 58 | "k": "12", 59 | "x": "D01115D548E7561B15C38F004D734633687CF4419620095BC5B0F47070AFE85A", 60 | "y": "A9F34FFDC815E0D7A8B64537E17BD81579238C5DD9A86D526B051B13F4062327" 61 | }, 62 | { 63 | "k": "13", 64 | "x": "F28773C2D975288BC7D1D205C3748651B075FBC6610E58CDDEEDDF8F19405AA8", 65 | "y": "0AB0902E8D880A89758212EB65CDAF473A1A06DA521FA91F29B5CB52DB03ED81" 66 | }, 67 | { 68 | "k": "14", 69 | "x": "499FDF9E895E719CFD64E67F07D38E3226AA7B63678949E6E49B241A60E823E4", 70 | "y": "CAC2F6C4B54E855190F044E4A7B3D464464279C27A3F95BCC65F40D403A13F5B" 71 | }, 72 | { 73 | "k": "15", 74 | "x": "D7924D4F7D43EA965A465AE3095FF41131E5946F3C85F79E44ADBCF8E27E080E", 75 | "y": "581E2872A86C72A683842EC228CC6DEFEA40AF2BD896D3A5C504DC9FF6A26B58" 76 | }, 77 | { 78 | "k": "16", 79 | "x": "E60FCE93B59E9EC53011AABC21C23E97B2A31369B87A5AE9C44EE89E2A6DEC0A", 80 | "y": "F7E3507399E595929DB99F34F57937101296891E44D23F0BE1F32CCE69616821" 81 | }, 82 | { 83 | "k": "17", 84 | "x": "DEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34", 85 | "y": "4211AB0694635168E997B0EAD2A93DAECED1F4A04A95C0F6CFB199F69E56EB77" 86 | }, 87 | { 88 | "k": "18", 89 | "x": "5601570CB47F238D2B0286DB4A990FA0F3BA28D1A319F5E7CF55C2A2444DA7CC", 90 | "y": "C136C1DC0CBEB930E9E298043589351D81D8E0BC736AE2A1F5192E5E8B061D58" 91 | }, 92 | { 93 | "k": "19", 94 | "x": "2B4EA0A797A443D293EF5CFF444F4979F06ACFEBD7E86D277475656138385B6C", 95 | "y": "85E89BC037945D93B343083B5A1C86131A01F60C50269763B570C854E5C09B7A" 96 | }, 97 | { 98 | "k": "20", 99 | "x": "4CE119C96E2FA357200B559B2F7DD5A5F02D5290AFF74B03F3E471B273211C97", 100 | "y": "12BA26DCB10EC1625DA61FA10A844C676162948271D96967450288EE9233DC3A" 101 | }, 102 | { 103 | "k": "112233445566778899", 104 | "x": "A90CC3D3F3E146DAADFC74CA1372207CB4B725AE708CEF713A98EDD73D99EF29", 105 | "y": "5A79D6B289610C68BC3B47F3D72F9788A26A06868B4D8E433E1E2AD76FB7DC76" 106 | }, 107 | { 108 | "k": "112233445566778899112233445566778899", 109 | "x": "E5A2636BCFD412EBF36EC45B19BFB68A1BC5F8632E678132B885F7DF99C5E9B3", 110 | "y": "736C1CE161AE27B405CAFD2A7520370153C2C861AC51D6C1D5985D9606B45F39" 111 | }, 112 | { 113 | "k": "28948022309329048855892746252171976963209391069768726095651290785379540373584", 114 | "x": "A6B594B38FB3E77C6EDF78161FADE2041F4E09FD8497DB776E546C41567FEB3C", 115 | "y": "71444009192228730CD8237A490FEBA2AFE3D27D7CC1136BC97E439D13330D55" 116 | }, 117 | { 118 | "k": "57896044618658097711785492504343953926418782139537452191302581570759080747168", 119 | "x": "00000000000000000000003B78CE563F89A0ED9414F5AA28AD0D96D6795F9C63", 120 | "y": "3F3979BF72AE8202983DC989AEC7F2FF2ED91BDD69CE02FC0700CA100E59DDF3" 121 | }, 122 | { 123 | "k": "86844066927987146567678238756515930889628173209306178286953872356138621120752", 124 | "x": "E24CE4BEEE294AA6350FAA67512B99D388693AE4E7F53D19882A6EA169FC1CE1", 125 | "y": "8B71E83545FC2B5872589F99D948C03108D36797C4DE363EBD3FF6A9E1A95B10" 126 | }, 127 | { 128 | "k": "115792089237316195423570985008687907852837564279074904382605163141518161494317", 129 | "x": "4CE119C96E2FA357200B559B2F7DD5A5F02D5290AFF74B03F3E471B273211C97", 130 | "y": "ED45D9234EF13E9DA259E05EF57BB3989E9D6B7D8E269698BAFD77106DCC1FF5" 131 | }, 132 | { 133 | "k": "115792089237316195423570985008687907852837564279074904382605163141518161494318", 134 | "x": "2B4EA0A797A443D293EF5CFF444F4979F06ACFEBD7E86D277475656138385B6C", 135 | "y": "7A17643FC86BA26C4CBCF7C4A5E379ECE5FE09F3AFD9689C4A8F37AA1A3F60B5" 136 | }, 137 | { 138 | "k": "115792089237316195423570985008687907852837564279074904382605163141518161494319", 139 | "x": "5601570CB47F238D2B0286DB4A990FA0F3BA28D1A319F5E7CF55C2A2444DA7CC", 140 | "y": "3EC93E23F34146CF161D67FBCA76CAE27E271F438C951D5E0AE6D1A074F9DED7" 141 | }, 142 | { 143 | "k": "115792089237316195423570985008687907852837564279074904382605163141518161494320", 144 | "x": "DEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34", 145 | "y": "BDEE54F96B9CAE9716684F152D56C251312E0B5FB56A3F09304E660861A910B8" 146 | }, 147 | { 148 | "k": "115792089237316195423570985008687907852837564279074904382605163141518161494321", 149 | "x": "E60FCE93B59E9EC53011AABC21C23E97B2A31369B87A5AE9C44EE89E2A6DEC0A", 150 | "y": "081CAF8C661A6A6D624660CB0A86C8EFED6976E1BB2DC0F41E0CD330969E940E" 151 | }, 152 | { 153 | "k": "115792089237316195423570985008687907852837564279074904382605163141518161494322", 154 | "x": "D7924D4F7D43EA965A465AE3095FF41131E5946F3C85F79E44ADBCF8E27E080E", 155 | "y": "A7E1D78D57938D597C7BD13DD733921015BF50D427692C5A3AFB235F095D90D7" 156 | }, 157 | { 158 | "k": "115792089237316195423570985008687907852837564279074904382605163141518161494323", 159 | "x": "499FDF9E895E719CFD64E67F07D38E3226AA7B63678949E6E49B241A60E823E4", 160 | "y": "353D093B4AB17AAE6F0FBB1B584C2B9BB9BD863D85C06A4339A0BF2AFC5EBCD4" 161 | }, 162 | { 163 | "k": "115792089237316195423570985008687907852837564279074904382605163141518161494324", 164 | "x": "F28773C2D975288BC7D1D205C3748651B075FBC6610E58CDDEEDDF8F19405AA8", 165 | "y": "F54F6FD17277F5768A7DED149A3250B8C5E5F925ADE056E0D64A34AC24FC0EAE" 166 | }, 167 | { 168 | "k": "115792089237316195423570985008687907852837564279074904382605163141518161494325", 169 | "x": "D01115D548E7561B15C38F004D734633687CF4419620095BC5B0F47070AFE85A", 170 | "y": "560CB00237EA1F285749BAC81E8427EA86DC73A2265792AD94FAE4EB0BF9D908" 171 | }, 172 | { 173 | "k": "115792089237316195423570985008687907852837564279074904382605163141518161494326", 174 | "x": "774AE7F858A9411E5EF4246B70C65AAC5649980BE5C17891BBEC17895DA008CB", 175 | "y": "267B5FCD1494A1E6FDBC22A928484C9AC8D24E1D20062957CFE28B3536AC3614" 176 | }, 177 | { 178 | "k": "115792089237316195423570985008687907852837564279074904382605163141518161494327", 179 | "x": "A0434D9E47F3C86235477C7B1AE6AE5D3442D49B1943C2B752A68E2A47E247C7", 180 | "y": "76C545BDABE643D85C4938196C5DB3969086B3D127885EA6C3411AC3FC8C9358" 181 | }, 182 | { 183 | "k": "115792089237316195423570985008687907852837564279074904382605163141518161494328", 184 | "x": "ACD484E2F0C7F65309AD178A9F559ABDE09796974C57E714C35F110DFC27CCBE", 185 | "y": "33CC76DE4F5826029BC7F68E89C49E165227775BC8A071F0FA33D9D439B05FF8" 186 | }, 187 | { 188 | "k": "115792089237316195423570985008687907852837564279074904382605163141518161494329", 189 | "x": "2F01E5E15CCA351DAFF3843FB70F3C2F0A1BDD05E5AF888A67784EF3E10A2A01", 190 | "y": "A3B25758BEAC66B6D6C2F7D5ECD2EC4B3D1DEC2945A489E84A25D3479342132B" 191 | }, 192 | { 193 | "k": "115792089237316195423570985008687907852837564279074904382605163141518161494330", 194 | "x": "5CBDF0646E5DB4EAA398F365F2EA7A0E3D419B7E0330E39CE92BDDEDCAC4F9BC", 195 | "y": "951435BF45DAA69F5CE8729279E5AB2457EC2F47EC02184A5AF7D9D6F78D9755" 196 | }, 197 | { 198 | "k": "115792089237316195423570985008687907852837564279074904382605163141518161494331", 199 | "x": "FFF97BD5755EEEA420453A14355235D382F6472F8568A18B2F057A1460297556", 200 | "y": "51ED8885530449DF0C4169FE80BA3A9F217F0F09AE701B5FC378F3C84F8A0998" 201 | }, 202 | { 203 | "k": "115792089237316195423570985008687907852837564279074904382605163141518161494332", 204 | "x": "2F8BDE4D1A07209355B4A7250A5C5128E88B84BDDC619AB7CBA8D569B240EFE4", 205 | "y": "2753DDD9C91A1C292B24562259363BD90877D8E454F297BF235782C459539959" 206 | }, 207 | { 208 | "k": "115792089237316195423570985008687907852837564279074904382605163141518161494333", 209 | "x": "E493DBF1C10D80F3581E4904930B1404CC6C13900EE0758474FA94ABE8C4CD13", 210 | "y": "AE1266C15F2BAA48A9BD1DF6715AEBB7269851CC404201BF30168422B88C630D" 211 | }, 212 | { 213 | "k": "115792089237316195423570985008687907852837564279074904382605163141518161494334", 214 | "x": "F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9", 215 | "y": "C77084F09CD217EBF01CC819D5C80CA99AFF5666CB3DDCE4934602897B4715BD" 216 | }, 217 | { 218 | "k": "115792089237316195423570985008687907852837564279074904382605163141518161494335", 219 | "x": "C6047F9441ED7D6D3045406E95C07CD85C778E4B8CEF3CA7ABAC09B95C709EE5", 220 | "y": "E51E970159C23CC65C3A7BE6B99315110809CD9ACD992F1EDC9BCE55AF301705" 221 | }, 222 | { 223 | "k": "115792089237316195423570985008687907852837564279074904382605163141518161494336", 224 | "x": "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 225 | "y": "B7C52588D95C3B9AA25B0403F1EEF75702E84BB7597AABE663B82F6F04EF2777" 226 | } 227 | ] 228 | -------------------------------------------------------------------------------- /src/dummy.rs: -------------------------------------------------------------------------------- 1 | //! Sample module implementing a __dummy__ (to be used as example) Verifiable Random Function (VRF) 2 | use crate::VRF; 3 | use failure::Error; 4 | 5 | pub struct DummyVRF; 6 | 7 | /// The size (in bytes) of a secret key 8 | pub const SECRET_KEY_SIZE: usize = 32; 9 | 10 | /// The size (in bytes) of a serialized public key. 11 | pub const PUBLIC_KEY_SIZE: usize = 33; 12 | 13 | /// The type of the secret key 14 | pub type SecretKey<'a> = &'a [u8; SECRET_KEY_SIZE]; 15 | 16 | /// The type of the public key 17 | pub type PublicKey<'a> = &'a [u8; PUBLIC_KEY_SIZE]; 18 | 19 | impl<'a> VRF, SecretKey<'a>> for DummyVRF { 20 | type Error = Error; 21 | 22 | // Generate proof from key pair and message 23 | fn prove(&mut self, _x: SecretKey, _alpha: &[u8]) -> Result, Self::Error> { 24 | Ok(vec![]) 25 | } 26 | 27 | // Verify proof given public key, proof and message 28 | fn verify(&mut self, _y: PublicKey, _pi: &[u8], _alpha: &[u8]) -> Result, Self::Error> { 29 | Ok(vec![]) 30 | } 31 | } 32 | 33 | #[cfg(test)] 34 | mod test { 35 | use super::*; 36 | 37 | #[test] 38 | fn test_prove() { 39 | let x = [0; 32]; 40 | let alpha = [0, 0, 0]; 41 | 42 | let proof = DummyVRF.prove(&x, &alpha); 43 | assert_eq!(proof.unwrap(), vec![]); 44 | } 45 | 46 | #[test] 47 | fn test_verify() { 48 | let y = [0; 33]; 49 | let pi = [0]; 50 | let alpha = [0, 0, 0]; 51 | 52 | assert_eq!(DummyVRF.verify(&y, &pi, &alpha).unwrap(), vec![]); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! # Verifiable Random Function (VRF) 2 | //! 3 | //! This crate defines the generic contract that must be followed by VRF implementations ([`VRF`](trait.VRF.html) trait). 4 | //! 5 | //! ## Elliptic Curve VRF 6 | //! 7 | //! The [`openssl`](openssl/index.html) module provides an implementation of Elliptic Curve VRF ([`ECVRF`](openssl/struct.ECVRF.html)). 8 | //! 9 | //! It follows the algorithms described in: 10 | //! 11 | //! * [VRF-draft-05](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05) 12 | //! * [RFC6979](https://tools.ietf.org/html/rfc6979) 13 | //! 14 | //! Currently the supported cipher suites are: 15 | //! 16 | //! * `P256_SHA256_TAI`: the aforementioned algorithms with `SHA256` and the `NIST P-256` curve. 17 | //! * `K163_SHA256_TAI`: the aforementioned algorithms with `SHA256` and the `NIST K-163` curve. 18 | //! * `SECP256K1_SHA256_TAI`: the aforementioned algorithms with `SHA256` and the `secp256k1` curve. 19 | pub mod dummy; 20 | pub mod openssl; 21 | 22 | /// A trait containing the common capabilities for all Verifiable Random Functions (VRF) implementations. 23 | pub trait VRF { 24 | type Error; 25 | 26 | /// Generates proof from a secret key and a message. 27 | /// 28 | /// # Arguments 29 | /// 30 | /// * `x` - A secret key. 31 | /// * `alpha` - A slice representing the message in octets. 32 | /// 33 | /// # Returns 34 | /// 35 | /// * If successful, a vector of octets representing the proof of the VRF. 36 | fn prove(&mut self, x: SecretKey, alpha: &[u8]) -> Result, Self::Error>; 37 | 38 | /// Verifies the provided VRF proof and computes the VRF hash output. 39 | /// 40 | /// # Arguments 41 | /// 42 | /// * `y` - A public key. 43 | /// * `pi` - A slice of octets representing the VRF proof. 44 | /// 45 | /// # Returns 46 | /// 47 | /// * If successful, a vector of octets with the VRF hash output. 48 | fn verify(&mut self, y: PublicKey, pi: &[u8], alpha: &[u8]) -> Result, Self::Error>; 49 | } 50 | -------------------------------------------------------------------------------- /src/openssl/mod.rs: -------------------------------------------------------------------------------- 1 | //! Module that uses the OpenSSL library to offer Elliptic Curve Verifiable Random Function (VRF) functionality. 2 | //! This module follows the algorithms described in [VRF-draft-05](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05) and [RFC6979](https://tools.ietf.org/html/rfc6979). 3 | //! 4 | //! In particular, it provides: 5 | //! 6 | //! * `ECVRF_hash_to_curve` as in the `ECVRF_hash_to_curve_try_and_increment` algorithm from [VRF-draft-05](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05) 7 | //! * `ECVRF_nonce_generation` as specified in Section 3.2 of [RFC6979](https://tools.ietf.org/html/rfc6979) 8 | //! 9 | //! Warning: if input data is private, information leaks in the form of timing side channels are possible. 10 | //! 11 | //! Currently the supported cipher suites are: 12 | //! * _P256_SHA256_TAI_: the aforementioned algorithms with `SHA256` and the `NIST P-256` curve. 13 | //! * _K163_SHA256_TAI_: the aforementioned algorithms with `SHA256` and the `NIST K-163` curve. 14 | //! * _SECP256K1_SHA256_TAI_: the aforementioned algorithms with `SHA256` and the `secp256k1` curve. 15 | //! 16 | //! ## Documentation 17 | //! 18 | //! * [VRF-draft-05](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05) 19 | //! * [RFC6979](https://tools.ietf.org/html/rfc6979) 20 | //! * [GitHub repository](https://github.com/witnet/vrf-rs) 21 | //! 22 | //! ## Features 23 | //! 24 | //! * Compute VRF proof 25 | //! * Verify VRF proof 26 | use std::fmt; 27 | use std::{ 28 | fmt::{Debug, Formatter}, 29 | os::raw::c_ulong, 30 | }; 31 | 32 | use failure::Fail; 33 | use hmac_sha256::HMAC; 34 | 35 | use openssl::{ 36 | bn::{BigNum, BigNumContext}, 37 | ec::{EcGroup, EcPoint, PointConversionForm}, 38 | error::ErrorStack, 39 | hash::{hash, MessageDigest}, 40 | nid::Nid, 41 | }; 42 | 43 | use crate::VRF; 44 | 45 | use self::utils::{append_leading_zeros, bits2int, bits2octets}; 46 | 47 | mod utils; 48 | 49 | /// Different cipher suites for different curves/algorithms 50 | #[allow(non_camel_case_types)] 51 | #[derive(Debug)] 52 | pub enum CipherSuite { 53 | /// `NIST P-256` with `SHA256` and `ECVRF_hash_to_curve_try_and_increment` 54 | P256_SHA256_TAI, 55 | /// `Secp256k1` with `SHA256` and `ECVRF_hash_to_curve_try_and_increment` 56 | SECP256K1_SHA256_TAI, 57 | /// `NIST K-163` with `SHA256` and `ECVRF_hash_to_curve_try_and_increment` 58 | K163_SHA256_TAI, 59 | } 60 | 61 | impl CipherSuite { 62 | fn suite_string(&self) -> u8 { 63 | match *self { 64 | CipherSuite::P256_SHA256_TAI => 0x01, 65 | CipherSuite::SECP256K1_SHA256_TAI => 0xFE, 66 | CipherSuite::K163_SHA256_TAI => 0xFF, 67 | } 68 | } 69 | } 70 | 71 | /// Different errors that can be raised when proving/verifying VRFs 72 | #[derive(Debug, Fail)] 73 | pub enum Error { 74 | /// Error raised from `openssl::error::ErrorStack` with a specific code 75 | #[fail(display = "Error with code {}", code)] 76 | CodedError { code: c_ulong }, 77 | /// The `hash_to_point()` function could not find a valid point 78 | #[fail(display = "Hash to point function could not find a valid point")] 79 | HashToPointError, 80 | /// The proof length is invalid 81 | #[fail(display = "The proof length is invalid")] 82 | InvalidPiLength, 83 | /// The proof is invalid 84 | #[fail(display = "The proof is invalid")] 85 | InvalidProof, 86 | /// Unknown error 87 | #[fail(display = "Unknown error")] 88 | Unknown, 89 | } 90 | 91 | impl From for Error { 92 | /// Transforms error from `openssl::error::ErrorStack` to `Error::CodedError` or `Error::Unknown` 93 | fn from(error: ErrorStack) -> Self { 94 | match error.errors().get(0).map(openssl::error::Error::code) { 95 | Some(code) => Error::CodedError { code }, 96 | _ => Error::Unknown {}, 97 | } 98 | } 99 | } 100 | 101 | /// An Elliptic Curve VRF 102 | pub struct ECVRF { 103 | // Bignumber arithmetic context 104 | bn_ctx: BigNumContext, 105 | // Ciphersuite identification 106 | cipher_suite: CipherSuite, 107 | // Cofactor of the curve 108 | cofactor: u8, 109 | // Elliptic curve group 110 | group: EcGroup, 111 | // Hasher structure 112 | hasher: MessageDigest, 113 | // The order of the curve 114 | order: BigNum, 115 | // Length of the order of the curve in bits 116 | qlen: usize, 117 | // 2n = length of a field element in bits rounded up to the nearest even integer 118 | n: usize, 119 | } 120 | 121 | impl Debug for ECVRF { 122 | fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { 123 | fmt.debug_struct("ECVRF") 124 | .field("cipher_suite", &self.cipher_suite) 125 | .field("cofactor", &self.cofactor) 126 | .field("qlen", &self.qlen) 127 | .field("n", &self.n) 128 | .field("order", &self.order) 129 | .finish() 130 | } 131 | } 132 | 133 | impl ECVRF { 134 | /// Factory method for creating a ECVRF structure with a context that is initialized for the provided cipher suite. 135 | /// 136 | /// # Arguments 137 | /// 138 | /// * `suite` - A ciphersuite identifying the curve/algorithms. 139 | /// 140 | /// # Returns 141 | /// 142 | /// * If successful, the ECVRF structure. 143 | pub fn from_suite(suite: CipherSuite) -> Result { 144 | // Context for big number algebra 145 | let mut bn_ctx = BigNumContext::new()?; 146 | 147 | // Elliptic Curve parameters 148 | let (group, cofactor) = match suite { 149 | CipherSuite::P256_SHA256_TAI => { 150 | (EcGroup::from_curve_name(Nid::X9_62_PRIME256V1)?, 0x01) 151 | } 152 | CipherSuite::K163_SHA256_TAI => (EcGroup::from_curve_name(Nid::SECT163K1)?, 0x02), 153 | CipherSuite::SECP256K1_SHA256_TAI => (EcGroup::from_curve_name(Nid::SECP256K1)?, 0x01), 154 | }; 155 | 156 | let mut order = BigNum::new()?; 157 | group.order(&mut order, &mut bn_ctx)?; 158 | let mut a = BigNum::new()?; 159 | let mut b = BigNum::new()?; 160 | let mut p = BigNum::new()?; 161 | group.components_gfp(&mut p, &mut a, &mut b, &mut bn_ctx)?; 162 | let n = ((p.num_bits() + (p.num_bits() % 2)) / 2) as usize; 163 | let qlen = order.num_bits() as usize; 164 | 165 | // Hash algorithm: `SHA256` 166 | // (only `P256_SHA256_TAI`, `K163_SHA256_TAI` and `SECP256K1_SHA256_TAI` are currently supported) 167 | let hasher = MessageDigest::sha256(); 168 | 169 | Ok(ECVRF { 170 | cipher_suite: suite, 171 | group, 172 | bn_ctx, 173 | order, 174 | hasher, 175 | n, 176 | qlen, 177 | cofactor, 178 | }) 179 | } 180 | 181 | /// Function for deriving a public key given a secret key point. 182 | /// Returns an `EcPoint` with the corresponding public key. 183 | /// 184 | /// # Arguments 185 | /// 186 | /// * `secret_key` - A `BigNum` referencing the secret key. 187 | /// 188 | /// # Returns 189 | /// 190 | /// * If successful, an `EcPoint` representing the public key. 191 | fn derive_public_key_point(&mut self, secret_key: &BigNum) -> Result { 192 | let mut point = EcPoint::new(self.group.as_ref())?; 193 | // secret_key = point*generator 194 | point.mul_generator(&self.group, secret_key, &self.bn_ctx)?; 195 | Ok(point) 196 | } 197 | 198 | /// Function for deriving a public key given a secret key point. 199 | /// Returns a vector of octets with the corresponding public key. 200 | /// 201 | /// # Arguments 202 | /// 203 | /// * `secret_key` - A `BigNum` referencing the secret key. 204 | /// 205 | /// # Returns 206 | /// 207 | /// * If successful, a `Vec` representing the public key. 208 | pub fn derive_public_key(&mut self, secret_key: &[u8]) -> Result, Error> { 209 | let secret_key_bn = BigNum::from_slice(secret_key)?; 210 | let point = self.derive_public_key_point(&secret_key_bn)?; 211 | let bytes = point.to_bytes( 212 | &self.group, 213 | PointConversionForm::COMPRESSED, 214 | &mut self.bn_ctx, 215 | )?; 216 | Ok(bytes) 217 | } 218 | 219 | /// Generates a nonce deterministically by following the algorithm described in the [RFC6979](https://tools.ietf.org/html/rfc6979) 220 | /// (section 3.2. __Generation of k__). 221 | /// 222 | /// # Arguments 223 | /// 224 | /// * `secret_key` - A `BigNum` representing the secret key. 225 | /// * `data` - A slice of octets (message). 226 | /// 227 | /// # Returns 228 | /// 229 | /// * If successful, the `BigNum` representing the nonce. 230 | fn generate_nonce(&mut self, secret_key: &BigNum, data: &[u8]) -> Result { 231 | // Bits to octets from data - bits2octets(h1) 232 | // We follow the new VRF-draft-05 in which the input is hashed` 233 | let data_hash = hash(self.hasher, data)?; 234 | 235 | let data_trunc = bits2octets(&data_hash, self.qlen, &self.order, &mut self.bn_ctx)?; 236 | let padded_data_trunc = append_leading_zeros(&data_trunc, self.qlen); 237 | 238 | // Bytes to octets from secret key - int2octects(x) 239 | // Left padding is required for inserting leading zeros 240 | let padded_secret_key_bytes: Vec = 241 | append_leading_zeros(&secret_key.to_vec(), self.qlen); 242 | 243 | // Init `V` & `K` 244 | // `K = HMAC_K(V || 0x00 || int2octects(secret_key) || bits2octects(data))` 245 | let mut v = [0x01; 32]; 246 | let mut k = [0x00; 32]; 247 | 248 | // First 2 rounds defined by specification 249 | for prefix in 0..2u8 { 250 | k = HMAC::mac( 251 | [ 252 | &v[..], 253 | &[prefix], 254 | &padded_secret_key_bytes[..], 255 | &padded_data_trunc[..], 256 | ] 257 | .concat() 258 | .as_slice(), 259 | &k, 260 | ); 261 | v = HMAC::mac(&v, &k); 262 | } 263 | 264 | // Loop until valid `BigNum` extracted from `V` is found 265 | loop { 266 | v = HMAC::mac(&v, &k); 267 | let ret_bn = bits2int(&v, self.qlen)?; 268 | 269 | if ret_bn > BigNum::from_u32(0)? && ret_bn < self.order { 270 | return Ok(ret_bn); 271 | } 272 | k = HMAC::mac([&v[..], &[0x00]].concat().as_slice(), &k); 273 | v = HMAC::mac(&v, &k); 274 | } 275 | } 276 | 277 | /// Function to convert a `Hash(PK|DATA)` to a point in the curve as stated in [VRF-draft-05](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05) 278 | /// (section 5.4.1.1). 279 | /// 280 | /// # Arguments 281 | /// 282 | /// * `public_key` - An `EcPoint` referencing the public key. 283 | /// * `alpha` - A slice containing the input data. 284 | /// 285 | /// # Returns 286 | /// 287 | /// * If successful, an `EcPoint` representing the hashed point. 288 | fn hash_to_try_and_increment( 289 | &mut self, 290 | public_key: &EcPoint, 291 | alpha: &[u8], 292 | ) -> Result { 293 | let mut c = 0..255; 294 | let pk_bytes = public_key.to_bytes( 295 | &self.group, 296 | PointConversionForm::COMPRESSED, 297 | &mut self.bn_ctx, 298 | )?; 299 | let cipher = [self.cipher_suite.suite_string(), 0x01]; 300 | let mut v = [&cipher[..], &pk_bytes[..], alpha, &[0x00]].concat(); 301 | let position = v.len() - 1; 302 | // `Hash(cipher||PK||data)` 303 | let mut point = c.find_map(|ctr| { 304 | v[position] = ctr; 305 | let attempted_hash = hash(self.hasher, &v); 306 | // Check validity of `H` 307 | match attempted_hash { 308 | Ok(attempted_hash) => self.arbitrary_string_to_point(&attempted_hash).ok(), 309 | _ => None, 310 | } 311 | }); 312 | 313 | if let Some(pt) = point.as_mut() { 314 | let mut new_pt = EcPoint::new(self.group.as_ref())?; 315 | new_pt.mul( 316 | self.group.as_ref(), 317 | pt, 318 | BigNum::from_slice(&[self.cofactor])?.as_ref(), 319 | &self.bn_ctx, 320 | )?; 321 | *pt = new_pt; 322 | } 323 | // Return error if no valid point was found 324 | point.ok_or(Error::HashToPointError) 325 | } 326 | 327 | /// Function to convert an arbitrary string to a point in the curve as specified in VRF-draft-05 328 | /// (section 5.5). 329 | /// 330 | /// # Arguments 331 | /// 332 | /// * `data` - A slice representing the data to be converted to a point. 333 | /// 334 | /// # Returns 335 | /// 336 | /// * If successful, an `EcPoint` representing the converted point. 337 | fn arbitrary_string_to_point(&mut self, data: &[u8]) -> Result { 338 | let mut v = vec![0x02]; 339 | v.extend(data); 340 | let point = EcPoint::from_bytes(&self.group, &v, &mut self.bn_ctx)?; 341 | Ok(point) 342 | } 343 | 344 | /// Function to hash a certain set of points as specified in [VRF-draft-05](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05) 345 | /// (section 5.4.3). 346 | /// 347 | /// # Arguments 348 | /// 349 | /// * `points` - A reference to an array containing the points that need to be hashed. 350 | /// 351 | /// # Returns 352 | /// 353 | /// * If successful, a `BigNum` representing the hash of the points, truncated to length `n`. 354 | fn hash_points(&mut self, points: &[&EcPoint]) -> Result { 355 | // point_bytes = [P1||P2||...||Pn] 356 | let point_bytes: Result, Error> = points.iter().try_fold( 357 | vec![self.cipher_suite.suite_string(), 0x02], 358 | |mut acc, point| { 359 | let bytes: Vec = point.to_bytes( 360 | &self.group, 361 | PointConversionForm::COMPRESSED, 362 | &mut self.bn_ctx, 363 | )?; 364 | acc.extend(bytes); 365 | 366 | Ok(acc) 367 | }, 368 | ); 369 | let to_be_hashed = point_bytes?; 370 | // H(point_bytes) 371 | let mut hash = hash(self.hasher, &to_be_hashed).map(|hash| hash.to_vec())?; 372 | hash.truncate(self.n / 8); 373 | let result = BigNum::from_slice(hash.as_slice())?; 374 | 375 | Ok(result) 376 | } 377 | 378 | /// Decodes a VRF proof by extracting the gamma (as `EcPoint`), and parameters `c` and `s` 379 | /// (as `BigNum`). 380 | /// 381 | /// # Arguments 382 | /// 383 | /// * `pi` - A slice of octets representing the VRF proof. 384 | /// 385 | /// # Returns 386 | /// 387 | /// * A tuple containing the gamma `EcPoint`, and `BigNum` parameters `c` and `s`. 388 | fn decode_proof(&mut self, pi: &[u8]) -> Result<(EcPoint, BigNum, BigNum), Error> { 389 | let gamma_oct = if self.qlen % 8 > 0 { 390 | self.qlen / 8 + 2 391 | } else { 392 | self.qlen / 8 + 1 393 | }; 394 | let c_oct = if self.n % 8 > 0 { 395 | self.n / 8 + 1 396 | } else { 397 | self.n / 8 398 | }; 399 | 400 | // Expected size of proof: len(pi) == len(gamma) + len(c) + len(s) 401 | // len(s) == 2 * len(c), so len(pi) == len(gamma) + 3 * len(c) 402 | if pi.len() != gamma_oct + c_oct * 3 { 403 | return Err(Error::InvalidPiLength); 404 | } 405 | let gamma_point = EcPoint::from_bytes(&self.group, &pi[0..gamma_oct], &mut self.bn_ctx)?; 406 | let c = BigNum::from_slice(&pi[gamma_oct..gamma_oct + c_oct])?; 407 | let s = BigNum::from_slice(&pi[gamma_oct + c_oct..])?; 408 | 409 | Ok((gamma_point, c, s)) 410 | } 411 | 412 | /// Computes the VRF hash output as result of the digest of a ciphersuite-dependent prefix 413 | /// concatenated with the gamma point ([VRF-draft-05](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05), section 5.2). 414 | /// 415 | /// # Arguments 416 | /// 417 | /// * `gamma` - An `EcPoint` representing the VRF gamma. 418 | /// 419 | /// # Returns 420 | /// 421 | /// * A vector of octets with the VRF hash output. 422 | fn gamma_to_hash(&mut self, gamma: &EcPoint) -> Result, Error> { 423 | // Multiply gamma with cofactor 424 | let mut gamma_cof = EcPoint::new(self.group.as_ref())?; 425 | gamma_cof.mul( 426 | self.group.as_ref(), 427 | gamma, 428 | BigNum::from_slice(&[self.cofactor])?.as_ref(), 429 | &self.bn_ctx, 430 | )?; 431 | 432 | let gamma_string = gamma_cof.to_bytes( 433 | &self.group, 434 | PointConversionForm::COMPRESSED, 435 | &mut self.bn_ctx, 436 | )?; 437 | 438 | let hash = hash( 439 | self.hasher, 440 | &[ 441 | &[self.cipher_suite.suite_string()], 442 | &[0x03], 443 | &gamma_string[..], 444 | ] 445 | .concat(), 446 | ) 447 | .map(|hash| hash.to_vec())?; 448 | 449 | Ok(hash) 450 | } 451 | 452 | /// Computes the VRF hash output as result of the digest of a ciphersuite-dependent prefix 453 | /// concatenated with the gamma point ([VRF-draft-05](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05), section 5.2). 454 | /// 455 | /// # Arguments 456 | /// 457 | /// * `pi` - A slice representing the VRF proof in octets. 458 | /// 459 | /// # Returns 460 | /// 461 | /// * If successful, a vector of octets with the VRF hash output. 462 | pub fn proof_to_hash(&mut self, pi: &[u8]) -> Result, Error> { 463 | let (gamma_point, _, _) = self.decode_proof(pi)?; 464 | 465 | self.gamma_to_hash(&gamma_point) 466 | } 467 | } 468 | 469 | /// VRFs are objects capable of generating and verifying proofs. 470 | impl VRF<&[u8], &[u8]> for ECVRF { 471 | type Error = Error; 472 | 473 | /// Generates proof from a secret key and message as specified in the 474 | /// [VRF-draft-05](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05) (section 5.1). 475 | /// 476 | /// # Arguments 477 | /// 478 | /// * `x` - A slice representing the secret key in octets. 479 | /// * `alpha` - A slice representing the message in octets. 480 | /// 481 | /// # Returns 482 | /// 483 | /// * If successful, a vector of octets representing the proof of the VRF. 484 | fn prove(&mut self, x: &[u8], alpha: &[u8]) -> Result, Error> { 485 | // Step 1: derive public key from secret key 486 | // `Y = x * B` 487 | //TODO: validate secret key length? 488 | let secret_key = BigNum::from_slice(x)?; 489 | let public_key_point = self.derive_public_key_point(&secret_key)?; 490 | 491 | // Step 2: Hash to curve 492 | let h_point = self.hash_to_try_and_increment(&public_key_point, alpha)?; 493 | 494 | // Step 3: point to string 495 | let h_string = h_point.to_bytes( 496 | &self.group, 497 | PointConversionForm::COMPRESSED, 498 | &mut self.bn_ctx, 499 | )?; 500 | 501 | // Step 4: Gamma = x * H 502 | let mut gamma_point = EcPoint::new(self.group.as_ref())?; 503 | gamma_point.mul(self.group.as_ref(), &h_point, &secret_key, &self.bn_ctx)?; 504 | 505 | // Step 5: nonce 506 | let k = self.generate_nonce(&secret_key, &h_string)?; 507 | 508 | // Step 6: c = hash points(...) 509 | let mut u_point = EcPoint::new(self.group.as_ref())?; 510 | let mut v_point = EcPoint::new(self.group.as_ref())?; 511 | u_point.mul_generator(self.group.as_ref(), &k, &self.bn_ctx)?; 512 | v_point.mul(self.group.as_ref(), &h_point, &k, &self.bn_ctx)?; 513 | let c = self.hash_points(&[&h_point, &gamma_point, &u_point, &v_point])?; 514 | 515 | // Step 7: s = (k + c*x) mod q 516 | let s = &(&k + &(&c * &secret_key)) % &self.order; 517 | 518 | // Step 8: encode (gamma, c, s) 519 | let gamma_string = gamma_point.to_bytes( 520 | &self.group, 521 | PointConversionForm::COMPRESSED, 522 | &mut self.bn_ctx, 523 | )?; 524 | // Fixed size; len(c) must be n and len(s)=2n 525 | let c_string = append_leading_zeros(&c.to_vec(), self.n); 526 | let s_string = append_leading_zeros(&s.to_vec(), self.qlen); 527 | // proof = [Gamma_string||c_string||s_string] 528 | let proof = [&gamma_string[..], &c_string, &s_string].concat(); 529 | 530 | Ok(proof) 531 | } 532 | 533 | /// Verifies the provided VRF proof and computes the VRF hash output as specified in 534 | /// [VRF-draft-05](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05) (section 5.3). 535 | /// 536 | /// # Arguments 537 | /// 538 | /// * `y` - A slice representing the public key in octets. 539 | /// * `pi` - A slice of octets representing the VRF proof. 540 | /// 541 | /// # Returns 542 | /// 543 | /// * If successful, a vector of octets with the VRF hash output. 544 | fn verify(&mut self, y: &[u8], pi: &[u8], alpha: &[u8]) -> Result, Error> { 545 | // Step 1: decode proof 546 | let (gamma_point, c, s) = self.decode_proof(pi)?; 547 | 548 | // Step 2: hash to curve 549 | let public_key_point = EcPoint::from_bytes(&self.group, y, &mut self.bn_ctx)?; 550 | let h_point = self.hash_to_try_and_increment(&public_key_point, alpha)?; 551 | 552 | // Step 3: U = sB -cY 553 | let mut s_b = EcPoint::new(self.group.as_ref())?; 554 | let mut c_y = EcPoint::new(self.group.as_ref())?; 555 | let mut u_point = EcPoint::new(self.group.as_ref())?; 556 | s_b.mul_generator(&self.group, &s, &self.bn_ctx)?; 557 | c_y.mul(&self.group, &public_key_point, &c, &self.bn_ctx)?; 558 | c_y.invert(&self.group, &self.bn_ctx)?; 559 | u_point.add(&self.group, &s_b, &c_y, &mut self.bn_ctx)?; 560 | 561 | // Step 4: V = sH -cGamma 562 | let mut s_h = EcPoint::new(self.group.as_ref())?; 563 | let mut c_gamma = EcPoint::new(self.group.as_ref())?; 564 | let mut v_point = EcPoint::new(self.group.as_ref())?; 565 | s_h.mul(&self.group, &h_point, &s, &self.bn_ctx)?; 566 | c_gamma.mul(&self.group, &gamma_point, &c, &self.bn_ctx)?; 567 | c_gamma.invert(&self.group, &self.bn_ctx)?; 568 | v_point.add(&self.group, &s_h, &c_gamma, &mut self.bn_ctx)?; 569 | 570 | // Step 5: hash points(...) 571 | let derived_c = self.hash_points(&[&h_point, &gamma_point, &u_point, &v_point])?; 572 | 573 | // Step 6: Check validity 574 | if !derived_c.eq(&c) { 575 | return Err(Error::InvalidProof); 576 | } 577 | let beta = self.gamma_to_hash(&gamma_point)?; 578 | 579 | Ok(beta) 580 | } 581 | } 582 | 583 | #[cfg(test)] 584 | mod test { 585 | use super::*; 586 | 587 | #[test] 588 | fn test_derive_public_key() { 589 | let mut vrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap(); 590 | 591 | let secret_key = BigNum::from_slice(&[0x01]).unwrap(); 592 | let public_key = vrf.derive_public_key_point(&secret_key).unwrap(); 593 | let public_key_bytes = public_key 594 | .to_bytes(&vrf.group, PointConversionForm::COMPRESSED, &mut vrf.bn_ctx) 595 | .unwrap(); 596 | 597 | let expected_point_bytes = vec![ 598 | 0x03, 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, 0xBC, 0xE6, 0xE5, 0x63, 599 | 0xA4, 0x40, 0xF2, 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0, 0xF4, 0xA1, 0x39, 600 | 0x45, 0xD8, 0x98, 0xC2, 0x96, 601 | ]; 602 | assert_eq!(public_key_bytes, expected_point_bytes); 603 | } 604 | 605 | /// Test vector for `P256-SHA256-TAI` cipher suite 606 | /// ASCII: "sample" 607 | /// Source: [VRF-draft-05](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05) (section A.1) 608 | #[test] 609 | fn test_prove_p256_sha256_tai_1() { 610 | let mut vrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap(); 611 | // Secret Key (labelled as x) 612 | let x = hex::decode("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721") 613 | .unwrap(); 614 | // Data: ASCII "sample" 615 | let alpha = hex::decode("73616d706c65").unwrap(); 616 | 617 | let pi = vrf.prove(&x, &alpha).unwrap(); 618 | let expected_pi = hex::decode("029bdca4cc39e57d97e2f42f88bcf0ecb1120fb67eb408a856050dbfbcbf57c524347fc46ccd87843ec0a9fdc090a407c6fbae8ac1480e240c58854897eabbc3a7bb61b201059f89186e7175af796d65e7").unwrap(); 619 | assert_eq!(pi, expected_pi); 620 | } 621 | 622 | /// Test vector for `P256-SHA256-TAI` cipher suite 623 | /// ASCII: "sample" 624 | /// Source: [VRF-draft-05](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05) (section A.1) 625 | #[test] 626 | fn test_verify_p256_sha256_tai_1() { 627 | let mut vrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap(); 628 | // Public Key (labelled as y) 629 | let y = hex::decode("0360fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6") 630 | .unwrap(); 631 | // VRF Proof 632 | let pi = hex::decode("029bdca4cc39e57d97e2f42f88bcf0ecb1120fb67eb408a856050dbfbcbf57c524347fc46ccd87843ec0a9fdc090a407c6fbae8ac1480e240c58854897eabbc3a7bb61b201059f89186e7175af796d65e7").unwrap(); 633 | // Data: ASCII "sample" 634 | let alpha = hex::decode("73616d706c65").unwrap(); 635 | 636 | let beta = vrf.verify(&y, &pi, &alpha).unwrap(); 637 | let expected_beta = 638 | hex::decode("59ca3801ad3e981a88e36880a3aee1df38a0472d5be52d6e39663ea0314e594c") 639 | .unwrap(); 640 | assert_eq!(beta, expected_beta); 641 | } 642 | 643 | /// Test vector for `P256-SHA256-TAI` cipher suite 644 | /// ASCII: "test" 645 | /// Source: [VRF-draft-05](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05) (section A.1) 646 | #[test] 647 | fn test_prove_p256_sha256_tai_2() { 648 | let mut vrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap(); 649 | // Secret Key (labelled as x) 650 | let x = hex::decode("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721") 651 | .unwrap(); 652 | // Data: ASCII "sample" 653 | let alpha = hex::decode("74657374").unwrap(); 654 | 655 | let pi = vrf.prove(&x, &alpha).unwrap(); 656 | let expected_pi = hex::decode("03873a1cce2ca197e466cc116bca7b1156fff599be67ea40b17256c4f34ba2549c94ffd2b31588b5fe034fd92c87de5b520b12084da6c4ab63080a7c5467094a1ee84b80b59aca54bba2e2baa0d108191b").unwrap(); 657 | assert_eq!(pi, expected_pi); 658 | } 659 | 660 | /// Test vector for `P256-SHA256-TAI` cipher suite 661 | /// ASCII: "test" 662 | /// Source: [VRF-draft-05](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05) (section A.1) 663 | #[test] 664 | fn test_verify_p256_sha256_tai_2() { 665 | let mut vrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap(); 666 | // Public Key (labelled as y) 667 | let y = hex::decode("0360fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6") 668 | .unwrap(); 669 | // VRF Proof 670 | let pi = hex::decode("03873a1cce2ca197e466cc116bca7b1156fff599be67ea40b17256c4f34ba2549c94ffd2b31588b5fe034fd92c87de5b520b12084da6c4ab63080a7c5467094a1ee84b80b59aca54bba2e2baa0d108191b").unwrap(); 671 | // Data: ASCII "sample" 672 | let alpha = hex::decode("74657374").unwrap(); 673 | 674 | let beta = vrf.verify(&y, &pi, &alpha).unwrap(); 675 | let expected_beta = 676 | hex::decode("dc85c20f95100626eddc90173ab58d5e4f837bb047fb2f72e9a408feae5bc6c1") 677 | .unwrap(); 678 | assert_eq!(beta, expected_beta); 679 | } 680 | 681 | /// Test vector for `P256-SHA256-TAI` cipher suite 682 | /// ASCII: "Example of ECDSA with ansip256r1 and SHA-256" 683 | /// Source: [VRF-draft-05](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05) (section A.1) 684 | #[test] 685 | fn test_prove_p256_sha256_tai_3() { 686 | let mut vrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap(); 687 | // Secret Key (labelled as x) 688 | let x = hex::decode("2ca1411a41b17b24cc8c3b089cfd033f1920202a6c0de8abb97df1498d50d2c8") 689 | .unwrap(); 690 | // Data to be hashed: ASCII "sample 691 | let alpha = hex::decode("4578616d706c65206f66204543445341207769746820616e736970323536723120616e64205348412d323536").unwrap(); 692 | let expected_pi = hex::decode("02abe3ce3b3aa2ab3c6855a7e729517ebfab6901c2fd228f6fa066f15ebc9b9d415a680736f7c33f6c796e367f7b2f467026495907affb124be9711cf0e2d05722d3a33e11d0c5bf932b8f0c5ed1981b64").unwrap(); 693 | let pi = vrf.prove(&x, &alpha).unwrap(); 694 | assert_eq!(pi, expected_pi); 695 | } 696 | 697 | /// Test vector for `P256-SHA256-TAI` cipher suite 698 | /// ASCII: "Example of ECDSA with ansip256r1 and SHA-256" 699 | /// Source: [VRF-draft-05](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05) (section A.1) 700 | #[test] 701 | fn test_verify_p256_sha256_tai_3() { 702 | let mut vrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap(); 703 | // Public Key (labelled as y) 704 | let y = hex::decode("03596375e6ce57e0f20294fc46bdfcfd19a39f8161b58695b3ec5b3d16427c274d") 705 | .unwrap(); 706 | // VRF Proof 707 | let pi = hex::decode("02abe3ce3b3aa2ab3c6855a7e729517ebfab6901c2fd228f6fa066f15ebc9b9d415a680736f7c33f6c796e367f7b2f467026495907affb124be9711cf0e2d05722d3a33e11d0c5bf932b8f0c5ed1981b64").unwrap(); 708 | // Data: ASCII "sample" 709 | let alpha = hex::decode("4578616d706c65206f66204543445341207769746820616e736970323536723120616e64205348412d323536").unwrap(); 710 | 711 | let beta = vrf.verify(&y, &pi, &alpha).unwrap(); 712 | let expected_beta = 713 | hex::decode("e880bde34ac5263b2ce5c04626870be2cbff1edcdadabd7d4cb7cbc696467168") 714 | .unwrap(); 715 | assert_eq!(beta, expected_beta); 716 | } 717 | 718 | /// Test vector for `P256-SHA256-TAI` cipher suite 719 | /// ASCII: "sample" 720 | /// Source: [VRF-draft-05](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05) (section A.1) 721 | #[test] 722 | fn test_hash_to_try_and_increment_1() { 723 | let mut vrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap(); 724 | 725 | // Public key 726 | let public_key_hex = 727 | hex::decode("0360fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6") 728 | .unwrap(); 729 | let public_key = EcPoint::from_bytes(&vrf.group, &public_key_hex, &mut vrf.bn_ctx).unwrap(); 730 | 731 | // Data to be hashed with TAI (ASCII "sample") 732 | let data = hex::decode("73616d706c65").unwrap(); 733 | let hash = vrf.hash_to_try_and_increment(&public_key, &data).unwrap(); 734 | let hash_bytes = hash 735 | .to_bytes(&vrf.group, PointConversionForm::COMPRESSED, &mut vrf.bn_ctx) 736 | .unwrap(); 737 | 738 | let expected_hash = 739 | hex::decode("02e2e1ab1b9f5a8a68fa4aad597e7493095648d3473b213bba120fe42d1a595f3e") 740 | .unwrap(); 741 | assert_eq!(hash_bytes, expected_hash); 742 | } 743 | 744 | /// Test vector for `P256-SHA256-TAI` cipher suite 745 | /// ASCII: "test" 746 | /// Source: [VRF-draft-05](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05) (section A.1) 747 | #[test] 748 | fn test_hash_to_try_and_increment_2() { 749 | let mut vrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap(); 750 | 751 | // Public key 752 | let public_key_hex = 753 | hex::decode("03596375e6ce57e0f20294fc46bdfcfd19a39f8161b58695b3ec5b3d16427c274d") 754 | .unwrap(); 755 | let public_key = EcPoint::from_bytes(&vrf.group, &public_key_hex, &mut vrf.bn_ctx).unwrap(); 756 | 757 | // Data to be hashed with TAI (ASCII "sample") 758 | let data = hex::decode("4578616d706c65206f66204543445341207769746820616e736970323536723120616e64205348412d323536").unwrap(); 759 | let hash = vrf.hash_to_try_and_increment(&public_key, &data).unwrap(); 760 | let hash_bytes = hash 761 | .to_bytes(&vrf.group, PointConversionForm::COMPRESSED, &mut vrf.bn_ctx) 762 | .unwrap(); 763 | 764 | let expected_hash = 765 | hex::decode("02141e41d4d55802b0e3adaba114c81137d95fd3869b6b385d4487b1130126648d") 766 | .unwrap(); 767 | assert_eq!(hash_bytes, expected_hash); 768 | } 769 | 770 | /// Test vector for `K-163` curve 771 | /// Source: [RFC6979](https://tools.ietf.org/html/rfc6979) (section A.1) 772 | #[test] 773 | fn test_generate_nonce_k163() { 774 | let mut vrf = ECVRF::from_suite(CipherSuite::K163_SHA256_TAI).unwrap(); 775 | let mut ord = BigNum::new().unwrap(); 776 | vrf.group.order(&mut ord, &mut vrf.bn_ctx).unwrap(); 777 | 778 | // Secret Key (labelled as x) 779 | let sk = hex::decode("009A4D6792295A7F730FC3F2B49CBC0F62E862272F").unwrap(); 780 | let sk_bn = BigNum::from_slice(&sk).unwrap(); 781 | 782 | // Hashed input message (labelled as h1) 783 | let data = hex::decode("73616d706c65").unwrap(); 784 | 785 | // Nonce generation 786 | let nonce = vrf.generate_nonce(&sk_bn, &data).unwrap(); 787 | 788 | // Expected result/nonce (labelled as K or T) 789 | let expected_nonce = hex::decode("023AF4074C90A02B3FE61D286D5C87F425E6BDD81B").unwrap(); 790 | assert_eq!(nonce.to_vec(), expected_nonce); 791 | } 792 | 793 | /// Test vector for `P-256` curve with `SHA-256` 794 | /// Message: sample 795 | /// Source: [RFC6979](https://tools.ietf.org/html/rfc6979) (section A.2.5) 796 | #[test] 797 | fn test_generate_nonce_p256_1() { 798 | let mut vrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap(); 799 | let mut ord = BigNum::new().unwrap(); 800 | vrf.group.order(&mut ord, &mut vrf.bn_ctx).unwrap(); 801 | 802 | // Secret Key (labelled as x) 803 | let sk = hex::decode("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721") 804 | .unwrap(); 805 | let sk_bn = BigNum::from_slice(&sk).unwrap(); 806 | 807 | // Data: ASCII "sample" 808 | let data = hex::decode("73616d706c65").unwrap(); 809 | 810 | // Nonce generation 811 | let nonce = vrf.generate_nonce(&sk_bn, &data).unwrap(); 812 | 813 | // Expected result/nonce (labelled as K or T) 814 | let expected_nonce = 815 | hex::decode("A6E3C57DD01ABE90086538398355DD4C3B17AA873382B0F24D6129493D8AAD60") 816 | .unwrap(); 817 | assert_eq!(nonce.to_vec(), expected_nonce); 818 | } 819 | 820 | /// Test vector for `P-256` curve with `SHA-256` 821 | /// Message: test 822 | /// Source: [RFC6979](https://tools.ietf.org/html/rfc6979) (section A.2.5) 823 | #[test] 824 | fn test_generate_nonce_p256_2() { 825 | let mut vrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap(); 826 | let mut ord = BigNum::new().unwrap(); 827 | vrf.group.order(&mut ord, &mut vrf.bn_ctx).unwrap(); 828 | 829 | // Secret Key (labelled as x) 830 | let sk = hex::decode("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721") 831 | .unwrap(); 832 | let sk_bn = BigNum::from_slice(&sk).unwrap(); 833 | 834 | // Data: ASCII "test" 835 | let data = hex::decode("74657374").unwrap(); 836 | 837 | // Nonce generation 838 | let nonce = vrf.generate_nonce(&sk_bn, &data).unwrap(); 839 | 840 | // Expected result/nonce (labelled as K or T) 841 | let expected_nonce = 842 | hex::decode("D16B6AE827F17175E040871A1C7EC3500192C4C92677336EC2537ACAEE0008E0") 843 | .unwrap(); 844 | assert_eq!(nonce.to_vec(), expected_nonce); 845 | } 846 | 847 | /// Test vector for `P256-SHA256-TAI` cipher suite 848 | /// ASCII: "sample" 849 | /// Source: [VRF-draft-05](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05) (section A.1) 850 | #[test] 851 | fn test_generate_nonce_p256_3() { 852 | let mut vrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap(); 853 | let mut ord = BigNum::new().unwrap(); 854 | vrf.group.order(&mut ord, &mut vrf.bn_ctx).unwrap(); 855 | 856 | // Secret Key (labelled as x) 857 | let sk = hex::decode("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721") 858 | .unwrap(); 859 | let sk_bn = BigNum::from_slice(&sk).unwrap(); 860 | 861 | // Hashed input message (labelled as h1) 862 | let data = 863 | hex::decode("02e2e1ab1b9f5a8a68fa4aad597e7493095648d3473b213bba120fe42d1a595f3e") 864 | .unwrap(); 865 | 866 | // Nonce generation 867 | let nonce = vrf.generate_nonce(&sk_bn, &data).unwrap(); 868 | 869 | // Expected result/nonce (labelled as K or T) 870 | let expected_nonce = 871 | hex::decode("b7de5757b28c349da738409dfba70763ace31a6b15be8216991715fbc833e5fa") 872 | .unwrap(); 873 | assert_eq!(nonce.to_vec(), expected_nonce); 874 | } 875 | 876 | /// Test vector for `P256-SHA256-TAI` cipher suite 877 | /// ASCII: "test" 878 | /// Source: [VRF-draft-05](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05) (section A.1) 879 | #[test] 880 | fn test_generate_nonce_p256_4() { 881 | let mut vrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap(); 882 | let mut ord = BigNum::new().unwrap(); 883 | vrf.group.order(&mut ord, &mut vrf.bn_ctx).unwrap(); 884 | 885 | // Secret Key (labelled as x) 886 | let sk = hex::decode("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721") 887 | .unwrap(); 888 | let sk_bn = BigNum::from_slice(&sk).unwrap(); 889 | 890 | // Hashed input message (labelled as h1) 891 | let data = 892 | hex::decode("02ca565721155f9fd596f1c529c7af15dad671ab30c76713889e3d45b767ff6433") 893 | .unwrap(); 894 | 895 | // Nonce generation 896 | let nonce = vrf.generate_nonce(&sk_bn, &data).unwrap(); 897 | 898 | // Expected result/nonce (labelled as K or T) 899 | let expected_nonce = 900 | hex::decode("c3c4f385523b814e1794f22ad1679c952e83bff78583c85eb5c2f6ea6eee2e7d") 901 | .unwrap(); 902 | assert_eq!(nonce.to_vec(), expected_nonce); 903 | } 904 | 905 | /// Test vector for `P256-SHA256-TAI` cipher suite 906 | /// ASCII: "Example of ECDSA with ansip256r1 and SHA-256" 907 | /// Source: [VRF-draft-05](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05) (section A.1) 908 | #[test] 909 | fn test_generate_nonce_p256_5() { 910 | let mut vrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap(); 911 | let mut ord = BigNum::new().unwrap(); 912 | vrf.group.order(&mut ord, &mut vrf.bn_ctx).unwrap(); 913 | 914 | // Secret Key (labelled as x) 915 | let sk = hex::decode("2ca1411a41b17b24cc8c3b089cfd033f1920202a6c0de8abb97df1498d50d2c8") 916 | .unwrap(); 917 | let sk_bn = BigNum::from_slice(&sk).unwrap(); 918 | 919 | // Hashed input message (labelled as h1) 920 | let data = 921 | hex::decode("02141e41d4d55802b0e3adaba114c81137d95fd3869b6b385d4487b1130126648d") 922 | .unwrap(); 923 | 924 | // Nonce generation 925 | let nonce = vrf.generate_nonce(&sk_bn, &data).unwrap(); 926 | 927 | // Expected result/nonce (labelled as K or T) 928 | let expected_nonce = 929 | hex::decode("6ac8f1efa102bdcdcc8db99b755d39bc995491e3f9dea076add1905a92779610") 930 | .unwrap(); 931 | assert_eq!(nonce.to_vec(), expected_nonce); 932 | } 933 | 934 | /// Test vector for `P256-SHA256-TAI` cipher suite 935 | /// ASCII: "sample" 936 | /// Source: [VRF-draft-05](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05) (section A.1) 937 | #[test] 938 | fn test_hash_points() { 939 | let mut vrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap(); 940 | 941 | // Test input data 942 | let hash_hex = 943 | hex::decode("02e2e1ab1b9f5a8a68fa4aad597e7493095648d3473b213bba120fe42d1a595f3e") 944 | .unwrap(); 945 | let pi_hex = hex::decode("029bdca4cc39e57d97e2f42f88bcf0ecb1120fb67eb408a856050dbfbcbf57c524347fc46ccd87843ec0a9fdc090a407c6fbae8ac1480e240c58854897eabbc3a7bb61b201059f89186e7175af796d65e7").unwrap(); 946 | // Compute all required points (gamma, u, v) 947 | let hash_point = EcPoint::from_bytes(&vrf.group, &hash_hex, &mut vrf.bn_ctx).unwrap(); 948 | let mut gamma_hex = pi_hex.clone(); 949 | let c_s_hex = gamma_hex.split_off(33); 950 | let gamma_point = EcPoint::from_bytes(&vrf.group, &gamma_hex, &mut vrf.bn_ctx).unwrap(); 951 | let u_hex = 952 | hex::decode("030286d82c95d54feef4d39c000f8659a5ce00a5f71d3a888bd1b8e8bf07449a50") 953 | .unwrap(); 954 | let u_point = EcPoint::from_bytes(&vrf.group, &u_hex, &mut vrf.bn_ctx).unwrap(); 955 | let v_hex = 956 | hex::decode("03e4258b4a5f772ed29830050712fa09ea8840715493f78e5aaaf7b27248efc216") 957 | .unwrap(); 958 | let v_point = EcPoint::from_bytes(&vrf.group, &v_hex, &mut vrf.bn_ctx).unwrap(); 959 | 960 | let computed_c = vrf 961 | .hash_points(&[&hash_point, &gamma_point, &u_point, &v_point]) 962 | .unwrap(); 963 | 964 | let mut expected_c = c_s_hex.clone(); 965 | expected_c.truncate(16); 966 | assert_eq!(computed_c.to_vec(), expected_c); 967 | } 968 | 969 | /// Test vector for `P256-SHA256-TAI` cipher suite 970 | /// ASCII: "sample" 971 | /// Source: [VRF-draft-05](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05) (section A.1) 972 | #[test] 973 | fn test_decode_proof() { 974 | let mut vrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap(); 975 | 976 | let pi_hex = hex::decode("029bdca4cc39e57d97e2f42f88bcf0ecb1120fb67eb408a856050dbfbcbf57c524347fc46ccd87843ec0a9fdc090a407c6fbae8ac1480e240c58854897eabbc3a7bb61b201059f89186e7175af796d65e7") 977 | .unwrap(); 978 | let (derived_gamma, derived_c, _) = vrf.decode_proof(&pi_hex).unwrap(); 979 | 980 | // Expected values 981 | let mut gamma_hex = pi_hex.clone(); 982 | let c_s_hex = gamma_hex.split_off(33); 983 | let mut c_hex = c_s_hex.clone(); 984 | c_hex.truncate(16); 985 | let expected_gamma = EcPoint::from_bytes(&vrf.group, &gamma_hex, &mut vrf.bn_ctx).unwrap(); 986 | let expected_c = BigNum::from_slice(c_hex.as_slice()).unwrap(); 987 | 988 | assert!(derived_c.eq(&expected_c)); 989 | assert!(expected_gamma 990 | .eq(&vrf.group, &derived_gamma, &mut vrf.bn_ctx) 991 | .unwrap()); 992 | } 993 | 994 | /// Test for `SECP256K1-SHA256-TAI` cipher suite 995 | /// ASCII: "sample" 996 | #[test] 997 | fn test_prove_secp256k1_sha256_tai() { 998 | let mut vrf = ECVRF::from_suite(CipherSuite::SECP256K1_SHA256_TAI).unwrap(); 999 | // Secret Key (labelled as x) 1000 | let x = hex::decode("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721") 1001 | .unwrap(); 1002 | // Data: ASCII "sample" 1003 | let alpha = hex::decode("73616d706c65").unwrap(); 1004 | 1005 | let pi = vrf.prove(&x, &alpha).unwrap(); 1006 | let expected_pi = hex::decode("031f4dbca087a1972d04a07a779b7df1caa99e0f5db2aa21f3aecc4f9e10e85d08748c9fbe6b95d17359707bfb8e8ab0c93ba0c515333adcb8b64f372c535e115ccf66ebf5abe6fadb01b5efb37c0a0ec9").unwrap(); 1007 | assert_eq!(pi, expected_pi); 1008 | } 1009 | 1010 | /// Test for `SECP256K1-SHA256-TAI` cipher suite 1011 | /// ASCII: "sample" 1012 | #[test] 1013 | fn test_verify_secp256k1_sha256_tai() { 1014 | let mut vrf = ECVRF::from_suite(CipherSuite::SECP256K1_SHA256_TAI).unwrap(); 1015 | // Public Key (labelled as y) 1016 | let y = hex::decode("032c8c31fc9f990c6b55e3865a184a4ce50e09481f2eaeb3e60ec1cea13a6ae645") 1017 | .unwrap(); 1018 | // Data: ASCII "sample" 1019 | let alpha = hex::decode("73616d706c65").unwrap(); 1020 | // VRF proof 1021 | let pi = hex::decode("031f4dbca087a1972d04a07a779b7df1caa99e0f5db2aa21f3aecc4f9e10e85d0814faa89697b482daa377fb6b4a8b0191a65d34a6d90a8a2461e5db9205d4cf0bb4b2c31b5ef6997a585a9f1a72517b6f").unwrap(); 1022 | 1023 | let beta = vrf.verify(&y, &pi, &alpha).unwrap(); 1024 | let expected_beta = 1025 | hex::decode("612065e309e937ef46c2ef04d5886b9c6efd2991ac484ec64a9b014366fc5d81") 1026 | .unwrap(); 1027 | assert_eq!(beta, expected_beta); 1028 | } 1029 | 1030 | /// Test for false positives in verification: 1031 | /// Verify should fail if the message has changed. 1032 | #[test] 1033 | fn test_verify_secp256k1_sha256_tai_bad_message() { 1034 | let mut vrf = ECVRF::from_suite(CipherSuite::SECP256K1_SHA256_TAI).unwrap(); 1035 | // Public Key (labelled as y) 1036 | let y = hex::decode("032c8c31fc9f990c6b55e3865a184a4ce50e09481f2eaeb3e60ec1cea13a6ae645") 1037 | .unwrap(); 1038 | // VRF proof 1039 | let pi = hex::decode("031f4dbca087a1972d04a07a779b7df1caa99e0f5db2aa21f3aecc4f9e10e85d0800851b42ee92f76d98c1f19e4a1e855526b20afe0dd6eb232a493adc107eb2b0f1").unwrap(); 1040 | 1041 | // Verify the proof with a different message will fail 1042 | // The original message was "sample" 1043 | let alpha2 = b"notsample".to_vec(); 1044 | assert!(vrf.verify(&y, &pi, &alpha2).is_err()); 1045 | } 1046 | 1047 | /// Test for malformed proof: 1048 | /// Verify should fail and the program should not panic. 1049 | #[test] 1050 | fn test_verify_secp256k1_sha256_tai_malformed_proof() { 1051 | let mut vrf = ECVRF::from_suite(CipherSuite::SECP256K1_SHA256_TAI).unwrap(); 1052 | // Public Key (labelled as y) 1053 | let y = hex::decode("032c8c31fc9f990c6b55e3865a184a4ce50e09481f2eaeb3e60ec1cea13a6ae645") 1054 | .unwrap(); 1055 | // VRF proof 1056 | let pi = hex::decode("00000000000000000000000000000000").unwrap(); 1057 | 1058 | let alpha = b"sample".to_vec(); 1059 | assert!(vrf.verify(&y, &pi, &alpha).is_err()); 1060 | } 1061 | } 1062 | -------------------------------------------------------------------------------- /src/openssl/utils.rs: -------------------------------------------------------------------------------- 1 | use openssl::{ 2 | bn::{BigNum, BigNumContext}, 3 | error::ErrorStack, 4 | }; 5 | 6 | /// Appends leading zeros if provided slice is smaller than given length. 7 | /// 8 | /// # Arguments 9 | /// 10 | /// * `data` - A slice of octets. 11 | /// * `bits_length` - An integer to specify the total length (in bits) after appending zeros. 12 | /// 13 | /// # Returns 14 | /// 15 | /// * A vector of octets with leading zeros (if necessary) 16 | pub fn append_leading_zeros(data: &[u8], bits_length: usize) -> Vec { 17 | if data.len() * 8 > bits_length { 18 | return data.to_vec(); 19 | } 20 | 21 | let leading_zeros = if bits_length % 8 > 0 { 22 | vec![0; bits_length / 8 - data.len() + 1] 23 | } else { 24 | vec![0; bits_length / 8 - data.len()] 25 | }; 26 | 27 | [&leading_zeros[..], data].concat() 28 | } 29 | 30 | /// Converts a slice of octets into a `BigNum` of length `qlen` as specified in [RFC6979](https://tools.ietf.org/html/rfc6979) 31 | /// (section 2.3.2). 32 | /// 33 | /// # Arguments 34 | /// 35 | /// * `data` - A slice representing the number to be converted. 36 | /// * `qlen` - The desired length for the output `BigNum`. 37 | /// 38 | /// # Returns 39 | /// 40 | /// * If successful, a `BigNum` representing the conversion. 41 | pub fn bits2int(data: &[u8], qlen: usize) -> Result { 42 | let data_len_bits = data.len() * 8; 43 | let result = BigNum::from_slice(data).and_then(|data_bn| { 44 | if data_len_bits > qlen { 45 | let mut truncated = BigNum::new()?; 46 | truncated.rshift(&data_bn, (data_len_bits - qlen) as i32)?; 47 | 48 | Ok(truncated) 49 | } else { 50 | Ok(data_bn) 51 | } 52 | })?; 53 | let _data2 = data.to_vec(); 54 | let _data_vec = result.to_vec(); 55 | 56 | Ok(result) 57 | } 58 | 59 | /// Transform an input to a sequence of `length` (in bits) and output this sequence representing a 60 | /// number between 0 and `order` (non-inclusive), as specified in [RFC6979](https://tools.ietf.org/html/rfc6979) (section 2.3.4.). 61 | /// 62 | /// # Arguments 63 | /// 64 | /// * `data` - A slice of octets. 65 | /// * `bits_length` - An integer to specify the total length (in bits) after appending zeros. 66 | /// 67 | /// # Returns 68 | /// 69 | /// * If successful, a vector of octets. 70 | pub fn bits2octets( 71 | data: &[u8], 72 | length: usize, 73 | order: &BigNum, 74 | bn_ctx: &mut BigNumContext, 75 | ) -> Result, ErrorStack> { 76 | let z1 = bits2int(data, length)?; 77 | let result = BigNum::new().and_then(|mut res| { 78 | res.nnmod(&z1, order, bn_ctx)?; 79 | Ok(res.to_vec()) 80 | })?; 81 | 82 | Ok(result) 83 | } 84 | 85 | #[cfg(test)] 86 | mod test { 87 | use super::*; 88 | 89 | #[test] 90 | fn test_bits2int() { 91 | let data1 = vec![0x01; 32]; 92 | let expected_result_1 = BigNum::from_slice(&data1).unwrap(); 93 | let result1 = bits2int(&data1, 256).unwrap(); 94 | assert_eq!(result1, expected_result_1); 95 | 96 | let data2 = vec![0x01; 33]; 97 | let data2_bn = BigNum::from_slice(&data2).unwrap(); 98 | let result2 = bits2int(&data2, 256).unwrap(); 99 | let mut expected_result_2 = BigNum::new().unwrap(); 100 | expected_result_2.rshift(&data2_bn, 8).unwrap(); 101 | 102 | assert_eq!(result2.to_vec(), expected_result_2.to_vec()); 103 | } 104 | 105 | /// Test vector taken from [RFC6979](https://tools.ietf.org/html/rfc6979) 106 | /// Input: `sha256("sample")` 107 | /// `qlen=163` 108 | #[test] 109 | fn test_bits2octets() { 110 | let data = hex::decode("AF2BDBE1AA9B6EC1E2ADE1D694F41FC71A831D0268E9891562113D8A62ADD1BF") 111 | .unwrap(); 112 | let order_hex = hex::decode("04000000000000000000020108A2E0CC0D99F8A5EF").unwrap(); 113 | let order = BigNum::from_slice(&order_hex.as_slice()).unwrap(); 114 | let mut bn_ctx = BigNumContext::new().unwrap(); 115 | let result = bits2octets( 116 | &data.as_slice(), 117 | order.num_bits() as usize, 118 | &order, 119 | &mut bn_ctx, 120 | ) 121 | .unwrap(); 122 | 123 | let expected_result = hex::decode("01795EDF0D54DB760F156D0DAC04C0322B3A204224").unwrap(); 124 | assert_eq!(result, expected_result); 125 | } 126 | } 127 | --------------------------------------------------------------------------------