Schnorr VRFs and signatures on the Ristretto group

Overview

schnorrkel

Schnorrkel implements Schnorr signature on Ristretto compressed Ed25519 points, as well as related protocols like HDKD, MuSig, and a verifiable random function (VRF).

Ristretto implements roughly section 7 of Mike Hamburg's Decaf paper to provide the 2-torsion free points of the Ed25519 curve as a prime order group. (related)

We employ the merlin strategy of type specific hashing methods with sound domain separation. These wrap Mike Hamburg's STROBE128 construction for symmetric cryptography, itself based on Keccak.

In practice, all our methods consume either a merlin::Transcript which developers create handily by feeding data to context specific builders. We do however also support &mut merlin::Transcript like the merlin crate prefers. We shall exploit this in future to adapt schnorrkel to better conform with the dalek ecosystem's zero-knowledge proof tooling.

We model the VRF itself on "Making NSEC5 Practical for DNSSEC" by Dimitrios Papadopoulos, Duane Wessels, Shumon Huque, Moni Naor, Jan Včelák, Leonid Rezyin, andd Sharon Goldberg. We note the V(X)EdDSA signature scheme by Trevor Perrin at is basically identical to the NSEC5 construction. Also, the VRF supports individual signers merging numerous VRF outputs created with the same keypair, which parallels the "DLEQ Proofs" and "Batching the Proofs" sections of "Privacy Pass - The Math" by Alex Davidson, and "Privacy Pass: Bypassing Internet Challenges Anonymously" by Alex Davidson, Ian Goldberg, Nick Sullivan, George Tankersley, and Filippo Valsorda.

Aside from some naive sequential VRF construction, we currently only support the three-round MuSig for Schnorr multi-signatures, due to all other Schnorr multi-signatures being somewhat broken. In future, we should develop secure schemes like mBCJ from section 5.1 starting page 21 of https://eprint.iacr.org/2018/417 however mBCJ itself works by proof-of-possession, while a delinearized variant sounds more applicable.

There are partial bindings for C, JavaScript, and Python as well.

