├── .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 | 
3 | [](https://github.com/dusk-network/schnorr)
4 | [](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 |
--------------------------------------------------------------------------------