Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions pallas-crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ thiserror = "1.0"
rand_core = "0.9"
serde = { version = "1.0.143", features = ["derive"] }
pallas-codec = { version = "=1.0.0-alpha.3", path = "../pallas-codec" }
cardano-crypto = { version = "=1.0.6", optional = true, features = ["vrf"] }
Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using exact version match for dependency. The cardano-crypto dependency uses '=1.0.6' which requires an exact version match. While this ensures reproducibility, it may cause issues when other crates in the dependency tree need a different patch version of the same major.minor version. Consider using '^1.0.6' (caret requirements) or '~1.0.6' (tilde requirements) to allow compatible patch updates while maintaining stability.

Suggested change
cardano-crypto = { version = "=1.0.6", optional = true, features = ["vrf"] }
cardano-crypto = { version = "^1.0.6", optional = true, features = ["vrf"] }

Copilot uses AI. Check for mistakes.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check cardano-crypto versions on crates.io
curl -s https://crates.io/api/v1/crates/cardano-crypto | jq '.versions[] | select(.num | test("1\\.0")) | {num, created_at, yanked}' | head -50

Repository: txpipe/pallas

Length of output: 665


🏁 Script executed:

#!/bin/bash
# Get summary info about cardano-crypto crate
curl -s https://crates.io/api/v1/crates/cardano-crypto | jq '.crate | {name, max_version, documentation}'

Repository: txpipe/pallas

Length of output: 166


🏁 Script executed:

#!/bin/bash
# Search for any security advisories or issues with cardano-crypto
curl -s https://rustsec.org/advisory.json | jq '.[] | select(.crate.name == "cardano-crypto") | {id, crate, title, date}'

Repository: txpipe/pallas

Length of output: 114


🌐 Web query:

cardano-crypto 1.0.6 security vulnerability advisory

💡 Result:

I couldn't find any published security advisory or CVE specifically for cardano-crypto 1.0.6. The package pages I checked (Hackage and docs.rs) show the cardano-crypto project but contain no vulnerability advisory for 1.0.6. [1][2]

If you want, I can:

  • run deeper CVE/NVD and GitHub issue/commit searches for that exact version, or
  • monitor vendor channels (Cardano release notes, Hackage package page, GitHub) and alert you if an advisory appears.

Sources:

  1. Hackage — cardano-crypto package page. [1]
  2. docs.rs — cardano-crypto crate pages (examples: 1.0.1, 1.0.5). [2]

Review the rationale for exact version pinning on cardano-crypto.

Version 1.0.6 exists, is the latest available, and has no known security advisories. However, the exact version constraint =1.0.6 will prevent adopting future patch releases. For a cryptographic library, confirm that this strict pinning is intentional and document the reason—whether for reproducibility, compatibility, or other constraints. If intentional, consider documenting it; otherwise, consider using ^1.0.6 to allow patch-level updates.

🤖 Prompt for AI Agents
In pallas-crypto/Cargo.toml around line 23 the dependency is pinned exact to
cardano-crypto = "=1.0.6", which prevents automatic adoption of future patch
fixes; either (A) if strict pinning is intentional for reproducibility or
compatibility, add a clear comment immediately above that line documenting the
rationale (e.g., ABI/behavior guarantees, tested release, or security/regulatory
requirement), or (B) if strict pinning is not required, relax the constraint to
allow patch updates by changing the requirement to ^1.0.6 (or use "1.0.6"
without =) so cargo will accept compatible patch releases; after changing, run
cargo update and test to ensure no regressions.


# kes dependencies
rand = { version = "0.9", optional = true }
Expand All @@ -42,6 +43,7 @@ default = []
sk_clone_enabled = []
kes = ["rand", "rand_chacha", "serde_with", "ed25519-dalek", "zeroize"]
relaxed = []
vrf = ["cardano-crypto/vrf"]

