Merge pull request #704 from mDuo13/doc2359

Key Derivation Info
This commit is contained in:
Rome Reginelli
2019-10-16 13:57:37 -07:00
committed by GitHub
21 changed files with 1841 additions and 110 deletions

View File

@@ -0,0 +1,375 @@
# Upstream version:
# https://github.com/dlitz/pycrypto/blob/master/lib/Crypto/Util/RFC1751.py
# This version has been adapted to Python 3 using the '2to3' utility
# and manually adjusted for better Python 3 compatibility.
# Those revisions are released to the public domain.
# rfc1751.py : Converts between 128-bit strings and a human-readable
# sequence of words, as defined in RFC1751: "A Convention for
# Human-Readable 128-bit Keys", by Daniel L. McDonald.
#
# Part of the Python Cryptography Toolkit
#
# Written by Andrew M. Kuchling and others
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ===================================================================
__revision__ = "$Id$"
import binascii
from functools import reduce
from io import BytesIO
def bchr(s):
return bytes([s])
def bord(s):
return s
binary={0:'0000', 1:'0001', 2:'0010', 3:'0011', 4:'0100', 5:'0101',
6:'0110', 7:'0111', 8:'1000', 9:'1001', 10:'1010', 11:'1011',
12:'1100', 13:'1101', 14:'1110', 15:'1111'}
def _key2bin(s):
"Convert a key into a string of binary digits"
kl=[bord(x) for x in s]
kl=[binary[x>>4]+binary[x&15] for x in kl]
return ''.join(kl)
def _extract(key, start, length):
"""Extract a bitstring(2.x)/bytestring(2.x) from a string of binary digits, and return its
numeric value."""
k=key[start:start+length]
return reduce(lambda x,y: x*2+ord(y)-48, k, 0)
def key_to_english (key):
"""key_to_english(key:string(2.x)/bytes(3.x)) : string
Transform an arbitrary key into a string containing English words.
The key length must be a multiple of 8.
"""
english=''
for index in range(0, len(key), 8): # Loop over 8-byte subkeys
subkey=key[index:index+8]
# Compute the parity of the key
skbin=_key2bin(subkey) ; p=0
for i in range(0, 64, 2): p=p+_extract(skbin, i, 2)
# Append parity bits to the subkey
skbin=_key2bin(subkey+bchr((p<<6) & 255))
for i in range(0, 64, 11):
english=english+wordlist[_extract(skbin, i, 11)]+' '
return english[:-1] # Remove the trailing space
def english_to_key (s):
"""english_to_key(string):string(2.x)/bytes(2.x)
Transform a string into a corresponding key.
The string must contain words separated by whitespace; the number
of words must be a multiple of 6.
"""
L=s.upper().split() ; key=b''
for index in range(0, len(L), 6):
sublist=L[index:index+6] ; char=9*[0] ; bits=0
for i in sublist:
index = wordlist.index(i)
shift = (8-(bits+11)%8) %8
y = index << shift
cl, cc, cr = (y>>16), (y>>8)&0xff, y & 0xff
if (shift>5):
char[bits>>3] = char[bits>>3] | cl
char[(bits>>3)+1] = char[(bits>>3)+1] | cc
char[(bits>>3)+2] = char[(bits>>3)+2] | cr
elif shift>-3:
char[bits>>3] = char[bits>>3] | cc
char[(bits>>3)+1] = char[(bits>>3)+1] | cr
else: char[bits>>3] = char[bits>>3] | cr
bits=bits+11
subkey=reduce(lambda x,y:x+bchr(y), char, b'')
# Check the parity of the resulting key
skbin=_key2bin(subkey)
p=0
for i in range(0, 64, 2): p=p+_extract(skbin, i, 2)
if (p&3) != _extract(skbin, 64, 2):
raise ValueError("Parity error in resulting key")
key=key+subkey[0:8]
return key
wordlist=[ "A", "ABE", "ACE", "ACT", "AD", "ADA", "ADD",
"AGO", "AID", "AIM", "AIR", "ALL", "ALP", "AM", "AMY", "AN", "ANA",
"AND", "ANN", "ANT", "ANY", "APE", "APS", "APT", "ARC", "ARE", "ARK",
"ARM", "ART", "AS", "ASH", "ASK", "AT", "ATE", "AUG", "AUK", "AVE",
"AWE", "AWK", "AWL", "AWN", "AX", "AYE", "BAD", "BAG", "BAH", "BAM",
"BAN", "BAR", "BAT", "BAY", "BE", "BED", "BEE", "BEG", "BEN", "BET",
"BEY", "BIB", "BID", "BIG", "BIN", "BIT", "BOB", "BOG", "BON", "BOO",
"BOP", "BOW", "BOY", "BUB", "BUD", "BUG", "BUM", "BUN", "BUS", "BUT",
"BUY", "BY", "BYE", "CAB", "CAL", "CAM", "CAN", "CAP", "CAR", "CAT",
"CAW", "COD", "COG", "COL", "CON", "COO", "COP", "COT", "COW", "COY",
"CRY", "CUB", "CUE", "CUP", "CUR", "CUT", "DAB", "DAD", "DAM", "DAN",
"DAR", "DAY", "DEE", "DEL", "DEN", "DES", "DEW", "DID", "DIE", "DIG",
"DIN", "DIP", "DO", "DOE", "DOG", "DON", "DOT", "DOW", "DRY", "DUB",
"DUD", "DUE", "DUG", "DUN", "EAR", "EAT", "ED", "EEL", "EGG", "EGO",
"ELI", "ELK", "ELM", "ELY", "EM", "END", "EST", "ETC", "EVA", "EVE",
"EWE", "EYE", "FAD", "FAN", "FAR", "FAT", "FAY", "FED", "FEE", "FEW",
"FIB", "FIG", "FIN", "FIR", "FIT", "FLO", "FLY", "FOE", "FOG", "FOR",
"FRY", "FUM", "FUN", "FUR", "GAB", "GAD", "GAG", "GAL", "GAM", "GAP",
"GAS", "GAY", "GEE", "GEL", "GEM", "GET", "GIG", "GIL", "GIN", "GO",
"GOT", "GUM", "GUN", "GUS", "GUT", "GUY", "GYM", "GYP", "HA", "HAD",
"HAL", "HAM", "HAN", "HAP", "HAS", "HAT", "HAW", "HAY", "HE", "HEM",
"HEN", "HER", "HEW", "HEY", "HI", "HID", "HIM", "HIP", "HIS", "HIT",
"HO", "HOB", "HOC", "HOE", "HOG", "HOP", "HOT", "HOW", "HUB", "HUE",
"HUG", "HUH", "HUM", "HUT", "I", "ICY", "IDA", "IF", "IKE", "ILL",
"INK", "INN", "IO", "ION", "IQ", "IRA", "IRE", "IRK", "IS", "IT",
"ITS", "IVY", "JAB", "JAG", "JAM", "JAN", "JAR", "JAW", "JAY", "JET",
"JIG", "JIM", "JO", "JOB", "JOE", "JOG", "JOT", "JOY", "JUG", "JUT",
"KAY", "KEG", "KEN", "KEY", "KID", "KIM", "KIN", "KIT", "LA", "LAB",
"LAC", "LAD", "LAG", "LAM", "LAP", "LAW", "LAY", "LEA", "LED", "LEE",
"LEG", "LEN", "LEO", "LET", "LEW", "LID", "LIE", "LIN", "LIP", "LIT",
"LO", "LOB", "LOG", "LOP", "LOS", "LOT", "LOU", "LOW", "LOY", "LUG",
"LYE", "MA", "MAC", "MAD", "MAE", "MAN", "MAO", "MAP", "MAT", "MAW",
"MAY", "ME", "MEG", "MEL", "MEN", "MET", "MEW", "MID", "MIN", "MIT",
"MOB", "MOD", "MOE", "MOO", "MOP", "MOS", "MOT", "MOW", "MUD", "MUG",
"MUM", "MY", "NAB", "NAG", "NAN", "NAP", "NAT", "NAY", "NE", "NED",
"NEE", "NET", "NEW", "NIB", "NIL", "NIP", "NIT", "NO", "NOB", "NOD",
"NON", "NOR", "NOT", "NOV", "NOW", "NU", "NUN", "NUT", "O", "OAF",
"OAK", "OAR", "OAT", "ODD", "ODE", "OF", "OFF", "OFT", "OH", "OIL",
"OK", "OLD", "ON", "ONE", "OR", "ORB", "ORE", "ORR", "OS", "OTT",
"OUR", "OUT", "OVA", "OW", "OWE", "OWL", "OWN", "OX", "PA", "PAD",
"PAL", "PAM", "PAN", "PAP", "PAR", "PAT", "PAW", "PAY", "PEA", "PEG",
"PEN", "PEP", "PER", "PET", "PEW", "PHI", "PI", "PIE", "PIN", "PIT",
"PLY", "PO", "POD", "POE", "POP", "POT", "POW", "PRO", "PRY", "PUB",
"PUG", "PUN", "PUP", "PUT", "QUO", "RAG", "RAM", "RAN", "RAP", "RAT",
"RAW", "RAY", "REB", "RED", "REP", "RET", "RIB", "RID", "RIG", "RIM",
"RIO", "RIP", "ROB", "ROD", "ROE", "RON", "ROT", "ROW", "ROY", "RUB",
"RUE", "RUG", "RUM", "RUN", "RYE", "SAC", "SAD", "SAG", "SAL", "SAM",
"SAN", "SAP", "SAT", "SAW", "SAY", "SEA", "SEC", "SEE", "SEN", "SET",
"SEW", "SHE", "SHY", "SIN", "SIP", "SIR", "SIS", "SIT", "SKI", "SKY",
"SLY", "SO", "SOB", "SOD", "SON", "SOP", "SOW", "SOY", "SPA", "SPY",
"SUB", "SUD", "SUE", "SUM", "SUN", "SUP", "TAB", "TAD", "TAG", "TAN",
"TAP", "TAR", "TEA", "TED", "TEE", "TEN", "THE", "THY", "TIC", "TIE",
"TIM", "TIN", "TIP", "TO", "TOE", "TOG", "TOM", "TON", "TOO", "TOP",
"TOW", "TOY", "TRY", "TUB", "TUG", "TUM", "TUN", "TWO", "UN", "UP",
"US", "USE", "VAN", "VAT", "VET", "VIE", "WAD", "WAG", "WAR", "WAS",
"WAY", "WE", "WEB", "WED", "WEE", "WET", "WHO", "WHY", "WIN", "WIT",
"WOK", "WON", "WOO", "WOW", "WRY", "WU", "YAM", "YAP", "YAW", "YE",
"YEA", "YES", "YET", "YOU", "ABED", "ABEL", "ABET", "ABLE", "ABUT",
"ACHE", "ACID", "ACME", "ACRE", "ACTA", "ACTS", "ADAM", "ADDS",
"ADEN", "AFAR", "AFRO", "AGEE", "AHEM", "AHOY", "AIDA", "AIDE",
"AIDS", "AIRY", "AJAR", "AKIN", "ALAN", "ALEC", "ALGA", "ALIA",
"ALLY", "ALMA", "ALOE", "ALSO", "ALTO", "ALUM", "ALVA", "AMEN",
"AMES", "AMID", "AMMO", "AMOK", "AMOS", "AMRA", "ANDY", "ANEW",
"ANNA", "ANNE", "ANTE", "ANTI", "AQUA", "ARAB", "ARCH", "AREA",
"ARGO", "ARID", "ARMY", "ARTS", "ARTY", "ASIA", "ASKS", "ATOM",
"AUNT", "AURA", "AUTO", "AVER", "AVID", "AVIS", "AVON", "AVOW",
"AWAY", "AWRY", "BABE", "BABY", "BACH", "BACK", "BADE", "BAIL",
"BAIT", "BAKE", "BALD", "BALE", "BALI", "BALK", "BALL", "BALM",
"BAND", "BANE", "BANG", "BANK", "BARB", "BARD", "BARE", "BARK",
"BARN", "BARR", "BASE", "BASH", "BASK", "BASS", "BATE", "BATH",
"BAWD", "BAWL", "BEAD", "BEAK", "BEAM", "BEAN", "BEAR", "BEAT",
"BEAU", "BECK", "BEEF", "BEEN", "BEER",
"BEET", "BELA", "BELL", "BELT", "BEND", "BENT", "BERG", "BERN",
"BERT", "BESS", "BEST", "BETA", "BETH", "BHOY", "BIAS", "BIDE",
"BIEN", "BILE", "BILK", "BILL", "BIND", "BING", "BIRD", "BITE",
"BITS", "BLAB", "BLAT", "BLED", "BLEW", "BLOB", "BLOC", "BLOT",
"BLOW", "BLUE", "BLUM", "BLUR", "BOAR", "BOAT", "BOCA", "BOCK",
"BODE", "BODY", "BOGY", "BOHR", "BOIL", "BOLD", "BOLO", "BOLT",
"BOMB", "BONA", "BOND", "BONE", "BONG", "BONN", "BONY", "BOOK",
"BOOM", "BOON", "BOOT", "BORE", "BORG", "BORN", "BOSE", "BOSS",
"BOTH", "BOUT", "BOWL", "BOYD", "BRAD", "BRAE", "BRAG", "BRAN",
"BRAY", "BRED", "BREW", "BRIG", "BRIM", "BROW", "BUCK", "BUDD",
"BUFF", "BULB", "BULK", "BULL", "BUNK", "BUNT", "BUOY", "BURG",
"BURL", "BURN", "BURR", "BURT", "BURY", "BUSH", "BUSS", "BUST",
"BUSY", "BYTE", "CADY", "CAFE", "CAGE", "CAIN", "CAKE", "CALF",
"CALL", "CALM", "CAME", "CANE", "CANT", "CARD", "CARE", "CARL",
"CARR", "CART", "CASE", "CASH", "CASK", "CAST", "CAVE", "CEIL",
"CELL", "CENT", "CERN", "CHAD", "CHAR", "CHAT", "CHAW", "CHEF",
"CHEN", "CHEW", "CHIC", "CHIN", "CHOU", "CHOW", "CHUB", "CHUG",
"CHUM", "CITE", "CITY", "CLAD", "CLAM", "CLAN", "CLAW", "CLAY",
"CLOD", "CLOG", "CLOT", "CLUB", "CLUE", "COAL", "COAT", "COCA",
"COCK", "COCO", "CODA", "CODE", "CODY", "COED", "COIL", "COIN",
"COKE", "COLA", "COLD", "COLT", "COMA", "COMB", "COME", "COOK",
"COOL", "COON", "COOT", "CORD", "CORE", "CORK", "CORN", "COST",
"COVE", "COWL", "CRAB", "CRAG", "CRAM", "CRAY", "CREW", "CRIB",
"CROW", "CRUD", "CUBA", "CUBE", "CUFF", "CULL", "CULT", "CUNY",
"CURB", "CURD", "CURE", "CURL", "CURT", "CUTS", "DADE", "DALE",
"DAME", "DANA", "DANE", "DANG", "DANK", "DARE", "DARK", "DARN",
"DART", "DASH", "DATA", "DATE", "DAVE", "DAVY", "DAWN", "DAYS",
"DEAD", "DEAF", "DEAL", "DEAN", "DEAR", "DEBT", "DECK", "DEED",
"DEEM", "DEER", "DEFT", "DEFY", "DELL", "DENT", "DENY", "DESK",
"DIAL", "DICE", "DIED", "DIET", "DIME", "DINE", "DING", "DINT",
"DIRE", "DIRT", "DISC", "DISH", "DISK", "DIVE", "DOCK", "DOES",
"DOLE", "DOLL", "DOLT", "DOME", "DONE", "DOOM", "DOOR", "DORA",
"DOSE", "DOTE", "DOUG", "DOUR", "DOVE", "DOWN", "DRAB", "DRAG",
"DRAM", "DRAW", "DREW", "DRUB", "DRUG", "DRUM", "DUAL", "DUCK",
"DUCT", "DUEL", "DUET", "DUKE", "DULL", "DUMB", "DUNE", "DUNK",
"DUSK", "DUST", "DUTY", "EACH", "EARL", "EARN", "EASE", "EAST",
"EASY", "EBEN", "ECHO", "EDDY", "EDEN", "EDGE", "EDGY", "EDIT",
"EDNA", "EGAN", "ELAN", "ELBA", "ELLA", "ELSE", "EMIL", "EMIT",
"EMMA", "ENDS", "ERIC", "EROS", "EVEN", "EVER", "EVIL", "EYED",
"FACE", "FACT", "FADE", "FAIL", "FAIN", "FAIR", "FAKE", "FALL",
"FAME", "FANG", "FARM", "FAST", "FATE", "FAWN", "FEAR", "FEAT",
"FEED", "FEEL", "FEET", "FELL", "FELT", "FEND", "FERN", "FEST",
"FEUD", "FIEF", "FIGS", "FILE", "FILL", "FILM", "FIND", "FINE",
"FINK", "FIRE", "FIRM", "FISH", "FISK", "FIST", "FITS", "FIVE",
"FLAG", "FLAK", "FLAM", "FLAT", "FLAW", "FLEA", "FLED", "FLEW",
"FLIT", "FLOC", "FLOG", "FLOW", "FLUB", "FLUE", "FOAL", "FOAM",
"FOGY", "FOIL", "FOLD", "FOLK", "FOND", "FONT", "FOOD", "FOOL",
"FOOT", "FORD", "FORE", "FORK", "FORM", "FORT", "FOSS", "FOUL",
"FOUR", "FOWL", "FRAU", "FRAY", "FRED", "FREE", "FRET", "FREY",
"FROG", "FROM", "FUEL", "FULL", "FUME", "FUND", "FUNK", "FURY",
"FUSE", "FUSS", "GAFF", "GAGE", "GAIL", "GAIN", "GAIT", "GALA",
"GALE", "GALL", "GALT", "GAME", "GANG", "GARB", "GARY", "GASH",
"GATE", "GAUL", "GAUR", "GAVE", "GAWK", "GEAR", "GELD", "GENE",
"GENT", "GERM", "GETS", "GIBE", "GIFT", "GILD", "GILL", "GILT",
"GINA", "GIRD", "GIRL", "GIST", "GIVE", "GLAD", "GLEE", "GLEN",
"GLIB", "GLOB", "GLOM", "GLOW", "GLUE", "GLUM", "GLUT", "GOAD",
"GOAL", "GOAT", "GOER", "GOES", "GOLD", "GOLF", "GONE", "GONG",
"GOOD", "GOOF", "GORE", "GORY", "GOSH", "GOUT", "GOWN", "GRAB",
"GRAD", "GRAY", "GREG", "GREW", "GREY", "GRID", "GRIM", "GRIN",
"GRIT", "GROW", "GRUB", "GULF", "GULL", "GUNK", "GURU", "GUSH",
"GUST", "GWEN", "GWYN", "HAAG", "HAAS", "HACK", "HAIL", "HAIR",
"HALE", "HALF", "HALL", "HALO", "HALT", "HAND", "HANG", "HANK",
"HANS", "HARD", "HARK", "HARM", "HART", "HASH", "HAST", "HATE",
"HATH", "HAUL", "HAVE", "HAWK", "HAYS", "HEAD", "HEAL", "HEAR",
"HEAT", "HEBE", "HECK", "HEED", "HEEL", "HEFT", "HELD", "HELL",
"HELM", "HERB", "HERD", "HERE", "HERO", "HERS", "HESS", "HEWN",
"HICK", "HIDE", "HIGH", "HIKE", "HILL", "HILT", "HIND", "HINT",
"HIRE", "HISS", "HIVE", "HOBO", "HOCK", "HOFF", "HOLD", "HOLE",
"HOLM", "HOLT", "HOME", "HONE", "HONK", "HOOD", "HOOF", "HOOK",
"HOOT", "HORN", "HOSE", "HOST", "HOUR", "HOVE", "HOWE", "HOWL",
"HOYT", "HUCK", "HUED", "HUFF", "HUGE", "HUGH", "HUGO", "HULK",
"HULL", "HUNK", "HUNT", "HURD", "HURL", "HURT", "HUSH", "HYDE",
"HYMN", "IBIS", "ICON", "IDEA", "IDLE", "IFFY", "INCA", "INCH",
"INTO", "IONS", "IOTA", "IOWA", "IRIS", "IRMA", "IRON", "ISLE",
"ITCH", "ITEM", "IVAN", "JACK", "JADE", "JAIL", "JAKE", "JANE",
"JAVA", "JEAN", "JEFF", "JERK", "JESS", "JEST", "JIBE", "JILL",
"JILT", "JIVE", "JOAN", "JOBS", "JOCK", "JOEL", "JOEY", "JOHN",
"JOIN", "JOKE", "JOLT", "JOVE", "JUDD", "JUDE", "JUDO", "JUDY",
"JUJU", "JUKE", "JULY", "JUNE", "JUNK", "JUNO", "JURY", "JUST",
"JUTE", "KAHN", "KALE", "KANE", "KANT", "KARL", "KATE", "KEEL",
"KEEN", "KENO", "KENT", "KERN", "KERR", "KEYS", "KICK", "KILL",
"KIND", "KING", "KIRK", "KISS", "KITE", "KLAN", "KNEE", "KNEW",
"KNIT", "KNOB", "KNOT", "KNOW", "KOCH", "KONG", "KUDO", "KURD",
"KURT", "KYLE", "LACE", "LACK", "LACY", "LADY", "LAID", "LAIN",
"LAIR", "LAKE", "LAMB", "LAME", "LAND", "LANE", "LANG", "LARD",
"LARK", "LASS", "LAST", "LATE", "LAUD", "LAVA", "LAWN", "LAWS",
"LAYS", "LEAD", "LEAF", "LEAK", "LEAN", "LEAR", "LEEK", "LEER",
"LEFT", "LEND", "LENS", "LENT", "LEON", "LESK", "LESS", "LEST",
"LETS", "LIAR", "LICE", "LICK", "LIED", "LIEN", "LIES", "LIEU",
"LIFE", "LIFT", "LIKE", "LILA", "LILT", "LILY", "LIMA", "LIMB",
"LIME", "LIND", "LINE", "LINK", "LINT", "LION", "LISA", "LIST",
"LIVE", "LOAD", "LOAF", "LOAM", "LOAN", "LOCK", "LOFT", "LOGE",
"LOIS", "LOLA", "LONE", "LONG", "LOOK", "LOON", "LOOT", "LORD",
"LORE", "LOSE", "LOSS", "LOST", "LOUD", "LOVE", "LOWE", "LUCK",
"LUCY", "LUGE", "LUKE", "LULU", "LUND", "LUNG", "LURA", "LURE",
"LURK", "LUSH", "LUST", "LYLE", "LYNN", "LYON", "LYRA", "MACE",
"MADE", "MAGI", "MAID", "MAIL", "MAIN", "MAKE", "MALE", "MALI",
"MALL", "MALT", "MANA", "MANN", "MANY", "MARC", "MARE", "MARK",
"MARS", "MART", "MARY", "MASH", "MASK", "MASS", "MAST", "MATE",
"MATH", "MAUL", "MAYO", "MEAD", "MEAL", "MEAN", "MEAT", "MEEK",
"MEET", "MELD", "MELT", "MEMO", "MEND", "MENU", "MERT", "MESH",
"MESS", "MICE", "MIKE", "MILD", "MILE", "MILK", "MILL", "MILT",
"MIMI", "MIND", "MINE", "MINI", "MINK", "MINT", "MIRE", "MISS",
"MIST", "MITE", "MITT", "MOAN", "MOAT", "MOCK", "MODE", "MOLD",
"MOLE", "MOLL", "MOLT", "MONA", "MONK", "MONT", "MOOD", "MOON",
"MOOR", "MOOT", "MORE", "MORN", "MORT", "MOSS", "MOST", "MOTH",
"MOVE", "MUCH", "MUCK", "MUDD", "MUFF", "MULE", "MULL", "MURK",
"MUSH", "MUST", "MUTE", "MUTT", "MYRA", "MYTH", "NAGY", "NAIL",
"NAIR", "NAME", "NARY", "NASH", "NAVE", "NAVY", "NEAL", "NEAR",
"NEAT", "NECK", "NEED", "NEIL", "NELL", "NEON", "NERO", "NESS",
"NEST", "NEWS", "NEWT", "NIBS", "NICE", "NICK", "NILE", "NINA",
"NINE", "NOAH", "NODE", "NOEL", "NOLL", "NONE", "NOOK", "NOON",
"NORM", "NOSE", "NOTE", "NOUN", "NOVA", "NUDE", "NULL", "NUMB",
"OATH", "OBEY", "OBOE", "ODIN", "OHIO", "OILY", "OINT", "OKAY",
"OLAF", "OLDY", "OLGA", "OLIN", "OMAN", "OMEN", "OMIT", "ONCE",
"ONES", "ONLY", "ONTO", "ONUS", "ORAL", "ORGY", "OSLO", "OTIS",
"OTTO", "OUCH", "OUST", "OUTS", "OVAL", "OVEN", "OVER", "OWLY",
"OWNS", "QUAD", "QUIT", "QUOD", "RACE", "RACK", "RACY", "RAFT",
"RAGE", "RAID", "RAIL", "RAIN", "RAKE", "RANK", "RANT", "RARE",
"RASH", "RATE", "RAVE", "RAYS", "READ", "REAL", "REAM", "REAR",
"RECK", "REED", "REEF", "REEK", "REEL", "REID", "REIN", "RENA",
"REND", "RENT", "REST", "RICE", "RICH", "RICK", "RIDE", "RIFT",
"RILL", "RIME", "RING", "RINK", "RISE", "RISK", "RITE", "ROAD",
"ROAM", "ROAR", "ROBE", "ROCK", "RODE", "ROIL", "ROLL", "ROME",
"ROOD", "ROOF", "ROOK", "ROOM", "ROOT", "ROSA", "ROSE", "ROSS",
"ROSY", "ROTH", "ROUT", "ROVE", "ROWE", "ROWS", "RUBE", "RUBY",
"RUDE", "RUDY", "RUIN", "RULE", "RUNG", "RUNS", "RUNT", "RUSE",
"RUSH", "RUSK", "RUSS", "RUST", "RUTH", "SACK", "SAFE", "SAGE",
"SAID", "SAIL", "SALE", "SALK", "SALT", "SAME", "SAND", "SANE",
"SANG", "SANK", "SARA", "SAUL", "SAVE", "SAYS", "SCAN", "SCAR",
"SCAT", "SCOT", "SEAL", "SEAM", "SEAR", "SEAT", "SEED", "SEEK",
"SEEM", "SEEN", "SEES", "SELF", "SELL", "SEND", "SENT", "SETS",
"SEWN", "SHAG", "SHAM", "SHAW", "SHAY", "SHED", "SHIM", "SHIN",
"SHOD", "SHOE", "SHOT", "SHOW", "SHUN", "SHUT", "SICK", "SIDE",
"SIFT", "SIGH", "SIGN", "SILK", "SILL", "SILO", "SILT", "SINE",
"SING", "SINK", "SIRE", "SITE", "SITS", "SITU", "SKAT", "SKEW",
"SKID", "SKIM", "SKIN", "SKIT", "SLAB", "SLAM", "SLAT", "SLAY",
"SLED", "SLEW", "SLID", "SLIM", "SLIT", "SLOB", "SLOG", "SLOT",
"SLOW", "SLUG", "SLUM", "SLUR", "SMOG", "SMUG", "SNAG", "SNOB",
"SNOW", "SNUB", "SNUG", "SOAK", "SOAR", "SOCK", "SODA", "SOFA",
"SOFT", "SOIL", "SOLD", "SOME", "SONG", "SOON", "SOOT", "SORE",
"SORT", "SOUL", "SOUR", "SOWN", "STAB", "STAG", "STAN", "STAR",
"STAY", "STEM", "STEW", "STIR", "STOW", "STUB", "STUN", "SUCH",
"SUDS", "SUIT", "SULK", "SUMS", "SUNG", "SUNK", "SURE", "SURF",
"SWAB", "SWAG", "SWAM", "SWAN", "SWAT", "SWAY", "SWIM", "SWUM",
"TACK", "TACT", "TAIL", "TAKE", "TALE", "TALK", "TALL", "TANK",
"TASK", "TATE", "TAUT", "TEAL", "TEAM", "TEAR", "TECH", "TEEM",
"TEEN", "TEET", "TELL", "TEND", "TENT", "TERM", "TERN", "TESS",
"TEST", "THAN", "THAT", "THEE", "THEM", "THEN", "THEY", "THIN",
"THIS", "THUD", "THUG", "TICK", "TIDE", "TIDY", "TIED", "TIER",
"TILE", "TILL", "TILT", "TIME", "TINA", "TINE", "TINT", "TINY",
"TIRE", "TOAD", "TOGO", "TOIL", "TOLD", "TOLL", "TONE", "TONG",
"TONY", "TOOK", "TOOL", "TOOT", "TORE", "TORN", "TOTE", "TOUR",
"TOUT", "TOWN", "TRAG", "TRAM", "TRAY", "TREE", "TREK", "TRIG",
"TRIM", "TRIO", "TROD", "TROT", "TROY", "TRUE", "TUBA", "TUBE",
"TUCK", "TUFT", "TUNA", "TUNE", "TUNG", "TURF", "TURN", "TUSK",
"TWIG", "TWIN", "TWIT", "ULAN", "UNIT", "URGE", "USED", "USER",
"USES", "UTAH", "VAIL", "VAIN", "VALE", "VARY", "VASE", "VAST",
"VEAL", "VEDA", "VEIL", "VEIN", "VEND", "VENT", "VERB", "VERY",
"VETO", "VICE", "VIEW", "VINE", "VISE", "VOID", "VOLT", "VOTE",
"WACK", "WADE", "WAGE", "WAIL", "WAIT", "WAKE", "WALE", "WALK",
"WALL", "WALT", "WAND", "WANE", "WANG", "WANT", "WARD", "WARM",
"WARN", "WART", "WASH", "WAST", "WATS", "WATT", "WAVE", "WAVY",
"WAYS", "WEAK", "WEAL", "WEAN", "WEAR", "WEED", "WEEK", "WEIR",
"WELD", "WELL", "WELT", "WENT", "WERE", "WERT", "WEST", "WHAM",
"WHAT", "WHEE", "WHEN", "WHET", "WHOA", "WHOM", "WICK", "WIFE",
"WILD", "WILL", "WIND", "WINE", "WING", "WINK", "WINO", "WIRE",
"WISE", "WISH", "WITH", "WOLF", "WONT", "WOOD", "WOOL", "WORD",
"WORE", "WORK", "WORM", "WORN", "WOVE", "WRIT", "WYNN", "YALE",
"YANG", "YANK", "YARD", "YARN", "YAWL", "YAWN", "YEAH", "YEAR",
"YELL", "YOGA", "YOKE" ]
if __name__=='__main__':
data = [('EB33F77EE73D4053', 'TIDE ITCH SLOW REIN RULE MOT'),
('CCAC2AED591056BE4F90FD441C534766',
'RASH BUSH MILK LOOK BAD BRIM AVID GAFF BAIT ROT POD LOVE'),
('EFF81F9BFBC65350920CDD7416DE8009',
'TROD MUTE TAIL WARM CHAR KONG HAAG CITY BORE O TEAL AWL')
]
for key, words in data:
print('Trying key', key)
key=binascii.a2b_hex(key)
w2=key_to_english(key)
if w2!=words:
print('key_to_english fails on key', repr(key), ', producing', str(w2))
k2=english_to_key(words)
if k2!=key:
print('english_to_key fails on key', repr(key), ', producing', repr(k2))

