Skip to content

Commit

Permalink
Zvkg: add vgmul.vv & vghsh.vv
Browse files Browse the repository at this point in the history
VGHSH.VV: Add-Multiply over GHASH Galois-Field
  This instruction treats all inputs and outputs as 128-bit
  polynomials and performs operations over GF[2]. The next
  partial hash(Y[i+1]) is produced by adding the current partial
  hash(Y[i]) to the cipher text block and then multiplying this
  sum by the Hash Subkey(H).

  Since the bits in the bytes are reversed, this instruction
  internally performs a bit swap within bytes to put the bits
  in the standard ordering.

VGMUL.VV: Vector Multiply over GHASH Galois-Field
  Same as vghsh.vv, this instruction treats all inputs and
  outputs as 128-bit polynomials and performs operations
  over GF[2].
  The multiplication is a caryless multiply of two 128-bit
  polynomials modulo GHASH's irreducible polynomial.

  Since the bits in the bytes are reversed, this instruction
  internally performs a bit swap within bytes to put the bits
  in the standard ordering.

Signed-off-by: Charalampos Mitrodimas <charalampos.mitrodimas@vrull.eu>
  • Loading branch information
Charalampos Mitrodimas committed Jul 11, 2023
1 parent 5872908 commit 75a0ba0
Show file tree
Hide file tree
Showing 3 changed files with 198 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ SAIL_DEFAULT_INST += riscv_insts_vext_mask.sail
SAIL_DEFAULT_INST += riscv_insts_vext_vm.sail
SAIL_DEFAULT_INST += riscv_insts_vext_red.sail

SAIL_DEFAULT_INST += riscv_insts_zvkg.sail

SAIL_SEQ_INST = $(SAIL_DEFAULT_INST) riscv_jalr_seq.sail
SAIL_RMEM_INST = $(SAIL_DEFAULT_INST) riscv_jalr_rmem.sail riscv_insts_rmem.sail

Expand Down
195 changes: 195 additions & 0 deletions model/riscv_insts_zvkg.sail
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
/*
* Vector Cryptography Extension - Vector GCM/GMAC
* ----------------------------------------------------------------------
*/

/*
* Helper functions.
* ----------------------------------------------------------------------
*/

val zvk_check_elements : (int, int, int, int) -> bool
function zvk_check_elements(VLEN, num_elem, LMUL, SEW) = {
((unsigned(vl)%num_elem) != 0) | ((unsigned(vstart)%num_elem) != 0) | (LMUL*VLEN) < (num_elem*SEW)
}