[[bench]]
harness = false
Expand Down
2 changes: 1 addition & 1 deletion pallas-crypto/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Crate with all the cryptographic material to support Cardano protocol:
- [x] Ed25519 Extended asymmetric key pair
- [ ] Bip32-Ed25519 key derivation
- [ ] BIP39 mnemonics
- [x] VRF
- [x] VRF (draft-03 and draft-13, behind the `vrf` feature)
- [x] [KES](src/kes/README.md)
- [ ] SECP256k1
- [x] Nonce calculations
7 changes: 7 additions & 0 deletions pallas-crypto/proptest-regressions/kes/summed_kes_tests.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Seeds for failure cases proptest has generated in the past. It is
# automatically read and these particular cases re-run before any
# novel cases are generated.
#
# It is recommended to check this file in to source control so that
# everyone who runs the test benefits from these saved cases.
cc a80811a55e353e6c0a9e2fb8bcc9331942c135baf17fea40c45b258aaa926c09 # shrinks to ((mut sk_bytes,pk),msg1,msg2) = (([118, 121, 140, 51, 101, 51, 163, 103, 235, 28, 143, 46, 23, 39, 102, 159, 3, 166, 178, 183, 145, 159, 199, 149, 221, 188, 177, 156, 251, 0, 120, 48, 26, 41, 81, 47, 50, 158, 95, 189, 47, 46, 196, 91, 131, 108, 2, 69, 219, 255, 46, 128, 103, 108, 82, 236, 55, 105, 210, 57, 189, 70, 145, 169, 196, 71, 254, 141, 70, 197, 189, 242, 7, 216, 170, 28, 166, 128, 195, 49, 110, 62, 186, 177, 58, 103, 6, 164, 62, 56, 83, 82, 19, 166, 0, 156, 51, 17, 32, 79, 87, 94, 90, 106, 181, 195, 124, 188, 72, 148, 114, 132, 89, 83, 191, 241, 63, 78, 85, 37, 245, 98, 65, 169, 129, 108, 136, 138, 227, 102, 43, 118, 77, 163, 227, 112, 111, 204, 101, 26, 132, 181, 91, 131, 95, 211, 240, 225, 115, 131, 210, 195, 222, 146, 15, 227, 58, 62, 69, 23, 92, 184, 60, 255, 172, 115, 30, 174, 92, 25, 25, 10, 40, 23, 228, 203, 28, 162, 69, 142, 77, 128, 68, 70, 134, 253, 221, 13, 45, 94, 115, 0, 166, 116, 181, 77, 120, 117, 36, 43, 166, 150, 140, 27, 108, 4, 184, 88, 27, 66, 119, 83, 102, 46, 190, 150, 165, 223, 56, 55, 50, 237, 91, 240, 137, 156, 122, 26, 49, 15, 29, 121, 240, 215, 65, 111, 191, 183, 200, 195, 53, 46, 187, 218, 178, 24, 56, 96, 21, 143, 122, 149, 50, 193, 122, 142, 192, 181, 155, 199, 52, 67, 29, 6, 215, 250, 215, 137, 227, 42, 248, 102, 118, 247, 59, 254, 229, 1, 134, 60, 234, 80, 210, 235, 252, 36, 99, 68, 101, 170, 146, 97, 6, 6, 6, 8, 71, 251, 64, 179, 144, 98, 170, 131, 152, 111, 252, 127, 150, 161, 80, 99, 224, 46, 25, 173, 170, 30, 13, 146, 50, 51, 155, 190, 232, 53, 157, 79, 209, 109, 188, 2, 37, 8, 75, 19, 46, 248, 55, 97, 19, 212, 93, 101, 5, 41, 197, 211, 117, 220, 28, 10, 230, 84, 248, 143, 30, 254, 217, 46, 235, 222, 52, 72, 247, 200, 114, 220, 48, 96, 222, 97, 126, 187, 52, 197, 89, 159, 105, 244, 8, 31, 121, 106, 94, 182, 48, 63, 193, 12, 250, 28, 93, 73, 235, 141, 218, 11, 190, 114, 29, 94, 16, 184, 88, 218, 174, 195, 109, 171, 3, 198, 76, 215, 3, 193, 74, 212, 49, 128, 2, 99, 132, 165, 11, 107, 152, 165, 64, 4, 248, 95, 122, 88, 142, 35, 184, 216, 181, 92, 188, 74, 42, 2, 116, 113, 168, 155, 246, 221, 110, 206, 41, 26, 247, 173, 26, 154, 132, 215, 31, 96, 184, 163, 125, 27, 100, 7, 205, 65, 160, 111, 123, 166, 4, 10, 112, 94, 185, 249, 201, 76, 248, 194, 123, 81, 226, 130, 128, 139, 72, 235, 214, 229, 222, 86, 247, 76, 249, 76, 108, 243, 242, 249, 136, 25, 130, 65, 102, 240, 24, 89, 118, 111, 138, 76, 90, 115, 25, 128, 20, 233, 207, 172, 30, 210, 124, 94, 254, 143, 172, 205, 186, 45, 228, 77, 247, 91, 171, 180, 204, 201, 221, 214, 119, 144, 27, 239, 128, 22, 52, 169, 231, 58, 209, 94, 15, 76, 65, 213, 60, 253, 166, 101, 7, 83, 225, 251, 95, 198, 184, 65, 33, 52, 106, 110, 190, 165, 83, 46, 152, 181, 18, 232, 101, 90, 154, 191, 9, 3, 213, 99, 48, 208, 136, 233, 142, 21, 72, 14, 124, 213, 191, 4, 13, 140, 19, 71, 0, 0, 0, 0], PublicKey([220, 226, 205, 176, 140, 133, 89, 107, 176, 150, 130, 165, 8, 119, 148, 63, 96, 138, 43, 31, 154, 151, 32, 236, 113, 152, 197, 198, 142, 158, 38, 162])), [], [])
3 changes: 2 additions & 1 deletion pallas-crypto/src/kes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ This library defines macros to generate KES algorithms with different depths. We
algorithms up to depth 7. However, if you require a higher depth key, feel free to open an
issue/PR.