Comments
  • `getrandom` feature should enable `rand_core/getrandom`

    `getrandom` feature should enable `rand_core/getrandom`

    Hello, I'm currently using this in a no_std environment and after adding my own getrandom implementation I enabled the getrandom feature of your crate but alas I got a compile error in your rand_hack when rand is not enabled.

    Compiling schnorrkel v0.9.2
    error[E0425]: cannot find value `OsRng` in crate `rand_core`
       --> /home/becominginsane/.cargo/registry/src/github.com-1ecc6299db9ec823/schnorrkel-0.9.2/src/lib.rs:233:18
        |
    233 |     ::rand_core::OsRng
        |                  ^^^^^ not found in `rand_core`
    
    error: aborting due to previous error
    
    For more information about this error, try `rustc --explain E0425`.
    error: could not compile `schnorrkel`
    

    I believe schnorrkel should enable rand_core/getrandom when the feature is enabled, as this scheme currently requires the user to add the feature manually

    opened by becominginsane 9
  • add dh

    add dh

    Seems like dh could be easily added [0] and there seems to be precedent for using the same keys for both signing and encryption [1].

    • [0] https://github.com/ZcashFoundation/ristretto255-dh
    • [1] https://signal.org/docs/specifications/xeddsa/
    opened by dvc94ch 9
  • Publish a new version?

    Publish a new version?

    The latest version has been published back in March 2020, around 10 months ago. The diff is starting to be quite substantial: https://github.com/w3f/schnorrkel/compare/156b84d6b49c43b49d38869a355a472ce9f30ef3...master

    opened by tomaka 7
  • Update travis.yml, add clippy, rust fmt

    Update travis.yml, add clippy, rust fmt

    While skimming through this repo, I've noticed a few things that a .travis.yml exists but still seems to contain arteefacts from dalek-cryptography? https://github.com/w3f/schnorrkel/blob/eaf66334f251984a9a9dd545a1c3bb043da62e12/.travis.yml#L30 I think re-enabling travis, and at least adding rust fmt, clippy, cargo audit (and maybe other lints), would help to keep the code quality high.

    opened by liamsi 7
  • Keypair::vrf_sign ignores (partially) passed RNG

    Keypair::vrf_sign ignores (partially) passed RNG

    When attempting to using vrf sign in #[no_std] context, no rand features, and with a custom rng attached to my transcript (via attach_rng) I got a panic, since schnorrkel was attempting to use os-provided rng.

    I think it might be due to the "extra" transcript being generated anew without basing it on the existing's transcript rng...

    Backtrace
    test tests::verify_vrf_sign ... thread 'main' panicked at 'Attempted to use functionality that requires system randomness!!', /home/karrq/.cargo/registry/src/github.com-1ecc6299db9ec823/schnorrkel-0.10.1/src/lib.rs:250:55
    stack backtrace:
      0: rust_begin_unwind
                at /rustc/07e0e2ec268c140e607e1ac7f49f145612d0f597/library/std/src/panicking.rs:493:5
      1: core::panicking::panic_fmt
                at /rustc/07e0e2ec268c140e607e1ac7f49f145612d0f597/library/core/src/panicking.rs:92:14
      2: core::panicking::panic_str
                at /home/karrq/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/panicking.rs:57:5
      3: <schnorrkel::rand_hack::PanicRng as rand_core::RngCore>::fill_bytes
                at /home/karrq/.cargo/registry/src/github.com-1ecc6299db9ec823/schnorrkel-0.10.1/src/lib.rs:250:55
      4: merlin::transcript::TranscriptRngBuilder::finalize
                at /home/karrq/.cargo/registry/src/github.com-1ecc6299db9ec823/merlin-3.0.0/src/transcript.rs:329:13
      5: <merlin::transcript::Transcript as schnorrkel::context::SigningTranscript>::witness_bytes_rng
                at /home/karrq/.cargo/registry/src/github.com-1ecc6299db9ec823/schnorrkel-0.10.1/src/context.rs:160:21
      6: schnorrkel::context::SigningTranscript::witness_bytes
                at /home/karrq/.cargo/registry/src/github.com-1ecc6299db9ec823/schnorrkel-0.10.1/src/context.rs:97:9
      7: schnorrkel::context::SigningTranscript::witness_scalar
                at /home/karrq/.cargo/registry/src/github.com-1ecc6299db9ec823/schnorrkel-0.10.1/src/context.rs:90:9
      8: schnorrkel::vrf::<impl schnorrkel::keys::Keypair>::dleq_proove
                at /home/karrq/.cargo/registry/src/github.com-1ecc6299db9ec823/schnorrkel-0.10.1/src/vrf.rs:637:21
      9: schnorrkel::vrf::<impl schnorrkel::keys::Keypair>::vrf_sign_extra
                at /home/karrq/.cargo/registry/src/github.com-1ecc6299db9ec823/schnorrkel-0.10.1/src/vrf.rs:678:40
     10: schnorrkel::vrf::<impl schnorrkel::keys::Keypair>::vrf_sign
                at /home/karrq/.cargo/registry/src/github.com-1ecc6299db9ec823/schnorrkel-0.10.1/src/vrf.rs:667:9
    
    opened by becominginsane 6
  • Version 0.9.2 breaks semver

    Version 0.9.2 breaks semver

    related https://github.com/paritytech/substrate/issues/8208

    semver breakage in 0.9.2

    it seems 0.9.2 is breaking semver because of merlin major update (from 2.0 to 3.0)

    It is because merlin is publicly used: SigningTranscript is implemented on merlin::Transcript

    sidenote about rng_hack failing in std or with u64_backend and getrandom but no std.

    schnorrkel with features "std" fails with:

    error[E0425]: cannot find function `thread_rng` in crate `rand`
       --> src/lib.rs:228:13
        |
    228 |     ::rand::thread_rng()
        |             ^^^^^^^^^^ not found in `rand`
    
    

    for this we need to set the feature rand/std_rng.

    And schnrrkel with features "u64_backend" and "getrandom" (and no default features) fails with:

    error[E0425]: cannot find value `OsRng` in crate `rand_core`
       --> src/lib.rs:233:18
        |
    233 |     ::rand_core::OsRng
        |                  ^^^^^ not found in `rand_core`
    
    

    I think to fix it we should add specific features to set the rng:

    rand_std_rng = ["rand/std_rng"]
    getrandom_rng = ["rand_core/getrandom"]
    std = ["rand_std_rng", ...]
    
    opened by thiolliere 6
  • Compatibility between Starsig and Schnorrkel

    Compatibility between Starsig and Schnorrkel

    Hi,

    I'd like to make Starsig and Schnorrkel compatible and maybe bikeshed the labels a little. Have you deployed Schnorrkel already, is it hard to update the labels? Would love to hear your thoughts on this: https://github.com/stellar/slingshot/issues/382

    Thanks!

    opened by oleganza 6
  • Use `serde_bytes`

    Use `serde_bytes`

    This PR addresses the issue outlined in #66.

    2 new dependencies were added: serde_bytes to actually use when serializing and deserializing, and cfg_if, so deserialization can use Bytes when in no alloc context and BytesBuf otherwise, since the latter allows to deserialize from more data types where the size is not known or it is not borrowable, such as sequences.

    serde has also been renamed in the manifest as serde_crate, similar to curve25519-dalek's manifest, to allow bundling serde_bytes and serde in a single feature flag.

    Tests were added to check compatibility with serde_json

    Closes #66

    opened by becominginsane 5
  • PublicKey incompatible with serde_json

    PublicKey incompatible with serde_json

    During testing I encountered an error when trying to deserialize a PublicKey from a serde_json::Value

    Error:

    thread 'main' panicked at 'unable to deserialize PublicKey: Error("invalid type: sequence, expected A Ristretto Schnorr public key represented as a 32-byte Ristretto compressed point", line: 0, column: 0)', src/main.rs:11:40
    

    example code can be found here.

    I think this can be fixed in multiple ways, either by implementing visit_seq or by making use of serde_bytes (even tho it will probably mean that it'll be necessary to wrap with Bytes during serialization / deserialization manually instead of using the attributes offered)

    opened by becominginsane 5
  • Test vectors

    Test vectors

    Adding some test vectors may be helpful to ensure internal consistency.

    • few vectors for expanding Secrets into Keypairs, and comparing a known result
    • few vectors for signing a payload and comparing to a known result
    • few vectors for verifying a result we know should correctly verify
    good first issue 
    opened by Mischala 5
  • What Is The Signing Context For?

    What Is The Signing Context For?

    Hello,

    I am trying to use schnorr signatures and know that to sign you need a nonce. I know you cannot use the same nonce twice.

    My question is that with schnorr signatures, is the signing context made into the nonce. In other words, how do I sign a message by using the signing context if I do not want anything in the signing context? Can I use a static value for the signing context and safely make more signatures with the same signing context?

    Sorry if this is a naive question or confusing.

    Thank you

    opened by AtropineTears 4
  • Adopt the new secret key interface

    Adopt the new secret key interface

    We should replace the loose public key interface we inherited from ed25519-dalek:

    • https://docs.rs/schnorrkel/latest/schnorrkel/keys/struct.Keypair.html
    • https://docs.rs/schnorrkel/latest/schnorrkel/keys/struct.SecretKey.html#method.sign

    We'll basically make SecretKey be a keypair that contains the PublicKey. I'm already doing the ring VRF this way, so then we can backport stuff. It's kind an overhaul of the whole crate interface, but once someone asked me how to use schnorrkel with the randomness in merlin disabled, so likely worth doing.

    opened by burdges 0
  • failed to verify signatures generated by `polkadot-js`

    failed to verify signatures generated by `polkadot-js`

    Description

    Hello! I'm trying to use the repository https://github.com/w3f/schnorrkel, more specifically the function verify_simple to verify signatures generated by polkadot-js using thesignRaw function and unforunately it's not working. However the function signatureVerify from @polkadot/util-crypto verify correctly the same signature.

    Steps to reproduce

    1. I've used the polkadot extension and the polkadot-js to generate the signature

    https://user-images.githubusercontent.com/17255488/147632039-8dad0b7a-2584-4a3c-9e16-08654d153720.mov

    output at console.log 
    
    Public Key (hex) 0xf84d048da2ddae2d9d8fd6763f469566e8817a26114f39408de15547f6d47805
    Message => message to sign
    Signature (hex) 0x48ce2c90e08651adfc8ecef84e916f6d1bb51ebebd16150ee12df247841a5437951ea0f9d632ca165e6ab391532e75e701be6a1caa88c8a6bcca3511f55b4183
    
    1. With the https://github.com/w3f/schnorrkel cloned at my machine I created the following test case (which fails) at src/sign.rs file:
    #[test]
    fn verify_polkadot_js_signature() {
          use hex_literal::hex;
          const CTX : &'static [u8] = b"substrate";
            
          let message = b"message to sign";
          let public = hex!("f84d048da2ddae2d9d8fd6763f469566e8817a26114f39408de15547f6d47805");
          let public = PublicKey::from_bytes(&public[..]).unwrap();
            
          let signature = hex!("48ce2c90e08651adfc8ecef84e916f6d1bb51ebebd16150ee12df247841a5437951ea0f9d632ca165e6ab391532e75e701be6a1caa88c8a6bcca3511f55b4183");
          let signature = Signature::from_bytes(&signature).unwrap();
            
          let ok = public.verify_simple(CTX, message, &signature).is_ok();
          assert!(ok)
    }
    

    Debugging the polkadot-js signatureVerify function I noticed that this function calls the rust function ext_sr_verify under the hoods by a WASM biding (very interestingly 😄 ) and the rust function uses the same w3f/schnorrkel repository, then I assumed the function ext_sr_sign is used to generate the signature so I decided to create the following test case that uses these 2 functions to generate and verify a signature:

        #[test]
    fn sign_and_verify() {
            const CTX : &'static [u8] = b"substrate";
            let sec = SecretKey::generate();
            let pub_bytes = sec.to_public().to_bytes();
            
            // ext_sr_sign function
            let sig = match (SecretKey::from_ed25519_bytes(&sec.to_bytes()), PublicKey::from_bytes(&pub_bytes)) {
                (Ok(s), Ok(k)) => s
                    .sign_simple(CTX, message, &k)
                    .to_bytes()
                    .to_vec(),
                _ => panic!("Invalid secret or pubkey provided.")
            };
    
            // ext_sr_verify function
            let res =   match (Signature::from_bytes(&sig), PublicKey::from_bytes(&pub_bytes)) {
                (Ok(s), Ok(k)) => k
                    .verify_simple(CTX, message, &s)
                    .is_ok(),
                _ => false
            };
    
            assert!(res)
    }
    

    And unfortunately, this test case fails. The same thing happens with the https://github.com/ChainSafe/go-schnorrkel package, the original issue was reported into Gossamer discord channel.

    Thanks in advance!

    opened by EclesioMeloJunior 10
  • Remove serde?

    Remove serde?

    Is serde too dangerous for key format stability? Should we remove the serde feature?

    It's likely fine if someone uses bincode, etc. but if someone use something with unicode or utf-8 then maybe they'd output ligatures or something similarly messed up

    Any thoughts @ordian or @becominginsane ?

    Related:

    • https://github.com/paritytech/substrate/issues/9072
    • https://github.com/w3f/schnorrkel/commits/master/src/serdey.rs
    opened by burdges 0
  • VRF2

    VRF2

    I discovered a trick that avoids the separate individual and batchable VRFProof types, which we'll adopt in the ring VRF crate, so maybe the correct solution would be adopting that here via some VRF2 proof/signature type that requires a PoK. We'd maybe remove VRFProofBatchable from the older VRF design.

    I believe VRF2 simplifies doing https://github.com/w3f/schnorrkel/issues/5 with some pre-signing abstraction for witness creation, so we'd eventually generalize the multi-signatures to cover VRF2 after doing https://github.com/w3f/schnorrkel/issues/6 and https://github.com/w3f/schnorrkel/issues/11

    I've closed #26 in favor of this. It's different functionality but if you go too far that direction you need bulletproofs really, and the little step never materialized.

    opened by burdges 1
  • DiffieHellman exchange as AEAD key

    DiffieHellman exchange as AEAD key

    The output of the raw diffie-hellman is used as the aead key after compression. Afaik standard practice is to use a hkdf over diffie-hellman to get symmetric keys. Is there a reason why this isn't needed/recommended here?

    opened by troublescooter 11
  • Add bitfield signed messages?

    Add bitfield signed messages?

    We could add some analog of the bitfield signed message stuff from the BLS crate: https://github.com/w3f/bls/blob/master/src/bit.rs

    Right now, you must implement it yourself using AggregatePublicKey::public_key, but you also cannot really screw it up since you cannot merge signatures like in BLS, so I'm not sure it's really critical here.

    opened by burdges 0
Owner
Web3 Foundation
Web3 Foundation
A pure-Rust implementation of group operations on Ristretto and Curve25519

curve25519-dalek A pure-Rust implementation of group operations on Ristretto and Curve25519. curve25519-dalek is a library providing group operations

dalek cryptography 611 Dec 25, 2022
A pure-Rust implementation of Bulletproofs using Ristretto.

Bulletproofs The fastest Bulletproofs implementation ever, featuring single and aggregated range proofs, strongly-typed multiparty computation, and a

dalek cryptography 832 Dec 28, 2022
A pairing-based threshold cryptosystem for collaborative decryption and signatures used in HoneybadgerBFT implementation

threshold_crypto A pairing-based threshold cryptosystem for collaborative decryption and signatures. The threshold_crypto crate provides cryptographic

null 166 Dec 29, 2022
Multi Party Key Management System (KMS) for Secp256k1 Elliptic curve based digital signatures.

Key Management System (KMS) for curve Secp256k1 Multi Party Key Management System (KMS) for Secp256k1 Elliptic curve based digital signatures. Introdu

[ZenGo X] 61 Dec 28, 2022
NIST P-256 signatures for Cortex-M4 microcontrollers

nisty NIST P256 signatures for Cortex-M4 microcontrollers What is this? Sometimes NIST P256 signatures need to be used. This is an attempt to create a

null 13 Mar 14, 2021
BLS Signatures in Rust

BLS Signatures Implementation of BLS signatures in pure Rust. Development BLST Portability To enable the portable feature when building blst dependenc

Filecoin 50 Dec 25, 2022
Generates Solidity code to verify EIP-712 style signatures

eip712 Generates Solidity code to verify EIP-712 style signatures. Usage First, create an abstract contract implementing the functionality you want: /

Sam Wilson 11 Dec 22, 2022
A tool to optimize your Solidity function signatures.

sigop A CLI tool to optimize your Solidity function signatures. I wanted to create this after seeing transmissions11's comment about this optimization

Quartz Technology 11 Nov 24, 2022
L2 validity rollup combined with blind signatures over elliptic curves inside zkSNARK, to provide offchain anonymous voting with onchain binding execution on Ethereum

blind-ovote Blind-OVOTE is a L2 voting solution which combines the validity rollup ideas with blind signatures over elliptic curves inside zkSNARK, to

Aragon ZK Research 3 Nov 18, 2022
Two-party and multi-party ECDSA protocols based on class group with Rust

CG-MPC-ECDSA This project aims to implement two-party and multi-party ECDSA protocols based on class group with Rust. It currently includes schemes de

LatticeX Foundation 16 Mar 17, 2022
A Rust implementation of the Message Layer Security group messaging protocol

Molasses An extremely early implementation of the Message Layer Security group messaging protocol. This repo is based on draft 4 of the MLS protocol s

Trail of Bits 109 Dec 13, 2022
Multilayered Linkable Spontaneous Anonymous Group - Implemented as is from paper. Not Monero specific

MLSAG This is a pure Rust implementation of the Multilayered Linkable Spontaneous Anonymous Group construction. This implementation has not been revie

Crate Crypto 19 Dec 4, 2022
Implementation of the BLS12-381 pairing-friendly elliptic curve group

bls12_381 This crate provides an implementation of the BLS12-381 pairing-friendly elliptic curve construction. This implementation has not been review

Zero-knowledge Cryptography in Rust 183 Dec 27, 2022
IBC modules and relayer - Formal specifications and Rust implementation

ibc-rs Rust implementation of the Inter-Blockchain Communication (IBC) protocol. This project comprises primarily four crates: The ibc crate defines t

Informal Systems 296 Dec 31, 2022
Diem’s mission is to build a trusted and innovative financial network that empowers people and businesses around the world.

Note to readers: On December 1, 2020, the Libra Association was renamed to Diem Association. The project repos are in the process of being migrated. A

Diem 16.7k Jan 8, 2023
Fast and efficient ed25519 signing and verification in Rust.

ed25519-dalek Fast and efficient Rust implementation of ed25519 key generation, signing, and verification in Rust. Documentation Documentation is avai

dalek cryptography 563 Dec 26, 2022
A safe implementation of the secure remote password authentication and key-exchange protocol (SRP), SRP6a and legacy are as features available.

Secure Remote Password (SRP 6 / 6a) A safe implementation of the secure remote password authentication and key-exchange protocol (SRP version 6a). Ver

Sven Assmann 10 Nov 3, 2022
Retrieving SSH and GPS keys from GitHub and GitLab

Dormarch Retrieving SSH and GPS keys from GitHub and GitLab Usage After having installed Dormarch, you can see all the options with dormarch -h. To re

Riccardo Padovani 2 Dec 24, 2021
Terabethia - A Bridge and Messaging Protocol between Ethereum and the Internet Computer.

Terabethia - A Bridge Between Ethereum & the Internet Computer Terabethia is a bridge between Ethereum & the Internet Computer that contracts in both

Psychedelic 36 Dec 26, 2022