Skip to content

Commit

Permalink
Add support for CTX in signature schemes
Browse files Browse the repository at this point in the history
  • Loading branch information
thomwiggers committed Oct 24, 2024
1 parent e9d654e commit 5770dde
Show file tree
Hide file tree
Showing 8 changed files with 481 additions and 25 deletions.
5 changes: 5 additions & 0 deletions generate-implementations.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ def generate_scheme(name, type, properties):
name=name,
type=type,
insecure=properties.get('insecure', False),
supports_context=properties.get('supports_context', False),
version=properties['version'],
implementations=properties['implementations'],
)
Expand All @@ -95,6 +96,7 @@ def generate_scheme(name, type, properties):
render_template(
target_dir, 'src/ffi.rs', 'scheme/src/ffi.rs.j2',
insecure=properties.get('insecure', False),
supports_context=properties.get('supports_context', False),
type=type,
name=name,
metadatas=metadatas,
Expand All @@ -107,6 +109,7 @@ def generate_scheme(name, type, properties):
"scheme/src/scheme.rs.j2",
type=type,
name=name,
supports_context=properties.get('supports_context', False),
insecure=properties.get('insecure', False),
scheme=scheme,
)
Expand All @@ -116,6 +119,7 @@ def generate_scheme(name, type, properties):
name=name,
type=type,
insecure=properties.get('insecure', False),
supports_context=properties.get('supports_context', False),
notes=properties.get('notes', None),
schemes=properties['schemes'],
)
Expand All @@ -125,6 +129,7 @@ def generate_scheme(name, type, properties):
name=name,
type=type,
insecure=properties.get('insecure', False),
supports_context=properties.get('supports_context', False),
notes=properties.get('notes', None),
schemes=properties['schemes'],
)
Expand Down
2 changes: 1 addition & 1 deletion pqcrypto-template/pqcrypto/examples/keygen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::fs::File;
use std::io::prelude::*;

use pqcrypto::prelude::*;
use pqcrypto::sign::dilithium2::*;
use pqcrypto::sign::mldsa44::*;


