The Rise of Contactless Payments:...
In recent years, contactless payments have surged in popularity, driven...
<?php
if (class_exists('ParagonIE_Sodium_Core_Poly1305_State', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Poly1305_State
*/
class ParagonIE_Sodium_Core_Poly1305_State extends ParagonIE_Sodium_Core_Util
{
/**
* @var array<int, int>
*/
protected $buffer = array();
/**
* @var bool
*/
protected $final = false;
/**
* @var array<int, int>
*/
public $h;
/**
* @var int
*/
protected $leftover = 0;
/**
* @var int[]
*/
public $r;
/**
* @var int[]
*/
public $pad;
/**
* ParagonIE_Sodium_Core_Poly1305_State constructor.
*
* @internal You should not use this directly from another application
*
* @param string $key
* @throws InvalidArgumentException
* @throws TypeError
*/
public function __construct($key = '')
{
if (self::strlen($key) < 32) {
throw new InvalidArgumentException(
'Poly1305 requires a 32-byte key'
);
}
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
$this->r = array(
(int) ((self::load_4(self::substr($key, 0, 4))) & 0x3ffffff),
(int) ((self::load_4(self::substr($key, 3, 4)) >> 2) & 0x3ffff03),
(int) ((self::load_4(self::substr($key, 6, 4)) >> 4) & 0x3ffc0ff),
(int) ((self::load_4(self::substr($key, 9, 4)) >> 6) & 0x3f03fff),
(int) ((self::load_4(self::substr($key, 12, 4)) >> 8) & 0x00fffff)
);
/* h = 0 */
$this->h = array(0, 0, 0, 0, 0);
/* save pad for later */
$this->pad = array(
self::load_4(self::substr($key, 16, 4)),
self::load_4(self::substr($key, 20, 4)),
self::load_4(self::substr($key, 24, 4)),
self::load_4(self::substr($key, 28, 4)),
);
$this->leftover = 0;
$this->final = false;
}
/**
* Zero internal buffer upon destruction
*/
public function __destruct()
{
$this->r[0] ^= $this->r[0];
$this->r[1] ^= $this->r[1];
$this->r[2] ^= $this->r[2];
$this->r[3] ^= $this->r[3];
$this->r[4] ^= $this->r[4];
$this->h[0] ^= $this->h[0];
$this->h[1] ^= $this->h[1];
$this->h[2] ^= $this->h[2];
$this->h[3] ^= $this->h[3];
$this->h[4] ^= $this->h[4];
$this->pad[0] ^= $this->pad[0];
$this->pad[1] ^= $this->pad[1];
$this->pad[2] ^= $this->pad[2];
$this->pad[3] ^= $this->pad[3];
$this->leftover = 0;
$this->final = true;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @return self
* @throws SodiumException
* @throws TypeError
*/
public function update($message = '')
{
$bytes = self::strlen($message);
if ($bytes < 1) {
return $this;
}
/* handle leftover */
if ($this->leftover) {
$want = ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE - $this->leftover;
if ($want > $bytes) {
$want = $bytes;
}
for ($i = 0; $i < $want; ++$i) {
$mi = self::chrToInt($message[$i]);
$this->buffer[$this->leftover + $i] = $mi;
}
// We snip off the leftmost bytes.
$message = self::substr($message, $want);
$bytes = self::strlen($message);
$this->leftover += $want;
if ($this->leftover < ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) {
// We still don't have enough to run $this->blocks()
return $this;
}
$this->blocks(
self::intArrayToString($this->buffer),
ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE
);
$this->leftover = 0;
}
/* process full blocks */
if ($bytes >= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) {
/** @var int $want */
$want = $bytes & ~(ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE - 1);
if ($want >= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) {
$block = self::substr($message, 0, $want);
if (self::strlen($block) >= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) {
$this->blocks($block, $want);
$message = self::substr($message, $want);
$bytes = self::strlen($message);
}
}
}
/* store leftover */
if ($bytes) {
for ($i = 0; $i < $bytes; ++$i) {
$mi = self::chrToInt($message[$i]);
$this->buffer[$this->leftover + $i] = $mi;
}
$this->leftover = (int) $this->leftover + $bytes;
}
return $this;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param int $bytes
* @return self
* @throws TypeError
*/
public function blocks($message, $bytes)
{
if (self::strlen($message) < 16) {
$message = str_pad($message, 16, "\x00", STR_PAD_RIGHT);
}
/** @var int $hibit */
$hibit = $this->final ? 0 : 1 << 24; /* 1 << 128 */
$r0 = (int) $this->r[0];
$r1 = (int) $this->r[1];
$r2 = (int) $this->r[2];
$r3 = (int) $this->r[3];
$r4 = (int) $this->r[4];
$s1 = self::mul($r1, 5, 3);
$s2 = self::mul($r2, 5, 3);
$s3 = self::mul($r3, 5, 3);
$s4 = self::mul($r4, 5, 3);
$h0 = $this->h[0];
$h1 = $this->h[1];
$h2 = $this->h[2];
$h3 = $this->h[3];
$h4 = $this->h[4];
while ($bytes >= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) {
/* h += m[i] */
$h0 += self::load_4(self::substr($message, 0, 4)) & 0x3ffffff;
$h1 += (self::load_4(self::substr($message, 3, 4)) >> 2) & 0x3ffffff;
$h2 += (self::load_4(self::substr($message, 6, 4)) >> 4) & 0x3ffffff;
$h3 += (self::load_4(self::substr($message, 9, 4)) >> 6) & 0x3ffffff;
$h4 += (self::load_4(self::substr($message, 12, 4)) >> 8) | $hibit;
/* h *= r */
$d0 = (
self::mul($h0, $r0, 27) +
self::mul($s4, $h1, 27) +
self::mul($s3, $h2, 27) +
self::mul($s2, $h3, 27) +
self::mul($s1, $h4, 27)
);
$d1 = (
self::mul($h0, $r1, 27) +
self::mul($h1, $r0, 27) +
self::mul($s4, $h2, 27) +
self::mul($s3, $h3, 27) +
self::mul($s2, $h4, 27)
);
$d2 = (
self::mul($h0, $r2, 27) +
self::mul($h1, $r1, 27) +
self::mul($h2, $r0, 27) +
self::mul($s4, $h3, 27) +
self::mul($s3, $h4, 27)
);
$d3 = (
self::mul($h0, $r3, 27) +
self::mul($h1, $r2, 27) +
self::mul($h2, $r1, 27) +
self::mul($h3, $r0, 27) +
self::mul($s4, $h4, 27)
);
$d4 = (
self::mul($h0, $r4, 27) +
self::mul($h1, $r3, 27) +
self::mul($h2, $r2, 27) +
self::mul($h3, $r1, 27) +
self::mul($h4, $r0, 27)
);
/* (partial) h %= p */
/** @var int $c */
$c = $d0 >> 26;
/** @var int $h0 */
$h0 = $d0 & 0x3ffffff;
$d1 += $c;
/** @var int $c */
$c = $d1 >> 26;
/** @var int $h1 */
$h1 = $d1 & 0x3ffffff;
$d2 += $c;
/** @var int $c */
$c = $d2 >> 26;
/** @var int $h2 */
$h2 = $d2 & 0x3ffffff;
$d3 += $c;
/** @var int $c */
$c = $d3 >> 26;
/** @var int $h3 */
$h3 = $d3 & 0x3ffffff;
$d4 += $c;
/** @var int $c */
$c = $d4 >> 26;
/** @var int $h4 */
$h4 = $d4 & 0x3ffffff;
$h0 += (int) self::mul($c, 5, 3);
/** @var int $c */
$c = $h0 >> 26;
/** @var int $h0 */
$h0 &= 0x3ffffff;
$h1 += $c;
// Chop off the left 32 bytes.
$message = self::substr(
$message,
ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE
);
$bytes -= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE;
}
$this->h = array(
(int) ($h0 & 0xffffffff),
(int) ($h1 & 0xffffffff),
(int) ($h2 & 0xffffffff),
(int) ($h3 & 0xffffffff),
(int) ($h4 & 0xffffffff)
);
return $this;
}
/**
* @internal You should not use this directly from another application
*
* @return string
* @throws TypeError
*/
public function finish()
{
/* process the remaining block */
if ($this->leftover) {
$i = $this->leftover;
$this->buffer[$i++] = 1;
for (; $i < ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE; ++$i) {
$this->buffer[$i] = 0;
}
$this->final = true;
$this->blocks(
self::substr(
self::intArrayToString($this->buffer),
0,
ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE
),
ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE
);
}
$h0 = (int) $this->h[0];
$h1 = (int) $this->h[1];
$h2 = (int) $this->h[2];
$h3 = (int) $this->h[3];
$h4 = (int) $this->h[4];
/** @var int $c */
$c = $h1 >> 26;
/** @var int $h1 */
$h1 &= 0x3ffffff;
/** @var int $h2 */
$h2 += $c;
/** @var int $c */
$c = $h2 >> 26;
/** @var int $h2 */
$h2 &= 0x3ffffff;
$h3 += $c;
/** @var int $c */
$c = $h3 >> 26;
$h3 &= 0x3ffffff;
$h4 += $c;
/** @var int $c */
$c = $h4 >> 26;
$h4 &= 0x3ffffff;
/** @var int $h0 */
$h0 += self::mul($c, 5, 3);
/** @var int $c */
$c = $h0 >> 26;
/** @var int $h0 */
$h0 &= 0x3ffffff;
/** @var int $h1 */
$h1 += $c;
/* compute h + -p */
/** @var int $g0 */
$g0 = $h0 + 5;
/** @var int $c */
$c = $g0 >> 26;
/** @var int $g0 */
$g0 &= 0x3ffffff;
/** @var int $g1 */
$g1 = $h1 + $c;
/** @var int $c */
$c = $g1 >> 26;
$g1 &= 0x3ffffff;
/** @var int $g2 */
$g2 = $h2 + $c;
/** @var int $c */
$c = $g2 >> 26;
/** @var int $g2 */
$g2 &= 0x3ffffff;
/** @var int $g3 */
$g3 = $h3 + $c;
/** @var int $c */
$c = $g3 >> 26;
/** @var int $g3 */
$g3 &= 0x3ffffff;
/** @var int $g4 */
$g4 = ($h4 + $c - (1 << 26)) & 0xffffffff;
/* select h if h < p, or h + -p if h >= p */
/** @var int $mask */
$mask = ($g4 >> 31) - 1;
$g0 &= $mask;
$g1 &= $mask;
$g2 &= $mask;
$g3 &= $mask;
$g4 &= $mask;
/** @var int $mask */
$mask = ~$mask & 0xffffffff;
/** @var int $h0 */
$h0 = ($h0 & $mask) | $g0;
/** @var int $h1 */
$h1 = ($h1 & $mask) | $g1;
/** @var int $h2 */
$h2 = ($h2 & $mask) | $g2;
/** @var int $h3 */
$h3 = ($h3 & $mask) | $g3;
/** @var int $h4 */
$h4 = ($h4 & $mask) | $g4;
/* h = h % (2^128) */
/** @var int $h0 */
$h0 = (($h0) | ($h1 << 26)) & 0xffffffff;
/** @var int $h1 */
$h1 = (($h1 >> 6) | ($h2 << 20)) & 0xffffffff;
/** @var int $h2 */
$h2 = (($h2 >> 12) | ($h3 << 14)) & 0xffffffff;
/** @var int $h3 */
$h3 = (($h3 >> 18) | ($h4 << 8)) & 0xffffffff;
/* mac = (h + pad) % (2^128) */
$f = (int) ($h0 + $this->pad[0]);
$h0 = (int) $f;
$f = (int) ($h1 + $this->pad[1] + ($f >> 32));
$h1 = (int) $f;
$f = (int) ($h2 + $this->pad[2] + ($f >> 32));
$h2 = (int) $f;
$f = (int) ($h3 + $this->pad[3] + ($f >> 32));
$h3 = (int) $f;
return self::store32_le($h0 & 0xffffffff) .
self::store32_le($h1 & 0xffffffff) .
self::store32_le($h2 & 0xffffffff) .
self::store32_le($h3 & 0xffffffff);
}
}
Blog Section
Dive into our blog to explore the cutting-edge trends in digital payments and NFC technology. Stay updated on the innovations that are revolutionizing transactions, boosting security, and making payments quicker and more convenient. Learn how these advancements are shaping the future of financial interactions and driving the global transition towards a cashless world.
In recent years, contactless payments have surged in popularity, driven...
As digital transactions proliferate, ensuring robust payment security is more critical than ever. Two foundational...
Digital wallets have fundamentally transformed how we manage money, offering a streamlined, secure, and highly...