val brev8 : forall 'm, 'm >= 0 & 'm <= 128. (bits('m)) -> bits('m)
function brev8(vec) = {
input = vec;
output : bits('m) = to_bits('m, 0);
foreach (j from 0 to ('m - 8) by 8) {
output[j+7..j] = reverse_bits_in_byte(input[j+7..j]);
};

output
}

/* VGHSH.VV */

union clause ast = RISCV_VGHSH_VV : (regidx, regidx, regidx)

mapping clause encdec = RISCV_VGHSH_VV(vs2, vs1, vd) if (haveRVV() & haveZvkg())
<-> 0b1011001 @ vs2 @ vs1 @ 0b010 @ vd @ 0b1110111 if (haveRVV() & haveZvkg())

mapping clause assembly = RISCV_VGHSH_VV(vs2, vs1, vd)
<-> "vghsh.vv" ^ spc() ^ vreg_name(vd)
^ sep() ^ vreg_name(vs2)
^ sep() ^ vreg_name(vs1)

function clause execute (RISCV_VGHSH_VV(vs2, vs1, vd)) = {
let SEW = get_sew();
let LMUL_pow = get_lmul_pow();
let LMUL = if LMUL_pow < 0 then 0 else LMUL_pow;
let VLEN = int_power(2, get_vlen_pow());
let num_elem = get_num_elem(LMUL_pow, SEW);

if (zvk_check_elements(VLEN, num_elem, LMUL, SEW) == false)
then {
handle_illegal();
RETIRE_FAIL
} else {
let 'n = num_elem;
let 'm = SEW;
assert('m == 32);

let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2);
let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1);
let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd);
result : vector('n, dec, bits('m)) = undefined;

Y : bits(128) = undefined;
X : bits(128) = undefined;
H : bits(128) = undefined;
Z : bits(128) = undefined;
S : bits(128) = undefined;

eg_len = (unsigned(vl) / 'n);
eg_start = (unsigned(vstart) / 'n);

foreach (i from eg_start to (eg_len - 1)) {
assert(0 <= ((i * 4) + 3) & ((i * 4) + 3) < 'n);

// Current partial-hash
Y[31..0] = vd_val[i*4+0];
Y[63..32] = vd_val[i*4+1];
Y[95..64] = vd_val[i*4+2];
Y[127..96] = vd_val[i*4+3];
// Block cipher output
X[31..0] = vs1_val[i*4+0];
X[63..32] = vs1_val[i*4+1];
X[95..64] = vs1_val[i*4+2];
X[127..96] = vs1_val[i*4+3];
// Hash subkey
H[31..0] = brev8(vs2_val[i*4+0]);
H[63..32] = brev8(vs2_val[i*4+1]);
H[95..64] = brev8(vs2_val[i*4+2]);
H[127..96] = brev8(vs2_val[i*4+3]);

Z = zeros();
S = brev8(Y ^ X);

foreach (b from 0 to 127 by 1) {
if bit_to_bool(S[b])
then Z = Z ^ H;

reduce : bool = bit_to_bool(H[127]);

H = H << 1;
if (reduce)
// Reduce using x^7 + x^2 + x^1 + 1 polynomial
then H = xor_vec(H, to_bits(128, unsigned(0x87)));
};

assert(0 <= 3 & 3 < 'n);
// Bit reverse bytes to get back to GCM standard ordering
let res = brev8(Z);
result[i*4+0] = res[31..0];
result[i*4+1] = res[63..32];
result[i*4+2] = res[95..64];
result[i*4+3] = res[127..96];
};

write_single_vreg(num_elem, 'm, vd, result);
RETIRE_SUCCESS
}
}

/* VGMUL.VV */

union clause ast = RISCV_VGMUL_VV : (regidx, regidx)

mapping clause encdec = RISCV_VGMUL_VV(vs2, vd) if (haveRVV() & haveZvkg())
<-> 0b1010001 @ vs2 @ 0b10001 @ 0b010 @ vd @ 0b1110111 if (haveRVV() & haveZvkg())

mapping clause assembly = RISCV_VGMUL_VV(vs2, vd)
<-> "vgmul.vv" ^ spc() ^ vreg_name(vd)
^ sep() ^ vreg_name(vs2)

function clause execute (RISCV_VGMUL_VV(vs2, vd)) = {
let SEW = get_sew();
let LMUL_pow = get_lmul_pow();
let LMUL = if LMUL_pow < 0 then 0 else LMUL_pow;
let VLEN = int_power(2, get_vlen_pow());
let num_elem = get_num_elem(LMUL_pow, SEW);

if (zvk_check_elements(VLEN, num_elem, LMUL, SEW) == false)
then {
handle_illegal();
RETIRE_FAIL
} else {
let 'n = num_elem;
let 'm = SEW;
assert('m == 32);

let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2);
let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd);
result : vector('n, dec, bits('m)) = undefined;

Y : bits(128) = undefined;
H : bits(128) = undefined;
Z : bits(128) = undefined;

eg_len = (unsigned(vl) / 'n);
eg_start = (unsigned(vstart) / 'n);

foreach (i from eg_start to (eg_len - 1)) {
assert(0 <= ((i * 4) + 3) & ((i * 4) + 3) < 'n);

// Current partial-hash
Y[31..0] = brev8(vd_val[i*4+0]);
Y[63..32] = brev8(vd_val[i*4+1]);
Y[95..64] = brev8(vd_val[i*4+2]);
Y[127..96] = brev8(vd_val[i*4+3]);
// Block cipher output
H[31..0] = brev8(vs2_val[i*4+0]);
H[63..32] = brev8(vs2_val[i*4+1]);
H[95..64] = brev8(vs2_val[i*4+2]);
H[127..96] = brev8(vs2_val[i*4+3]);

Z : bits(128) = zeros();

foreach (b from 0 to 127 by 1) {
if bit_to_bool(Y[b])
then Z = Z ^ H;

reduce : bool = bit_to_bool(H[127]);

H = H << 1;
if (reduce)
// Reduce using x^7 + x^2 + x^1 + 1 polynomial
then H = H ^ to_bits(128, unsigned(0x87));
};

assert(0 <= 3 & 3 < 'n);
let res = brev8(Z);
result[i*4+0] = res[31..0];
result[i*4+1] = res[63..32];
result[i*4+2] = res[95..64];
result[i*4+3] = res[127..96];
};

write_single_vreg(num_elem, 'm, vd, result);

RETIRE_SUCCESS
}
}
1 change: 1 addition & 0 deletions model/riscv_sys_regs.sail
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ function haveZknd() -> bool = true

function haveZmmul() -> bool = true
function haveRVV() -> bool = misa.V() == 0b1
function haveZvkg() -> bool = true
/* see below for F and D extension tests */

bitfield Mstatush : bits(32) = {
Expand Down

0 comments on commit 75a0ba0

Please sign in to comment.