Update and clarify documentation comments (#5206)
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com> Co-authored-by: Ernesto García <ernestognw@gmail.com> Signed-off-by: Hadrien Croubois <hadrien.croubois@gmail.com>
This commit is contained in:
@ -142,7 +142,7 @@ library P256 {
|
||||
|
||||
/**
|
||||
* @dev Checks if (x, y) are valid coordinates of a point on the curve.
|
||||
* In particular this function checks that x <= P and y <= P.
|
||||
* In particular this function checks that x < P and y < P.
|
||||
*/
|
||||
function isValidPublicKey(bytes32 x, bytes32 y) internal pure returns (bool result) {
|
||||
assembly ("memory-safe") {
|
||||
@ -239,7 +239,7 @@ library P256 {
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Compute P·u1 + Q·u2 using the precomputed points for P and Q (see {_preComputeJacobianPoints}).
|
||||
* @dev Compute G·u1 + P·u2 using the precomputed points for G and P (see {_preComputeJacobianPoints}).
|
||||
*
|
||||
* Uses Strauss Shamir trick for EC multiplication
|
||||
* https://stackoverflow.com/questions/50993471/ec-scalar-multiplication-with-strauss-shamir-method
|
||||
@ -292,17 +292,17 @@ library P256 {
|
||||
points[0x04] = JPoint(GX, GY, 1); // 0,1 (g)
|
||||
points[0x02] = _jDoublePoint(points[0x01]); // 2,0 (2p)
|
||||
points[0x08] = _jDoublePoint(points[0x04]); // 0,2 (2g)
|
||||
points[0x03] = _jAddPoint(points[0x01], points[0x02]); // 3,0 (3p)
|
||||
points[0x03] = _jAddPoint(points[0x01], points[0x02]); // 3,0 (p+2p = 3p)
|
||||
points[0x05] = _jAddPoint(points[0x01], points[0x04]); // 1,1 (p+g)
|
||||
points[0x06] = _jAddPoint(points[0x02], points[0x04]); // 2,1 (2p+g)
|
||||
points[0x07] = _jAddPoint(points[0x03], points[0x04]); // 3,1 (3p+g)
|
||||
points[0x09] = _jAddPoint(points[0x01], points[0x08]); // 1,2 (p+2g)
|
||||
points[0x0a] = _jAddPoint(points[0x02], points[0x08]); // 2,2 (2p+2g)
|
||||
points[0x0b] = _jAddPoint(points[0x03], points[0x08]); // 3,2 (3p+2g)
|
||||
points[0x0c] = _jAddPoint(points[0x04], points[0x08]); // 0,3 (g+2g)
|
||||
points[0x0c] = _jAddPoint(points[0x04], points[0x08]); // 0,3 (g+2g = 3g)
|
||||
points[0x0d] = _jAddPoint(points[0x01], points[0x0c]); // 1,3 (p+3g)
|
||||
points[0x0e] = _jAddPoint(points[0x02], points[0x0c]); // 2,3 (2p+3g)
|
||||
points[0x0f] = _jAddPoint(points[0x03], points[0x0C]); // 3,3 (3p+3g)
|
||||
points[0x0f] = _jAddPoint(points[0x03], points[0x0c]); // 3,3 (3p+3g)
|
||||
}
|
||||
|
||||
function _jAddPoint(JPoint memory p1, JPoint memory p2) private pure returns (JPoint memory) {
|
||||
|
||||
@ -14,7 +14,7 @@ import {Math} from "../math/Math.sol";
|
||||
*/
|
||||
library RSA {
|
||||
/**
|
||||
* @dev Same as {pkcs1} but using SHA256 to calculate the digest of `data`.
|
||||
* @dev Same as {pkcs1Sha256} but using SHA256 to calculate the digest of `data`.
|
||||
*/
|
||||
function pkcs1Sha256(
|
||||
bytes memory data,
|
||||
@ -22,15 +22,16 @@ library RSA {
|
||||
bytes memory e,
|
||||
bytes memory n
|
||||
) internal view returns (bool) {
|
||||
return pkcs1(sha256(data), s, e, n);
|
||||
return pkcs1Sha256(sha256(data), s, e, n);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Verifies a PKCSv1.5 signature given a digest according to the verification
|
||||
* method described in https://datatracker.ietf.org/doc/html/rfc8017#section-8.2.2[section 8.2.2 of RFC8017].
|
||||
* method described in https://datatracker.ietf.org/doc/html/rfc8017#section-8.2.2[section 8.2.2 of RFC8017] with support
|
||||
* for explicit or implicit NULL parameters in the DigestInfo (no other optional parameters are supported).
|
||||
*
|
||||
* IMPORTANT: Although this function allows for it, using n of length 1024 bits is considered unsafe.
|
||||
* Consider using at least 2048 bits.
|
||||
* IMPORTANT: For security reason, this function requires the signature and modulus to have a length of at least 2048 bits.
|
||||
* If you use a smaller key, consider replacing it with a larger, more secure, one.
|
||||
*
|
||||
* WARNING: PKCS#1 v1.5 allows for replayability given the message may contain arbitrary optional parameters in the
|
||||
* DigestInfo. Consider using an onchain nonce or unique identifier to include in the message to prevent replay attacks.
|
||||
@ -40,12 +41,12 @@ library RSA {
|
||||
* @param e is the exponent of the public key
|
||||
* @param n is the modulus of the public key
|
||||
*/
|
||||
function pkcs1(bytes32 digest, bytes memory s, bytes memory e, bytes memory n) internal view returns (bool) {
|
||||
function pkcs1Sha256(bytes32 digest, bytes memory s, bytes memory e, bytes memory n) internal view returns (bool) {
|
||||
unchecked {
|
||||
// cache and check length
|
||||
uint256 length = n.length;
|
||||
if (
|
||||
length < 0x40 || // PKCS#1 padding is slightly less than 0x40 bytes at the bare minimum
|
||||
length < 0x100 || // Enforce 2048 bits minimum
|
||||
length != s.length // signature must have the same length as the finite field
|
||||
) {
|
||||
return false;
|
||||
@ -94,13 +95,13 @@ library RSA {
|
||||
// it should be at 32 (digest) + 2 bytes from the end. To those 34 bytes, we add the
|
||||
// OID (9 bytes) and its length (2 bytes) to get the position of the DigestInfo sequence,
|
||||
// which is expected to have a length of 0x31 when the NULL param is present or 0x2f if not.
|
||||
if (bytes1(_unsafeReadBytes32(buffer, length - 50)) == 0x31) {
|
||||
if (bytes1(_unsafeReadBytes32(buffer, length - 0x32)) == 0x31) {
|
||||
offset = 0x34;
|
||||
// 00 (1 byte) | SEQUENCE length (0x31) = 3031 (2 bytes) | SEQUENCE length (0x0d) = 300d (2 bytes) | OBJECT_IDENTIFIER length (0x09) = 0609 (2 bytes)
|
||||
// SHA256 OID = 608648016503040201 (9 bytes) | NULL = 0500 (2 bytes) (explicit) | OCTET_STRING length (0x20) = 0420 (2 bytes)
|
||||
params = 0x003031300d060960864801650304020105000420000000000000000000000000;
|
||||
mask = 0xffffffffffffffffffffffffffffffffffffffff000000000000000000000000; // (20 bytes)
|
||||
} else if (bytes1(_unsafeReadBytes32(buffer, length - 48)) == 0x2F) {
|
||||
} else if (bytes1(_unsafeReadBytes32(buffer, length - 0x30)) == 0x2F) {
|
||||
offset = 0x32;
|
||||
// 00 (1 byte) | SEQUENCE length (0x2f) = 302f (2 bytes) | SEQUENCE length (0x0b) = 300b (2 bytes) | OBJECT_IDENTIFIER length (0x09) = 0609 (2 bytes)
|
||||
// SHA256 OID = 608648016503040201 (9 bytes) | NULL = <implicit> | OCTET_STRING length (0x20) = 0420 (2 bytes)
|
||||
@ -111,7 +112,7 @@ library RSA {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Length is at least 0x40 and offset is at most 0x34, so this is safe. There is always some padding.
|
||||
// Length is at least 0x100 and offset is at most 0x34, so this is safe. There is always some padding.
|
||||
uint256 paddingEnd = length - offset;
|
||||
|
||||
// The padding has variable (arbitrary) length, so we check it byte per byte in a loop.
|
||||
@ -137,7 +138,7 @@ library RSA {
|
||||
/// @dev Reads a bytes32 from a bytes array without bounds checking.
|
||||
function _unsafeReadBytes32(bytes memory array, uint256 offset) private pure returns (bytes32 result) {
|
||||
// Memory safeness is guaranteed as long as the provided `array` is a Solidity-allocated bytes array
|
||||
// and `offset` is within bounds. This is the case for all calls to this private function from {pkcs1}.
|
||||
// and `offset` is within bounds. This is the case for all calls to this private function from {pkcs1Sha256}.
|
||||
assembly ("memory-safe") {
|
||||
result := mload(add(add(array, 0x20), offset))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user