This module requires the `kes` feature flag.
This module requires the `kes` feature flag. VRF support (draft-03 and draft-13) now lives
alongside KES under the `vrf` feature; Cardano currently uses KES Sum6 and VRF draft-03.

## Library usage

Expand Down
4 changes: 4 additions & 0 deletions pallas-crypto/src/kes/summed_kes_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ mod test {

#[test]
fn two_msgs_have_different_signature_with_one_skey(((mut sk_bytes,_pk),msg1,msg2) in (secret_public_key_bytes(), payload(),payload())) {
prop_assume!(msg1 != msg2);

let mut sk_bytes1 = [0u8; Sum6Kes::SIZE + 4];
sk_bytes1.copy_from_slice(&sk_bytes);
let sk = Sum6Kes::from_bytes(&mut sk_bytes);
Expand All @@ -70,6 +72,8 @@ mod test {

#[test]
fn simple_verification_fails_for_other_msg(((mut sk_bytes,pk),msg1,msg2) in (secret_public_key_bytes(), payload(), payload())) {
prop_assume!(msg1 != msg2);

let sk = Sum6Kes::from_bytes(&mut sk_bytes);
let sig = sk?.sign(&msg1);
let err_str = String::from("signature error: Verification equation was not satisfied");
Expand Down
2 changes: 2 additions & 0 deletions pallas-crypto/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ pub mod kes;
pub mod key;
pub mod memsec;
pub mod nonce;
#[cfg(feature = "vrf")]
pub mod vrf;
101 changes: 101 additions & 0 deletions pallas-crypto/src/vrf/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
//! Verifiable Random Functions (VRF) bindings
//!
//! This module re-exports Cardano-compatible VRF primitives from the `cardano-crypto`
//! crate so downstream users can generate proofs and verify outputs for both
//! draft-03 (Cardano standard) and draft-13 variants.

use cardano_crypto::common::{CryptoError, CryptoResult};
use cardano_crypto::vrf::CertifiedVrf;

pub use cardano_crypto::vrf::{
cardano_compat::cardano_vrf_prove as prove_cardano,
cardano_compat::cardano_vrf_verify as verify_cardano, CertifiedVrf as CertifiedOutput,
OutputVrf as Output, VrfDraft03, VrfDraft13, VrfKeyPair, VrfProof, VrfSigningKey,
VrfVerificationKey, DRAFT03_PROOF_SIZE, DRAFT13_PROOF_SIZE, OUTPUT_SIZE, PUBLIC_KEY_SIZE,
SECRET_KEY_SIZE, SEED_SIZE,
};

/// Generate a draft-03 keypair from a 32-byte seed.
Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing documentation about draft variant compatibility. Since the module supports both draft-03 and draft-13, it would be helpful to document that keypairs generated by this function can be used with both variants, or if they're specific to draft-03 only.

Suggested change
/// Generate a draft-03 keypair from a 32-byte seed.
/// Generate a VRF keypair from a 32-byte seed.
///
/// The generated keypair is compatible with both draft-03 (Cardano standard) and draft-13 VRF variants.

Copilot uses AI. Check for mistakes.
pub fn keypair_from_seed(seed: &[u8; SEED_SIZE]) -> VrfKeyPair {
VrfKeyPair::generate(seed)
}
Comment on lines +18 to +21
Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function name 'keypair_from_seed' is specific to draft-03. Consider renaming to 'keypair_from_seed_draft03' or documenting that it specifically generates draft-03 keypairs, especially since this module supports both draft-03 and draft-13 variants.

Copilot uses AI. Check for mistakes.

/// Produce a draft-03 VRF proof and output for the given message.
pub fn prove_draft03(sk: &VrfSigningKey, message: &[u8]) -> CryptoResult<(VrfProof, Output)> {
let proof = VrfDraft03::prove(sk, message)?;
let output = VrfDraft03::proof_to_hash(&proof)?;
Ok((proof, Output::new(output)))
}

/// Verify a draft-03 VRF proof and return the output if valid.
pub fn verify_draft03(
vk: &VrfVerificationKey,
proof: &VrfProof,
message: &[u8],
) -> CryptoResult<Output> {
let output = VrfDraft03::verify(vk, proof, message)?;
Ok(Output::new(output))
}

/// Convenience wrapper that runs draft-03 end-to-end and returns a certified output.
pub fn certify_draft03(sk: &VrfSigningKey, message: &[u8]) -> CryptoResult<CertifiedOutput> {
CertifiedVrf::eval(sk, message)
}

/// Verify a certified draft-03 output.
pub fn verify_certified(
vk: &VrfVerificationKey,
certified: &CertifiedOutput,
message: &[u8],
) -> CryptoResult<()> {
certified.verify(vk, message)
}
Comment on lines +40 to +52
Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing test coverage for convenience wrapper functions. The module includes certify_draft03 and verify_certified functions that lack test coverage. Consider adding tests for these functions to ensure they work correctly, especially since they're part of the public API.

Copilot uses AI. Check for mistakes.

/// Produce a draft-13 VRF proof and output for the given message.
pub fn prove_draft13(
sk: &VrfSigningKey,
message: &[u8],
) -> CryptoResult<([u8; cardano_crypto::vrf::draft13::PROOF_SIZE], Output)> {
let proof = VrfDraft13::prove(sk, message)?;
let output = VrfDraft13::proof_to_hash(&proof)?;
Ok((proof, Output::new(output)))
}
Comment on lines +54 to +62
Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent return types between draft-03 and draft-13 prove functions. The prove_draft03 function returns a VrfProof, while prove_draft13 returns a raw array [u8; PROOF_SIZE]. Consider making these consistent by either having both return typed wrappers (like VrfProof) or both return raw arrays for consistency in the API.

Copilot uses AI. Check for mistakes.

/// Verify a draft-13 VRF proof and return the output if valid.
pub fn verify_draft13(
vk: &VrfVerificationKey,
proof: &[u8; cardano_crypto::vrf::draft13::PROOF_SIZE],
message: &[u8],
) -> CryptoResult<Output> {
let output = VrfDraft13::verify(vk, proof, message)?;
Ok(Output::new(output))
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn draft03_roundtrip() {
let seed = [7u8; SEED_SIZE];
let (proof, output) =
prove_draft03(&keypair_from_seed(&seed).signing_key, b"msg").expect("prove");
let vk = keypair_from_seed(&seed).verification_key;
let out2 = verify_draft03(&vk, &proof, b"msg").expect("verify");
assert_eq!(output.as_bytes(), out2.as_bytes());
}

#[test]
fn draft13_roundtrip() {
let seed = [9u8; SEED_SIZE];
let kp = keypair_from_seed(&seed);
let (proof, output) = prove_draft13(&kp.signing_key, b"msg-13").expect("prove13");
let out2 = verify_draft13(&kp.verification_key, &proof, b"msg-13").expect("verify13");
assert_eq!(output.as_bytes(), out2.as_bytes());
}
}

/// Error type alias for VRF operations.
pub type Error = CryptoError;
/// Result type alias for VRF operations.
Comment on lines +98 to +100
Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type aliases lack documentation comments. The Error and Result type aliases should include doc comments explaining that they're aliases for CryptoError and CryptoResult from the cardano-crypto crate, to help users understand the error types they'll encounter when using this API.

Suggested change
/// Error type alias for VRF operations.
pub type Error = CryptoError;
/// Result type alias for VRF operations.
/// Error type alias for VRF operations.
///
/// This is an alias for [`CryptoError`] from the [`cardano-crypto`] crate,
/// representing errors that can occur during VRF operations in this API.
pub type Error = CryptoError;
/// Result type alias for VRF operations.
///
/// This is an alias for [`CryptoResult`] from the [`cardano-crypto`] crate,
/// representing the result of VRF operations in this API.

Copilot uses AI. Check for mistakes.
pub type Result<T> = CryptoResult<T>;
Comment on lines +98 to +101
Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type aliases should be declared near the top of the module, not at the end. According to Rust conventions, type aliases should appear early in the module, typically after imports and before function definitions, to improve readability and discoverability.

Copilot uses AI. Check for mistakes.
68 changes: 68 additions & 0 deletions pallas-crypto/tests/kes_golden.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#![cfg(feature = "kes")]

use pallas_crypto::kes::summed_kes::Sum6Kes;
use pallas_crypto::kes::traits::{KesSig, KesSk};

#[test]
fn sum6_total_periods_and_roundtrip() {
let mut key_bytes = [0u8; Sum6Kes::SIZE + 4];
let mut seed = [0x46u8; 32];
let (mut sk, vk) = Sum6Kes::keygen(&mut key_bytes, &mut seed);

// sign at period 0
let msg0 = b"Sum6 period 0";
let sig0 = sk.sign(msg0);
sig0.verify(sk.get_period(), &vk, msg0).expect("verify p0");

// evolve to final period and sign
for _ in 0..63 {
sk.update().expect("evolve");
}
assert_eq!(sk.get_period(), 63);

let msg_last = b"Sum6 period 63";
let sig_last = sk.sign(msg_last);
sig_last.verify(63, &vk, msg_last).expect("verify p63");

// adjacent periods should fail
assert!(sig_last.verify(62, &vk, msg_last).is_err());
}

#[test]
fn sum6_verification_key_stability() {
let mut key_bytes = [0u8; Sum6Kes::SIZE + 4];
let mut seed = [0x99u8; 32];
let (mut sk, vk0) = Sum6Kes::keygen(&mut key_bytes, &mut seed);
let vk0_bytes = vk0.as_bytes().to_vec();

for period in 0..10 {
let vk_bytes = sk.to_pk().as_bytes().to_vec();
assert_eq!(
vk0_bytes, vk_bytes,
"vkey must stay stable at period {period}"
);
if period < 9 {
sk.update().expect("evolve");
}
}
}

#[test]
fn sum6_deterministic_from_seed() {
let seed = [0xCCu8; 32];

let mut key_bytes1 = [0u8; Sum6Kes::SIZE + 4];
let mut seed1 = seed.clone();
let (sk1, vk1) = Sum6Kes::keygen(&mut key_bytes1, &mut seed1);

let mut key_bytes2 = [0u8; Sum6Kes::SIZE + 4];
let mut seed2 = seed.clone();
Comment on lines +55 to +59
Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary clone of a Copy type. Arrays implement Copy, so cloning is not needed. Simply assign the value directly.

Suggested change
let mut seed1 = seed.clone();
let (sk1, vk1) = Sum6Kes::keygen(&mut key_bytes1, &mut seed1);
let mut key_bytes2 = [0u8; Sum6Kes::SIZE + 4];
let mut seed2 = seed.clone();
let mut seed1 = seed;
let (sk1, vk1) = Sum6Kes::keygen(&mut key_bytes1, &mut seed1);
let mut key_bytes2 = [0u8; Sum6Kes::SIZE + 4];
let mut seed2 = seed;

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary clone of a Copy type. Arrays implement Copy, so cloning is not needed. Simply assign the value directly.

Suggested change
let mut seed2 = seed.clone();
let mut seed2 = seed;

Copilot uses AI. Check for mistakes.
let (sk2, vk2) = Sum6Kes::keygen(&mut key_bytes2, &mut seed2);

let m = b"deterministic";
let sig1 = sk1.sign(m);
let sig2 = sk2.sign(m);

assert_eq!(vk1.as_bytes(), vk2.as_bytes());
assert_eq!(sig1.to_bytes(), sig2.to_bytes());
}
117 changes: 117 additions & 0 deletions pallas-crypto/tests/vrf_golden.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#![cfg(feature = "vrf")]

use pallas_crypto::vrf::{keypair_from_seed, verify_draft03, VrfDraft03};

fn hex_decode(s: &str) -> Vec<u8> {
(0..s.len())
.step_by(2)
.map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap())
.collect()
}

#[test]
fn draft03_ietf_vector_10() {
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vrf-03#appendix-A.1
let sk_seed = hex_decode("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60");
let expected_pk =
hex_decode("d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a");
let expected_pi = hex_decode(concat!(
"b6b4699f87d56126c9117a7da55bd0085246f4c56dbc95d20172612e9d38e8d7",
"ca65e573a126ed88d4e30a46f80a666854d675cf3ba81de0de043c3774f06156",
"0f55edc256a787afe701677c0f602900",
));
let expected_beta = hex_decode(concat!(
"5b49b554d05c0cd5a5325376b3387de59d924fd1e13ded44648ab33c21349a60",
"3f25b84ec5ed887995b33da5e3bfcb87cd2f64521c4c62cf825cffabbe5d31cc",
));

let seed: [u8; 32] = sk_seed.try_into().unwrap();
let (sk, pk) = VrfDraft03::keypair_from_seed(&seed);

assert_eq!(pk.as_slice(), expected_pk.as_slice());

let proof = VrfDraft03::prove(&sk, &[]).expect("prove");
assert_eq!(proof.as_slice(), expected_pi.as_slice());

let beta = VrfDraft03::verify(&pk, &proof, &[]).expect("verify");
assert_eq!(beta.as_slice(), expected_beta.as_slice());

let beta2 = VrfDraft03::proof_to_hash(&proof).expect("proof_to_hash");
assert_eq!(beta, beta2);
}

#[test]
fn draft03_ietf_vector_11() {
let sk_seed = hex_decode("4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb");
let expected_pk =
hex_decode("3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c");
let alpha = hex_decode("72");
let expected_pi = hex_decode("ae5b66bdf04b4c010bfe32b2fc126ead2107b697634f6f7337b9bff8785ee111200095ece87dde4dbe87343f6df3b107d91798c8a7eb1245d3bb9c5aafb093358c13e6ae1111a55717e895fd15f99f07");
let expected_beta = hex_decode(concat!(
"94f4487e1b2fec954309ef1289ecb2e15043a2461ecc7b2ae7d4470607ef82eb",
"1cfa97d84991fe4a7bfdfd715606bc27e2967a6c557cfb5875879b671740b7d8",
));

let seed: [u8; 32] = sk_seed.try_into().unwrap();
let (sk, pk) = VrfDraft03::keypair_from_seed(&seed);

assert_eq!(pk.as_slice(), expected_pk.as_slice());

let proof = VrfDraft03::prove(&sk, &alpha).expect("prove");
assert_eq!(
proof.as_slice().len(),
pallas_crypto::vrf::DRAFT03_PROOF_SIZE
);
assert_eq!(proof.as_slice(), expected_pi.as_slice());

let beta = VrfDraft03::verify(&pk, &proof, &alpha).expect("verify");
assert_eq!(beta.as_slice().len(), pallas_crypto::vrf::OUTPUT_SIZE);
assert_eq!(beta.as_slice(), expected_beta.as_slice());
}

#[test]
fn draft03_ietf_vector_12() {
let sk_seed = hex_decode("c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7");
let expected_pk =
hex_decode("fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025");
let alpha = hex_decode("af82");
let expected_pi = hex_decode(concat!(
"dfa2cba34b611cc8c833a6ea83b8eb1bb5e2ef2dd1b0c481bc42ff36ae7847f6",
"ab52b976cfd5def172fa412defde270c8b8bdfbaae1c7ece17d9833b1bcf3106",
"4fff78ef493f820055b561ece45e1009",
));
let expected_beta = hex_decode(concat!(
"2031837f582cd17a9af9e0c7ef5a6540e3453ed894b62c293686ca3c1e319dde",
"9d0aa489a4b59a9594fc2328bc3deff3c8a0929a369a72b1180a596e016b5ded",
));

let seed: [u8; 32] = sk_seed.try_into().unwrap();
let (sk, pk) = VrfDraft03::keypair_from_seed(&seed);

assert_eq!(pk.as_slice(), expected_pk.as_slice());

let proof = VrfDraft03::prove(&sk, &alpha).expect("prove");
assert_eq!(proof.as_slice(), expected_pi.as_slice());

let beta = VrfDraft03::verify(&pk, &proof, &alpha).expect("verify");
assert_eq!(beta.as_slice(), expected_beta.as_slice());
}

#[test]
fn draft03_cardano_messages() {
let seed = [0x42u8; 32];
let kp = keypair_from_seed(&seed);
let messages: &[&[u8]] = &[
b"Block header hash",
b"Epoch nonce derivation",
b"Leader election slot 12345",
&[0u8; 64],
&[],
];

for msg in messages {
let (proof, out1) = pallas_crypto::vrf::prove_draft03(&kp.signing_key, msg).expect("prove");
let out2 = verify_draft03(&kp.verification_key, &proof, msg).expect("verify");
assert_eq!(out1.as_bytes(), out2.as_bytes());
}
}
1 change: 1 addition & 0 deletions pallas/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ unstable = ["hardano", "pallas-traverse/unstable"]
# pallas-validate feature flags
phase2 = ["pallas-validate/phase2"]
relaxed = ["pallas-primitives/relaxed", "pallas-crypto/relaxed"]
vrf = ["pallas-crypto/vrf"]