Skip to content
Closed
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
11 changes: 8 additions & 3 deletions src/dashbls/go-bindings/schemes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,14 @@ CG1Element CCoreMPSkToG1(const CCoreMPL scheme, const CPrivateKey sk) {
CG2Element CCoreMPLSign(CCoreMPL scheme, const CPrivateKey sk, const void* msg, const size_t msgLen) {
bls::CoreMPL* schemePtr = (bls::CoreMPL*)scheme;
const bls::PrivateKey* skPtr = (bls::PrivateKey*)sk;
return new bls::G2Element(
schemePtr->Sign(*skPtr, bls::Bytes((uint8_t*)msg, msgLen))
);
try {
return new bls::G2Element(
schemePtr->Sign(*skPtr, bls::Bytes((uint8_t*)msg, msgLen))
);
} catch (const std::exception& ex) {
gErrMsg = ex.what();
return nullptr;
}
}

bool CCoreMPLVerify(const CCoreMPL scheme,
Expand Down
6 changes: 5 additions & 1 deletion src/dashbls/go-bindings/schemes.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,20 @@ func (s *coreMPL) SkToG1(sk *PrivateKey) *G1Element {
}

// Sign signs a message using a PrivateKey and returns the G2Element as a signature
// It returns nil if native signing fails.
// this method is a binding of bls::CoreMPL::Sign
func (s *coreMPL) Sign(sk *PrivateKey, msg []byte) *G2Element {
cMsgPtr := C.CBytes(msg)
defer C.free(cMsgPtr)
sig := G2Element{
val: C.CCoreMPLSign(s.val, sk.val, cMsgPtr, C.size_t(len(msg))),
}
runtime.SetFinalizer(&sig, func(sig *G2Element) { sig.free() })
runtime.KeepAlive(s)
runtime.KeepAlive(sk)
if sig.val == nil {
return nil
}
runtime.SetFinalizer(&sig, func(sig *G2Element) { sig.free() })
return &sig
}

Expand Down
1 change: 1 addition & 0 deletions src/dashbls/go-bindings/schemes.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ typedef CCoreMPL CPopSchemeMPL;
// CoreMPL
CPrivateKey CCoreMPLKeyGen(const CCoreMPL scheme, const void* seed, const size_t seedLen, bool* didErr);
CG1Element CCoreMPSkToG1(const CCoreMPL scheme, const CPrivateKey sk);
// Returns nullptr on signing failure; GetLastErrorMsg provides the error.
CG2Element CCoreMPLSign(const CCoreMPL scheme, const CPrivateKey sk, const void* msg, const size_t msgLen);
bool CCoreMPLVerify(const CBasicSchemeMPL scheme,
const CG1Element pk,
Expand Down
1 change: 1 addition & 0 deletions src/dashbls/include/dashbls/elements.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ class G2Element {
static G2Element FromBytesUnchecked(Bytes bytes, bool fLegacy = false);
static G2Element FromByteVector(const std::vector<uint8_t> &bytevec, bool fLegacy = false);
static G2Element FromNative(const g2_t element);
// Legacy mapping requires at least 32 message bytes and uses only the first 32.
static G2Element FromMessage(const std::vector<uint8_t>& message,
const uint8_t* dst,
int dst_len,
Expand Down
1 change: 1 addition & 0 deletions src/dashbls/include/dashbls/privatekey.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ class PrivateKey {
std::vector<uint8_t> Serialize(bool fLegacy = false) const;
std::array<uint8_t, PrivateKey::PRIVATE_KEY_SIZE> SerializeToArray(bool fLegacy = false) const;

// Legacy mapping requires at least 32 message bytes and uses only the first 32.
G2Element SignG2(
const uint8_t *msg,
size_t len,
Expand Down
2 changes: 2 additions & 0 deletions src/dashbls/include/dashbls/schemes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ class PopSchemeMPL final : public CoreMPL {
/**
* This scheme reflects the Sign/Verify behaviour of older bls-signatures library versions (<0.1.29).
*/
// Legacy signing and verification require at least 32 bytes and use only the first 32.
// Signing rejects shorter messages with an exception; verification returns false.
class LegacySchemeMPL final : public CoreMPL {

public:
Expand Down
18 changes: 14 additions & 4 deletions src/dashbls/rust-bindings/bls-dash-sys/c-bindings/schemes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,13 @@ G2Element CoreMPLSign(
{
bls::CoreMPL* schemePtr = (bls::CoreMPL*)scheme;
const bls::PrivateKey* skPtr = (bls::PrivateKey*)sk;
return new bls::G2Element(
schemePtr->Sign(*skPtr, bls::Bytes((uint8_t*)msg, msgLen)));
try {
return new bls::G2Element(
schemePtr->Sign(*skPtr, bls::Bytes((uint8_t*)msg, msgLen)));
} catch (const std::exception& ex) {
gErrMsg = ex.what();
return nullptr;
}
}

bool CoreMPLVerify(
Expand Down Expand Up @@ -324,8 +329,13 @@ G2Element LegacySchemeMPLSign(
{
bls::LegacySchemeMPL* schemePtr = (bls::LegacySchemeMPL*)scheme;
const bls::PrivateKey* skPtr = (bls::PrivateKey*)sk;
return new bls::G2Element(
schemePtr->Sign(*skPtr, bls::Bytes((uint8_t*)msg, msgLen)));
try {
return new bls::G2Element(
schemePtr->Sign(*skPtr, bls::Bytes((uint8_t*)msg, msgLen)));
} catch (const std::exception& ex) {
gErrMsg = ex.what();
return nullptr;
}
}

bool LegacySchemeMPLVerify(
Expand Down
3 changes: 3 additions & 0 deletions src/dashbls/rust-bindings/bls-dash-sys/c-bindings/schemes.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ PrivateKey CoreMPLKeyGen(
const size_t seedLen,
bool* didErr);
G1Element CoreMPLSkToG1(const CoreMPL scheme, const PrivateKey sk);
// Returns nullptr on signing failure; GetLastErrorMsg provides the error.
G2Element CoreMPLSign(
const CoreMPL scheme,
const PrivateKey sk,
Expand Down Expand Up @@ -144,6 +145,8 @@ void PopSchemeMPLFree(PopSchemeMPL scheme);

// LegacySchemeMPL
LegacySchemeMPL NewLegacySchemeMPL();
// Requires at least 32 message bytes and uses only the first 32.
// Returns nullptr on failure; GetLastErrorMsg provides the error.
G2Element LegacySchemeMPLSign(
const LegacySchemeMPL scheme,
const PrivateKey sk,
Expand Down
156 changes: 129 additions & 27 deletions src/dashbls/rust-bindings/bls-signatures/src/schemes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use bls_dash_sys::{
};

// TODO Split into modules
use crate::{private_key::PrivateKey, G1Element, G2Element};
use crate::{private_key::PrivateKey, utils::c_err_to_result, BlsError, G1Element, G2Element};

pub trait Scheme {
fn as_mut_ptr(&self) -> *mut c_void;
Expand Down Expand Up @@ -130,16 +130,20 @@ impl Scheme for BasicSchemeMPL {
}

fn sign(&self, private_key: &PrivateKey, message: &[u8]) -> G2Element {
G2Element {
c_element: unsafe {
let c_element = c_err_to_result(|did_error| {
let result = unsafe {
CoreMPLSign(
self.scheme,
private_key.as_mut_ptr(),
message.as_ptr() as *const _,
message.len(),
)
},
}
};
*did_error = result.is_null();
result
})
.expect("Signing failed");
G2Element { c_element }
}

fn verify(&self, public_key: &G1Element, message: &[u8], signature: &G2Element) -> bool {
Expand Down Expand Up @@ -190,24 +194,43 @@ impl LegacySchemeMPL {
scheme: unsafe { NewLegacySchemeMPL() },
}
}

/// Signs the first 32 bytes of a legacy message, rejecting shorter messages.
pub fn try_sign(
&self,
private_key: &PrivateKey,
message: &[u8],
) -> Result<G2Element, BlsError> {
if message.len() < 32 {
return Err(BlsError {
msg: "Legacy message must contain at least 32 bytes".to_owned(),
});
}
let c_element = c_err_to_result(|did_error| {
let result = unsafe {
LegacySchemeMPLSign(
self.scheme,
private_key.as_mut_ptr(),
message.as_ptr() as *const _,
message.len(),
)
};
*did_error = result.is_null();
result
})?;
Ok(G2Element { c_element })
}
}

impl Scheme for LegacySchemeMPL {
fn as_mut_ptr(&self) -> *mut c_void {
self.scheme
}

/// Panics if legacy signing fails. Use `try_sign` for a recoverable error.
fn sign(&self, private_key: &PrivateKey, message: &[u8]) -> G2Element {
G2Element {
c_element: unsafe {
LegacySchemeMPLSign(
self.scheme,
private_key.as_mut_ptr(),
message.as_ptr() as *const _,
message.len(),
)
},
}
self.try_sign(private_key, message)
.expect("Legacy signing failed")
}

fn verify(&self, public_key: &G1Element, message: &[u8], signature: &G2Element) -> bool {
Expand Down Expand Up @@ -355,7 +378,7 @@ impl Drop for AugSchemeMPL {
mod tests {
use super::*;

fn verify_aggregate(scheme: impl Scheme) {
fn verify_aggregate(scheme: impl Scheme, message_repetitions: usize) {
let seed1 = b"seedweedseedweedseedweedseedweed";
let seed2 = b"weedseedweedseedweedseedweedseed";
let seed3 = b"seedseedseedseedweedweedweedweed";
Expand Down Expand Up @@ -383,15 +406,15 @@ mod tests {
.g1_element()
.expect("unable to get public key");

let message_1 = b"ayya";
let message_2 = b"ayyb";
let message_3 = b"ayyc";
let message_4 = b"ayyd";
let message_1 = b"ayya".repeat(message_repetitions);
let message_2 = b"ayyb".repeat(message_repetitions);
let message_3 = b"ayyc".repeat(message_repetitions);
let message_4 = b"ayyd".repeat(message_repetitions);

let signature_1 = scheme.sign(&private_key_1, message_1);
let signature_2 = scheme.sign(&private_key_2, message_2);
let signature_3 = scheme.sign(&private_key_3, message_3);
let signature_4 = scheme.sign(&private_key_4, message_4);
let signature_1 = scheme.sign(&private_key_1, &message_1);
let signature_2 = scheme.sign(&private_key_2, &message_2);
let signature_3 = scheme.sign(&private_key_3, &message_3);
let signature_4 = scheme.sign(&private_key_4, &message_4);

let signature_agg = scheme.aggregate_sigs([&signature_1, &signature_2, &signature_3]);

Expand Down Expand Up @@ -419,16 +442,95 @@ mod tests {

#[test]
fn verify_aggregate_aug() {
verify_aggregate(AugSchemeMPL::new());
verify_aggregate(AugSchemeMPL::new(), 1);
}

#[test]
fn verify_aggregate_basic() {
verify_aggregate(BasicSchemeMPL::new());
verify_aggregate(BasicSchemeMPL::new(), 1);
}

#[test]
fn verify_aggregate_legacy() {
verify_aggregate(LegacySchemeMPL::new());
verify_aggregate(LegacySchemeMPL::new(), 8);
}

#[test]
fn legacy_message_lengths() {
let scheme = LegacySchemeMPL::new();
let key1 = PrivateKey::key_gen(&scheme, &[1; 32]).unwrap();
let key2 = PrivateKey::key_gen(&scheme, &[2; 32]).unwrap();
let public1 = key1.g1_element().unwrap();
let public2 = key2.g1_element().unwrap();
let message1 = [0xAB; 64];
let message2 = [0xCD; 64];
let signature1 = scheme.try_sign(&key1, &message1[..32]).unwrap();
let signature2 = scheme.try_sign(&key2, &message2[..32]).unwrap();
let aggregate = scheme.aggregate_sigs([&signature1, &signature2]);

for length in 0..32 {
let short = &message1[..length];
assert!(scheme.try_sign(&key1, short).is_err());
assert!(std::panic::catch_unwind(|| scheme.sign(&key1, short)).is_err());
assert!(!scheme.verify(&public1, short, &signature1));
assert!(!scheme.aggregate_verify(
[&public1, &public2],
[short, &message2[..32]],
&aggregate
));
assert!(!scheme.aggregate_verify(
[&public1, &public2],
[&message1[..32], &message2[..length]],
&aggregate
));

// Both exported C signing paths must contain the native length exception.
for result in unsafe {
[
LegacySchemeMPLSign(
scheme.as_mut_ptr(),
key1.as_mut_ptr(),
message1.as_ptr() as *const _,
length,
),
CoreMPLSign(
scheme.as_mut_ptr(),
key1.as_mut_ptr(),
message1.as_ptr() as *const _,
length,
),
]
} {
if !result.is_null() {
unsafe { bls_dash_sys::G2ElementFree(result) };
}
assert!(result.is_null());
}
}

for length in [32, 33, 64] {
let message = &message1[..length];
assert_eq!(scheme.try_sign(&key1, message).unwrap(), signature1);
assert_eq!(scheme.sign(&key1, message), signature1);
assert!(scheme.verify(&public1, message, &signature1));
assert!(scheme.aggregate_verify(
[&public1, &public2],
[message, &message2[..length]],
&aggregate
));
let result = unsafe {
CoreMPLSign(
scheme.as_mut_ptr(),
key1.as_mut_ptr(),
message1.as_ptr() as *const _,
length,
)
};
assert!(!result.is_null());
unsafe {
assert!(bls_dash_sys::G2ElementIsEqual(result, signature1.c_element));
bls_dash_sys::G2ElementFree(result);
}
}
}
}
3 changes: 3 additions & 0 deletions src/dashbls/src/elements.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,9 @@ G2Element G2Element::FromMessage(Bytes const message,
int dst_len,
const bool fLegacy)
{
if (fLegacy && message.size() < BLS::MESSAGE_HASH_LEN) {
throw std::invalid_argument("Legacy message must contain at least 32 bytes");
}
G2Element ans;
if (fLegacy) {
ep2_map_legacy(ans.q, message.begin(), BLS::MESSAGE_HASH_LEN);
Expand Down
3 changes: 3 additions & 0 deletions src/dashbls/src/privatekey.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,9 @@ G2Element PrivateKey::SignG2(
const bool fLegacy) const
{
CheckKeyData();
if (fLegacy && len < BLS::MESSAGE_HASH_LEN) {
throw std::invalid_argument("Legacy message must contain at least 32 bytes");
}

g2_t pt;
g2_null(pt);
Expand Down
6 changes: 6 additions & 0 deletions src/dashbls/src/schemes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,7 @@ G2Element LegacySchemeMPL::Sign(const PrivateKey& seckey, const Bytes& message)

bool LegacySchemeMPL::Verify(const G1Element &pubkey, const Bytes& message, const G2Element &signature)
{
if (message.size() < BLS::MESSAGE_HASH_LEN) return false;
g1_t g1s[2];
g2_t g2s[2];

Expand All @@ -677,6 +678,7 @@ G2Element LegacySchemeMPL::AggregateSecure(std::vector<G1Element> const &vecPubl
bool LegacySchemeMPL::VerifySecure(const std::vector<G1Element>& vecPublicKeys,
const G2Element& signature,
const Bytes& message) {
if (message.size() < BLS::MESSAGE_HASH_LEN) return false;
return CoreMPL::VerifySecure(vecPublicKeys, signature, message, true);
}

Expand All @@ -688,6 +690,10 @@ bool LegacySchemeMPL::AggregateVerify(const vector<G1Element> &pubkeys,
const auto arg_check = VerifyAggregateSignatureArguments(nPubKeys, messages.size(), signature);
if (arg_check != CONTINUE) return arg_check;

for (const auto& message : messages) {
if (message.size() < BLS::MESSAGE_HASH_LEN) return false;
}

std::vector<g1_st> vecG1(nPubKeys + 1);
std::vector<g2_st> vecG2(nPubKeys + 1);
G1Element::Generator().Negate().ToNative(&vecG1[0]);
Expand Down
Loading
Loading