Beispiel #1
0
def find_prime_root(l, blum=True, n=1):
    """Find smallest prime of bit length at least l satisfying given constraints.

    Default is to return Blum primes (primes p with p % 4 == 3).
    Also, a primitive root w is returned of prime order at least n (0 < w < p).
    """
    if l <= 2:
        if not blum:
            p = 2
            assert n == 1
            w = 1
        else:
            p = 3
            n, w = 2, p - 1
    elif n <= 2:
        p = gmpy2.next_prime(1 << l - 1)
        if blum:
            while p % 4 != 3:
                p = gmpy2.next_prime(p)
        p = int(p)
        w = p - 1 if n == 2 else 1
    else:
        assert blum
        if not gmpy2.is_prime(n):
            n = gmpy2.next_prime(n)
        p = 1 + 2 * n * (3 + 2 * ((1 << l - 3) // n))
        while not gmpy2.is_prime(p):
            p += 4 * n

        a = 2
        while (w := gmpy2.powmod(a, (p - 1) // n, p)) == 1:
            a += 1
        p, w = int(p), int(w)
Beispiel #2
0
def find_prime_root(l, blum=True, n=1):
    """Find smallest prime of bit length l satisfying given constraints.

    Default is to return Blum primes (primes p with p % 4 == 3).
    Also, a primitive root w is returned of prime order at least n.
    """
    if l == 1:
        assert not blum
        assert n == 1
        p = 2
        w = 1
    elif n <= 2:
        n = 2
        w = -1
        p = gmpy2.next_prime(2**(l - 1))
        if blum:
            while p % 4 != 3:
                p = gmpy2.next_prime(p)
        p = int(p)
    else:
        assert blum
        if not gmpy2.is_prime(n):
            n = int(gmpy2.next_prime(n))
        p = 1 + n * (1 + (n**2) % 4 + 4 * ((2**(l - 2)) // n))
        while not gmpy2.is_prime(p):
            p += 4 * n

        a = 1
        w = 1
        while w == 1:
            a += 1
            w = gmpy2.powmod(a, (p - 1) // n, p)
        p, w = int(p), int(w)
    return p, n, w
Beispiel #3
0
def SchnorrGroup(p=None, q=None, g=None, l=None, n=None):
    """Create type for Schnorr group of odd prime order q.

    If q is not given, q will be the smallest n-bit prime, n>=2.
    If p is not given, p will be the least l-bit prime, l>n, such that q divides p-1.

    If l and/or n are not given, default bit lengths will be set (2<=n<l).
    """
    n_l = ((160, 1024), (192, 1536), (224, 2048), (256, 3072), (384, 7680))
    if p is None:
        if q is None:
            if n is None:
                if l is None:
                    l = 2048
                n = next((n for n, _ in n_l if _ >= l), 512)
            q = next_prime(1 << n-1)
        else:
            if n is None:
                n = q.bit_length()
            assert q%2 and is_prime(q)
        if l is None:
            l = next((l for _, l in n_l if _ >= n), 15360)

        # n-bit prime q
        w = (1 << l-2) // q + 1  # w*q >= 2^(l-2), so p = 2*w*q + 1 > 2^(l-1)
        p = 2*w*q + 1
        while not is_prime(p):
            p += 2*q
        # 2^(l-1) < p < 2^l
    else:
        assert q is not None  # if p is given, q must be given as well
        assert (p - 1) % q == 0
        assert q%2 and is_prime(q)
        assert is_prime(p)
        if l is None:
            l = p.bit_length()
        if n is None:
            n = q.bit_length()
    assert l == p.bit_length()
    assert n == q.bit_length()

    p = int(p)
    q = int(q)
    if g is None:
        w = (p-1) // q
        i = 2
        while True:
            g = powmod(i, w, p)
            if g != 1 and powmod(g, q, p) == 1:
                break
            i += 1
        g = int(g)
    return _SchnorrGroup(p, q, g)
Beispiel #4
0
def GF(modulus, f=0):
    """Create a Galois (finite) field for given prime modulus."""
    if isinstance(modulus, tuple):
        p, n, w = modulus
    else:
        p = modulus
        if p == 2:
            n, w = 1, 1
        else:
            n, w = 2, -1

    if (p, f) in _field_cache:
        return _field_cache[(p, f)]

    if not gmpy2.is_prime(p):
        raise ValueError(f'{p} is not a prime')

    GFElement = type(f'GF({p})', (PrimeFieldElement, ), {'__slots__': ()})
    GFElement.modulus = p
    GFElement.order = p
    GFElement.is_signed = True
    GFElement.nth = n
    GFElement.root = w % p
    GFElement.frac_length = f
    GFElement.rshift_factor = int(gmpy2.invert(1 << f,
                                               p))  # cache (1/2)^f mod p
    _field_cache[(p, f)] = GFElement
    return GFElement
Beispiel #5
0
def ClassGroup(Delta=None, l=None):
    """Create type for class group, given (bit length l of) discriminant Delta.

    The following conditions are imposed on discriminant Delta:

        - Delta < 0, only supporting class groups of imaginary quadratic field
        - Delta = 1 (mod 4), preferably Delta = 1 (mod 8)
        - -Delta is prime

    This implies that Delta is a fundamental discriminant.
    """
    if l is not None:
        if Delta is None:
            # find fundamental discriminant Delta of bit length l >= 2
            p = next_prime(1 << l-1)
            while p != 3 and p != 11 and p%8 != 7:
                p = next_prime(p)
            Delta = int(-p)  # D = 1 mod 4, and even D = 1 mod 8 if possible (and -D is prime)
    elif Delta is None:
        Delta = -3
    if Delta%4 != 1:
        raise ValueError('discriminant required to be 1 modulo 4, preferably 1 modulo 8')

    if Delta >= 0 or not is_prime(-Delta):
        raise ValueError('negative prime discriminant required')

    return _ClassGroup(Delta)
Beispiel #6
0
def pGF(modulus, f=0):
    """Create a finite field for given prime modulus."""
    if isinstance(modulus, tuple):
        p, n, w = modulus
    else:
        p = modulus
        if p == 2:
            n, w = 1, 1
        else:
            n, w = 2, -1
    if not gmpy2.is_prime(p):
        raise ValueError('modulus is not a prime')

    GFElement = type(f'GF({p})', (PrimeFieldElement, ), {'__slots__': ()})
    GFElement.modulus = p
    GFElement.order = p
    GFElement.characteristic = p
    GFElement.ext_deg = 1
    GFElement.byte_length = (GFElement.order.bit_length() + 7) >> 3
    GFElement.frac_length = f
    GFElement.rshift_factor = int(gmpy2.invert(1 << f,
                                               p))  # cache (1/2)^f mod p
    GFElement.is_signed = True
    GFElement.nth = n
    GFElement.root = w % p
    return GFElement
Beispiel #7
0
def GF(modulus, f=0):
    """Create a Galois (finite) field for given prime modulus."""
    if isinstance(modulus, tuple):
        p, n, w = modulus
    else:
        p = modulus
        if p == 2:
            n, w = 1, 1
        else:
            n, w = 2, -1

    if (p, f) in _field_cache:
        return _field_cache[(p, f)]

    if not gmpy2.is_prime(p):
        raise ValueError("%d is not a prime" % p)

    GFElement = type('GF(' + str(p) + ')', (PrimeFieldElement, ),
                     {'__slots__': ()})
    GFElement.modulus = p
    GFElement.is_signed = True
    GFElement.nth = n
    GFElement.root = w % p
    GFElement.frac_length = f
    _field_cache[(p, f)] = GFElement
    return GFElement
Beispiel #8
0
def GFpX(p):
    """Create type for polynomials over GF(p)."""
    if not gmpy2.is_prime(p):
        raise ValueError('number is not prime')

    BasePolynomial = BinaryPolynomial if p == 2 else Polynomial
    GFpPolynomial = type(f'GF({p})[{X}]', (BasePolynomial,), {'__slots__': ()})
    GFpPolynomial.p = p
    return GFpPolynomial
Beispiel #9
0
def GFpX(p):
    """Create type for polynomials over GF(p)."""
    if not gmpy2.is_prime(p):
        raise ValueError('number is not prime')

    BasePolynomial = BinaryPolynomial if p == 2 else Polynomial
    GFpPolynomial = type(f'GF({p})[{X}]', (BasePolynomial,), {'__slots__': ()})
    GFpPolynomial.p = p
    globals()[f'GF({p})[{X}]'] = GFpPolynomial  # NB: exploit unique name dynamic Polynomial type
    return GFpPolynomial
Beispiel #10
0
    def test_basic(self):
        self.assertFalse(gmpy.is_prime(1))
        self.assertTrue(gmpy.is_prime(2))
        self.assertTrue(gmpy.is_prime(101))
        self.assertFalse(gmpy.is_prime(561))
        self.assertTrue(gmpy.is_prime(2**16 + 1))
        self.assertFalse(gmpy.is_prime(41041))

        self.assertEqual(gmpy.next_prime(1), 2)
        self.assertEqual(gmpy.next_prime(2), 3)
        self.assertEqual(gmpy.next_prime(256), 257)

        self.assertEqual(gmpy.powmod(3, 256, 257), 1)

        self.assertEqual(gmpy.invert(3, 257), 86)
        self.assertRaises(ZeroDivisionError, gmpy.invert, 2, 4)

        self.assertEqual(gmpy.legendre(0, 101), 0)
        self.assertEqual(gmpy.legendre(42, 101), -1)
        self.assertEqual(gmpy.legendre(54, 101), 1)

        self.assertTrue(gmpy.is_square(625))
        self.assertFalse(gmpy.is_square(652))

        self.assertEqual(gmpy.isqrt(0), 0)
        self.assertEqual(gmpy.isqrt(1225), 35)

        self.assertTrue(gmpy.iroot(0, 10)[1])
        self.assertFalse(gmpy.iroot(1226, 2)[1])
        self.assertEqual(gmpy.iroot(1226, 2)[0], 35)
        self.assertEqual(gmpy.iroot(3**10 + 42, 10)[0], 3)
Beispiel #11
0
def SecFld(order=None, modulus=None, char2=None, l=None):
    """Secure prime or binary field of (l+1)-bit order.

    Field is prime by default, and if order (or modulus) is prime.
    Field is binary if order is a power of 2, if modulus is a
    polynomial, or if char2 is True.
    """
    if isinstance(modulus, str):
        modulus = gf2x.Polynomial(modulus)
    if isinstance(modulus, gf2x.Polynomial):
        char2 = char2 or (char2 is None)
        assert char2  # binary field
        modulus = int(modulus)
    if order is not None:
        if order == 2:
            assert modulus is None or modulus == 2 or modulus == 3
            if modulus is None or modulus == 2:
                # default: prime field
                char2 = char2 or False
            else:
                char2 = char2 or (char2 is None)
                assert char2  # binary field
        elif gmpy.is_prime(order):
            modulus = modulus or order
            assert modulus == order
            char2 = char2 or False
            assert not char2  # prime field
        elif order % 2 == 0:
            assert modulus is None or modulus.bit_length() == order.bit_length(
            )
            char2 = char2 or (char2 is None)
            assert char2  # binary field
        else:
            raise ValueError('only prime fields and binary fields supported')
        l = l or order.bit_length() - 1
        assert l == order.bit_length() - 1
    if modulus is None:
        l = l or 1
        if char2:
            modulus = int(bfield.find_irreducible(l))
        else:
            modulus = pfield.find_prime_root(l + 1, blum=False)[0]
    l = modulus.bit_length() - 1
    if char2:
        field = bfield.GF(modulus)
    else:
        field = pfield.GF(modulus)
    assert runtime.threshold == 0 or field.order > len(runtime.parties), \
        'Field order must exceed number of parties, unless threshold is 0.'
    # field.order >= number of parties for MDS
    field.is_signed = False
    return _SecFld(l, field)
Beispiel #12
0
def pGF(p, n, w):
    """Create a finite field for given prime modulus p."""
    if not gmpy2.is_prime(p):
        raise ValueError('modulus is not a prime')

    GFp = type(f'GF({p})', (PrimeFieldElement, ), {'__slots__': ()})
    GFp.__doc__ = 'Class of prime field elements.'
    GFp.modulus = p
    GFp.order = p
    GFp.characteristic = p
    GFp.ext_deg = 1
    GFp.byte_length = (GFp.order.bit_length() + 7) >> 3
    GFp.is_signed = True
    GFp.nth = n
    GFp.root = w % p
    return GFp
Beispiel #13
0
def _find_safe_prime(l):
    """Find safe prime p of bit length l, l>=2.

    Hence, q=(p-1)/2 is also prime (except when l=2 and p=3).
    It is also ensured that p=3 (mod 4), hence p is a Blum prime.
    """
    IKE_options_l_k = {
        768: 149686,
        1024: 129093,
        1536: 741804,
        2048: 124476,
        3072: 1690314,
        4096: 240904,
        6144: 929484,
        8192: 4743158
    }
    if l in IKE_options_l_k:
        # Compute pi to the required precision.
        decimal.setcontext(decimal.Context(prec=round(l / math.log2(10))))
        # See https://docs.python.org/3/library/decimal.html for following recipe:
        decimal.getcontext().prec += 2  # extra digits for intermediate steps
        three = decimal.Decimal(3)
        lasts, t, s, n, na, d, da = 0, three, 3, 1, 0, 0, 24
        while s != lasts:
            lasts = s
            n, na = n + na, na + 8
            d, da = d + da, da + 32
            t = (t * n) / d
            s += t
        decimal.getcontext().prec -= 2
        pi_l = +s  # NB: unary plus applies the new precision

        # Following https://kivinen.iki.fi/primes to compute IKE prime p:
        k = IKE_options_l_k[l]
        fixedbits = 64
        epi = math.floor(pi_l * 2**(l - 2 * fixedbits - 2)) + k
        p = 2**l - 2**(l - fixedbits) - 1 + epi * 2**fixedbits
    else:
        if l == 2:
            p = 3
        else:
            q = next_prime(1 << l - 2)
            while not is_prime(2 * q + 1):
                q = next_prime(q)
            # q is a Sophie Germain prime
            p = int(2 * q + 1)
    return p
Beispiel #14
0
async def keygen(g):
    """Threshold ElGamal key generation."""
    group = type(g)
    secgrp = mpc.SecGrp(group)
    n = group.order
    if n is not None and is_prime(n):
        secnum = mpc.SecFld(n)
    else:
        l = isqrt(-group.discriminant).bit_length()
        secnum = mpc.SecInt(l)

    while True:
        x = mpc._random(secnum)
        h = await secgrp.repeat_public(g, x)  # g^x
        if h != group.identity:
            # NB: this branch will always be followed unless n is artificially small
            return x, h
Beispiel #15
0
def pGF(p, f, n, w):
    """Create a finite field for given prime modulus p."""
    if not gmpy2.is_prime(p):
        raise ValueError('modulus is not a prime')

    GFtype = type(f'GF({p})', (PrimeFieldElement, ), {'__slots__': ()})
    GFtype.__doc__ = 'Class of prime field elements.'
    GFtype.modulus = p
    GFtype.order = p
    GFtype.characteristic = p
    GFtype.ext_deg = 1
    GFtype.byte_length = (GFtype.order.bit_length() + 7) >> 3
    GFtype._frac_length = f
    GFtype._rshift_factor = int(gmpy2.invert(1 << f, p))  # cache (1/2)^f mod p
    GFtype.is_signed = True
    GFtype.nth = n
    GFtype.root = w % p
    return GFtype
Beispiel #16
0
def SecFld(order=None, modulus=None, char2=None, l=None):
    """Secure prime or binary field of (l+1)-bit order.

    Field is prime by default, and if order (or modulus) is prime.
    Field is binary if order is a power of 2, if modulus is a
    polynomial, or if char2 is True.
    """
    if isinstance(modulus, str):
        modulus = gf2x.Polynomial(modulus)
    if isinstance(modulus, gf2x.Polynomial):
        char2 = char2 or (char2 is None)
        assert char2  # binary field
        modulus = int(modulus)
    if order is not None:
        if order == 2:
            assert modulus is None or modulus == 2 or modulus == 3
            if modulus is None or modulus == 2:
                # default: prime field
                char2 = char2 or False
            else:
                char2 = char2 or (char2 is None)
                assert char2  # binary field
        elif gmpy.is_prime(order):
            modulus = modulus or order
            assert modulus == order
            char2 = char2 or False
            assert not char2  # prime field
        elif order % 2 == 0:
            assert modulus is None or modulus.bit_length() == order.bit_length(
            )
            char2 = char2 or (char2 is None)
            assert char2  # binary field
        else:
            raise ValueError('only prime fields and binary fields supported')
        l = l or order.bit_length() - 1
        assert l == order.bit_length() - 1
    if modulus is None:
        l = l or 1
        if char2:
            modulus = int(bfield.find_irreducible(l))
        else:
            modulus = pfield.find_prime_root(l + 1, blum=False)[0]
    l = modulus.bit_length() - 1
    if char2:
        field = bfield.GF(modulus)
    else:
        field = pfield.GF(modulus)
    assert runtime.threshold == 0 or field.order > len(runtime.parties), \
            'Field order must exceed number of parties, unless threshold is 0.'
    # field.order >= number of parties for MDS
    field.is_signed = False

    if (modulus, char2) not in _sectypes:

        class SecureFld(Share):
            __slots__ = ()

            def __init__(self, value=None):
                super().__init__(field, value)

        SecureFld.field = field
        SecureFld.bit_length = l
        name = f'SecFld{SecureFld.bit_length}({SecureFld.field.modulus})'
        _sectypes[(modulus, char2)] = type(name, (SecureFld, ),
                                           {'__slots__': ()})
    return _sectypes[(modulus, char2)]
Beispiel #17
0
def _EllipticCurve(curvename, coordinates):
    if curvename.startswith('Ed'):
        if curvename == 'Ed25519':
            p = 2**255 - 19
            gf = GF(p)
        elif curvename == 'Ed448':
            p = 2**448 - 2**224 - 1
            gf = GF(p)
        else:
            raise ValueError('invalid curvename')

        name = f'E({gf.__name__}){curvename}{coordinates}'
        if coordinates == 'extended':
            base = EdwardsExtended
        elif coordinates == 'affine':
            base = EdwardsAffine
        elif coordinates == 'projective':
            base = EdwardsProjective
        else:
            raise ValueError('invalid coordinates')

        EC = type(name, (base,), {'__slots__': ()})
        EC.field = gf

        if curvename == 'Ed25519':
            EC.a = gf(-1)  # twisted
            EC.d = gf(-121665) / gf(121666)
            y = gf(4) / gf(5)
            x2 = (1 - y**2) / (EC.a - EC.d * y**2)
            x = x2.sqrt()
            x = x if x.value%2 == 0 else -x  # enforce "positive" (even) x coordinate
            base_pt = (x, y)
            EC.order = 2**252 + 27742317777372353535851937790883648493
        else:  # 'Ed448'
            EC.a = gf(1)
            EC.d = gf(-39081)
            y = gf(19)
            x2 = (1 - y**2) / (EC.a - EC.d * y**2)
            x = x2.sqrt()
            x = x if 2*x.value < p else -x  # enforce principal root
            base_pt = (x, y)
            EC.order = 2**446 - int('8335dc163bb124b65129c96fde933d8d723a70aadc873d6d54a7bb0d', 16)
    elif curvename.startswith('BN'):
        u = 1868033**3
        p = 36*u**4 + 36*u**3 + 24*u**2 + 6*u + 1  # p = 3 (mod 4)
        if curvename == 'BN256':
            gf = GF(p)
        elif curvename == 'BN256_twist':
            gf = GF(GFpX(p)('x^2+1'))  # i^2 == -1
        else:
            raise ValueError('invalid curvename')

        name = f'E({gf.__name__}){curvename}{coordinates}'
        if coordinates == 'jacobian':
            base = WeierstrassJacobian
        elif coordinates == 'affine':
            base = WeierstrassAffine
        elif coordinates == 'projective':
            base = WeierstrassProjective
        else:
            raise ValueError('invalid coordinates')

        EC = type(name, (base,), {'__slots__': ()})
        EC.field = gf

        if curvename == 'BN256':
            EC.a = gf(0)
            EC.b = gf(3)
            base_pt = (gf(1), gf(-2))
        else:  # 'BN256_twist'
            EC.a = gf('0')
            xi = gf('x+3')
            EC.b = gf('3') / xi
            x = gf([64746500191241794695844075326670126197795977525365406531717464316923369116492,
                    21167961636542580255011770066570541300993051739349375019639421053990175267184])
            y = gf([17778617556404439934652658462602675281523610326338642107814333856843981424549,
                    20666913350058776956210519119118544732556678129809273996262322366050359951122])
            base_pt = (x, y)
        EC.order = p - 6*u**2
    else:
        raise ValueError('curve not supported')

    assert is_prime(EC.order)
    EC.curvename = curvename
    EC.field.is_signed = False  # for consistency between sectypes and regular types
    EC.is_cyclic = True  # these EC groups are cyclic (but not all EC groups are)
    EC.gap = 256  # TODO: optimize gap value
    EC.identity = EC(check=False)
    EC.generator = EC(base_pt, check=False)
    globals()[name] = EC  # NB: exploit (almost?) unique name dynamic EC type
    return EC
Beispiel #18
0
    def test_basic(self):
        self.assertFalse(gmpy.is_prime(1))
        self.assertTrue(gmpy.is_prime(2))
        self.assertTrue(gmpy.is_prime(101))
        self.assertFalse(gmpy.is_prime(561))
        self.assertTrue(gmpy.is_prime(2**16 + 1))
        self.assertFalse(gmpy.is_prime(41041))

        self.assertEqual(gmpy.next_prime(1), 2)
        self.assertEqual(gmpy.next_prime(2), 3)
        self.assertEqual(gmpy.next_prime(256), 257)

        self.assertEqual(gmpy.powmod(3, 256, 257), 1)

        self.assertEqual(gmpy.gcdext(3, 257), (1, 86, -1))
        self.assertEqual(gmpy.gcdext(1234, 257), (1, -126, 605))
        self.assertEqual(gmpy.gcdext(-1234 * 3, -257 * 3), (3, 126, -605))

        def te_s_t(a, b):
            g, s, t = gmpy.gcdext(a, b)
            if abs(a) == abs(b):
                test_s = s == 0
            elif b == 0 or abs(b) == 2 * g:
                test_s = s == bool(a > 0) - bool(a < 0)  # sign of a
            else:
                test_s = abs(s) < abs(b) / (2 * g)
            if abs(a) == abs(b) or a == 0 or abs(a) == 2 * g:
                test_t = t == bool(b > 0) - bool(b < 0)  # sign of b
            else:
                test_t = abs(t) < abs(a) / (2 * g)
            return g == a * s + b * t and test_s and test_t

        self.assertTrue(
            all((te_s_t(0, 0), te_s_t(0, -1), te_s_t(1, 0), te_s_t(-1, 1))))
        self.assertTrue(te_s_t(-1234, 257))
        self.assertTrue(te_s_t(-12537, -257))
        self.assertTrue(te_s_t(-11 * 1234, -11 * 2567))
        self.assertTrue(te_s_t(1234, -2 * 1234))
        self.assertTrue(te_s_t(-2 * 12364, 12364))

        # self.assertEqual(gmpy.invert(3, -1), 0)  # pending gmpy2 issue if modulus is 1 or -1
        self.assertEqual(gmpy.invert(3, 257), 86)
        self.assertRaises(ZeroDivisionError, gmpy.invert, 2, 0)
        self.assertRaises(ZeroDivisionError, gmpy.invert, 2, 4)

        self.assertEqual(gmpy.legendre(0, 101), 0)
        self.assertEqual(gmpy.legendre(42, 101), -1)
        self.assertEqual(gmpy.legendre(54, 101), 1)
        self.assertRaises(ValueError, gmpy.legendre, 1, 2)
        self.assertEqual(gmpy.jacobi(9, 99), 0)
        self.assertEqual(gmpy.jacobi(43, 99), -1)
        self.assertEqual(gmpy.jacobi(53, 99), 1)
        self.assertRaises(ValueError, gmpy.jacobi, 1, 20)
        self.assertEqual(gmpy.kronecker(0, 0), 0)
        self.assertEqual(gmpy.kronecker(-1, 0), 1)
        self.assertEqual(gmpy.kronecker(43, -98), -1)
        self.assertEqual(gmpy.kronecker(-53, -98), 1)
        self.assertEqual(gmpy.kronecker(-54, -98), 0)

        self.assertTrue(gmpy.is_square(625))
        self.assertFalse(gmpy.is_square(652))

        self.assertEqual(gmpy.isqrt(0), 0)
        self.assertEqual(gmpy.isqrt(1225), 35)

        self.assertTrue(gmpy.iroot(0, 10)[1])
        self.assertFalse(gmpy.iroot(1226, 2)[1])
        self.assertEqual(gmpy.iroot(1226, 2)[0], 35)
        self.assertEqual(gmpy.iroot(3**10 + 42, 10)[0], 3)