Skip to content

Commit

Permalink
Merge pull request #217 from oasisprotocol/CedarMist/sha384-p384
Browse files Browse the repository at this point in the history
contracts: add SHA384 hash and P-384 curve
  • Loading branch information
CedarMist authored Oct 31, 2023
2 parents 9f6eea4 + 56b1f3e commit fcd5102
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 13 deletions.
26 changes: 23 additions & 3 deletions contracts/contracts/Sapphire.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ library Sapphire {
0x0100000000000000000000000000000000000101;
address internal constant SHA512 =
0x0100000000000000000000000000000000000102;
address internal constant SHA384 =
0x0100000000000000000000000000000000000103;

type Curve25519PublicKey is bytes32;
type Curve25519SecretKey is bytes32;
Expand All @@ -52,7 +54,9 @@ library Sapphire {
// Sr25519 signature over the provided message.
Sr25519,
// Secp256r1 signature over the provided SHA-256 digest.
Secp256r1PrehashedSha256
Secp256r1PrehashedSha256,
// Secp384r1 signature over the provided SHA-384 digest.
Secp384r1PrehashedSha384
}

/**
Expand Down Expand Up @@ -231,7 +235,7 @@ library Sapphire {
* **not** vulnerable to length-extension attacks.
*
* @custom:standard https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
* @custom:see @oasisprotocol/oasis-sdk :: precompile/sha512.rs :: call_sha512_256
* @custom:see @oasisprotocol/oasis-sdk :: precompile/sha2.rs :: call_sha512_256
* @param input Bytes to hash
* @return result 32 byte digest
*/
Expand All @@ -247,7 +251,7 @@ function sha512_256(bytes memory input) view returns (bytes32 result) {
* Hash the input data with SHA-512
*
* @custom:standard https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
* @custom:see @oasisprotocol/oasis-sdk :: precompile/sha512.rs :: call_sha512
* @custom:see @oasisprotocol/oasis-sdk :: precompile/sha2.rs :: call_sha512
* @param input Bytes to hash
* @return output 64 byte digest
*/
Expand All @@ -258,3 +262,19 @@ function sha512(bytes memory input) view returns (bytes memory output) {

require(success, "sha512");
}

/**
* Hash the input data with SHA-384
*
* @custom:standard https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
* @custom:see @oasisprotocol/oasis-sdk :: precompile/sha2.rs :: call_sha384
* @param input Bytes to hash
* @return output 48 byte digest
*/
function sha384(bytes memory input) view returns (bytes memory output) {
bool success;

(success, output) = Sapphire.SHA384.staticcall(input);

require(success, "sha384");
}
10 changes: 9 additions & 1 deletion contracts/contracts/tests/HashTests.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

pragma solidity ^0.8.0;

import {sha512, sha512_256} from "../Sapphire.sol";
import {sha512, sha512_256, sha384} from "../Sapphire.sol";

contract HashTests {
function testSHA512(bytes memory data)
Expand All @@ -13,6 +13,14 @@ contract HashTests {
return sha512(data);
}

function testSHA384(bytes memory data)
external
view
returns (bytes memory)
{
return sha384(data);
}

function testSHA512_256(bytes memory data) external view returns (bytes32) {
return sha512_256(data);
}
Expand Down
28 changes: 19 additions & 9 deletions contracts/test/hashes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ import { randomBytes, createHash } from 'crypto';
import { ethers } from 'hardhat';
import { HashTests } from '../typechain-types/contracts/tests/HashTests';
import { HashTests__factory } from '../typechain-types/factories/contracts/tests';
import { PromiseOrValue } from '../typechain-types/common';
import { BytesLike, CallOverrides } from 'ethers';

type HasherTestT = (
data: PromiseOrValue<BytesLike>,
overrides?: CallOverrides | undefined,
) => Promise<string>;

describe('Hashes', () => {
let contract: HashTests;
Expand All @@ -15,21 +22,24 @@ describe('Hashes', () => {
await contract.deployed();
});

it('SHA512/256', async () => {
async function testHashes(algname: string, method: HasherTestT) {
for (let i = 0; i < 512; i += 64) {
const data = randomBytes(i);
const hash = createHash('SHA512-256').update(data).digest('hex');
const result = await contract.testSHA512_256(data);
const hash = createHash(algname).update(data).digest('hex');
const result = await method(data);
expect(result).eq('0x' + hash);
}
}

it('SHA512-256', async () => {
testHashes('SHA512-256', contract.testSHA512_256.bind(contract));
});

it('SHA512', async () => {
for (let i = 0; i < 512; i += 64) {
const data = randomBytes(i);
const hash = createHash('SHA512').update(data).digest('hex');
const result = await contract.testSHA512(data);
expect(result).eq('0x' + hash);
}
testHashes('SHA512', contract.testSHA512.bind(contract));
});

it('SHA384', async () => {
testHashes('SHA384', contract.testSHA384.bind(contract));
});
});
16 changes: 16 additions & 0 deletions contracts/test/signing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ const VARYING_SIZED_BUFFERS = [
randomBytes(1),
randomBytes(16),
randomBytes(32),
randomBytes(48),
randomBytes(64),
];

Expand Down Expand Up @@ -213,4 +214,19 @@ describe('Signing', function () {
0,
);
});

it('Secp384r1 (Prehashed SHA384)', async () => {
// Try Secp384r1 (alg=8)
// 48 byte context, empty message
const sha384_kp = await se.testKeygen(8, randomBytes(48));
await testSignThenVerify(
se,
8,
sha384_kp,
randomBytes(48),
EMPTY_BUFFER,
48,
0,
);
});
});

0 comments on commit fcd5102

Please sign in to comment.