// // JKBigInteger.m // JKBigInteger // // Created by Jānis Kiršteins on 5/21/13. // Copyright (c) 2013 Jānis Kiršteins. All rights reserved. // // Licensed under the MIT License #import "JKBigInteger.h" @implementation JKBigInteger { @private mp_int m_value; } + (BOOL)supportsSecureCoding { return YES; } - (id)initWithValue:(mp_int *)value { self = [super init]; if (self) { mp_init_copy(&m_value, value); } return self; } - (mp_int *)value { return &m_value; } - (id)initWithUnsignedLong:(unsigned long)unsignedLong { self = [super init]; if (self) { mp_set_int(&m_value, unsignedLong); } return self; } - (id)init { return [self initWithUnsignedLong:0]; } - (id)initWithCString:(char *)cString andRadix:(int)radix { if (radix < 2 || radix > 64) { return nil; } self = [super init]; if (self) { mp_init(&m_value); int result; result = mp_read_radix(&m_value, cString, radix); if (result != MP_OKAY) { mp_clear(&m_value); return nil; } } return self; } - (id)initWithCString:(char *)cString { int radix = 10; return [self initWithCString:cString andRadix:radix]; } - (id)initWithString:(NSString *)string andRadix:(int)radix { return [self initWithCString:(char *)[string UTF8String] andRadix:radix]; } - (id)initWithString:(NSString *)string { int radix = 10; return [self initWithCString:(char *)[string UTF8String] andRadix:radix]; } - (id)initWithCoder:(NSCoder *)decoder { self = [super init]; if (self) { int sign = [decoder decodeInt32ForKey:@"JKBigIntegerSign"]; int alloc = [decoder decodeInt32ForKey:@"JKBigIntegerAlloc"]; mp_init_size(&m_value, alloc); NSData *data = (NSData *)[decoder decodeObjectOfClass:[NSData class] forKey:@"JKBigIntegerDP"]; mp_digit *temp = (mp_digit *)[data bytes]; for (unsigned int i = 0; i < alloc; ++i) { m_value.dp[i] = temp[i]; } m_value.used = alloc; m_value.sign = sign; } return self; } - (void)encodeWithCoder:(NSCoder *)encoder { mp_clamp(&m_value); NSData *data = [NSData dataWithBytes:(const void *)m_value.dp length:m_value.alloc * sizeof(mp_digit)]; [encoder encodeObject:data forKey:@"JKBigIntegerDP"]; [encoder encodeInteger:m_value.alloc forKey:@"JKBigIntegerAlloc"]; [encoder encodeInteger:m_value.sign forKey:@"JKBigIntegerSign"]; } - (id)add:(JKBigInteger *)bigInteger { mp_int sum; mp_init(&sum); mp_add(&m_value, [bigInteger value], &sum); id newBigInteger = [[JKBigInteger alloc] initWithValue:&sum]; mp_clear(&sum); return newBigInteger; } - (id)subtract:(JKBigInteger *)bigInteger { mp_int difference; mp_init(&difference); mp_sub(&m_value, [bigInteger value], &difference); id newBigInteger = [[JKBigInteger alloc] initWithValue:&difference]; mp_clear(&difference); return newBigInteger; } - (id)multiply:(JKBigInteger *)bigInteger { mp_int product; mp_init(&product); mp_mul(&m_value, [bigInteger value], &product); JKBigInteger *newBigInteger = [[JKBigInteger alloc] initWithValue:&product]; mp_clear(&product); return newBigInteger; } - (id)divide:(JKBigInteger *)bigInteger { int result; mp_int quotient; mp_init("ient); result = mp_div(&m_value, [bigInteger value], "ient, NULL); if (result == MP_VAL) { mp_clear("ient); return nil; } JKBigInteger *newBigInteger = [[JKBigInteger alloc] initWithValue:"ient]; mp_clear("ient); return newBigInteger; } - (id)remainder:(JKBigInteger *)bigInteger { int result; mp_int remainder; mp_init(&remainder); result = mp_div(&m_value, [bigInteger value], NULL, &remainder); if (result == MP_VAL) { mp_clear(&remainder); return nil; } JKBigInteger *newBigInteger = [[JKBigInteger alloc] initWithValue:&remainder]; mp_clear(&remainder); return newBigInteger; } - (NSArray *)divideAndRemainder:(JKBigInteger *)bigInteger { int result; mp_int quotient, remainder; mp_init_multi("ient, &remainder, NULL); result = mp_div(&m_value, [bigInteger value], "ient, &remainder); if (result == MP_VAL) { mp_clear_multi("ient, &remainder, NULL); return nil; } JKBigInteger *quotientBigInteger = [[JKBigInteger alloc] initWithValue:"ient]; JKBigInteger *remainderBigInteger = [[JKBigInteger alloc] initWithValue:&remainder]; mp_clear_multi("ient, &remainder, NULL); return @[quotientBigInteger, remainderBigInteger]; } - (id)pow:(unsigned int)exponent { int result; mp_int power; mp_init(&power); result = mp_expt_d(&m_value, (mp_digit)exponent, &power); if (result == MP_VAL) { mp_clear(&power); return nil; } JKBigInteger *newBigInteger = [[JKBigInteger alloc] initWithValue:&power]; mp_clear(&power); return newBigInteger; } - (id)pow:(JKBigInteger*)exponent andMod: (JKBigInteger*)modulus { int result; mp_int output; mp_init(&output); result = mp_exptmod(&m_value, &exponent->m_value, &modulus->m_value, &output); if (result == MP_VAL) { mp_clear(&output); return nil; } JKBigInteger *newBigInteger = [[JKBigInteger alloc] initWithValue:&output]; mp_clear(&output); return newBigInteger; } - (id)negate { mp_int negate; mp_init(&negate); mp_neg(&m_value, &negate); JKBigInteger *newBigInteger = [[JKBigInteger alloc] initWithValue:&negate]; mp_clear(&negate); return newBigInteger; } - (id)abs { mp_int absolute; mp_init(&absolute); mp_abs(&m_value, &absolute); JKBigInteger *newBigInteger = [[JKBigInteger alloc] initWithValue:&absolute]; mp_clear(&absolute); return newBigInteger; } - (id)bitwiseXor:(JKBigInteger *)bigInteger { mp_int xor; mp_init(&xor); mp_xor(&m_value, [bigInteger value], &xor); JKBigInteger *newBigInteger = [[JKBigInteger alloc] initWithValue:&xor]; mp_clear(&xor); return newBigInteger; } - (id)bitwiseOr:(JKBigInteger *)bigInteger { mp_int or; mp_init(&or); mp_or(&m_value, [bigInteger value], &or); JKBigInteger *newBigInteger = [[JKBigInteger alloc] initWithValue:&or]; mp_clear(&or); return newBigInteger; } - (id)bitwiseAnd:(JKBigInteger *)bigInteger { mp_int and; mp_init(&and); mp_and(&m_value, [bigInteger value], &and); JKBigInteger *newBigInteger = [[JKBigInteger alloc] initWithValue:&and]; mp_clear(&and); return newBigInteger; } - (id)shiftLeft:(unsigned int)n { mp_int lShift; mp_init(&lShift); mp_mul_2d(&m_value, n, &lShift); JKBigInteger *newBigInteger = [[JKBigInteger alloc] initWithValue:&lShift]; mp_clear(&lShift); return newBigInteger; } - (id)shiftRight:(unsigned int)n { mp_int rShift; mp_init(&rShift); mp_div_2d(&m_value, n, &rShift, NULL); JKBigInteger *newBigInteger = [[JKBigInteger alloc] initWithValue:&rShift]; mp_clear(&rShift); return newBigInteger; } - (id)gcd:(JKBigInteger *)bigInteger { int result; mp_int gcd; mp_init(&gcd); result = mp_gcd(&m_value, [bigInteger value], &gcd); if (result == MP_VAL) { mp_clear(&gcd); return nil; } JKBigInteger *newBigInteger = [[JKBigInteger alloc] initWithValue:&gcd]; mp_clear(&gcd); return newBigInteger; } - (NSComparisonResult) compare:(JKBigInteger *)bigInteger { NSComparisonResult comparisonResult; comparisonResult = mp_cmp([bigInteger value], &m_value); switch (comparisonResult) { case MP_GT: return NSOrderedAscending; case MP_EQ: return NSOrderedSame; case MP_LT: return NSOrderedDescending; default: return 0; } } - (unsigned long)unsignedIntValue { return mp_get_int(&m_value); } - (NSString *)stringValue { int radix = 10; return [self stringValueWithRadix:radix]; } - (NSString *)stringValueWithRadix:(int)radix { int stringSize; mp_radix_size(&m_value, radix, &stringSize); char cString[stringSize]; mp_toradix(&m_value, cString, radix); for (int i = 0; i < stringSize; ++i) { cString[i] = (char)tolower(cString[i]); } return [NSString stringWithUTF8String:cString]; } - (NSString *)description { return [self stringValue]; } - (void)dealloc { mp_clear(&m_value); } /* Returns the number of bytes required to store this JKBigInteger as binary */ - (unsigned int)countBytes { return (unsigned int) mp_unsigned_bin_size(&m_value); } /* Retrieves the signed [big endian] format of this JKBigInteger */ - (void)toByteArraySigned: (unsigned char*) byteArray { mp_to_signed_bin(&m_value, byteArray); } /* Retrieves the unsigned [big endian] format of this JKBigInteger */ - (void)toByteArrayUnsigned: (unsigned char*) byteArray { mp_to_unsigned_bin(&m_value, byteArray); } @end