silk.crypto.p256.
Key agreement (ECDH) and ECDSA signature verification on the NIST P-256 curve (secp256r1).
When to use#
Use P256 for an ECDH key exchange where a protocol needs P-256, such as a TLS 1.3 key share
secp256r1. For a new design, silk.crypto.x25519 is simpler. Use EcdsaP256Sha256 to verify an
ECDSA signature with SHA-256, for example the signature of a certificate or a JSON Web Token
with ES256.
Details#
Public keys are 65 bytes in uncompressed SEC1 form: 0x04, then the X and Y coordinates, each
32 bytes big-endian. Secrets are 32 bytes big-endian. P256.agree returns the X coordinate of
the shared point and consumes the key. Signatures are in DER form, as in X.509 and TLS. Nothing
allocates. This module cannot sign.
Errors#
P256Errorfor a secret or a peer public key that is not valid.P256SignatureErrorfor a signature that is not valid, or that does not match.
Gotchas#
A valid signature proves only that the holder of the private key signed the message. It does not
prove that you can trust the key. To check a certificate chain, use the silk.tls.trust_* modules.
The key exchange does not authenticate the peer. Pass the shared secret through silk.crypto.hkdf
before you use it as a key. The secret is not erased when it is dropped.
Examples#
Agree on a shared secret#
import silk.crypto.p256 { P256, P256Error }
import silk.core.result { Result }
pub fn main() -> i32 {
// Real programs use `P256.generate()` with a secure `Random` provider.
let mut one: [u8; 32] = [0; 32]
one[31] = 1
let mut two: [u8; 32] = [0; 32]
two[31] = 2
let alice = match P256.fromBytes(&one) {
Result<P256, P256Error>.Success { value } => move value
Result<P256, P256Error>.Failure { error: _ } => {
return 1
}
}
let bob = match P256.fromBytes(&two) {
Result<P256, P256Error>.Success { value } => move value
Result<P256, P256Error>.Failure { error: _ } => {
return 1
}
}
let alicePublic = P256.publicKey(&alice)
let bobPublic = P256.publicKey(&bob)
// The public key of the secret 1 is the base point, with X = 6b17d1f2...
if alicePublic[0] != 0x04 || alicePublic[1] != 0x6b {
return 1
}
let fromAlice = match P256.agree(move alice, &bobPublic) {
Result<[u8; 32], P256Error>.Success { value } => value
Result<[u8; 32], P256Error>.Failure { error: _ } => {
return 1
}
}
let fromBob = match P256.agree(move bob, &alicePublic) {
Result<[u8; 32], P256Error>.Success { value } => value
Result<[u8; 32], P256Error>.Failure { error: _ } => {
return 1
}
}
if fromAlice[0] != fromBob[0] || fromAlice[31] != fromBob[31] {
return 1
}
return 0
}Verify a signature#
import silk.crypto.p256 { EcdsaP256Sha256, P256SignatureError }
import silk.core.result { Result }
pub fn main() -> i32 {
// A public key and a signature of "hello" that another program made.
let publicKey: [u8; 65] = [
0x04,
0x26,
0xef,
0xce,
0xbd,
0x0e,
0xe9,
0xe3,
0x4a,
0x66,
0x91,
0x87,
0xe1,
0x8b,
0x3a,
0x91,
0x22,
0xb2,
0xf7,
0x33,
0x94,
0x5b,
0x64,
0x9c,
0xc9,
0xf9,
0xf9,
0x21,
0xe9,
0xf9,
0xda,
0xd8,
0x12,
0x90,
0x23,
0x8b,
0xde,
0x9c,
0xc7,
0xbb,
0x33,
0x0d,
0x15,
0x0c,
0x67,
0x70,
0x4d,
0xd2,
0x5a,
0xe7,
0x05,
0x52,
0x05,
0x74,
0x4b,
0x6f,
0x31,
0xbf,
0x40,
0x70,
0x74,
0x58,
0x72,
0xd0,
0xe6
]
let signature: [u8; 72] = [
0x30,
0x46,
0x02,
0x21,
0x00,
0xc9,
0x70,
0x75,
0x86,
0x11,
0x4e,
0x93,
0x49,
0xd8,
0x2b,
0x8d,
0x3d,
0x97,
0x52,
0x86,
0x0c,
0x9f,
0xab,
0x24,
0xf2,
0x9e,
0xff,
0x83,
0x6e,
0x0a,
0x6f,
0xbf,
0xc5,
0x7a,
0x30,
0x9d,
0x1c,
0x02,
0x21,
0x00,
0x88,
0x3f,
0xb1,
0x3c,
0x3b,
0x44,
0x28,
0x70,
0x2e,
0xc4,
0x88,
0x52,
0xf8,
0x5e,
0xe5,
0x63,
0x1a,
0xec,
0x2f,
0x25,
0x23,
0xe3,
0xd7,
0x18,
0xf8,
0xae,
0x33,
0x25,
0xe0,
0x00,
0xdc,
0xa8
]
match EcdsaP256Sha256.verify(&publicKey, b"hello", &signature) {
Result<(), P256SignatureError>.Success { value: _ } => {}
Result<(), P256SignatureError>.Failure { error: _ } => {
return 1
}
}
// The same signature does not match another message.
return match EcdsaP256Sha256.verify(&publicKey, b"hellp", &signature) {
Result<(), P256SignatureError>.Failure { error: P256SignatureError.AuthenticationFailed } => 0
_ => 1
}
}Import as P256 with import silk.crypto.p256 { P256 }.
Public declarations: 4.
P256Error#
pub enum P256ErrorThe reason that a P-256 secret or public key is not valid. It holds no secret bytes.
InvalidLength#
InvalidLengthA secret is not 32 bytes, or a public key is not 65 bytes.
InvalidScalar#
InvalidScalarThe secret is 0, or not less than the order of the curve.
InvalidEncoding#
InvalidEncodingThe public key does not start with 0x04. Compressed keys are not supported.
InvalidPoint#
InvalidPointA coordinate is not less than the field prime, or the point is not on the curve.
Implementation Debug for P256Error#
impl Debug for P256ErrorOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as InvalidLength.
P256#
pub struct P256A P-256 secret for key agreement. It is not Copy.
When to use#
Use it for an ECDH key exchange where a protocol needs P-256, such as a TLS 1.3 key share
secp256r1. For a new design, silk.crypto.x25519 is simpler.
Details#
P256.agree consumes it. Make a new one for each exchange. Public keys are 65 bytes in
uncompressed SEC1 form: 0x04, then the X and Y coordinates, each 32 bytes big-endian. Secrets
are 32 bytes big-endian. Nothing allocates.
Gotchas#
The key exchange does not authenticate the peer. Pass the shared secret through silk.crypto.hkdf
before you use it as a key. The secret is not erased when it is dropped.
Implementation P256#
impl P256Associated function validatePublicKey#
pub fn validatePublicKey(publicKey: &[u8]) -> Result<(), P256Error>Checks that publicKey is a valid uncompressed P-256 public key.
It must be 65 bytes: 0x04, then X and Y, each 32 bytes big-endian and less than the field
prime, and the point must be on the curve.
Errors#
InvalidLength,InvalidEncoding, orInvalidPoint.
Associated function fromBytes#
pub fn fromBytes(bytes: &[u8]) -> Result<P256, P256Error>Returns the secret for the 32 big-endian bytes bytes.
Errors#
InvalidLengthifbytesis not 32 bytes.InvalidScalarif the value is 0, or not less than the order of the curve.
Associated function generate#
pub effect fn generate() -> P256 ? &mut RandomReturns a new random secret, with bytes from the ambient Random.
It draws 32 bytes again until the value is valid, so the result is uniform. The Random
provider must be cryptographically secure. If it fails, the program stops.
Method publicKey#
pub fn publicKey(self: &Self) -> [u8; 65]Returns the 65-byte uncompressed public key to send to the peer. It does not consume the secret.
Method agree#
pub fn agree(self: Self, peer: &[u8]) -> Result<[u8; 32], P256Error>Returns the 32-byte shared secret for the public key peer, and consumes the secret.
The result is the big-endian X coordinate of the shared point.
Errors#
InvalidLength,InvalidEncoding, orInvalidPointifpeeris not a valid uncompressed public key. The secret is consumed also when it fails.
Gotchas#
Pass the result through silk.crypto.hkdf before you use it as a key.
P256SignatureError#
pub enum P256SignatureErrorThe reason that an ECDSA P-256 verification failed.
InvalidLength#
InvalidLengthThe message is longer than SHA-256 allows (2^61 - 1 bytes).
InvalidKey#
InvalidKeyThe public key is not a valid uncompressed P-256 key.
InvalidEncoding#
InvalidEncodingThe signature is not strict DER, or r or s is not between 1 and the order of the curve.
UnsupportedAlgorithm#
UnsupportedAlgorithmA certificate names a key or signature algorithm other than ECDSA P-256 with SHA-256.
InvalidParameters#
InvalidParametersA certificate has wrong algorithm parameters, or a BIT STRING with unused bits.
AuthenticationFailed#
AuthenticationFailedThe inputs are valid, but the signature does not match the message and the key.
Implementation Debug for P256SignatureError#
impl Debug for P256SignatureErrorOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as InvalidLength.
EcdsaP256Sha256#
pub struct EcdsaP256Sha256Functions that verify ECDSA signatures on P-256 with SHA-256.
When to use#
Use it to verify an ECDSA signature with SHA-256, for example the signature of a certificate or
a JSON Web Token with ES256. It cannot sign.
Details#
Public keys are 65 bytes in uncompressed SEC1 form. Signatures are in DER form, as in X.509 and TLS. Nothing allocates.
Gotchas#
A valid signature proves only that the holder of the private key signed the message. It does not
prove that you can trust the key. To check a certificate chain, use the silk.tls.trust_* modules.
Implementation EcdsaP256Sha256#
impl EcdsaP256Sha256Associated function verify#
pub fn verify(publicKey: &[u8], message: &[u8], signature: &[u8]) -> Result<
(),
P256SignatureError,
>Checks that signature is a valid signature of message by publicKey.
publicKey is 65 bytes, uncompressed. signature is DER. The function hashes message with
SHA-256, so give the message, not its digest. Both high and low s values are accepted.
Errors#
InvalidLength,InvalidKey, orInvalidEncodingfor input that is not valid.AuthenticationFailedif the signature does not match.
Associated function verifyCertificate#
pub fn verifyCertificate<'key, 'sig>(
keyAlgorithm: &AlgorithmView<'key>,
publicKey: &BitStringView<'key>,
message: &[u8],
signatureAlgorithm: &AlgorithmView<'sig>,
signature: &BitStringView<'sig>,
) -> Result<(), P256SignatureError>Verifies a certificate signature from the parts that silk.tls.certificate reads.
message is the signed part of the certificate (the TBSCertificate DER). The key algorithm
must be id-ecPublicKey with the curve secp256r1, and the signature algorithm must be
ecdsa-with-SHA256 with no parameters.
Errors#
UnsupportedAlgorithmorInvalidParametersif the algorithms do not match.InvalidLength,InvalidKey, orInvalidEncodingif the key or the signature is not valid.AuthenticationFailedif the signature does not match.
Gotchas#
It checks only this one signature. It does not check the chain, the dates, or the names.
Category: Cryptography.
Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2.