use libsodium_sys::{crypto_generichash_state as HashState, crypto_generichash_update};
// 2^252 + 27742317777372353535851937790883648493
const L: [u8; 32] = [
0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10
];
/// Ensures signature is canonical
pub(crate) fn sc25519_is_canonical(s: &[u8]) -> bool
{
let (mut c, mut n) = (0u8, 1u8);
for i in (0..32).rev() {
c |= ((s[i].wrapping_sub(L[i])).wrapping_shl(8)) & n;
n &= ((s[i] ^ L[i]).wrapping_sub(1)).wrapping_shl(8);
}
c != 0
}
pub(crate) unsafe fn lp_update(h: &mut HashState, x: &[u8])
{
let x_len = x.len() as u64;
let x_len_u8 = x_len as u8;
crypto_generichash_update(h, &x_len_u8, 1);
crypto_generichash_update(h, x.as_ptr(), x_len);
}
// Interop unit testing
#[test]
fn lp_update_correctness() {
let mut input_state = HashState {
opaque: [40, 201, 189, 242, 103, 230, 9, 106, 59, 167, 202, 132, 133, 174, 103, 187, 43, 248, 148, 254, 114, 243, 110, 60, 241, 54, 29, 95, 58, 245, 79, 165, 209, 130, 230, 173, 127, 82, 14, 81, 31, 108, 62, 43, 140, 104, 5, 155, 107, 189, 65, 251, 171, 217, 131, 31, 121, 33, 126, 19, 25, 205, 224, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115, 104, 97, 114, 101, 100, 95, 107, 101, 121, 226, 238, 49, 56, 117, 65, 38, 198, 116, 149, 165, 251, 175, 169, 172, 43, 142, 139, 189, 89, 95, 77, 226, 189, 59, 29, 209, 10, 205, 192, 222, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 155, 252, 247, 255, 127, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 94, 65, 213, 247, 255, 127, 0, 0,]
};
let expected_state = HashState {
opaque: [40, 201, 189, 242, 103, 230, 9, 106, 59, 167, 202, 132, 133, 174, 103, 187, 43, 248, 148, 254, 114, 243, 110, 60, 241, 54, 29, 95, 58, 245, 79, 165, 209, 130, 230, 173, 127, 82, 14, 81, 31, 108, 62, 43, 140, 104, 5, 155, 107, 189, 65, 251, 171, 217, 131, 31, 121, 33, 126, 19, 25, 205, 224, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115, 104, 97, 114, 101, 100, 95, 107, 101, 121, 226, 238, 49, 56, 117, 65, 38, 198, 116, 149, 165, 251, 175, 169, 172, 43, 142, 139, 189, 89, 95, 77, 226, 189, 59, 29, 209, 10, 205, 192, 222, 100, 6, 115, 101, 110, 100, 101, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 155, 252, 247, 255, 127, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 94, 65, 213, 247, 255, 127, 0, 0,]
};
let x = b"sender";
unsafe { lp_update(&mut input_state, &*x); }
assert_eq!(input_state.opaque, expected_state.opaque);
}
#[test]
fn canonical_bytes() {
const CANONICAL_L_MINUS_ONE: [u8; 32] = [
237, 211, 245, 92, 26, 99, 18, 88, 214, 156,
247, 162, 222, 249, 222, 20, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15,
];
assert!(sc25519_is_canonical(&CANONICAL_L_MINUS_ONE));
}
#[test]
fn non_canonical_bytes() {
const NON_CANONICAL_L: [u8; 32] = [
237, 211, 245, 92, 26, 99, 18, 88, 214, 156,
247, 162, 222, 249, 222, 20, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16,
];
assert!(!sc25519_is_canonical(&NON_CANONICAL_L));
}