fn main() -> std::io::Result<()> {
Expand Down
2 changes: 1 addition & 1 deletion pqcrypto-template/pqcrypto/examples/signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::fs::{self, File};
use std::io::prelude::*;

use pqcrypto::prelude::*;
use pqcrypto::sign::dilithium2::*;
use pqcrypto::sign::mldsa44::*;

fn parseargs() -> (String, String, String) {
let args: Vec<String> = std::env::args().collect();
Expand Down
2 changes: 1 addition & 1 deletion pqcrypto-template/pqcrypto/examples/verifier.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::fs;

use pqcrypto::prelude::*;
use pqcrypto::sign::dilithium2::*;
use pqcrypto::sign::mldsa44::*;

fn parseargs() -> (String, String, String) {
let args: Vec<String> = std::env::args().collect();
Expand Down
5 changes: 4 additions & 1 deletion pqcrypto-template/scheme/Cargo.toml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@ keywords = ["cryptography", "post-quantum", "security"]
categories = ["cryptography", "no-std"]

[dependencies]
pqcrypto-internals = { path = "../pqcrypto-internals", version = "0.2" }
pqcrypto-internals = { path = "../pqcrypto-internals", version = "0.2.6" }
pqcrypto-traits = { path = "../pqcrypto-traits", version = "{{ traits_version }}", default-features = false }
libc = "0.2.0"
serde = { version = "1.0", features = ["derive"], optional = true }
serde-big-array = { version = "0.5.1", optional = true }
{% if supports_context %}
paste = "*"
{% endif %}

[features]
default = [{% if 'avx2' in implementations or 'avx' in implementations %}"avx2", {% endif %}{% if 'aesni' in implementations %}"aes", {% endif %}{% if 'aarch64' in implementations %}"neon", {% endif %}"std"]
Expand Down
156 changes: 135 additions & 21 deletions pqcrypto-template/scheme/src/ffi.rs.j2
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,19 @@ extern "C" {
#[deprecated(note = "Insecure cryptography, do not use in production")]
{% endif %}
pub fn PQCLEAN_{{ NS_NAME }}_crypto_sign(sm: *mut u8, smlen: *mut usize, msg: *const u8, len: usize, sk: *const u8) -> c_int;
{% if supports_context %}
{% if implementation == 'avx2' or implementation == 'avx' %}
#[cfg(enable_x86_avx2)]
{% elif implementation == 'aesni' %}
#[cfg(enable_x86_aes)]
{% elif implementation == 'aarch64' %}
#[cfg(enable_aarch64_neon)]
{% endif %}
{% if insecure %}
#[deprecated(note = "Insecure cryptography, do not use in production")]
{% endif %}
pub fn PQCLEAN_{{ NS_NAME }}_crypto_sign_ctx(sm: *mut u8, smlen: *mut usize, msg: *const u8, len: usize, ctx: *const u8, ctxlen: usize, sk: *const u8) -> c_int;
{% endif %}
{% if implementation == 'avx2' or implementation == 'avx' %}
#[cfg(enable_x86_avx2)]
{% elif implementation == 'aesni' %}
Expand All @@ -165,6 +178,19 @@ extern "C" {
#[deprecated(note = "Insecure cryptography, do not use in production")]
{% endif %}
pub fn PQCLEAN_{{ NS_NAME }}_crypto_sign_open(m: *mut u8, mlen: *mut usize, sm: *const u8, smlen: usize, pk: *const u8) -> c_int;
{% if supports_context %}
{% if implementation == 'avx2' or implementation == 'avx' %}
#[cfg(enable_x86_avx2)]
{% elif implementation == 'aesni' %}
#[cfg(enable_x86_aes)]
{% elif implementation == 'aarch64' %}
#[cfg(enable_aarch64_neon)]
{% endif %}
{% if insecure %}
#[deprecated(note = "Insecure cryptography, do not use in production")]
{% endif %}
pub fn PQCLEAN_{{ NS_NAME }}_crypto_sign_open_ctx(m: *mut u8, mlen: *mut usize, sm: *const u8, smlen: usize, ctx: *const u8, ctxlen: usize, pk: *const u8) -> c_int;
{% endif %}
{% if implementation == 'avx2' or implementation == 'avx' %}
#[cfg(enable_x86_avx2)]
{% elif implementation == 'aesni' %}
Expand All @@ -176,6 +202,19 @@ extern "C" {
#[deprecated(note = "Insecure cryptography, do not use in production")]
{% endif %}
pub fn PQCLEAN_{{ NS_NAME }}_crypto_sign_signature(sig: *mut u8, siglen: *mut usize, m: *const u8, mlen: usize, sk: *const u8) -> c_int;
{% if supports_context %}
{% if implementation == 'avx2' or implementation == 'avx' %}
#[cfg(enable_x86_avx2)]
{% elif implementation == 'aesni' %}
#[cfg(enable_x86_aes)]
{% elif implementation == 'aarch64' %}
#[cfg(enable_aarch64_neon)]
{% endif %}
{% if insecure %}
#[deprecated(note = "Insecure cryptography, do not use in production")]
{% endif %}
pub fn PQCLEAN_{{ NS_NAME }}_crypto_sign_signature_ctx(sig: *mut u8, siglen: *mut usize, m: *const u8, mlen: usize, ctx: *const u8, ctxlen: usize, sk: *const u8) -> c_int;
{% endif %}
{% if implementation == 'avx2' or implementation == 'avx' %}
#[cfg(enable_x86_avx2)]
{% elif implementation == 'aesni' %}
Expand All @@ -187,6 +226,20 @@ extern "C" {
#[deprecated(note = "Insecure cryptography, do not use in production")]
{% endif %}
pub fn PQCLEAN_{{ NS_NAME }}_crypto_sign_verify(sig: *const u8, siglen: usize, m: *const u8, mlen: usize, pk: *const u8) -> c_int;
{% if supports_context %}
{% if implementation == 'avx2' or implementation == 'avx' %}
#[cfg(enable_x86_avx2)]
{% elif implementation == 'aesni' %}
#[cfg(enable_x86_aes)]
{% elif implementation == 'aarch64' %}
#[cfg(enable_aarch64_neon)]
{% endif %}
{% if insecure %}
#[deprecated(note = "Insecure cryptography, do not use in production")]
{% endif %}
pub fn PQCLEAN_{{ NS_NAME }}_crypto_sign_verify_ctx(sig: *const u8, siglen: usize, m: *const u8, mlen: usize, ctx: *const u8, ctxlen: usize, pk: *const u8) -> c_int;
{% endif %}

{% endif %}
}
{% endfor %} {# implementations #}
Expand Down Expand Up @@ -295,73 +348,134 @@ mod test_{{ scheme.name|nameize }}_{{ implementation|nameize }} {
let mut detached_sig = vec![0u8; PQCLEAN_{{ NS_NAME }}_CRYPTO_BYTES];
let mut sm = Vec::with_capacity(mlen + PQCLEAN_{{ NS_NAME }}_CRYPTO_BYTES);
let mut smlen = 0;

assert_eq!(
0,
PQCLEAN_{{ NS_NAME }}_crypto_sign_keypair(pk.as_mut_ptr(), sk.as_mut_ptr())
);
{% if supports_context %}
{% set ctx = "_ctx" %}
{% set ctxptrs = "core::ptr::null(), 0,"%}
{% else %}
{% set ctx = "" %}
{% set ctxptrs = "" %}
{% endif%}
assert_eq!(
0,
PQCLEAN_{{ NS_NAME }}_crypto_sign(
PQCLEAN_{{ NS_NAME }}_crypto_sign{{ctx}}(
sm.as_mut_ptr(), &mut smlen as *mut usize,
msg.as_ptr(), mlen, sk.as_ptr())
msg.as_ptr(), msg.len(), {{ ctxptrs }}
sk.as_ptr()),
"sign"
);
sm.set_len(smlen);

let mut unpacked_m = Vec::with_capacity(mlen + PQCLEAN_{{ NS_NAME }}_CRYPTO_BYTES);
assert_eq!(
0,
PQCLEAN_{{ NS_NAME }}_crypto_sign_open(
PQCLEAN_{{ NS_NAME }}_crypto_sign_open{{ctx}}(
unpacked_m.as_mut_ptr(), &mut mlen as *mut usize,
sm.as_ptr(), sm.len(),
pk.as_ptr()
)
sm.as_ptr(), sm.len(), {{ctxptrs}}
pk.as_ptr(),
),
"sign_open"
);
unpacked_m.set_len(mlen);
assert_eq!(unpacked_m, msg);

// check verification fails with wrong pk
assert_eq!(
0,
PQCLEAN_{{ NS_NAME }}_crypto_sign_keypair(pk_alt.as_mut_ptr(), sk_alt.as_mut_ptr())
PQCLEAN_{{ NS_NAME }}_crypto_sign_keypair(pk_alt.as_mut_ptr(), sk_alt.as_mut_ptr()),
"keypair"
);
assert_eq!(
-1,
PQCLEAN_{{ NS_NAME }}_crypto_sign_open(
PQCLEAN_{{ NS_NAME }}_crypto_sign_open{{ctx}}(
unpacked_m.as_mut_ptr(), &mut mlen as *mut usize,
sm.as_ptr(), sm.len(),
{{ctxptrs}}
pk_alt.as_ptr()
)
),
"sign_open"
);
assert_eq!(
0,
PQCLEAN_{{ NS_NAME }}_crypto_sign_signature(
PQCLEAN_{{ NS_NAME }}_crypto_sign_signature{{ctx}}(
detached_sig.as_mut_ptr(), &mut smlen as *mut usize,
msg.as_ptr(), msg.len(),
sk.as_ptr())
msg.as_ptr(), msg.len(), {{ctxptrs}}
sk.as_ptr()),
"sign_signature"
);
assert!(smlen <= PQCLEAN_{{ NS_NAME }}_CRYPTO_BYTES,
"Signed message length should be ≤ CRYPTO_BYTES");
assert_eq!(
0,
PQCLEAN_{{ NS_NAME }}_crypto_sign_verify(
PQCLEAN_{{ NS_NAME }}_crypto_sign_verify{{ctx}}(
detached_sig.as_ptr(), smlen,
msg.as_ptr(), msg.len(),
pk.as_ptr())
msg.as_ptr(), msg.len(), {{ctxptrs}}
pk.as_ptr()),
"sign_verify"
);
assert_eq!(
-1,
PQCLEAN_{{ NS_NAME }}_crypto_sign_verify(
PQCLEAN_{{ NS_NAME }}_crypto_sign_verify{{ctx}}(
detached_sig.as_ptr(), smlen,
msg.as_ptr(), msg.len(),
pk_alt.as_ptr())
msg.as_ptr(), msg.len(), {{ctxptrs}}
pk_alt.as_ptr()),
"sign_verify alt pk"
);
assert_eq!(
-1,
PQCLEAN_{{ NS_NAME }}_crypto_sign_verify(
PQCLEAN_{{ NS_NAME }}_crypto_sign_verify{{ctx}}(
detached_sig.as_ptr(), smlen,
msg.as_ptr(), msg.len()-1,
pk.as_ptr())
msg.as_ptr(), msg.len()-1, {{ctxptrs}}
pk.as_ptr()),
"sign_verify wrong length"
);

{% if supports_context %}
let ctx = vec![1u8; 10];
assert_eq!(
0,
PQCLEAN_{{ NS_NAME }}_crypto_sign_ctx(
sm.as_mut_ptr(), &mut smlen as *mut usize,
msg.as_ptr(), msg.len(),
ctx.as_ptr(), ctx.len(),
sk.as_ptr()),
"Sign ctx call"
);
sm.set_len(smlen);
assert!(smlen >= PQCLEAN_{{ NS_NAME }}_CRYPTO_BYTES, "too small sig");
assert!(smlen <= PQCLEAN_{{ NS_NAME }}_CRYPTO_BYTES + msg.len(), "too big sig");

let mut mlen: usize = 0;
unpacked_m.clear();
assert_eq!(
0,
PQCLEAN_{{ NS_NAME }}_crypto_sign_open_ctx(
unpacked_m.as_mut_ptr(), &mut mlen as *mut usize,
sm.as_ptr(), sm.len(),
ctx.as_ptr(), ctx.len(),
pk.as_ptr()
),
"sign_open_ctx"
);
unpacked_m.set_len(mlen);
assert!(unpacked_m == msg, "unequal messages");

let ctx_alt = vec![0u8; 10];
assert_eq!(
-1,
PQCLEAN_{{ NS_NAME }}_crypto_sign_open_ctx(
unpacked_m.as_mut_ptr(), &mut mlen as *mut usize,
sm.as_ptr(), sm.len(),
ctx_alt.as_ptr(), ctx_alt.len(),
pk.as_ptr()
),
"sign_open_ctx with alt context"
);
{% endif %}
}
}
{% endif %} {# SIGN #}
Expand Down
6 changes: 6 additions & 0 deletions pqcrypto-template/scheme/src/lib.rs.j2
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ pub use crate::{{ scheme_name }}::{
open as {{ scheme_name }}_open,
detached_sign as {{ scheme_name }}_detached_sign,
verify_detached_signature as {{ scheme_name }}_verify_detached_signature,
{% if supports_context %}
sign_ctx as {{ scheme_name }}_sign_ctx,
open_ctx as {{ scheme_name }}_open_ctx,
detached_sign_ctx as {{ scheme_name }}_detached_sign_ctx,
verify_detached_signature_ctx as {{ scheme_name }}_verify_detached_signature_ctx,
{% endif %}
{% endif %}
};
{% endfor %}
Loading

0 comments on commit 5770dde

Please sign in to comment.