jlxip icon

RFC 7748 errata

jlxip | PRO | 02/27/24 10:45:39 AM UTC | 0 ⭐ | 1480 👁️ | Never ⏰ | []
Python |

3.05 KB

|

None

|

0 👍

/

0 👎

# Regarding, RFC 7748, Section 5.2, X448, second vector, the given input
# u-coordinate is not part of a valid point on the Montgomery form of Curve448.
# I suggest replacing the point with a valid one: (2^447 + 100)*G
# Execute at: https://sagecell.sagemath.org/
 
 
# Curve448 parameters, as per RFC 7748, Section 4.2
# Galois Field
F = GF(2^448 - 2^224 - 1)
# Montgomery form parameters
A = 156326
B = 1
 
 
 
# --- AUXILIARY FUNCTIONS ---
def is_valid_point(u):
    # Check if the point satisfies the curve equation v^2 = u^3 + Au^2 + u in the field F
    u3_plus_Au2_plus_u = u^3 + A*u^2 + u
    # Check if this is a quadratic residue in F, meaning there exists a v^2
    return u3_plus_Au2_plus_u.is_square()
rawslicer = lambda x, k : [x[k*i:k*(i+1)] for i in range(len(x)//k)]
stringslicer = lambda x, k : ''.join(rawslicer(x, k))
little2big = lambda x : stringslicer(x, 2)
def little(x):
    if len(x) % 2: x = '0' + x
    return ''.join(rawslicer(x, 2)[::-1])
def fixscalar(d):
    d >>= 2
    d <<= 2
    d |= 1 << 447
    return d
 
 
 
# Generator's u-coordinate
G = F(5)
# First test vector, from Section 5.2, X448
FIRST = F(382239910814107330116229961234899377031416365240571325148346555922438025162094455820962429142971339584360034337310079791515452463053830)
FIRSTSCALAR = F(fixscalar(599189175373896402783756016145213256157230856085026129926891459468622403380588640249457727683869421921443004045221642549886377526240828))
FIRSTOUTPUT = 'ce3e4ff95a60dc6697da1db1d85e6afbdf79b50a2412d7546d5f239fe14fbaadeb445fc66a01b0779d98223961111e21766282f73dd96b6f'
FIRSTOUTPUT = int.from_bytes(bytes.fromhex(FIRSTOUTPUT), byteorder='little')
# Second test vector
SECOND = F(622761797758325444462922068431234180649590390024811299761625153767228042600197997696167956134770744996690267634159427999832340166786063)
SECONDSCALAR = F(fixscalar(633254335906970592779259481534862372382525155252028961056404001332122152890562527156973881968934311400345568203929409663925541994577184))
 
# Prove my point
assert is_valid_point(G)
assert is_valid_point(FIRST)
assert not is_valid_point(SECOND)
 
# Curve implementation
ec = EllipticCurve(F, [0,A,0,B,0])
assert (FIRSTSCALAR * ec.lift_x(FIRST))[0] == FIRSTOUTPUT
 
# Proposed point
PROPOSED = fixscalar(100) * ec.lift_x(G)
PROPOSED = PROPOSED[0] # Get only u
assert is_valid_point(PROPOSED)
 
# Proposed output, keeping the same d
out = SECONDSCALAR * ec.lift_x(PROPOSED)
out = out[0] # Only u
 
# Encodings
stru = str(PROPOSED)
hexu = little(hex(PROPOSED)[2:])
hexout = little(hex(out)[2:])
 
# Just in case
assert (SECONDSCALAR * ec.lift_x(PROPOSED))[0] == out
assert int.from_bytes(bytes.fromhex(hexu), byteorder='little') == PROPOSED
assert int.from_bytes(bytes.fromhex(hexout), byteorder='little') == out
 
print('   Input u-coordinate:')
print('     '+'\n     '.join(rawslicer(hexu, len(hexu)//2)))
print('   Input u-coordinate as a number (base 10):')
print('     '+'\n     '.join(rawslicer(stru, len(stru)//3)))
print('   Output u-coordinate:')
print('     '+'\n     '.join(rawslicer(hexout, len(hexout)//2)))
 

Comments