View File

@@ -0,0 +1,19 @@
Copyright (c) 2015 David Keijser
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,177 @@
'''Base58 encoding
Implementations of Base58 and Base58Check encodings that are compatible
with the XRP Ledger.
'''
# This code is adapted from the module by David Keijser at
# <https://github.com/keis/base58>. - rome@ripple.com
# His notes are preserved below:
# This module is based upon base58 snippets found scattered over many bitcoin
# tools written in python. From what I gather the original source is from a
# forum post by Gavin Andresen, so direct your praise to him.
# This module adds shiny packaging and support for python3.
from hashlib import sha256
__version__ = '1.0.3-xrp'
# 58 character alphabet used
# alphabet = b'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' # Bitcoin
alphabet = b'rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz' # XRP Ledger
if bytes == str: # python2
iseq, bseq, buffer = (
lambda s: map(ord, s),
lambda s: ''.join(map(chr, s)),
lambda s: s,
)
else: # python3
iseq, bseq, buffer = (
lambda s: s,
bytes,
lambda s: s.buffer,
)
def scrub_input(v):
if isinstance(v, str) and not isinstance(v, bytes):
v = v.encode('ascii')
if not isinstance(v, bytes):
raise TypeError(
"a bytes-like object is required (also str), not '%s'" %
type(v).__name__)
return v
def b58encode_int(i, default_one=True):
'''Encode an integer using Base58'''
if not i and default_one:
return alphabet[0:1]
string = b""
while i:
i, idx = divmod(i, 58)
string = alphabet[idx:idx+1] + string
return string
def b58encode(v):
'''Encode a string using Base58'''
v = scrub_input(v)
nPad = len(v)
v = v.lstrip(b'\0')
nPad -= len(v)
p, acc = 1, 0
for c in iseq(reversed(v)):
acc += p * c
p = p << 8
result = b58encode_int(acc, default_one=False)
return (alphabet[0:1] * nPad + result)
def b58decode_int(v):
'''Decode a Base58 encoded string as an integer'''
v = scrub_input(v)
decimal = 0
for char in v:
decimal = decimal * 58 + alphabet.index(char)
return decimal
def b58decode(v):
'''Decode a Base58 encoded string'''
v = scrub_input(v)
origlen = len(v)
v = v.lstrip(alphabet[0:1])
newlen = len(v)
acc = b58decode_int(v)
result = []
while acc > 0:
acc, mod = divmod(acc, 256)
result.append(mod)
return (b'\0' * (origlen - newlen) + bseq(reversed(result)))
def b58encode_check(v):
'''Encode a string using Base58 with a 4 character checksum'''
digest = sha256(sha256(v).digest()).digest()
return b58encode(v + digest[:4])
def b58decode_check(v):
'''Decode and verify the checksum of a Base58 encoded string'''
result = b58decode(v)
result, check = result[:-4], result[-4:]
digest = sha256(sha256(result).digest()).digest()
if check != digest[:4]:
raise ValueError("Invalid checksum")
return result
def main():
'''Base58 encode or decode FILE, or standard input, to standard output.'''
import sys
import argparse
stdout = buffer(sys.stdout)
parser = argparse.ArgumentParser(description=main.__doc__)
parser.add_argument(
'file',
metavar='FILE',
nargs='?',
type=argparse.FileType('r'),
default='-')
parser.add_argument(
'-d', '--decode',
action='store_true',
help='decode data')
parser.add_argument(
'-c', '--check',
action='store_true',
help='append a checksum before encoding')
args = parser.parse_args()
fun = {
(False, False): b58encode,
(False, True): b58encode_check,
(True, False): b58decode,
(True, True): b58decode_check
}[(args.decode, args.check)]
data = buffer(args.file).read()
try:
result = fun(data)
except Exception as e:
sys.exit(e)
if not isinstance(result, bytes):
result = result.encode('ascii')
stdout.write(result)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,114 @@
# Python Implementation from https://ed25519.cr.yp.to/software.html
# Adjusted to Python 3 syntax by rome@ripple.com. The revisions are
# released to the public domain.
# Public domain software. This is a reference implementation that
# does not include recommended speed & security optimizations.
import hashlib
def bchr(i):
return bytes([i])
b = 256
q = 2**255 - 19
l = 2**252 + 27742317777372353535851937790883648493
def H(m):
return hashlib.sha512(m).digest()
def expmod(b,e,m):
if e == 0: return 1
t = expmod(b,e//2,m)**2 % m
if e & 1: t = (t*b) % m
return t
def inv(x):
return expmod(x,q-2,q)
d = -121665 * inv(121666)
I = expmod(2,(q-1)//4,q)
def xrecover(y):
xx = (y*y-1) * inv(d*y*y+1)
x = expmod(xx,(q+3)//8,q)
if (x*x - xx) % q != 0: x = (x*I) % q
if x % 2 != 0: x = q-x
return x
By = 4 * inv(5)
Bx = xrecover(By)
B = [Bx % q,By % q]
def edwards(P,Q):
x1 = P[0]
y1 = P[1]
x2 = Q[0]
y2 = Q[1]
x3 = (x1*y2+x2*y1) * inv(1+d*x1*x2*y1*y2)
y3 = (y1*y2+x1*x2) * inv(1-d*x1*x2*y1*y2)
return [x3 % q,y3 % q]
def scalarmult(P,e):
if e == 0: return [0,1]
Q = scalarmult(P,e//2)
Q = edwards(Q,Q)
if e & 1: Q = edwards(Q,P)
return Q
def encodeint(y):
bits = [(y >> i) & 1 for i in range(b)]
return b''.join([bchr(sum([bits[i * 8 + j] << j for j in range(8)])) for i in range(b//8)])
def encodepoint(P):
x = P[0]
y = P[1]
bits = [(y >> i) & 1 for i in range(b - 1)] + [x & 1]
return b''.join([bchr(sum([bits[i * 8 + j] << j for j in range(8)])) for i in range(b//8)])
def bit(h,i):
return (h[i//8] >> (i%8)) & 1
def publickey(sk):
h = H(sk)
a = 2**(b-2) + sum(2**i * bit(h,i) for i in range(3,b-2))
A = scalarmult(B,a)
return encodepoint(A)
def Hint(m):
h = H(m)
return sum(2**i * bit(h,i) for i in range(2*b))
def signature(m,sk,pk):
h = H(sk)
a = 2**(b-2) + sum(2**i * bit(h,i) for i in range(3,b-2))
r = Hint(bytes([h[i] for i in range(b//8,b//4)]) + m)
R = scalarmult(B,r)
S = (r + Hint(encodepoint(R) + pk + m) * a) % l
return encodepoint(R) + encodeint(S)
def isoncurve(P):
x = P[0]
y = P[1]
return (-x*x + y*y - 1 - d*x*x*y*y) % q == 0
def decodeint(s):
return sum(2**i * bit(s,i) for i in range(0,b))
def decodepoint(s):
y = sum(2**i * bit(s,i) for i in range(0,b-1))
x = xrecover(y)
if x & 1 != bit(s,b-1): x = q-x
P = [x,y]
if not isoncurve(P): raise Exception("decoding point that is not on curve")
return P
def checkvalid(s,m,pk):
if len(s) != b//4: raise Exception("signature length is wrong")
if len(pk) != b//8: raise Exception("public-key length is wrong")
R = decodepoint(s[0:b//8])
A = decodepoint(pk)
S = decodeint(s[b//8:b//4])
h = Hint(encodepoint(R) + pk + m)
if scalarmult(B,S) != edwards(R,scalarmult(A,h)):
raise Exception("signature does not pass verification")

View File

@@ -0,0 +1,325 @@
#!/usr/bin/env python3
################################################################################
# XRPL Key Derivation Code
# Author: rome@ripple.com
# Copyright Ripple 2019
# This sample code is provided as a reference for educational purposes. It is
# not optimized for speed or for security. Use this code at your own risk and
# exercise due caution before using it with real money or infrastructure.
# This file is provided under the MIT license along with the rest of the
# XRP Ledger Dev Portal docs and sample code:
# https://github.com/ripple/xrpl-dev-portal/blob/master/LICENSE
# Some of its dependencies are released under other licenses or are adapted
# from public domain code. See their respective files for details.
################################################################################
import argparse
import sys
from hashlib import sha512
if sys.version_info[0] < 3:
sys.exit("Python 3+ required")
elif sys.version_info.minor < 6:
from random import SystemRandom
randbits = SystemRandom().getrandbits
else:
from secrets import randbits
from fastecdsa import keys, curve
import ed25519
import RFC1751
from base58 import base58
XRPL_SEED_PREFIX = b'\x21'
XRPL_ACCT_PUBKEY_PREFIX = b'\x23'
XRPL_VALIDATOR_PUBKEY_PREFIX = b'\x1c'
ED_PREFIX = b'\xed'
def sha512half(buf):
"""
Return the first 256 bits (32 bytes) of a SHA-512 hash.
"""
return sha512(buf).digest()[:32]
class Seed:
"""
A 16-byte value used for key derivation.
"""
def __init__(self, in_string=None, correct_rfc1751=False):
"""
Decode a buffer input in one of the formats the XRPL supports and convert
it to a buffer representing the 16-byte seed to use for key derivation.
Formats include:
- XRPL base58 encoding
- RFC-1751
- hexadecimal
- passphrase
"""
self.correct_rfc1751 = correct_rfc1751
# Keys are lazy-derived later
self._secp256k1_sec = None
self._secp256k1_pub = None
self._secp256k1_root_pub = None
self._ed25519_sec = None
self._ed25519_pub = None
if in_string is None:
# Generate a new seed randomly from OS-level RNG.
self.bytes = randbits(16*8).to_bytes(16, byteorder="big")
return
# Is it base58?
try:
decoded = base58.b58decode_check(in_string)
if decoded[:1] == XRPL_SEED_PREFIX and len(decoded) == 17:
self.bytes = decoded[1:]
return
else:
raise ValueError
except:
pass
# Maybe it's RFC1751?
try:
decoded = RFC1751.english_to_key(in_string)
if len(decoded) == 16:
if correct_rfc1751:
self.bytes = decoded
else:
self.bytes = swap_byte_order(decoded)
return
else:
raise ValueError
except:
pass
# OK, how about hexadecimal?
try:
decoded = bytes.fromhex(in_string)
if len(decoded) == 16:
self.bytes = decoded
return
else:
raise ValueError
except ValueError as e:
pass
# Fallback: Guess it's a passphrase.
encoded = in_string.encode("UTF-8")
self.bytes = sha512(encoded).digest()[:16]
return
def encode_base58(self):
"""
Returns a string representation of this seed as an XRPL base58 encoded
string such as 'snoPBrXtMeMyMHUVTgbuqAfg1SUTb'.
"""
return base58.b58encode_check(XRPL_SEED_PREFIX + self.bytes).decode()
def encode_hex(self):
"""
Returns a string representation of this seed as hexadecimal.
"""
return self.bytes.hex().upper()
def encode_rfc1751(self, correct_rfc1751=None):
"""
Returns a string representation of this seed as an RFC-1751 encoded
passphrase.
"""
# Use the default byte order swap this Seed was generated with
# unless the method call overrides it.
if correct_rfc1751 is None:
correct_rfc1751=self.correct_rfc1751
if correct_rfc1751:
buf = self.bytes
else:
buf = swap_byte_order(self.bytes)
return RFC1751.key_to_english(buf)
@property
def ed25519_secret_key(self):
"""
Returns a 32-byte Ed25519 secret key (bytes).
Saves the calculation for later calls.
"""
if self._ed25519_sec is None:
self._ed25519_sec = sha512half(self.bytes)
return self._ed25519_sec
@property
def ed25519_public_key(self):
"""
33-byte Ed25519 public key (bytes)—really a 32-byte key
prefixed with the byte 0xED to indicate that it's an Ed25519 key.
"""
if self._ed25519_pub is None:
self._ed25519_pub = (ED_PREFIX +
ed25519.publickey(self.ed25519_secret_key))
return self._ed25519_pub
@property
def secp256k1_secret_key(self):
"""
32-byte secp256k1 secret key (bytes)
"""
if self._secp256k1_sec is None:
self.derive_secp256k1_master_keys()
return self._secp256k1_sec
@property
def secp256k1_public_key(self):
"""
33-byte secp256k1 account public key (bytes)
"""
if self._secp256k1_pub is None:
self.derive_secp256k1_master_keys()
return self._secp256k1_pub
@property
def secp256k1_root_public_key(self):
"""
33-byte secp256k1 root public key (bytes)
This is the public key used for validators.
"""
if self._secp256k1_root_pub is None:
self.derive_secp256k1_master_keys()
return self._secp256k1_root_pub
def derive_secp256k1_master_keys(self):
"""
Uses the XRPL's convoluted key derivation process to get the
secp256k1 master keypair for this seed value.
Saves the values to the object for later reference.
"""
root_sec_i = secp256k1_secret_key_from(self.bytes)
root_pub_point = keys.get_public_key(root_sec_i, curve.secp256k1)
root_pub_b = compress_secp256k1_public(root_pub_point)
fam_b = bytes(4) # Account families are unused; just 4 bytes of zeroes
inter_pk_i = secp256k1_secret_key_from( b''.join([root_pub_b, fam_b]) )
inter_pub_point = keys.get_public_key(inter_pk_i, curve.secp256k1)
# Secret keys are ints, so just add them mod the secp256k1 group order
master_sec_i = (root_sec_i + inter_pk_i) % curve.secp256k1.q
# Public keys are points, so the fastecdsa lib handles adding them
master_pub_point = root_pub_point + inter_pub_point
self._secp256k1_sec = master_sec_i.to_bytes(32, byteorder="big", signed=False)
self._secp256k1_pub = compress_secp256k1_public(master_pub_point)
self._secp256k1_root_pub = root_pub_b
# Saving the full key to make it easier to sign things later
self._secp256k1_full = master_pub_point
def encode_secp256k1_public_base58(self, validator=False):
"""
Return the base58-encoded version of the secp256k1 public key.
"""
if validator:
# Validators use the "root" public key
key = self.secp256k1_root_public_key
prefix = XRPL_VALIDATOR_PUBKEY_PREFIX
else:
# Accounts use the derived "master" public key
key = self.secp256k1_public_key
prefix = XRPL_ACCT_PUBKEY_PREFIX
return base58.b58encode_check(prefix + key).decode()
def encode_ed25519_public_base58(self):
"""
Return the base58-encoded version of the Ed25519 public key.
"""
# Unlike secp256k1, Ed25519 public keys are the same for
# accounts and for validators.
prefix = XRPL_ACCT_PUBKEY_PREFIX
return base58.b58encode_check(prefix +
self.ed25519_public_key).decode()
def secp256k1_secret_key_from(seed):
"""
Calculate a valid secp256k1 secret key by hashing a seed value;
if the result isn't a valid key, increment a seq value and try
again.
Returns a secret key as a 32-byte integer.
"""
seq = 0
while True:
buf = seed + seq.to_bytes(4, byteorder="big", signed=False)
h = sha512half(buf)
h_i = int.from_bytes(h, byteorder="big", signed=False)
if h_i < curve.secp256k1.q and h_i != 0:
return h_i
# Else, not a valid secp256k1 key; try again with a new sequence value.
seq += 1
def compress_secp256k1_public(point):
"""
Returns a 33-byte compressed key from an secp256k1 public key,
which is a point in the form (x,y) where both x and y are 32-byte ints
"""
if point.y % 2:
prefix = b'\x03'
else:
prefix = b'\x02'
return prefix + point.x.to_bytes(32, byteorder="big", signed=False)
def swap_byte_order(buf):
"""
Swap the byte order of a bytes object.
The rippled implementation of RFC-1751 uses the reversed byte order as the
examples included in the RFC-1751 spec (which doesn't mention byte order).
"""
size = len(buf)
# doesn't actually matter if it's "really" big-endian
i = int.from_bytes(buf, byteorder="big", signed=False)
revbuf = i.to_bytes(size, byteorder="little", signed=False)
return revbuf
if __name__ == "__main__":
p = argparse.ArgumentParser()
p.add_argument("secret", nargs="?", default=None, help="The seed to "+
"derive a key from, in hex, XRPL base58, or RFC-1751; or the " + "passphrase to derive a seed and key from. If omitted, generate a "+
"random seed.")
p.add_argument("--unswap", "-u", default=False, action="store_true",
help="If specified, preserve the byte order of RFC-1751 encoding"+
"/decoding. Not compatible with rippled's RFC-1751 implementation.")
args = p.parse_args()
seed = Seed(args.secret, correct_rfc1751=args.unswap)
seed.derive_secp256k1_master_keys()
print("""
Seed (base58): {base58}
Seed (hex): {hex}
Seed (true RFC-1751): {rfc1751_true}
Seed (rippled RFC-1751): {rfc1751_rippled}
Ed25519 Secret Key (hex): {ed25519_secret}
Ed25519 Public Key (hex): {ed25519_public}
Ed25519 Public Key (base58 - Account): {ed25519_pub_base58}
secp256k1 Secret Key (hex): {secp256k1_secret}
secp256k1 Public Key (hex): {secp256k1_public}
secp256k1 Public Key (base58 - Account): {secp256k1_pub_base58}
secp256k1 Public Key (base58 - Validator): {secp256k1_pub_base58_val}
""".format(
base58=seed.encode_base58(),
hex=seed.encode_hex(),
rfc1751_true=seed.encode_rfc1751(correct_rfc1751=True),
rfc1751_rippled=seed.encode_rfc1751(correct_rfc1751=False),
ed25519_secret=seed.ed25519_secret_key.hex().upper(),
ed25519_public=seed.ed25519_public_key.hex().upper(),
secp256k1_secret=seed.secp256k1_secret_key.hex().upper(),
secp256k1_public=seed.secp256k1_public_key.hex().upper(),
secp256k1_pub_base58=seed.encode_secp256k1_public_base58(),
secp256k1_pub_base58_val=seed.encode_secp256k1_public_base58(
validator=True),
ed25519_pub_base58=seed.encode_ed25519_public_base58(),
))

View File

@@ -0,0 +1 @@
fastecdsa==1.7.4

View File

@@ -1,10 +1,10 @@
'''Base58 encoding
Implementations of Base58 and Base58Check endcodings that are compatible
Implementations of Base58 and Base58Check encodings that are compatible
with the XRP Ledger.
'''
# This This code is adapted from the module by David Keijser at
# This code is adapted from the module by David Keijser at
# <https://github.com/keis/base58>. - rome@ripple.com
# His notes are preserved below:

View File

@@ -4,75 +4,22 @@
<element>
<id>UMLObject</id>
<coordinates>
<x>60</x>
<y>60</y>
<w>150</w>
<h>70</h>
</coordinates>
<panel_attributes>Passphrase
--
(Optional)
Any string
lt=.</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLObject</id>
<coordinates>
<x>350</x>
<y>60</y>
<w>180</w>
<h>70</h>
</coordinates>
<panel_attributes>Secret Key
--
</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>200</x>
<y>80</y>
<w>170</w>
<h>40</h>
</coordinates>
<panel_attributes>lt=&lt;.
SHA-512Half</panel_attributes>
<additional_attributes>150.0;20.0;10.0;20.0</additional_attributes>
</element>
<element>
<id>UMLObject</id>
<coordinates>
<x>650</x>
<y>60</y>
<x>40</x>
<y>70</y>
<w>220</w>
<h>70</h>
</coordinates>
<panel_attributes>Public Key
<panel_attributes>Master Public Key
--
33 bytes (secp256k1)
0xED + 32 bytes (Ed25519)</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>520</x>
<y>80</y>
<w>150</w>
<h>50</h>
</coordinates>
<panel_attributes>lt=&lt;-
Public Key
Derivation</panel_attributes>
<additional_attributes>130.0;20.0;10.0;20.0</additional_attributes>
</element>
<element>
<id>UMLObject</id>
<coordinates>
<x>360</x>
<y>190</y>
<x>340</x>
<y>160</y>
<w>180</w>
<h>80</h>
</coordinates>
@@ -84,25 +31,28 @@ Derivation</panel_attributes>
<element>
<id>Relation</id>
<coordinates>
<x>300</x>
<y>120</y>
<w>440</w>
<h>130</h>
<x>250</x>
<y>70</y>
<w>220</w>
<h>160</h>
</coordinates>
<panel_attributes>lt=&lt;-
SHA-256 of RIPEMD160
RIPEMD160 of SHA-256
</panel_attributes>
<additional_attributes>60.0;90.0;10.0;90.0;10.0;40.0;420.0;40.0;420.0;10.0</additional_attributes>
<additional_attributes>90.0;110.0;40.0;110.0;40.0;40.0;10.0;40.0</additional_attributes>
</element>
<element>
<id>UMLObject</id>
<coordinates>
<x>690</x>
<y>190</y>
<x>670</x>
<y>160</y>
<w>180</w>
<h>80</h>
</coordinates>
@@ -115,22 +65,22 @@ Checksum (4 bytes)</panel_attributes>
<element>
<id>UMLObject</id>
<coordinates>
<x>60</x>
<y>190</y>
<x>40</x>
<y>160</y>
<w>190</w>
<h>80</h>
</coordinates>
<panel_attributes>Type Prefix
--
0x00
("r" in Ripple's base58)</panel_attributes>
("r" in XRPL base58)</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>240</x>
<y>230</y>
<x>220</x>
<y>200</y>
<w>140</w>
<h>30</h>
</coordinates>
@@ -140,8 +90,8 @@ Checksum (4 bytes)</panel_attributes>
<element>
<id>UMLObject</id>
<coordinates>
<x>400</x>
<y>320</y>
<x>380</x>
<y>290</y>
<w>100</w>
<h>70</h>
</coordinates>
@@ -153,8 +103,8 @@ Checksum (4 bytes)</panel_attributes>
<element>
<id>Relation</id>
<coordinates>
<x>490</x>
<y>230</y>
<x>470</x>
<y>200</y>
<w>120</w>
<h>140</h>
</coordinates>
@@ -164,8 +114,8 @@ Checksum (4 bytes)</panel_attributes>
<element>
<id>Relation</id>
<coordinates>
<x>530</x>
<y>210</y>
<x>510</x>
<y>180</y>
<w>80</w>
<h>30</h>
</coordinates>
@@ -175,8 +125,8 @@ Checksum (4 bytes)</panel_attributes>
<element>
<id>UMLState</id>
<coordinates>
<x>590</x>
<y>210</y>
<x>570</x>
<y>180</y>
<w>100</w>
<h>40</h>
</coordinates>
@@ -187,8 +137,8 @@ type=sender</panel_attributes>
<element>
<id>Relation</id>
<coordinates>
<x>420</x>
<y>260</y>
<x>400</x>
<y>230</y>
<w>130</w>
<h>80</h>
</coordinates>
@@ -196,4 +146,16 @@ type=sender</panel_attributes>
SHA-256 twice</panel_attributes>
<additional_attributes>10.0;60.0;10.0;10.0</additional_attributes>
</element>
<element>
<id>Text</id>
<coordinates>
<x>40</x>
<y>30</y>
<w>280</w>
<h>30</h>
</coordinates>
<panel_attributes>*Address Encoding*
style=wordwrap</panel_attributes>
<additional_attributes/>
</element>
</diagram>

View File

@@ -0,0 +1,136 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<diagram program="umlet" version="14.2">
<zoom_level>10</zoom_level>
<element>
<id>UMLObject</id>
<coordinates>
<x>20</x>
<y>60</y>
<w>120</w>
<h>70</h>
</coordinates>
<panel_attributes>Passphrase
--
(Optional)
Any string
lt=.</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>130</x>
<y>80</y>
<w>170</w>
<h>50</h>
</coordinates>
<panel_attributes>lt=.&gt;
SHA-512, keep
first 16 bytes</panel_attributes>
<additional_attributes>10.0;20.0;150.0;20.0</additional_attributes>
</element>
<element>
<id>UMLObject</id>
<coordinates>
<x>280</x>
<y>60</y>
<w>120</w>
<h>70</h>
</coordinates>
<panel_attributes>Seed
--
(16 bytes)</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLObject</id>
<coordinates>
<x>170</x>
<y>200</y>
<w>230</w>
<h>70</h>
</coordinates>
<panel_attributes>Private Key
--
(32 bytes)</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>290</x>
<y>120</y>
<w>120</w>
<h>100</h>
</coordinates>
<panel_attributes>lt=&lt;-
SHA-512Half</panel_attributes>
<additional_attributes>10.0;80.0;10.0;10.0</additional_attributes>
</element>
<element>
<id>UMLObject</id>
<coordinates>
<x>170</x>
<y>330</y>
<w>230</w>
<h>70</h>
</coordinates>
<panel_attributes>Public Key
--
(32 bytes)</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLObject</id>
<coordinates>
<x>110</x>
<y>330</y>
<w>60</w>
<h>70</h>
</coordinates>
<panel_attributes>0xED
Prefix
--
(1 byte)
</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>230</x>
<y>260</y>
<w>180</w>
<h>90</h>
</coordinates>
<panel_attributes>lt=-&gt;
Public Key Derivation</panel_attributes>
<additional_attributes>10.0;10.0;10.0;70.0</additional_attributes>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>100</x>
<y>400</y>
<w>320</w>
<h>70</h>
</coordinates>
<panel_attributes>lt=..
Master Public Key
(33 bytes)</panel_attributes>
<additional_attributes>10.0;10.0;10.0;30.0;300.0;30.0;300.0;10.0</additional_attributes>
</element>
<element>
<id>Text</id>
<coordinates>
<x>20</x>
<y>20</y>
<w>280</w>
<h>30</h>
</coordinates>
<panel_attributes>*Ed25519 Key Derivation*
style=wordwrap</panel_attributes>
<additional_attributes/>
</element>
</diagram>

View File

@@ -0,0 +1,517 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<diagram program="umlet" version="14.2">
<zoom_level>10</zoom_level>
<element>
<id>UMLObject</id>
<coordinates>
<x>50</x>
<y>70</y>
<w>140</w>
<h>70</h>
</coordinates>
<panel_attributes>Passphrase
--
(Optional)
Any string
lt=.</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>180</x>
<y>90</y>
<w>180</w>
<h>50</h>
</coordinates>
<panel_attributes>lt=.&gt;
SHA-512, keep
first 16 bytes</panel_attributes>
<additional_attributes>10.0;20.0;160.0;20.0</additional_attributes>
</element>
<element>
<id>UMLObject</id>
<coordinates>
<x>340</x>
<y>70</y>
<w>140</w>
<h>70</h>
</coordinates>
<panel_attributes>Seed
--
(16 bytes)</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLObject</id>
<coordinates>
<x>50</x>
<y>280</y>
<w>150</w>
<h>70</h>
</coordinates>
<panel_attributes>Root Private Key
--
(32 bytes)</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>110</x>
<y>130</y>
<w>460</w>
<h>170</h>
</coordinates>
<panel_attributes>lt=&lt;-
SHA-512Half</panel_attributes>
<additional_attributes>10.0;150.0;10.0;110.0;440.0;110.0;440.0;10.0;400.0;10.0</additional_attributes>
</element>
<element>
<id>UMLObject</id>
<coordinates>
<x>330</x>
<y>280</y>
<w>150</w>
<h>70</h>
</coordinates>
<panel_attributes>Root Public Key
--
(33 bytes
compressed)</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>190</x>
<y>300</y>
<w>160</w>
<h>50</h>
</coordinates>
<panel_attributes>lt=-&gt;
Public Key
Derivation</panel_attributes>
<additional_attributes>10.0;20.0;140.0;20.0</additional_attributes>
</element>
<element>
<id>Text</id>
<coordinates>
<x>50</x>
<y>30</y>
<w>280</w>
<h>30</h>
</coordinates>
<panel_attributes>*secp256k1 Key Derivation*
style=wordwrap</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLSyncBarVertical</id>
<coordinates>
<x>500</x>
<y>110</y>
<w>20</w>
<h>70</h>
</coordinates>
<panel_attributes>template=txt
title=titletext
bg=red</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLObject</id>
<coordinates>
<x>370</x>
<y>150</y>
<w>110</w>
<h>70</h>
</coordinates>
<panel_attributes>Root Key
Sequence
--
(4 bytes;
default 0)</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>470</x>
<y>120</y>
<w>60</w>
<h>30</h>
</coordinates>
<panel_attributes>lt=-&gt;</panel_attributes>
<additional_attributes>10.0;10.0;40.0;10.0</additional_attributes>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>470</x>
<y>150</y>
<w>60</w>
<h>30</h>
</coordinates>
<panel_attributes>lt=-&gt;</panel_attributes>
<additional_attributes>10.0;10.0;40.0;10.0</additional_attributes>
</element>
<element>
<id>UMLObject</id>
<coordinates>
<x>370</x>
<y>440</y>
<w>110</w>
<h>70</h>
</coordinates>
<panel_attributes>Int Key
Sequence
--
(4 bytes;
default 0)</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLObject</id>
<coordinates>
<x>370</x>
<y>360</y>
<w>110</w>
<h>70</h>
</coordinates>
<panel_attributes>Family
Number
--
(4 bytes;
all 0's)</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLNote</id>
<coordinates>
<x>140</x>
<y>170</y>
<w>210</w>
<h>50</h>
</coordinates>
<panel_attributes>Increment the key sequence and try again if the SHA-512Half doesn't make a valid private key.
bg=yellow
fontsize=10
style=wordwrap</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLNote</id>
<coordinates>
<x>150</x>
<y>460</y>
<w>210</w>
<h>50</h>
</coordinates>
<panel_attributes>Increment the key sequence and try again if the SHA-512Half doesn't make a valid private key.
bg=yellow
fontsize=10
style=wordwrap</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>140</x>
<y>380</y>
<w>410</w>
<h>220</h>
</coordinates>
<panel_attributes>lt=&lt;-
SHA-512Half</panel_attributes>
<additional_attributes>10.0;200.0;10.0;160.0;390.0;160.0;390.0;10.0;370.0;10.0</additional_attributes>
</element>
<element>
<id>UMLSyncBarVertical</id>
<coordinates>
<x>500</x>
<y>360</y>
<w>20</w>
<h>80</h>
</coordinates>
<panel_attributes>template=txt
title=titletext
bg=red</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>470</x>
<y>320</y>
<w>60</w>
<h>80</h>
</coordinates>
<panel_attributes>lt=-&gt;</panel_attributes>
<additional_attributes>10.0;10.0;20.0;10.0;20.0;60.0;40.0;60.0</additional_attributes>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>470</x>
<y>390</y>
<w>60</w>
<h>30</h>
</coordinates>
<panel_attributes>lt=-&gt;</panel_attributes>
<additional_attributes>10.0;10.0;40.0;10.0</additional_attributes>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>470</x>
<y>410</y>
<w>60</w>
<h>70</h>
</coordinates>
<panel_attributes>lt=-&gt;</panel_attributes>
<additional_attributes>10.0;50.0;20.0;50.0;20.0;10.0;40.0;10.0</additional_attributes>
</element>
<element>
<id>UMLObject</id>
<coordinates>
<x>80</x>
<y>580</y>
<w>150</w>
<h>80</h>
</coordinates>
<panel_attributes>Intermediate
Private Key
--
(32 bytes)
</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLObject</id>
<coordinates>
<x>330</x>
<y>580</y>
<w>150</w>
<h>80</h>
</coordinates>
<panel_attributes>Intermediate
Public Key
--
(33 bytes
compressed)</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>220</x>
<y>610</y>
<w>130</w>
<h>50</h>
</coordinates>
<panel_attributes>lt=-&gt;
Public Key
Derivation</panel_attributes>
<additional_attributes>10.0;20.0;110.0;20.0</additional_attributes>
</element>
<element>
<id>UMLState</id>
<coordinates>
<x>660</x>
<y>330</y>
<w>140</w>
<h>40</h>
</coordinates>
<panel_attributes>Elliptic Curve
Point Add
type=sender</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>470</x>
<y>290</y>
<w>210</w>
<h>70</h>
</coordinates>
<panel_attributes>lt=&lt;-</panel_attributes>
<additional_attributes>190.0;50.0;150.0;50.0;150.0;10.0;10.0;10.0</additional_attributes>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>470</x>
<y>350</y>
<w>210</w>
<h>280</h>
</coordinates>
<panel_attributes>lt=&lt;-</panel_attributes>
<additional_attributes>190.0;10.0;150.0;10.0;150.0;260.0;10.0;260.0</additional_attributes>
</element>
<element>
<id>UMLObject</id>
<coordinates>
<x>800</x>
<y>320</y>
<w>150</w>
<h>70</h>
</coordinates>
<panel_attributes>Master Public Key
--
(33 bytes
compressed)</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLState</id>
<coordinates>
<x>150</x>
<y>700</y>
<w>160</w>
<h>40</h>
</coordinates>
<panel_attributes>Add, Modulo
Group Order
type=sender</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>100</x>
<y>650</y>
<w>70</w>
<h>80</h>
</coordinates>
<panel_attributes>lt=&lt;-</panel_attributes>
<additional_attributes>50.0;60.0;10.0;60.0;10.0;10.0</additional_attributes>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>50</x>
<y>340</y>
<w>120</w>
<h>410</h>
</coordinates>
<panel_attributes>lt=&lt;-</panel_attributes>
<additional_attributes>100.0;390.0;10.0;390.0;10.0;10.0</additional_attributes>
</element>
<element>
<id>UMLObject</id>
<coordinates>
<x>330</x>
<y>690</y>
<w>150</w>
<h>70</h>
</coordinates>
<panel_attributes>Master Private Key
--
(32 bytes)</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>300</x>
<y>710</y>
<w>50</w>
<h>30</h>
</coordinates>
<panel_attributes>lt=&lt;-</panel_attributes>
<additional_attributes>30.0;10.0;10.0;10.0</additional_attributes>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>470</x>
<y>380</y>
<w>410</w>
<h>380</h>
</coordinates>
<panel_attributes>lt=.&gt;
(Public key derivation
yields the same result.)</panel_attributes>
<additional_attributes>10.0;350.0;390.0;350.0;390.0;10.0</additional_attributes>
</element>
<element>
<id>UMLNote</id>
<coordinates>
<x>590</x>
<y>230</y>
<w>210</w>
<h>50</h>
</coordinates>
<panel_attributes>Validators use the root key pair.
bg=green
style=wordwrap</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>200</x>
<y>240</y>
<w>410</w>
<h>60</h>
</coordinates>
<panel_attributes>lt=&lt;..
fg=#25A768
transparency=0</panel_attributes>
<additional_attributes>10.0;40.0;390.0;10.0</additional_attributes>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>480</x>
<y>260</y>
<w>130</w>
<h>50</h>
</coordinates>
<panel_attributes>lt=&lt;..
fg=#25A768
transparency=0</panel_attributes>
<additional_attributes>10.0;30.0;110.0;10.0</additional_attributes>
</element>
<element>
<id>UMLNote</id>
<coordinates>
<x>630</x>
<y>630</y>
<w>210</w>
<h>50</h>
</coordinates>
<panel_attributes>Accounts use the master key pair.
bg=green
style=wordwrap</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>760</x>
<y>380</y>
<w>80</w>
<h>270</h>
</coordinates>
<panel_attributes>lt=&lt;..
fg=#25A768
transparency=0</panel_attributes>
<additional_attributes>60.0;10.0;10.0;250.0</additional_attributes>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>470</x>
<y>660</y>
<w>180</w>
<h>70</h>
</coordinates>
<panel_attributes>lt=&lt;..
fg=#25A768
transparency=0</panel_attributes>
<additional_attributes>10.0;50.0;160.0;10.0</additional_attributes>
</element>
</diagram>

View File

@@ -33,11 +33,11 @@ To be "canonical", signatures created with the ECDSA algorithm and secp256k1 cur
- The signature must be properly [DER-encoded data](https://en.wikipedia.org/wiki/X.690#DER_encoding).
- The signature must not have any padding bytes outside the DER-encoded data.
- The signature's component integers must not be negative, and they must not be larger than the secp256k1 modulus.
- The signature's component integers must not be negative, and they must not be larger than the secp256k1 group order.
Generally speaking, any standard ECDSA implementation handles these requirements automatically. However, with secp256k1, those requirements are insufficient to prevent malleability. Thus, the XRP Ledger has a concept of "fully canonical" signatures which do not have the same problem.
An ECDSA signature consists of two integers, called R and S. The secp256k1 modulus, called N, is a constant value for all secp256k1 signatures. Specifically, N is the value `0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141`. For any given signature `(R,S)`, the signature `(R, N-S)` (that is, using N minus S in place of S) is also valid.
An ECDSA signature consists of two integers, called R and S. The secp256k1 _group order_, called N, is a constant value for all secp256k1 signatures. Specifically, N is the value `0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141`. For any given signature `(R,S)`, the signature `(R, N-S)` (that is, using N minus S in place of S) is also valid.
Thus, to have _fully_ canonical signatures, one must choose which of the two possibilities is preferred and declare the other to be invalid. The creators of the XRP Ledger decided arbitrarily to prefer the _smaller_ of the two possible values, `S` or `N-S`. A transaction is considered _fully canonical_ if it uses the preferred (smaller) value of `S`, and follows all the normal rules for being canonical.

View File

@@ -92,13 +92,13 @@ For more information on each of these objects, see the [Ledger Format Reference]
[[Source]<br>](https://github.com/ripple/rippled/blob/35fa20a110e3d43ffc1e9e664fc9017b6f2747ae/src/ripple/protocol/impl/AccountID.cpp#L109-L140 "Source")
XRP Ledger addresses are encoded using [base58](https://en.wikipedia.org/wiki/Base58) with the Ripple _dictionary_: `rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz`. Since the XRP Ledger encodes several types of keys with base58, it prefixes the encoded data with a one-byte "type prefix" (also called a "version prefix") to distinguish them. The type prefix causes addresses to usually start with different letters in base58 format.
XRP Ledger addresses are encoded using [base58](https://en.wikipedia.org/wiki/Base58) with the _dictionary_ `rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz`. Since the XRP Ledger encodes several types of keys with base58, it prefixes the encoded data with a one-byte "type prefix" (also called a "version prefix") to distinguish them. The type prefix causes addresses to usually start with different letters in base58 format.
The following diagram shows the relationship between keys and addresses:
![Passphrase → Secret Key → Public Key + Type Prefix → Account ID + Checksum → Address](img/key-address-rels.png)
[![Master Public Key + Type Prefix → Account ID + Checksum → Address](img/address-encoding.png)](img/address-encoding.png)
The formula for calculating an XRP Ledger address is as follows. For the complete example code, see [`encode_address.js`](https://github.com/ripple/ripple-dev-portal/blob/master/content/_code-samples/address_encoding/encode_address.js).
The formula for calculating an XRP Ledger address from a public key is as follows. For the complete example code, see [`encode_address.js`](https://github.com/ripple/ripple-dev-portal/blob/master/content/_code-samples/address_encoding/encode_address.js). For the process of deriving a public key from a passphrase or seed value, see [Key Derivation](cryptographic-keys.html#key-derivation).
1. Import required algorithms: SHA-256, RIPEMD160, and base58. Set the dictionary for base58.

View File

@@ -1,10 +1,10 @@
# Cryptographic Keys
In the XRP Ledger, a digital signature proves that a transaction is authorized to do a specific set of actions. Only signed transactions can be submitted to the network and included in a validated ledger. <!-- STYLE_OVERRIDE: is authorized to -->
In the XRP Ledger, a digital signature proves that a [transaction](transaction-basics.html) is authorized to do a specific set of actions. Only signed transactions can be submitted to the network and included in a validated ledger. <!-- STYLE_OVERRIDE: is authorized to -->
Every digital signature is based on a cryptographic key pair associated with the transaction's sending account. A key pair may be generated using any of the XRP Ledger's supported [cryptographic signing algorithms](#signing-algorithms). A key pair can be used as [master key pair](#master-key-pair), [regular key pair](#regular-key-pair) or a member of a [signer list](multi-signing.html), regardless of what algorithm was used to generate it.
**Warning:** It is important to maintain proper security over your private keys. Digital signatures are the only way of verifying to the XRP Ledger that you are authorized to send a transaction, and there is no privileged administrator who can undo or reverse any transaction that has been applied to the ledger. If someone else knows the private key of your XRP Ledger account, that person can create digital signatures to authorize any transaction the same as you could.
**Warning:** It is important to maintain proper security over your secret keys. Digital signatures are the only way of verifying to the XRP Ledger that you are authorized to send a transaction, and there is no privileged administrator who can undo or reverse any transaction that has been applied to the ledger. If someone else knows the secret key of your XRP Ledger account, that person can create digital signatures to authorize any transaction the same as you could.
## Generating Keys
@@ -26,15 +26,21 @@ You generate a key pair using the [`wallet_propose`](wallet_propose.html) method
}
```
The response contains a key pair (a private key and a public key, in various formats) as well as an `account_id`.
The response contains a key pair (a seed and a public key, in various formats) as well as an `account_id`.
**Private Key**
**Seed**
The `master_key`, `master_seed`, and `master_seed_hex` are the private key in various formats, all of which can be used to sign transactions. Despite being prefixed with `master_`, these keys are not necessarily the master keys for an account. In this context, the `master_` prefix refers more to the keys' role as private keys. The `master_seed` is the master seed from which all other information about this account is derived.
A _seed_ value is a compact value that is used to [derive](#key-derivation) the actual secret key (and public key) for an account. The `master_key`, `master_seed`, and `master_seed_hex` all represent the same seed value, in various formats. Any of these formats can be used to [sign transactions](transaction-basics.html#signing-and-submitting-transactions) in the [`rippled` APIs](rippled-api.html) and some [other XRPL software](software-ecosystem.html). Despite being prefixed with `master_`, the keys this seed represents are not necessarily the master keys for an account; you can use a key pair as a regular key or a member of a multi-signing list as well.
Because the seed value is the basis for all the other information of an account, you must protect it very carefully. Anyone who has knows an address's seed value effectively has full control over that address.
**Secret Key**
The `wallet_propose` response does not explicitly list the secret key value, also called a _private key_. Software that can sign transactions is expected to [derive the secret key](#key-derivation) from the seed value.
**Public Key**
The `public_key` and `public_key_hex` are the public key in various formats, with the `public_key_hex` being the public key corresponding to the private key that signed the transaction. Both the `public_key` and `public_key_hex` are directly derived from the `master_seed`.
The `public_key` and `public_key_hex` both represent the same public key value. The public key is derived from the secret key as part of key derivation. The public key makes it possible to verify the authenticity of a transaction signature, but not to create more signatures.
**account_id**
@@ -55,7 +61,7 @@ The field `key_type` indicates what [cryptographic signing algorithm](#signing-a
## Master Key Pair
The master key pair is composed of a private key and a public key. In addition to being able to sign all transactions that a regular key pair can, the master key pair's private key is the only key that can be used to perform the following actions:
The master key pair is composed of a secret key and a public key. In addition to being able to sign all transactions that a regular key pair can, the master key pair's secret key is the only key that can be used to perform the following actions:
* [Disable the master public key](accountset.html).
@@ -63,20 +69,20 @@ The master key pair is composed of a private key and a public key. In addition t
* Send a cost-0 [key reset transaction](transaction-cost.html#key-reset-transaction).
The master key pair for an account is generated in the same [`wallet_propose`](wallet_propose.html) response as the `account_id` of the account the master key pair is authorized to sign transactions for. Because the master key pair is generated in the same response, it is [intrinsically related](accounts.html#address-encoding) to the `account_id`, which is derived from the `public_key_hex`.
The master key pair for an account is generated in the same [`wallet_propose`](wallet_propose.html) response as the `account_id` of the account the master key pair is authorized to sign transactions for. Because the master key pair is generated in the same response, it is [intrinsically related](accounts.html#address-encoding) to the address, which is derived from the public key.
This is as opposed to a regular key pair, which is also generated using the `wallet_propose` method, but which must be explicitly assigned as a regular key pair to an account. Because a regular key pair is explicitly assigned, it is not intrinsically related to the `account_id` of the account it is authorized to sign transactions for. For more information, see [Regular Key Pair](#regular-key-pair).
This is as opposed to a regular key pair, which is also generated using the `wallet_propose` method, but which must be explicitly assigned as a regular key pair to an account. Because a regular key pair is explicitly assigned, it is not intrinsically related to the address of the account it is authorized to sign transactions for. For more information, see [Regular Key Pair](#regular-key-pair).
**Caution:** A master key pair cannot be changed, but it can be disabled. This means that if your master private key is compromised, rather than change it, you must [disable it](accountset.html).
**Caution:** A master key pair cannot be changed, but it can be disabled. This means that if your master seed or secret key is compromised, rather than change it, you must [disable it](accountset.html).
Because a master key pair cannot be changed and can only disabled in the event of a compromise, this is a compelling reason to keep your master key pair offline and set up a regular key pair to sign transactions from your account instead.
Keeping your master key pair offline means not putting your master private key somewhere malicious actors can get access to it. For example, this can mean keeping it on an air-gapped machine that never connects to the internet, on a piece of paper stored in a safe, or in general, not within reach of a computer program that interacts with the internet at large. Ideally, a master key pair is used only on the most trusted of devices and for emergencies only, such as to change a regular key pair in the event of a possible or actual compromise.
Keeping your master key pair offline means not putting your master secret key anywhere that malicious actors can get access to it. For example, this can mean keeping it on an air-gapped machine that never connects to the internet, on a piece of paper stored in a safe, or in general, not within reach of a computer program that interacts with the internet at large. Ideally, a master key pair is used only on the most trusted of devices and for emergencies only, such as to change a regular key pair in the event of a possible or actual compromise.
## Regular Key Pair
The XRP Ledger allows an account to authorize a secondary key pair, called a _regular key pair_, to sign future transactions, while keeping your master key pair offline. If the private key of a regular key pair is compromised, you can remove or replace it without changing the rest of your account and re-establishing its relationships to other accounts. You can also rotate a regular key pair proactively. (Neither of those things is possible for the master key pair of an account, which is intrinsically linked to the account's address.)
The XRP Ledger allows an account to authorize a secondary key pair, called a _regular key pair_, to sign future transactions, while keeping your master key pair offline. If the seed or secret key of a regular key pair is compromised, you can remove or replace the key pair without changing the rest of your account. This saves the trouble of re-establishing the account's settings and relationships to other accounts. You can also rotate a regular key pair proactively. (Neither of those things is possible for the master key pair of an account, which is intrinsically linked to the account's address.)
You generate a key pair to use as a regular key pair using the [`wallet_propose`](wallet_propose.html) method. However, unlike with a [master key pair](#master-key-pair), which is generated alongside and intrinsically related to the `account_id` of an account it supports, you must explicitly create the relationship between a regular key pair and the account you want it to sign transactions for. You use the [`SetRegularKey`](setregularkey.html) method to assign a regular key pair to an account.
@@ -84,19 +90,19 @@ For a tutorial on assigning a regular key pair, see [Assign a Regular Key Pair](
After you assign a regular key pair to an account, the account has two key pairs associated with it:
* A master key pair that is intrinsically related to the account's `account_id` and which you keep offline.
* A master key pair that is intrinsically related to the account's `account_id` and which you should keep offline.
* A regular key pair that you've explicitly assigned to the account and which you use to sign transactions for the account.
You can assign one regular key pair to an account and use it to sign all transactions, except for the ones reserved for the [master key pair](#master-key-pair).
You can remove or change a regular key pair at any time. This means that if a regular private key is compromised (but the master private key is not), you can regain control of your account by simply removing or changing the regular key pair.
You can remove or change a regular key pair at any time. This means that if a regular secret key is compromised (but the master secret key is not), you can regain control of your account by simply removing or changing the regular key pair.
For a tutorial on changing or removing a regular key pair, see [Assign a Regular Key Pair](assign-a-regular-key-pair.html).
## Signing Algorithms
Cryptographic key pairs are always tied to a specific signing algorithm, which defines the mathematical relationships between the private key and the public key. Cryptographic signing algorithms have the property that, given the current state of cryptographic techniques, it is "easy" to use a private key to calculate a matching public key, but it is effectively impossible to compute a matching private key by starting from a public key.
Cryptographic key pairs are always tied to a specific signing algorithm, which defines the mathematical relationships between the secret key and the public key. Cryptographic signing algorithms have the property that, given the current state of cryptographic techniques, it is "easy" to use a secret key to calculate a matching public key, but it is effectively impossible to compute a matching secret key by starting from a public key.
The XRP Ledger supports the following cryptographic signing algorithms:
@@ -116,6 +122,104 @@ The supported types of key pairs can be used interchangeably throughout the XRP
In the future, it is likely that the XRP Ledger will need new cryptographic signing algorithms to keep up with developments in cryptography. For example, if quantum computers using [Shor's algorithm](https://en.wikipedia.org/wiki/Shor's_algorithm) (or something similar) will soon be practical enough to break elliptic curve cryptography, XRP Ledger developers can add a cryptographic signing algorithm that isn't easily broken. As of mid 2019, there's no clear first choice "quantum-resistant" signing algorithm and quantum computers are not yet practical enough to be a threat, so there are no immediate plans to add any specific algorithms. <!-- STYLE_OVERRIDE: will -->
## Key Derivation
The process of deriving a key pair depends on the signing algorithm. In all cases, keys are generated from a _seed_ value that is 16 bytes (128 bits) in length. The seed value can be completely random (recommended) or it can be derived from a specific passphrase by taking the [SHA-512 hash][Hash] and keeping the first 16 bytes (similar to [SHA-512Half][], but keeping only 128 bits instead of 256 bits of the output).
### Sample Code
The key derivation processes described here are implemented in multiple places and programming languages:
- In C++ in the `rippled` code base:
- [Seed definition](https://github.com/ripple/rippled/blob/develop/src/ripple/protocol/Seed.h)
- [General & Ed25519 key derivation](https://github.com/ripple/rippled/blob/develop/src/ripple/protocol/impl/SecretKey.cpp)
- [secp256k1 key derivation](https://github.com/ripple/rippled/blob/develop/src/ripple/crypto/impl/GenerateDeterministicKey.cpp)
- In Python 3 in [this repository's code samples section]({{target.github_forkurl}}/blob/{{target.github_branch}}/content/_code-samples/key-derivation/key_derivation.py).
- In JavaScript in the [`ripple-keypairs`](https://github.com/ripple/ripple-keypairs/) package.
### Ed25519 Key Derivation
[[Source]](https://github.com/ripple/rippled/blob/fc7ecd672a3b9748bfea52ce65996e324553c05f/src/ripple/protocol/impl/SecretKey.cpp#L203 "Source")
[![Passphrase → Seed → Secret Key → Prefix + Public Key](img/key-derivation-ed25519.png)](img/key-derivation-ed25519.png)
1. Calculate the [SHA-512Half][] of the seed value. The result is the 32-byte secret key.
**Tip:** All 32-byte numbers are valid Ed25519 secret keys. However, only numbers that are chosen randomly enough are secure enough to be used as secret keys.
2. To calculate an Ed25519 public key, use the standard public key derivation for [Ed25519](https://ed25519.cr.yp.to/software.html) to derive the 32-byte public key.
**Caution:** As always with cryptographic algorithms, use a standard, well-known, publicly-audited implementation whenever possible. For example, [OpenSSL](https://www.openssl.org/) has implementations of core Ed25519 and secp256k1 functions.
3. Prefix the 32-byte public key with the single byte `0xED` to indicate an Ed25519 public key, resulting in 33 bytes.
If you are implementing code to sign transactions, remove the `0xED` prefix and use the 32-byte key for the actual signing process.
4. When serializing an account public key to [base58][], use the account public key prefix `0x23`.
Validator ephemeral keys cannot be Ed25519.
### secp256k1 Key Derivation
[[Source]](https://github.com/ripple/rippled/blob/develop/src/ripple/crypto/impl/GenerateDeterministicKey.cpp "Source")
[![Passphrase → Seed → Root Key Pair → Intermediate Key Pair → Master Key Pair](img/key-derivation-secp256k1.png)](img/key-derivation-secp256k1.png)
Key derivation for secp256k1 XRP Ledger account keys involves more steps than Ed25519 key derivation for a couple reasons:
- Not all 32-byte numbers are valid secp256k1 secret keys.
- The XRP Ledger's reference implementation has an unused, incomplete framework for deriving a family of key pairs from a single seed value.
The steps to derive the XRP Ledger's secp256k1 account key pair from a seed value are as follows:
1. Calculate a "root key pair" from the seed value, as follows:
1. Concatenate the following in order, for a total of 20 bytes:
- The seed value (16 bytes)
- A "root sequence" value (4 bytes), as a big-endian unsigned integer. Use 0 as a starting value for the root sequence.
2. Calculate the [SHA-512Half][] of the concatenated (seed+root sequence) value.
3. If the result is not a valid secp265k1 secret key, increment the root sequence by 1 and start over. [[Source]](https://github.com/ripple/rippled/blob/fc7ecd672a3b9748bfea52ce65996e324553c05f/src/ripple/crypto/impl/GenerateDeterministicKey.cpp#L103 "Source")
A valid secp256k1 key must not be zero, and it must be numerically less than the _secp256k1 group order_. The secp256k1 group order is the constant value `0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141`.
4. With a valid secp256k1 secret key, use the standard ECDSA public key derivation with the secp256k1 curve to derive the root public key. (As always with cryptographic algorithms, use a standard, well-known, publicly-audited implementation whenever possible. For example, [OpenSSL](https://www.openssl.org/) has implementations of core Ed25519 and secp256k1 functions.)
**Tip:** Validators use this root key pair. If you are calculating a validator's key pair, you can stop here. To distinguish between these two different types of public keys, the [base58][] serialization for validator public keys uses the prefix `0x1c`.
2. Convert the root public key to its 33-byte compressed form.
The uncompressed form of any ECDSA public key consists of a pair of 32-byte integers: an X coordinate, and a Y coordinate. The compressed form is just the X coordinate and a one-byte prefix: `0x02` if the Y coordinate is even, or `0x03` if the Y coordinate is odd.
You can convert an uncompressed public key to the compressed form with the `openssl` commandline tool. For example, if the uncompressed public key is in the file `ec-pub.pem`, you can output the compressed form like this:
$ openssl ec -in ec-pub.pem -pubin -text -noout -conv_form compressed
3. Derive an "intermediate key pair" from the compressed root public key you, as follows:
1. Concatenate the following in order, for a total of 40 bytes:
- The compressed root public key (33 bytes)
- `0x00000000000000000000000000000000` (4 bytes of zeroes). (This value was intended to be used to derive different members of the same family, but in practice only the value 0 is used.)
- A "key sequence" value (4 bytes), as a big-endian unsigned integer. Use 0 as a starting value for the key sequence.
2. Calculate the [SHA-512Half][] of the concatenated value.
3. If the result is not a valid secp265k1 secret key, increment the key sequence by 1 and restart deriving the account's intermediate key pair.
4. With a valid secp256k1 secret key, use the standard ECDSA public key derivation with the secp256k1 curve to derive the intermediate public key. (As always with cryptographic algorithms, use a standard, well-known, publicly-audited implementation whenever possible. For example, [OpenSSL](https://www.openssl.org/) has implementations of core Ed25519 and secp256k1 functions.)
4. Derive the master public key pair by adding the intermediate public key to the root public key. Similarly, derive the secret key by adding the intermediate secret key to the root secret key.
- An ECDSA secret key is just a very large integer, so you can calculate the sum of two secret keys by summing them modulo the secp256k1 group order.
- An ECDSA public key is a point on the elliptic curve, so you should use elliptic curve math to sum the points.
5. Convert the master public key to its 33-byte compressed form, as before.
6. When serializing an account's public key to its [base58][] format, use the account public key prefix, `0x23`.
See [Address Encoding](accounts.html#address-encoding) for information and sample code to convert from an account's public key to its address.
## See Also
- **Concepts:**

View File

@@ -72,14 +72,14 @@ The request can contain the following parameters:
| `Field` | Type | Description |
|:-------------|:-------|:-----------------------------------------------------|
| `key_type` | String | Which elliptic curve to use for this key pair. Valid values are `ed25519` and `secp256k1` (all lower case). Defaults to `secp256k1`. |
| `key_type` | String |Which [signing algorithm](cryptographic-keys.html#signing-algorithms) to use to derive this key pair. Valid values are `ed25519` and `secp256k1` (all lower case). The default is `secp256k1`. |
| `passphrase` | String | _(Optional)_ Generate a key pair and address from this seed value. This value can be formatted in [hexadecimal][], the XRP Ledger's [base58][] format, [RFC-1751][], or as an arbitrary string. Cannot be used with `seed` or `seed_hex`. |
| `seed` | String | _(Optional)_ Generate the key pair and address from this seed value in the XRP Ledger's [base58][]-encoded format. Cannot be used with `passphrase` or `seed_hex`. |
| `seed_hex` | String | _(Optional)_ Generate the key pair and address from this seed value in [hexadecimal][] format. Cannot be used with `passphrase` or `seed`. |
You must provide **at most one** of the following fields: `passphrase`, `seed`, or `seed_hex`. If you omit all three, `rippled` uses a random seed.
**Note:** [Ed25519](https://ed25519.cr.yp.to/) support is experimental. The commandline version of this command cannot generate Ed25519 keys.
**Note:** The commandline version of this command cannot generate [Ed25519](https://ed25519.cr.yp.to/) keys.
#### Specifying a Seed
@@ -167,9 +167,10 @@ The response follows the [standard format][], with a successful result containin
| `Field` | Type | Description |
|:------------------|:-------|:------------------------------------------------|
| `key_type` | String | Which [signing algorithm](cryptographic-keys.html#signing-algorithms) was used to derive this key pair. Valid values are `ed25519` and `secp256k1` (all lower case). |
| `master_seed` | String | This is the private key of the key pair. The master seed from which all other information about this account is derived, in the XRP Ledger's [base58][] encoded string format. Typically, you use the key in this format to sign transactions. |
| `master_seed_hex` | String | The master seed, in hex format. A simple, widely-supported way to represent the private key. Can be used to sign transactions. |
| `master_key` | String | The master seed, in [RFC 1751](http://tools.ietf.org/html/rfc1751) format. An easier to remember, easier-to-write-down version of the private key. Can be used to sign transactions. |
| `master_key` | String | **DEPRECATED** The master seed, in [RFC-1751][] format. An easier to remember, easier-to-write-down version of the private key. Can be used to sign transactions. **Note:** The `rippled` implementation reverses the byte order of the key after decoding from RFC-1751 and before encoding it to RFC-1751; if you read or write keys for use with the XRP Ledger using a different RFC-1751 implementation, you must do the same to be compatible with `rippled`'s RFC-1751 encoding. |
| `account_id` | String | The [Address][] of the account in the XRP Ledger's [base58][] format. This is not the public key, but a hash-of-a-hash of it. It also has a checksum so a typo almost certainly results in an invalid address rather than a valid, but different address. This is the primary identifier of an account in the XRP Ledger. You tell people this to get paid, and use it in transactions to indicate who you are and who you're paying, trusting, and so forth. [Multi-signing lists](multi-signing.html) also use these to identify other signers. |
| `public_key` | String | The public key of the key pair, in the XRP Ledger's [base58][] encoded string format. Derived from the `master_seed`. |
| `public_key_hex` | String | This is the public key of the key pair, in hexadecimal. Derived from the `master_seed`. To validate the signature on a transaction, `rippled` needs this public key. That's why the format for a signed transaction includes the public key in the `SigningPubKey` field. |

View File

@@ -377,7 +377,7 @@ The response follows the [standard format][], with a successful result containin
| `cluster` | Object | Summary of other `rippled` servers in the same cluster, if [configured as a cluster](clustering.html). [New in: rippled 0.30.1][] |
| `peers` | Array | Array of peer objects. |
Each field of the `cluster` object is the public key of that `rippled` server's identifying keypair. (This is the same value that that server returns as `pubkey_node` in the [server_info method][].) The contents of that field are an object with the following fields:
Each field of the `cluster` object is the public key of that `rippled` server's identifying key pair. (This is the same value that that server returns as `pubkey_node` in the [server_info method][].) The contents of that field are an object with the following fields:
| `Field` | Type | Description |
|:--------|:-------|:----------------------------------------------------------|

View File

@@ -1,7 +1,7 @@
# Serialization Format
[[Source]<br>](https://github.com/ripple/rippled/blob/develop/src/ripple/protocol/impl/STObject.cpp#L696-L718 "Source")
This page describes the XRP Ledger's canonical binary format for transactions and other data. This binary format is necessary to create and verify digital signatures of those transactions' contents, and is also used in other places. The [rippled APIs](rippled-api.html) typically use JSON to communicate with client applications. However, JSON is unsuitable as a format for serializing transactions for being digitally signed, because JSON can represent the same data in many different but equivalent ways.
This page describes the XRP Ledger's canonical binary format for transactions and other data. This binary format is necessary to create and verify digital signatures of those transactions' contents, and is also used in other places including in the [peer-to-peer communications between servers](peer-protocol.html). The [`rippled` APIs](rippled-api.html) typically use JSON to communicate with client applications. However, JSON is unsuitable as a format for serializing transactions for being digitally signed, because JSON can represent the same data in many different but equivalent ways.
The process of serializing a transaction from JSON or any other representation into their canonical binary format can be summarized with these steps:
@@ -9,7 +9,7 @@ The process of serializing a transaction from JSON or any other representation i
The [Transaction Formats Reference](transaction-formats.html) defines the required and optional fields for XRP Ledger transactions.
**Note:** The `SigningPubKey` must also be provided at this step. When signing, you can derive this key from the secret key that is provided for signing.
**Note:** The `SigningPubKey` must also be provided at this step. When signing, you can [derive this key](cryptographic-keys.html#key-derivation) from the secret key that is provided for signing.
2. Convert each field's data into its ["internal" binary format](#internal-format).

View File

@@ -42,7 +42,7 @@ The `AccountRoot` object has the following fields:
| `Domain` | String | VariableLength | _(Optional)_ A domain associated with this account. In JSON, this is the hexadecimal for the ASCII representation of the domain. |
| `EmailHash` | String | Hash128 | _(Optional)_ The md5 hash of an email address. Clients can use this to look up an avatar through services such as [Gravatar](https://en.gravatar.com/). |
| `MessageKey` | String | VariableLength | _(Optional)_ A public key that may be used to send encrypted messages to this account. In JSON, uses hexadecimal. No more than 33 bytes. |
| `RegularKey` | String | AccountID | _(Optional)_ The address of a keypair that can be used to sign transactions for this account instead of the master key. Use a [SetRegularKey transaction][] to change this value. |
| `RegularKey` | String | AccountID | _(Optional)_ The address of a [key pair](cryptographic-keys.html) that can be used to sign transactions for this account instead of the master key. Use a [SetRegularKey transaction][] to change this value. |
| `TickSize` | Number | UInt8 | _(Optional)_ How many significant digits to use for exchange rates of Offers involving currencies issued by this address. Valid values are `3` to `15`, inclusive. _(Requires the [TickSize amendment][].)_ |
| `TransferRate` | Number | UInt32 | _(Optional)_ A [transfer fee](https://ripple.com/knowledge_center/transfer-fees/) to charge other users for sending currency issued by this account to each other. |
| `WalletLocator` | String | Hash256 | _(Optional)_ **DEPRECATED**. Do not use. |