├── .gitignore ├── rustfmt.toml ├── rust-toolchain.toml ├── .cargo └── config.toml ├── src ├── keys.rs ├── lib.rs ├── gadgets.rs ├── signatures.rs └── keys │ ├── secret.rs │ └── public.rs ├── katex-header.html ├── .github └── workflows │ └── dusk_ci.yaml ├── tests ├── schnorr.rs ├── schnorr_var_generator.rs ├── schnorr_double.rs ├── keys.rs └── gadgets.rs ├── Cargo.toml ├── benches ├── signature.rs ├── signature_double.rs └── signature_var_generator.rs ├── README.md ├── CHANGELOG.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | max_width = 80 2 | wrap_comments = true 3 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2023-05-22" 3 | components = ["rustfmt", "clippy"] -------------------------------------------------------------------------------- /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | # Flags needed to render LaTeX in documentation 3 | # With this, `cargo doc` must be run with the `--no-deps` flag 4 | rustdocflags = "--html-in-header ./katex-header.html" 5 | -------------------------------------------------------------------------------- /src/keys.rs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | // 5 | // Copyright (c) DUSK NETWORK. All rights reserved. 6 | 7 | //! # Keys 8 | //! 9 | //! Modules for the secret and public keys. 10 | //! 11 | //! - `public`: Contains the public key and double public key. Used in signature 12 | //! verification. 13 | //! - `secret`: Contains the secret key. Used for signing messages. 14 | 15 | pub mod public; 16 | pub mod secret; 17 | -------------------------------------------------------------------------------- /katex-header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | // 5 | // Copyright (c) DUSK NETWORK. All rights reserved. 6 | 7 | #![doc = include_str!("../README.md")] 8 | #![no_std] 9 | 10 | mod keys; 11 | mod signatures; 12 | 13 | #[cfg(feature = "alloc")] 14 | pub mod gadgets; 15 | 16 | #[deprecated(note = "Please use DoubleSignature instead")] 17 | #[cfg(feature = "double")] 18 | pub type Proof = signatures::SignatureDouble; 19 | 20 | pub use keys::public::PublicKey; 21 | pub use keys::secret::SecretKey; 22 | pub use signatures::Signature; 23 | 24 | #[cfg(feature = "double")] 25 | pub use keys::public::PublicKeyDouble; 26 | #[cfg(feature = "double")] 27 | pub use signatures::SignatureDouble; 28 | 29 | #[cfg(feature = "var_generator")] 30 | pub use keys::public::PublicKeyVarGen; 31 | #[cfg(feature = "var_generator")] 32 | pub use keys::secret::SecretKeyVarGen; 33 | #[cfg(feature = "var_generator")] 34 | pub use signatures::SignatureVarGen; 35 | -------------------------------------------------------------------------------- /.github/workflows/dusk_ci.yaml: -------------------------------------------------------------------------------- 1 | on: [pull_request] 2 | 3 | name: Continuous integration 4 | 5 | jobs: 6 | analyze: 7 | name: Code Analysis 8 | uses: dusk-network/.github/.github/workflows/code-analysis.yml@main 9 | with: 10 | clippy_default: false 11 | clippy_args: --features=rkyv/size_32,double,var_generator 12 | 13 | dusk_analyzer: 14 | name: Dusk Analyzer 15 | uses: dusk-network/.github/.github/workflows/dusk-analysis.yml@main 16 | 17 | build_benches: 18 | name: Build Benchmarks 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v3 22 | - uses: Swatinem/rust-cache@v2 23 | - run: cargo bench --no-run --features=double,var_generator 24 | 25 | test_nightly_std: 26 | name: Nightly tests std 27 | uses: dusk-network/.github/.github/workflows/run-tests.yml@main 28 | with: 29 | test_flags: --features=double,var_generator 30 | 31 | test_nightly_std_double: 32 | name: Nightly tests std 33 | uses: dusk-network/.github/.github/workflows/run-tests.yml@main 34 | with: 35 | test_flags: --features=var_generator 36 | 37 | test_nightly_std_var_generator: 38 | name: Nightly tests std 39 | uses: dusk-network/.github/.github/workflows/run-tests.yml@main 40 | with: 41 | test_flags: --features=double 42 | 43 | test_nightly_no_std: 44 | name: Nightly tests no_std 45 | uses: dusk-network/.github/.github/workflows/run-tests.yml@main 46 | with: 47 | test_flags: --no-default-features --features=double,var_generator 48 | -------------------------------------------------------------------------------- /tests/schnorr.rs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | // 5 | // Copyright (c) DUSK NETWORK. All rights reserved. 6 | 7 | use dusk_bls12_381::BlsScalar; 8 | use dusk_bytes::Serializable; 9 | use dusk_schnorr::{PublicKey, SecretKey, Signature}; 10 | use ff::Field; 11 | use rand::rngs::StdRng; 12 | use rand::SeedableRng; 13 | 14 | #[test] 15 | fn sign_verify() { 16 | let mut rng = StdRng::seed_from_u64(2321u64); 17 | 18 | let sk = SecretKey::random(&mut rng); 19 | let message = BlsScalar::random(&mut rng); 20 | let pk = PublicKey::from(&sk); 21 | 22 | let sig = sk.sign(&mut rng, message); 23 | 24 | assert!(pk.verify(&sig, message)); 25 | } 26 | 27 | #[test] 28 | fn test_wrong_keys() { 29 | let mut rng = StdRng::seed_from_u64(2321u64); 30 | 31 | let sk = SecretKey::random(&mut rng); 32 | let message = BlsScalar::random(&mut rng); 33 | 34 | let sig = sk.sign(&mut rng, message); 35 | 36 | // Derive random public key 37 | let pk = PublicKey::from(&SecretKey::random(&mut rng)); 38 | 39 | assert!(!pk.verify(&sig, message)); 40 | } 41 | 42 | #[test] 43 | fn to_from_bytes() { 44 | let mut rng = StdRng::seed_from_u64(2321u64); 45 | 46 | let sk = SecretKey::random(&mut rng); 47 | let message = BlsScalar::random(&mut rng); 48 | 49 | let sig = sk.sign(&mut rng, message); 50 | assert_eq!(sig, Signature::from_bytes(&sig.to_bytes()).unwrap()); 51 | } 52 | -------------------------------------------------------------------------------- /tests/schnorr_var_generator.rs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | // 5 | // Copyright (c) DUSK NETWORK. All rights reserved. 6 | 7 | use dusk_bls12_381::BlsScalar; 8 | use dusk_bytes::Serializable; 9 | use dusk_schnorr::{PublicKeyVarGen, SecretKeyVarGen, SignatureVarGen}; 10 | use ff::Field; 11 | use rand::rngs::StdRng; 12 | use rand::SeedableRng; 13 | 14 | #[test] 15 | fn sign_verify() { 16 | let mut rng = StdRng::seed_from_u64(2321u64); 17 | 18 | let sk = SecretKeyVarGen::random(&mut rng); 19 | let message = BlsScalar::random(&mut rng); 20 | let pk = PublicKeyVarGen::from(&sk); 21 | 22 | let sig = sk.sign(&mut rng, message); 23 | 24 | assert!(pk.verify(&sig, message)); 25 | } 26 | 27 | #[test] 28 | fn test_wrong_keys() { 29 | let mut rng = StdRng::seed_from_u64(2321u64); 30 | 31 | let sk = SecretKeyVarGen::random(&mut rng); 32 | let message = BlsScalar::random(&mut rng); 33 | 34 | let sig = sk.sign(&mut rng, message); 35 | 36 | // Derive random public key 37 | let pk = PublicKeyVarGen::from(&SecretKeyVarGen::random(&mut rng)); 38 | 39 | assert!(!pk.verify(&sig, message)); 40 | } 41 | 42 | #[test] 43 | fn to_from_bytes() { 44 | let mut rng = StdRng::seed_from_u64(2321u64); 45 | 46 | let sk = SecretKeyVarGen::random(&mut rng); 47 | let message = BlsScalar::random(&mut rng); 48 | 49 | let sig = sk.sign(&mut rng, message); 50 | assert_eq!(sig, SignatureVarGen::from_bytes(&sig.to_bytes()).unwrap()); 51 | } 52 | -------------------------------------------------------------------------------- /tests/schnorr_double.rs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | // 5 | // Copyright (c) DUSK NETWORK. All rights reserved. 6 | 7 | use dusk_bls12_381::BlsScalar; 8 | use dusk_bytes::Serializable; 9 | use dusk_schnorr::{PublicKeyDouble, SecretKey, SignatureDouble}; 10 | use ff::Field; 11 | use rand::rngs::StdRng; 12 | use rand::SeedableRng; 13 | 14 | #[test] 15 | fn sign_verify() { 16 | let mut rng = StdRng::seed_from_u64(2321u64); 17 | 18 | let sk = SecretKey::random(&mut rng); 19 | let message = BlsScalar::random(&mut rng); 20 | let pk_double: PublicKeyDouble = sk.into(); 21 | 22 | let sig = sk.sign_double(&mut rng, message); 23 | 24 | assert!(pk_double.verify(&sig, message)); 25 | } 26 | 27 | #[test] 28 | fn test_wrong_keys() { 29 | let mut rng = StdRng::seed_from_u64(2321u64); 30 | 31 | let sk = SecretKey::random(&mut rng); 32 | let message = BlsScalar::random(&mut rng); 33 | 34 | let sig = sk.sign_double(&mut rng, message); 35 | 36 | // Derive random public key 37 | let wrong_sk = SecretKey::random(&mut rng); 38 | let pk_double: PublicKeyDouble = wrong_sk.into(); 39 | 40 | assert!(!pk_double.verify(&sig, message)); 41 | } 42 | 43 | #[test] 44 | fn to_from_bytes() { 45 | let mut rng = StdRng::seed_from_u64(2321u64); 46 | 47 | let sk = SecretKey::random(&mut rng); 48 | let message = BlsScalar::random(&mut rng); 49 | 50 | let sig = sk.sign_double(&mut rng, message); 51 | assert_eq!(sig, SignatureDouble::from_bytes(&sig.to_bytes()).unwrap()); 52 | } 53 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dusk-schnorr" 3 | version = "0.18.0" 4 | edition = "2021" 5 | readme = "README.md" 6 | repository = "https://github.com/dusk-network/schnorr" 7 | keywords = ["cryptography", "schnorr", "zk-snarks", "zero-knowledge", "signatures"] 8 | categories =["algorithms", "cryptography", "mathematics"] 9 | description = "A pure-Rust implementation of Schnorr signatures with a PLONK circuit module additionally" 10 | exclude = [ 11 | ".gitignore", 12 | "Cargo.lock", 13 | ".github/" 14 | ] 15 | license = "MPL-2.0" 16 | 17 | [badges] 18 | maintanance = { status = "depracated" } 19 | 20 | [dependencies] 21 | rand_core = { version = "0.6", default-features = false } 22 | dusk-bytes = "0.1" 23 | dusk-poseidon = { version ="0.33", default-features = false } 24 | dusk-plonk = { version = "0.19", default-features = false } 25 | dusk-bls12_381 = { version = "0.13", default-features = false } 26 | dusk-jubjub = { version = "0.14", default-features = false } 27 | rkyv = { version = "0.7", optional = true, default-features = false } 28 | bytecheck = { version = "0.6", optional = true, default-features = false } 29 | ff = { version = "0.13", default-features = false } 30 | 31 | [dev-dependencies] 32 | rkyv = { version = "0.7", default-features = false, features = ["size_32"] } 33 | criterion = "0.3" 34 | rand = "0.8" 35 | lazy_static = "1.4" 36 | 37 | [[bench]] 38 | name = "signature" 39 | harness = false 40 | 41 | [[bench]] 42 | name = "signature_double" 43 | harness = false 44 | required-features = ["double"] 45 | 46 | [[bench]] 47 | name = "signature_var_generator" 48 | harness = false 49 | required-features = ["var_generator"] 50 | 51 | [features] 52 | default = ["std"] 53 | alloc = ["dusk-bls12_381/alloc", "dusk-plonk/alloc", "dusk-poseidon/alloc"] 54 | std = [ 55 | "alloc", 56 | "dusk-plonk/std", 57 | "rand_core/std" 58 | ] 59 | rkyv-impl = [ 60 | "dusk-jubjub/rkyv-impl", 61 | "rkyv", 62 | "bytecheck", 63 | ] 64 | double = [] 65 | var_generator = [] 66 | 67 | [[test]] 68 | name = "double" 69 | path = "tests/schnorr_double.rs" 70 | required-features = ["double"] 71 | 72 | [[test]] 73 | name = "var_generator" 74 | path = "tests/schnorr_var_generator.rs" 75 | required-features = ["var_generator"] 76 | 77 | [[test]] 78 | name = "gadgets" 79 | path = "tests/gadgets.rs" 80 | required-features = ["alloc"] 81 | 82 | # we use the approach from https://github.com/victe/rust-latex-doc-minimal-example 83 | # to render latex on docs.rs 84 | [package.metadata.docs.rs] 85 | rustdoc-args = [ "--html-in-header", "./katex-header.html" ] 86 | -------------------------------------------------------------------------------- /benches/signature.rs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | // 5 | // Copyright (c) DUSK NETWORK. All rights reserved. 6 | 7 | use criterion::{criterion_group, criterion_main, Criterion}; 8 | 9 | use dusk_schnorr::{gadgets, PublicKey, SecretKey, Signature}; 10 | use ff::Field; 11 | use rand::rngs::StdRng; 12 | use rand::SeedableRng; 13 | 14 | use dusk_plonk::prelude::Error as PlonkError; 15 | use dusk_plonk::prelude::*; 16 | 17 | const CAPACITY: usize = 13; 18 | 19 | lazy_static::lazy_static! { 20 | pub static ref PP: PublicParameters = { 21 | let rng = &mut StdRng::seed_from_u64(2321u64); 22 | 23 | PublicParameters::setup(1 << CAPACITY, rng) 24 | .expect("Failed to generate PP") 25 | }; 26 | } 27 | 28 | static mut CONSTRAINTS: usize = 0; 29 | static LABEL: &[u8; 12] = b"dusk-network"; 30 | 31 | fn bench_prover(rng: &mut StdRng, prover: &Prover, circuit: &C) 32 | where 33 | C: Circuit, 34 | { 35 | prover 36 | .prove(rng, circuit) 37 | .expect("proof creation of valid circuit should succeed"); 38 | } 39 | 40 | #[derive(Debug, Default)] 41 | struct SignatureCircuit { 42 | signature: Signature, 43 | pk: PublicKey, 44 | message: BlsScalar, 45 | } 46 | 47 | impl SignatureCircuit { 48 | pub fn valid(rng: &mut StdRng) -> Self { 49 | let sk = SecretKey::random(rng); 50 | let message = BlsScalar::random(&mut *rng); 51 | let signature = sk.sign(rng, message); 52 | 53 | let pk = PublicKey::from(&sk); 54 | 55 | Self { 56 | signature, 57 | pk, 58 | message, 59 | } 60 | } 61 | } 62 | 63 | impl Circuit for SignatureCircuit { 64 | fn circuit(&self, composer: &mut Composer) -> Result<(), PlonkError> { 65 | let (u, r) = self.signature.append(composer); 66 | 67 | let pk = composer.append_point(self.pk.as_ref()); 68 | let m = composer.append_witness(self.message); 69 | 70 | let _result = gadgets::verify_signature(composer, u, r, pk, m); 71 | 72 | unsafe { 73 | CONSTRAINTS = composer.constraints(); 74 | } 75 | 76 | Ok(()) 77 | } 78 | } 79 | 80 | fn proof_creation_signature(c: &mut Criterion) { 81 | let mut rng = &mut StdRng::seed_from_u64(0xbeef); 82 | 83 | // We compile the circuit using the public parameters PP 84 | let (prover, _verifier) = Compiler::compile::(&PP, LABEL) 85 | .expect("circuit should compile"); 86 | 87 | let circuit = SignatureCircuit::valid(&mut rng); 88 | 89 | // We benchmark the prover 90 | unsafe { 91 | let log = 92 | &format!("Signature proof creation ({} constraints)", CONSTRAINTS); 93 | c.bench_function(log, |b| { 94 | b.iter(|| bench_prover(&mut rng, &prover, &circuit)) 95 | }); 96 | } 97 | } 98 | 99 | criterion_group! { 100 | name = schnorr; 101 | config = Criterion::default().sample_size(10); 102 | targets = proof_creation_signature, 103 | } 104 | criterion_main!(schnorr); 105 | -------------------------------------------------------------------------------- /benches/signature_double.rs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | // 5 | // Copyright (c) DUSK NETWORK. All rights reserved. 6 | 7 | use criterion::{criterion_group, criterion_main, Criterion}; 8 | 9 | use dusk_schnorr::{gadgets, PublicKeyDouble, SecretKey, SignatureDouble}; 10 | use ff::Field; 11 | use rand::rngs::StdRng; 12 | use rand::SeedableRng; 13 | 14 | use dusk_plonk::prelude::Error as PlonkError; 15 | use dusk_plonk::prelude::*; 16 | 17 | const CAPACITY: usize = 13; 18 | 19 | lazy_static::lazy_static! { 20 | pub static ref PP: PublicParameters = { 21 | let rng = &mut StdRng::seed_from_u64(2321u64); 22 | 23 | PublicParameters::setup(1 << CAPACITY, rng) 24 | .expect("Failed to generate PP") 25 | }; 26 | } 27 | 28 | static mut CONSTRAINTS: usize = 0; 29 | static LABEL: &[u8; 12] = b"dusk-network"; 30 | 31 | fn bench_prover(rng: &mut StdRng, prover: &Prover, circuit: &C) 32 | where 33 | C: Circuit, 34 | { 35 | prover 36 | .prove(rng, circuit) 37 | .expect("proof creation of valid circuit should succeed"); 38 | } 39 | 40 | #[derive(Debug, Default)] 41 | struct SigDoubleCircuit { 42 | signature: SignatureDouble, 43 | pk: PublicKeyDouble, 44 | message: BlsScalar, 45 | } 46 | 47 | impl SigDoubleCircuit { 48 | pub fn valid(rng: &mut StdRng) -> Self { 49 | let sk = SecretKey::random(rng); 50 | let message = BlsScalar::random(&mut *rng); 51 | let signature = sk.sign_double(rng, message); 52 | 53 | let pk = PublicKeyDouble::from(&sk); 54 | 55 | Self { 56 | signature, 57 | pk, 58 | message, 59 | } 60 | } 61 | } 62 | 63 | impl Circuit for SigDoubleCircuit { 64 | fn circuit(&self, composer: &mut Composer) -> Result<(), PlonkError> { 65 | let (u, r, r_p) = self.signature.append(composer); 66 | 67 | let pk = composer.append_point(self.pk.pk()); 68 | let pk_p = composer.append_point(self.pk.pk_prime()); 69 | let m = composer.append_witness(self.message); 70 | 71 | gadgets::verify_signature_double(composer, u, r, r_p, pk, pk_p, m) 72 | .expect("this is infallible"); 73 | 74 | unsafe { 75 | CONSTRAINTS = composer.constraints(); 76 | } 77 | 78 | Ok(()) 79 | } 80 | } 81 | 82 | fn proof_creation_signature_double(c: &mut Criterion) { 83 | let mut rng = &mut StdRng::seed_from_u64(0xbeef); 84 | 85 | // We compile the circuit using the public parameters PP 86 | let (prover, _verifier) = Compiler::compile::(&PP, LABEL) 87 | .expect("circuit should compile"); 88 | 89 | let circuit = SigDoubleCircuit::valid(&mut rng); 90 | 91 | // We benchmark the prover 92 | unsafe { 93 | let log = &format!( 94 | "Signature double proof creation ({} constraints)", 95 | CONSTRAINTS 96 | ); 97 | c.bench_function(log, |b| { 98 | b.iter(|| bench_prover(&mut rng, &prover, &circuit)) 99 | }); 100 | } 101 | } 102 | 103 | criterion_group! { 104 | name = schnorr; 105 | config = Criterion::default().sample_size(10); 106 | targets = proof_creation_signature_double, 107 | } 108 | criterion_main!(schnorr); 109 | -------------------------------------------------------------------------------- /benches/signature_var_generator.rs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | // 5 | // Copyright (c) DUSK NETWORK. All rights reserved. 6 | 7 | use criterion::{criterion_group, criterion_main, Criterion}; 8 | 9 | use dusk_schnorr::{ 10 | gadgets, PublicKeyVarGen, SecretKeyVarGen, SignatureVarGen, 11 | }; 12 | use ff::Field; 13 | use rand::rngs::StdRng; 14 | use rand::SeedableRng; 15 | 16 | use dusk_plonk::prelude::Error as PlonkError; 17 | use dusk_plonk::prelude::*; 18 | 19 | const CAPACITY: usize = 13; 20 | 21 | lazy_static::lazy_static! { 22 | pub static ref PP: PublicParameters = { 23 | let rng = &mut StdRng::seed_from_u64(2321u64); 24 | 25 | PublicParameters::setup(1 << CAPACITY, rng) 26 | .expect("Failed to generate PP") 27 | }; 28 | } 29 | 30 | static mut CONSTRAINTS: usize = 0; 31 | static LABEL: &[u8; 12] = b"dusk-network"; 32 | 33 | fn bench_prover(rng: &mut StdRng, prover: &Prover, circuit: &C) 34 | where 35 | C: Circuit, 36 | { 37 | prover 38 | .prove(rng, circuit) 39 | .expect("proof creation of valid circuit should succeed"); 40 | } 41 | 42 | #[derive(Debug, Default)] 43 | struct SigVarGenCircuit { 44 | signature: SignatureVarGen, 45 | pk: PublicKeyVarGen, 46 | message: BlsScalar, 47 | } 48 | 49 | impl SigVarGenCircuit { 50 | pub fn valid(rng: &mut StdRng) -> Self { 51 | let sk = SecretKeyVarGen::random(rng); 52 | let message = BlsScalar::random(&mut *rng); 53 | let signature = sk.sign(rng, message); 54 | 55 | let pk = PublicKeyVarGen::from(&sk); 56 | 57 | Self { 58 | signature, 59 | pk, 60 | message, 61 | } 62 | } 63 | } 64 | 65 | impl Circuit for SigVarGenCircuit { 66 | fn circuit(&self, composer: &mut Composer) -> Result<(), PlonkError> { 67 | let (u, r) = self.signature.append(composer); 68 | 69 | let pk = composer.append_point(self.pk.public_key()); 70 | let generator = composer.append_point(self.pk.generator()); 71 | let m = composer.append_witness(self.message); 72 | 73 | let _result = 74 | gadgets::verify_signature_var_gen(composer, u, r, pk, generator, m); 75 | 76 | unsafe { 77 | CONSTRAINTS = composer.constraints(); 78 | } 79 | 80 | Ok(()) 81 | } 82 | } 83 | 84 | fn proof_creation_signature_var_generation(c: &mut Criterion) { 85 | let mut rng = &mut StdRng::seed_from_u64(0xbeef); 86 | 87 | // We compile the circuit using the public parameters PP 88 | let (prover, _verifier) = Compiler::compile::(&PP, LABEL) 89 | .expect("circuit should compile"); 90 | 91 | let circuit = SigVarGenCircuit::valid(&mut rng); 92 | 93 | // We benchmark the prover 94 | unsafe { 95 | let log = &format!( 96 | "Signature variable generator proof creation {} constraints)", 97 | CONSTRAINTS 98 | ); 99 | c.bench_function(log, |b| { 100 | b.iter(|| bench_prover(&mut rng, &prover, &circuit)) 101 | }); 102 | } 103 | } 104 | 105 | criterion_group! { 106 | name = schnorr; 107 | config = Criterion::default().sample_size(10); 108 | targets = proof_creation_signature_var_generation, 109 | } 110 | criterion_main!(schnorr); 111 | -------------------------------------------------------------------------------- /tests/keys.rs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | // 5 | // Copyright (c) DUSK NETWORK. All rights reserved. 6 | 7 | use dusk_jubjub::{JubJubAffine, JubJubExtended, JubJubScalar}; 8 | use dusk_schnorr::{PublicKey, SecretKey}; 9 | use rand_core::OsRng; 10 | 11 | #[cfg(feature = "double")] 12 | use dusk_schnorr::PublicKeyDouble; 13 | 14 | #[cfg(feature = "var_generator")] 15 | use dusk_schnorr::{PublicKeyVarGen, SecretKeyVarGen}; 16 | 17 | #[test] 18 | #[allow(clippy::eq_op)] 19 | fn partial_eq_pk() { 20 | let sk1 = SecretKey::random(&mut OsRng); 21 | let sk2 = SecretKey::random(&mut OsRng); 22 | 23 | assert_ne!(sk1, sk2); 24 | 25 | let pk1 = PublicKey::from(&sk1); 26 | let pk2 = PublicKey::from(&sk2); 27 | 28 | assert_eq!(pk1, pk1); 29 | assert_ne!(pk1, pk2); 30 | 31 | // With all coordinates being different the points are the same ie. 32 | // equality holds using this technique. 33 | let s = ( 34 | JubJubScalar::from(2u64), 35 | JubJubScalar::from(7u64), 36 | JubJubScalar::from(4u64), 37 | JubJubScalar::from(5u64), 38 | JubJubScalar::from(567758785u64), 39 | ); 40 | 41 | let left: JubJubExtended = dusk_jubjub::GENERATOR_EXTENDED * s.0 42 | + dusk_jubjub::GENERATOR_EXTENDED * s.1; 43 | 44 | let right: JubJubExtended = dusk_jubjub::GENERATOR_EXTENDED * s.2 45 | + dusk_jubjub::GENERATOR_EXTENDED * s.3; 46 | 47 | let wrong: JubJubExtended = dusk_jubjub::GENERATOR_EXTENDED * s.2 48 | + dusk_jubjub::GENERATOR_EXTENDED * s.4; 49 | 50 | // Assert none of the extended points coordinates actually matches even 51 | // though the points in affine version are the same 52 | assert_ne!(left.get_u(), right.get_u()); 53 | assert_ne!(left.get_v(), right.get_v()); 54 | assert_ne!(left.get_z(), right.get_z()); 55 | 56 | assert_eq!(JubJubAffine::from(right), JubJubAffine::from(left)); 57 | 58 | assert_eq!(PublicKey::from(left), PublicKey::from(right)); 59 | assert_ne!(PublicKey::from(left), PublicKey::from(wrong)) 60 | } 61 | 62 | #[test] 63 | #[cfg(feature = "double")] 64 | fn partial_eq_pk_double() { 65 | let sk1 = SecretKey::random(&mut OsRng); 66 | let sk2 = SecretKey::random(&mut OsRng); 67 | 68 | assert_ne!(sk1, sk2); 69 | 70 | let pk1 = PublicKeyDouble::from(&sk1); 71 | let pk2 = PublicKeyDouble::from(&sk2); 72 | 73 | assert_eq!(pk1, pk1); 74 | assert_ne!(pk1, pk2); 75 | } 76 | 77 | #[test] 78 | #[cfg(feature = "var_generator")] 79 | fn partial_eq_pk_var_gen() { 80 | let sk1 = SecretKeyVarGen::random(&mut OsRng); 81 | let sk2 = SecretKeyVarGen::random(&mut OsRng); 82 | 83 | assert_ne!(sk1, sk2); 84 | 85 | let pk1 = PublicKeyVarGen::from(&sk1); 86 | let pk2 = PublicKeyVarGen::from(&sk2); 87 | 88 | assert_eq!(pk1, pk1); 89 | assert_ne!(pk1, pk2); 90 | 91 | // With all coordinates being different the points are the same ie. 92 | // equality holds using this technique. 93 | let s = ( 94 | JubJubScalar::from(2u64), 95 | JubJubScalar::from(7u64), 96 | JubJubScalar::from(4u64), 97 | JubJubScalar::from(5u64), 98 | ); 99 | 100 | let left: JubJubExtended = dusk_jubjub::GENERATOR_EXTENDED * s.0 101 | + dusk_jubjub::GENERATOR_EXTENDED * s.1; 102 | 103 | let right: JubJubExtended = dusk_jubjub::GENERATOR_EXTENDED * s.2 104 | + dusk_jubjub::GENERATOR_EXTENDED * s.3; 105 | 106 | // Assert none of the extended points coordinates actually matches even 107 | // though the points in affine version are the same 108 | assert_ne!(left.get_u(), right.get_u()); 109 | assert_ne!(left.get_v(), right.get_v()); 110 | assert_ne!(left.get_z(), right.get_z()); 111 | assert_eq!(JubJubAffine::from(right), JubJubAffine::from(left)); 112 | 113 | // construct two different generator points 114 | let var_gen = dusk_jubjub::GENERATOR_EXTENDED * JubJubScalar::from(42u64); 115 | let wrong_var_gen = 116 | dusk_jubjub::GENERATOR_EXTENDED * JubJubScalar::from(4242u64); 117 | assert_ne!(var_gen, wrong_var_gen); 118 | 119 | assert_eq!( 120 | PublicKeyVarGen::from_raw_unchecked(left, var_gen), 121 | PublicKeyVarGen::from_raw_unchecked(right, var_gen) 122 | ); 123 | assert_ne!( 124 | PublicKeyVarGen::from_raw_unchecked(left, var_gen), 125 | PublicKeyVarGen::from_raw_unchecked(left, wrong_var_gen) 126 | ) 127 | } 128 | -------------------------------------------------------------------------------- /src/gadgets.rs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | // 5 | // Copyright (c) DUSK NETWORK. All rights reserved. 6 | 7 | //! # Schnorr Signature Gadgets 8 | //! 9 | //! This module provides Plonk gadgets for verification of Schnorr signatures. 10 | 11 | use dusk_jubjub::GENERATOR_EXTENDED; 12 | use dusk_poseidon::sponge; 13 | 14 | #[cfg(feature = "double")] 15 | use dusk_jubjub::GENERATOR_NUMS_EXTENDED; 16 | 17 | use dusk_plonk::prelude::*; 18 | 19 | /// Verifies a single-key Schnorr signature [`Signature`]within a Plonk circuit 20 | /// without requiring the secret key as a witness. 21 | /// 22 | /// The function performs Schnorr verification by calculating the challenge and 23 | /// confirming the signature equation. 24 | /// 25 | /// # Feature 26 | /// 27 | /// Only available with the "alloc" feature enabled. 28 | /// 29 | /// ### Parameters 30 | /// 31 | /// - `composer`: A mutable reference to the Plonk [`Composer`]`. 32 | /// - `u`: Witness for the random nonce used during signature generation. 33 | /// - `r`: Witness Point representing the nonce point `r = u*G`. 34 | /// - `pk`: Witness Point representing the public key `pk = sk*G`. 35 | /// - `msg`: Witness for the message. 36 | /// 37 | /// ### Returns 38 | /// 39 | /// - `Result<(), Error>`: Returns an empty `Result` on successful gadget 40 | /// creation or an `Error` if the witness `u` is not a valid [`JubJubScalar`]. 41 | /// 42 | /// ### Errors 43 | /// 44 | /// This function will return an `Error` if the witness `u` is not a valid 45 | /// [`JubJubScalar`]. 46 | /// 47 | /// [`Signature`]: [`crate::Signature`] 48 | pub fn verify_signature( 49 | composer: &mut Composer, 50 | u: Witness, 51 | r: WitnessPoint, 52 | pk: WitnessPoint, 53 | msg: Witness, 54 | ) -> Result<(), Error> { 55 | let r_x = *r.x(); 56 | let r_y = *r.y(); 57 | 58 | let challenge = [r_x, r_y, msg]; 59 | let challenge_hash = sponge::truncated::gadget(composer, &challenge); 60 | 61 | let s_a = composer.component_mul_generator(u, GENERATOR_EXTENDED)?; 62 | let s_b = composer.component_mul_point(challenge_hash, pk); 63 | let point = composer.component_add_point(s_a, s_b); 64 | 65 | composer.assert_equal_point(r, point); 66 | 67 | Ok(()) 68 | } 69 | 70 | /// Verifies a [`SignatureDouble`] within a Plonk circuit without requiring 71 | /// the secret key as a witness. 72 | /// 73 | /// # Feature 74 | /// 75 | /// Only available with the "double" and "alloc" features enabled. 76 | /// 77 | /// ### Parameters 78 | /// 79 | /// - `composer`: A mutable reference to the Plonk [`Composer`]. 80 | /// - `u`: Witness for the random nonce used during signature generation. 81 | /// - `r`: Witness Point representing the nonce points `R = u*G` 82 | /// - `r_p`: Witness Point representing the nonce points `R' = u*G'`. 83 | /// - `pk`: Witness Point public key `PK = sk*G` 84 | /// - `pk_p`: Witness Point public key `PK' = sk*G'` 85 | /// - `msg`: Witness for the message. 86 | /// 87 | /// ### Returns 88 | /// 89 | /// - `Result<(), Error>`: Returns an empty `Result` on successful gadget 90 | /// creation or an `Error` if the witness `u` is not a valid [`JubJubScalar`]. 91 | /// 92 | /// ### Errors 93 | /// 94 | /// This function will return an `Error` if the witness `u` is not a valid 95 | /// [`JubJubScalar`]. 96 | /// 97 | /// [`SignatureDouble`]: [`crate::SignatureDouble`] 98 | #[cfg(feature = "double")] 99 | pub fn verify_signature_double( 100 | composer: &mut Composer, 101 | u: Witness, 102 | r: WitnessPoint, 103 | r_p: WitnessPoint, 104 | pk: WitnessPoint, 105 | pk_p: WitnessPoint, 106 | msg: Witness, 107 | ) -> Result<(), Error> { 108 | let r_x = *r.x(); 109 | let r_y = *r.y(); 110 | 111 | let r_p_x = *r_p.x(); 112 | let r_p_y = *r_p.y(); 113 | 114 | let challenge = [r_x, r_y, r_p_x, r_p_y, msg]; 115 | let challenge_hash = sponge::truncated::gadget(composer, &challenge); 116 | 117 | let s_a = composer.component_mul_generator(u, GENERATOR_EXTENDED)?; 118 | let s_b = composer.component_mul_point(challenge_hash, pk); 119 | let point = composer.component_add_point(s_a, s_b); 120 | 121 | let s_p_a = composer.component_mul_generator(u, GENERATOR_NUMS_EXTENDED)?; 122 | let s_p_b = composer.component_mul_point(challenge_hash, pk_p); 123 | let point_p = composer.component_add_point(s_p_a, s_p_b); 124 | 125 | composer.assert_equal_point(r, point); 126 | composer.assert_equal_point(r_p, point_p); 127 | 128 | Ok(()) 129 | } 130 | 131 | /// Verifies a Schnorr signature with variable generator [`SignatureVarGen`] 132 | /// within a Plonk circuit without requiring the secret key as a witness. 133 | /// 134 | /// The function performs Schnorr verification by calculating the challenge and 135 | /// confirming the signature equation. 136 | /// 137 | /// # Feature 138 | /// 139 | /// Only available with the "var_generator" and "alloc" features enabled. 140 | /// 141 | /// ### Parameters 142 | /// 143 | /// - `composer`: A mutable reference to the Plonk [`Composer`]`. 144 | /// - `u`: Witness for the random nonce used during signature generation. 145 | /// - `r`: Witness Point representing the nonce point `r = u*G`. 146 | /// - `pk`: Witness Point representing the public key `pk = sk*G`. 147 | /// - `gen`: Witness Point representing the variable generator `G` 148 | /// - `msg`: Witness for the message. 149 | /// 150 | /// ### Returns 151 | /// 152 | /// - `Result<(), Error>`: Returns an empty `Result` on successful gadget 153 | /// creation or an `Error` if the witness `u` is not a valid [`JubJubScalar`]. 154 | /// 155 | /// ### Errors 156 | /// 157 | /// This function will return an `Error` if the witness `u` is not a valid 158 | /// [`JubJubScalar`]. 159 | /// 160 | /// [`SignatureVarGen`]: [`crate::SignatureVarGen`] 161 | #[cfg(feature = "var_generator")] 162 | pub fn verify_signature_var_gen( 163 | composer: &mut Composer, 164 | u: Witness, 165 | r: WitnessPoint, 166 | pk: WitnessPoint, 167 | gen: WitnessPoint, 168 | msg: Witness, 169 | ) -> Result<(), Error> { 170 | let r_x = *r.x(); 171 | let r_y = *r.y(); 172 | 173 | let challenge = [r_x, r_y, msg]; 174 | let challenge_hash = sponge::truncated::gadget(composer, &challenge); 175 | 176 | // TODO: check whether we need to append the generator as a constant 177 | let s_a = composer.component_mul_point(u, gen); 178 | let s_b = composer.component_mul_point(challenge_hash, pk); 179 | let point = composer.component_add_point(s_a, s_b); 180 | 181 | composer.assert_equal_point(r, point); 182 | 183 | Ok(()) 184 | } 185 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dusk-schnorr 2 | ![Build Status](https://github.com/dusk-network/schnorr/workflows/Continuous%20integration/badge.svg) 3 | [![Repository](https://img.shields.io/badge/github-schnorr-blueviolet?logo=github)](https://github.com/dusk-network/schnorr) 4 | [![Documentation](https://img.shields.io/badge/docs-schnorr-blue?logo=rust)](https://docs.rs/schnorr/) 5 | 6 | # Disclaimer 7 | **This crate is not in active development anymore, use [jubjub-schorr](https://github.com/dusk-network/jubjub-schnorr) instead.** 8 | 9 | --- 10 | 11 | This crate provides a Rust implementation of the Schnorr signature scheme for the JubJub elliptic curve group, using the Poseidon hash function. This implementation is designed by the [Dusk](https://dusk.network) team. 12 | 13 | ## About 14 | The Schnorr signature scheme, named after its creator Claus Schnorr, is a digital signature scheme renowned for its simplicity. The scheme provides a simple method of creating short signatures. 15 | 16 | The implementation has been created using the [`jubjub`](https://github.com/dusk-network/jubjub) elliptic curve and the [`Poseidon`](https://github.com/dusk-network/Poseidon252) hash function, the paper for which can be found [here](https://eprint.iacr.org/2019/458.pdf). 17 | 18 | The signature scheme is implemented within the [Phoenix](https://github.com/dusk-network/phoenix-core/blob/master/docs/protocol-description.pdf) transaction model and is based on the Schnorr Sigma protocol, compiled alongside the Fiat–Shamir transformation, to serve as a non-interactive signature scheme. Specifically, the Phoenix protocol employs a variant that utilizes double Schnorr signatures, verifiable with double public keys, enabling the delegation of computational processes within the protocol's later stages. 19 | 20 | ## Library Structure 21 | The library is partitioned into the following components: 22 | 23 | - **Keys**: Module containing the secret key structure for signing messages, as well as the public key and the double public key structures used in verification. 24 | - **Signatures**: Module containing the standard and double signature structs as well as functions to verify the validity of Schnorr signatures and double Schnorr signatures. 25 | - **Gadgets**: Contains the Plonk gadgets for in-circuit verification of Schnorr signatures and double Schnorr Signatures. 26 | 27 | ## Signature Scheme Description 28 | 29 | ### Notation 30 | 31 | In the following: 32 | - Multiplication of a point $P$ by a scalar $s$ stands for adding $P$ $s$-times to itself. 33 | - $\mathbb{F}_q$ is the prime finite field of order $q$ 34 | - for a prime $q$: $\mathbb{F}_q^× = \mathbb{F}_q \setminus 0$ contains all nonzero elements of $\mathbb{F}_q$. 35 | 36 | ### Single Signature 37 | 38 | #### Setup 39 | 40 | In this library we implement our Schnorr signature scheme on the jubjub elliptic curve, specifically we have: 41 | - a finite field $\mathbb{F}_q$ over prime $q$, in this implementation this field corresponds to the scalar field of the elliptic curve BLS12-381 42 | - an elliptic curve $E / \mathbb{F}_q$, in our case this is the jubjub elliptic curve 43 | - a subgroup $\mathbb{G} \in E(\mathbb{F}_q)$ of curve points, with prime order $p$ 44 | - a fixed generator point $G \in \mathbb{G}$ 45 | - a cryptographic hash function $H : \{0 , 1\}^∗ \rightarrow \mathbb{F}_p$ where $\mathbb{F}_p$ is the scalar field of the jubjub elliptic curve. 46 | 47 | #### Key generation 48 | 49 | - Choose a private signing key, $sk \in \mathbb{F}_p^×$. 50 | - The public verification key is $PK = skG \in \mathbb{G}$. 51 | 52 | #### Signing 53 | 54 | To sign a message $m \in \mathbb{F}_q^×$: 55 | 56 | - Choose a random private nonce $r \in \mathbb{F}_p^×$. 57 | - Compute nonce point $R = rG \in \mathbb{G}$. 58 | - Compute challenge hash $c = H(R \parallel m) \in \mathbb{F}_p$ where $\parallel$ denotes concatenation and $R$ is represented as a bit string. 59 | - Compute $u = r − sk \cdot c \in \mathbb{F}_p$. 60 | 61 | The signature is the tuple $(u, R) \in \mathbb{F}_p \times \mathbb{G}$. 62 | 63 | #### Verifying 64 | 65 | - Compute challenge hash $c = H(R \parallel m) \in \mathbb{F}_p$. 66 | - Verify that $uG + cPK = R$. 67 | 68 | If the signature was signed with the secret key corresponding to $PK$, this will hold true, since: 69 | 70 | $$ 71 | uG + cPK = (r - sk\cdot c)G + (sk\cdot c)G = (r - sk\cdot c + sk\cdot c)G = rG = R 72 | $$ 73 | 74 | ### Double Signature 75 | 76 | #### Setup 77 | 78 | Same as in the single signature above with the addition of another generator point $G' \in \mathbb{G}$, that is different from $G$ and whose discrete logarithm relation with $G$ is unknown. 79 | 80 | #### Key generation 81 | 82 | - Choose a private signing key, $sk \in \mathbb{F}_p^×$. 83 | - The public verification key is the tuple $(PK, PK')$ with $PK = skG \in \mathbb{G}$ and $PK' = skG' \in \mathbb{G}$. 84 | 85 | #### Signing 86 | 87 | To sign a message $m \in \mathbb{F}_q^×$: 88 | 89 | - Choose a random private nonce $r \in \mathbb{F}_p^×$. 90 | - Compute nonce points $R = rG \in \mathbb{G}$ and $R' = rG' \in \mathbb{G}$. 91 | - Compute challenge hash $c = H(R \parallel R' \parallel m) \in \mathbb{F}_p$ where $\parallel$ denotes concatenation and $R, R'$ are represented as a bit strings. 92 | - Compute $u = r − sk \cdot c \in \mathbb{F}_p$. 93 | 94 | The signature is the tuple $(u, R, R') \in \mathbb{F}_p \times \mathbb{G} \times \mathbb{G}$. 95 | 96 | #### Verifying 97 | 98 | - Compute challenge hash $c = H(R \parallel R' \parallel m) \in \mathbb{F}_p$. 99 | - Verify that $rG + cPK = R$ and $uG' + cPK' = R'$. 100 | 101 | If the signature was signed with the correct private key, this should hold true because: 102 | 103 | $$ 104 | uG + cPK = (r - sk\cdot c)G + (sk\cdot c)G = (r - sk\cdot c + sk\cdot c)G = rG = R 105 | $$ 106 | 107 | and 108 | 109 | $$ 110 | uG' + cPK' = (r - sk\cdot c)G' + (sk\cdot c)G' = (r - sk\cdot c + sk\cdot c)G' = rG' = R' 111 | $$ 112 | 113 | 114 | ### Notes on Security and Implementation 115 | 116 | The implemented signature scheme is existentially unforgeable under chosen-message attacks assuming the hardness of the discrete logarithm problem in the random oracle model. This property is detailed in Section 12.5.1 of Katz and Lindell's Introduction to Modern Cryptography. 117 | 118 | While the basic Schnorr signature scheme is a widely recognized construct, the double-key variant as employed by Phoenix is a novel introduction. In the context of the transaction protocol, this allows for the delegation of proof computations without compromising the confidentiality of the signer's secret key. 119 | 120 | ## Usage 121 | To integrate the `dusk-schnorr` crate into your project, add it with the following command: 122 | ```bash 123 | cargo add dusk-schnorr 124 | ``` 125 | 126 | A basic example demonstrating how to generate and verify a Schnorr signature: 127 | ```rust 128 | use dusk_bls12_381::BlsScalar; 129 | use dusk_schnorr::{SecretKey, PublicKey}; 130 | use rand::rngs::StdRng; 131 | use rand::SeedableRng; 132 | use ff::Field; 133 | 134 | fn main() { 135 | // Setup 136 | let mut rng = StdRng::seed_from_u64(1234u64); 137 | let message = BlsScalar::random(&mut rng); 138 | 139 | // Key generation 140 | let sk = SecretKey::random(&mut rng); 141 | 142 | // Standard Dusk-Schnorr signature scheme: 143 | let pk = PublicKey::from(&sk); 144 | let signature = sk.sign(&mut rng, message); 145 | assert!(pk.verify(&signature, message), "The signature should be valid."); 146 | 147 | // Double Dusk-Schnorr signature scheme: 148 | #[cfg(features = "double")] 149 | { 150 | let pk = dusk_schnorr::PublicKeyDouble::from(&sk); 151 | let signature = sk.sign_double(&mut rng, message); 152 | assert!(pk.verify(&signature, message), "The signature should be valid."); 153 | } 154 | 155 | // Dusk-Schnorr signature scheme with variable generator: 156 | #[cfg(features = "var_generator")] 157 | { 158 | let generator = dusk_jubjub::GENERATOR_EXTENDED * JubJubScalar::from(42u64); 159 | let sk = sk.with_variable_generator(generator); 160 | let pk = dusk_schnorr::PublicKeyVarGen::from(&sk); 161 | let signature = sk.sign(&mut rng, message); 162 | assert!(pk.verify(&signature, message), "The signature should be valid."); 163 | } 164 | } 165 | ``` 166 | 167 | ## Licensing 168 | This Source Code Form is subject to the terms of the Mozilla Public 169 | License, v. 2.0. If a copy of the MPL was not distributed with this 170 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 171 | 172 | Copyright (c) DUSK NETWORK. All rights reserved. 173 | -------------------------------------------------------------------------------- /tests/gadgets.rs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | // 5 | // Copyright (c) DUSK NETWORK. All rights reserved. 6 | 7 | use dusk_plonk::prelude::Error as PlonkError; 8 | use dusk_schnorr::{gadgets, PublicKey, SecretKey, Signature}; 9 | use ff::Field; 10 | use rand::rngs::StdRng; 11 | use rand::SeedableRng; 12 | 13 | use dusk_plonk::prelude::*; 14 | 15 | #[cfg(feature = "double")] 16 | use dusk_schnorr::{PublicKeyDouble, SignatureDouble}; 17 | 18 | #[cfg(feature = "var_generator")] 19 | use dusk_schnorr::{PublicKeyVarGen, SecretKeyVarGen, SignatureVarGen}; 20 | 21 | lazy_static::lazy_static! { 22 | pub static ref PP: PublicParameters = { 23 | let rng = &mut StdRng::seed_from_u64(2321u64); 24 | 25 | PublicParameters::setup(1 << 13, rng) 26 | .expect("Failed to generate PP") 27 | }; 28 | } 29 | 30 | const LABEL: &[u8] = b"dusk-network"; 31 | 32 | // 33 | // Test verify_signature 34 | // 35 | #[derive(Debug, Default)] 36 | struct SignatureCircuit { 37 | signature: Signature, 38 | pk: PublicKey, 39 | message: BlsScalar, 40 | } 41 | 42 | impl SignatureCircuit { 43 | pub fn valid_random(rng: &mut StdRng) -> Self { 44 | let sk = SecretKey::random(rng); 45 | let message = BlsScalar::random(&mut *rng); 46 | let signature = sk.sign(rng, message); 47 | 48 | let pk = PublicKey::from(&sk); 49 | 50 | Self { 51 | signature, 52 | pk, 53 | message, 54 | } 55 | } 56 | 57 | pub fn invalid_random(rng: &mut StdRng) -> Self { 58 | let sk = SecretKey::random(rng); 59 | let message = BlsScalar::random(&mut *rng); 60 | let signature = sk.sign(rng, message); 61 | 62 | let sk_wrong = SecretKey::random(rng); 63 | let pk = PublicKey::from(&sk_wrong); 64 | 65 | Self { 66 | signature, 67 | pk, 68 | message, 69 | } 70 | } 71 | } 72 | 73 | impl Circuit for SignatureCircuit { 74 | fn circuit(&self, composer: &mut Composer) -> Result<(), PlonkError> { 75 | let (u, r) = self.signature.append(composer); 76 | 77 | let pk = composer.append_point(self.pk.as_ref()); 78 | let msg = composer.append_witness(self.message); 79 | 80 | gadgets::verify_signature(composer, u, r, pk, msg)?; 81 | 82 | Ok(()) 83 | } 84 | } 85 | 86 | #[test] 87 | fn verify_signature() { 88 | let mut rng = StdRng::seed_from_u64(0xfeeb); 89 | 90 | // Create prover and verifier circuit description 91 | let (prover, verifier) = Compiler::compile::(&PP, LABEL) 92 | .expect("Circuit should compile successfully"); 93 | 94 | // 95 | // Check valid circuit verifies 96 | let circuit = SignatureCircuit::valid_random(&mut rng); 97 | 98 | let (proof, _) = prover 99 | .prove(&mut rng, &circuit) 100 | .expect("Proving the circuit should be successful"); 101 | 102 | let pub_inputs = vec![]; 103 | verifier 104 | .verify(&proof, &pub_inputs) 105 | .expect("Verification should be successful"); 106 | 107 | // 108 | // Check proof creation of invalid circuit not possible 109 | let circuit = SignatureCircuit::invalid_random(&mut rng); 110 | 111 | prover 112 | .prove(&mut rng, &circuit) 113 | .expect_err("Proving invalid circuit shouldn't be possible"); 114 | } 115 | 116 | // 117 | // Test verify_signature_double 118 | // 119 | #[derive(Debug, Default)] 120 | #[cfg(feature = "double")] 121 | struct SignatureDoubleCircuit { 122 | signature: SignatureDouble, 123 | pk_double: PublicKeyDouble, 124 | message: BlsScalar, 125 | } 126 | 127 | #[cfg(feature = "double")] 128 | impl SignatureDoubleCircuit { 129 | pub fn valid_random(rng: &mut StdRng) -> Self { 130 | let sk = SecretKey::random(rng); 131 | let message = BlsScalar::random(&mut *rng); 132 | let signature = sk.sign_double(rng, message); 133 | 134 | let pk_double = PublicKeyDouble::from(&sk); 135 | 136 | Self { 137 | signature, 138 | pk_double, 139 | message, 140 | } 141 | } 142 | 143 | pub fn invalid_random(rng: &mut StdRng) -> Self { 144 | let sk = SecretKey::random(rng); 145 | let message = BlsScalar::random(&mut *rng); 146 | let signature = sk.sign_double(rng, message); 147 | 148 | let sk_wrong = SecretKey::random(rng); 149 | let pk_double = PublicKeyDouble::from(&sk_wrong); 150 | 151 | Self { 152 | signature, 153 | pk_double, 154 | message, 155 | } 156 | } 157 | } 158 | 159 | #[cfg(feature = "double")] 160 | impl Circuit for SignatureDoubleCircuit { 161 | fn circuit(&self, composer: &mut Composer) -> Result<(), PlonkError> { 162 | let (u, r, r_p) = self.signature.append(composer); 163 | 164 | let pk = composer.append_point(self.pk_double.pk()); 165 | let pk_p = composer.append_point(self.pk_double.pk_prime()); 166 | let msg = composer.append_witness(self.message); 167 | 168 | gadgets::verify_signature_double(composer, u, r, r_p, pk, pk_p, msg) 169 | .expect("this is infallible"); 170 | 171 | Ok(()) 172 | } 173 | } 174 | 175 | #[test] 176 | #[cfg(feature = "double")] 177 | fn verify_signature_double() { 178 | let mut rng = StdRng::seed_from_u64(0xfeeb); 179 | 180 | // Create prover and verifier circuit description 181 | let (prover, verifier) = 182 | Compiler::compile::(&PP, LABEL) 183 | .expect("Circuit compilation should succeed"); 184 | 185 | // 186 | // Check valid circuit verifies 187 | let circuit = SignatureDoubleCircuit::valid_random(&mut rng); 188 | 189 | let (proof, _) = prover 190 | .prove(&mut rng, &circuit) 191 | .expect("Proving the circuit should succeed"); 192 | 193 | let pub_inputs = vec![]; 194 | verifier 195 | .verify(&proof, &pub_inputs) 196 | .expect("Verifying the proof should succeed"); 197 | 198 | // 199 | // Check proof creation of invalid circuit not possible 200 | let circuit = SignatureDoubleCircuit::invalid_random(&mut rng); 201 | 202 | prover 203 | .prove(&mut rng, &circuit) 204 | .expect_err("Proving invalid circuit shouldn't be possible"); 205 | } 206 | 207 | // 208 | // Test verify_signature_var_gen 209 | // 210 | #[derive(Debug, Default)] 211 | #[cfg(feature = "var_generator")] 212 | struct SignatureVarGenCircuit { 213 | signature: SignatureVarGen, 214 | pk_var_gen: PublicKeyVarGen, 215 | message: BlsScalar, 216 | } 217 | 218 | #[cfg(feature = "var_generator")] 219 | impl SignatureVarGenCircuit { 220 | pub fn valid_random(rng: &mut StdRng) -> Self { 221 | let sk = SecretKeyVarGen::random(rng); 222 | let message = BlsScalar::random(&mut *rng); 223 | let signature = sk.sign(rng, message); 224 | 225 | let pk_var_gen = PublicKeyVarGen::from(&sk); 226 | 227 | Self { 228 | signature, 229 | pk_var_gen, 230 | message, 231 | } 232 | } 233 | 234 | pub fn invalid_random(rng: &mut StdRng) -> Self { 235 | let sk = SecretKeyVarGen::random(rng); 236 | let message = BlsScalar::random(&mut *rng); 237 | let signature = sk.sign(rng, message); 238 | 239 | let sk_wrong = SecretKeyVarGen::random(rng); 240 | let pk_var_gen = PublicKeyVarGen::from(&sk_wrong); 241 | 242 | Self { 243 | signature, 244 | pk_var_gen, 245 | message, 246 | } 247 | } 248 | } 249 | 250 | #[cfg(feature = "var_generator")] 251 | impl Circuit for SignatureVarGenCircuit { 252 | fn circuit(&self, composer: &mut Composer) -> Result<(), PlonkError> { 253 | let (u, r) = self.signature.append(composer); 254 | 255 | let pk_var_gen = composer.append_point(self.pk_var_gen.public_key()); 256 | let generator = composer.append_point(self.pk_var_gen.generator()); 257 | let msg = composer.append_witness(self.message); 258 | 259 | gadgets::verify_signature_var_gen( 260 | composer, u, r, pk_var_gen, generator, msg, 261 | )?; 262 | 263 | Ok(()) 264 | } 265 | } 266 | 267 | #[test] 268 | #[cfg(feature = "var_generator")] 269 | fn verify_signature_var_gen() { 270 | let mut rng = StdRng::seed_from_u64(0xfeeb); 271 | 272 | // Create prover and verifier circuit description 273 | let (prover, verifier) = 274 | Compiler::compile::(&PP, LABEL) 275 | .expect("Circuit should compile successfully"); 276 | 277 | // 278 | // Check valid circuit verifies 279 | let circuit = SignatureVarGenCircuit::valid_random(&mut rng); 280 | 281 | let (proof, _) = prover 282 | .prove(&mut rng, &circuit) 283 | .expect("Proving the circuit should be successful"); 284 | 285 | let pub_inputs = vec![]; 286 | verifier 287 | .verify(&proof, &pub_inputs) 288 | .expect("Verification should be successful"); 289 | 290 | // 291 | // Check proof creation of invalid circuit not possible 292 | let circuit = SignatureVarGenCircuit::invalid_random(&mut rng); 293 | 294 | prover 295 | .prove(&mut rng, &circuit) 296 | .expect_err("Proving invalid circuit shouldn't be possible"); 297 | } 298 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | ### Changed 11 | 12 | - Deprecate crate [#123] 13 | use [jubjub-schnorr](https://github.com/dusk-network/jubjub-schnorr) instead 14 | 15 | ## [0.18.0] - 2024-01-03 16 | 17 | ### Changed 18 | 19 | - Update `dusk-plonk` -> 0.19 20 | - Update `dusk-poseidon` -> 0.33 21 | 22 | ## [0.17.0] - 2023-12-13 23 | 24 | ### Changed 25 | 26 | - Move `verify` method to the public key structs [#81] 27 | - Rename `PublicKeyPair` to `PublicKeyDouble` [#110] 28 | - Rename `sign-single` to `sign` [#110] 29 | - Restructure code internally [#110] 30 | - Rename `DoubleSignature` to `SignatureDouble` [#107] 31 | - Rename gadgets [#107]: 32 | - `single_key_verify` -> `verify_signature` 33 | - `double_key_verify` -> `verify_signature_double` 34 | - Replace `HexDebug` trait by `Debug` for `SecretKey` and `PublicKey` [#107] 35 | - Derive `PartialEq` trait instead of implementing it manually [#107] 36 | - Derive `PartialEq` for `PublicKeyDouble` [#107] 37 | - Update `dusk-bls12_381` -> 0.13 38 | - Update `dusk-jubjub` -> 0.14 39 | - Update `dusk-plonk` -> 0.18 40 | - Update `dusk-poseidon` -> 0.32 41 | 42 | ### Added 43 | 44 | - Add `from_raw_unchecked` to `PublicKeyDouble` [#81] 45 | - Add latex documentation of the signature scheme to the README [#110] 46 | - Add `SecretKeyVarGen`, `PublicKeyVarGen` and `SignatureVarGen` [#107] 47 | - Add "double" feature for `SignatureDouble` [#107] 48 | - Add "var_generator" feature for `SignatureVarGen` [#107] 49 | - Add gadget `verify_signature_var_gen` [#107] 50 | - Add `ff` dependency 51 | 52 | ## [0.16.0] - 2023-11-22 53 | 54 | ### Added 55 | 56 | - Update README with keys structure [#104] 57 | - Add documentation to the new key structs [#105] 58 | 59 | ### Changed 60 | 61 | - Change the NotePublicKey tuple struct to directly be a tuple with two fields [#111] 62 | - Change double and single signature creation to be a method on `NoteSecretKey` [#81] 63 | - Rename internal `key_variants` module to `signatures` [#96] 64 | - Rename the signatures method `to_witness` to `append` [#99] 65 | - Update benchmarks to latest version of plonk [#94] 66 | - Update test structure [#94] 67 | - Move `PublicKeyPair` from `DoubleSignature` to `public_keys` [#95] 68 | - Rename keys: `NoteSecretKey` -> `SecretKey`, `NotePublicKey` -> `PublicKey` [#108] 69 | 70 | ### Removed 71 | 72 | - Hide `(Double)Signature::new()` from the public API [#81] 73 | 74 | ## [0.15.0] - 2023-11-1 75 | 76 | ### Added 77 | 78 | - Move `SecretKey` & `PublicKey` from dusk_pki and renamed them to `NoteSecretKey` & `NotePublicKey` [#80] 79 | - Add lib and module level documentation [#49] 80 | 81 | ### Changed 82 | 83 | - Rename `double_key::Proof` struct to `double_key::Signature` [#89] 84 | - Deprecate `Proof` public struct [#89] 85 | - Re-export `double_key::Proof` as `DoubleSignature` [#89] 86 | 87 | ## [0.14.0] - 2023-10-12 88 | 89 | ### Changed 90 | 91 | - Update `dusk-bls12_381` from `0.11` to `0.12` 92 | - Update `dusk-jubjub` from `0.12` to `0.13` 93 | - Update `dusk-pki` from `0.12` to `0.13` 94 | - Update `dusk-poseidon` from `0.30` to `0.31` 95 | - Update `dusk-plonk` from `0.14` to `0.16` 96 | 97 | ### Added 98 | 99 | - Add `ff` dev-dependency 100 | 101 | ### Removed 102 | 103 | - Remove `canonical` and `canonical_derive` dependencies 104 | - Remove `canon` feature 105 | 106 | ## [0.13.0] - 2023-06-28 107 | 108 | ### Changed 109 | 110 | - Update `dusk-pki` from `0.11` to `0.12` 111 | - Update `dusk-poseidon` from `0.28` to `0.30` 112 | - Update `dusk-plonk` from `0.13` to `0.14` 113 | - Update `rust-toolchain` from `nightly-2022-08-08` to `nightly-2023-05-22` 114 | 115 | ## [0.12.1] - 2022-12-19 116 | 117 | ### Added 118 | 119 | - Derive `Default` for `Signature` and `Proof` 120 | 121 | ## [0.12.0] - 2022-10-27 122 | 123 | ### Changed 124 | 125 | - Update `dusk-plonk` from `0.12` to `0.13` 126 | - Update `dusk-poseidon` from `0.26` to `0.28` 127 | 128 | ## [0.11.1] - 2022-10-19 129 | 130 | ### Added 131 | 132 | - Add support for `rkyv-impl` under `no_std` 133 | 134 | ## [0.11.0] - 2022-08-17 135 | 136 | ### Added 137 | 138 | - Add `CheckBytes` impl for `rkyv`ed structs 139 | - Add `rkyv` implementations behind feature [#69] 140 | 141 | ### Changed 142 | 143 | - Update dusk-poseidon from `0.23.0-rc` to `0.26` 144 | - Update dusk-pki from `0.9.0-rc` to `0.11` 145 | - Update dusk-plonk from `0.9` to `0.12` 146 | - Update dusk-bls12_381 from `0.8` to `0.11` 147 | - Update dusk-jubjub from `0.10` to `0.12` 148 | - Update canonical from `0.6` to `0.7` 149 | - Update canonical_derive from `0.6` to `0.7` 150 | 151 | ## Fixed 152 | 153 | - Fix KeyPair serialization 154 | 155 | ## [0.8.0-rc] 156 | 157 | ### Changed 158 | 159 | - Update `dusk-poseidon` from `0.21` to `0.22.0-rc` [#59] 160 | - Update `dusk-pki` from `0.7` to `0.8.0-rc` [#59] 161 | 162 | ## [0.7.0] - 2021-06-02 163 | 164 | ### Added 165 | 166 | - Add `default-features=false` to `rand_core` [#52] 167 | 168 | ### Changed 169 | 170 | - Update `canonical` from `0.5` to `0.6` [#41] 171 | - Update `dusk-plonk` from `0.6` to `0.8` [#41] 172 | - Update `dusk-poseidon` from `0.18` to `0.21.0-rc` [#41] 173 | - Update `dusk-pki` from `0.6` to `0.7` [#41] 174 | - Change crate name from `schnorr` to `dusk-schnorr` [#41] 175 | - Change default crate featureset to be `alloc`. [#50] 176 | 177 | ### Removed 178 | 179 | - Remove one hashing level for `message` in signature processing [#55] 180 | - Remove `anyhow` from dependencies [#50] 181 | 182 | ## [0.6.0] - 2021-04-06 183 | 184 | ### Changed 185 | 186 | - Update `dusk-plonk` from `0.6` to `0.7` [#37] 187 | - Update `dusk-poseidon` from `0.19` to `0.20` [#37] 188 | 189 | ## [0.5.2] - 2021-02-15 190 | 191 | ### Changed 192 | 193 | - Update `dusk-pki` to pull from crates.io 194 | 195 | ## [0.5.1] - 2021-02-11 196 | 197 | ### Changed 198 | 199 | - Update `dusk-pki` `v0.6.0` 200 | 201 | ## [0.5.0] - 2021-02-11 202 | 203 | ### Changed 204 | 205 | - Update `poseidon252` to `dusk-poseidon` `v0.18` 206 | 207 | ## [0.4.1] - 2021-02-09 208 | 209 | ### Changed 210 | 211 | - Bump `dusk-pki` to `v0.5.3` 212 | 213 | ## [0.4.0] - 2021-01-29 214 | 215 | ### Added 216 | 217 | - `PublicKeyPair` attributes R and R_prime exposed as methods 218 | - `Proof::keys` added to fetch `PublicKeyPair` 219 | 220 | ### Changed 221 | 222 | - JubJubScalars renamed from `U` to `u`, as in notation standards 223 | - Bump `poseidon252` to `v0.17.0` 224 | - Bump `dusk-pki` to `v0.5.1` 225 | 226 | ## [0.3.0] - 2021-01-28 227 | 228 | ### Added 229 | 230 | - Add `dusk_bytes::Serializable` trait to structure 231 | - Add dusk_pki's `SecretKey` and `PublicKey` 232 | 233 | ### Removed 234 | 235 | - Remove manual implementation of `to_bytes` and `from_bytes` 236 | - Remove `SecretKey`, `PublicKey` from `schnorr` 237 | - Remove `Error` schnorr enum 238 | 239 | ### Changed 240 | 241 | - `single_key::SecretKey.sign` method is now `Signature::new` 242 | - `double_key::SecretKey.sign` method is now `Proof::new` 243 | - Change return value of single's key `verify` from `Result` to `bool` 244 | - Change return value of double's key `verify` from `Result` to `bool` 245 | - Update CHANGELOG to ISO 8601 246 | - Bump `poseidon252` to `v0.16.0` 247 | - Bump `dusk-bls12_381` to `v0.6` 248 | - Bump `dusk-jubjub` to `v0.8` 249 | - Bump `dusk-plonk` to `v0.5` 250 | - Bump `canonical` to `v0.5` 251 | - Bump `canonical_derive` to `v0.5` 252 | 253 | ## [0.2.1] - 2021-01-08 254 | 255 | ### Fixes 256 | 257 | - Fix byte truncation for BLS -> JubJub conversion 258 | 259 | 260 | [#123]: https://github.com/dusk-network/schnorr/issues/123 261 | [#111]: https://github.com/dusk-network/schnorr/issues/111 262 | [#110]: https://github.com/dusk-network/schnorr/issues/110 263 | [#108]: https://github.com/dusk-network/schnorr/issues/108 264 | [#105]: https://github.com/dusk-network/schnorr/issues/105 265 | [#104]: https://github.com/dusk-network/schnorr/issues/104 266 | [#99]: https://github.com/dusk-network/schnorr/issues/99 267 | [#96]: https://github.com/dusk-network/schnorr/issues/96 268 | [#95]: https://github.com/dusk-network/schnorr/issues/95 269 | [#94]: https://github.com/dusk-network/schnorr/issues/94 270 | [#89]: https://github.com/dusk-network/schnorr/issues/89 271 | [#81]: https://github.com/dusk-network/schnorr/issues/81 272 | [#80]: https://github.com/dusk-network/schnorr/issues/80 273 | [#69]: https://github.com/dusk-network/schnorr/issues/69 274 | [#59]: https://github.com/dusk-network/schnorr/issues/59 275 | [#55]: https://github.com/dusk-network/schnorr/issues/55 276 | [#52]: https://github.com/dusk-network/schnorr/issues/52 277 | [#50]: https://github.com/dusk-network/schnorr/issues/50 278 | [#49]: https://github.com/dusk-network/schnorr/issues/49 279 | [#41]: https://github.com/dusk-network/schnorr/issues/41 280 | [#37]: https://github.com/dusk-network/schnorr/issues/37 281 | 282 | 283 | [Unreleased]: https://github.com/dusk-network/schnorr/compare/v0.18.0...HEAD 284 | [0.18.0]: https://github.com/dusk-network/schnorr/compare/v0.17.0...v0.18.0 285 | [0.17.0]: https://github.com/dusk-network/schnorr/compare/v0.16.0...v0.17.0 286 | [0.16.0]: https://github.com/dusk-network/schnorr/compare/v0.15.0...v0.16.0 287 | [0.15.0]: https://github.com/dusk-network/schnorr/compare/v0.14.0...v0.15.0 288 | [0.14.0]: https://github.com/dusk-network/schnorr/compare/v0.13.0...v0.14.0 289 | [0.13.0]: https://github.com/dusk-network/schnorr/compare/v0.12.1...v0.13.0 290 | [0.12.1]: https://github.com/dusk-network/schnorr/compare/v0.12.0...v0.12.1 291 | [0.12.0]: https://github.com/dusk-network/schnorr/compare/v0.11.1...v0.12.0 292 | [0.11.1]: https://github.com/dusk-network/schnorr/compare/v0.11.0...v0.11.1 293 | [0.11.0]: https://github.com/dusk-network/schnorr/compare/v0.7.0...v0.11.0 294 | [0.7.0]: https://github.com/dusk-network/schnorr/compare/v0.6.0...v0.7.0 295 | [0.6.0]: https://github.com/dusk-network/schnorr/compare/v0.5.2...v0.6.0 296 | [0.5.2]: https://github.com/dusk-network/schnorr/compare/v0.5.1...v0.5.2 297 | [0.5.1]: https://github.com/dusk-network/schnorr/compare/v0.5.0...v0.5.1 298 | [0.5.0]: https://github.com/dusk-network/schnorr/compare/v0.4.1...v0.5.0 299 | [0.4.1]: https://github.com/dusk-network/schnorr/compare/v0.4.0...v0.4.1 300 | [0.4.0]: https://github.com/dusk-network/schnorr/compare/v0.3.0...v0.4.0 301 | [0.3.0]: https://github.com/dusk-network/schnorr/compare/v0.2.1...v0.3.0 302 | [0.2.1]: https://github.com/dusk-network/schnorr/compare/v0.2.0...v0.2.1 303 | [0.2.0]: https://github.com/dusk-network/schnorr/compare/v0.1.0...v0.2.0 304 | [0.1.0]: https://github.com/dusk-network/schnorr/releases/tag/v0.1.0 305 | -------------------------------------------------------------------------------- /src/signatures.rs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | // 5 | // Copyright (c) DUSK NETWORK. All rights reserved. 6 | 7 | //! # Schnorr Signature 8 | //! 9 | //! This module provides functionality for a Schnorr-based signature, a 10 | //! Schnorr-based double signature and a Schnorr-based signature with variable 11 | //! generator. 12 | 13 | use dusk_bytes::{DeserializableSlice, Error as BytesError, Serializable}; 14 | use dusk_jubjub::{JubJubExtended, JubJubScalar}; 15 | use dusk_plonk::prelude::*; 16 | use dusk_poseidon::sponge::truncated::hash; 17 | 18 | #[cfg(feature = "rkyv-impl")] 19 | use rkyv::{Archive, Deserialize, Serialize}; 20 | 21 | /// An Schnorr signature, produced by signing a message with a [`SecretKey`]. 22 | /// 23 | /// ## Fields 24 | /// 25 | /// - `u`: A [`JubJubScalar`] 26 | /// - `R`: A [`JubJubExtended`] point 27 | /// 28 | /// ## Example 29 | /// 30 | /// ``` 31 | /// use dusk_bls12_381::BlsScalar; 32 | /// use dusk_schnorr::{PublicKey, SecretKey, Signature}; 33 | /// use rand::rngs::StdRng; 34 | /// use rand::SeedableRng; 35 | /// use ff::Field; 36 | /// 37 | /// let mut rng = StdRng::seed_from_u64(1234u64); 38 | /// 39 | /// let sk = SecretKey::random(&mut rng); 40 | /// let message = BlsScalar::random(&mut rng); 41 | /// let pk = PublicKey::from(&sk); 42 | /// 43 | /// // Sign the message 44 | /// let signature = sk.sign(&mut rng, message); 45 | /// 46 | /// // Verify the signature 47 | /// assert!(pk.verify(&signature, message)); 48 | /// ``` 49 | /// 50 | /// [`SecretKey`]: [`crate::SecretKey`] 51 | #[derive(Default, PartialEq, Clone, Copy, Debug)] 52 | #[cfg_attr( 53 | feature = "rkyv-impl", 54 | derive(Archive, Deserialize, Serialize), 55 | archive_attr(derive(bytecheck::CheckBytes)) 56 | )] 57 | #[allow(non_snake_case)] 58 | pub struct Signature { 59 | u: JubJubScalar, 60 | R: JubJubExtended, 61 | } 62 | 63 | impl Signature { 64 | /// Exposes the `u` scalar of the Schnorr signature. 65 | pub fn u(&self) -> &JubJubScalar { 66 | &self.u 67 | } 68 | 69 | /// Exposes the `R` point of the Schnorr signature. 70 | #[allow(non_snake_case)] 71 | pub fn R(&self) -> &JubJubExtended { 72 | &self.R 73 | } 74 | 75 | /// Creates a new single key [`Signature`] with the given parameters 76 | #[allow(non_snake_case)] 77 | pub(crate) fn new(u: JubJubScalar, R: JubJubExtended) -> Self { 78 | Self { u, R } 79 | } 80 | 81 | /// Appends the single key as a witness to the circuit composed by the 82 | /// [`Composer`]. 83 | /// 84 | /// # Feature 85 | /// 86 | /// Only available with the "alloc" feature enabled. 87 | /// 88 | /// ## Parameters 89 | /// 90 | /// - `composer`: Mutable reference to the Plonk `Composer`. 91 | /// 92 | /// ## Returns 93 | /// 94 | /// Returns a tuple `(Witness, WitnessPoint)` containing converted `u` and 95 | /// `R` fields. 96 | #[cfg(feature = "alloc")] 97 | pub fn append(&self, composer: &mut Composer) -> (Witness, WitnessPoint) { 98 | // TODO: check whether the signature should be appended as public 99 | let u = composer.append_witness(self.u); 100 | let r = composer.append_point(self.R); 101 | 102 | (u, r) 103 | } 104 | } 105 | 106 | impl Serializable<64> for Signature { 107 | type Error = BytesError; 108 | 109 | fn to_bytes(&self) -> [u8; Self::SIZE] { 110 | let mut buf = [0u8; Self::SIZE]; 111 | buf[..32].copy_from_slice(&self.u.to_bytes()[..]); 112 | buf[32..].copy_from_slice(&JubJubAffine::from(self.R).to_bytes()[..]); 113 | buf 114 | } 115 | 116 | #[allow(non_snake_case)] 117 | fn from_bytes(bytes: &[u8; Self::SIZE]) -> Result { 118 | let u = JubJubScalar::from_slice(&bytes[..32])?; 119 | let R = JubJubExtended::from(JubJubAffine::from_slice(&bytes[32..])?); 120 | 121 | Ok(Self { u, R }) 122 | } 123 | } 124 | 125 | // Create a challenge hash for the standard signature scheme. 126 | #[allow(non_snake_case)] 127 | pub(crate) fn challenge_hash( 128 | R: &JubJubExtended, 129 | message: BlsScalar, 130 | ) -> JubJubScalar { 131 | let R_coordinates = R.to_hash_inputs(); 132 | 133 | hash(&[R_coordinates[0], R_coordinates[1], message]) 134 | } 135 | 136 | /// Structure representing a Schnorr signature with a double-key mechanism. 137 | /// 138 | /// # Feature 139 | /// 140 | /// Only available with the "double" feature enabled. 141 | /// 142 | /// ## Fields 143 | /// 144 | /// - `u`: A [`JubJubScalar`] scalar value representing part of the Schnorr 145 | /// signature. 146 | /// - 'R': A [`JubJubExtended`] point representing the nonce generated with the 147 | /// generator point [`G`]. 148 | /// - 'R_prime': A [`JubJubExtended`] point representing the nonce generated 149 | /// with the generator point [`G'`]. 150 | /// 151 | /// ## Example 152 | /// ``` 153 | /// use rand::rngs::StdRng; 154 | /// use rand::SeedableRng; 155 | /// use dusk_schnorr::{SecretKey, PublicKeyDouble, SignatureDouble}; 156 | /// use dusk_bls12_381::BlsScalar; 157 | /// use ff::Field; 158 | /// 159 | /// let mut rng = StdRng::seed_from_u64(2321u64); 160 | /// 161 | /// let sk = SecretKey::random(&mut rng); 162 | /// let message = BlsScalar::random(&mut rng); 163 | /// let pk_double: PublicKeyDouble = sk.into(); 164 | /// 165 | /// let signature = sk.sign_double(&mut rng, message); 166 | /// 167 | /// assert!(pk_double.verify(&signature, message)); 168 | /// ``` 169 | /// 170 | /// [`G`]: `GENERATOR_EXTENDED` 171 | /// [`G'`]: `GENERATOR_NUMS_EXTENDED` 172 | #[derive(Default, PartialEq, Clone, Copy, Debug)] 173 | #[cfg_attr( 174 | feature = "rkyv-impl", 175 | derive(Archive, Deserialize, Serialize), 176 | archive_attr(derive(bytecheck::CheckBytes)) 177 | )] 178 | #[cfg(feature = "double")] 179 | #[allow(non_snake_case)] 180 | pub struct SignatureDouble { 181 | u: JubJubScalar, 182 | R: JubJubExtended, 183 | R_prime: JubJubExtended, 184 | } 185 | 186 | #[cfg(feature = "double")] 187 | impl SignatureDouble { 188 | /// Returns the `JubJubScalar` `u` component of the Schnorr signature. 189 | pub fn u(&self) -> &JubJubScalar { 190 | &self.u 191 | } 192 | 193 | /// Returns the nonce point `R` 194 | #[allow(non_snake_case)] 195 | pub fn R(&self) -> &JubJubExtended { 196 | &self.R 197 | } 198 | 199 | /// Returns the nonce point `R_prime` 200 | #[allow(non_snake_case)] 201 | pub fn R_prime(&self) -> &JubJubExtended { 202 | &self.R_prime 203 | } 204 | 205 | /// Creates a new [`SignatureDouble`] 206 | #[allow(non_snake_case)] 207 | pub(crate) fn new( 208 | u: JubJubScalar, 209 | R: JubJubExtended, 210 | R_prime: JubJubExtended, 211 | ) -> Self { 212 | Self { u, R, R_prime } 213 | } 214 | 215 | /// Appends the `Signature` as a witness to the circuit composed by the 216 | /// `Composer`. 217 | /// 218 | /// # Feature 219 | /// 220 | /// This function is only available when the "alloc" feature is enabled. 221 | /// 222 | /// # Parameters 223 | /// 224 | /// * `composer`: Mutable reference to a `Composer`. 225 | /// 226 | /// # Returns 227 | /// 228 | /// A tuple comprising the `Witness` of scalar `u`, and `WitnessPoint`s of 229 | /// `R` and `R'`. 230 | #[cfg(feature = "alloc")] 231 | pub fn append( 232 | &self, 233 | composer: &mut Composer, 234 | ) -> (Witness, WitnessPoint, WitnessPoint) { 235 | // TODO: check whether the signature should be public 236 | let u = composer.append_witness(self.u); 237 | let r = composer.append_point(self.R()); 238 | let r_p = composer.append_point(self.R_prime()); 239 | 240 | (u, r, r_p) 241 | } 242 | } 243 | 244 | #[cfg(feature = "double")] 245 | impl Serializable<96> for SignatureDouble { 246 | type Error = BytesError; 247 | 248 | #[allow(non_snake_case)] 249 | fn to_bytes(&self) -> [u8; Self::SIZE] { 250 | let R_affine: JubJubAffine = self.R().into(); 251 | let R_p_affine: JubJubAffine = self.R_prime().into(); 252 | 253 | let mut buf = [0u8; Self::SIZE]; 254 | buf[..32].copy_from_slice(&self.u.to_bytes()[..]); 255 | buf[32..64].copy_from_slice(&R_affine.to_bytes()[..]); 256 | buf[64..].copy_from_slice(&R_p_affine.to_bytes()[..]); 257 | buf 258 | } 259 | 260 | #[allow(non_snake_case)] 261 | fn from_bytes(bytes: &[u8; Self::SIZE]) -> Result { 262 | let u = JubJubScalar::from_slice(&bytes[..32])?; 263 | let R: JubJubExtended = 264 | JubJubAffine::from_slice(&bytes[32..64])?.into(); 265 | let R_prime: JubJubExtended = 266 | JubJubAffine::from_slice(&bytes[64..])?.into(); 267 | 268 | Ok(Self { u, R, R_prime }) 269 | } 270 | } 271 | 272 | // Create a challenge hash for the double signature scheme. 273 | #[cfg(feature = "double")] 274 | #[allow(non_snake_case)] 275 | pub(crate) fn challenge_hash_double( 276 | R: &JubJubExtended, 277 | R_prime: &JubJubExtended, 278 | message: BlsScalar, 279 | ) -> JubJubScalar { 280 | let R_coordinates = R.to_hash_inputs(); 281 | let R_p_coordinates = R_prime.to_hash_inputs(); 282 | 283 | hash(&[ 284 | R_coordinates[0], 285 | R_coordinates[1], 286 | R_p_coordinates[0], 287 | R_p_coordinates[1], 288 | message, 289 | ]) 290 | } 291 | 292 | /// An Schnorr SignatureVarGen, produced by signing a message with a 293 | /// [`SecretKeyVarGen`]. 294 | /// 295 | /// The `SignatureVarGen` struct encapsulates variables of the Schnorr scheme. 296 | /// 297 | /// # Feature 298 | /// 299 | /// Only available with the "var_generator" feature enabled. 300 | /// 301 | /// ## Fields 302 | /// 303 | /// - `u`: A [`JubJubScalar`] scalar representing the Schnorr signature. 304 | /// - `R`: A [`JubJubExtended`] point produced as part of the Schnorr signature. 305 | /// 306 | /// ## Example 307 | /// 308 | /// ``` 309 | /// use dusk_bls12_381::BlsScalar; 310 | /// use dusk_schnorr::{PublicKeyVarGen, SecretKeyVarGen, SignatureVarGen}; 311 | /// use rand::rngs::StdRng; 312 | /// use rand::SeedableRng; 313 | /// use ff::Field; 314 | /// 315 | /// let mut rng = StdRng::seed_from_u64(1234u64); 316 | /// 317 | /// let sk = SecretKeyVarGen::random(&mut rng); 318 | /// let message = BlsScalar::random(&mut rng); 319 | /// let pk = PublicKeyVarGen::from(&sk); 320 | /// 321 | /// // Sign the message 322 | /// let signature = sk.sign(&mut rng, message); 323 | /// 324 | /// // Verify the signature 325 | /// assert!(pk.verify(&signature, message)); 326 | /// ``` 327 | /// 328 | /// [`SecretKeyVarGen`]: [`crate::SecretKeyVarGen`] 329 | #[allow(non_snake_case)] 330 | #[derive(Default, PartialEq, Clone, Copy, Debug)] 331 | #[cfg_attr( 332 | feature = "rkyv-impl", 333 | derive(Archive, Deserialize, Serialize), 334 | archive_attr(derive(bytecheck::CheckBytes)) 335 | )] 336 | #[cfg(feature = "var_generator")] 337 | pub struct SignatureVarGen { 338 | u: JubJubScalar, 339 | R: JubJubExtended, 340 | } 341 | 342 | #[cfg(feature = "var_generator")] 343 | impl SignatureVarGen { 344 | /// Exposes the `u` scalar of the Schnorr SignatureVarGen. 345 | pub fn u(&self) -> &JubJubScalar { 346 | &self.u 347 | } 348 | 349 | /// Exposes the `R` point of the Schnorr SignatureVarGen. 350 | #[allow(non_snake_case)] 351 | pub fn R(&self) -> &JubJubExtended { 352 | &self.R 353 | } 354 | 355 | /// Creates a new single key [`SignatureVarGen`] with the given parameters 356 | #[allow(non_snake_case)] 357 | pub(crate) fn new(u: JubJubScalar, R: JubJubExtended) -> Self { 358 | Self { u, R } 359 | } 360 | 361 | /// Appends the single key as a witness to the circuit composed by the 362 | /// [`Composer`]. 363 | /// 364 | /// # Feature 365 | /// 366 | /// Only available with the "alloc" feature enabled. 367 | /// 368 | /// ## Parameters 369 | /// 370 | /// - `composer`: Mutable reference to the Plonk `Composer`. 371 | /// 372 | /// ## Returns 373 | /// 374 | /// Returns a tuple `(Witness, WitnessPoint)` containing converted `u` and 375 | /// `R` fields. 376 | #[cfg(feature = "alloc")] 377 | pub fn append(&self, composer: &mut Composer) -> (Witness, WitnessPoint) { 378 | // TODO: check whether the signature should be public 379 | let u = composer.append_witness(self.u); 380 | let r = composer.append_point(self.R); 381 | 382 | (u, r) 383 | } 384 | } 385 | 386 | #[cfg(feature = "var_generator")] 387 | impl Serializable<64> for SignatureVarGen { 388 | type Error = BytesError; 389 | 390 | fn to_bytes(&self) -> [u8; Self::SIZE] { 391 | let mut buf = [0u8; Self::SIZE]; 392 | buf[..32].copy_from_slice(&self.u.to_bytes()[..]); 393 | buf[32..].copy_from_slice(&JubJubAffine::from(self.R).to_bytes()[..]); 394 | buf 395 | } 396 | 397 | #[allow(non_snake_case)] 398 | fn from_bytes(bytes: &[u8; Self::SIZE]) -> Result { 399 | let u = JubJubScalar::from_slice(&bytes[..32])?; 400 | let R = JubJubExtended::from(JubJubAffine::from_slice(&bytes[32..])?); 401 | 402 | Ok(Self { u, R }) 403 | } 404 | } 405 | -------------------------------------------------------------------------------- /src/keys/secret.rs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | // 5 | // Copyright (c) DUSK NETWORK. All rights reserved. 6 | 7 | //! # Secret Key Module 8 | //! 9 | //! This module provides the `SecretKey` and `SecretKeyVarGen`, essential for 10 | //! signing messages, proving ownership. It facilitates the generation of 11 | //! Schnorr signatures, supporting both single and double signature schemes, as 12 | //! well as signatures with variable generators. 13 | 14 | use dusk_bls12_381::BlsScalar; 15 | use dusk_bytes::{Error, Serializable}; 16 | use dusk_jubjub::{JubJubScalar, GENERATOR_EXTENDED}; 17 | use ff::Field; 18 | use rand_core::{CryptoRng, RngCore}; 19 | 20 | use crate::Signature; 21 | 22 | #[cfg(feature = "var_generator")] 23 | use crate::SignatureVarGen; 24 | #[cfg(feature = "var_generator")] 25 | use dusk_jubjub::{JubJubAffine, JubJubExtended}; 26 | 27 | #[cfg(feature = "double")] 28 | use crate::SignatureDouble; 29 | #[cfg(feature = "double")] 30 | use dusk_jubjub::GENERATOR_NUMS_EXTENDED; 31 | 32 | #[cfg(feature = "rkyv-impl")] 33 | use rkyv::{Archive, Deserialize, Serialize}; 34 | 35 | /// Structure representing a [`SecretKey`], represented as a private scalar 36 | /// in the JubJub scalar field. 37 | /// 38 | /// ## Examples 39 | /// 40 | /// Generate a random `SecretKey`: 41 | /// ``` 42 | /// use dusk_schnorr::SecretKey; 43 | /// use rand::rngs::StdRng; 44 | /// use rand::SeedableRng; 45 | /// 46 | /// let mut rng = StdRng::seed_from_u64(12345); 47 | /// let sk = SecretKey::random(&mut rng); 48 | /// ``` 49 | #[allow(non_snake_case)] 50 | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] 51 | #[cfg_attr( 52 | feature = "rkyv-impl", 53 | derive(Archive, Serialize, Deserialize), 54 | archive_attr(derive(bytecheck::CheckBytes)) 55 | )] 56 | pub struct SecretKey(pub(crate) JubJubScalar); 57 | 58 | impl From for SecretKey { 59 | fn from(s: JubJubScalar) -> SecretKey { 60 | SecretKey(s) 61 | } 62 | } 63 | 64 | impl From<&JubJubScalar> for SecretKey { 65 | fn from(s: &JubJubScalar) -> SecretKey { 66 | SecretKey(*s) 67 | } 68 | } 69 | 70 | impl AsRef for SecretKey { 71 | fn as_ref(&self) -> &JubJubScalar { 72 | &self.0 73 | } 74 | } 75 | 76 | impl SecretKey { 77 | /// This will create a random [`SecretKey`] from a scalar 78 | /// of the Field JubJubScalar. 79 | pub fn random(rand: &mut T) -> SecretKey 80 | where 81 | T: RngCore + CryptoRng, 82 | { 83 | let fr = JubJubScalar::random(rand); 84 | 85 | SecretKey(fr) 86 | } 87 | } 88 | 89 | impl Serializable<32> for SecretKey { 90 | type Error = Error; 91 | 92 | fn to_bytes(&self) -> [u8; 32] { 93 | self.0.to_bytes() 94 | } 95 | 96 | fn from_bytes(bytes: &[u8; 32]) -> Result { 97 | let sk = match JubJubScalar::from_bytes(bytes).into() { 98 | Some(sk) => sk, 99 | None => return Err(Error::InvalidData), 100 | }; 101 | Ok(Self(sk)) 102 | } 103 | } 104 | 105 | impl SecretKey { 106 | /// Signs a chosen message with a given secret key using the dusk variant 107 | /// of the Schnorr signature scheme. 108 | /// 109 | /// This function performs the following cryptographic operations: 110 | /// - Generates a random nonce `r`. 111 | /// - Computes `R = r * G`. 112 | /// - Computes the challenge `c = H(R || m)`. 113 | /// - Computes the signature `u = r - c * sk`. 114 | /// 115 | /// ## Parameters 116 | /// 117 | /// - `rng`: Reference to the random number generator. 118 | /// - `message`: The message in [`BlsScalar`] to be signed. 119 | /// 120 | /// ## Returns 121 | /// 122 | /// Returns a new [`Signature`] containing the `u` scalar and `R` point. 123 | /// 124 | /// ## Example 125 | /// 126 | /// Sign a message with a [`SecretKey`] and verify with the respective 127 | /// [`PublicKey`]: 128 | /// ``` 129 | /// use dusk_schnorr::{SecretKey, PublicKey}; 130 | /// use dusk_jubjub::JubJubScalar; 131 | /// use dusk_bls12_381::BlsScalar; 132 | /// use rand::rngs::StdRng; 133 | /// use rand::SeedableRng; 134 | /// use ff::Field; 135 | /// 136 | /// let mut rng = StdRng::seed_from_u64(12345); 137 | /// 138 | /// let message = BlsScalar::random(&mut rng); 139 | /// 140 | /// let sk = SecretKey::random(&mut rng); 141 | /// let pk = PublicKey::from(&sk); 142 | /// 143 | /// let signature = sk.sign(&mut rng, message); 144 | /// 145 | /// assert!(pk.verify(&signature, message)); 146 | /// ``` 147 | /// 148 | /// [`PublicKey`]: [`crate::PublicKey`] 149 | #[allow(non_snake_case)] 150 | pub fn sign(&self, rng: &mut R, msg: BlsScalar) -> Signature 151 | where 152 | R: RngCore + CryptoRng, 153 | { 154 | // Create random scalar value for scheme, r 155 | let r = JubJubScalar::random(rng); 156 | 157 | // Derive a points from r, to sign with the message 158 | // R = r * G 159 | let R = GENERATOR_EXTENDED * r; 160 | 161 | // Compute challenge value, c = H(R||m); 162 | let c = crate::signatures::challenge_hash(&R, msg); 163 | 164 | // Compute scalar signature, U = r - c * sk, 165 | let u = r - (c * self.as_ref()); 166 | 167 | Signature::new(u, R) 168 | } 169 | 170 | /// Constructs a new `Signature` instance by signing a given message with 171 | /// a `SecretKey`. 172 | /// 173 | /// Utilizes a secure random number generator to create a unique random 174 | /// scalar, and subsequently computes public key points `(R, R')` and a 175 | /// scalar signature `u`. 176 | /// 177 | /// # Feature 178 | /// 179 | /// Only available with the "double" feature enabled. 180 | /// 181 | /// # Parameters 182 | /// 183 | /// * `rng`: Cryptographically secure random number generator. 184 | /// * `message`: Message as a `BlsScalar`. 185 | /// 186 | /// # Returns 187 | /// 188 | /// A new [`SignatureDouble`] instance. 189 | /// 190 | /// ## Example 191 | /// 192 | /// Double sign a message with a [`SecretKey`] and verify with the 193 | /// respective [`PublicKeyDouble`]: 194 | /// ``` 195 | /// use dusk_schnorr::{SecretKey, PublicKeyDouble}; 196 | /// use dusk_jubjub::JubJubScalar; 197 | /// use dusk_bls12_381::BlsScalar; 198 | /// use rand::rngs::StdRng; 199 | /// use rand::SeedableRng; 200 | /// use ff::Field; 201 | /// 202 | /// let mut rng = StdRng::seed_from_u64(12345); 203 | /// 204 | /// let message = BlsScalar::random(&mut rng); 205 | /// 206 | /// let sk = SecretKey::random(&mut rng); 207 | /// let pk = PublicKeyDouble::from(&sk); 208 | /// 209 | /// let signature = sk.sign_double(&mut rng, message); 210 | /// 211 | /// assert!(pk.verify(&signature, message)); 212 | /// ``` 213 | /// 214 | /// [`PublicKeyDouble`]: [`crate::PublicKeyDouble`] 215 | #[allow(non_snake_case)] 216 | #[cfg(feature = "double")] 217 | pub fn sign_double( 218 | &self, 219 | rng: &mut R, 220 | message: BlsScalar, 221 | ) -> SignatureDouble 222 | where 223 | R: RngCore + CryptoRng, 224 | { 225 | // Create random scalar value for scheme, r 226 | let r = JubJubScalar::random(rng); 227 | 228 | // Derive two points from r, to sign with the message 229 | // R = r * G 230 | // R_prime = r * G' 231 | let R = GENERATOR_EXTENDED * r; 232 | let R_prime = GENERATOR_NUMS_EXTENDED * r; 233 | // Compute challenge value, c = H(R||R_prime||m); 234 | let c = crate::signatures::challenge_hash_double(&R, &R_prime, message); 235 | 236 | // Compute scalar signature, u = r - c * sk, 237 | let u = r - (c * self.as_ref()); 238 | 239 | SignatureDouble::new(u, R, R_prime) 240 | } 241 | 242 | /// Create a [`SecretKeyVarGen`], a `SecretKey` with a generator 243 | /// other than [`GENERATOR_EXTENDED`]. 244 | /// 245 | /// # Feature 246 | /// 247 | /// Only available with the "var_generator" feature enabled. 248 | /// 249 | /// # Parameters 250 | /// 251 | /// * `generator`: A `JubJubExtended` point that will replace 252 | /// `GENERATOR_EXTENDED` in the signature algorithm 253 | /// 254 | /// # Returns 255 | /// 256 | /// A new [`SecretKeyVarGen`] instance. 257 | #[cfg(feature = "var_generator")] 258 | pub fn with_variable_generator( 259 | self, 260 | generator: JubJubExtended, 261 | ) -> SecretKeyVarGen { 262 | SecretKeyVarGen::new(self.0, generator) 263 | } 264 | } 265 | 266 | /// Structure representing a [`SecretKeyVarGen`], represented as a private 267 | /// scalar in the JubJub scalar field, with a variable generator, 268 | /// represented as a point on the JubJub curve. 269 | /// 270 | /// # Feature 271 | /// 272 | /// Only available with the "var_generator" feature enabled. 273 | /// 274 | /// ## Examples 275 | /// 276 | /// Generate a random `SecretKey`: 277 | /// Generating a random `SecretKeyVarGen` with a variable generator 278 | /// ``` 279 | /// use dusk_schnorr::{SecretKey, SecretKeyVarGen}; 280 | /// use rand::rngs::StdRng; 281 | /// use rand::SeedableRng; 282 | /// use dusk_jubjub::{JubJubScalar, GENERATOR_EXTENDED}; 283 | /// use ff::Field; 284 | /// 285 | /// let mut rng = StdRng::seed_from_u64(12345); 286 | /// 287 | /// // generate a variable generator secret key from an existing standard 288 | /// // SecretKey: 289 | /// let sk = SecretKey::random(&mut rng); 290 | /// let generator = GENERATOR_EXTENDED * JubJubScalar::random(&mut rng); 291 | /// let sk_var_gen: SecretKeyVarGen = sk.with_variable_generator(generator); 292 | /// 293 | /// // generate a variable generator secret key from the raw values: 294 | /// let sk_var_gen = SecretKeyVarGen::new(JubJubScalar::from(42u64), generator); 295 | /// 296 | /// // generate a variable generator secret key at random: 297 | /// let sk_var_gen = SecretKeyVarGen::random(&mut rng); 298 | /// ``` 299 | #[allow(non_snake_case)] 300 | #[derive(Clone, Copy, PartialEq, Debug, Default)] 301 | #[cfg_attr( 302 | feature = "rkyv-impl", 303 | derive(Archive, Serialize, Deserialize), 304 | archive_attr(derive(bytecheck::CheckBytes)) 305 | )] 306 | #[cfg(feature = "var_generator")] 307 | pub struct SecretKeyVarGen { 308 | sk: JubJubScalar, 309 | generator: JubJubExtended, 310 | } 311 | 312 | #[cfg(feature = "var_generator")] 313 | impl Serializable<64> for SecretKeyVarGen { 314 | type Error = Error; 315 | 316 | fn to_bytes(&self) -> [u8; 64] { 317 | let mut buf = [0u8; 64]; 318 | let sk_bytes = self.sk.to_bytes(); 319 | let gen: JubJubAffine = self.generator.into(); 320 | let gen_bytes = gen.to_bytes(); 321 | buf[..32].copy_from_slice(&sk_bytes); 322 | buf[32..].copy_from_slice(&gen_bytes); 323 | buf 324 | } 325 | 326 | fn from_bytes(bytes: &[u8; 64]) -> Result { 327 | let mut sk_bytes = [0u8; 32]; 328 | let mut gen_bytes = [0u8; 32]; 329 | sk_bytes.copy_from_slice(&bytes[..32]); 330 | gen_bytes.copy_from_slice(&bytes[32..]); 331 | let sk = >::from_bytes(&sk_bytes)?; 332 | let generator: JubJubExtended = 333 | >::from_bytes(&gen_bytes)?.into(); 334 | Ok(Self { sk, generator }) 335 | } 336 | } 337 | 338 | #[cfg(feature = "var_generator")] 339 | impl SecretKeyVarGen { 340 | /// Create a new [`SecretKeyVarGen`] with a given secret key and a 341 | /// generator point. 342 | /// 343 | /// ## Parameters 344 | /// 345 | /// - `sk`: The secret key as `JubJubScalar`. 346 | /// - `generator`: The generator point as `JubJubExtended`. 347 | /// 348 | /// ## Returns 349 | /// 350 | /// - A new [`SecretKeyVarGen`] instance for signing with a variable 351 | /// generator. 352 | pub fn new(sk: JubJubScalar, generator: JubJubExtended) -> Self { 353 | Self { sk, generator } 354 | } 355 | 356 | /// Create a random [`SecretKeyVarGen`] from a scalar. 357 | /// of the Field JubJubScalar. 358 | /// 359 | /// ## Parameters 360 | /// 361 | /// - `rng`: Reference to a random number generator. 362 | /// 363 | /// ## Returns 364 | /// 365 | /// - A new [`SecretKeyVarGen`] instance for signing with a variable 366 | /// generator. 367 | pub fn random(rand: &mut T) -> SecretKeyVarGen 368 | where 369 | T: RngCore + CryptoRng, 370 | { 371 | let sk = JubJubScalar::random(&mut *rand); 372 | let scalar = JubJubScalar::random(&mut *rand); 373 | let generator = GENERATOR_EXTENDED * scalar; 374 | 375 | SecretKeyVarGen { sk, generator } 376 | } 377 | 378 | /// Returns a reference to the [`JubJubScalar`] secret key. 379 | pub(crate) fn secret_key(&self) -> &JubJubScalar { 380 | &self.sk 381 | } 382 | 383 | /// Returns a reference to the [`JubJubExtended`] generator. 384 | pub(crate) fn generator(&self) -> &JubJubExtended { 385 | &self.generator 386 | } 387 | 388 | /// Signs a chosen message with a given secret key using the dusk 389 | /// variant of the Schnorr signature scheme. 390 | /// 391 | /// This function performs the following cryptographic operations: 392 | /// - Generates a random nonce `r`. 393 | /// - Computes `R = r * G`. 394 | /// - Computes the challenge `c = H(R || m)`. 395 | /// - Computes the signature `u = r - c * sk`. 396 | /// 397 | /// ## Parameters 398 | /// 399 | /// - `rng`: Reference to the random number generator. 400 | /// - `message`: The message in [`BlsScalar`] to be signed. 401 | /// 402 | /// ## Returns 403 | /// 404 | /// Returns a new [`SignatureVarGen`] containing the `u` scalar and `R` 405 | /// point. 406 | /// 407 | /// ## Example 408 | /// 409 | /// Sign a message with a [`SecretKeyVarGen`] and verify with the respective 410 | /// [`PublicKeyVarGen`]: 411 | /// ``` 412 | /// use dusk_schnorr::{SecretKeyVarGen, PublicKeyVarGen}; 413 | /// use dusk_jubjub::JubJubScalar; 414 | /// use dusk_bls12_381::BlsScalar; 415 | /// use rand::rngs::StdRng; 416 | /// use rand::SeedableRng; 417 | /// use ff::Field; 418 | /// 419 | /// let mut rng = StdRng::seed_from_u64(12345); 420 | /// 421 | /// let message = BlsScalar::random(&mut rng); 422 | /// 423 | /// let sk = SecretKeyVarGen::random(&mut rng); 424 | /// let pk = PublicKeyVarGen::from(&sk); 425 | /// 426 | /// let signature = sk.sign(&mut rng, message); 427 | /// 428 | /// assert!(pk.verify(&signature, message)); 429 | /// ``` 430 | /// 431 | /// [`PublicKeyVarGen`]: [`crate::PublicKeyVarGen`] 432 | #[allow(non_snake_case)] 433 | pub fn sign(&self, rng: &mut R, msg: BlsScalar) -> SignatureVarGen 434 | where 435 | R: RngCore + CryptoRng, 436 | { 437 | // Create random scalar value for scheme, r 438 | let r = JubJubScalar::random(rng); 439 | 440 | // Derive a points from r, to sign with the message 441 | // R = r * G 442 | let R = self.generator() * r; 443 | 444 | // Compute challenge value, c = H(R||H(m)); 445 | let c = crate::signatures::challenge_hash(&R, msg); 446 | 447 | // Compute scalar signature, U = r - c * sk, 448 | let u = r - (c * self.secret_key()); 449 | 450 | SignatureVarGen::new(u, R) 451 | } 452 | } 453 | -------------------------------------------------------------------------------- /src/keys/public.rs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | // 5 | // Copyright (c) DUSK NETWORK. All rights reserved. 6 | 7 | //! # Public Key Module 8 | //! 9 | //! This module provides the public key components for the Schnorr signature 10 | //! scheme, necessary for verifying signature validity. It includes single and 11 | //! double public keys, as well as public keys for signing with a variable 12 | //! generator. Public keys in this context are points on the JubJub 13 | //! elliptic curve generated from the [`SecretKey`] and generator point, and 14 | //! they provide the basis for signature verification. 15 | 16 | use dusk_bls12_381::BlsScalar; 17 | use dusk_bytes::{Error, Serializable}; 18 | use dusk_jubjub::{JubJubAffine, JubJubExtended, GENERATOR_EXTENDED}; 19 | 20 | use crate::{SecretKey, Signature}; 21 | 22 | #[cfg(feature = "double")] 23 | use crate::SignatureDouble; 24 | #[cfg(feature = "double")] 25 | use dusk_bytes::DeserializableSlice; 26 | #[cfg(feature = "double")] 27 | use dusk_jubjub::GENERATOR_NUMS_EXTENDED; 28 | 29 | #[cfg(feature = "var_generator")] 30 | use crate::{SecretKeyVarGen, SignatureVarGen}; 31 | 32 | #[cfg(feature = "rkyv-impl")] 33 | use rkyv::{Archive, Deserialize, Serialize}; 34 | 35 | /// Structure representing a [`PublicKey`], consisting of a [`JubJubExtended`] 36 | /// point on the JubJub curve. This public key allows for the verification of 37 | /// signatures created with its corresponding secret key without revealing the 38 | /// secret key itself. 39 | /// 40 | /// ## Examples 41 | /// 42 | /// Generate a [`PublicKey`] from a [`SecretKey`]: 43 | /// ``` 44 | /// use dusk_schnorr::{SecretKey, PublicKey}; 45 | /// use dusk_bls12_381::BlsScalar; 46 | /// use rand::rngs::StdRng; 47 | /// use rand::SeedableRng; 48 | /// 49 | /// let mut rng = StdRng::seed_from_u64(12345); 50 | /// let sk = SecretKey::random(&mut rng); 51 | /// let pk = PublicKey::from(&sk); 52 | /// ``` 53 | #[derive(Default, Copy, Clone, Debug, PartialEq)] 54 | #[cfg_attr( 55 | feature = "rkyv-impl", 56 | derive(Archive, Serialize, Deserialize), 57 | archive_attr(derive(bytecheck::CheckBytes)) 58 | )] 59 | pub struct PublicKey(JubJubExtended); 60 | 61 | impl From<&SecretKey> for PublicKey { 62 | fn from(sk: &SecretKey) -> Self { 63 | let pk = GENERATOR_EXTENDED * sk.0; 64 | 65 | PublicKey(pk) 66 | } 67 | } 68 | 69 | impl From for PublicKey { 70 | fn from(p: JubJubExtended) -> PublicKey { 71 | PublicKey(p) 72 | } 73 | } 74 | 75 | impl From<&JubJubExtended> for PublicKey { 76 | fn from(p: &JubJubExtended) -> PublicKey { 77 | PublicKey(*p) 78 | } 79 | } 80 | 81 | impl AsRef for PublicKey { 82 | fn as_ref(&self) -> &JubJubExtended { 83 | &self.0 84 | } 85 | } 86 | 87 | impl Serializable<32> for PublicKey { 88 | type Error = Error; 89 | 90 | fn to_bytes(&self) -> [u8; 32] { 91 | JubJubAffine::from(self.0).to_bytes() 92 | } 93 | 94 | fn from_bytes(bytes: &[u8; 32]) -> Result { 95 | let pk: JubJubAffine = match JubJubAffine::from_bytes(*bytes).into() { 96 | Some(pk) => pk, 97 | None => return Err(Error::InvalidData), 98 | }; 99 | Ok(Self(pk.into())) 100 | } 101 | } 102 | 103 | impl PublicKey { 104 | /// Verifies that the given Schnorr [`Signature`] is valid. 105 | /// 106 | /// This function computes a challenge hash `c` using the stored `R` point 107 | /// and the provided message, then performs the verification by checking 108 | /// that: 109 | /// ```text 110 | /// u * G + c * PK == R 111 | /// ``` 112 | /// 113 | /// ## Parameters 114 | /// 115 | /// - `sig`: Reference to the [`Signature`] to be verified. 116 | /// - `message`: The message as [`BlsScalar`]. 117 | /// 118 | /// ## Returns 119 | /// 120 | /// A boolean value indicating the validity of the Schnorr [`Signature`]. 121 | pub fn verify(&self, sig: &Signature, message: BlsScalar) -> bool { 122 | // Compute challenge value, c = H(R||m); 123 | let c = crate::signatures::challenge_hash(sig.R(), message); 124 | 125 | // Compute verification steps 126 | // u * G + c * PK 127 | let point_1 = (GENERATOR_EXTENDED * sig.u()) + (self.as_ref() * c); 128 | 129 | point_1.eq(&sig.R()) 130 | } 131 | 132 | /// Create a [`PublicKey`] from its internal parts. 133 | /// 134 | /// The public keys are generated from a bijective function that takes a 135 | /// secret keys domain. If keys are generated directly from curve 136 | /// points, there is no guarantee a secret key exists - in fact, the 137 | /// discrete logarithm property will guarantee the secret key cannot be 138 | /// extracted from this public key. 139 | /// 140 | /// If you opt to generate the keys manually, be sure you have its secret 141 | /// counterpart - otherwise this key will be of no use. 142 | pub const fn from_raw_unchecked(key: JubJubExtended) -> Self { 143 | Self(key) 144 | } 145 | } 146 | 147 | /// Structure representing a [`PublicKeyDouble`], consisting of two 148 | /// [`JubJubExtended`] poinst on the JubJub curve. 149 | /// 150 | /// The [`PublicKeyDouble`] struct contains two public keys: `(pk, pk')`, 151 | /// which are generated from different bases. 152 | /// Specifically: `pk = sk * G` with the standard generator point [`G`], 153 | /// and `pk' = sk * G'` with generator point [`G'`]. 154 | /// 155 | /// This construct allows for a double-key mechanism to enable more advanced 156 | /// uses then the single-key variant. For example, it is used in Phoenix for 157 | /// proof delegation while preventing the leakage of secret keys. 158 | /// 159 | /// # Feature 160 | /// 161 | /// Only available with the "double" feature enabled. 162 | /// 163 | /// ## Fields 164 | /// 165 | /// - `(pk, pk')`: two [`PublicKey`], where `pk` is generated with [`G`] and 166 | /// `pk'` with [`G'`] 167 | /// 168 | /// Generate a [`PublicKeyDouble`] from a [`SecretKey`]: 169 | /// ## Example 170 | /// ``` 171 | /// use rand::rngs::StdRng; 172 | /// use rand::SeedableRng; 173 | /// use dusk_schnorr::{SecretKey, PublicKeyDouble}; 174 | /// 175 | /// let mut rng = StdRng::seed_from_u64(12345); 176 | /// let sk = SecretKey::random(&mut rng); 177 | /// let pk_double = PublicKeyDouble::from(&sk); 178 | /// ``` 179 | /// 180 | /// [`G`]: `GENERATOR_EXTENDED` 181 | /// [`G'`]: `GENERATOR_NUMS_EXTENDED` 182 | #[derive(Default, Copy, Clone, Debug, PartialEq)] 183 | #[cfg_attr( 184 | feature = "rkyv-impl", 185 | derive(Archive, Deserialize, Serialize), 186 | archive_attr(derive(bytecheck::CheckBytes)) 187 | )] 188 | #[cfg(feature = "double")] 189 | pub struct PublicKeyDouble(JubJubExtended, JubJubExtended); 190 | 191 | #[cfg(feature = "double")] 192 | impl PublicKeyDouble { 193 | /// Returns the `PublicKey` corresponding to the standard elliptic curve 194 | /// generator point `sk * G`. 195 | #[allow(non_snake_case)] 196 | pub fn pk(&self) -> &JubJubExtended { 197 | &self.0 198 | } 199 | 200 | /// Returns the `PublicKey` corresponding to the secondary elliptic 201 | /// curve generator point `sk * G'`. 202 | #[allow(non_snake_case)] 203 | pub fn pk_prime(&self) -> &JubJubExtended { 204 | &self.1 205 | } 206 | 207 | /// Verifies that the given Schnorr [`SignatureDouble`] is valid. 208 | /// 209 | /// It computes the challenge scalar and verifies the equality of points, 210 | /// thereby ensuring the [`SignatureDouble`] is valid. 211 | /// 212 | /// # Parameters 213 | /// 214 | /// * `sig_double`: Reference to the [`SignatureDouble`] to be verified. 215 | /// - `message`: The message as [`BlsScalar`]. 216 | /// 217 | /// # Returns 218 | /// 219 | /// A boolean value indicating the validity of the Schnorr 220 | /// [`SignatureDouble`]. 221 | #[allow(non_snake_case)] 222 | pub fn verify( 223 | &self, 224 | sig_double: &SignatureDouble, 225 | message: BlsScalar, 226 | ) -> bool { 227 | // Compute challenge value, c = H(R||R_prime||m); 228 | let c = crate::signatures::challenge_hash_double( 229 | sig_double.R(), 230 | sig_double.R_prime(), 231 | message, 232 | ); 233 | 234 | // Compute verification steps 235 | // u * G + c * PK 236 | let point_1 = (GENERATOR_EXTENDED * sig_double.u()) + (self.pk() * c); 237 | // u * G' + c * PK' 238 | let point_2 = 239 | (GENERATOR_NUMS_EXTENDED * sig_double.u()) + (self.pk_prime() * c); 240 | 241 | // Verify point equations 242 | // point_1 = R && point_2 = R_prime 243 | point_1.eq(sig_double.R()) && point_2.eq(sig_double.R_prime()) 244 | } 245 | 246 | /// Create a [`PublicKeyDouble`] from its internal parts 247 | /// 248 | /// The public keys are generated from a bijective function that takes a 249 | /// secret keys domain. If keys are generated directly from curve 250 | /// points, there is no guarantee a secret key exists - in fact, the 251 | /// discrete logarithm property will guarantee the secret key cannot be 252 | /// extracted from this public key. 253 | /// 254 | /// If you opt to generate the keys manually, be sure you have its secret 255 | /// counterpart - otherwise this key will be of no use. 256 | pub const fn from_raw_unchecked( 257 | pk: JubJubExtended, 258 | pk_prime: JubJubExtended, 259 | ) -> Self { 260 | Self(pk, pk_prime) 261 | } 262 | } 263 | 264 | #[cfg(feature = "double")] 265 | impl From<&SecretKey> for PublicKeyDouble { 266 | fn from(sk: &SecretKey) -> Self { 267 | let pk = GENERATOR_EXTENDED * sk.as_ref(); 268 | let pk_prime = GENERATOR_NUMS_EXTENDED * sk.as_ref(); 269 | 270 | PublicKeyDouble(pk, pk_prime) 271 | } 272 | } 273 | 274 | #[cfg(feature = "double")] 275 | impl From for PublicKeyDouble { 276 | fn from(sk: SecretKey) -> Self { 277 | (&sk).into() 278 | } 279 | } 280 | 281 | #[cfg(feature = "double")] 282 | impl Serializable<64> for PublicKeyDouble { 283 | type Error = Error; 284 | 285 | fn to_bytes(&self) -> [u8; Self::SIZE] { 286 | let mut buf = [0u8; Self::SIZE]; 287 | let pk: JubJubAffine = self.pk().into(); 288 | let pk_prime: JubJubAffine = self.pk_prime().into(); 289 | buf[..32].copy_from_slice(&pk.to_bytes()[..]); 290 | buf[32..].copy_from_slice(&pk_prime.to_bytes()[..]); 291 | buf 292 | } 293 | 294 | fn from_bytes(bytes: &[u8; Self::SIZE]) -> Result { 295 | let pk = JubJubAffine::from_slice(&bytes[..32])?; 296 | let pk_prime = JubJubAffine::from_slice(&bytes[32..])?; 297 | Ok(PublicKeyDouble(pk.into(), pk_prime.into())) 298 | } 299 | } 300 | 301 | /// Structure representing a [`PublicKeyVarGen`], consisting of a public key 302 | /// [`JubJubExtended`] point and a variable generator [`JubJubExtended`] point 303 | /// on the JubJub curve. This public key allows for the verification of 304 | /// signatures created with its corresponding variable generator secret key 305 | /// without revealing the secret key itself. 306 | /// 307 | /// # Feature 308 | /// 309 | /// Only available with the "var_generator" feature enabled. 310 | /// 311 | /// ## Examples 312 | /// 313 | /// Generate a [`PublicKeyVarGen`] from a [`SecretKeyVarGen`]: 314 | /// ``` 315 | /// use dusk_schnorr::{SecretKeyVarGen, PublicKeyVarGen}; 316 | /// use dusk_bls12_381::BlsScalar; 317 | /// use rand::rngs::StdRng; 318 | /// use rand::SeedableRng; 319 | /// 320 | /// let mut rng = StdRng::seed_from_u64(12345); 321 | /// let sk = SecretKeyVarGen::random(&mut rng); 322 | /// let pk = PublicKeyVarGen::from(&sk); 323 | /// ``` 324 | #[derive(Default, Copy, Clone, Debug, PartialEq)] 325 | #[cfg_attr( 326 | feature = "rkyv-impl", 327 | derive(Archive, Serialize, Deserialize), 328 | archive_attr(derive(bytecheck::CheckBytes)) 329 | )] 330 | #[cfg(feature = "var_generator")] 331 | pub struct PublicKeyVarGen { 332 | pk: JubJubExtended, 333 | generator: JubJubExtended, 334 | } 335 | 336 | #[cfg(feature = "var_generator")] 337 | impl From<&SecretKeyVarGen> for PublicKeyVarGen { 338 | fn from(sk: &SecretKeyVarGen) -> Self { 339 | let generator = sk.generator().clone(); 340 | let pk = generator * sk.secret_key(); 341 | 342 | PublicKeyVarGen { pk, generator } 343 | } 344 | } 345 | 346 | #[cfg(feature = "var_generator")] 347 | impl Serializable<64> for PublicKeyVarGen { 348 | type Error = Error; 349 | 350 | fn to_bytes(&self) -> [u8; 64] { 351 | let mut buf = [0u8; 64]; 352 | let pk: JubJubAffine = self.pk.into(); 353 | let pk_bytes = pk.to_bytes(); 354 | let gen: JubJubAffine = self.generator.into(); 355 | let gen_bytes = gen.to_bytes(); 356 | buf[..32].copy_from_slice(&pk_bytes); 357 | buf[32..].copy_from_slice(&gen_bytes); 358 | buf 359 | } 360 | 361 | fn from_bytes(bytes: &[u8; 64]) -> Result { 362 | let mut pk_bytes = [0u8; 32]; 363 | let mut gen_bytes = [0u8; 32]; 364 | pk_bytes.copy_from_slice(&bytes[..32]); 365 | gen_bytes.copy_from_slice(&bytes[32..]); 366 | let pk: JubJubExtended = 367 | >::from_bytes(&pk_bytes)?.into(); 368 | let generator: JubJubExtended = 369 | >::from_bytes(&gen_bytes)?.into(); 370 | Ok(Self { pk, generator }) 371 | } 372 | } 373 | 374 | #[cfg(feature = "var_generator")] 375 | impl PublicKeyVarGen { 376 | /// Returns a reference to the [`JubJubExtended`] public key. 377 | pub fn public_key(&self) -> &JubJubExtended { 378 | &self.pk 379 | } 380 | 381 | /// Returns a reference to the [`JubJubExtended`] generator. 382 | pub fn generator(&self) -> &JubJubExtended { 383 | &self.generator 384 | } 385 | 386 | /// Verifies that the given Schnorr [`SignatureVarGen`] is valid. 387 | /// 388 | /// This function computes a challenge hash using the stored `R` point and 389 | /// the provided message, then performs the verification by checking the 390 | /// equality of `u * G + c * PK` and `R`. 391 | /// 392 | /// ## Parameters 393 | /// 394 | /// - `sig_var_gen`: Reference to the [`SignatureVarGen`] to be verified. 395 | /// - `message`: The message in [`BlsScalar`] format. 396 | /// 397 | /// ## Returns 398 | /// 399 | /// A boolean value indicating the validity of the Schnorr 400 | /// [`SignatureVarGen`]. 401 | pub fn verify( 402 | &self, 403 | sig_var_gen: &SignatureVarGen, 404 | message: BlsScalar, 405 | ) -> bool { 406 | // Compute challenge value, c = H(R||H(m)); 407 | let c = crate::signatures::challenge_hash(sig_var_gen.R(), message); 408 | 409 | // Compute verification steps 410 | // u * G + c * PK 411 | let point_1 = 412 | (*self.generator() * sig_var_gen.u()) + (self.public_key() * c); 413 | 414 | point_1.eq(&sig_var_gen.R()) 415 | } 416 | 417 | /// Create a [`PublicKeyVarGen`] from its internal parts 418 | /// 419 | /// The public keys are generated from a bijective function that takes a 420 | /// secret keys domain. If keys are generated directly from curve 421 | /// points, there is no guarantee a secret key exists - in fact, the 422 | /// discrete logarithm property will guarantee the secret key cannot be 423 | /// extracted from this public key. 424 | /// 425 | /// If you opt to generate the keys manually, be sure you have its secret 426 | /// counterpart - otherwise this key will be of no use. 427 | pub const fn from_raw_unchecked( 428 | pk: JubJubExtended, 429 | generator: JubJubExtended, 430 | ) -> Self { 431 | Self { pk, generator } 432 | } 433 | } 434 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | --------------------------------------------------------------------------------